Copyright © 1998-2005 Mentor Graphics Corporation
August 2005
Abstract
This guide is the primary reference document for the engineers and scientists translating Nucleus BridgePoint® xtUML models with the MC-3020 model compiler. It explains how to use the compiler's features and capabilities.
Table of Contents
List of Figures
List of Tables
List of Examples
This chapter describes the purpose and use of this guide, lists other related documents, and presents the conventions used within.
This section explains the intent of this document and describes its usage.
The purpose of this guide is to enable the user of the MC-3020 model compiler to generate and execute an ANSI C program from Shlaer-Mellor xtUML models specified in the Nucleus BridgePoint Model Builder. Essential tasks that this guide will enable the user to perform include the following.
Install MC-3020.
Translate xtUML models into ANSI C code.
Build an executable program.
Create xtUML models that fully utilize the capabilities of MC-3020.
This guide is written for software engineers who are using the Shlaer-Mellor development method and will implement their system using the MC-3020 model compiler. It assumes that the user is familiar with the ANSI C programming language and general usage of the development platform and its software development utilities.
There are various roles that software engineers can play in the course of developing a system. These roles reflect the different types of tasks that must be undertaken to successfully specify, design, construct, and test a system. Roles that are relevant to the usage of the MC-3020 model compiler include the following.
| Analyst | Develops the xtUML models on the Nucleus BridgePoint tool set that specify system behavior and that will be used to construct the final system. |
| Software Architect | Installs and maintains the MC-3020 Model Compiler. Frequently assists in its use to translate the xtUML models and build the system. |
| System Architect | Makes system wide decisions about how the xtUML models will be ``marked'' to utilize the facilities provided by MC-3020. This person frequently assists in the translation and building of the system. |
| Programmer | Designs and develops C or other code that interfaces to the MC-3020 generated code. |
| Tester | Tests the system. |
An engineer in each of these roles will be looking for different types of information in this guide to fulfill the tasks of that role.
The Analyst will want to understand how to use MC-3020 modeling conventions to specify such things as instance initialization and bridge operations. The Analyst will also be interested in understanding the limitations that MC-3020 places on the xtUML models.
The Software Architect will want to understand how to install and run MC-3020 as well as understand its structure well enough to maintain it.
The System Architect will want to understand the underlying software design or architecture provided by MC-3020 and the marking options that are available for translating the xtUML models into ANSI C code.
The Programmer will want to understand the published interfaces to the MC-3020 generated system and how to use them to successfully interact with the generated components.
The Tester will want to understand how to execute and debug the generated system for ``black box'' testing, and how the system is constructed and operates for ``white box'' testing.
The following section provides guidance on using this guide to meet these needs.
This section describes the general structure of this guide and provides suggestions for its usage in different situations.
The guide is assembled with the more frequently accessed chapters toward the front. These chapters are in roughly chronological order according to how they will be used. General Shlaer-Mellor development background is provided toward the end.
Here is a short description of each chapter and appendix.
Appendices have been provided.
This chapter provides a concise overview of many of the capabilities built into MC-3020. The basic gist of translation strategy for model components is given in an outline format.
MC-3020 delivers translation technology and a set of features and components found in no other model compiler existing to date. The mix of optimizations, conveniences and simplicity provide a solid foundation upon which ``down on the iron'' embedded designs can be based.
The translation engine embodied in the MC-3020 Model Compiler performs two passes across the xtUML model under translation. The first pass analyzes the model structure and action language semantics of each domain. The results of this analysis drive the generation in the second pass. The second pass generates code and data that is minimized and optimized for speed. Unaccessed data and unneeded code are eliminated.
This multi-pass intelligence spans domains and allows for optimizations at the system level based on information collected and collated from all domains in the system.
Preemptive multi-tasking is supported on the Nucleus PLUS® real-time operation system (RTOS) and on systems supporting POSIX threading. Single-task operation (with or without and RTOS) is also supported. Tasking supplies a rich means of providing preemptive prioritization among the xtUML classes running in the system.
Preemptive task/thread prioritization is provided in the generated C code. Groups of xtUML classes are mapped to tasks running at differing priorities.
MC-3020 also provides for prioritization through the marking of events. Higher priority xtUML threads of control can run without being preempted by lower priority activities.
MC-3020 cleanly translates large systems consisting of multiple xtUML and realized domains. Support is provided to integrate and interface to hand-craft, legacy and/or off-the-shelf code.
MC-3020 supports the marking of persistent classes. The instance data for classes marked as persistent is restored at power-up from a non-volatile storage (NVS) device.
A set of metrics is generated and reported each time the model compiler is run. Statistics on classes, associations, events and first pass analysis results are stored in a report directory.
Metrics provided can be fed back to the analyst to provide a focus on recognized dangerous practices and fully illegal operations and accesses. Some of the metrics relate to sizing and complexity. These metrics could easily be tracked over the life of a project to provide quality and effort related measurements.
Based upon information modeled in Nucleus BridgePoint Model Builder MC-3020 automatically generates source code frameworks for operations and outbound bridge implementation. These skeleton files will actually compile as generated. The user is saved from delving into generated code to divine interfaces required for these boundary functions. Kind and helpful comments are provided to guide insertion of bridge and operation implementation code.
Support is provided for translation of AL in operation and bridge descriptions. The same action language used for Nucleus BridgePoint Model Verifier is translated into the of bodies of the operation C source files and the bridge skeleton files.
Several hooks have been supplied to allow easy interfacing of user supplied code to the system level generated code. A source module is automatically generated that supplies empty functions which are invoked at various points during initialization, dispatch processing and shut down. These empty functions can be populated with user code for ``can't happen'' events, hardware bring-up, ``background'' processing, legacy clean-up and more.
To allow optimization for space and control over precision, the storage classes of integer and real based user-defined data types (UDTs) can be supplied by the user. MC-3020 also allows user-defined data types to be implemented as pointers. The pointer types are very convenient for passing across bridges (in both directions). Precision and pointer information is provided to the model compiler through marking.
Further optimization of space is provided through ANSI C bit field support. Multiple attributes can be packed into a single word of storage. This feature may also be used (with caution) in conjunction with memory mapped classes to model hardware with xtUML constructs.
MC-3020 attempts to optimize select any [inst_ref] from instances of [key_letters] where [where clause] when the where clause is checking for equality of the identifier. MC-3020 optimizes for code space. In addition, hooks into the scanning routines are provided to enable customizations to the selection search algorithms. Applications dealing with large collections of class instance data (hundreds or thousands) may use these hooks to further speed the selection process.
MC-3020 provides a safe way to bridge into the application from interrupt handlers (or other external tasks). Consistency is maintained in software architecture data structures and application data access sets.
A means is provided for the user to supply application specific fule file functions. This capability serves to extend the marking capabilities of MC-3020. It is possible to steer code generation in such a way as to provide customizations characteristic of particular target platforms, compilers and tool sets.
MC-3020 is purely ANSI C and generates code that can be compiled by any compiler compliant with the ANSI standard. The core model compiler uses no libraries or system functions. stdio.h is included simply for convenience during debug (for printf, etc). All generated code is simple, native C.
As of version 3.1, MC-3020 supports initialization of preexisting instances in data. This provides a substantial optimization in both bring-up execution speed and overall code footprint. Instead of creating, relating and initializing all of the classes at start-up, pre-existing class instances can be pre-populated with static initializers. Support is maintained for dynamic initialization using an initialization function (or an initialization object).
As of version 3.1, MC-3020 supports xtUML-level model debugging with Nucleus BridgePoint Model Debugger. This support allows execution tracing at state action as well as the AL statement level. The state of the system can be openly queried and viewed at any point of execution. Support is limited to execution on the host computer or socket-capable targets with sufficient RAM capacity.
MC-3020 is a modular software architecture characterized by a distinct effort to maximize component independence. The coupling between the model compiler components has been minimized while maximizing component cohesion. A model of the architecture drives the implementation of the generation components.
To a great extent components can be modified independently. Additional components can be added. This makes MC-3020 ideal for extension and modification. In a limited fashion, individual architecture components can be ``unplugged'' and new or modified components ``plugged in'' to replace them. For example, the strategy for collecting instances can be changed by modifying or replacing only the localized component. Names and coding style rules are concentrated into a single component allowing architects to dial in a preferred naming convention and generation style.
Each class is translated into an ANSI C structure. Instances are maintained in collections of instances of classes (class extents). Space for class instances is pre-allocated at bring-up time.
Creation occurs in constant time. Creation can occur synchronously with the create action language statement or asynchronously with a creation event. In synchronous creation, no action is executed. In asynchronous creation, a creation state is executed and at minimum initializes the instance identifier.
Instance deletion moves an class instance from the active extent and deactivates it onto a list of inactive (``inanimate'') class instances. If no action language ever performs deletion of a particular class, no deletion accessor method is generated.
Instance selection is optimized for speed when selecting based on the instance identifier. For unoptimized selections O(N) (linear) time is required. (MC-3020 provides O(N) for all ``blind selections'', select any from instances of action language commands.) Hooks are provided for architect replacement of certain signature selection search functions.
Attributes are elements of the translated structure. Most attributes are translated with no function interface layer. No call/return overhead is incurred for most attribute read and write operations. Code is generated to directly access attribute data. Speed is optimized.
In typical models, some attributes are never accessed. MC-3020 detects this situation and omits the implementation of attribute data elements that are never accessed. Unused data is optimized away.
Associations are optimized by storing a copy of the instance handle as extended attribute data. This optimization is implemented between sub/super-types as well.
As with data attribute elements, MC-3020 optimizes away unused referential attributes. Relate, unrelate (link and unlink) and association traversal operations are optimized for low overhead. These operations are performed directly on instance data when appropriate avoiding the generation and associated run time overhead of function calls.
The translated state models are optimized for speed. State transitions and action dispatches execute in constant time. The state event matrix is implemented as a two dimensional array. Rows represent states; columns are indexed by event to obtain the transition.
Actions are translated into functions associated by name and packaging with the class containing the state model containing the state action.
Adherence to Shlaer-Mellor event rules is assured in the generated code. Centralized event queues order events for the entire system.
Prioritized events can be marked by the user. 256 priority levels are provided.
Creation events are recognized and treated differently from non-creation events. The model compiler will create an instance of the class before the event is delivered. The event will cause a transition into the creation state and execution of the associated action.
Domain functions (bridges) and operations are listed together, because MC-3020 treats them with a great deal of symmetry. Domain functions and operations translate into C function invocations. Any number of arguments can be passed.
Domain functions (synchronous services) are supported between domains. Events across bridges are not allowed.
MC-3020 generates bridge and operation frameworks. These frameworks provide the entire invocation interface. A comment is provided to guide the user in where to insert implementation code. These skeletons will compile with or without inserted user code. However, the bridge must be declared to the generation system and the bridge must be wired. See Chapter 4, Marking for details on how to accomplish this.
These are the unclassified features.
Marking allows Nucleus BridgePoint Model Verifier flavored initialization objects to be used for system initialization. In addition, several initialization objects can be defined in the model and only one marked to generate code.
Various stylistic and implementation conventions are centralized and documented to be easily controlled by the software architect. Generated file names, directory structure, coding conventions and even coding style can be dialed in by the user. (Look for fule files with the word ``name'' in the file name.)
See release notes for most recent restrictions and limitations.
No dynamic memory allocation. System storage space for all instances is pre-allocated at start-up. This implies marking the OIM to define the maximum number of instances needed for each class. Note that MC-3020 intelligently determines rational defaults for instance and event populations. Sophisticated analysis is performed to size instance, event and queue populations across multiple domains. Marking is used to dial these in tightly.
Some platforms have no real time clock. Therefore date and time may not be available in standard Gregorian or Caesarian form.
State machines are optimized for speed rather than space.
Events across bridges are not allowed.
Navigations of composed associations must explicitly use the ``real'' (non-composed) association formalizations.
Association conditionality is not enforced by the model compiler.
Actions may not leave identifying attributes inconsistent beyond the end of any action.
MC-3020 attempts to optimize select any [inst_ref] from instances of [key_letters] where [where clause] for code size when the where clause is checking for equality of the identifier. Future versions of MC-3020 may provide advanced (hashed) searching techniques to optimize the blind selections for speed. In MC-3020, certain limitations apply to the selection optimization when unnecessary parentheses are used in the where clause expression. To guarantee the best optimization, avoid unnecessary parentheses in where clauses.
Blind selections following a create and in the same scope as the create may not see the newly created instance in the extent.
create object instance of keyletters (create with no return value) is allowed only when the identifier of class keyletters is of type unique_ID.
The implementation of string expressions is somewhat inelegant. Strings in expressions are limited to simple binary operations. For example
company = "Mentor" + "Graphics" + "Corp.";
results in a compilation error. The alternative,
company = "Mentor" + "Graphics";
company = company + "Corp.";
must be used to work around this shortcoming.
There is no support for ``N to N + 1'' release compatibility. Changes to a model result in changes in the code, including event numbers, state numbers, etc. The registration theme is introduced to pave the way for future N+1 release capability.
The MC-3020 build process has been integrated with Nucleus BridgePoint Model Debugger version 7 and Nucleus EDGE, the Embedded Developers Graphical Environment. EDGE is based upon the Eclipse framework. The use of MC-3020 in this environment is described in this section.
MC-3020 can now be run from inside of Nucleus BridgePoint Model Builder/EDGE. Nucleus BridgePoint Model Builder version 7 now runs within an Eclipse environment. This environment provides excellent flexibility to integrate tools together. Eclipse is open and easy to modify. EDGE is the name of the Eclipse environment as customized for xtUML and embedded development.
Read the user guides for Nucleus BridgePoint Model Builder version 7 and view the online documentation from within EDGE.
All of the marking capabilities of MC-3020 are available from within the EDGE user interface.
Following the instructions when creating a New Project will result in all of the model compiler related marking files will be present in the project. These files and folders are described in more detail below.
The files for a project reside within the project folder. All of the files having to do with the project exist within this folder (or are linked into this folder using Eclipse links). Some of the files and folders in the project are part of the model compilation and code generation process. The gen and src folders in the project are used by the model compiler.
All of the marking files for a project will be found in the gen folder. These files can be edited by double-clicking on the file or by right clicking and opening the file for editing. Note that the marking files end with the file extension .mark. System level marking files include bridge.mark, datatype.mark, registry.mark and system.mark.
The domain level marking files are prepended with the name of the xtUML model (domain) with which they are associated. There will be a class marking file [model]_class.mark, a domain marking file [model]_domain.mark and an event marking file [model]_event.mark for each model (domain) in the project.
To supply marking to the code generation process, edit the marking files. Chapter 4, Marking explains the markings available to control the code generation of MC-3020
The code generation process creates a folder called code_generation in the gen folder. The is the generation workspace and is largely a temporary ("scratch") work area for the model compiler. It will be deleted before new code generation begins. The code_generation folder contains the files and folders that users of MC-3020 versions 3.3 and before are accustomed to seeing.
After code generation runs to completion, the generated source code will be copied into the src folder of the project. If running with Nucleus BridgePoint Model Debugger marking enabled, an XML file for each debugged model will also be copied into this folder.
In some circumstances it is desirable to replace code generated by MC-3020 with code supplied by the user. This is often the case with the timer subsystem (TIM) in TIM_bridge.c and almost always the case with the system user callouts (sys_user_co.c and sys_user_co.h). In these cases, replacement source files must be supplied to the code generation process.
To supply user source code that will replace files of the same name generated by MC-3020, place the source files (.c and .h) in the gen folder within the project folder. When the code generation process runs, the supplied files will be copied in to overwrite/replace those generated by the model compiler.
MC-3020 supports the integration of user supplied source code (.c and .h files) and libraries (.a and .dll). To add additional source code and libraries to the generated and compiled system, simply deposit files into the src folder within the project folder.
EDGE will detect these source files and libraries anywhere within the project except within the gen folder and within the models folder. It is recommended that the user create sub-folders within the src folder to organize the added source code and libraries.
Note that the naming conventions used by the source code and libraries being added should differ substantially from the naming conventions used in the MC-3020 generated code. Careful naming will avoid name collisions and conflicts between generated code and added code.
To start the code generation process, right click on the project and select "Build Project". This will cause code generation (MC-3020 execution) to begin. All models in the project will be translated. The generated source code will be copied into the src folder in the project.
It is also possible to begin code generation by pressing the "Build All" button on the Eclipse toolbar or by selecting one of "Build All", "Build Project" or "Clean..." from the Eclipse "Project" menu. Note that these alternative methods of starting the build will also start a build for all other open projects within the Eclipse workspace. Be sure this is what is intended when using these methods to begin the build process.
Output code generation logging will appear in the Eclipse console.
To stop code generation, press the square, red stop button in the console view during code generation.
Code compilation will occur after code is generated. See the section called “Compiling” below.
MC-3020 provides a rich set of ``knobs and dials'' that can be spun to optimize and customize the code generation process. This chapter gives instructions on the use of these marking parameters.
Formerly termed "coloring", marking is the primary means of steering and controlling the code generation process. When there is more than one software architecture element into which an xtUML element can be translated, marks are used to indicate which translation to make. The name ``mark'' comes from the visualization of using a highlighter pen to mark each element that has a particular property. Marks are used to direct the translation to select one of two or more branches in the translation rules. It is through marking that design decisions are injected during the translation process.
An example of the type of design information that is specified through marking is the mapping of analysis data types into implementation (e.g., C) data types. Clearly, this is information that does not belong in either the xtUML models or the model compiler itself.
Marking capability can be provided in many different ways. In MC-3020 marking input is communicated to the model compiler through marking files read during translation. Other marking input is provided through key words placed in artifact description with Nucleus BridgePoint Model Builder. This is similar to the way enumerations are identified to Nucleus BridgePoint Model Builder. Marking input steers the code generation by selecting between alternatives during code generation.
Some marking is mandatory; some marking is optional. In the case of optional marking, the model compiler will assume reasonable defaults. In the case of mandatory marking, the model compiler is not capable of divining the intent of the user and will abort the translation.
Domain Registration is a reflection of the Shlaer-Mellor domain chart. All domains are declared in the registration marking file.
The registry.clr marking file is used to register all the domains, both xtUML and realized, which will be used to construct system load images. Domain registration is a mandatory marking file. Domains are registered by providing a registered name in correlation with a repository name. Registration of domains provides indirection between the name space of Nucleus BridgePoint Model Builder and the generation and build environments. Registration provides a clean break between the naming choices of the analysts and model maintainers and the back end code generation. This conveniently allows the same model to be named differently in different repositories, or for versioning of models to be independent of versioning of the generation.
To register the domains in the system, edit registry.clr.
Marking is specified via rule file function invocation(s) in this file. A function invocation statement must be specified on a single line. All indicated function input parameters must be supplied.
All quoted string parameters are case sensitive.
Comments in this file start with ".//".
Do not leave any blank lines in this file.
Registered domain names and numbers must be unique.
Domain ID number zero (0) is reserved for the model compiler.
To indicate to MC-3020 that an xtUML domain is part of a system build, provide the following rule file function invocation in the registry.clr marking file.
RegisterOoaDomain( | string | "repository_name", |
| string | "registered_name", | |
| integer | registered_id); |
Where the input parameters are:
| repository_name | xtUML domain repository name |
| registered_name | registered domain name |
| registered_id | registered domain number |
Example 4.1. Example of xtUML Domain Registration
.invoke RegisterOoaDomain( "autosampler", "AS", 69 )
To indicate to the model compiler that a realized (non-xtUML) domain is part of a system build, make the following rule file function invocation, one for each realized domain, from the registry.clr marking file.
RegisterRealizedDomain( | string | "description", |
| string | "registered_name", | |
| integer | registered_id); |
Where the input parameters are:
| description | optional textual description of the realized domain (Use "" as a default description.) |
| registered_name | registered domain name |
| registered_id | registered domain number |
Example 4.2. Example of Realized Domain Registration
.invoke RegisterRealizedDomain( "", "CARPIO", 101 )
The registry.clr described above declares the names and types of the domains on the domain chart to be included in the system build. To round out the manifestation of the domain chart, bridges are wired together in the bridge.clr file. The word ``wiring'' is used as an analogy to an electrical circuit. After the components of a circuit are placed, the interconnecting wires must be defined. In like manner, domains on a domain chart are interconnected with bridges. These bridges must be declared in the bridge marking file.
The bridge.clr marking file is used to wire together all the domains, both xtUML and realized. This marking file is used to specify inter-domain bridge signatures to the model compiler's translation engine. All references to a domain name in this file correspond to the registered domain name, and not the Nucleus BridgePoint domain repository name.
Beginning with version 2.0 of MC-3020 there are two ways to wire bridges between xtUML domains. The new method wires bridges using Synchronous Services (Domain Functions); the old way uses Bridge Objects (FBOs). Synchronous Service bridges are preferred, because they provide a cleaner interface.
To wire the domains in the system together, edit bridge.clr.
Marking is specified via rule file function invocation(s) in this file. A function invocation statement must be specified on a single line. All indicated function input parameters must be supplied.
All quoted string parameters are case sensitive.
Comments in this file start with ".//".
Do not leave any blank lines in this file.
Synchronous services, also known as domain functions, provide a convenient home for a reusable package of processing requiring no state. Synchronous services can be invoked from within the domain or from without. Bridging is only concerned with connecting the interface to external entities.
WireSynchServiceOoaBridge( | string | "initiating_dom", |
| string | "ee_key_letters", | |
| string | "recip_domain"); |
Where the input parameters are:
| initiating_dom | registered name of the initiating domain |
| ee_key_letters | key letters of the external entity in the initiating domain |
| recipient_domain | registered name of the recipient domain |
Example 4.3. Wiring Between xtUML Domains
.invoke WireSynchServiceOoaBridge( "HOME", "AWAY_EE", "AWAY" )
Use this invocation to declare the interface between two xtUML domains using a bridge object. [Note that this marking option is provided for backwards compatibility reasons only. Domain function (synchronous services) should be used for all bridging purposes.] The term initiating domain refers to the xtUML domain which contains the external entity (EE) against which bridge calls to the recipient domain are made. The term recipient domain refers to the xtUML domain which contains the ``Funky Bridge Object'' (FBO). The FBO is a pseudo state model that provides the implementation interface for the EE in the initiating domain.
WireOoaBridge( | string | "init_dom", |
| string | "ee_key_letters", | |
| string | "recip_domain", | |
| string | "fbo_key_letters"); |
Where the input parameters are:
| init_dom | registered name of the initiating domain |
| ee_key_letters | key letters of the external entity in the initiating domain |
| recip_domain | registered name of the recipient domain |
| fbo_key_letters | key letters of the funky bridge object (FBO) in the recipient domain |
Example 4.4. Wiring Between xtUML Domains Using Bridge Object
.invoke WireOoaBridge( "HOME", "AWAY_EE", "AWAY", "AWAY_FBO" )
Use this invocation to declare the interface between an xtUML domain and realized (non-xtUML) domain. MC-3020 will generate an interface framework source file that represents a compilable definition of the implementation interface. This bridge skeleton will be generated into the system/skel directory. It can be copied to the system/user/source directory and modified (if desired) to invoke user supplied code.
WireRealizedExternalEntity( | string | "ooa_domain_name", |
| string | "ee_key_letters", | |
| string | "realized_domain_name", | |
| string | "method_prefix", | |
| string | "include_file"); |
Where the input parameters are:
| ooa_domain_name | registered name of xtUML domain (``*'' means any domain.) |
| ee_key_letters | key letters of the external entity in the xtUML domain |
| realized_domain_name | registered name of realized domain |
| method_prefix | prefix to be prepended to the bridge process method name used in the Nucleus BridgePoint action language |
| include_file | name of the header file to include for the realized domain |
Example 4.5. Wiring a Realized Domain
.invoke WireRealizedExternalEntity("ODMS", "PIO", "PIO", "PIO", "PIO_bridge.h")
As of version 5.0 of Nucleus BridgePoint Model Builder, domain functions make the cleanest interfaces between xtUML and non-xtUML domains. Using domain functions for bridging is preferred over the previous (although still supported) bridge object strategy. MC-3020 will automatically generate interface declaration files into the system/skel directory for all domain functions in the system. There is no requirement to mark the domain functions in any way, the declaration occurs automatically. Use these .h declaration files for inclusion into realized code to declare the signatures of interfaces into an xtUML domain(s).
MC-3020 allows domain function bridges to be marked as callable from interrupt handlers or other asynchronous sources (such as other tasks, signal handlers, etc). Synchronous services marked here will generate a short stub interface that will defer execution of the bridge to be between dispatched state actions. When a domain function marked as safe for interrupts is invoked, its action body is posted to a queue for dispatch after any currently running state action completes. This guarantees architecture data mechanism integrity while maintaining application data access set consistency.
Synchronous services marked safe for interrupts cannot return data. They must be of return type void. However, core data type data can be passed into these domain functions. Such data is packaged safely at interrupt level and then unpacked in the bridge service.
To indicate to the model compiler that a domain function serves as a bridge operation which may be invoked in a manner safe for invocation from an interrupt handler or other asynchronous activation (one for each domain function):
TagSyncServiceSafeForInterrupts(string "domain", string "sync_service");
Where the input parameters are:
| domain | registered xtUML domain name |
| sync_service | is name of the domain function being tagged as safe for calling. |
Example 4.6. Tagging Interrupt Bridges
.invoke TagSyncServiceSafeForInterrupts( "ILB", "kick_start" )
MC-3020 allows "funky bridge objects" to be marked as callable from interrupt handlers or other asynchronous sources (such as other tasks, signal handlers, etc). This feature is available on bridge objects for continued support of now obsolete functionality. Using domain functions for bridges is preferred. Use of "funky bridge objects" is discouraged.
Bridge object actions marked safe for interrupts cannot return data. They must be of return type void. Bridge object actions marked safe for interrupts cannot pass parameters. Use synchronous services (domain functions) if passing data is desired.
To protect data structures for Interrupt Safe Bridges, interrupts are disabled for a very few instructions. The method of disabling interrupts varies from target to target and from compiler to compiler. Therefore, the responsibility of defining the specific flavor of EI/DI instruction is left to the user. The marking functions UserEnableInterrupts and UserDisableInterrupts are are provided for specifying the specific way interrupts are enabled and disabled with your specific target.
To define the instruction sequence for enabling and disabling interrupts, edit the system-level user defined rule file sys_functions.arc.
Bit fields provide a means of packing many small value attributes into single words of computer storage. MC-3020 allows attributes to be stored as bit fields in ANSI C structs.
Attributes are marked with Nucleus BridgePoint Model Builder. The string BIT_WIDTH: n is placed within a comment as the first line of the attribute description. ``n'' is the width in bits required to store the attribute.
It should be understood that bit fields are inherently somewhat less portable than most other ANSI C constructs. Dependence upon ``Endian-ness'', memory models and other compiler/target implementation specifics is not uncommon. Use bit fields with care.
The maximum width for a bit field member attribute is 16 bits. Bit field members are of type unsigned int.
MC-3020 provides a means of establishing the base memory address of class instance collections (extents). Within Nucleus BridgePoint Model Builder the string BASE_ADDRESS: n is placed within a comment as the first line of the class description. ``n'' is the memory address anchoring the start of the collection of class instances.
Two user defined rule file functions at the system-level define how this number (``n'') will appear in the generated code. One function (UserFixExtentBaseBegin) is used to insert code before the definition of the class instance collection memory. Another function (UserFixExtentBaseEnd) is used to insert code directly after the data definition. This combination of functions will allow a pragma around the data definition.
To define the instruction sequence for fixing the class extent, edit the system-level user defined rule file sys_functions.arc.
Nucleus BridgePoint allows the user to define special data types. Marking is used to define the precision of these data types. This is particularly useful to reduce the storage (say from 16 or 32 bits to 8 bits) of class attributes when the ranges of the attributes are known to be limited. User defined types which are also enumerations are included in the category of types that can be controlled. The datatype.clr provides the means for specifying these data type specializations.
Note that core types can be marked with this function as well as user defined types (UDTs). For example, the core type real can be marked to generate "double" precision.
The return data type for bridges and operations can be user defined data types. Empty operations can be used as a sort of variable declaration in conjunction with UDT precision tagging.
Mark TagDataTypePrecision may only be used for application analysis data types which are derived from either Nucleus BridgePoint core data types of integer or real. Also, user defined types that are enumerations can be marked. Such data will have core data type string, but will serve as integers. Attempting to use this mark with any other core data type will result in a fatal marking error (translation aborted). This restriction applies equally to both domain specific and system wide use of this mark.
Precision tag tagged_name may be any standard C/C++ integer or real variable type. For example, unsigned char, long long, double, etc. POSIX types are also accepted, such as uchar_t, ulong_t, etc.
When an analysis class is instantiated, the default is to initialize attributes of core type integer to 0, and attributes of core type real to 0.0 (declared as code type float). Tag initial_value may be used to re-define the default initialization value.
Casting may be used in the tag, such as "(unsigned)EACCESS", but should be used only with careful system level discretion.
No translation time error checking is performed on initial_value. Bogus tags such as "@*#$" will only be caught during compilation.
Invoke TagDataTypePrecision to indicate to the model compiler the precision of a user defined data type defined in the Nucleus BridgePoint Subsystem Partitioning Model (SPM) domain data editor.
TagDataTypePrecision( | string | "domain", |
| string | "dt_name", | |
| string | "tagged_name", | |
| string | "initial_value"); |
Where the input parameters are:
| domain | registered domain name (Use ``*'' to indicate a system wide data type to be applied to all domains containing the user data type.) |
| dt_name | name of the data type as known in the application analysis |
| tagged_name | name of the data type as known in generated implementation code (e.g. the precision of the data type) |
| initial_value | optional specification of the default value for the data type (Use "" for the architectural default (e.g. 0 for integer, 0.0 for real.) |
Example 4.7. Data Type Precision
.invoke TagDataTypePrecision( "MyDom", "Octet", "uchar_t", "" )
.invoke TagDataTypePrecision( "MyDom", "FunkyReal", "double", "666.999" )
.invoke TagDataTypePrecision( "*", "SysWideLong", "long int", "-1" )
To allow for pointer reference to arbitrarily shaped masses of data, user-defined data types can be implemented as pointers. After marking a UDT as a pointer, the pointer typed data can be passed into and returned from operation and bridge operations. Marking is used to tag pointer types. The datatype.clr provides the means for specifying these pointer data type specializations.
Invoke MapDataTypeAsPointer to indicate to the model compiler that a user defined data type defined in the Nucleus BridgePoint Subsystem Partitioning Model (SPM) domain data editor shall be implemented as a pointer.
MapDataTypeAsPointer( | string | "domain", |
| string | "dt_name", | |
| string | "pointer_type", | |
| string | "include_file"); |
Where the input parameters are:
| domain | registered domain name (Use ``*'' to indicate a system wide data type to be applied to all domains containing the user data type.) |
| dt_name | name of the data type as known in the application analysis |
| pointer_type | name of the pointer data type as known in generated implementation code. |
| include_file | optional include file which declares the implementation type of `pointer_type'. |
Example 4.8. Mapping Pointer Types
.invoke MapDataTypeAsPointer( "MyDom", "DataPacket", "char", "" )
.invoke MapDataTypeAsPointer( "DomA", "AcmeType", "SomeStruct_t", "legacy.h" )
In analysis models, enumerated types defined within Nucleus BridgePoint Model Builder (using the Data Type editor available in BP5.0+) have no initial (uninitialized) value. With marking, it is possible to explicity define this value for uninitialized enumeration variables. The datatype.clr provides the means for specifying this starting value.
To indicate to the software architecture that the uninitialized enumerator of an enumeration (defined in the Nucleus BridgePoint Subsystem Partitioning Model (SPM) domain data editor) shall have a value other than the default, use the following invocation:
TagUninitializedEnumerationValue( | string | "domain", |
| string | "enumeration", | |
| string | "value"); |
Where the input parameters are:
| domain | registered domain name (Use ``*'' to indicate a system wide data type to be applied to all domains containing the enumeration data type.) |
| enumeration | is the name of the enumration data type as known in the application analysis. Use ``*'' to indicate all enumerations domain or system wide. |
| value | a string containing the value to be assigned to the unitialized enumerator |
Example 4.9. Specifying a Value for the Default Uninitialized Enumerator
Domain specific:
.invoke TagUninitializedEnumerationValue( "MO", "wattage", "4" )
All Enumerations in Domain:
.invoke TagUninitializedEnumerationValue( "MO", "*", "0x40" )
System Wide:
.invoke TagUninitializedEnumerationValue( "*", "wattage", "0x20" )
All Enumerations in All Domains:
.invoke TagUninitializedEnumerationValue( "*", "*", "100" )
In some target environments, it may be desirable to select the integer values of the individual enumerators in an enumeration. MC-3020 enables the assigning of discrete values to one or more of the enumerators in an enumeration.
Invoke TagEnumeratorDiscreteValue to indicate to the model compiler that a user defined enumeration data type enumerator (defined in the Nucleus BridgePoint Subsystem Partitioning Model (SPM) domain data editor) shall have a value other than the default.
TagEnumeratorDiscreteValue( | string | "domain", |
| string | "enumeration", | |
| string | "enumerator", | |
| string | "value"); |
Where the input parameters are:
| domain | registered domain name (Use ``*'' to indicate a system wide data type to be applied to all domains containing the enumeration data type.) |
| enumeration | is the name of the enumration data type as known in the application analysis. Use ``*'' to indicate all enumerations domain or system wide. |
| value | a string containing the value to be assigned to the specified enumerator |
Example 4.10. Specifying Enumerator Values
Domain specific:
.invoke .invoke TagEnumeratorDiscreteValue( "MO", "wattage", "low", "4" )
.invoke TagEnumeratorDiscreteValue( "MO", "wattage", "med", "0x20" )
System Wide:
.invoke TagEnumeratorDiscreteValue( "*", "wattage", "high", "0x40" )
There are characteristics of the system as a whole that may need to be controlled during translation. Several constants define resource allocation and generation constraints. Some constants allow for ``tweaking'' the system to obtain optimal performance in terms of size or speed. These constants can be marked as the system architect desires.
Marking at the system level is provided by a set of marking files in the system directory in the build area. The file system.clr provides the means for specifying these system constants.
Within system marking, the flavor of collection containers can be specified. Different collection flavors provide optimizations for space or speed.
MC-3020 provides for tasking/threading using the capabilities of the target operating system (OS) or real-time operating system (RTOS). An example of an RTOS is the Nucleus PLUS real-time operating system.
To cause MC-3020 to generate multi-tasking/threading code, invoke the following marking function. Pass it arguments that specify the type of multi-tasking environment and whether or not to serialize all action processing (across all tasks).
To enable tasking in the generated system:
EnableTasking(string flavor, string serialization, integer tasks);
Where the input parameters are:
| flavor | is the type of tasking environment being integrated (such as "POSIX" or "Nucleus"). |
| serialization | is set to "serialize" to force all action across all tasks to be run sequentially. Note that serializing the action processing reduces data access contention, but can severely reduce the multi-tasking performance of the generated system. |
| tasks | is the number of tasks/threads in the xtUML generated system. |
Example 4.11. Enabling Tasking/Threading
.invoke EnableTasking( "Nucleus", "", 4 )
.invoke EnableTasking( "POSIX", "serialize", 2 )
Some flavors of tasking/threading allow for differing execution priorities of tasks or threads. MC-3020 allows the priorities of tasks to be set through marking. In systems that support explicit prioritization of tasks, each task (of the number specified in EnableTasking) can have a priority assigned. Use the following marking function to set the priority for each task.
To specify the priorities of tasks/threads:
SetTaskPriority(integer task_number, string priority);
Where the input parameters are:
| task_number | is the number of the task starting with zero and going to one less than the number specified in EnableTasking. |
| priority | is a string representing the priority level of the task. The string type of this argument allows for symbolic as well as numeric representation of task priority. This representation will be a function of the tasking environment being integrated. |
Example 4.12. Setting Task/Thread Priority
.invoke SetTaskPriority( 0, "100" )
.invoke SetTaskPriority( 3, "high" )
MC-3020 tries to use relatively safe methods of manipulating strings. The ``n'' library functions are used (strncpy, strncpy, strncat) rather than their more dangerous (as regards buffer overruns) counterparts.
To specify the maximum length of a string in the system:
TagMaximumStringLength(integer max_len);
Where the input parameters are:
| max_len | is the longest string that will be manipulated by the system. Truncation will occur beyond this length. |
Sets of instances are collected for various AL operations. Relationships with multiplicity MANY require set container mechanisms at the implementation level to manage the collection of related instances. The maximum number of instances allowed in such collections can be controlled with a mark.
To specify the maximum ``relationship extent'' size in the system:
TagMaximumRelationshipExtentSize(integer value);
Where the input parameters are:
| value | represents the highest number of instances allowed in a MANY relationship. |
Another operation requiring set manipulation is a selection (SELECT MANY) that may result in a collection of multiple instances.
To specify the maximum ``selections extent'' size in the system:
TagMaximumSelectionExtentSize(integer value);
Where the input parameters are:
| value | represents number of containers that will be pre-allocated for AL SELECT statements. |
Collections are maintained with a mechanism of one type or another. With this mark, the type desired for a particular translation can be specified. The default is singly linked list container nodes. Doubly linked list containers can be selected as flavor 20. Doubly linked lists allow for faster deletion of instances in exchange for an additional pointer size (for ``prev'') per container in the system.
To specify the flavor of the collection nodes:
TagCollectionsFlavor(integer value);
Where the input parameters are:
| value | a numerical representation of a specific type and strategy of collections container. |
MC-3020 attempts to dynamically calculate reasonable and safe values for queue depths within the event generation and delivery mechanism. However, for optimization purposes the user may wish to override these values.
To override the compiler calculated maximum queue depth for the self directed event queue:
TagMaximumSelfDirectedEvents(integer value);
Where the input parameters are:
| value | which is the hard-coded depth of the self-directed event queue. |
To override the compiler calculated maximum queue depth for the instance directed event queue:
TagMaximumNonSelfDirectedEvents(integer value);
Where the input parameters are:
| value | which is the hard-coded depth of the non- self-directed event queue. |
A mark is provided so the system analyst can direct the model compiler to increase or decrease the timer queue used to manage multiple pending xtUML timers (delayed events). To override the compiler calculated queue depth for pending xtUML timers:
TagMaximumPendingOoaTimers(integer value);
Where the input parameters are:
| value | represents is the hard-coded maximum number of timers that may be pending expiration at any point in time. |
Use this mark to expand or reduce the depth of the queue used to interleave ``asynchronous'' bridge operations between state actions. The default will be a system divined value that should be relatively safe in most cases.
To hard-code the depth of the interleaved bridges queue:
TagMaximumInterleavedBridges(integer value);
Where the input parameters are:
| value | represents the maximum queue depth for safe bridge operations that are interleaved between state actions (to maintain data access set consistency). |
Use this mark to define how many bytes of argument data come in across an interleaved bridge operation. The default is 8.
To hard-code the width of the interleaved bridge argument path:
TagInterleavedBridgeDataSize(integer value);
Where the input parameters are:
| value | represents the maximum number of bytes of arguments that an interleaved bridge may receive during an invocation. |
This mark works in conjunction with the Nucleus BridgePoint Model Debugger. By invoking this marking interface, target debug code is generated. Note that a significant amount of tooling code is generated in line with functional code. A debug version of the target image will run successfully on the development host computer or a socket- capable target with sufficient memory (RAM).
To enable the generation of debug code for use with Nucleus BridgePoint Model Debugger:
TagModelDebuggingOn(void);
This mark is used to specify the maximum number of instances and links that can be queued waiting to be flushed to non-volatile storage (NVS). As instances and links become "dirty" they get queued to NVS. When PERSIST::Commit is called these queues are flushed.
To change the default depth (128) to something different:
MarkPersistenceCacheDepth(integer instance_depth, integer link_depth);
Where the argument:
| instance_depth | is the number of instances that can be queued waiting to be flushed to non-volatile storage (NVS). |
| link_depth | is the number of links that can be queued waiting to be flushed to non-volatile storage (NVS). |
Example 4.23. Changing Persistence Cache Queue Depth
.invoke MarkPersistenceCacheDepth( 16, 32 )
.invoke MarkPersistenceCacheDepth( 1000, 500 )
Within MC-3020 domain level customizations can be applied. The marking file domain.clr is the place to tag the customizations.
Initialization functions provide the analyst a means to specify preexisting instances for production bring-up. They also serves to set up test scenarios. Domain functions also can be activated/deactivated with marking. Use domain functions instead of initialization objects. Through marking, specific initialization functions can be chosen for system bring-up while others are marked (or erased as the case may be) as not to be translated.
Marking a function for initialization does not change the function. The function remains available for invocation by any of the action semantics that could normally call it. If more than one function is tagged as an initialization function, each will be invoked. The order of invocation is alphabetical by function name.
Identify a function in the domain to be used as the an initialization function by invoking the following rule file function in the domain.clr marking file.
TagInitializationFunction(string "function_name");
Where the input parameters are:
| function_name | is the name of the domain function (synchronous service) to be invoking during bring-up. |
Example 4.24. Tagging Initialization Functions
.invoke TagInitializationFunction( "CreateAndPopulate" )
Initialization objects represent an obsolete (although still supported) means for the analyst to specify preexisting instances for production bring-up. All of the functionality of the obsolete TagInitializationFunction is now provided in domain functions which can activated/deactivated and marked for initialization. Use domain functions instead of initialization objects. See TagInitializationFunction.
MC-3020 can be directed to skip code generation for classes marked with the TagExcludeObjectFromCodeGen invocation. Combined with selective marking of initialization functions, class exclusion allows for a simple method of providing multiple bring-up scenarios. Exclude a class from code generation by marking it thusly:
TagExcludeObjectFromCodeGen(string "key_letters");
Where the input parameters are:
| key_letters | key letters of the excluded class |
To indicate to the model compiler that all classes in a specified subsystem should be excluded from implementation code generation, use the following invocation (one for each excluded subsystem):
TagExcludeSubsystemFromCodeGen(string "subsystem");
Where the input parameters are:
| name | name of the excluded subsystem |
Example 4.26. Tagging Excluded Subsystems
.invoke TagExcludeSubsystemFromCodeGen( "MyVerifierUnitTests" )