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.
system.mark
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 allows the user to select a package of components to be used when generating the code for the model. Such a package is called a "system configuration".
A model may contain more components than are needed/required for a particular working configuration of a system. Often a model will include additional components used for testing. A user may want multiple versions of components.
To assemble a system configuration in BridgePoint, the user builds a component diagram in a package from component references and wires them together as desired. Multiple system configurations packages may exist. Each configuration can be different and use only a subset of the components defined in the model.
When a component package is marked as the system configuration, code will be generated for components contained in this package and referred to from this package. Components not contained in this package and not referred to from this package will be excluded from code generation.
To mark a package as containing the system configuration:
MarkSystemConfigurationPackage( | string system_package) ; |
Where the input parameter(s) are:
system_package | is the name of the package containing the components wired together for a system build. |
Example 4.7. Marking the System Configuration Package
.invoke MarkSystemConfigurationPackage( "system1" ) .invoke MarkSystemConfigurationPackage( "system2" )
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 ("POSIX", "Nucleus", "Windows" or "SystemC"). |
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.8. Enabling Tasking/Threading
.invoke EnableTasking( "Nucleus", "", 4 ) .invoke EnableTasking( "POSIX", "serialize", 2 ) .invoke EnableTasking( "Windows", "", 3 ) .invoke EnableTasking( "SystemC", "", 1 )
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 |
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.9. 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. |
Simulated Time in MC-3020 implements a form of discrete event simulation. In simulated time mode, no external clock is read. The application runs as fast as the architecture allows. The time base is derived from timers used to cause functional delays in the modeled application.
SystemC and BridgePoint Verifier both support modes where time is "simulated". In these environments, "wall clock" is not used. The timers in the system advance the system time in sequence of expiration. This is convenient for very fast (short-running) and for very slow (long-running) applications.
To switch from the default wall clock time base to simulated time:
MarkSimulatedTime( | ) ; |
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 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.20. Changing Persistence Cache Queue Depth
.invoke MarkPersistenceCacheDepth( 16, 32 )
.invoke MarkPersistenceCacheDepth( 1000, 500 )
By default, MC-3020 statically allocates instance data and all mechanistic collection containers. This is great for many deeply embedded applications. However, some applications require the flexibility of dynamically allocated storage. In such an application, the number of instances of elements from the xtUML model file is not predictable. Here, the application needs to be able to allocate more memory when the statically allocated memory runs out.
To turn on and use dynamic memory allocation:
TagDynamicMemoryAllocationOn( | integer additional_instances) ; |
Where the argument:
additional_instances | is the number of additional instances to allocate each time space for new instances runs out. |
When dynamic memory allocation is marked off, system user callout functions are called when a request is made to allocate resources beyond what is statically available.
State Save is a feature that captures information present in the running system that may be useful for analysis and debugging purposes. Upon a state save trigger, information is collected into a buffer of a size specified through marking (this mark).
From the application model, state saves are controlled through bridges on an external entity named 'state save' (with key letters 'SS'). A default version of this external entity is supplied with the model compiler. It is expected that users will modify the state save external entity realized code.
To enable state save capability and specify the size of the buffer:
MarkStateSave( | integer buffer_size) ; |
Where the argument:
buffer_size | is the size expressed in bytes of the buffer where state save information will be stored. |
By default, the SystemC model compiler generates basic
sc_interface
ports. The tool also supports
generating TLM ports as well as bit level signals. All ports will be
generated using the given value, so this marking function should
be invoked only once in the marking file. If the marking is invoked
multiple times, the last one processed is used.
Specify the SystemC port type to generate:
MarkSystemCPortType( | string type) ; |
Where the argument:
type | Can be "sc_interface", "TLM", or "BitLevelSignals". Using "sc_interface" causes the code generator to create interface classes that implement the interface using vanilla C++. "TLM" causes the code generator to create interface classes that conform to the SystemC Transaction-Level Modeling paradigm. TLM interfaces provide a means to perform hardware and software module connection and coverification. Using "BitLevelSignals" causes the code generator to create interfaces that correspond to hardware wires in an application model of hardware. It also causes the generation of additional wires "clk" and "rst_X" in components that represent hardware. |
Example 4.23. Setting the Port Type
.invoke MarkSystemCPortType( "sc_interface" );
.invoke MarkSystemCPortType( "TLM" );
.invoke MarkSystemCPortType( "BitLevelSignals" );
An interface port is said to be "polymorphic" when a component exposes (provides or requires) the same interface multiple times. The model compiler treats polymorphic and non-polymorphic ports differently. It generates additional checks to resolve ambiguity when messages are sent through polymorphic ports.
Specify the SystemC port type to generate:
MarkAllPortsPolymorphic( | void) ; |
No arguments.
The SystemC model compiler supports marking individual components as pre-defined SystemC channels.
Components that are marked as pre-defined channels have no internal behavior generated for them by the model compiler. Instead, the implementation is expected to be provided by the referenced include file.
In components that make use of pre-defined channels, the channel declaration is bypassed. In addition, the binding of ports inside the pre-defined channel is bypassed and components that use the pre-defined channel are bound to the pre-defined channel's name instead of the channel generated by the model compiler.
Specify the component as a SystemC channel:
MarkAsChannel( | string package, |
string component, | |
string include file) ; |
Where the arguments:
package | name of the package being marked |
component | name of the component (domain) being marked |
include file | name of the include file containing the channel's implementation |
Example 4.25. Marking a Component as a Channel
.invoke MarkAsChannel( "*", "wait_hs", "my_channel.h" );
The SystemC model compiler supports adding a prefix to the generated names of provided ports, required ports, and channels. Use this marking to set these prefixes on all elements of these types.
Specify the prefixes to use on interface elements:
MarkInterfacePrefix( | string provided_port, |
string required_port, | |
string channel) ; |
Where the arguments:
provided_port | text to add as a prefix on provided port generated names |
required_port | text to add as a prefix on required port generated names |
channel | text to add as a prefix on channel generated names |
Example 4.26. Marking Interface Prefixes
.invoke MarkInterfacePrefix( "proPort", "reqPort", "channel" );
The SystemC model compiler supports marking components and interfaces as reusable paramterized C++ templates.
To avoid ambiguity between components and component references,
users must set the ClassifierName
to a unique
value in the element's Properties. Also, be sure to name ports in a
way that they can all be marked. Do not reuse the same port name when
connecting to different interfaces.
Interface template parameters must be supplied with a default value which is used in the channel signal declarations.
Specify the template parameter information:
MarkComponentWithTemplate( | string package_name, |
string component_name) ; |
MarkInterfaceWithTemplate( | string package_name, |
string interface_name) ; |
AddTemplateParameter( | string package_name, |
string component_name, | |
string type_name, | |
string variable_name, | |
string default_value) ; |
SetTPV( | string package_name, |
string parent_component_name, | |
string component_name, | |
string classifier_name, | |
string port, | |
string variable_name, | |
string value) ; |
Where the arguments:
package_name | Name of the package being marked. |
component_name | Name of the component (domain) being marked. |
interface_name | Name of the interface being marked. |
type_name | Type of the given parameterized variable. |
variable_name | Name of the template variable being set. |
default_value | Default type to apply to the template variable. Interface template parameters must be supplied with a default value which is used in the channel signal declarations. |
parent_component_name | Name
of the component package that is a child of the specified
|
classifier_name | Identifies the unique instance of a component (a component reference) that is the target of the template parameter value (whether for the instance itself or for one of its ports). |
port | Is only used when marking a template parameter value for the usage of an interface (port). If this parameter is empty, then the template parameter value will be applied to the component reference. If this parameter is not empty, then the template parameter value will be applied to the interface usage (port) found on the targeted component reference. |
value | Type to apply to the named template variable. |
Example 4.27. Marking a template parameter
.// for component reference: .invoke MarkComponentWithTemplate( "simtop", "wait_hs" ) .invoke AddTemplateParameter( "simtop", "wait_hs", "class", "T", "rgb_t") .invoke SetTPV( "simtop", "", "wait_hs", "din", "", "T", "abc_t" ) .invoke SetTPV( "simtop", "", "wait_hs", "din", "", "U", "xyz_t" ) .// for interface reference: .invoke MarkInterfaceWithTemplate( "", "wait_out" ) .invoke AddTemplateParameter( "", "wait_out", "class", "T", "rgb_t") .invoke SetTPV( "simtop", "", "filt_top", "i_filt_top", "din", "T", "my_t" ) .invoke SetTPV( "simtop", "", "filt_top", "i_filt_top", "dout", "T", "int" )