[Previous] [Next] [Contents] [Index]


    The Master Library

This chapter covers the following topics:

Note that the Master Library is only used together with the Cadvanced and Cbasic Code Generators. It cannot be used together with the Cmicro Code Generator.

Table of Contents 

Introduction

This chapter describes the source code of the runtime library for applications generated by the SDT Cadvanced/Cbasic Code Generator. Applications generated by the Cmicro Code Generator are not covered.

The chapter covers basically three topics:

  1. The sections File Structure, The Symbol Table, and The SDL Model describe the runtime model for programs generated by the SDT Cadvanced/Cbasic Code Generator.

  2. Mainly it is the data structure used to represent various SDL objects that is discussed, both from the static point of view (the type definitions), and from the dynamic point of view (what information it represents and how it is initialized, changed, and used).

    The full runtime model that is used during simulations (with the monitor) is described. From this model, an optimization is made to obtain an application (not using the monitor). The optimization is discussed under Compilation Switches.
  3. The section Structure of Generated Code contains information about the code generated by the Cadvanced/Cbasic Code Generator. The generated code is described in detail (although some details are omitted).

  4. There are explanations and examples showing what the generated code looks like, but not why it looks like it does. There are also some comments indicating in what circumstances different generated objects (functions, types, variables, and so on) are used.
  5. In the sections Compilation Switches, Creating a New Library, and Adaptation to Compilers, different aspects on how to make new versions of the runtime library are discussed.

  6. The compilation switches treated in the section Compilation Switches are used to determine the properties of the runtime library and the generated C code, while section Creating a New Library shows how to make new versions of the runtime library using for example new combinations of compilation switches.

    In the section Adaptation to Compilers, porting issues are discussed.

File Structure

The runtime library is structured into a number of files. These are:

On UNIX, all files except sctworld.o can be found in the directory $telelogic/sdt/sdtdir/<machine dependent dir>/INCLUDE where <machine dependent dir> is for example sunos5sdtdir on SunOS 5, and hppasdtdir on HP. The sctworld.o file can be found in the corresponding kernel directory:
$telelogic/sdt/sdtdir/
<machine dependent dir>/<kernel>

In Windows, all files except sctworld.lib can be found in the directory<Telelogic Tau installation directory>\sdt\sdtdir\wini386\include. The sctworld.lib file can be found in the corresponding kernel directory: <Telelogic Tau installation directory>\sdt\sdtdir\wini386\<kernel>. There are different kernel directories for the Borland and the Microsoft compiler. The Borland directories have the prefix scta while the Microsoft compiler directories have the prefix sctam.

Description of Files

scttypes.h

This file contains type definitions and extern declarations of variables and functions. The file is included by sctsdl.c, sctpred.c, sctutil.c, sctmon.c, sctpost.c, sctos.c, and by each generated C file.

sctlocal.h

This file contains type definitions and extern declarations of variables and functions that are used only in the kernel. This file is not included in generated code.

sctpred.h

This file contains type definitions and extern declarations handling the predefined data types in SDL (except PId, which is in scttypes.h). Macros used to implement the predefined generators in SDL can also be found here. This file is included in generated code via scttypes.h.

sctsdt.c

In this file the implementation of the SDL operations can be found, together with the functions used for scheduling. In more detail, this file contains groups of functions for:

sctpred.c

The functions implementing the operations defined in the SDL predefined data types can be fund in this file. Operators for PId is implemented in sctsdl.c.

sctutil.c

This file contains basic read and write functions together with functions to handle reading and writing of values of abstract data types, including the predefined data types. It also contains the functions for MSC trace.

sctmon.c

The sctmon.c file contains the functions that implement the monitor interface, that is, interpreting and executing monitor commands.

sctpost.c

This file contains all the basic functions that are used to connect a simulator with the other parts of SDT.

sctos.c

In this file, some functions that represent the dependencies of hardware, operating system and compiler are placed.

The basic functions necessary for an application are a function to read the clock and a function to allocate memory.

To move a generated C program plus the runtime library to a new platform (including a new compiler), the major changes are to be made in this file, together with writing a new section in scttypes.h to describe the properties of the new compiler.

sctworld.o (sctworld.lib in Windows)

This is a pre-linked object file containing

A pre-linked file gives a faster link operation when generating an application. This file is of course only present if the hardware platform supports pre-linking.

post.h and sdt.h

These files are included in sctpost.c if the communication mechanism with other SDT applications should be part of the actual object code version of the library. The file post.h contains the function interface, while sdt.h contains message definitions.

Caution! 

Windows only: When linking with the PostMaster's dynamically linked libraries (post.lib and post.dll), the environment variable USING_DLL must be defined before including post.h. Example:

#define USING_DLL
#include "post.h"
#undef USING_DLL

post.o (post.lib in Windows)

This file contains the implementation of functions needed to send messages, via the Postmaster, to other tools in SDT.

The Symbol Table

The symbol table is used for storing information mainly about the static properties of the SDL system, such as the block structure, connections of channels and the valid input signal set for processes. Some dynamic properties are also placed in the symbol table; for example the list of all active process instances of a process instance set. This is part of the node representing the process instance set.

The nodes in the symbol table are structs with components initialized in the declaration. During the initialization of the application, in the yInit function in generated code, a tree is built up from these nodes.

Symbol Table Tree Structure

The symbol table is created in two steps:

  1. First, symbol table nodes are declared as structs with components initialized in the declaration (in generated code).
  2. Then, the yInit function (in generated code) updates some components in the nodes and builds a tree from the nodes. This operation is not needed in an application!

The following names can be used to refer to some of the nodes that are always present. These names are defined in scttypes.h.

xSymbolTableRoot is the root node in the symbol table tree. Below this node the system node is inserted. After the system node, there is a node representing the environment of the system (xEnvId). Then there is one node for each package referenced from the SDL system. This is true also for the package predefined containing the predefined data types. The nodes for the predefined data types, that are sons to the node for the package predefined, can be directly referenced by the names xSrtN_SDL_xxx, according to the list above.

Nodes in the symbol table are placed in the tree exactly according its place of declaration in SDL. A node that represent an item declared in a block is placed as a child to that block node, and so on. The hierarchy in the symbol table tree will directly reflect the block structure and declarations within the blocks and processes.

A small example can be found in Figure 496. The following node types will be present in the tree:

Node Type Description
xSystemEC

Represent the system or the system instance.

xSystemTypeEC

Represents a system type.

xPackageEC

Represents a package.

xBlockEC

Represent blocks and block instances.

xBlockTypeEC

Represents a block type.

xBlockSubstEC

Represents a block substructure and can be found as a child of a block node.

xProcessEC

Represent processes and process instances. The environment process node is placed after the system node and is used to represent the environment of the system.

xProcessTypeEC

Represents a process type.

xServiceEC

Represents a service or service instance.

xServiceTypeEC

Represents a service type.

xProcedureEC

Represents a procedure.

xOperatorEC

Represents an operator diagram, i.e. an ADT operator with an implementation in SDL.

xCompoundStmtEC

Represents a compound statement containing variable declarations.

xSignalEC 
xTimerEC

Represents a signal or timer type.

xRPCSignalEC

Represents the implicit signals (pCALL, pREPLY) used to implement RPCs.

xSignalParEC

There will be one signal parameter node, as a child to a signal, timer, and RPC signal node, for each signal or timer parameter.

xStartUpSignalEC

Represents a start-up signal, that is, the signal sent to a newly created process containing the actual FPAR parameters. An xStartUpSignalEC node is always placed directly after the node for its process.

xSortEC
xSyntypeEC

Represents a newtype or a syntype.

Struct Component Node 
(xVariableEC)

A sort node representing a struct has one struct component node as child for each struct component in the sort definition.

xLiteralEC

A sort node similar to an enum type has one literal node as child for each literal in literal list.

xStateEC

Represents a state and can be found as a child to process and procedure nodes.

xVariableEC 
xFormalParEC

Represents a variable (DCL) or a formal parameter (FPAR) and can be found as children of process and procedure nodes.

xChannelEC 
xSignalRouteEC
xGate

Represents a channel, a signal route, or a gate.

xRemoteVarEC

Represents a remote variable definition.

xRemotePrdEC

Represents a remote procedure definition.

xSyntVariableEC

Represents implicit variables or components introduced by the Cadvanced/Cbasic Code Generator. Used only by the Validator.

xSynonymEC

Represent synonyms. Used only by the Validator.

The nodes (the struct variables) will in generated code be given names according to the following table:

In most cases it is of interest to refer to a symbol table node via a pointer. By taking the address of a variable according to the table above, i.e.

such a reference is obtained. For backward compatibility, macros according to the following example is also generated for several of the entity classes:

Types Representing the Symbol Table Nodes

The following type definitions, from the file scttypes.h, are used in connection with the symbol table:

There are also pointer types defined for each of the xECIdStruct according to the following example:

The type definitions above define the contents in the symbol table nodes. Each xECIdStruct, where EC should be replaced by an appropriate string, have the first five components in common. These components are used to build the symbol table tree. To access these components, a pointer to a symbol table node can be type cast to any of the xIdECNode types. The type xIdNode is used as such general type, for example when traversing the tree.

The five components present in all xIdNode are:

Next there are components depending on what entity class that is to be represented. Below we discuss the non-common elements in the other xECIdStruct.

Package

System, System Type

Channel, Signal route, Gate

For channels, signal routes, and gates there are always two consecutive xChannelIdNodes in the symbol table, representing the two possible directions for a channel, signal route, or gate. The components are:

Block, Block Type, Block Instance

Process, Process Type, Process Instance

Service, Service Type, Service Instance

Procedure, Operator Diagram, Compound Statement

Note that operator diagrams and compound statements containing variable declarations are treated as procedures. However, such objects can, for example, not contain states.

Remote Procedure

Signal, Timer, StartUpSignal, and RPC Signals

State

Sort and Syntype

SortType is xArray, xGArray, xCArray
SortType is xString
SortType is xPowerSet, xGPowerSet, xBag, xRef
SortType is xInherits
SortType is xSyntype

Variable, FormalPar, SignalPar, and Struct Components

Remote Variable

The SDL Model

Signals and Timers

Data Structure Representing Signals and Timers

A signal is represented by a struct type. The xSignalRec struct, defined in scttypes.h, is a struct containing general information about a signal except from the signal parameters. In scttypes.h the following information about signals can be found:

The xSignalNode type is thus a pointer type which is used to refer to allocated data areas of type xSignalRec. The components in the xSignalRec struct are used as follows:

A signal without parameters are represented by a xSignalStruct, while for signals with parameters a struct type named yPDef_SignalName and a pointer type referencing this struct type (yPDP_SignalName) are defined in generated code. The struct type will start with the SIGNAL_VARS macro and then have one component for each signal parameter, in the same order as the signal parameters are defined. The components will be named Param1, Param2, and so on.


Example 346       

These types would represent a signal sig(Integer, Boolean).


As all signals starts with the components defined in SIGNAL_VARS it is possible to type cast a pointer to a signal, to the xSignalNode type, if only the components in SIGNAL_VARS is to be accessed.

Allocation of Data Areas for Signals

In sctos.c there are two functions, xGetSignal and xReleaseSignal, where data areas for signal are handled:

xGetSignal takes a reference to the SignalIdNode identifying the signal type and two PId values (sending and receiving process instance) and returns a signal instance. xGetSignal first looks in the avail list for the signal type (the component AvailSignalList in the SignalIdNode for the signal type) and reuses any available signal there. Only if the avail list is empty new memory is allocated. The component VarSize in the SignalIdNode for the signal type provides the size information needed to correctly allocate the yPDef_SignalName even though the type is unknown for the xGetSignal function.

The function xReleaseSignal takes the address of an xSignalNode pointer and returns the referenced signal to the avail list for the signal type. The xSignalNode pointer is then set to 0.

The function xGetSignal is used:

The function xReleaseSignal is used by:

Overview of Output and Input of Signals

In this subsection the signal handling operation is only outlined. More details will be given in the section treating processes. See Output and Input of Signals.

Signal instances are sent using the function SDL_Output. That function takes a signal instance and inserts it into the input port of the receiving process instance.

If the receiver is not already in the ready queue (the queue containing the processes that can perform a transition, but which have not yet been scheduled to do so) and the current signal may cause an immediate transition, the process instance is inserted into the ready queue.

If the receiver is already in the ready queue or in a state where the current signal should be saved, the signal instance is just inserted into the input port.

If the signal instance can neither cause a transition nor should be saved, it is immediately discarded (the data area for the signal instance is returned to the avail list).

The input port is scanned during nextstate operations, according the rules of SDL, to find the next signal in the input port that can cause a transition. Signal instances may then be saved or discarded.

There is no specific input function, instead this behavior is distributed both in the runtime library and in the generated code. The signal instance that should cause the next transition to be executed is removed from the input port in the main loop (the scheduler), immediately before the PAD function for the current process is called. The PAD function is the function where the behavior of the process is implemented and is part of the generated code. The assignment of the signal parameters to local SDL variables is one of the first actions performed by the PAD function.

The signal instance that caused a transition is released and returned to the avail list in the nextstate or stop action that ends the current transition.

Timers and Operations on Timers

A timer with parameters is represented by a type definition, where the timer parameters are defined, in exactly the same way as for a signal definition, see Data Structure Representing Signals and Timers. At runtime, all timers that are set and where the timer time has not expired, are represented by a xTimerRec struct and a signal instance:

The TIMER_VARS is and must be identical to the SIGNAL_VARS macro, except for the TimerTime component last in the macro. A timer with parameters have yPDef_timername and yPDP_timername types in generated code exactly as a signal (see previous section), except that SIGNAL_VARS is replaced by TIMER_VARS.

During its life-time a timer have two different appearances. First it is a timer waiting for the timer time to expire. In that phase the timer is inserted in the xTimerQueue. When the timer time expires the timer becomes a signal and is inserted in the input port of the receiver just like any other signal. Due to the identical typedefs for xSignalRec and xTimerRec, there are no problems with type casting between xTimerNode and xSignalNode types.

When a timer is treated as a signal the components in the xTimerRec are used in the same ways as for a xSignalRec. While the timer is in the timer queue, the components are used as follows:

The queue mentioned above, the timer queue for active timers is represented by the component xTimerQueue in the variable xSysD:

The variable is initialized in the function xInitKernel in sctsdl.c. xTimerQueue is initialized it refers to the queue head of the timer queue.

The queue head is an extra element in the timer queue that does not represent a timer, but is introduced as it simplifies the algorithms for queue handling. The TimerTime component in the queue head is set to a very large time value (xSysD.xMaxTime).

The timer queue is thus a doubly linked list with a list head and it is sorted according to the timer times, so that the timer with lowest time is at the first position.

The xTimerRec structs are allocated and reused in the same way as signal.

From the SDL point of view, timers are handled in:

The timer output is the event when the timer time has expired and the timer signal is sent. After that, a timer signal is treated as an ordinary signal. These operations are implemented as follows:

This function, which represents the Set operation, takes the timer time and a signal instance as parameters. It first uses the signal instance to make an implicit reset (see reset operation below) It then updates the TimerTime component in S and inserts S into the timer queue at the correct position.

The SDL_Set operation is used in generated code, together with xGetSignal, in much the same way as SDL_Output. First a signal instance is created (by xGetSignal), then timer parameters are assigned their values, and finally the Set operation is performed (by SDL_Set).

Two functions are used to represent the SDL action reset. SDL_SimpleReset is used for timers without parameters and SDL_Reset for timers with parameters.

SDL_Reset uses the two functions xRemoveTimer and xRemoveTimerSignal to remove a timer in the timer queue and to remove a signal instance in the input port of the process. It then releases the signal instance given as parameter. This signal is only used to carry the parameter values given in the reset action.

The function SDL_SimpleReset is implemented in the same way as SDL_Reset, except that it creates its own signal instance (without parameters).

At a reset action the possibly found timer is removed from the timer queue and returned to the avail list. A found signal instance (in the input port) is removed from the input port and returned to the avail list for the current signal type.

The SDL_OutputTimerSignal is called from the main loop (the scheduler) when the timer time has expired for the timer first in the timer queue. The corresponding signal instance is then sent.

SDL_OutputTimerSignal takes a pointer to an xTimerRec as parameter, removes it from the timer queue and sends as an ordinary output using the function SDL_Output.

It can be checked if timer is active by using a call to the function SDL_Active. This function is used in generated code to represent the SDL operator active.

Note: 

Only timers without parameters can be tested. This is a restriction in the Cadvanced/Cbasic Code Generator.

There is one more place where timers are handled. When a process instance performs a stop action all timers in the timer queue connected to this process instance are removed. This is performed by calling the function xRemoveTimer with the first parameter equal to 0.

Processes

Data Structure Representing Processes

A process instance is represented by two structs, an xLocalPIdRec and a struct containing both the general process data and the local variables and formal parameters of the process (yVDef_ProcessName), see also Figure 490. The reason for having both the xLocalPIdRec and the yVDef_ProcessName will be discussed under Create and Stop Operations.

Figure 490 : Representation of a process instance

Extracted pic [1]

The corresponding type definitions, which can be found in scttypes.h, are:

A PId value is thus a struct containing two components:

The use of the global node number is discussed in the Building an Application.

A xLocalPIdRec contains the following three components:

A xPrsRec struct contains the following components described below. As each yVDef_ProcessName struct contains the PROCESS_VARS macro as first item, it is possible to cast pointer values between a pointer to xPrsRec and a pointer to a yVDef_ProcessName struct.

The Ready Queue, Scheduling

The ready queue is a doubly linked list with a head. It contains the process instances that can execute an immediate transition, but which has not been allowed to complete that transition. Process instances are inserted into the ready queue during output operations and nextstate operations and are removed from the ready queue when they execute the nextstate or stop operation that ends the current transition. The head in the ready queue, which is an object in the queue that does not represent any process but is inserted only to simplify the queue operations, is referenced by the xSysD component:

This component is initiated in the function xInitKernel and used throughout the runtime library to reference the ready queue.

Scheduling of events is performed by the function xMainLoop, which is called from the main function after the initialization is performed.

The strategy to have all interesting queues (the ready queue, the timer queue, and the input ports) sorted in the correct order is used in the library. Sorting is thus performed when an object is inserted into a queue, which means that scheduling is a simple task: select the first object in the timer queue or in the ready queue and submit it for execution.

There are several versions of the body of the endless loop in the function xMainLoop, which are used for different combinations of compilation switches. When it comes to scheduling of transitions and timer outputs they all have the following outline:

or, in descriptive terms:

The different versions of the main loop handle different combinations of compilation switches. Other actions necessary in the main loop are dependent of the compilation switches. Example of such actions are:

Create and Stop Operations

A process instance is, while it is active, represented by the two structs:

These two structs are dynamically allocated. A PId value is also a struct (not allocated) containing two components, GlobalNodeNr and LocalPId, where LocalPId is a pointer to the xLocalPIdRec. Figure 491 shows how the xLocalPIdRec and the yVDef_ProcessName structs representing a process instance are connected.

Figure 491 : A xLocalPIdRec and a yVDef_ProcessName
representing a Process instance

Extracted pic [2]

When a process instance performs a stop action, the memory used for the process instance should be reclaimed and it should be possible to reuse in subsequent create actions. After the stop action, old (invalid) PId values might however be stored in variables in other process instances.

If a signal is sent to such an old PId value, that is, to a stopped process instance, it should be possible to find and perform appropriate actions. If the complete representation of a process instance is reused then this will not be possible. There must therefore remain some little piece of information and thus some memory for each process instance that has ever existed. This is the purpose of the xLocalPIdRec. These structs will never be reused. Instead the following (see Figure 492) will happen when the process instance in Figure 491 performs a stop action.

Figure 492 : The memory structure after the process in
Figure 491 has performed a stop action

Extracted pic [3]

A new xLocalPIdRec is allocated and its PrsP references the yVDef_ProcessName (InstNr is 0). The Self component in the yVDef_ProcessName is changed to reference this new xLocalPIdRec. The old xLocalPIdRec still references the yVDef_ProcessName. The yVDef_ProcessName is entered into the avail list for this process type.

To reuse the data area for a process instance at a create operation it is only necessary to remove the yVDef_ProcessName from the avail list and update the InstNr component in the xLocalPIdRec referenced by Self.

Using this somewhat complicated structure to represent process instances allows a simple test to see if a PId value refers to an active or a stopped instance:

If P is a PId variable then the following expression:

is true if the process instance is active and false if it is stopped.

The basic behavior of the create and stop operations is performed by the functions SDL_Create and SDL_Stop.

To create a process instance takes three steps performed in generated code:

  1. Call xGetSignal to obtain the start-up signal.
  2. Assign the actual process parameters to the start up signal parameters.
  3. Call SDL_Create with the start-up signal as parameter, together with the PrsIdNode representing the process to be created.

In xGetProcess the process instance is removed from the avail list of the process instance set (the component AvailPrsList in the PrsIdNode representing the process instance set), or if the avail list is empty new memory is allocated.

The process instance is linked into the list of active process instances (the component ActivePrsList in the PrsIdNode representing the process instance set). Both the avail list and the active list are single linked lists (without a head) using the component NextPrs in the yVDef_ProcessName struct as link.

To have an equal treatment of the initial transition and other transitions, the start state is implemented as an ordinary state with the name "start state" It is represented by 0. To execute the initial transition a "startup" signal is sent to the process. The start state can thus be seen as a state with one input of the startup signal and with save for all other signals. This implementation is completely transparent in the monitor, where startup signals are never shown in any way.

Note: 

The actual values for FPARs are passed in the startup signal.

Two IdNodes that are not part of the symbol table tree are created to represent a start state and a startup signal.

These xSysD components are initialized in the function xInitSymbolTable, which is part of sctsdl.c.

At a stop operation the function SDL_Stop is called. This function will release the signal that caused the current transition and all other signals in the input port. It will also remove all timers in the timer queue that are connected to this process instance by calling xRemoveTimer with the first parameter equal to 0. It then removes the process executing the stop operation from the ready queue and from the active list of the process type and returns the memory to the avail list of the current process instance set.

Output and Input of Signals

There are three actions performed in generated code to send a signal. First xGetSignal is called to obtain a data area that represents the signal instance, then the signal parameters are assigned their values and finally the function SDL_Output is called to actually send the signal. First in the SDL_Output function there are a number of dynamic tests (check if receiver in TO-clause is not NULL and not stopped, check if there is a path to the receiver). If the output does not contain any TO-clause and the Cadvanced/Cbasic Code Generator has not been able to calculate the receiver, the xFindReceiver function is called to calculate the receiver according to the rules of SDL.

Next, in SDL_Output signals to the environment are handled. Three cases can be identified here:

  1. The environment function xOutEnv is called.
  2. The corresponding function that sends signals via the SDT communication mechanism (xOutPM) is called.
  3. The signal is inserted into the input port of the process representing the environment (xEnv).

Finally, internal signals in the SDL system are treated. Here also three cases can be identified (how this is evaluated is described last in this subsection):

  1. The signal can cause an immediate transition by the receiver.
  2. The signal should be saved.
  3. The signal should be immediately discarded.

If the signal can cause an immediate transition, the signal is inserted into the input port of the receiver, and the receiving process instance is inserted into the ready queue.

If the signal should be saved, the signal is just inserted into the input port of the receiver.

If the signal should be discarded, the function xReleaseSignal is called to reused the data area for the signal.

When a signal is identified to be the signal that should cause the next transition by the current process instance (at an Output or Nextstate operation), the component Signal in the yVDef_ProcessName for the process is set to refer to the signal. The signal is still part of the input port list.

When the transition is to be executed, the signal is removed from the input port in the main loop (see The Ready Queue, Scheduling) immediately before the PAD function for the process is called.

First in the PAD function, the parameters of the signal are copied to the local variables according to the input statement. In the ending Nextstate or Stop operation of the transition the signal instance is returned to the avail list.

Evaluating How To Handle a Received Signal

There are two places in the run-time kernel where it is necessary to evaluate how to handle signals (input, save, discard,...):

This calculation is implemented in the run-time kernel function xFindInputAction.

The parameters of this function is:

As a result the function should return:

After this last update the correct transition can be started by the scheduler by just calling the function referenced by RestartPAD, which the as first action performs switch RestartAddr and starts execute the input symbol.

Figure 493 : Data structure used to evaluate the xFindInputAction

Extracted pic [4]

The algorithm to find the InputAction, the RestartAddr, and the RestartPAD is as follows:

  1. Let ProcessId become yVarP->NameNode and let StateId become ProcessId->StateList[yVarP->State].
  2. In ProcessId->SignalSet find the index (Index) where SignalId->NameNode is found. If the signal is not found, this signal is not in the signal set of the process, and the algorithm terminates returning the result xDiscard.
  3. StateId->SignalHandlArray[Index] now gives the action to be performed. If this value is xEnablCond, then the function StateId->EnablCond_Function is called. This function returns either xInput or xSave.
  4. If the result from step 3 is xInput, the algorithm terminates returning this value. yVarP->RestartAddr is also updated to
    StateId->InputRef[Index], while yVarP->RestartPAD is updated to ProcessId->PAD_Function.

  5. If the result from step 3 is xSave, the algorithm terminates returning this value.

    If the result from step 3 is xDiscard and ProcessId->Super equal to NULL, then the algorithm terminates returning this value.

    If the result from step 3 is xDiscard and ProcessId->Super not equal to NULL, then we are in a process type that inherits from another process type. We then have to perform step 2 - 4 again, with ProcessId assigned the value ProcessId->Super and StateId assigned the value StateId->Super.

Nextstate Operations

The nextstate operation is implemented by the SDL_Nextstate function, where the following actions are performed:

  1. The signal that caused the current transition (component Signal in the yVDef_ProcessName) is released and the state variable (component State in the yVDef_ProcessName) is updated to the new state.
  2. Then the input port of the process is scanned for a signal that can cause a transition. During the scan signals might be saved or discarded until a signal specified in an input is found. Priority inputs are treated according to the rules of SDL.
  3. If no signal that can cause a transition is found, a check is made if any continuous signal can cause a transition (see Enabling Conditions and Continuous Signals). The process is thereafter removed from the ready queue.
  4. If any signal (or continuous signal) can cause a transition then the process is re-inserted into the ready queue again at a position determined by its priority, else if the new state contains any continuous signal or enabling condition with an expression that might change its value during the time the process is in the state (view, import...), the process is inserted into the check list (see also Enabling Conditions and Continuous Signals).

Decision and Task Operations

Decision and Task operations are implemented in generated code, except for the Trace-functions implemented in the sctutil.c and sctmon.c file and for informal and any decisions that uses some support functions in sctmon.c. A Decision is implemented as a C if-statement, while the assignments in a Task are implemented as assignments or function calls in C.

Compound Statements

A compound statement without variable declarations is translated just to the sequence of action it contains, while a compound statement with variable declarations is translated to a procedure (without parameters). Statements within a compound statement are translated according to the normal rules. The new statement types in compound statements are translated as:

Enabling Conditions and Continuous Signals

The expressions involved in continuous signals and enabling conditions are implemented in generated code in functions called yCont_StateName and yEnab_StateName. These functions are generated for each state containing continuous signals respectively enabling conditions. The functions are referenced through the components ContSig_Function and EnablCond_Function in the StateIdNode for the state. These components are 0 if no corresponding functions are generated.

The EnablCond_Functions are called from the function xFindInputAction, which is called from SDL_Output and SDL_Nextstate. If the enabling condition expression for the current signal is true then xInput is returned else xSave is returned. This information is then used to determine how to handle the signal in this state.

The ContSig_Functions are called from SDL_Nextstate, if the component ContSig_Function is not 0 and no signal that can cause an immediate transition is found during the input port scan. A ContSig_Function has the following prototype:

where the first parameter is the pointer to the yVDef_ProcessName. The remaining parameters are all out parameters; the second contains the priority of the continuous signal with highest priority (=lowest value) that has an expression with the value true. Otherwise <0 is returned here. The third and fourth is only defined the second parameter >=0; the third is the IdNode for the process/procedure where the actual continuous signal can be found and the fourth is the RestartAddress connected to this continuous signal.

If a continuous signal expression with value true is found, a signal instance representing the continuous signal is created and inserted in the input port, and is thereafter treated as an ordinary signal. The signal type is continuous signal and is represented by an SignalIdNode (referenced by the variable xContSigId).

The check list is a list that contains the processes that wait in a state where enabling conditions or continuous signals need to be repeatedly recalculated.

A process is inserted into the check list if:

  1. It enters a state containing enabling conditions and/or continuous signals and
  2. No signal or continuous signal can cause an immediate transition and
  3. One or several of the expressions in the enabling conditions or continuous signals can change its value while the process is in the state (view, import, now, ...)

The component StateProperties in the StateIdNode reflects if any such expression is present in the state.

The check list is represented by the xSysD component:

The behavior of enabling conditions and continuous signals is in SDL modeled by letting the process repeatedly send signals to itself, thereby to repeatedly entering the current state. In the implementation chosen here, nextstate operations are performed "behind the scene" for all processes in the check list directly after a call to a PAD function is completed, that is directly after a transition is ended and directly after a timer output. This is performed by calling the function xCheckCheckList in the main loop of the program.

View and Reveal

A view expression is part of an expression in generated code and implemented by calling the function SDL_View.

The SDL_View function performs a test that the view expression is not NULL, refers to a process in the environment, or to a stopped process instance. If no errors are found the address of the revealed variable is returned as result from the SDL_View function. Otherwise the address of a variable containing only zeros is returned.

Import, Export, and Remote Variables

For an exported variable there are two components in the yVDef_ProcessName struct. One for the current value of the variable and one for the currently exported value of the variable. For each exported variable there will also be a struct that can be linked into a list in the corresponding RemoteVarIdNode. This list is then used to find a suitable exporter of a variable in an import action.

An export action is a simple operation. The current value of the variable is copied to the component representing the exported value. This is performed in generated code.

An import action is more complicated. It involves mainly a call of the function xGetExportAddr:

RemoteVarNode is a reference to the RemoteVarIdNode representing the remote variable (implicit or explicit), P is the PId expression given in the import action and IsDef is 0 or 1 depending on if any PId expression was given in the import action or not, Importer is the importing process instance. The xGetExportAddr will check the legality of the import action and will, if no PId expression is given, calculate which process it should be imported from.

If no errors are found the function will return the address where the exported value can be found. This address is then casted to the correct type (in generated code) and the value is obtained. If no process possible to import from is found, the address of a variable containing only zeros is returned by the xGetExportAddr function.

Note: 

The strategy for import actions is in one sense not equal to the model for import given in the SDL recommendation. An import action is in the recommendation modeled as a signal sent from the importing process to the exporting process asking for the exported value, and a signal with this value sent back again. The synchronization effects by this signal communication is lost in the implementation model we have chosen. Instead our model is much easier and faster and the primary part of the import action, to obtain the exported value, is the same.

Services

Data Structure Representing Services

A service is represented by a struct type. The xSrvRec struct defined in scttypes.h, is, just like xPrsRec for processes, a struct containing general information about a service, while the parameters and variables of the service are defined in generated code in the same way as for processes.

In scttypes.h the following types concerning procedures can be found:

In generated code yVDef_ProcedureName structs are defined according to the following:

The components in the xSrvRec are used as follows:

Executing Transitions in Services

From the scheduler's point view, it is not of interest if a process contains services or not. It is still the process instance that is scheduled in the ready queue and the PAD function of the process that is to be called to execute a transition. The PAD function for a process containing services performs three different actions:

The structure for a PAD function for a process with services are as follows:

where LOOP_LABEL_SERVICEDECOMP and BEGIN_START_TARNSITION are empty macros, i.e. expanded to no code. The yAss_SDL_Integer statement in an assignment of a default value to a process variable.

The macro CALL_SERVICE is expanded to:

that is to a call of the PAD function of service reference by ActiveSrv.

The macro START_SERVICE is expanded to a call to the function xStart_Services, which can be found in sctsdl.c.The function creates the service instances, sets up the ActiveSrv pointer for the process to the first service, and then schedules the process for a new transition. This means that the next action performed by the system will be the start transition by the first service instance. When the first service executes a nextstate or stop action in the end of its start transition, the process will be scheduled again to execute the start transition of the second service, and so on until all services in the process has executed its start transitions.

For ordinary transitions, i.e. reception of a signal, it is obvious from the code above that the ActiveSrv pointer is essential. It should refer to the service instance that is to be executed. When a signal is to be received by a process, it is the function xFindInputAction (in sctsdl.c) that determines how to handle the signal and if it is to be received, where is the code for that transition. This function now also determines and sets up the ActiveSrv pointer.

Procedures

Data Structure Representing Procedures

A procedure is represented by a struct type. The xPrdRec struct defined in scttypes.h, is, just like xPrsRec for processes, a struct containing general information about a procedure, while the parameters and variables of the procedure are defined in generated code in the same way as for processes.

In scttypes.h the following types concerning procedures can be found:

In generated code yVDef_ProcedureName structs are defined according to the following:

The components in the xPrdRec are used as follows:

In Figure 494 an example of the structure of yVDef_ProcedureName after four nested procedure calls are presented. Note that procedure Q is declared in the process, procedure R and S in Q and T in S.

Figure 494 : Structure of yVDef_ProcedureName
after four nested procedure calls

Extracted pic [5]

The SDL procedures are partly implemented using C functions and partly using the structure shown above. Each SDL procedure is represented by a C function, which is called to execute actions defined in the procedure. This function corresponds to the PAD function for processes. The formal parameters and the variables are however implemented using a struct defined in generated code. The procedure stack for nested procedure calls is implemented using the components StaticFather and DynamicFather, and does not use the C function stack.

Calling and Returning from Procedures

Procedure calls and procedure returns are handled by three functions, one handling allocation of the data areas for procedures:

and two functions called from generated code at a procedure call and a procedure return:

A procedure call in SDL is in C represented by the following steps:

  1. Calling xGetPrd to obtain a data area for the procedure.
  2. Assigning procedure parameters to the data area.
  3. Calling xAddPrdCall to link the procedure into the static and dynamic chains.
  4. Calling the C function modeling the SDL procedure, i.e. the yProcedureName function.

The parameters to xAddPrdCall are as follows:

The xGetPrd returns a pointer to an xPrdRec, which can then be used to assign the parameter values directly to the components in the data area representing the formal parameters and variables of the procedure. Note that IN/OUT parameters are represented as addresses in this struct.

A procedure return is in generated code represented by calling the xReleasePrd followed by return 0, whereby the function representing the behavior of the SDL procedure is left.

The function representing the behavior of the SDL procedure is returned in two main situations:

If 0 is returned then the execution should continue with the next SDL symbol after the procedure call, while if 1 is returned the execution of the process instance should be terminated and the scheduler (main loop) should take control. This could mean that a number of nested SDL procedure calls should be terminated.

To continue to execute at the correct symbol when a procedure should be resumed after a nextstate operation, the following code is introduced in the PAD function for processes containing procedure calls:

This means that uncompleted procedures are resumed one after one from the bottom of the procedure stack, until all procedures are completed or until one of them returns 1, i.e. executes a nextstate operation, at which the process is left for the scheduler again.

Channels and Signal Routes

The ChannelIdNodes for channels, signal routes, and gates are used in the functions xFindReceiver and xIsPath, which are both called from SDL_Output, to find the receiving process when there is no TO clause in the Output statement, respectively to check that there is a path to the receiver in the case of a TO clause in the Output statement. In both cases the paths built up using the ToId components in the IdNodes for processes, channels and signal routes are followed. To show the structure of these paths we use the small SDL system given in Figure 495.

Figure 495 : A small SDL system

Extracted pic [6]

During the initialization of the system, the symbol table is built up. The part of the symbol table starting with the system will then have the structure outlined in Figure 496. As we can see in this example the declarations in the SDL system are directly reflected by IdNodes.

Note: 

Each channel and signal route is represented by two IdNodes, one for each direction. This is also true for an unidirectional channel or signal route. In this case the signal set will be empty for the unused direction.

Figure 496 : The symbol table tree for the system in Figure 495
.
Extracted pic [7]

Each IdNode representing a process, a signal route, or a channel will have a component ToId. A ToId component is an address to an array of references to IdNodes. The size of this array is dependent on the number of items this object is connected to. A process that has three outgoing signal routes will have a ToId array which can represent three pointers plus an ending 0 pointer.

In the example in Figure 495 and Figure 496 there is no branching, so all ToId arrays will be of the size necessary for two pointers. Figure 497 shows how the IdNodes for the processes, signal routes and channels are connected to form paths, using the components ToId. In this case only simple paths are found (one from P1, via SR1, C, SR2, to P2, and one in the reverse direction). The generalization of this structure to handle branches is straightforward and discussed in the previous paragraph.

Figure 497 : The connection of ToId for the system in
Figure 495 and Figure 496

Extracted pic [8]

The Type Concept in SDL-92

The probably most important new feature in SDL-92 is the introduction of the object oriented features, such as TYPE, INHERITS, VIRTUAL, and REDEFINED. Here we start by discussing process types.

For each process type the Cadvanced/Cbasic Code Generator will generate:

In the PrsIdNode there is one component (Super) that will refer to the PrsIdNode for the process type inherited by this process type. As sons to a PrsIdNode, IdNodes for declaration that are common for all instantiation of the process type can be found. Examples of such IdNodes are: nodes for variables, formal parameters, signals, timers, procedures, states, newtypes, and syntypes. Any typedefs or help functions for such units are also treated in the process type.

The PAD function will be independent of the PAD function for a inherited type, each PAD function just implementing the action described in its process type.

A yVDef_ProcessName struct will on the other hand include all variables and formal parameters from the top of the inheritance chain and downwards. Example:

This will generate the following principle yVDef_... structs:

A pointer to yVDef_P2 can thus be casted to a pointer to yVDef_P1, if only the common component (in PROCESS_VARS) or the variables in P1 is to be accessed. This possibility is used every time the PAD function for an inherited process type is called.

Each process instantiation will all be implemented as a xPrsIdNode. The Super component in such an object refers to the process type that is instantiated. No PAD function or yVDef_... struct will be generated. As sons to the PrsIdNode for a process instantiation, only such object are inserted that are different in different instantiations. For a process instantiation this is the gates. For other types of information the process instantiation uses the information given for its process type.

A very similar structure when it comes to IdNodes generated for block types and block instantiations are used by the code generator. There will be a BlockIdNode for both a block type and for a block instantiation. As sons to a block type, nodes that are the same in each block instantiation can be found (example: signal, newtype, syntype, block type, process type, procedure). As sons to a block instantiation, nodes that are needs to be represented in each block instantiation can be found (example: block instantiation, process instantiation, channel, signal route, gate, remote definitions).

Note: 

A block or process (according to SDL-88), that is contained in a block type or a system type, is translated as if it was a type and instantiation at the same place.

A way to look at the structure of IdNodes in a particular system is to use the command Symboltable in the monitor system. This command prints the IdNode structure as an indented list of objects.

Structure of Generated Code

This section gives an overview of the C code that is generated by the SDT Cadvanced/Cbasic Code Generator. The purpose is to help to see the correspondence between the SDL diagrams and the generated code. This knowledge will in turn make it easier for the user to trace a C compilation or runtime error back to the originating SDL definition or action.

The generated code is described in detail (although not in all details). There are explanations and examples showing what the generated code looks like, but not why it looks like this. There are also some comments indicating in what circumstances different generated objects (functions, types, variables, and so on) are used.

In many places in the generated C code, a C name will consist of a prefix plus the SDL name of the current SDL object. In this section prefixes will not be indicated in the examples.

The code that is described here is the complete code. Parts of the code are not used in applications (but together with the monitor), and are thus removed by the use of compilation switches. This is not shown in here.

In the generated code, comments containing SDT references can be found. These comments are not shown in the examples, but are of course an important aid to finding the originating SDL statement or declaration. For more information about SDT references, see SDT References. Each generated compilation unit consists of a subtree in the static structure containing the system, the blocks, the processes, the services and the procedures. For an example see Figure 498. A compilation unit is generated either on one file, a .c file, or on two files, a .c and a .h file.

In this section the following terminology is used:

Unit Compilation unit

System unit

The top element of the SDL unit subtree for this compilation unit is the system or a system type.

Package unit

The top element of the SDL unit subtree for this compilation unit is a package.

Block unit

The top element of the SDL unit subtree for this compilation unit is a block or a block type.

Process unit

The top element of the SDL unit subtree for this compilation unit is a process or a process type.

Service unit

The top element of the SDL unit subtree for this compilation unit is a service or a service type.

Procedure unit

The top element of the SDL unit subtree for this compilation unit is a procedure.

Father unit

The compilation unit which is father to the current compilation unit.

Child unit

A compilation unit which is direct child to the current compilation unit.

Sub unit

A compilation unit which is part of the subtree with the current compilation unit as root.

Unit name

The name of the SDL object that is top element in the subtree for the compilation unit.

Figure 498 : Block structure and compilation unit structure (example)

Extracted pic [9]

Structure of a Generated File

A generated file will consist of a number of sections, which will be discussed below:

  1. Include file section
  2. Section with types and forward references
  3. CODE directives, #HEADING section
  4. CODE directives, #BODY section
  5. Section with variables and functions
  6. Initialization section

If this unit has any subunits or it is a unit for a package, a system type, block type, or process type, then point 2 and 3 are generated on a .h file and the rest on a .c file, otherwise all code is generated on a .c file.

Include files

Code generation on the .c file for the current unit is started by generating the include statement of the scttypes.h file:

If packages are used, the .h file for the packages and for the system types, block types, and process types defined in the package are included. If the unit has father units, their .h files are included starting from the top:

If the unit has any subunits, or is a unit for a system type, a block type, or a process type, its own .h file is then included:

If this is a unit for a system then this is followed by:

The name of this file is then generated as a char variable:

If the unit has any subunits or is a unit for a system type, a block type, or a process type, now code generation is continued on the .h file for the current unit. Otherwise all code is generated on the .c file.

Types and Forward References

General Structure

In this "Types and Forward References" section, each entity defined in SDL will have its own subsection. Example of such entities are: blocks, block types, block instantiations, processes, process types, process instantiations, services, service types, service instances, procedures, signals, timers, newtypes, syntypes, synonyms, variables, formal parameters, and so on. Only entities belonging to this separate unit is handled.

The SDL entities in separate unit forms a tree, either with the system or a package as root, or if it is subunit, with a block, block type, process, process type, service, service type, or procedure as root. This tree of entities is traversed in prefix order. Example:

If a block B contains two processes P1 and P2 and one signal S, these entities are treated in the order:

  1. B
  2. P1
  3. entities within P1
  4. P2
  5. entities within P2
  6. S.

Newtypes, syntypes, and synonyms are always treated before other entities defined in the same scope (a block for example). The order for these entities are (see also Newtype, Syntype, Synonym and #CODE (#TYPE section):

  1. Synonyms translated to macros
  2. Type definitions, #TYPE sections in #ADT and #CODE directives
  3. #HEADING sections in #ADT directives
  4. Synonyms translated to variables.

There are some special treatment when it comes to types and instantiations. A BlockIdNode is created both for a block type and for a block instance. The node below these BlockIdNodes differs however. Below the node for the block type, nodes are created for such entities that are equal in each instantiation. Examples are nodes for newtypes, syntype, signals, procedures, process types. Below a block instantiation, nodes that in some respect differs between each block instantiation are generated. Example of such nodes are nodes for process instantiations, channels, signal routes, gates, remote definitions. Process types - process instantiations, service types - service instantiations, and system types - system instantiations have similar properties, when it comes to sub-nodes.

Each subsection for an SDL entity starts with a comment to identify the entity.


Example 347       

The information presented here is the type of entity and the entity name, the qualifier for the entity, and the SDT reference for the entity (see SDT References).


The following entity classes are treated in subsections below:

System, System Instance, System Type

The following is generated for a system:

That is extern definition of the IdStruct for the system.

The following is generated for a system instance:

where ySysP_z_systype1 will become a list of channels defined in the system.

The following is generated for a system type:

where the yChaE_... can be used as indexes in the ySysP_z_systype1 list of channels (see example above). Using this list and these indexes it is possible to refer to channels generated in the system instance from Cadvanced/Cbasic code generated for the system type, for example in an OUTPUT VIA.

Package

The code generated for a package is just a definition of a PackageIdStruct.

Note: 

A package is always a separate unit and that both a .c and a .h file are generated.

Block Substructure

For a block substructure the following BlockSubstIdStruct is defined. In a block instantiation no node for block substructure are generated.

Block, Block Instance, Block Type

For a block and for a block instantiation the following BlockIdStruct are generated:

If the block contains processes and there are revealed variables in the any of the processes, then a definition of what will become a list of revealed variables is introduced. Also some defines for indexing this list are generated:

If the block contains processes but no signal routes (implicit signal routes), or it is a block instantiation, then a definition of what will become a list replacing the signal routes is introduced. Also some defines for indexing in this list are generated.

For a block type the following code is generated:

where the defines can be used to index in the yBloP_BlockName list generated for a block instance of this block type.

Process, Process Instance, Process Type

For a process or process type the following code is generated:

The first part is a number of extern definition of the data structures used to represent the process, and the extern definition of the PAD function, implementing the behavior of the process.

After that we have the yVDef_Process name struct, which will be discussed separately below.

After the yVDef_ProcessName struct a similar struct, only containing the FPARs of the process is generated. This struct, yPDef_ProcessName is used as definition of the startup signal. At the end there is a macro ySym_ProcessName which is the number of "symbols" in the process graph (counted after some transformations). Last there is an extern definition of the function yRef_ProcessName. This function is used to translate symbol numbers to SDT references.

For a process instantiation only the extern definition of the PrsIdStruct is necessary, as most of the other information needed for the process instance can be reused from the process type.

The Type yVDef_ProcessName

For each process and process type there will be a struct containing one component for each formal parameter (FPAR) and each variable (DCL). For an exported variable there will be one extra component to represent the currently exported value. There will also be a component for each type of expression that is used in decisions, except for the types Integer, Real, Boolean, Character, PId. Take, for example, a decision with a Charstring question:

then there will be a component where the question value can be stored. Together with the struct type the will also be a pointer type to the struct type. In the example below we assume that the process has two formal parameters, FPAR_var1 and FPAR_var2, two variables, DCL_var1 and DCL_var2, where the second variable is exported, and a decision where the question type is TypeName5.

In a process type, all variables, formal parameters, and so on, from the all the inherited process types are included in the struct above, starting from the top of the inheritance chain.

Service, Service Instantiation, Service Type

For a service or a service type code very similar to the code for a process or process type is generated. Example:

The major difference between the code generated for a service and for a process is that yPrs is replaced by ySrv, and that not all items are generated for a service, the start up signal for example. For more information about the object above please see the corresponding object for processes.

Procedure, Operator Diagram, Compound Statement

A procedure (or an operator diagram or a compound statement containing variables) has much in common with a process, when it comes to implementation. It is represented by a PrdIdStruct (extern definition here), a yVDef_ProcedureName struct defining the variables and formal parameters of the procedure (defined here), and by the procedure function, implementing the behavior of the procedure (extern definition here).

The Type yVDef_ProcedureName

For each procedure there will be a struct containing one component for each formal parameter (FPAR) and each variable (DCL). There will also be a component for each type of expression that is used in decisions, except for the types Integer, Real, Boolean, Character, PId. For a decision with a Charstring question:

there will be a component where the question value can be stored. Together with the struct type, there will also be a pointer type to the struct type:

where FPAR_var1 is assumed to be an IN parameter, while FPAR_var2 is assumed to be an IN/OUT parameter. Note that an IN/OUT parameter is represented as an address. In a procedure, all variables, formal parameters, and decision variables, from all the inherited procedures are included in the struct above, starting from the top of the inheritance chain.

Signal, Timer

For a signal or a timer a definition of a SignalIdStruct is generated. If the signal or timer contains parameters, a struct yPDef_SignalName with one component for each parameter is generated.

Remote Procedure

The following declarations are generated for a remote procedure in SDL.

For a remote procedure one RemotePrdIdStruct is defined together with two SignalIdStructs and yPDef_... structs, for the two implicit signals used to implement an RPC call. The pCALL signal has one signal parameter for each procedure parameter, while the pREPLY signal has one parameter for each in/out parameter to the procedure. Empty yPDef_ structs are not generated.

Variable, Formal Parameter

The following definition of a VarIdStruct is generated for each variable and formal parameter in processes, process types, procedures, and operator diagrams.

Remote Variable

For a remote variable (the remote definition, either it is explicit or implicit) a definition of a RemoteVarIdStruct is generated.

State

The following definition of a StateIdStruct is introduced for each state. The StateName (z002_State3 in example below) is used as the representation of the state in, for example, the state variable in a process. This name is defined to an appropriate integer value.

If the state contains enabling conditions then an extern definition for an enabling condition function is generated:

If the state contains continuous signals then an extern definition for an continuous signal function is generated:

Channel, Signal Route, Gate

A channel, signal route or gate is represented by two ChanneIdStructs, one for each direction.

Newtype, Syntype, Synonym and #CODE (#TYPE section)

Synonyms Translated to Macros

For each synonym definition that can be translated to a macro (predefined data type and computable at code generation time) the following code is generated:

Type Definitions from Abstract Data Types and #CODE
(#TYPE Section)

The unit is scanned for Newtypes, Syntypes, and #CODE directives (among declarations). The search algorithm is described in Implementation.

If newtype or syntype is found:

  1. A typedef which is the translation of the SDL type to C, if the user has not turned off the generation of the type in the #ADT directive.
  2. An extern definition of a xSortIdStruct:

  3. #ifndef XOPTSORT
    extern XCONST struct xSortIdStruct ySrtR_sort1;
    #define ySrtN_sort1  (&ySrtR_sort1)
    #endif
    
  4. The #TYPE section in the #ADT directive is copied.
  5. If the #ADT directive contains a name of a file that should be included then:

  6. #include "filename"
    
    

If #CODE directive is found the following is generated:

Example of a type section for a struct.

Function Headings from Abstract Data Types

The unit is scanned for Newtypes and Syntypes. In the order the types are found the following is generated:

  1. The #HEADING section in the #ADT directive is copied.
  2. Help function headings and some macros. Examples:
  3. extern void yAss_TypeName
      XPP(( TypeName *, TypeName , int ));
    
    
    extern void yDef_TypeName  XPP(( TypeName * ));
    
    
    #define yDef_TypeName1(yVar) \
       *(yVar) = DefaultExpression;
    #define yDef_TypeName2(yVar) \
       yDef_TypeName3(yVar)
    
    
    The first macro is used in most circumstances, and the second is used for a syntype, without default value, of a structured type. In this case the default function for the base type is reused.
    extern char * yWri_TypeName XPP(( void * ));
    
    
    extern int yRead_TypeName XPP(( void * ));
    
    
    extern SDL_Boolean yEq_TypeName
      XPP(( TypeName, TypeName ));
    
    
    extern TypeName yMake_TypeName
      XPP(( ComponentTypeName ));
    
    
    extern TypeName yMake_TypeName
      XPP(( Component1TypeName,
            Component2TypeName ))
    
    
    extern yComp1Make_TypeName XPP(( Comp1TypeName ));
    extern yComp2Make_TypeName XPP(( Comp2TypeName ));
    
    #ifdef XTESTF
    extern xbool  yTest_TypeName  XPP(( TypeName ));
    #endif
    #ifdef XERANGE
    extern TypeName  yTstA_TypeName XPP(( TypeName ));
    #else
    #define yTstA_TypeName(yExpr)  yExpr
    #endif
    #ifdef XEINDEX
    extern TypeName  yTstI_TypeName XPP(( TypeName ));
    #else
    #define yTstI_TypeName(yExpr)  yExpr
    #endif
    
    
    The yTstA_TypeName and yTstI_TypeName are used to check the validity of an assignment to a syntype variable (yTstA_) and to check the validity of an index expression when indexing an array.

Note: 

Note that the compilation flags XERANGE and XEINDEX determine if there should be test functions or if the macro versions, which only are substituted by the expression, should be used.

  1. If the type is a newtype, then operator and literal function headings are generated.

  2. For each literal that should have a generated heading (type not translated to enum type):

    extern TypeName  LiteralName XPP(( void ));
    
    
    For each operator that should have a generated heading:

    extern ResultTypeName  OperatorName
      XPP(( appropriate parameters ));
    
    
Synonym Variables

For each synonym that cannot be translated to a macro (this includes the external synonyms) a variable declaration is generated. If code is generated on a .h file, extern declarations are placed here and the current variable declarations will be generated later.


Example 348       

The variables representing the SDL synonyms are assigned values during startup of the program in the init function, see Initialization.

CODE Directives, #HEADING Section

All #CODE directives (among declarations) are scanned in their relative order and the #HEADING sections are copied.

CODE Directives, #BODY Section

All #CODE directives (among declarations) are scanned in their relative order and the #BODY sections are copied.

Variables and Functions

Here the declaration of the variables and functions, defined in section Types and Forward References, can be found. The symbol table tree discussed in this previous section is here once more traversed in the same order.

System, System Instance, System Type

The following declarations are generated for a system:

The components in the xSystemIdNode for the system, can be compared with the type definitions for the IdSystemStruct, see section Type Definitions from Abstract Data Types and #CODE (#TYPE Section).

For a system instance a similar sequence of code is generated. The differences are in the IdNode for the system:

Here we see the implementation of the ySysP_z_systype1 list of channels, discussed in the subsection about systems in Types and Forward References. Note also the ySysP_z_systype1 is stored in the IdStruct for the system instance.

For a system type the following code is generated:

Package

Only the declaration of a PackageIdStruct is generated for a package.

Block Substructure

A BlockSubstIdStruct according to the example below is generated for block substructures, except in block instantiations.

Block, Block Instance, Block Type

For a block or block instantiation the following BlockIdStruct declaration in generated. The yBloP_BlockName list is only generated for a block containing processes but no signal routes and for a block instantiation. In block this list contains the processes, process instantiations in the block, and the out-going channels from the block. The purpose of the list is to replace the (implicit) signal routes.

In a block instance the yBloP_BlockName has two purposes, one is the replace implicit signal routes, the other is to store references to different entities in the block instance, so generated code for the corresponding block instance can access the entities in the instance. For example, an OUTPUT VIA a signal route should access the signal route in the block instance, even though the code is generated for the block type.

This yBloP_BlockName will contain the following entities:

Block or Block Instance with Substructure
Block or Block Instance with Processes

If the block contains processes with revealed variables a yView list is generated. This contains value tuples for each revealed variable with {PrsIdNode for revealing process, revealing service, offset in yVDef struct for value}.

For a block type the following BlockIdStruct declaration is generated:

Process, Process Instance, Process Type

A process or a process type is represented basically by a PrsIdStruct (declared here), a yVDef_ProcessName struct (typedef in Type and Forward References section), and the yPAD_ProcessName function (declared here). In the example below

The macro XPROCESSDEF_C is not used in the Master Library.

After these data declaration, any exported variable or exported procedure will cause the generation of a list element that will be inserted in the remote definition for the entity.

After that a function is generated that is used to translated a symbol number to a symbol type and a SDT reference.

As last information for a process the yPAD function is generated. In this the implementation of the behavior of the process is implemented. This function will be discussed in detail, in the section Process Behavior.

Process Instantiation

For a process instantiation most of the information needed to represent it can be reused from its process type. It is only necessary to generate the avail list and active list pointers and the PrsIdStruct. Then of course the process gates have to be handled and the connection data areas, for connecting the process and the gate into paths.

Note: 

A process (SDL-88 process) in a block type or a system type, is treated as a process type and process instantiation at the same place.

Service, Service Instantiation, Service Type

The following code is generated for a service.

First for a service we have the declaration of the coverage array for the symbols in the procedure, then we have the state list, the avail list pointer, and the SrvIdStruct for the service. Last is the list of connected service signal routes for this service.

After these declaration of a yRef_ServiceName function and the PAD function for the service can be found. For more information about these function please see the corresponding information about processes.

Procedure, Operator Diagram

The following code is generated for a procedure. A operator diagram is treated just as a procedure.

First for a procedure we have the declaration of the coverage array for the symbols in the procedure, then we have the state list, the avail list pointer, and the PrdIdStruct for the procedure.

After these declarations the yRef_ProcedureName function can be found. This function is used to translate a symbol number to a symbol type and a SDT reference to the symbol.

Last for the procedure the procedure function, implementing the behavior of the procedure can be found. The details in this function will be discussed in detail in the section Process Behavior.

Signal, Timer

For a signal or timer a SignalIdStruct is generated here:

If the signal contains parameter then one VarIdStruct is generated for each signal parameter:

Remote Procedure

A remote procedure declaration in SDL generates several IdStructs, one for the remote procedure and two for the implicit signals used to implement a remote procedure call. Additionally one VarIdStruct is generated for each signal parameter of the implicit signals (just as for an ordinary signal). The implicit pCALL signal has one signal parameter for each procedure parameter, while the implicit pREPLY signal has one parameter for each in/out parameter to the procedure.

Variable, Formal Parameter

The following declaration is an example of a VarIdStruct for a process variable.

Remote Variable

For a remote variable the following declaration is generated:

The last component in the struct is a list of all exported variables connected to this remote definition. This list is built up in the yInit function via calls of the function xInsertExportedVar:

State

For a state a StateIdStruct, together with some list, are generated. The list are used as follows:

Enabling Conditions

If the state contains one or more enabling conditions, an enabling condition function is generated that handles all enabling conditions in this state. A pointer to this function is stored in the StateIdStruct for the state.

Continuous Signals

If the state contains one or more continuous signals, a continuous signal function is generated that handles all continuous signals in this state. A pointer to this function is stored in the StateIdStruct for the state.

Channel, Signal Route, Gate

A channel, signal route or gate is represented by two ChannelIdStructs, one for each direction. An example of such a declaration is given below.

The two lists yChaS1_z1_C1 and yChaS2_z1_C1 represent the signal set of the two directions of the channel. The ToId component in a channel, signal route, or gate is used for connecting such objects together with processes into paths. For this purpose the yBloP_BlockName component in a block is used. Sometimes a list with names:

is generated and used for such connections.

Newtype, Syntype

Example of generated code for a struct called struct1 with two integer components a and b:

  1. First the SortIdNode for this newtype or syntype is declared. This is followed by the IdNodes for struct components or literals (if valid).
  2. After that the help function bodies are generated.
  3. #ifndef XNOPROTO
    extern void yAss_TypeName (
      TypeName *yVar,
      TypeName  yExpr,
      int       AssType )
    #else
    extern void yAss_TypeName (yVar, yExpr, AssType)
      TypeName *yVar;
      TypeName  yExpr;
      int       AssType;
    #endif
    {
      code to perform assignment
    }
    
    #ifndef XNOPROTO
    extern void yDef_TypeName( TypeName *yVar )
    #else
    extern void yDef_TypeName( yVar )
      TypeName  *yVar;
    #endif
    {
      code to assign the default value to
      variable yVar
    }
    
    
    #ifndef XNOPROTO
    extern SDL_Boolean yEq_TypeName(
      TypeName yExpr1, TypeName yExpr2 )
    #else
    extern SDL_Boolean yEq_TypeName
      ( yExpr1, yExpr2 )
      TypeName  yExpr1, yExpr2;
    #endif
    {
      code to check if yExpr1 and yExpr2 are
      equal
    }
    
    
    #ifndef XNOPROTO
    extern TypeName  yMake_TypeName(
      ComponentTypeName yExpr)
    #else
    extern TypeName  yMake_TypeName( yExpr )
      ComponentTypeName yExpr;
    #endif
    {
      code to return an array with all components 
      equal to yExpr
    }
    
    
    #ifndef XNOPROTO
    extern TypeName  yMake_TypeName(
      Component1TypeName  yComponent1,
      Component2TypeName  yComponent2 )
    #else
    extern TypeName  yMake_TypeName
      ( yComponent1,yComponent2 )
      Component1TypeName  yComponent1;
      Component2TypeName  yComponent2;
    
    #endif
    {
      code to return a struct with value
      according to the parameters
    }
    
    
    #ifndef XNOPROTO
    extern TypeName  yComponent1Make_TypeName(
      Component1TypeName  yComponent1 )
    #else
    extern TypeName  yComponent1Make_TypeName
      ( yComponent1 )
      Component1TypeName  yComponent1;
    #endif
    {
      code to return a choice with value
      according to the parameters
    }
    
    
    #ifdef XTESTF
    #ifndef XNOPROTO
    extern xbool yTest_TypeName(TypeName yExpr)
    #else
    extern xbool yTest_TypeName( yExpr )
      TypeName  yExpr;
    {
      code to check if yExpr is in the range
      conditions for this newtype or syntype
    }
    #endif
    #ifdef XERANGE
    #ifndef XNOPROTO
    extern TypeName  yTstA_TypeName(TypeName yExpr )
    #else
    extern TypeName  yTstA_TypeName( yExpr )
      TypeName  yExpr;
    #endif
    {
      if (! yTest_TypeName(yExpr) ) {
        xErrorSubrange(ySrtN_TypeName,
          xWriteSort(&yExpr, ySrtN_TypeName));
      return yExpr;
    }
    #endif
    
    #ifdef XEINDEX
    #ifndef XNOPROTO
    
    extern TypeName  yTstI_TypeName(TypeName yExpr )
    #else
    extern TypeName  yTstI_TypeName(  yExpr )
      TypeName  yExpr;
    #endif
    {
      if (! yTest_TypeName(yExpr) ) {
        xErrorIndex(ySrtN_TypeName,
          xWriteSort(&yExpr, ySrtN_TypeName));
        return lowest value of type;
      }
      return yExpr;
    }
    #endif
    
    
  4. The #BODY section in the #ADT directive is copied.
  5. If the type is a newtype then the operator and literal function bodies of the operators and literals that should have question functions are generated. Code is generated for each operator or literal according to the example below, where the code for an operator with two parameters is shown. A literal is treated as an operator without parameters.

Example 349       

Initialization

The init function is used to initialize the generated program and has the following structure:

The name of the init function is yInit in a unit for a system or system instance and yInit_UnitName in a non-system unit.

Building the Symbol Table Tree

In the code to build the symbol table tree, nodes that represent the static structure of the SDL system are inserted into the tree, using the function xInsertIdNode:

This function updates the Suc and First pointers in the IdNodes. In an application this operation is not necessary. In that case xInsertIdNode is defined as an empty macro!

The yInit function will also contain some additional code for the symbol table. For example: for each exported variable the statement below will be executed to add knowledge about the exporting processes in the IdNode for a remote variable.

The same structure is used for exported procedures, but the function is then called xInsertExportedPrd.

In the yInit function calls to yInit functions for subunits are inserted. In the yInit for the system or system instance unit, the yInit functions for the used packages are also inserted.

Creation of Static Process Instances

For each process or process instantiation there will be one macro call of INIT_PROCESS_TYPE. This is in the Master Library expanded as nothing.

Depending on how many static instances that should be created of the process or process instantiation, the will be either:

Example of code for a process P1 with one static instance.

The macro SDL_STATIC_CREATE above is expanded to:

Initialization of Synonyms


Example 350 : Initialization of synonyms      

SynonymName1 and SynonymName2 are ordinary synonyms and ExtSynonymName is an external synonym.

Process Behavior

This section will treat the yPAD_ProcessName and yProcedureName functions, that are used to implement the actions performed by processes.

Structure of Process and Procedure Functions

There will be one function for each process and process type and each procedure, where the actions performed by the process or procedure during transitions are placed. Functions that represent processes and procedures have the structure given below, where the sections referenced in these examples are discussed in the next subsections.

The prototypes for the process and procedure functions contain some macros. These are expanded in the examples below.


Example 351        


Example 352       

Local Variables Section

The following local variables will always be present:

which after macro expansion becomes:

If it is a procedure that is generated then the following is generated:

This is expanded to almost the same code as for the process:

If the process or procedure contains any decisions of type Integer, Boolean, Real, Character, or PId, there will be decision variables for the used types:

If the process or procedure contains any outputs with a via list then:

Section Handling Procedure Calls

If the process contains any procedure call the following code is introduced to handle the case when the execution of the process is interrupted within a procedure call (single-step in the monitor or states in the procedure):

where CALL_PROCEDURE_STARTUP is defined as:

Switch Statement

To be able to resume the execution at any symbol in the SDL graph there is a switch statement surrounding all the code for the SDL actions. If the generated code is executed together with the monitor, the switch is used to restart execution at any symbol, while if the code is just executing code, only the symbols that start a transition, like input, continuous signal, and symbols after procedure calls are of interest for restart.

If code is generated for a process, the switch statement looks as follows:

If code is generated for a procedure, the switch statement looks as follows:

If the process that is translated contains services, there will be no switch statement. Instead the following code is generated in the PAD function:

Translation of Symbols

The following actions (+label) are treated:

Start, Input, Priority input, Continuous signal, Task, Output, Create, Decision, Set, Reset, Export, Call, Nextstate, Join, Stop, Return, and Label.

Between the translation of two symbols the following code is generated (not before Join and Label):

where SymbolNumber is an integer identifying the symbol and LineNo is the line number of this statement in the C file. If the previous symbol is a procedure call then the

is replaced by

The macro XBETWEEN_SYMBOLS (or XBETWEEN_SYMBOLS_PRD if symbol in a procedure) is in a simulator expanded to a call of the function xBreakBefore, which determines if the monitor system should be entered between these two symbols on not.

Translation of Start

The start symbol is translated according to the following example:

In the start symbol, which always have the case label 0, assignment of the FPARs from the startup signal and assignments of start values to all local variables in the process are made. In a procedure only the assignment of start values for variables are performed.

Translation of Input and Continuous Signal

An input or a priority input is translated according to the following example:

where XDEBUG_LABEL and XOS_TRACE_INPUT are expanded to nothing. The macro XAT_FIRST_SYMBOL is in a simulator expanded to a function call to setup the graphical trace. The important action performed in an input symbol is to copy the parameters of the signal to the local process variables, as specified in the input statement.

A continuous signal is translated according to the same model as used for inputs. A continuous signal, however, never has any parameters:

Translation of Task

The assignment statements in a task are individually (as symbols of their own) translated to assignments in C, while informal text in a task is ignored (except in trace). The following structure is generated:

The assignment is always generated using a yAssF_... macro, which is either expanded to assignment in C or the call of an assignment function. For more information about variables and expressions see the section Translation of SDL Expressions.

Translation of Output

OUTPUT statements are translated to the following basic structure:


Example 353       

An OUTPUT of, for example, a signal called Sig2 with one parameter will be translated to:

The macro ALLOC_SIGNAL_PAR will be expanded to a function call of xGetSignal. This function (in sctos.c) will create and initialize a signal instance. The macro SDL_2OUTPUT will be expanded to a call of the function SDL_Output, which is the function where the signal is sent.

ToExpr is a translation of the expression after TO in the OUTPUT statement. If no such expression is found, the value xNotDefPId is generated at this place.

xDefaultPrioSignal is replaced by the actual signal priority, if such a priority is assigned in the output or in the signal definition.


There are a number of versions of the ALLOC_SIGNAL and SDL2_OUTPUT macros.

If a VIA clause is given in the OUTPUT, then (xIdNode *)0 is replaced by yViaList, and the SDL_Output statement will be preceded by a number of assignment statements where yViaList is assigned an appropriate value.


Example 354       

Example of via list containing two channels:


Translation of Create

CREATE statements are translated to the following basic structure:

A CREATE of, for example, a process called P2 with one parameter will be translated to:

The macro ALLOC_STARTUP_PAR will be expanded to the call of the function xGetSignal, while SDL_CREATE will be expanded to a call of the function SDL_Create.

There are a number of versions of the ALLOC macro:

The value xDefaultPrioProcess will be replaced by the process priority if a #PRIO directive is used.

Translation of Decision

We distinguish between three types of decision:

The informal decisions and the any decisions are treated last in this subsection about decisions.

XBETWEEN_SYMBOL macros are used to represent the statements in that decision path. An informal decision according to the following example:

is generated as:

XBETWEEN_SYMBOL macros are used to represent the statements in that decision path.

Translation of Set

SET on timer without parameters:

A set operation on a timer without parameters is generated according to the following example:

This macro is expanded to a call of the function SDL_Set. There are three version of the SDL_SET macro:

A SET operation on a timer with parameters is generated using the following structure which is similar to the structure used for outputs:

The SDL_SET_DUR_WITH_PAR macro is expanded to a call of the function SDL_Set. There are three version of the SDL_SET macro for timers with parameters:

Translation of Reset

A RESET operation on a timer without parameters is generated using the macro SDL_RESET, according to the following example:

The SDL_RESET macro is expanded to a call of the function SDL_SimpleReset.

A reset operation on a timer with parameters is generated exactly as a set operation with parameters, except that the macro SDL_SET_WITH_PARA is replaced by:

This macro is expanded to:

Translation of Export

The following assignment is generated for an export statement:

Translation of Call

A PROCEDURE CALL (to a procedure called Proc) is generated as:

The ALLOC_PROCEDURE macro will be expanded to a call of the function xGetPrd. After that the actual parameters are assigned to the formal parameters. Note that for an in/out parameter, it is the address of the parameter that is copied.

The CALL_PROCEDURE macro is typically expanded to something like:

where levels is an integer representing the number of declaration levels between the caller and the called procedure. restartaddr is the return address, that is the symbol number of the symbol immediately following the procedure call. Both these parameters are obtained from the macro call.

There are several versions of the ALLOC_PROCEDURE and CALL_PROCEDURE macros.

In SDL-92 it is allowed to perform value returning procedure calls, that is procedure calls performed within an expression. According to the model for this in SDL, such procedure call are calculated before the symbol where it is used.


Example 355       

is translated as if it was transformed to:

where Temp1 and Temp2 are implicit temporary variables, and the extra parameter in the calls are used to pass the result value out from the procedure.


Translation of RPC

A remote procedure call is translated according to its transformation model in SDL. In SDL an RPC call:

is transformed to:

The difference between the code generated for ordinary outputs, nextstates and the transformed actions according to the example above, is that some other macros are used:

The output of the pCALL signal is for example translated using the macro SDL_2OUTPUT_RPC_CALL, while the implicit nextstate above is translated using SDL_RPCWAIT_NEXTSTATE.

In the exporter of procedures implicit transitions are inserted:

This is implemented as:

  1. Receive signal pCALL.
  2. Create the pREPLY signal.
  3. Copy in/out parameter from pCALL to pREPLY.
  4. Call procedure with in parameters from the pCALL signal and in/out parameters as the address of the corresponding parameter in pREPLY.
  5. After the procedure has returned, output the pREPLY signal.
  6. Perform an ordinary nextstate operation.
Translation of Nextstate

A NEXTSTATE is generated as a call to the xGRSetSymbol function followed by an application of one of the macros below:

This macros are expanded to calls of the function SDL_Nextstate followed by a return statement.

Translation of Join

A JOIN is translated to a goto in C.

If the referenced label is in a super type, the join statement is translated to a macro.

Translation of Stop

A STOP action is translated to the macro SDL_STOP. After macro expansion the code becomes a call of the SDL_Stop function followed by a return statement.

Translation of Return

A RETURN is generated as an application of the macro
SDL_RETURN. After macro expansion this becomes:

Translation of Label

An SDL LABEL is simply translated to a C label. The C name will be L_SDLLabelName.

Translation of SDL Expressions

In this section some of the translation rules for expressions are described. For more information see The Cadvanced/Cbasic Code Generatorwhere, for example, the translation rules for literals and operators in the predefined abstract data types are given.

Subrange Variable

If an expression is assigned to a subrange variable (in a task, input, output,...) a test function is generated to check the consistency of the value:

where yTstA_TypeName is either a consistency check function or a macro that replaces the macro call by only the expression itself.

Index in Array

If an expression is used as index expression of an array, yTstI_TypeName is used in exactly the same way to check the consistency of the index expression.

SDL Variable

An SDL variable is represented in C by:

The examples are:

  1. Reference to a process variable from the process or from a called procedure.
  2. Reference to a local variable or formal IN parameter from the procedure.
  3. Reference to a variable declared one static level above the one accessing the variable. The number of
    ->StaticFather determines the difference in declaration levels.
  4. Reference to a formal IN/OUT parameter from the procedure.
View

A VIEW expression is translated to a macro call SDL_VIEW. This is later expanded to a function call of SDL_View.

Import

An IMPORT expression is translated to a macro call of the macro XGETEXPORTADDR, which is expanded to a function call of the function xGetExportAddr:

Now

NOW is translated to the macro SDL_NOW which is expanded to SDL_Now().

Self, Parent, Offspring, Sender

SELF, PARENT, OFFSPRING, SENDER are translated to:

Timer Active

A TIMER ACTIVE expression is translated to:

which is expanded to:

A conditional expression in SDL is translated to a conditional expression in C.

Allocating Dynamic Memory

Introduction

This section deals with the allocation and deallocation of dynamic memory in SDT.

Note: 

This information is only valid when the Master Library is used. The OS integrations might have different strategies for memory allocation.

Information is provided about the following topics:

Dynamic memory is used for a number of objects in a run-time model for applications generated by the Cadvanced/Cbasic Code Generator. These objects are:

To help to estimate the need for memory for an application we will give information about the size of these objects and about how many of the objects are created. The size information given is true for generated applications, that is, ones that do not, for example, contain the monitor. The type definitions given are stripped of components that will not be part of an application. The full definitions may be found in the file scttypes.h.

Processes

Each process instance is represented by two structs that will be allocated on the heap. In scttypes.h the type xLocalPIdRec is defined and in generated code yVDef_ProcessName structs are defined:

To calculate the size of the structs above it is necessary to know more about the components in the structs. The types xPrsNode, xPrdNode,xSignalNode, xPrsIdNode, xStateIdNode, and xSignalIdNode are all pointers, while SDL_PId is a struct containing an int and a pointer. The xInputPortRec is a struct with two pointers and one int.

This means that it is possible to calculate the size of the xLocalPIdRec and the xPrsRec struct using the following formulas, if the compiler does not use any strange alignment rules:


Extracted pic [11]


Extracted pic [12]

The size of xPrsRec can be reduced by 2 x sizeof (address) if the code is compiled with the XNOUSEOFSERVICE flag. Then, of course, the SDL concept service cannot be used. The size of yVDef_ProcessName is the size of the xPrsRec plus the size of the variables and parameters in the process. Any overhead introduced by the C system should also be added. The size of the formal parameter and variables is of course dependent on the declarations in the process. The translation rules for SDL types, both predefined and user defined, can be found in The Cadvanced/Cbasic Code Generator.

For each process instance set in the system the following number of structs of a different kind will be allocated:

The yVDef_ProcessName structs are reused by having an avail list where this struct is placed when the process instance it represents perform a stop action. There is one avail list for each process type. When a process instance should be created, the runtime library first looks at the avail list and reuses an item from the list. Only if the avail list is empty new memory is allocated.

Compilation switch XPRSOPT

If the compilation switch XPRSOPT is defined then:

Services

Services are handled very similar to processes. The following struct type are allocated for each service instance.

This means that:


Extracted pic [13]

The size of yVDef_ServiceName is the size of the xSrvRec plus the size of the variables in the service. yVDef_ServiceName struct are reused in the same way as for processes (see previous section).

Signals

Signals are handled in much the same way as processes. A signal instance is represented by one struct (in generated code generated).

This struct type contains one component for each signal parameter. The component types will be the translated version of the SDL types of the parameters.

This means that it is possible can calculate the size of a xSignalRec, which is the same as a struct for a signal without parameters, using the following formula:


Extracted pic [14]

The size of a yPDef_SignalName struct is thus equal to the size of the xSignalRec plus the size of the parameters. The translation rules for SDL types, both the predefined and user defined, can be found in The Cadvanced/Cbasic Code Generator.

For each signal type in the system the following number of data areas will be allocated:

The yPDef_SignalName struct is reused by having an avail list, where the struct is placed when the signal instance they represent is received. The exact point where the signal instance is returned to the avail list is when the transition caused by the signal instance is ended by a nextstate or stop action. There is one avail list for each signal type. When a signal instance should be created, for example during an output operation, the runtime library first looks at the avail list and reuses an item from this list. Only if the avail list is empty new memory is allocated.

Note: 

There is one common avail list for all signals without parameters.

Timers

The memory needed for timers can be calculated in the same way as for signals with one exception, each timer contains an extra SDL_Time component, i.e. two extra 32-bit integers.

Procedures

Procedures and processes have much in common in terms of memory allocation. A procedure is, during the time it exists from call to return, represented by a struct; the yVDef_ProcedureName.

The struct type contains one component for each formal parameter or variable. The component types will be the translated version of the SDL types of the parameters, except for an IN/OUT parameter which is represented as an address.

The size of the xPrdRec struct (which is the same as a procedure without variables and formal parameters) can be calculated using the following formula:


Extracted pic [15]

The size of a yVDef_ProcedureName struct is the size of the xPrdRec plus the size of the formal parameter and variables defined in the procedure. The translation rules for SDL types, both the predefined and user defined can be found in The Cadvanced/Cbasic Code Generator.

For each type of procedure in the system the following number of data areas will be allocated:

The yVDef_ProcedureName struct is reused by having an avail list, where this two struct is placed when the procedure instance executes a return action. There is one avail list for each procedure type. When a procedure instance should be created, that is, at a call operation, the runtime library first looks at the avail list and reuses an item in the list. Only if the avail list is empty new memory is allocated.

Data types

The predefined SDL type charstring is implemented as char * in C and thus requires dynamic memory allocation. The predefined data types Bit_String and Octet_String are also implemented using dynamic memory.

The implementation of the SDL sorts Charstring, Bit_String, and Octet_String is both flexible in length and all memory can be reused.

The mechanism used to release unused memory is to call the xFree function in the file sctos.c, which uses the standard function free to release the memory. For more details please see the section Changing the Standard Memory Allocation Procedure.

Charstrings, Bit_Strings, and Octet_Strings are also handled correctly if they are part of structs or arrays. When, for example, a new value is given to a struct having a charstring component, the old charstring value will be released. For all structured types containing any of these types there will also be a Free function that is utilized to release all dynamic memory in the structured variable.

Functions for Allocation and Deallocation

The allocation and deallocation of memory is handled by the functions xAlloc and xFree in the file sctos.c. The functions in this file are used for the adoption of the generated applications to the operating system or hardware. The sctos.c file is described in detail in The sctos.c File.

In generated code and in the run-time library the functions xAlloc and xFree are used in each situation where memory is needed or can be released. xAlloc receives as parameter a requested size in bytes and returns the address to a data area of the requested size. All bytes in the data area are set to zero. xFree takes the address of a pointer and returns the data area referenced by the pointer to the pool of free memory. It also sets the pointer to 0.

The xAlloc and xFree functions are usually implemented using some version of the C standard functions for allocation (malloc, calloc) and deallocation (free). Other implementations are of course possible as long as the interface described in the previous section is fulfilled. In a micro controller, for example, it is probably necessary to handle allocation and deallocation directly towards the physical memory.

To prevent memory fragmentation we have used our own avail lists in almost all circumstances. Memory fragmentation is phenomena occurring when a program allocates and de-allocates data areas (of different sizes) in some "random" order. Then small pieces of memory here and there are lost, since their sizes are to small to fit an allocation request. This can lead to a slowly increasing demand for memory for the application.

Note that deallocation of memory is only used for data types, for Charstring and data types where it is decided to implement the data type with dynamic memory. This means that if Charstring variables are not used and the user has not introduced the need for deallocation of memory himself, no memory deallocation will occur. In this case it is of course unnecessary to implement the xFree function.

It is easy to trace the need for dynamic memory. As all memory allocation is carried out through the xAlloc function and this function is available in source code (in sctos.c), it is only necessary to introduce whatever count statements or printout statements that are appropriate.

Changing the Standard Memory Allocation Procedure

In this section we describe how it is possible to re-implement the memory handling functions to avoid the standard avail lists and how to customize memory reuse.

The basic tools are the sctos.c functions:

and the compilation switch XFREEVARS. The functions for Bit_String are also used for Octet_String.

The xGet functions mentioned above will be called each time a process, signal, or procedure is to be created. The functions first look in their avail lists and only if this is empty a new data area is created. The Get functions then initializes the data area. By changing the implementation of these functions it is possible to allocate memory in any suitable way. The xAlloc_SDL_Charstring is called each time a new data area for a charstring is needed. The corresponding is true for Bit_String and Octet_String.

The xRelease and xFree functions listed will be called when a process, signal, procedure, Charstring, Bit_String, or Octet_String data area is to be returned to the pool of free memory. In the standard implementation the memory is returned to the avail list for the object (except for charstring). By changing these functions, memory may be returned to the pool of available memory in any way. (By not entering the memory in the avail list, the xAlloc function above will always be called when memory is needed.)

The remaining problem now is the dynamic data values among the variables and parameters in the processes, signals and procedures.

Everything that is said above about Charstring, Bit_String, or Octet_String values is also true for user defined data types implemented using dynamic memory. If a Free function is introduced in the #ADT directive, the type is treated in the same way as charstring in relation to memory handling.

Compilation Switches

The compilation switches are used to decide the properties of the Master Library and the generated C code. Both in the library and in generated code #ifdefs are used to include or exclude parts of the code.

The switches that are used can be grouped into five groups.

  1. Switches defining the compiler.
  2. Switches defining properties of the compiler.
  3. Switches defining a library version.
  4. Switches defining a property of a library version.
  5. Switches defining the implementation of a property.

The first two groups will be discussed in Adaptation to Compilers.

The following switches define the library version:

Switch Corresponds to Library

SCTDEBCOM

Simulation


SCTDEBCLCOM

RealTimeSimulation


SCTAPPLCLENV

Application


SCTDEBCLENVCOM

ApplicationDebug
(Simulation with environment)


SCTPERFSIM

PerformanceSimulation
(Library with simulated time, no environment functions, no monitor.)


SCTCORBA

Application with CORBA environment


SCTCORBASIM

Simulator, with real time and env functions, with CORBA environment.

The definition of the properties of these libraries can be found in scttypes.h and will be discussed below. Each library version is specified by the switches in the group property switches that it defines.

New library versions, containing other combinations of property switches, can easily be defined by introducing new library definitions in the scttypes.h file.

The property switches discussed below can be used to form library versions. If not stated otherwise for a certain property, all code, variables, struct components, and so on, are either included or excluded using conditional compiling (#ifdef), depending on whether the property is used or not.

This means, for example, that all code for the monitor interface will be removed in an application not using the monitor, which makes the application both smaller and faster.

Description of Compilation Switches

XCLOCK

If this compilation switch is not defined then simulated time is used, otherwise the system time is connected to a real clock, via the sctos.c function SDL_Clock.

XCALENDERCLOCK

This is the same as XCLOCK (it will actually define XCLOCK), except that if XCLOCK is used, time will be zero at system start up, while if XCALENDERCLOCK is used, time will be whatever the clock returns at system start up.

XPMCOMM

Define this compilation switch if the application should be able to communicate with signals via the SDT communication mechanism. This facility is used to accomplish communicating simulations and simulations communicating with, for example, user interfaces.

XITEXCOMM

This switch should be defined if a generated simulator should be able to communicate with an ITEX simulator.

XENV

If this compilation switch is defined the environment functions xInitEnv, xCloseEnv, xInEnv, and xOutEnv will be called at appropriate places.

XTENV

This is the same as XENV (it will actually define XENV), except that xInEnv should return a time value which is the next time it should be called (a value of type SDL_Time). The main loop will call xInEnv at the first possible occasion after the specified time has expired, or when the SDL system becomes idle.

XENV_CONFORM_2_3

This switch make signals using a compatible data structure as in SDT 2.3. This means that an extra and unnecessary component yVarP is inserted in each signal.

XSIGLOG

This facility makes it possible for a user to implement his own log of the major events in the system. This compilation switch is normally not defined. By defining this switch, each output of a signal, i.e. each call of the function SDL_Output, will result in a call of the function xSignalLog. Each time a transition is started, the function xProcessLog will be called.

These functions have the following prototypes:

which are included in scttypes.h if XSIGLOG is defined.

Signal will be a pointer to the data area representing the signal instance.

NrOfReceivers will indicate the success of the output according to the following table:

NrOfReceivers Output Statement Contents

-1:

A TO clause, but no path of channels and signal routes were found between the sender and the receiver.

0:

No TO clause, and no possible receivers were found in the search for receivers.

1:

If the output statement contains a TO clause, a path of channels and signal routes was found between the sender and the receiver.
If the output statement contains no TO clause, exactly one possible receiver was found in the search for receivers.
The output was thus successful. The only error situation that still might be present is if an output with a TO clause is directed to a process instance that is stopped.

The third parameter, Path, is an array of pointer to IdNodes, where Path[0] refers to the IdNode for the sending process, Path[1] refers to the first signal route (or channel) in the path between the sender and the receiver, and so on, until Path[PathLength] which refers to the IdNode for the receiving process.

The parameter P in the xProcessLog function will refer to the process just about to start executing.

The fourth parameter, PathLength, represents thus the number of components in the Path array that are used to represent the path for the signal sent in the output. If the signal is sent to or from the environment, either Path[0] or Path[PathLength] will refer to xEnvId, that is to the IdNode for the environment process.

In the implementation of the xSignalLog and xProcessLog functions which should be provided by the user, the user has full freedom to use the information provided by the parameters in any suitable way, except that it is not possible to change the contents of the signal instance. The functions are provided to make it possible for a user to implement a simple log facility in environments where standard IO is not provided, or where the monitor system is too slow or too large to fit. A suitable implementation can be found in the file sctenv.c

XTRACE

If this compilation switch is defined, traces of the execution can be printed.

This facility is normally used together with the monitor, but can also be used without the monitor. The file stdout must of course be available for printing.

Setting trace values must, without the monitor, be performed in included C code, as the monitor interface is excluded. The trace components are called Trace_Default and can be found in IdNodes representing system, blocks, and processes, and in the struct xPrsRec used to represent a process instance. The values stored in these components are the values given in the Set-Trace command in the monitor. The value undefined is represented by -1.

When the monitor is excluded all trace values will be undefined at startup, except for the system which has trace value 0. This means that no trace is active at start up.


Example 356       

Suitable statements to set trace values in C code:

PId_Var is assumed to be a variable of type PId.

Note: 

Note that the variable xPrsN_ProcessName is declared, and therefore only available, in the file containing the block where the process is defined (and in files representing processes contained in the block).


XGRTRACE

If this compilation switch is defined it is possible for a simulation to communicate with the Organizer and the SDL Editor to highlight SDL symbols in the graphical representation.

This feature is used together with the monitor to implement graphical trace and commands like Show-Next-Symbol and Show-Previous-Symbol. It is possible to use graphical trace without the monitor in the same way as the ordinary trace (substitute Trace_Default with GRTrace in the description above). However the graphical trace is synchronized which means that the speed of the application is dramatically reduced.

XCTRACE

Defining this compilation switch makes information available to the monitor about where in the source C code the execution is currently suspended. This facility, which is used together with the monitor, makes it possible to implement the monitor command Show-C-Line-Number.

XMONITOR

If this compilation switch is defined, the monitor system is included in the generated application.

XCOVERAGE

This compilation switch makes it possible to generate coverage tables. It should be used together with XMONITOR.

MAX_READ_LENGTH, MAX_WRITE_LENGTH

These macros control the length of the char * buffers used to read and write values of SDL sorts. A typical usage is when the monitor commands Assign-Value and Examine-Variable are entered. If large data types are used, it is possible to redefine the sizes of the buffers from their default size (5000 bytes) to something more appropriate.

XSIMULATORUI

This compilation switch should be defined if the generated simulator is to be executed from the Graphical User Interface to the simulator monitor.

XMSCE

This compilation switch should be defined if the generated simulator should be able to generate Message Sequence Charts.

XSDLENVUI

This compilation switch should be defined if it should be possible to start and communicate with a user interface (or another application) from the simulation. This feature should be used together with the monitor and will define the switch XPMCOMM (see also this switch).

XNOMAIN

When this compilation switch is defined the functions main and xMainLoop are removed using conditional compiling. This feature is intended to be used when a generated SDL application should be part of an already existing application, that is when the SDL system implements a new function in an existing environment. The following functions are available for the user to implement scheduling of SDL actions:

The behavior of these functions are as follows:

xMainInit: This function should be called to initialize the SDL system before any other function in the runtime library is called. An appropriate way to call xMainInit is:

The compilation switch XCONNECTPM will be defined if the any switch that requires communication via SDT communication mechanism is defined (XPMCOMM or XGRTRACE).

SDL_Execute: This function will execute one transition by the process instance first in the ready queue.

Before calling this function it must be checked that there really is at least one process instance in the ready queue. This test can be performed using the function SDL_Transition_Prio discussed below.

SDL_Transition_Prio: This function returns the priority of the process first in the ready queue (if signal priorities are used it is the priority of the signal that has caused the transition by the actual process instance). If the ready queue is empty, -1 is returned.

SDL_OutputTimer: This function will execute one timer output and may only be called if there is a timer ready to perform a timer output. This test can be performed with either SDL_Timer_Prio or SDL_Timer_Time described below.

SDL_Timer_Prio: This function returns the priority of the timer first in the timer queue if the timer time has expired for this timer. That is, if Nowis greater than or equal to the time given in the Set statement for the timer.

If the timer queue is empty or the timer time for the first timer has not expired, -1 will be returned.

If signal priorities are used, the priority returned is the priority assigned to the timer type (in the timer definition) or the default timer priority; while if process priorities are used the priority returned is the priority of the process that has set the timer.

SDL_Timer_Time: This function returns the time given in the set statement for the first timer in the timer queue. If the timer queue is empty, the largest possible time value (xSysD.xMaxTime) is returned.

Depending on how the SDL system is integrated in an existing environment it might be possible to also use the monitor system. In that case the function xCheckMonitors should be called to execute monitor commands.

To give some idea of how to use the functions discussed above, an example reflecting the way the internal scheduler in the runtime library works is given below:


Example 357       

XMAIN_NAME

Sometimes when integrating generated application or simulations in larger environments the main function can be useful but cannot have the name main. This name can be changed to something else by defining the macro XMAIN_NAME. The main function came be found in the file sctsdl.c.

XSIGPRIO

The XSIGPRIO compilation switch defines that priorities on signals (set in Output statements) should be used. This switch and the three other switches for priorities given below are, of course, mutually exclusive.

A signal priority is specified with a priority directive (see Assigning Priorities -- Directive #PRIO, that is by a comment with the following outline:

A priority can be assigned to a signal instance in an output statement by putting a #PRIO directive last in the output symbol. In SDL-PR it is possible to put the #PRIO directive both immediately before and immediately after the semicolon ending the output statement. The Cadvanced/Cbasic Code Generator will first look for #PRIO directives in the output statement. If no directive is found there it will look in the signal definition for the signal for a priority directive. A #PRIO directive should be placed directly before the comma or semicolon ending the definition of the signal.


Example 358       

If no priority directive is found in the output symbol or in the definition of the signal, the default value for signal priority is used. This value is 100. Timers can be assigned priorities in timer definitions in the same way as signals in signal definitions.

The signal priorities will be used to sort the input port of process instances in priority order, so that the signal with highest priority (lowest priority value) is at the first position. Two signals with same priority are placed in the order they arrive. The priority of the signal that can cause the next transition by a process instance is used to sort the ready queue in priority order, so that the process with a signal of highest priority is first. With equal priority, the processes are placed in the order they are inserted into the ready queue. If a continuous signal caused a processes to be inserted into the ready queue, it is the priority of the continuous signal that will be used as signal priority for this "signal".

Caution! 

Signal priority is not included in SDL according to ITU Recommendation Z.100, and that sorting the signals in the input port of a process instance according to priorities is a direct violation of the SDL standard. This feature is however included for users that need such a behavior to implement their applications.

XPRSPRIO

This compilation switch defines that process priorities should be used. For more information see The Cadvanced/Cbasic Code Generator, section Assigning Priorities - Directive #PRIO.

XSIGPRSPRIO

This compilation switch defines that priorities on signals should be used as first key for sorting in priority order, and process priorities should be used as second key.

XPRSSIGPRIO

This compilation switch defines that process priorities should be used as first key for sorting in priority order, and priorities on signals should be used as second key.

xDefaultPrio...

It is possible to redefine the default priorities for processes, signals, timer signals, continuous signals and start-up signals by defining the symbols below to appropriate values. The default value for these defaults are 100.

XOPT

This compilation switch will turn on full optimization (except XOPTCHAN), that is, it will define the following switches:


XOPTSIGPARA

XOPTDCL

XOPTFPAR

XOPTSTRUCT

XOPTLIT

XOPTSORT

For more information, see these switches below. The XOPT switches should not be used together with the monitor.

XOPTSIGPARA

In the symbol table tree (see section Symbol Table Tree Structure) there will be one node for each parameter to a signal. These nodes are not necessary in an application and can be removed by defining the compilation switch XOPTSIGPARA.

XOPTDCL

There will be a VarIdNode in the symbol table tree for each variable declared in processes, procedures, or operator diagram. These nodes are not used in an application (without the monitor) and can be removed by defining the compilation switch XOPTDCL.

XOPTFPAR

There will be a VarIdNode in the symbol table tree for each formal parameter in a processes, procedures, or operator diagram. These node are not used in an application and may be removed by defining the compilation switch XOPTFPAR.

XOPTSTRUCT

For each component in an SDL struct there will be one VarIdNode defining the properties of this component. These VarIdNodes are not used in an application and can be removed by defining the compilation switch XOPTSTRUCT.

XOPTLIT

For each literal in a newtype that will be translated to an enum type, there will be an LitIdNode representing the literal. These nodes will not be used in an application and can be removed by defining the compilation switch XOPTLIT.

XOPTSORT

Each newtype and syntype, including the SDL standard types, will be represented by an SortIdNode. These nodes are not used in an application if all the other XOPT... mentioned above are defined.

XNOUSEOFREAL

Defining this compilation switch will remove all occurrences of C float and double types, and means for example that the SDL type Real is no longer available.

This switch is intended to be used in situations when it is important to save space, to see to that the library functions for floating type operations are not necessary to load. This switch cannot handle situations when the user includes floating type operations in C code in, for example, #CODE directives.

XNOUSEOFOBJECTIDENTIFER

Defining this switch will remove all code for the SDL predefined sort Object_Identifier.

XNOUSEOFOCTETBITSTRING

Defining this switch will remove all code for the SDL predefined sorts Bit_String, Octet, and Octet_String.

XNOUSEOFEXPORT

By defining this switch the user states that he is not going to use the export - import concept in SDL.

Caution! 

An attempt to perform an import operation when
XNOUSEOFEXPORTis defined will result in a compilation error, as the function xGetExportAddr is not defined.

XNOUSEOFSERVICE

This compilation switch can be defined to save space, both in data and in the size of the kernel, if the SDL concept service is not used. If services are used and this switch is defined, there will be compilation errors (probably many!), when the generated code is compiled.

XPRSOPT

Section Create and Stop Operations describes how xLocalPIdRec structs are allocated for each created process instance, and how these structs are used to represent process instances even after they have performed stop actions. This method for handling xLocalPIdRecs is required to be able to detect when a signal is sent to a process instance that has performed a stop operation.

In an application that is going to run for a "long" period of time and that uses dynamic processes instances, this way of handling xLocalPIdRecs will eventually lead to no memory being available.

By defining the compilation switch XPRSOPT, the memory for the xLocalPIdRecs will be reused together the yVDef_ProcessName structs. This has two consequences:

  1. The need for memory will not increase due to the use of dynamic processes (the memory need depends on the maximum number of concurrent instances).
  2. It will no longer be possible to always find the situation when a signal is sent to a process instance that has performed a stop action.

More precisely, if we have a PId variable that refers to a process instance which performs a stop operation and after that a create operation (on the same process instance set) is performed where the same data area is reused, then the PId variable will now refer to the new process instance.

This means, for example, that signals intended for the old instance will be sent to the new instance. Note that it is still possible to detect signal sending to processes in the avail list even if XPRSOPT is defined.

XOPTCHAN

This switch can be used to remove all information about the paths of channels and signal routes in the system. The following memory optimization will take place:

When the information about channels, signal routes, and gates is not present two types of calculations can no longer be performed:

  1. To check if there is a path of channels and signal routes between the sender and the receiver in an OUTPUT statement with a TO clause. This is no problem as this is just an error test that we probably do not want to be performed in an application.
  2. To calculate the receiver in an OUTPUT without TO clause, if the Cadvanced/Cbasic Code Generator has not performed this calculation at generate time (see Calculation of Receiver in Outputs). This is more serious, as it means that OUTPUT without TO cannot always be used. The restrictions are:

Caution! 

If the XOPTCHAN switch is defined and still OUTPUT without TO clause are used (which the Cadvanced/Cbasic Code Generator cannot optimize), there will be a C compilation error saying that the name xNotDefPId is not defined.

In an ordinary SDL system OUTPUTs without TO must be used to start up the communication between different parts of the system, as there is no other way in SDL to distribute the PId values needed for OUTPUTs with TO.

This problem is solved if the Cadvanced/Cbasic Code Generator can calculate the receiver. Otherwise the data type PIdList in the library of abstract data types is intended to solve this problem. It is described in The ADT Library. When this data type is used, global PId literals my be introduced, implemented as SDL synonyms. These literals can then be used to utilize OUTPUT statements with TO clauses from the very beginning.

X_LONG_INT

The SDL sort Integer is translated to int in C. To translate the Integer sort to long int instead, just define the compilation switch X_LONG_INT.

XENVSIGNALLIMIT

If this switch is defined, only a limited number of signals will be stored in the input port of the Env function. The limit is equal to the value defined for XENVSIGNALLIMIT and is normally set to 20.

XEALL

This switch will define all error handling switches (XE...) and XASSERT given below.

XECREATE

This switch will report if the initial number of instances of a process type is greater than the maximum number.

XECSOP

This switch will report error situations in ADT operator.

XEDECISION

This switch will report if no path out from a Decision is found.

XEEXPORT

This switch will report errors during Import actions.

XEFIXOF

This switch will report overflow when an SDL Real value is converted to an SDL Integer value using the operator Fix.

XEINDEX

This switch will report value out of range for array index.

XEINTDIV

This switch will report division by zero in an integer division.

XEOUTPUT

This switch will report errors during Output operations.

XERANGE

This switch will report range errors when a value is assigned to a variable of a sort containing range conditions.

XEREALDIV

This switch will report division by zero in a real division.

XEVIEW

This switch will report errors in View operations

XECHOICE

This switch will turn on error reports when accessing non-active choice components.

XEOPTIONAL

This switch will turn on error reports when accessing non-present optional struct components.

XEUNION

This switch will turn on error reports when accessing non-active union components.

XEREF, XEOWN

These switches turn on error checking on pointers (generator Ref and Own).

XASSERT

By defining this switch the possibility to define user assertions which is described in Assertions.

XFREEVARS

This switch is used when the default memory handling algorithm is to be changed. By defining XFRREVARS each Stop and Return statement in processes and procedures is preceded by statements to deallocate dynamic memory stored in variables and parameters. See also Changing the Standard Memory Allocation Procedure.

Caution! 

The variables defined at process level in a process containing services are not de-allocated when the last service stops.

XTRACHANNELSTOENV

When using partitioning of a system a problem during the redirection of channels is that the number of channels going to the environment is not known at code generation time, which means that the size of the data area used for the connections is not known. This problem is solved in two ways.

Either the function handling redirections allocates more memory, which is the default, or the user specifies how many channels that will be redirected (which could be difficult to compute, but will lead to less need of memory).

In the first case (allocation of more memory) the macros:

should be defined like above. This is the standard in scttypes.h. If the user wants to specify the number of channels himself then

i.e. XTRACHANNELSTOENV should be the number of channels, while XTRACHANNELLIST should be a list of that many zeros.

XDEBUG_LABEL

It is for debugging purposes sometimes of interest to introduce extra labels. The macro XDEBUG_LABEL is inserted in the code for each input symbol. As macro parameter it has a name which is the name of the state concatenated with an underscore concatenated with the signal name.


Example 359       

In the generated code for these input statements the following macros will be found:

A suitable macro definition to introduce label would be:

To use these label the usage of SDL must be restricted in one area. The same state may not receive two different signals with the same name! This is allowed and handled by SDT. The signal have to be defined at different block or system level and the outermost signal must be referenced with a qualifier.


XCONST, XCONST_COMP

Using these compilation switches most of the memory used for the IdStructs can be moved from RAM to ROM. This depends of course on the compiler and what properties it has.

The following macro definitions can be inserted:

This will introduce const in the declaration of most of the IdStructs. It is then up to the compiler to handle const.

The XCONST_COMP macro is used to introduce const on components within a struct definition. This is necessary for some compilers to accept const on the struct as such.

If const is successfully introduced, there is a lot of RAM memory that will be saved, as probably 90% of the data area for IdStructs can be made const.

Compilation Switches -- Summary

The property switches are in principle independent, except for the relations given in the descriptions above, and it should always be possible to any combination.

The number of combinations is, however, so huge that it is impossible for us to even compile all combinations. If you happen to form a combination that does not work, please let us know, so that we either can correct the code, or, if that is not possible, publish a warning against that combination.

The switches defining a standard library version will define the following property switches:


SCTDEBCOM

XPRSPRIO
XPARTITION
XEALL
XMONITOR
XTRACE
XCTRACE
XMSCE
XCOVERAGE
XGRTRACE
XPMCOMM
XSDLENVUI
XITEXCOMM
XSIMULATORUI

SCTDEBCLCOM

XCLOCK
XPRSPRIO
XPARTITION
XEALL
XMONITOR
XTRACE
XCTRACE
XMSCE
XCOVERAGE
XGRTRACE
XPMCOMM
XSDLENVUI
XSIMULATORUI

SCTAPPLCLENV

XCALENDERCLOCK
XENV
XPRSPRIO
XOPT
XPRSOPT

SCTDEBCLENVCOM

XCALENDERCLOCK
XPRSPRIO
XPARTITION
XENV
XPRSOPT
XEALL
XMONITOR
XTRACE
XCTRACE
XMSCE
XCOVERAGE
XGRTRACE
XPMCOMM
XSDLENVUI
XSIMULATORUI

SCTPERFSIM

XEALL
XPRSPRIO

The lowest layer of switches (that handle the implementation details) are set up using the three layers above. These switches will not be discussed here. Please refer to the source code files scttypes.h and sctsdl.c for more details.

Creating a New Library

Caution! 

If you create new versions of the library, make sure that the library and the generated code are compiled with the same compilation switches. If not, you might experience any type of strange behavior in the generated application!

This section describes how to generate a new library. The following topics are covered:

Directory Structure

The structure of files and directories used for the Cadvanced/Cbasic Code Generator libraries is shown in Figure 499 The directory sdtdir is in the installation:

where <machine dependent dir> is for example sunos5sdtdir on SunOS 5, hppasdtdir on HP, and wini386 in Windows. (In Windows, / should be replaced by \ in the path above.)

This directory is here called sdtdir and is in UNIX normally referred to by the environment variable sdtdir.

Figure 499 : Directory structure

Extracted pic [10]

"sctdir" is a reference to an object library and is usually setup as a parameter in the call to make. It can also be an environment variable.

In the sdtdir directory three important files are found:

  1. predef.sdl contains the definition of the predefined sorts in SDL.
  2. sdtsct.knl contains a list of the available libraries that can be used together with code generated by the Cadvanced/Cbasic Code Generator.
  3. help_sct.hlp contains the help information that can be obtained using the monitor command help.

The file predef.sdl is read by the SDT Analyzer during analysis, while the file sdtsct.knl is used to present the available libraries in the Make dialog in the Organizer (see Make).

In the INCLUDE directory, there are two important groups of files:

  1. The source code files for the runtime library:
    scttypes.h, sctlocal.h, sctsdl.c, sctutil.c, sctpost.c, sctpred.h, sctpred.c, sctmon.c, sctos.c and sctenv.c
  2. The files necessary to include communication with other SCT applications: post.h, post.o (post.lib in Windows), sdt.h, itex.h.

In parallel with the INCLUDE directory there are a number of directories for libraries in object form. The SCTDEBCOM directory in Figure 499 is an example of such a directory. Each of these directories will contain three files: comp.opt, makeoptions (make.opt in Windows) and sctworld.o (sctworld.lib in Windows).

The comp.opt file determines the contents of the generated makefile and how make is called. For more details see below.

The makeoptions (make.opt) file describes the properties of the library, such as the compiler used, compiler options, linker options, and so on, while sctworld.o (sctworld.lib) is a pre-linked library file.

To guarantee the consistency of, for example, compilation flags between the SDL system and the kernel, the makeoptions (make.opt) file is used both by the make file compiling the library (Makefile) and by the generated make files used to compile the generated SDL system. Non-consistency in this sense between the library and the SDL system will make the result unpredictable.

File sdtsct.knl

The sdtsct.knl file describes for SDT which libraries that are available. This is presented by the Organizer in the Make dialog see Make). The sdtsct.knl file has the following structure. Each available library is described on a line of its own. Such a line should first contain the name of the library (the name presented in the dialog), then the path to the directory containing the library, and last a comment up to end of line.

The path to the library can either be the complete path or a relative path. A relative path is relative to the environment variable sdtdir (on UNIX) or SDTDIR (in Windows), if that variable is defined. Otherwise it is relative to the SDT installation.


Example 360       

Not that the two last lines is examples for Windows, while the fourth line is for UNIX.


The Organizer will look for an sdtsct.knl file first in the directory SDT is started from, then in the home directory for the user, and then in the directory referenced by the environment variable sdtdir (SDTDIR) if it is defined, and last in the SDT installation.

File Makefile

In each directory that contains a library version there is a Makefile that can "make" the library. To create a new library after an update of the source code, change directory to the directory for the library and execute the Makefile. The Makefile uses the makeoptions (make.opt) file in the directory to get the correct compilation switches and other relevant information.

Caution! 

Do not generate and test libraries in the installation directory structure. Create an appropriate copy.

Note: 

The environment variables (if used) sdtdir (SDTDIR) and sctdir (SCTDIR) need not necessarily refer to directories in the installation directory. Any directory containing the relevant files may be used.

File comp.opt

This file determines the details of the generated make files, and the command issued to execute the makefile. A comp.opt file contains zero, one or more initial line starting with a #. These lines are treated as comments. After that it contains four lines of essential data.

On each of these lines % codes can be used to insert specific information.

On all four lines:

On line 2, the compile script:

On line 3, the link script:

On line 4, the make command:


Example 361 : comp.opt file for UNIX      

File makeoptions / make.opt

This file has the following structure:

Example on UNIX:

Example in Windows:

The information to the right of the equal signs should be seen as an example. These environment variables set in the makeoptions (make.opt) file should specify:

Generated Make Files

The generated make files for an SDL system will as first action include the makeoptions (make.opt) file in the directory referenced by the environment variable sctdir. It will then use the variables sctIFDEF, sctLINKKERNEL, sctCC, sctCPPFLAGS, sctCCFLAGS, sctLD, and sctLDFLAGS to compile and link the SDL system with the selected library.

The make file is generated and executed by the Cadvanced/Cbasic Code Generator.


Example 362       

Below a UNIX make file generated for the SDT system example is shown.


Adaptation to Compilers

In this section the necessary changes to the source code to adapt it to a new environment are discussed. Adapting to a new environment could mean moving the code to new hardware or using a new compiler.

There are two parts of the source code that might need changes:

  1. In scttypes.h there is a section defining the properties of different compilers, where a new compiler can be added.
  2. In sctos.c the functions that depend on the operating system or hardware are collected. These might need to be changed due to a new compiler, a new OS, or a new hardware.

In Compiler Definition Section in scttypes.h the compiler definition section in scttypes.h is discussed in detail, while sctos.c is treated in The sctos.c File.

Compiler Definition Section in scttypes.h

Caution! 

Do not to use the compiler /usr/ucb/cc. Our experience is that the bundled compiler is subject to generating compilation errors.

Instead, we recommend to run the unbundled compiler
/opt/SUNWSpro/bin/cc or the GNU C compiler.

The following switches defining the compiler are currently handled in scttypes.h:

SUN4_1_1CC

The Sun C compiler for SunOS 4.1.3

SUN4_1_1GCC

The GNU C compiler for SunOS 4.1.3

SUN_CXX

The Sun C++ compiler

SUN4_ANSICC

The Sun ANSI C compiler for SunOS 4.x

SUN5_ANSICC

The Sun ANSI C compiler for SunOS 5.x

SUN5_CC

The Sun C compiler for SunOS 5.x

linux

The GNU C compiler for Linux

HPUXANSICC
HPUXANSI_RISCCC

The HP ANSI C compiler

HPUXCC
HPUX_RISCCC

The HP C compiler

ULTRIXCC

The Digital C compiler for ULTRIX

AIXV3CC

IBM RS/6000 C compiler for AIX 3.2

OASYS_CXX

Green Hill/Oasys cross compiler
C++-68000 and
Microtec C cross compiler for 68000

IC86

Borland C++, version 3.0 and later
Microsoft C, version 6.x

IARC51

IAR C compiler for 8051 computers

These are the compilers we have used to compile and link generated code and different versions of the library. To introduce a new compiler, a new section in scttypes.h should be introduced in which the properties of the compiler would be defined.

Some changes might also be necessary in sctos.c, where the generated application is connected to OS or hardware. The remaining part of the code ought to be possible to compile without changes, especially if the compiler follows the ANSI C standard.

The list of compilers will of course be extended with new compilers as we obtain the necessary information on how to handle each particular compiler.

The file scttypes.h contains one section for each compiler where the properties of the compiler are defined. The following information is given in the section:

Below a typical section defining the properties of a compiler following ANSI-C is given.


Example 363       

Before the compiler definition sections the following macros are defined:

which defines the most common setting for a number of properties. These might need to be changed for a particular compiler. If the compiler cannot use function prototypes then the following should be included:

which defines that prototypes are not to be used. The XPP macro is used to include or exclude the parameters of functions in mainly extern declarations.

If token concatenation cannot be performed using the ANSI C standard, i.e. ##, one of the following examples is worth trying:

or

Next are the two types xptrint, which defines an int type with the same size as an address, and xint32, which defines a 32-bits int type. The type xptrint is by default defined as unsigned but might need to be changed unsigned long and xint32 is by default defined as long int but might need to be changed to some other int type. If xint32 is defined as int, the macro X_XINT32_INT should also be defined to get the printout correct as well.

Next in the section defining the compiler properties a number of .h files are included. Below a table is given, that for each .h file lists the functions and types used by the Cadvanced/Cbasic Code Generator system in either the library or in generated code:

If the compiler does not handle C signals then the statement
#include <signal.h>

should be replaced by:

The last three parts in this section handle the utility functions needed by sctos.c to implement some of the operating system dependent functions. Please see below where sctos.c is discussed in detail.

The sctos.c File

The following functions are defined in sctos.c

SDL_Clock

The function SDL_Clock should return the current time, read from a clock somewhere in the OS or hardware. The return value is of type SDL_Time, that is a struct with two 32-bits integer components, representing seconds and nanoseconds in the time value.

The standard implementation of SDL_Clock uses the C function time, which returns the number of seconds since some defined date.

Note: 

Note that the C function time only handles full seconds.

In an embedded system or any other application that requires better time resolution, or when the C function time is not available, SDL_Clock should be implemented by the user.

Note: 

If an application does not require a connection with real time (for example if it is not using timers and should run as fast as possible), there is no need for a clock function. In such a case it is probably suitable to use simulated time by not defining the compilation switch XCLOCK, whereby SDL_Clock is never called and does not need to be implemented. An alternative is to let SDL_Clock always return the time value 0.

A typical implementation in an embedded system is to have hardware generating interrupts at a predefined rate. At each such interrupt a variable containing the current time is updated. This variable can then be read by SDL_Clock to return the current time.

Caution! 

The variable must be protected from updates during the period of time that the SDL_Clock reads the clock variable.

Calling the interrupt routine while the SDL_Clock reads the clock variable would cause a system disaster.

xSleep_Until

The function xSleep_Until is given a time value, as a value of type SDL_Time (see above) and should suspend the executing until this time is reached, when it should return.

This function is used only when real time is used (the switch XCLOCK is defined) and when there is no environment functions (XENV is not defined). The xSleep_Until function is used to wait until the next event is scheduled when there is no environment that can generate events.

xAlloc

The function xAlloc is used to allocate dynamic memory and is used throughout the runtime library and in generated code. The function is given a size in bytes and should return a pointer to a data area of the requested size. All bytes in this data area are set to zero. The standard implementation of this function uses the C function calloc.

A user who wants to estimate the need for dynamic memory can introduce statements in xAlloc to record the number of calls of xAlloc and the total requested size of dynamic memory. Please note two things. A program using the monitor requires more dynamic memory than a program not using the monitor, so estimates should be made with the appropriate compilation switches. A call of calloc will actually allocate more memory than is requested to make it possible for the C runtime system to deallocate and reuse memory. The size of this additional memory is compiler-dependent.

A user who wants to handle the case when no more memory is available at an allocation request can implement that in xAlloc. In the standard implementation for xAlloc a test if calloc returns 0 can be introduced, at which the program can be terminated with an appropriate message.

xFree

The function xFree is used for the opposite operation, that is to return memory to the list of free memory so it can be reused by subsequent calls of xAlloc. The standard implementation of this function uses the C function free. The xFree function is only used to free the memory allocated for Charstring values using the standard implementation. This means that if the user does not introduce any use of xFree and the SDL type Charstring is not used, then there is no need to implement xFree.

xHalt

The function xHalt is used to exit from a program and is in the standard implementation using the C function exit to perform its task.

xGlobalNodeNumber

The function xGlobalNodeNumber is used to assign unique numbers to each SDL system which is part of an application.

If environment functions are used for an SDL system this function should be implemented there. If, however, we have communicating simulations, there are no env functions and the xGlobalNodeNumber function is defined in sctos.c instead.

So the xGlobalNodeNumber function is only used if XPMCOMM is defined and XENV is not defined. As this function is only used in the case of a communicating simulation, it is only necessary to implement it for computers/compilers handling SDT, which means that it is not interesting for a user to change the standard implementation of this function. The implementation calls the function getpid, and uses thus the OS process number as global node number.

xCheckForKeyboardInput

The function xCheckForKeyboardInput is used to determine if there is a line typed on the keyboard (stdin) or not. If this is difficult to implement it can instead determine if there are any characters typed on the keyboard or not. This function is only used by the monitor system, (when XMONITOR is defined). If the function is not implemented the compilation switch XNOSELECT should be defined to prohibit calls of the function.

The xCheckForKeyboardInput function is used to implement the possibility to interrupt the execution of SDL transitions by typing <Return> and to handle polling of the environment (xInEnv or its equivalent when communicating simulations is used) when the program is waiting at the "Command :" prompt in the monitor.

xGet... and xRelease...

The functions

are called to allocate and release memory used for processes, signals, procedures, charstrings, Bit_Strings, and Octet_Strings. By changing the implementation of these function a user can change the strategy for reuse of memory. For more information see the section Changing the Standard Memory Allocation Procedure.

List of All Compilation Switches

Introduction

This section is a reference to the macros that are used together with the generated C code from the Cadvanced/Cbasic Code Generator. Here the macros are just enumerated and explained. The section is divided in a number of subsection, each treating one major aspect of the code. Within the subsections the macros are enumerated in alphabetic order.

The context in which macros are used and the sequence of generated macro calls are not discussed here. Such information can be found in the section Structure of Generated Code.

Information about some of the macros ( Library Version Macros, Compiler Definition Section Macros, and General Properties) can also be found in the section Compilation Switches.

To fully understand the descriptions of the macros in this section it is also necessary to know the basic data structures used, especially for the static structures, i.e. the xIdNodes. This information can be found in the section The Symbol Table.

The information about the data types used for the dynamic structure of the system, i.e. about process instances, signal, timers, and so on, are also of interest. This can be found in The SDL Model.

Library Version Macros

SCTAPPLCLENV

Application.

SCTAPPLENV

Application without clock.

SCTCORBA

Application with a CORBA environment.

SCTDEB

Stand-alone simulator for any environment. Should be executed from OS.

SCTDEBCORBA

A simulator with a CORBA environment.

SCTDEBCL

Stand-alone simulator with real time for any environment. Should be executed from OS.

SCTDEBCLCOM

Simulator with real time for host. Can be executed from SDT or from OS.

SCTDEBCLENV

Stand-alone simulator, with real time and env functions, for any environment. Should be executed from OS.

SCTDEBCLENVCOM

Simulator, with real time and env functions, for any environment. May be executed from OS or from simulator GUI.

SCTDEBCOM

Simulator for host. Can be executed from SDT or from OS.

SCTOPT1APPLCLENV

Application with minimal memory requirements. Real cannot be used. No channel information

SCTOPT2APPLCLENV

Application with minimal memory requirements. Real cannot be used. Const for all channel information.

SCTPERFSIM

Suitable for execution of performance simulations.

Compiler Definition Section Macros

ALPHACC

cc for the ALPHA architecture.

AIXV3CC

cc for the IBM RS/6000 architecture.

GCCWIN

gcc for Windows NT4 (Windows 95).

HPUXANSICC

ANSI cc for HP-300 and HP-400 (Motorola architecture).

HPUXANSI_RISCCC

ANSI cc for HP-700 (PA-RISC architecture).

HPUXCC

cc for HP-300 and HP-400 (Motorola architecture).

HPUX_RISCCC

cc for HP-700 (PA-RISC architecture).

IC86

PC compilers.

IARC51

The IAR compiler.

linux

GNU cc for linux.

OASYS_CXX

The OASYS cross compiler.

QNX4_CC

QNX4 Watcom 10.6

SUN4_ANSICC

ANSI cc for SunOS 4.

SUN4_1_1CC

cc for SunOS 4.

SUN4_1_1GCC

GNU cc for SunOS 4.

SUN5_ANSICC

ANSI cc for SunOS 5.

SUN5_CC

cc for SunOS 5.

SUN5_GCC

GNU cc for SunOS 5.

SUN_CXX

C++ for SUN.

ULTRIXCC

cc for ULTRIX.

VAXVMSCC

cc for VAX/VMS.

Some Configuration Macros

COMMENT(P)

Should be defined as:

The macro is used to insert comments in included C code.

GETINTRAND

A random generation function. Usually rand() or random().

GETINTRAND_MAX

The max int value generated by function mentioned in GETINTRAND. Usually 2147483647 (32-bit integers).

SCT_VERSION_3_5

Defined in generated code if the Cadvanced/Cbasic Code Generator version 3.5 was used.

XCAT(P1,P2)

Should concatenate token P1 and P2. Possibilities:

or

or

XNOOSSIGNALS

Should be defined if there is no support for C signals. This feature is only of interest in simulations.

XNOPROTO

Should be defined if prototypes are not to be used.

XNOSELECT

Should be defined if there is no support for the select function found in UNIX operating systems. This is used to implement "user defined interrupt" by typing the return key while simulating.

XNO_VERSION_CHECK

If this macro is defined there will be no version check between the generated code and the scttypes.h file.

XPP(x)

Should be defined as nothing if XNOPROTO is defined, otherwise as x. The macro is used to produce function prototypes with or without parameters (ANSI-C or old style).

XSCT_CBASIC

Defined in generated code if Cbasic was used.

XSCT_CADVANCED

Defined in generated code if Cadvanced was used.

X_SCTTYPES_H

Defined in scttypes.h in a way that it possible to include the scttypes.h file several times without any problems.

X_XINT32_INT

Should be defined if xint32 is int.

X_XPTRINT_LONG

Should be defined if xptrint is unsigned long.

General Properties

TARGETSIM

Can be used to connect an application with a monitor on a target system with SDT running on a host computer.

XASSERT

Detect and report user defined assertions that are not valid.

XCALENDERCLOCK

Use the clock function in sctos.c (not simulated time). Time is whatever the clock function returns.

XCLOCK

Use the clock function in sctos.c (not simulated time). Time is zero at system start up.

XCOVERAGE

Compile with code to store information about the current coverage of the SDL system. This information can also be printed in the monitor.

XCTRACE

Compile preserving the possibility to report the current C line number during simulations.

XEALL

Defines XEOUTPUT, XEINTDIV, XEREALDIV, XECSOP, XEFIXOF, XERANGE, XEINDEX, XECREATE, XEDECISION, XEEXPORT, XEVIEW, XEERROR, XEUNION, XECHOICE, XEOPTIONAL, XEREF, XEOWN, and XASSERT.

For more information, see these macros.

XECHOICE

Detect and report attempts to access non-active components in Choice variables.

XECREATE

Detect and report if more static instances are created at start up, than the maximum number of concurrent instances.

XECSOP

Detect and report errors in ADT operators.

XEDECISION

Detect and report when there is no possible path out from a decision.

XEERROR

Detect and report the usage of the error term in an SDL expression.

XEEXPORT

Detect and report errors in import actions.

XEFIXOF

Detect and report integer overflow in the operator fix.

XEINDEX

Detect and report index out of bounds in arrays.

XEINTDIV

Detect and report integer division with 0.

XENV

Call the env functions.

XENV_CONFORM_2_3

Insert the VarP pointer in the xSignalNode so that signals conform with their implementation in SDT 2.3.

XEOPTIONAL

Detect and report attempts to access optional struct components that are not present.

XEOUTPUT

Detect and report warnings in outputs (mainly outputs where signal is immediately discarded).

XEOWN

Detect and report illegal usage of Own and ORef pointers.

XERANGE

Detect and report subrange errors.

XEREALDIV

Detect and report real division with 0.0.

XEREF

Detect and report attempts to dereference null pointer.

XEUNION

Detect and report attempts to access non-active components in a #UNION.

XEVIEW

Detect and report errors in view actions.

XGRTRACE

Compile with the trace in source SDL graphs enabled.

XITEXCOMM

Enable the possibility for an executable to communicate with ITEX via the Postmaster.

XMAIN_NAME

If this macro is defined the main function in sctsdl.c will be renamed to the name given by the macro.

XMONITOR

Compile with the monitor system. This macro will implicitly set up a number of other macros as well.

XMSCE

Compile with the MSC trace enabled.

XNOMAIN

If this macro is defined the main function in sctsdl.c will be removed.

XPMCOMM

Enable the possibility for an executable to communicate via the Postmaster.

XPRSPRIO

Use priorities on process instance sets.

XPRSSIGPRIO

Use first priorities on process instance sets and then priorities on signal instances.

XSDLENVUI

Enable the possibility to communicate with a user-defined UI.

XSIGLOG

Call the xSignalLog and xProcessLog functions.

XSIGPRIO

Use priorities on signal instances.

XSIGPRSPRIO

Use first priorities on signal instances and then priorities on process instance sets.

XSIMULATORUI

Enable the possibility to communicate with the simulator UI.

XTENV

As XENV but call xInEnv at specified times (next event time is out parameter from function xInEnv).

XTRACE

Compile with the textual trace enabled.

Code Optimization

XCONST

The majority of the xIdNode structs can be made const by defining CONST as const. This is only possible in applications (not simulations).

XCONST_COMP

This should normally be defined as const if XCONST is const. It is used to introduce const in the component declarations within the xIdNode structs.

XNOCONTSIGFUNC

Do not include functions to calculate the expressions in continuous signals. This saves also one function pointer in the xIdNode for the states. If this switch is defined, continuous signals cannot be used.

XNOENABCONDFUNC

Do not include functions to calculate the expressions in enabling conditions. This saves also one function pointer in the xIdNode for the states. If this switch is defined, enabling conditions cannot be used.

XNOEQTIMERFUNC

Do not include function to compare the parameters of two timers. This saves also one function pointer in the xIdNode for the signals. If this switch is defined, timers with parameters cannot be used.

XNOREMOTEVARIDNODE

Do not include xIdNodes for remote variable definitions.

XNOSIGNALIDNODE

Do not include xSignalIdNodes for signals and timers.

XNOSTARTUPIDNODE

Do not include xSignalIdNodes for start up signals.

XNOUSEOFOBJECTIDENTIFIER

The type Object_Identifier and all operations on that type is removed.

XNOUSEOFOCTETBITSTRING

The types Bit_String, Octet, Octet_String and all operations on these types are removed.

XNOUSEOFSERVICE

All data and code needed to handle services are removed.

XNOUSEOFREAL

The type real and all operations on real are removed.

XOPT

Defines XOPTSIGPARA, XOPTDCL, XOPTFPAR, XOPTSTRUCT, XOPTLIT, and XOPTSORT.

For more information see these macros.

XOPTCHAN

Do not include xIdNodes for channels, signal routes, and gates. Information in services and processes about connections to signal routes and gates are also removed.

Note: 

If this compilation switch is defined all outputs must either be sent TO a process or the receiver must be possible to calculate during code generation.

XOPTDCL

Do not include xIdNodes for variables.

XOPTFPAR

Do not include xIdNodes for formal parameters.

XOPTLIT

Do not include xIdNodes for literals.

XOPTSIGPARA

Do not include xIdNodes for signal parameters.

XOPTSORT

Do not include xIdNodes for newtypes and syntypes.

XOPTSTRUCT

Do not include xIdNodes for struct components.

XPRSOPT

Optimize memory for process instances. All memory for a process instance can be reused, but signal sending to a stopped process, who's memory has been reused by a new process, cannot be detected. The new process will in this case receive the signal.

XSYNTVAR

If this compilation switch is defined, xVarIdNodes are inserted for the Present components for optional struct components. This feature is only needed by the Validator and by LINK. It should not be defined otherwise.

Definitions of Minor Features

XBREAKBEFORE

Should be used mainly if the MONITOR or GRTRACE switches are defined. It will make the functions and struct components for SDT references available and is also used to expand the macros XAT_FIRST_SYMBOL, XBETWEEN_SYMBOLS, XBETWEEN_SYMBOLS_PRD, XBETWEEN_STMTS, XBETWEEN_STMTS_PRD, XAFTER_VALUE_RET_PRDCALL, and XAT_LAST_SYMBOL to suitable function calls. These functions are used to interrupt a transition between symbols during simulation.

XCASEAFTERPRDLABELS

See XCASELABELS below. The SDL symbols just after an SDL procedure call have to be treated specially, as the symbol number (=case label) for these symbols are used as the restart address for the calling graph. Normally this macro should be defined. If SDL procedure calls are transformed to proper C function calls, and SDL return is translated to a C return, and nextstate in a procedure is NOT translated to a C return (i.e. the process will be hanging in the C function representing the SDL procedure) then it is not necessary to define XCASEAFTERPRDLABELS.

XCASELABELS

The function implementing the behavior of a process, procedure, or service contains one large switch statement with a case label for each SDL symbol in the graph. This switch is used to be able to restart the execution of a process, procedure, or service at any symbol. In an application most of these label can be removed (all except for those symbols that start a transition, i.e. start, input, continuous signal). The macro XCASELABELS should be defined to introduce the case labels for all SDL symbol. This means that XCASELABELS should be defined in a simulation but not in an application.

XCONNECTPM

If XCONNECTPM is defined the SDL simulation will try to connect itself to the postmaster. This is necessary if GR trace ( XGRTRACE), communicating simulations ( XPMCOMM), or communication with ITEX ( XITEXCOMM) is to be used. The XCONNECTPM feature is normally only used in simulations.

XCOUNTRESETS

Count the number of timers that are removed at a reset operation. This information is used by the textual trace system ( XTRACE) to present this information. The information is really only of interest at a stop action when more then one timer might be (implicitly) reset. XCOUNTRESETS should not be defined in an application.

XENVSIGNALLIMIT

This macro is used to determine the number of signals sent to the environment that, during simulation, should be saved in the input port of the env process instance. Such signals can be inspected with the normal monitor commands for viewing of signals. This macro is only of interest in a simulation and has the default value 20.

XERRORSTATE

Insert the data structure to represent an "error" state that can be used if no path is found out from a decision. This should normally be defined if XEDECISION is defined.

XFREESIGNALFUNCS

Insert free functions for each signal, timer, or startup signal that contains a parameter of a type having a free function. These signal free functions can the be used to free allocated data within a signal.

XFREEVARS

Insert free function calls for all variables of a type with free function, just before stop or return actions. This means that free actions are performed on allocated data referred to from variables is before the object ceases to exist.

XIDNAMES

This macro is used to determine if the SDL name of an SDL object should be stored in the xIdNode for the object. This character string is used for communication with the user in for example the monitor. Normally this macro should not be used in an application. Sometime it might be useful for target debugging to define XIDNAMES, as it is then fairly easy to identify objects by just printing the SDL name from a debugger. On average this seems to cost approximately 5% more memory.

XNRINST

This macro should be defined if process instance numbers are to be maintained. The instance number is the number in the monitor printout Test:2, identifying the individual instances of the process instance set Test in this case. XNRINST is normally only used in a simulation.

XOPERRORF

Include the function xSDLOpError in sctsdl.c. This function is used to print run-time errors in ADT operators.

XPRSSENDER

Store the value of sender also in the xPrsNode. The normal place is in the latest received signal. This is only needed in a simulation as sender might be accessed from the monitor system after the transition is completed and the signal has been returned to the pool of available memory.

XREADANDWRITEF

Include the functions for basic Read and Write. This is needed mainly in simulations.

XREMOVETIMERSIG

Allow the removal of timer signals for not-executing PIds. This is needed only in simulations to implement the monitor commands set-timer and reset-timer.

XSIGPATH

If this macro is defined then the functions xIsPath and xFindReceiver will return the path of signal routes, channels, and gates from the sender to the receiver, as out parameters. This information can then be used in the monitor system, for example, to produce signal logs. This macro should normally not be defined in an application.

XSYMBTLINK

The XSYMBTLINK macro is used to determine if a complete tree should be built from the xIdNodes of the system. If XSYMBTLINK is defined then all xIdNodes contains a Parent, a Suc, and a First pointer. The value of the Parent pointer is generated directly into the xIdNodes. Suc and First, however, are calculated in the yInit function by calling the xInsertIdNode function. The Suc and First pointers are needed by the monitor system, but not in an application, i.e. XSYMBTLINK should be defined in a simulation but not in an application.

XTESTF

This macro is used to include or remove test functions for syntype (or newtypes) with range conditions. The yTest function is used by the monitor system and by the functions to test index out of bounds in arrays and to test subranges. This means that XTESTF should be defined if the monitor is used or if XERANGE or XEINDEX is defined.

XTRACHANNELSTOENV

When using partitioning of a system a problem during the redirection of channels is that the number of channels going to the environment is not known at code generation time, which means that the size of the data area used for the connections is not known. This problem is solved in two ways.

Either the function handling redirections allocates more memory, which is the default, or the user specifies how many channels that will be redirected (which could be difficult to compute, but will lead to less need of memory).

In the first case (allocation of more memory) the macros:

should be defined like above. This is the standard in scttypes.h. If the user wants to specify the number of channels himself then

i.e. XTRACHANNELSTOENV should be the number of channels, while XTRACHANNELLIST should be a list of that many zeros.

XTRACHANNELLIST

See XTRACHANNELSTOENV just above.

Static Data, Mainly xIdNodes

XBLO_EXTRAS

All generated struct values for block, block type, and block instance structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xBlockIdStruct must be updated as well. Normally this macro should be empty.


Example 364       

XBLS_EXTRAS

All generated struct values for block substructure structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xBlockSubstIdStruct must be updated as well. Normally this macro should be empty.


Example 365       

XCOMMON_EXTRAS

All generated struct values for xIdNode structs contain this macro after the common components. This means that it is possible to insert new components in all xIdNodes by defining this macro. Normally this macro should be empty.


Example 366       

To insert a new int component with value 0 the following definition can be used:


XLIT_EXTRAS

All generated struct values for literal structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xLiteralIdStruct must be updated as well. Normally this macro should be empty.


Example 367       

XPAC_EXTRAS

All generated struct values for package structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xPackageIdStruct must be updated as well. Normally this macro should be empty.


Example 368       

XPRD_EXTRAS

All generated struct values for procedure structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xPrdIdStruct must be updated as well. Normally this macro should be empty.


Example 369       

XPRS_EXTRAS

All generated struct values for process, process type, and process instance structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xPrsIdStruct must be updated as well.


Example 370       

XSIG_EXTRAS

All generated struct values for signal, timer, RPC_signal, startup signal structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xSignalIdStruct must be updated as well. Normally this macro should be empty.


Example 371       

XSPA_EXTRAS

All generated struct values for signal parameter structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xVarIdStruct must be updated as well (Note that variables, formal parameters, signal parameters, and struct components are all handled in xVarIdStruct.) Normally this macro should be empty.


Example 372       

XSRT_EXTRAS

All generated struct values for newtype and syntype structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xSortIdStruct must be updated as well. Normally this macro should be empty.


Example 373       

XSRV_EXTRAS

All generated struct values for service, service type, and service instance structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xSrvIdStruct must be updated as well. Normally this macro should be empty.


Example 374       

XSTA_EXTRAS

All generated struct values for state structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xStateIdStruct must be updated as well. Normally this macro should be empty.


Example 375       

XSYS_EXTRAS

All generated struct values for system, system type, and system instance structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xSystemIdStruct must be updated as well. Normally this macro should be empty.


Example 376       

XSYSTEMVARS

This macro gives the possibility to introduce global variables declared in the beginning of the C file containing the implementation of the SDL system unit.

XSYSTEMVARS_H

If extern definitions are needed for the data declared in XSYSTEMVARS, this is the place to introduce it. These definitions will be present in the .h file for the system unit (if separate generation is used).

XVAR_EXTRAS

All generated struct values for variables, formal parameters, and struct components structs contain this macro last in the struct. By defining this macro new components can be inserted. Note that the type xVarIdStruct must be updated as well (Note that signal parameters also uses the type xVarIdStruct). Normally this macro should be empty.


Example 377       

Data in Processes, Procedures and Services

PROCEDURE_VARS

The struct components that are needed for each procedure instance. Example: state.

PROCESS_VARS

The struct components that are needed for each process instance. Example: state, parent, offspring, self, sender, inputport.

SERVICE_VARS

The struct components that are needed for each service instance. Example: state

YGLOBALPRD_YVARP

This macro is used to declare the yVarP pointer (which is a pointer to the yVDef struct for the process) in a procedure defined outside of a process. As a global procedure never can access process local data, it is suitable to let yVarP be a pointer to a struct only containing the components defined in the macro PROCESS_VARS.

YGLOBALSRV_YVARP

This macro is used to declare the yVarP pointer (which is a pointer to the yVDef struct for the process) in a service type defined outside of a process. As a global service type never can access process local data, it is suitable to let yVarP be a pointer to a struct only containing the components defined in the macro PROCESS_VARS.

YPAD_TEMP_VARS

Local variables in the PAD function for a process or service. Example: temporary variables needed for outputs, create actions.

YPAD_YSVARP

Declaration of the ySVarP pointer used to refer to the received signal. Normally ySVarP is void *.

YPAD_YVARP

This macro is used within a process and in a service defined within a process. It should be expanded to a declaration of yVarP, which is the pointer that is used to access SDL variables in the process. yVarP should be of type VDEF_TYPE *, where VDEF_TYPE is the type of the yVDef struct for the process. If the pointer to the yVDef struct is passed as parameter to the PAD function, yVarP can be assigned its correct value already in the declaration.

YPRD_TEMP_VARS

Local variables in the function implementing the behavior of an SDL procedure.

YPRD_YVARP

This macro is used within a procedure defined in a process. It should be expanded to a declaration of yVarP, which is the pointer that is used to access SDL variables in the process. yVarP should be of type VDEF_TYPE *, where VDEF_TYPE is the type of the yVDef struct for the process. If the pointer to the yVDef struct is passed as parameter to the procedure function, yVarP can be assigned its correct value already in the declaration.

Some Macro Used Within PAD Functions

BEGIN_PAD

BEGIN_PAD is a macro that can be used to insert code that is executed in the beginning of the PAD functions. VDEF_TYPE is the yVDef type for the process.

BEGIN_START_TRANSITION

This macro can be used to introduce code that is executed at the beginning of the start transition. STARTUP_PAR_TYPE is the yPDef struct for the startup signal for this process.

CALL_SERVICE

This macro is used in the PAD function of a process that contains services. It should be expanded to a call to PAD function for the service that should execute the next transition (ActiveSrv).

CALL_SUPER_PAD_START

During the start transition of a process all inherited PAD functions up to and including the PAD function containing the START symbol have to be called. The reason is to initialize all variables defined in the process. This macro is used to perform a call to the inherited PAD function (the macro parameter PAD). Usually this macro is expanded to something like:

followed by either a return or a goto NewTransition depending on execution model.

CALL_SUPER_PRD_START

This macro is used in the same way as CALL_SUPER_PAD_START (see above) but for the start transition in a procedure. THISPRD is the executing procedure function, while PRD is the inherited procedure function.

CALL_SUPER_SRV_START

This macro is used in the same way as CALL_SUPER_PAD_START (see above) but for the start transition in a service. PAD is the inherited PAD function.

LOOP_LABEL

The LOOP_LABEL macro should be used to form the loop from a nextstate operation to the next input operation necessary in the OS where OS tasks does not perform return at end of transition (most commercial OS). This macro is also suitable to handle free on received signals and the treatment of the save queue. In an OS where SDL nextstate is implemented using a C return (the Master Library for example) the LOOP_LABEL macro is usually empty.

LOOP_LABEL_PRD

Similar to LOOP_LABEL but used in procedures with states.

LOOP_LABEL_PRD_NOSTATE

Similar to LOOP_LABEL but used in procedures without states. This macro is in many circumstances expanded to nothing.

LOOP_LABEL_SERVICEDECOMP

Similar to LOOP_LABEL but used in the PAD function for a process containing services.

SDL_OFFSPRING

Should return the value of offspring.

SDL_PARENT

Should return the value of parent.

SDL_SELF

Should return the value of self.

SDL_SENDER

Should return the value of sender.

START_SERVICES

This macro is used in the PAD function of a process that contains services. It should be expanded in such a way that the start transitions for all of the services are executed.

XEND_PRD

This is a macro generated at the end of a function that represents the behavior of a procedure. It needs not to be expanded to anything. To define it as

might remove a compiler warning that the end of a value returning function might be reached.

XPRSNODE

Should usually be expanded to the type xPrsNode.

XNAMENODE

How to reach the xPrsIdNode from a PAD function. Normally this is yVarP->NameNode.

XNAMENODE_PRD

How to reach the xPrdIdNode from a PRD function. Normally this is yPrdVarP->NameNode.

XNAMENODE_SRV

How to reach the xSrvIdNode from a PAD function. Normally this is ySrvVarP->NameNode.

YPAD_FUNCTION

The function heading of the PAD function given as parameter.

YPAD_PROTOTYPE

The function prototype of the PAD function given as parameter.

YPRD_FUNCTION

The function heading of the PRD function given as parameter.

YPRD_PROTOTYPE

The function prototype of the PRD function given as parameter.

yInit Function

BEGIN_YINIT

This macro is placed in the beginning of the yInit function in the file containing code for the system. It can be expanded to variable declarations and initialization code.

XPROCESSDEF_C

This macro can be used to introduce code for each process instance set in the system.

XPROCESSDEF_H

This macro can be used to introduce extern declaration (placed in the proper .h file) for each process instance set in the system.

xInsertIdNode

In the yInit function the function xInsertIdNode is called for each IdNode. In an application this is not necessary, and xInsertIdNode can be defined as

The function xInsertIdNode is needed if XSYMBTLINK, XCOVERAGE, or XMONITOR is defined.

YINIT_TEMP_VARS

This macro is placed in all yInit functions and can be expanded to local variables needed within the yInit function.

Implementation of Signals and Output

ALLOC_SIGNAL

ALLOC_SIGNAL_PAR

These macros are used to allocate a data area for a signal to be sent. ALLOC_SIGNAL is used if the signal has no parameters, while ALLOC_SIGNAL_PAR is used if the signal has parameters. The resulting data area should be reference by the variable mentioned by the macro OUTSIGNAL_DATA_PTR (see below).

INSIGNAL_NAME

This macro should be expanded to the identification of the currently received signal. It is used to distinguish between signals when several signal is enumerated in the same input symbol.

OUTSIGNAL_DATA_PTR

This should be the pointer referring to be signal data area while building the signal during an output. It should be assigned its value in ALLOC_SIGNAL or ALLOC_SIGNAL_PAR, and will then be used during assignment of signal parameters and in the SDL_2OUTPUT macro just below.

SDL_2OUTPUT

SDL_2OUTPUT_NO_TO

SDL_2OUTPUT_COMPUTED_TO

SDL_ALT2OUTPUT

SDL_ALT2OUTPUT_NO_TO

SDL_ALT2OUTPUT_COMPUTED_TO

These six macros are used to send the signal created in ALLOC_SIGNAL or ALLOC_SIGNAL_PAR. The SDL_ALT versions of the macros are used if the directive /*#ALT*/ has been given in the output. The version without suffix is used for an output TO, while the suffix _COMPUTED_TO is used for an output without to but it was possible to compute the receiver during code generation time. The suffix _NO_TO indicates an output without to, where the receiver cannot be calculated during code generation time.

SDL_THIS

In an output TO THIS in SDL, the RECEIVER parameter in the ALLOC_SIGNAL and SDL_2OUTPUT macros discussed above will become SDL_THIS.

SIGCODE

This macro makes it possible to store a signal code (signal number) in the xSignalIdNode for a signal. The macro parameter P is the signal name without prefix.

SIGNAL_ALLOC_ERROR

This macro is inserted after the ALLOC_SIGNAL macro and the assignment of parameter values to the signal. It can be used to test if the alloc was successful or not.

SIGNAL_ALLOC_ERROR_END

This macro is inserted after the SDL_2OUTPUT macro.

SIGNAL_NAME

This macro should be expanded to an identification of the signal given as parameter. Normally the identification is either the xSignalIdNode for the signal or an int value. If the id is an int value it is suitable to insert defines of type #define signal_name number. A file containing such defines can be generated using the Generate Signal Numbers feature in Cadvanced/Cbasic.

SIGNAL_VARS

The struct components that are needed for each signal instance. Example: sender, receiver, signal type.

TO_PROCESS

This macro is used as RECEIVER in the ALLOC_SIGNAL and SDL_2OUTPUT macros if the signal is sent to a process instance set in SDL.

TRANSFER_SIGNAL

TRANSFER_SIGNAL_PAR

These macros are used as alternative for the ALLOC_SIGNAL macros (see these macros above) if the directive #TRANSFER if given in the output.

XNONE_SIGNAL

The representation for a none signal.

XSIGNALHEADERTYPE

This macro is used to indicate a yPDef struct for a signal without parameters. Such a signal has no generated yPDef struct. It is suitable to let XSIGNALHEADERTYPE be the name of a struct just containing the components in SIGNAL_VARS.

XSIGTYPE

Depending on the representation of the signal type that is used (xSignalIdNode or int) this macro should either be xSignalIdNode or int.

Implementation of RPC

ALLOC_REPLY_SIGNAL

ALLOC_REPLY_SIGNAL_PAR

ALLOC_REPLY_SIGNAL_PRD

ALLOC_REPLY_SIGNAL_PRD_PAR

These macros are used to allocate the Reply signal in the signal exchange in an RPC. The suffix _PAR is used if the reply signal contains parameters. The suffix _PRD is used if the implicit RPC transition is part of a procedure.

REPLYSIGNAL_DATA_PTR

REPLYSIGNAL_DATA_PTR_PRD

This should be a reference to the data area for the reply signal that is allocated in the ALLOC_REPLY_SIGNAL macro. The suffix _PRD is used if the implicit RPC transition is part of a procedure.

SDL_RPCWAIT_NEXTSTATE

SDL_RPCWAIT_NEXTSTATE_PRD

These macros are used to implement the implicit nextstate operation in the caller of an RPC. The suffix _PRD is used if the implicit RPC transition is part of a procedure.

SDL_2OUTPUT_RPC_CALL

Send the call signal of an RPC.

SDL_2OUTPUT_RPC_REPLY

SDL_2OUTPUT_RPC_REPLY_PRD

These macros are used to send the RPC reply signal. The suffix _PRD is used if the implicit RPC transition is part of a procedure.

XGETEXPORTINGPRS

This macro should be expanded to an expression that given the remote procedure given as actual macro parameter (more exactly the IdNode for the remote procedure), returns one possible exporter of this remote procedure. Usually this macro is expanded to a call of the library function xGetExportingPrs.

XRPC_REPLY_INPUT

XRPC_REPLY_INPUT_PRD

Macros that can be used for special processing needed to receive an RPC reply signal. The macros are usually expanded to nothing.

XRPC_SAVE_SENDER

XRPC_SAVE_SENDER_PRD

These macros can be used to save the sender of a received RPC call signal, for further use when the reply signal is to be sent. The suffix _PRD is used if the implicit RPC transition is part of a procedure.

XRPC_SENDER_IN_ALLOC

XRPC_SENDER_IN_ALLOC_PRD

These macros are used to obtain the receiver of the reply signal (from the sender of the call signal) in the ALLOC_REPLY_SIGNAL macros. The suffix _PRD is used if the implicit RPC transition is part of a procedure.

XRPC_SENDER_IN_OUTPUT

XRPC_SENDER_IN_OUTPUT_PRD

These macros are used to obtain the receiver of the reply signal (from the sender of the call signal) in the SDL_2OUTPUT_RPC_REPLY macros. The suffix _PRD is used if the implicit RPC transition is part of a procedure.

XRPC_WAIT_STATE

The state number used for a RPC wait state. XRPC_WAIT_STATE is usually defined as -3.

Implementation of View and Import

XGETEXPORTADDR

This macro should be expanded to an expression that returns the address of the exported variable. Usually the function xGetExportAddr is called.

SDL_VIEW

This macro should be expanded to an expression that returns the address of the viewed variable. Usually the function SDL_View is called.

Implementation of Static and Dynamic Create and Stop

ALLOC_STARTUP

ALLOC_STARTUP_PAR

Allocate the data area for a startup signal and let the pointer mentioned in the macro STARTUP_DATA_PTR refer to this data area. The suffix _PAR is used if the startup signal contains parameters.

ALLOC_STARTUP_THIS

Allocate the data area for a startup signal and let the pointer mentioned in the macro STARTUP_DATA_PTR refer to this data area. This macro is used in a create THIS operation.

INIT_PROCESS_TYPE

This macro will be call once for each process instance set in the yInit function. It should be used to initiated common features for all instances of a process instance set.

SDL_CREATE

This macro is used to create (a create action) a process instance.

SDL_CREATE_THIS

This macro is used to implement create this.

SDL_STATIC_CREATE

This macro is called in the yInit function once for each static process instances that should be created of a process instance set.

SDL_STOP

This macro is used to implement the SDL operation stop (both in processes and in services).

STARTUP_ALLOC_ERROR

This macro is inserted after the ALLOC_STARTUP macro and the assignment of parameter values to the signal. It can be used to test if the alloc was successful or not.

STARTUP_ALLOC_ERROR_END

This macro is inserted after the SDL_CREATE macro.

STARTUP_DATA_PTR

This macro should be expanded to a temporary variable used to store a reference to the startup signal data area. It should be assigned in the ALLOC_STARTUP macro and will be used to assign the actual signal parameters (the fpar values) to the startup signal.

STARTUP_VARS

This macro can be used to insert additional general components in the startup signals. In all startup signal yPDef structs SIGNAL_VARS will be followed by STARTUP_VARS.

Implementation of Timers, Timer Operations and Now

ALLOC_TIMER_SIGNAL_PAR

Allocate a data area for the timer signal with parameters.

DEF_TIMER_VAR

DEF_TIMER_VAR_PARA

There will be one application of this macro in the yVDef type for the process for each timer declaration the process contains. These declarations can be used to introduce components (timer variables) in the yVDef struct to track timers. The parameter TIMER_VAR is a suitable name for such a variable. The suffix _PARA is used if the timer has parameters.

INIT_TIMER_VAR

INIT_TIMER_VAR_PARA

These macros will be inserted in start transitions, during initialization of process variables. This makes it possible to initialize the timer variables that might be inserted in the DEF_TIMER_VAR macro. The parameter TIMER_VAR is the name for such a variable. The suffix _PARA is used if the timer has parameters.

INPUT_TIMER_VAR

INPUT_TIMER_VAR_PARA

These macros will be inserted at an input operation on a timer signal. This makes it possible to update the timer variables that might be inserted in the DEF_TIMER_VAR macro. The parameter TIMER_VAR is the name for such a variable. The suffix _PARA is used if the timer has parameters. Note that if a timer signal is received in an input * statement, no INPUT_TIMER_VAR will be present in this case.

RELEASE_TIMER_VAR

RELEASE_TIMER_VAR_PARA

These macros will be inserted at a stop. This makes it possible to perform cleaning up of the timer variables that might be inserted in the DEF_TIMER_VAR macro. The parameter TIMER_VAR is the name for such a variable. The suffix _PARA is used if the timer has parameters.

SDL_ACTIVE

This macro is used to implement the SDL operation active on a timer. Note that active on timers with parameters is not implemented in the Cadvanced/Cbasic Code Generator.

SDL_NOW

This is the implementation of now in SDL.

SDL_RESET

This macro is used to implement the SDL operation reset on a timer without parameters.

SDL_RESET_WITH_PARA

This macro is used to implement the SDL operation reset on a timer with parameters. Before this macro a timer signal with the timer parameters in the reset operation is created.

SDL_SET

SDL_SET_WITH_PARA

SDL_SET_DUR

SDL_SET_DUR_WITH_PARA

SDL_SET_TICKS

SDL_SET_TICKS_WITH_PARA

These six SDL_SET macros are used to implement the SDL operation set on a timer. The suffix _WITH_PARA indicates the set of a timer with parameters. In this case the SDL_SET macro is preceded by an ALLOC_TIMER_SIGNAL_PAR macro call, plus the assignment of the timer parameters. The suffix _DUR is used if the time value in the set operation is expressed as:

In this case both the time value and the duration value (the expression above) is available as macro parameter. The suffix _TICKS is used if the time value in the set operation is expressed as:

where TICKS is an operator returning a duration value. In this case both the time value and the duration value (the TICKS expression above) is available as macro parameter.

TIMER_DATA_PTR

This should be the pointer referring to be timer data area while building
the timer. It should be assigned its value in ALLOC_TIMER_SIGNAL_PAR, and will then be used during assignment of signal parameters and in the SDL_SET macro

TIMER_SIGNAL_ALLOC_ERROR

This macro is inserted after the ALLOC_TIMER_SIGNAL_PAR macro and the assignment of parameter values to the timer. It can be used to test if the alloc was successful or not.

TIMER_SIGNAL_ALLOC_ERROR_END

This macro is inserted after the SDL_SET macro.

TIMER_VARS

The struct components that are needed for each timer instance. Example: sender, receiver, timer type.

As timers are signals as well, after the timer signal has been sent, TIMER_VARS has to be identical to SIGNAL_VARS, except that new component may be add last in TIMER_VARS.

XTIMERHEADERTYPE

This macro is used to indicate a yPDef struct for a timer without parameters. Such a timer has no generated yPDef struct. It is suitable to let XTIMERHEADERTYPE be the name of a struct just containing the components in TIMER_VARS.

Implementation of Call and Return

ALLOC_PROCEDURE

Allocate a data area (yVDef) for the called procedure.

ALLOC_THIS_PROCEDURE

Allocate a data area (yVDef) for a procedure when call THIS is used.

ALLOC_VIRT_PROCEDURE

Allocate a data area (yVDef) for the called procedure when calling a virtual procedure. The PROC_IDNODE parameter is the xPrdIdNode for the call procedure.

CALL_PROCEDURE

CALL_PROCEDURE_IN_PRD

These macros are used to implement a call operation in SDL. The yVDef struct has been allocated earlier (in ALLOC_PROCEDURE) and the actual parameters have been assigned to components in this struct. The suffix _IN_PRD indicates that the procedure call is made in a procedure.

CALL_PROCEDURE_STARTUP

CALL_PROCEDURE_STARTUP_SRV

These two macros are only of interest if the PAD functions are left via a return at the end of transitions. In that case any outstanding procedure must be restarted when the process becomes active again.

CALL_THIS_PROCEDURE

This macro is used to implement a call THIS operation in SDL. RESTARTADDR is the restart address the symbol number for the symbol after the procedure call.

CALL_VIRT_PROCEDURE

CALL_VIRT_PROCEDURE_IN_PRD

These macros are used to implement a call operation on a virtual procedure in SDL. The yVDef struct has been allocated earlier (in ALLOC_VIRT_PROCEDURE) and the actual parameters have been assigned to components in this struct. The suffix _IN_PRD indicates that the procedure call is made in a procedure.

PROCEDURE_ALLOC_ERROR

This macro is inserted after the ALLOC_PROCEDURE macro and the assignment of parameter values to the procedure parameters. It can be used to test if the alloc was successful or not.

PROCEDURE_ALLOC_ERROR_END

This macro is inserted after the CALL_PROCEDURE macro.

PROC_DATA_PTR

This macro should be expanded to a temporary variable used to store a reference to the procedure data area. It should be assigned in the ALLOC_PROCEDURE macro and will be used to assign the actual procedure parameters (the fpar values).

SDL_RETURN

The implementation of return in SDL.

XNOPROCATSTARTUP

If this macro is defined then all the code discussed for the macro CALL_PROCEDURE_STARTUP (just above) is removed.

Implementation of Join

Joins in SDL are normally implemented as goto:s in C, but in one case a more complex implementation is needed. This is when the label, mentioned in the join, is in a super type.

XJOIN_SUPER_PRS

XJOIN_SUPER_PRD

XJOIN_SUPER_SRV

These macros represent join to super type in processes, procedures, and services, in that order.

Implementation of State and Nextstate

Note: 

Implicit nextstate operations in RPC calls are treated in the RPC section.

ASTERISK_STATE

The state number for an asterisk state. ASTERISK_STATE is usually defined as -1.

ERROR_STATE

The state number used for the error state. ERROR_STATE is usually defined as -2.

START_STATE

The state number for the start state. START_STATE should be defined as 0.

START_STATE_PRD

The state number for the start state in a procedure. START_STATE_PRD should be defined as 0.

SDL_NEXTSTATE

Nextstate operation (in process or service) of the given state.

SDL_DASH_NEXTSTATE

Dash nextstate operation in a process.

SDL_DASH_NEXTSTATE_SRV

Dash nextstate operation in a service.

SDL_NEXTSTATE_PRD

Nextstate operation (in procedure) of the given state.

SDL_DASH_NEXTSTATE_PRD

Dash nextstate operation in a procedure.

Implementation of Any Decisions

An any decision with two paths are generated according to the following structure:

BEGIN_ANY_DECISION

Start of the any decision. NO_OF_PATHS is the number of paths in the decision.

BEGIN_ANY_PATH

A path (not the first) in implementation part of the any decision. PATH_NO is the path number.

BEGIN_FIRST_ANY_PATH

The first possible path in implementation part of the any decision. PATH_NO is the path number.

DEF_ANY_PATH

Definition of a path in the decision.

END_ANY_DECISION

The end of the any decision.

END_ANY_PATH

End of one of the paths in the implementation section.

END_DEFS_ANY_PATH

End of the definition part of the any decision. NO_OF_PATHS is the number of paths in the decision.

Implementation of Informal Decisions

The implementation of informal decisions are similar to any decisions.

BEGIN_FIRST_INFORMAL_PATH

The first possible path in implementation part of the informal decision. PATH_NO is the path number.

BEGIN_INFORMAL_DECISION

Start of the any decision.

BEGIN_INFORMAL_ELSE_PATH

The else path in implementation part of the any decision. PATH_NO is the path number.

BEGIN_INFORMAL_PATH

A path in implementation part of the any decision. PATH_NO is the path number.

DEF_INFORMAL_PATH

Definition of a path in the decision.

DEF_INFORMAL_ELSE_PATH

Definition of the else path in the decision.

END_DEFS_INFORMAL_PATH

End of the definition part of the informal decision. NO_OF_PATHS is the number of paths in the decision.

END_INFORMAL_ELSE_PATH

End of the else paths in the implementation section.

END_INFORMAL_DECISION

The end of the informal decision.

END_INFORMAL_PATH

End of one of the paths in the implementation section.

Macros for Component Selection Tests

The macros in this section handles testing the validity of for example a component selection of a choice or #UNION variable. Also tests for optional components in structs and for de-referencing of pointers is treated here.

XCHECK_CHOICE_USAGE

XSET_CHOICE_TAG

XSET_CHOICE_TAG_FREE

The CHOICE macros are used to test and to set the implicit tag in a choice variable. The XSET_CHOICE_TAG and XSET_CHOICE_TAG_FREE set the tag when some component of the choice is assigned a value. The FREE version of the macro is used if the choice contains some component that has a Free function. The XCHECK_CHOICE_USAGE is used to test if an accessed component is active or not.

XCHECK_OPTIONAL_USAGE

This macro is used to check that a selected optional component is present. The PRESENT_VAR parameter is the present variable for this component, while COMPNAME is the selected components name as a char string.

XCHECK_UNION_TAG_USAGE

XCHECK_UNION_TAG

XCHECK_UNION_TAG_FREE

The UNION macros are used to test tag in a union variable. The XCHECK_UNION_TAG and XCHECK_UNION_TAG_FREE check the tag when some component of the union is assigned a value. The FREE version of the macro is used if the union contains some component that has a Free function. The XCHECK_UNION_USAGE is used to test if an accessed component is active or not.

XCHECK_REF

XCHECK_OWN

XCHECK_OREF

These macros are used to implement a test that Null pointers (using the Ref, Own, or ORef generator) are not de-referenced. These macros are inserted before each statement containing a Ref/Own/ORef pointer de-referencing. In case of an ORef pointer it is also checked that the ORef is valid, i.e. that it refers to an object owned by the current process.

XCHECK_OREF2

Checks that a ORef pointer is a valid pointer, i.e. NULL, or that it refers to an object owned by the current process.

Debug and Simulation Macros

XAFTER_VALUE_RET_PRDCALL

A macro generated between the implementation of a value returning procedure call (implicit call symbol) and the symbol containing the value returning procedure call. SYMB_NO is the symbol number of the symbol containing the value returning procedure call.

XAT_FIRST_SYMBOL

A macro generated between an input or start symbol and the first symbol in the transition. SYMB_NO is the symbol number of the first symbol in the transition.

XAT_LAST_SYMBOL

A macro generated immediately before a nextstate or stop operation.

XBETWEEN_STMTS

XBETWEEN_STMTS_PRD

A macro generated between statements in a task. The suffix _PRD indicates that these statements are part of a procedure.

XBETWEEN_SYMBOLS

XBETWEEN_SYMBOLS_PRD

A macro generated between symbols in a transition. The suffix _PRD indicates that these symbols are part of a procedure.

XDEBUG_LABEL

This macro gives the possibility to insert label at the beginning of transitions. Such labels can be useful during debugging. The LABEL_NAME parameter is a concatenation of state name and the signal name. The * in state *; and input *; will cause the name ASTERISK to appear.

XOS_TRACE_INPUT

This macro is generated at input statements and can, for example, be used to generated trace information about inputs. The SIG_NAME_STRING parameter is the name of the signal in the input.

YPRSNAME_VAR

This macro is generated among the declarations of variables in the PAD function for a process. It can, for example, be used to declare a char * variable containing the name of the process. Such a variable can be useful during debugging. The PRS_NAME_STRING parameter is the name of the process as a character string.

YPRDNAME_VAR

This macro is generated among the declarations of variables in the PRD function for a procedure. It can, for example, be used to declare a char* variable containing the name of the procedure. Such a variable can be useful during debugging. The PRD_NAME_STRING parameter is the name of the procedure as a character string.

Utility Macros to Be Inserted

The following sequence of macros should be inserted. Most of them concern removal of struct components (in IdNodes) that are not used due to the combination of other switches used.

The xDefaultPrio macros above should, of course, be defined to the suitable default values.

Other macros that should be defined are.

SDL_NULL

a null value for the type PId.

xNotDefPId

which is used as RECEIVER parameter in the SDL_2OUTPUT macros. Please see also the section were signals are treated.


[Previous] [Next] [Contents] [Index]