CMP EMBEDDED.COM

Login | Register     Welcome Guest  
HOME DESIGN PRODUCTS COLUMNS E-LEARNING CONFERENCES CODE FORUMS/BLOGS NEWSLETTERS CONTACT FEATURES RSS RSS

How to use UML in your SoC hardware/software design: Part 3
Manipulating and using SoC xtUML application models



Embedded.com
Once you have captured the semantics of your SoC application model completely in a neutral form (see Part 2), you are now ready to compile it into software and silicon. Only the semantics of the modeling language matter for translation purposes.

If a class is represented graphically as a box, or even as text, this is of no consequence. The UML is just an accessible graphical front-end for those simple elements.

When you build a 'class' such as CookingStep in a microwave oven, that represents a set of possible cooking steps you might execute, each with a cooking time and power level.

Similarly, when you describe the lifecycle of a cooking step using a state machine, it follows a sequence of states as synchronized by other state machines, external signals, and timers. And in each state, we execute some functions. All of this structure and behavior, for the entire model, is captured as data in the metamodel.

Rules and Rule Languages
Now that we have a verified platform-independent model of our application captured as a metamodel, we can translate it into hardware and software description languages, such as VHDL or C, using a model compiler. A model compiler is implemented as a set of rules.

One rule might take a 'class' represented as a set CookingStep( cookingTime, powerLevel ), and produce a class declaration. Crucially, the rule could just as easily produce a struct for a C program, or a VHDL entity. Similarly, we may define rules that turn states into arrays, lists, switch statements, or follow the State pattern from the Design Patterns community.

(This is why we put 'class' in quotation marks. A 'class' in an executable model represents the set of data that can be transformed into anything that captures that data; in a blueprint-type model, a class is an instruction to construct a class in the software.)

These rules let us separate the application from the architecture. The xtUML model captures the problem domain graphically, and represents it in the metamodel. The rules read the application as stored in the metamodel, and turn that into code.

There are many possible rule languages, and the Object Management Group is now working to define a standard [1]. All that's required is the ability to traverse a model and emit text. As an example, the rule below generates code for private data members of a class by selecting all related attributes and iterating over them.

.function PrivateDataMember( class Class )
.select many PDMs from instances of Attribute related to Class
.for each PDM in PDMs
${PDM.Type} ${PDM.Name};
.endfor

All lines beginning with a period ('.') are commands to the rule language processor, which traverses the metamodel whose instances represent the executable model and performs text substitutions.

${PDM.Type} recovers the type of the attribute, and substitutes it on the output stream. Similarly, the fragment ${PDM.Name} substitutes the name of the attribute. The space that separates them and the lone ';' is just text, copied without change onto the output stream, as shown below:

You may wonder what the produced code is for. It is an enumeration that contains each of the states of a state machine for a class. (There is a similar rule that produces an enumeration of signals.)

The enumerations are used to declare a two-dimensional array containing the pointers to the activity to be executed. You may not like this code, or you may have a better way to do it.

Cool: all you have to do is modify the rule and regenerate. Every single place where this code appears will then be changed. Propagating changes this way enables rapid performance optimization.

While the generated code is less than half the size of the rule, the rule can generate any number of these enumerations, all in the same way, all equally right—or wrong. We have also used the rule language to generate VHDL, as follows:

The rule language can be used in conjunction with the generator to generate code in any language: C, C++, Java, Ada, and, if you know the syntax, Klingon.

Model Compilers and System Construction
Figure 1 below shows the overall structure of a model compiler. The application is captured in the metamodel, and the model compiler comprises some library code and a set of rules. The rules are interpreted against the metamodel to produce text. The rules may also "wrap" external libraries and legacy code. All of this is compiled—using the appropriate compilers—to produce the system-on-a-chip.

Figure 1: Model Compiler and System Construction

The overall architecture of the generated system is determined by the model compiler. Each model compiler is thus coupled to the target, but the model compiler is independent of the application models that it translates. This separation of application from design allows us to reuse both application model and model compiler as needed.

We can translate the same application model for many different targets by using different model compilers, but the models of the application do not change. Similarly we can use the same model compiler to translate any number of application models for a given target without changing the model compiler.

For example, a model compiler for an object-oriented architecture will likely contain rules to translate each UML class to a C++ class or a C struct with each associated UML attribute being translated to a data member of the class or a member of the struct.

The state machines in the application model would be translated into two dimensional arrays where the row index represents the current state of an object, and the received event provides the column index. Each cell contains the value of the next state for the transition identified by the current state (row) and the received event (column).

This next-state value is then used as an index into an array of function pointers, each corresponding to a state. This particular approach leads to a constant-time dispatching mechanism for the actions of each state machine. Of course we can use alternative implementations depending on our needs.

For example, in some cases, we might choose to use a switch statement or nested if-else statements to implement the state machine, each of which would have slightly different speed and space characteristics (if-else is linear in the product of states and events).

For hardware implementations we might choose to translate each UML class into a collection of registers, one for each attribute in the class. Each state machine of the application model could be mapped to a VHDL case statement. There are, of course, many other possible implementations. UML classes can be mapped into blocks of RAM, and state machines can be translated into a data-driven and gate-conservative dispatcher.

But what about the interfaces between the hardware and software components of the system? These interfaces are just a part of the architecture encapsulated within the model compiler.

Let's look at a simple example.
Suppose we have two UML classes, CookingStep and Oven where CookingStep is translated to software and Oven is translated to hardware. In this case the hardware architecture for Oven is a collection of memory-mapped registers.

The generated interface for an action in CookingStep that accesses an attribute of Oven is then a simple memory access of the address allocated for the register in question.

Consider a slightly different hardware architecture in which the UML class Oven is mapped to only two addresses, one representing a control register and one for a data register. Accesses to attributes of the class would then be accomplished by writing the attribute identifier and the type of access (read or write) to the control register and then manipulating the data register accordingly (reading it after writing to the control register or writing it before writing to the control register).

Since the model compiler is generating the implementation for both the hardware and the software components of the system, it has sufficient information to generate the interface between the two, and it will do so without succumbing to the ambiguities of a natural language specification. And it will do it correctly, every time.

It's possible to build and deploy model compilers that provide completely open translation systems. Exposing the translation rules in this way allows you to make changes to the rules to meet your particular needs so that the model compiler generates code exactly the way you want. This puts the translation of the models completely under your control.

The importance of marks in your UML design
To tell the model compiler whether to generate hardware or software for a given model element we need additional inputs to decide which mapping to perform. These additional inputs are provided as marks, which are lightweight, non-intrusive extensions to models that capture information required for model transformation without polluting those models.

Each kind of mark has a name and a type. In addition, a kind of mark can have a default value. In programmer-esque language, we might write:

Mark HardSoft [ isHardware, isSoftware ] = isSoftware

which declares a kind of mark named HardSoft that can have one of two values, where the default is isSoftware.

Most marks apply to instances of metaclasses, so that, for example, if we have a metamodel with class Class, and two instances of that class, Oven and CookingStep, the mark HardSoft can have a separate value for each of those instances, isHardware for the Oven, say, and isSoftware for the CookingStep.

Were the kind of mark to apply instead to generated signals, then the marks would be associated with instances of the class GenerateSignalAction in the metamodel. A given application model element can have several marks associated with it. Each of these marks is an extended attribute of the appropriate metamodel class.

Metacasses as plastic sheets
We do not intend to leave the impression that the metamodel should be extended directly. Marks are not part of either the application model or the metamodel, though they can refer to them both. Rather, we view the extended attributes of the metaclasses as being housed on a plastic sheet that can be peeled off at will for a different model compiler. This separation supports both model portability and longevity.

The separation also provides the ability to evaluate a number of different architectural possibilities without requiring modification of the application model. Just change the values of the marks. Not to put too fine a point on it, this solves the problem of changing the hardware-software partition after we have verified the behavior of the application model by executing test cases against it.

The plastic sheet analogy suggests that some marks might be related and could all be placed on the same sheet. A single sheet could contain multiple related marks, such as those indicating which types of hardware implementations should be applied to which elements of the application model. Removal of the plastic sheet, then, implies the removal of the entire hardware architecture represented by that sheet from the system.

Marks may also be quantities used to optimize the target implementation. Consider a model that must be transformed into an implementation that occupies as small an amount of memory as possible. We can save memory if we observe that a particular class has only one instance (e.g., Oven). Such a class can be marked as extentLess, and no container need be generated for instances of that class, making references to the instances more efficient.

Similarly, we can make trade-offs within the hardware architecture. Suppose the original target had plenty of address space available and consequently mapped each class attribute implemented in hardware to a specific address, making the software access to the attributes simple and efficient.

In a subsequent release we move to a lower-cost processor with a constrained address space. Through marks we then instruct the model compiler to use a single pair of addresses for each class to provide access to all the attributes in the class. Since the model compiler knows how to generate the software required for this more interesting approach for accessing hardware-resident attributes, the application models do not change even though the nature of the hardware/software interface has been drastically altered.

There have to be ways for the modeler to assign values to marks. Some implementations provide for graphical drag-and-drop allocation of model elements into folders that correspond with marks; others define an editor for the defined mark sets that can display all marks defined by the model for a selected model element, with pull-down menus for each of the marks. Another option is to define text files, and then use the large set of available editing, and scripting tools.

In the final article of this series, we assess progress in standardization, and in the market.

To read Part 1 in this series, go to "The central problem of SoC design and a proposed xtUML solution."
To read Part 2 in this series, go to "Executable UML Models for SoC design."

This series is reprinted in four parts from Chapter 2 of "UML for SoC Design" with permission of Springer.

Stephen J. Mellor, Chief Scientist of the Embedded Software Division at Mentor Graphics, is an internationally recognized pioneer in creating effective, engineering approaches to software development. In 1985, he published the widely read Ward-Mellor trilogy Structured Development for Real-Time Systems, and in 1988, the first books defining object-oriented analysis. His latest book MDA Distilled: Principles of Model-Driven Architecture was published in 2004.

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.

Campbell D. 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.

References:
[1] MOF Model to Text Transformation RfP - http://www.omg.org/cgi-bin/doc?ad/04-04-07 

Other resources on Embedded.com about UML and xtUML:

1) 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
8) From UML to embedded system: Is it possible?




1

Rate this article: Low High
Current rating
  • .
Embedded.com Career Center
Looking for a new job?
SEARCH JOBS

Browse all jobs

SPONSOR
RECENT JOB POSTINGS





 :