System Level Marks

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.

Specifying a System Build Configuration

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" )
        


Enabling Multi-Tasking

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 )
        


Establishing Multi-Task Priority

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.9. Setting Task/Thread Priority

.invoke SetTaskPriority( 0, "100" )
.invoke SetTaskPriority( 3, "high" )
        


Maximum String Size

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.

Example 4.10. Defining String Length

.invoke TagMaximumStringLength( 16 )
        


Controlling Collection Sizes

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.

Example 4.11. Max Relationship Extent

.invoke TagMaximumRelationshipExtentSize( 8 )
        


Managing Selection Collections

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.

Example 4.12. Max Selections Extent

.invoke TagMaximumSelectionExtentSize( 12 )
        


Changing the Flavor of Collections

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.

Example 4.13. Collection Node Type Selection

.invoke TagCollectionsFlavor( 20 )
        


Limiting/Extending Event Queues

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.

Example 4.14. Self-Directed Queue Depth

.invoke TagMaximumSelfDirectedEvents( 3 )
        


Limiting/Extending NonSelf 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.

Example 4.15. Instance Directed Queue Depth

.invoke TagMaximumNonSelfDirectedEvents( 5 )
        


Timer 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.

Example 4.16. Pending xtUML Timers

.invoke TagMaximumPendingOoaTimers( 6 )
        


Simulated 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();
 

Example 4.17. Establish Simulated Time Base

.invoke MarkSimulatedTime()
        


Interleaved Bridges

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).

Example 4.18. Interleaved Bridges Queue Depth

.invoke TagMaximumInterleavedBridges( 4 )
        


Interleaved Bridge Data

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.

Example 4.19. Interleaved Bridge Argument Data

.invoke TagInterleavedBridgeDataSize( 2 )
        


Marking Persistence Cache Queue Depth

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 )


Marking Dynamic Memory Allocation On

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.

Example 4.21. Using Dynamic Memory Allocation

.invoke TagDynamicMemoryAllocationOn( 2 );


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.

Marking State Save

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.

Example 4.22. Configuring State Save

.invoke MarkStateSave( 1024 );


SystemC-specific Markings

Mark Port Type

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" );


Mark All Ports Polymorphic

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.

Example 4.24. Treat All Ports as Polymorphic

.invoke MarkAllPortsPolymorphic();


Mark Component As Channel

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" );


Mark Interface Prefix

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" );


C++ Template Feature

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 package_name and the parent of the specified component_name. If component_name is a direct child of package_name, leave this field empty. Only use when an extra layer of nesting information must be supplied.

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" )