Software design tools have been around for over 20 years now. Althoughthey have improved greatly over that time, there seems to be a problemwith generated code: it is still too inefficient and unreadable. Untilnow.
At one level, building efficient executable UML models is trivial:write some code and put some boxes around it. The code will run as fastas you build it, and the boxes (for a class, eg) can easily be turnedinto some appropriate code. But the value added from this approach islow, and the mental overhead high.
An option is to generate more of the code from boxes, under thesupposition that the boxes are more abstract and so more productivethan writing code directly. This is intuitively correct, but inpractice it tends to break down because bit-fiddling code cannotcheaply be represented in UML. It is, in fact, more productive to writethe code directly—but then we lose the productivity advantages ofabstraction.
An alternative is to make UML both executable and translatable .This approach lets the developer verify that the design is solving theproblems he intends to solve by executing an executable UML model anddebugging the model's behavior before any code is generated.
Moreover, translation is carried out using a set of rules thatbuilds a system in a strict and repeatable manner. The developer hasfull control over these rules so that the most appropriate code for aparticular architecture can be generated.
Rather than bit-fiddling the generated code, a more structured andrepeatable process is now used. If there is a problem with the behaviorof the application, then the model is changed accordingly; if there isa problem with the performance of the code, then the rules areadjusted.
This separation of the application from the architecture (thetranslation rules) results in a more maintainable and efficient system.
Embedded software developers have a reputation in the software world atlarge for being a bit slow. Not dim, you understand—everyone knows wetackle sophisticated problems—but slow to pick up on new software toolsand languages.
This accusation has some truth. Today, some 77.2% of projects usesome C, another 46.2% use assembly language, and 44.2% use C++.(Venture Development Corporation, TheEmbedded Software StrategicMarket Intelligence Program, 2004 .}The numbers add up to more than 100% because a project may use morethan one language. Hardly anyone in IT would think of writing in alanguage as close to the machine as C, let alone assembly code, thesedays.
We embedded developers would quickly retort that our problems haveto be very efficient, very small, and in many cases, very fast too.Moreover, we need to have complete control over the generated code, andthat is taken away from us by programming language compilers.
We recognize, of course, the advantages of writing code at a higherlevel of abstraction. After all, studies for nigh thirty years haveshown that we can write the same number of lines of code per day,irrespective of the language. Since we get more functionality for aline of C++ than for a line of assembly, it stands to reason that wecan increase productivity if we use a more abstract language.
Meanwhile, the IT folk are moving towards higher-level-stilllanguages such as the Unified Modeling Language(UML), mostly as asketching language, or as a blueprint for further software development.
The UML is also an executable language, with state machines formodeling concurrent behavior and exploring synchronization issues,which would make the language appropriate for the embedded market, butit is so far away from the machine it seems at first blush to be evenmore unlikely than using C++ in the embedded space.
But what if you could generate small, efficient code? And what ifyou could have complete control over it? That would give us theproductivity advantages of a higher-level language while still meetingour performance constraints. Then moving from UML to embedded systemwould indeed be possible.
We begin our discussion, then, by describing a model-based approachto systems development, based on executable models.
|Figure1: The overall development process|
The first step, shown on the left inFigure 1 above as a light bulb,represents the concept behind an embedded project, a marriage of thedesirable, as expressed by the participation of marketing, and theavailable, as expressed by the participation of hardware and softwareexperts.
Defining the concept behind a product is often a compromise andtrade-off between possible features desired by marketing and thecapabilities that can be delivered by a given hardware-softwarearchitecture.
At this point, the development process bifurcates into applicationand architecture sections. These sections may be carried out inparallel, but we describe the application first.
Application models are executable, and consist of three primarydiagrams as shown in Figure 2 below .(For a complete description, see; for an extended example, see ). The first part is thedeclaration of the conceptual entities in a particular subject matter;these are represented using a Unified Modeling Language (UML) classdiagram.
It is critical to recognize that our use of a “class diagram” saysnothing about the software structure. In a translatable model, a “classdiagram” is only a convenient representation for a conceptual groupingof information and behavior.
Behavior over time is represented using a subset of a UML statechart diagram (the second part of Figure2 below ). There is astate-chart diagram for each object of a class. (More accurately, theremay be one state chart for each instance and there may be one statechart for the behavior of the collection of instances as a whole.Moreover, instances may participate in subtyping hierarchies.)All thedynamic behavior in an application model takes place as a part of astate machine.
An executable model is meaningless without rules that defineexecution. In executable UML, each state machine executes concurrentlywith all other state machines. They communicate by sending signals thatdefine precedence relationships between sequences of actions. Just aswith class diagrams, the state chart diagram does not imply animplementation; signals may be implemented in any manner that preservesthe desired precedence of actions.
|Figure2: An application model example|
Actions are the last of the primary artifacts of executable UML.Actions are also implementation independent, in that they do not assumea software structure. Consider, for example, a function that sums thetotal time used in the last n phone calls.
Looping through a linked list of recent calls is one way toimplement this, but that definition relies of a specific softwarestructure: a linked list. UML actions are cast so we first get thetimes for each of the calls and then sum them up. This subtledifference in expression allows us to access stored the data in any waywe choose, so as to get the best performance.
Other diagrams, such as communication diagrams, can be derived fromthe primary models as required for presentation and comprehensionpurposes.
Work on defining the architecture can take place at any time in respectto work on defining the application. This unexpected property comesabout because the architecture is not an elaboration of the applicationbut rather a set of rules that define how to transform an applicationwritten in executable UML into an implementation. A consistent set ofrules that target an architecture is called a model compiler.
When we build an executable UML model, the meaning of the model isstored in a database. The diagram shown in Figure 2 above createsinstances in the database as shown in Figure3, below .
The structure of the database is given by the elements of theexecutable UML language. Hence, we have a table Class to storeinformation about classes, and a table State to store information aboutstates. The structure of this database is called a metamodel.
A model compiler applies the architecture rules to the applicationas stored in the database. The rules traverse this database inaccordance with the desired target output; they also manipulate stringsto produce text acceptable to a compiler in the language of choice. Theresult is text on some output streams that may be compiled. The modelcompiler is oblivious to the language; it merely manipulates text.
It is here that the rubber meets the code: the performance needs tobe adequate. Should you find the code is too slow or too big, you canquickly identify the cause and write a rule to fix it.
For example, we may find that turning the magnetron on and off everyso many seconds is not fast enough. In that case, you should fix therules to generate a periodically executing task, not diddle thegenerated code: Write the new rule, add it to the rule set and test it.That way your expertise can be leveraged across the organization.
Off-the-shelf rule sets are available from vendors or internalorganizations that have modified rule sets to meet the needs of aspecific environment or product. The reason for such modification is tomeet performance constraints on speed or memory and perhaps tointerface to a library or some legacy code.
Once the model compiler has produced text, it can be compiled by aprogramming language compiler. This represents the transition from theabstract world of model-driven architectures to the familiar embeddedsoftware development environment. An open model compiler makes theprocess controllable and seamless.
The generated code may be in a selection of familiar languages:
1. Standard C. This is stillthe most widely used language for embedded software development.
2. Standard C++. Although notembraced by all developers, C++ is used increasingly often for embeddedcode.
3. C with special features.Sometimes standard C does not map directly onto a processor'sarchitecture and a special variant is useful. Or you need to meetcertain standards such as MISRA.
4. Assembler. Althoughhigh-level languages are the now norm, assembler has its place,particular with smaller devices.
This covers all the widely-used embedded development languages. Thenext step is to simply put the generated code through the appropriatetool-chain”compile, assemble, link with relevant libraries (e.g. RTOS)for the chosen target.
The application model has been verified; the architecture rules havebeen verified; the model compiler is part of well-tested tool set. Isthere anything left to do? Intellectually, no. But we may still get itwrong. At that point, it is helpful to be able to examine the generatedcode in action and debug the resulting code using a debugger.
Just like trying to debug assembly code generated from a C compiler,this can be difficult without a symbolic debugger. A model-leveldebugger allows us to set breakpoints in the model, halt the runningcode, and hyperlink back to the model element that caused the problem.
Frequently, hardware and the embedded user interface are beingassembled as the software is being written. To provide a commonplatform for all developers, a host-compiled simulation environment canrun embedded applications on the development host. This provides theability to simulate the complete system, including hardware andperipherals, I/O and the application's GUI, which allows you to startdevelopment before receiving hardware.
With several powerful additions including visualization, monitoringand tracing tools, this also provides expanded network simulation andthe ability to simulate not just the application's GUI, but also thecomplete Man-Machine-Interface (MMI) of the product under development.
Beyond the standard debug support, you need a number of advancedfeatures that enable in-depth analysis and debugging of complexembedded systems. Features for establishing the state of the machine,identifying areas of code for performance gains and interacting withthe program executes are all required.
Of course, the next step is to move on to deployment
From UML to Embedded System
The software development flow of Figure1, above, says it all. From idea to deployment.
The key concept is that of open translation rules. These allow youto tune the code to produce anything you need.
That said, we have found that better than two thirds of projectshave no need to tweak the rules at all from the out-of-the-box modelcompiler.
Yes. Not only is it possible to go from UML to embedded system, itis easy.
Thisarticle is excerpted from a paper of the same name presented at theEmbedded Systems Conference Silicon Valley 2006. Used with permissionof the Embedded Systems Conference. For more information, please visit www.embedded.com/esc/sv.
StephenJ. Mellor is an internationally recognized pioneer in creatingeffective, engineering approaches to software development. In 1985, hepublished the widely read Ward-Mellor trilogy Structured Developmentfor Real-Time Systems, and in 1988, the first books definingobject-oriented analysis. He is now chief scientist of the EmbeddedSystems Division at Mentor Graphics. He also chairs the IEEESoftware Industrial Advisory Board. www.acceleratedtechnology.com
 Stephen, J. Mellor, Marc J. Balcer. Executable UML: A Foundationfor Model-Driven Architecture
 Leon Starr, Executable UML, The Elevator Case Study, ModelIntegration, LLC.
Other UMLreferences on Embedded.com:
Executableand Translatable UML
Needfor modeling tools rises with design complexity
InFocus: Unified Modeling Language
Introductionto UML statecharts
UMLevolves total system perspective
Introductionto UML Class Diagrams