How to use UML in your SoC hardware/software design: Part 2In the first article in this series, we introduced the notion of an executable UML, but we did not describe the elements of which it consists. These elements must be sufficiently primitive to be translatable into multiple implementations, including hardware, but be powerful enough to be useful.
The number of elements in executable UML must also be low to ease the construction of translators, to ease the burden of learning the language, and to eliminate the ambiguity that accompanies the use of multiple constructs to represent the same concept. Determining exactly which elements make up an executable UML is therefore a matter of judgment.
In this second article, we describe the elements of Executable and Translatable UML (xtUML, or just Executable UML) , how actions enable description of behavior at a higher level of abstraction, the dynamic behavior of an executable UML model, and how a model of an SoC design can be verified before committing to a hardware-software partition.
The Static Elements of xtUML
xtUML is a streamlined subset of UML to support the needs of execution- and translation-based development for SoC. As you will recall from the first article, we propose the construction of a single application model that captures behavior but does not capture the implementation structure (especially whether some functionality is to be executed in hardware or software).
The xtUML diagrams (e.g. class diagrams, state machines, activity specifications) are "projections" or "views" of an underlying model that has defined execution semantics. Other UML diagrams that do not support execution, such as use case diagrams, may be used freely to help build the xtUML models, but as they do not have an executable semantics, they are not a part of the xtUML language. The xtUML model is the formal specification of the solution to be built on the chip.
The essential components of xtUML are illustrated in Figure 2, below, which shows a set of classes and objects that use state machines1 to communicate.
[UML 2 uses "state machine" to mean both the diagram (previously known as a state chart diagram) and the executing instance that has state.To reduce ambiguity, we have chosen to use "state model" for the diagram describing the behaviors, and "state machine" for the executing instance. Where either meaning could apply, we use "state machine" to be consistent with the UML.]
Each state machine has a set of actions triggered by the state changes in the state machine. The actions then cause synchronization, data access, and functional computations to be executed.
Each class may be endowed with a state model that describes the behavior of each instance of the class. The state model uses only states (including initial pseudo-states and final states), transitions, events, and actions.
Each class may also be endowed with a state model that describes the behavior of the collection of instances. Each class in a sub-typing hierarchy may have a state model defined for it as a graphical convenience. As each state machine progresses through its lifecycle, it executes a set of actions.
|Figure 1: The structure of an xtUML model|
Enabling execution of UML models
The introduction of a complete set of actions, as provided by UML 1.5 carried forward into UML 2.0, makes UML a computationally-complete specification language with a defined "abstract syntax" for creating objects, sending signals to them, accessing data about instances, and executing general computations.
An action language "concrete syntax" provides a notation for expressing these computations. [Mentor Graphics' EDGE UML Suite provides OAL (Object Action Language) that complies with the abstract syntax standard, but there is presently no action language (notation) standard.]
The difference between an ordinary, boring programming language and a UML action language is analogous to the difference between assembly code and a programming language. They both specify completely the work to be done, but they do so at different levels of language abstraction.
Programming languages abstract away details of the hardware platform so you can write what needs to be done without having to worry about e.g. the number of registers on the target machine, the structure of the stack or how parameters are passed to functions. The existence of standards also made programs portable across multiple machines.
To illustrate the issues, consider the following fragment of logic:
Until Calls = null do
Sum += Calls.timeOfLastCall;
Calls = Calls.next;
The elements in this fragment include assignments, until, null, an expression (with equality), an increment of a variable, and a linked list of some sort. The semantics of While not (expr) and Until (expr) are the same. One of them is syntactic sugar—a sweeter way of expressing the same thing.[We once saw the following code:
Constant Hell_Freezes_Over = False;
Until Hell_Freezes_Over do. . . .
Of course, which is syntactic sugar, and which the one true way of expressing the statement can be a matter of heated debate. One can always add syntactic sugar to hide a poverty of primitives so long as the new syntax can be reduced to the primitives. The choice of primitives is a matter of judgment; there is no bright line.
Consider now a triplet of classes, X, Y, and Z with associations between them. We might wish to traverse from the x instance of X to Y to Z to get the p attribute (x-->Y-->Zp). The primitives involved here are a traversal and a data access.
However, we could choose to implement these classes by joining them together to remove the time-consuming traversal. In this case, the specification (x-->Y-->Z.p) can be implemented by a simple data access xyz.p, where xyz is an instance of the combined classes X, Y, and Z.
In this example, the traversal is a single logical unit expressed as a set of primitives. Defining the specification language so that these primitives are grouped together in a specification allows the translated code to be more efficient.
For example, if GetTheTimesOfAllCalls is a query defined as a single unit in the manner of (x-->Y-->Z.p), so that all knowledge of the data structures is localized in one place, we can implement it however we choose.
We can go further. The logic above sums the times of some calls that happen to be stored in a list. We can recast it at a higher level of abstraction as: GetTheTimesOfAllCalls, then sum them. This is the formulation used by the UML action model. The application model can be translated into a linked list as in the code above, a table, distributed across processors, or a simple array.
This last point is the reason for the word 'translatable.' An executable translatable UML has to be defined so that the primitives can be translated into any implementation.
This means isolating all data access logic from the computations that act on the data. Similarly, the computations must be separated from the control structures (in the logic above, the loop) so that the specification is independent of today's implementation—including whether to implement in hardware or software.
The Dynamic Behavior of an xtUML
Figure 1 above showed the static structure of xtUML, but a language is meaningful only with a definition of its dynamic behavior.
To execute and translate, the language has to have well-defined execution semantics that define how it executes at run time. xtUML has specific unambiguous rules regarding dynamic behavior, stated in terms of a set of communicating state machines, the only active elements in an xtUML program.
Each object and class can have a state model that captures its behavior over time. Every state machine is in exactly one state at a time, and all state machines execute concurrently with respect to one another.
Each state machine synchronizes its behavior with another by sending a signal that is interpreted by the receiver's state machine as an event. On receipt of a signal, a state machine fires a transition and executes an activity, the set of actions that must run to completion before that state machine processes the next event.
Each activity comprises a set of actions that execute concurrently unless otherwise constrained by data or control flow, and these actions may access data of other objects. It is the proper task of the modeler to specify the correct sequencing and to ensure object data consistency.
The essential elements, then, are a set of classes and objects with concurrently executing state machines. State machines communicate only by signals. On receipt of a signal, a state machine executes a set of actions that runs to completion before the next signal is processed. (Other state machines can continue merrily along their way. Only this state machine's activities must run-to-completion.)
Signal order is preserved between sender and receiver object pairs, so that the actions in the destination state of the receiver execute after the action that sent the signal. This captures desired cause and effect.
It is a wholly separate problem to guarantee that signals do not get out of order, links fail, etc., just as it is separate problem to ensure sequential execution of instructions in a parallel machine.
Those are the rules of the language, but what is really going on is that xtUML is a concurrent specification language. Rules about synchronization and object data consistency are simply rules for that language, just as in C we execute one statement after another and data is accessed one statement at a time. We specify in such a concurrent language so that we may translate it onto concurrent, distributed platforms; hardware definition languages; as well as fully synchronous, single tasking environments.
Application Model Verification
An executable application model can be executed independent of implementation. No design details or code need be added, so formal test cases can be executed against the application model to verify that requirements have been properly met. Critically, xtUML is structured to allow developers to model the underlying semantics of a problem without having to worry about whether it is to be implemented in hardware of software.
Verification of application models is exactly that: It verifies the behavior of the application models and nothing else. It does not check that the system will be fast enough or small enough; it checks only that the application does what you (your client and your experts) want. Verification is carried out by model execution.
When we construct an application model, such as that shown in Figure 1, we declare the types of entities, but models execute on instances. To test the behavior of the example in Figure 1, therefore, we need first to create instances. We can do this with action language or with an instance editor.
We then define operations to create the object instances on which the test will execute. Then, we send a signal to one of the created objects to cause it to begin going though its lifecycle. Of course, actions in that object may be signal-sends that cause behavior in other objects. Eventually the cascade of signals will cease and the system will once again be in a steady state, ready for another test.
Each test can be run interpretively. Should the test fail, the application model can be changed immediately and the test rerun. Care should be exercised to ensure the correct initial conditions still apply. It is useful to be able to 'run' the whole test at once; to 'jog' through each state change, and to 'step' through each action.
When each test run is complete, we need to establish whether it passed. This can be achieved either by interactively inspecting attribute values and the state of the application models or by using action language that checks expected values against actuals. A report can be produced in regression-test mode that states whether each test passed or failed.
Capturing xtUML Models
When we build an application model such as that in Figure 1, its semantic content must be captured somehow. This is accomplished by building a model of the modeling language itself.
The classes Oven and CookingStep, for example, are both instances of the class Class in the model of the modeling language. (The formal name for a model whose instances are types in another model is a metamodel. Informally, it is the "dotted line" of the first article.)
Similarly, the states Ready and Executing for the class CookingStep are captured as instances of the class State, and attributes powerOutput and pulseTimer of the class Magnetron are captured as instances of the class Attribute. This is also true for the actions. The action language statement generate powerOn to magnetron; is an instance of the metamodel class GenerateSignalAction.
Naturally, a tool will also capture information about the graphical layout of the boxes on the diagrams entered by the developer, but this is not necessary for the translation process. Only the semantics of the application model is necessary for that, and that's exactly what is captured in a metamodel.
At system construction time, the elements captured in the metamodel are mapped to implementation. The desired sequencing specified in the application models must be maintained. Objects may be distributed, sequentialized, even duplicated redundantly, so long as the defined behavior is preserved.
We take up how to do this in the third article in the series.
To read Part 1 in this series, go to "The central problem of SoC design and a proposed xtUML solution."
This series is
reprinted in four parts from Chapter 2 of UML
for SoC Design
with permission of Springer.
John R. Wolfe, Director of Operations and Engineering for the BridgePoint UML suite at Mentor Graphics, was President and CEO of Project Technology, Inc., since acquired by Mentor Graphics acquired the company, which was focused on tools to execute and translate UML models in the context of Agile MDA.
McCausland is a Principal
Engineer, Mentor Graphics
Corp, where he is the chief designer of the BridgePoint UML Suite. He
is the creator of (to his knowledge) the very first model compiler that
translates xtUML models to behavioral VHDL.
John Wolfe will be at the upcoming Embedded Systems Conference Boston, September 25-28 at the Mentor Graphics booth #1201. In addition, Cortland Starrett will be conducting a series of seminars. Go to www.embedded.com/esc/boston/ to check on the speaker's schedule details. Starrett is Engineering Manager leading development of translation technology at Mentor Graphics, responsible for the production of tools and methods for translating xtUML models into source code such as C, C++, Java and VHDL.
 UML Profile for System on a Chip. http://www.omg.org/cgi-bin/doc?formal/06-06-01
 Executable UML: A Foundation for Model-Driven Architecture, Mellor and Balcer, Addison-Wesley, 2002.
resources on Embedded.com on UML and xUML:
Executable and Translatable UML
2) Need for modeling tools rises with design complexity
3) In Focus: Unified Modeling Language
4) Introduction to UML statecharts
5) UML evolves total system perspective
6) Introduction to UML Class Diagrams
7) State machine shortcuts