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 chapter 41, References in SDT-3. 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 562 on page 2201. 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 562 : Block Structure and Compilation Unit Structure (Example). ----- (fig) -----
/* Program generated by SDT C Code Generator, version 2.02 */ /* C-Advanced option */ #define XSCT_CADVANCED #define SCT_VERSION_2_02 #include "scttypes.h"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:
#include "packagename.h" #include "systemname.h" #include "blockname.h"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:
#include "unitname.h"If this is a unit for a system then this is followed by:
XSYSTEMVARS extern void yInit XPP((void));The name of this file is then generated as a char variable:
#ifdef XCTRACE static char xFileName[] = "mall.c"; #endifIf 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.
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:
Each subsection for an SDL entity starts with a comment to identify the entity.
Example 137 /***** * PROCESS P1 * <<SYSTEM mall/BLOCK B1>> * #SDTREF(TEXT,mall.pr,30) ******/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 chapter 41, References in SDT-3).
The following entity classes are treated in subsections below:
/***** * SYSTEM mall and ENV * #SDTREF(TEXT,mall.pr,1) ******/ extern XCONST struct xSystemIdStruct ySysR_mall; extern XCONST struct xPrsIdStruct yEnvR_env;That is extern definitions of the IdStructs for the system and for the process representing the environment.
The following is generated for a system instance:
/***** * SYSTEM INST systype1 and ENV * #SDTREF(TEXT,systype1.pr,2) ******/ extern XCONST struct xSystemIdStruct ySysR_z_systype1; extern XCONST xIdNode ySysP_z_systype1[]; extern XCONST struct xPrsIdStruct yEnvR_env;where ySysP_z_systype1 will become a list of channels defined in the system.
The following is generated for a system type:
/***** * SYSTEM TYPE S0 * <<PACKAGE slib>> * #SDTREF(TEXT,systype1.pr,7) ******/ extern XCONST struct xSystemIdStruct ySysR_z_slib_0_S0; #define yChaE_z_slib_01_C1 0 #define yChaE_z_slib_02_C2 1where the yChaE_... can be used as indexes in the ySysP_z_systype1 list of channels (see example above). Using this list and these indexes its is possible to refer to channels generated in the system instance from C code generated for the system type, for example in an OUTPUT VIA.
/***** * PACKAGE slib * #SDTREF(TEXT,systype1.pr,5) ******/ extern struct xPackageIdStruct yPacR_z_slib__slib;--------------------------------------------------------------------- Note: A package is always a separate unit and that both a .c and a .h file are generated. ---------------------------------------------------------------------
/***** * SUBSTRUCTURE BType * <<SYSTEM inst6/BLOCK TYPE BType>> * #SDTREF(TEXT,inst6.pr,19) ******/ extern XCONST struct xBlockSubstIdStruct yBSuR_z80_BType;
/***** * BLOCK B1 * <<SYSTEM mall>> * #SDTREF(TEXT,mall.pr,28) ******/ extern XCONST struct xBlockIdStruct yBloR_z0_B1;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:
extern XCONST struct xViewListStruct yView_z0_B1[]; #define yView_z_predefined_6_revVar 0If 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.
extern XCONST xIdNode yBloP_z0_B1[]; #define yPrsE_z00_P1 0 #define yPrsE_z01_P2 1For a block type the following code is generated:
/***** * BLOCK TYPE B1Type * <<PACKAGE sib/SYSTEM TYPE S0>> * #SDTREF(TEXT,systype1.pr,16) ******/ extern XCONST struct xBlockIdStruct yBloR_z_slib_06_B1Type; #define yChaE_z_systemlib_061_G 0 #define yPrsE_z_systemlib_060_P1 0where the defines can be used to index in the yBloP_BlockName list generated for a block instance of this block type.
/***** * PROCESS P1 * <<SYSTEM mall/BLOCK B1>> * #SDTREF(TEXT,mall.pr,30) ******/ extern XCONST XSIGTYPE yPrsS_z00_P1[]; extern XCONST xStateIdNode yPrsT_z00_P1[]; extern XCONST struct xPrsIdStruct yPrsR_z00_P1; #define yPrsN_z00_P1 (&yPrsR_z00_P1) #ifdef XCOVERAGE extern long int yPrsC_z00_P1[]; #endif YPAD_PROTOTYPE(yPAD_z00_P1) #ifndef XNOSTARTUPIDNODE extern XCONST struct xSignalIdStruct ySigR_z00_P1; #define ySigN_z00_P1 (&ySigR_z00_P1) #endifThe 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.
typedef struct { PROCESS_VARS /* #SDTREF(TEXT,mall.pr,33) */ SDL_Integer z004_remVar; SDL_Integer yExp_z004_remVar; /* #SDTREF(TEXT,mall.pr,34) */ SDL_Integer z005_revVar; /* #SDTREF(TEXT,mall.pr,36) */ SDL_Integer z006_I; } yVDef_z00_P1; typedef yVDef_z00_P1 *yVDP_z00_P1; typedef struct { SIGNAL_VARS STARTUP_VARS } yPDef_z00_P1; typedef yPDef_z00_P1 *yPDP_z00_P1; XPROCESSDEF_H(P1,"P1",z00_P1,yPAD_z00_P1,yVDef_z00_P1) #ifdef XBREAKBEFORE #define ySym_z00_P1 26 extern char * yRef_z00_P1 XPP((int, xSymbolType *)); #endifAfter 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.
DECISION CharstringVar; ('abc') : ...; ELSE : ...; ENDDECISION;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.
typedef struct { PROCESS_VARS TypeName1 FPAR_var1; TypeName2 FPAR_var2; TypeName3 DCL_var1; TypeName4 DCL_var2; TypeName4 yExp_DCL_var2; TypeName5 yDcn_TypeName5; } yVDef_ProcessName; typedef yVDef_ProcessName *yVDP_ProcessName;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 S1 * <<SYSTEM serv3/BLOCK Block1/PROCESS P1>> * #SDTREF(TEXT,serv3.pr,27) ******/ extern XCONST XSIGTYPE ySrvS_z011_S1[]; extern XCONST xStateIdNode ySrvT_z011_S1[]; extern XCONST struct xSrvIdStruct ySrvR_z011_S1; #define ySrvN_z011_S1 (&ySrvR_z011_S1) #ifdef XCOVERAGE extern long int ySrvC_z011_S1[]; #endif YPAD_PROTOTYPE(yPAD_z011_S1) #ifndef XOPTCHAN extern XCONST_NOPART xIdNode ySrvO_z011_S1[]; #endif #ifdef XBREAKBEFORE #define ySym_z011_S1 8 extern char * yRef_z011_S1 XPP((int, xSymbolType *)); #endif typedef struct { SERVICE_VARS /* declarations of service local variables */ } yVDef_z011_S1; typedef yVDef_z011_S1 *yVDP_z011_S1;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 Proc2 * <<SYSTEM mall/BLOCK B1/PROCESS P2>> * #SDTREF(TEXT,mall.pr,89) ******/ YPRD_PROTOTYPE(z011_Proc2) extern XCONST struct xPrdIdStruct yPrdR_z011_Proc2; #define yPrdN_z011_Proc2 (&yPrdR_z011_Proc2) #ifdef XBREAKBEFORE #define ySym_z011_Proc2 2 extern char * yRef_z011_Proc2 XPP((int, xSymbolType *)); #endif typedef struct { PROCEDURE_VARS /* #SDTREF(TEXT,mall.pr,90) */ SDL_Integer z0110_P1; /* #SDTREF(TEXT,mall.pr,90) */ SDL_Integer *z0111_P2; } yVDef_z011_Proc2; typedef yVDef_z011_Proc2 *yVDP_z011_Proc2;
DECISION CharstringVar; ('abc') : ...; ELSE : ...; ENDDECISION;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
typedef struct { PROCEDURE_VARS TypeName1 FPAR_var1; TypeName2 *FPAR_var2; TypeName3 DCL_var1; TypeName4 DCL_var2; TypeName5 yDcn_TypeName5; } yVDef_ProcedureName; typedef yVDef_ProcedureName *yVDP_ProcedureName;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 the all the inherited procedures are included in the struct above, starting from the top of the inheritance chain.
/***** * SIGNAL Sig3 * <<SYSTEM mall>> * #SDTREF(TEXT,mall.pr,4) ******/ #ifndef XNOSIGNALIDNODE extern XCONST struct xSignalIdStruct ySigR_z3_Sig3; #define ySigN_z3_Sig3 (&ySigR_z3_Sig3) #endif typedef struct { SIGNAL_VARS SDL_Integer Param1; SDL_Character Param2; } yPDef_z3_Sig3; typedef yPDef_z3_Sig3 *yPDP_z3_Sig3;
/***** * REMOTE PROCEDURE rpc1 * <<SYSTEM rpc1>> * #SDTREF(TEXT,rpc1.pr,8) ******/ extern struct xRemotePrdIdStruct yRePR_z3_rpc1; #ifndef XNOSIGNALIDNODE extern XCONST struct xSignalIdStruct ySigR_pCALL_z3_rpc1; extern XCONST struct xSignalIdStruct ySigR_pREPLY_z3_rpc1; #define ySigN_pCALL_z3_rpc1 (&ySigR_pCALL_z3_rpc1) #define ySigN_pREPLY_z3_rpc1 (&ySigR_pREPLY_z3_rpc1) #endif typedef struct { SIGNAL_VARS SDL_Integer Param1; SDL_Integer Param2; } yPDef_pCALL_z3_rpc1; typedef yPDef_pCALL_z3_rpc1 *yPDP_pCALL_z3_rpc1; typedef struct { SIGNAL_VARS SDL_Integer Param2; } yPDef_pREPLY_z3_rpc1; typedef yPDef_pREPLY_z3_rpc1 *yPDP_pREPLY_z3_rpc1;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.
/***** * DCL I * <<SYSTEM mall/BLOCK B1/PROCESS P1>> * #SDTREF(TEXT,mall.pr,36) ******/ #ifndef XOPTDCL extern XCONST struct xVarIdStruct yVarR_z006_I; #endif
/***** * REMOTE VARIABLE remVar * <<SYSTEM mall>> * #SDTREF(TEXT,mall.pr,26) ******/ #ifndef XNOREMOTEVARIDNODE extern struct xRemoteVarIdStruct yReVR_z7_remVar; #define yReVN_z7_remVar (&yReVR_z7_remVar) #endif
/***** * STATE State3 * <<SYSTEM mall/BLOCK B1/PROCESS P1>> * #SDTREF(TEXT,mall.pr,72) ******/ #define z002_State3 3 extern XCONST struct xStateIdStruct yStaR_z002_State3; #define yStaN_z002_State3 (&yStaR_z002_State3)If the state contains enabling conditions then an extern definition for an enabling condition function is generated:
#ifndef XNOENABCONDFUNC extern xInputAction yEnab_z001_State2 XPP((XSIGTYPE, void *)); #endifIf the state contains continuous signals then an extern definition for an continuous signal function is generated:
#ifndef XNOCONTSIGFUNC extern void yCont_z001_State2 XPP((void *, int *, xIdNode *, int *)); #endif
/***** * CHANNEL C1 * <<PACKAGE systemlib/SYSTEM TYPE S0>> * #SDTREF(TEXT,systype1.pr,9) ******/ #ifndef XOPTCHAN extern XCONST_CHAN struct xChannelIdStruct yChaR_z1_C1; extern XCONST_CHAN struct xChannelIdStruct yChaRR_z1_C1; #define yChaN_z1_C1 (&yChaR_z1_C1) #endif
#define SynonymName SynonymValue
If newtype or syntype is found:
#ifndef XOPTSORT extern XCONST struct xSortIdStruct ySrtR_sort1; #define ySrtN_sort1 (&ySrtR_sort1) #endif
#include "filename"If #CODE directive is found:
/***** * NEWTYPE struct1 (TYPE section) * <<SYSTEM mall>> * #SDTREF(TEXT,mall.pr,6) ******/ typedef struct struct1_s { SDL_Integer a; SDL_Integer b; } struct1; /* #SDTREF(TEXT,mall.pr,7) */ COMMENT((This is the #type section)) #ifndef XOPTSORT extern XCONST struct xSortIdStruct ySrtR_struct1; #define ySrtN_struct1 (&ySrtR_struct1) #endif
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 ))
#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 #endifThe 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. --------------------------------------------------------------------The code for the yTstA_TypeName and yTstI_TypeName functions are shown in the section "Newtype, Syntype" on page 2233 and their use is discussed in "Translation of SDL Expressions" on page 2257.
extern TypeName LiteralName XPP(( void ));For each operator that should have a generated heading:
extern ResultTypeName OperatorName XPP(( appropriate parameters ));
Example 138 extern TypeName1 SynonymName; #ifndef ExtSynonymName extern TypeName2 ExtSynonymName; #endifThe variables representing the SDL synonyms are assigned values during startup of the program in the init function, see "Initialization" on page 2238.
/***** * SYMBOL TABLE ROOT ******/ static XCONST struct xIdStruct ySymbRootVar = {xSystemEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)0 xIdNames("SymbolTableRoot") XCOMMON_EXTRAS}; /***** * SYSTEM mall * #SDTREF(TEXT,mall.pr,1) ******/ XCONST struct xSystemIdStruct ySysR_z_mall = {xSystemEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySymbRootVar xIdNames("mall") XCOMMON_EXTRAS, (xIdNode *)0, (xPrdIdNode *)0, (xSystemIdNode)0 xTrace(-1) xGRTrace(-1) xMSCETrace(-1) XSYS_EXTRAS}; /***** * ENV ******/ #ifndef XOPTCHAN static xIdNode yEnvO_env[] = { (xIdNode)&yChaRR_z1_Channel1, (xIdNode)0 XTRACHANNELLIST}; #endif static XPRSNODE yEnvA_env = (XPRSNODE)0; static XPRSNODE yEnvB_env = (XPRSNODE)0; XCONST struct xPrsIdStruct yEnvR_env = {xProcessEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySymbRootVar xIdNames("env") XCOMMON_EXTRAS, 0, 0 xService(0) xOptChan(yEnvO_env), 1 xNrInst(1) xNrInst(1), &yEnvB_env,(xptrint)sizeof(xPrsRec) xPrsPrioPar(xDefaultPrioProcess), &yEnvA_env xTrace(-1) xGRTrace(-1) xBreakB(0) xBreakB(-1) xBreakB(0) xMSCETrace(-1) xCoverage(0) xCoverage(0) xCoverage(0), 0, (xPrsIdNode)0, (xPrdIdNode *)0, (xBlockIdNode)0 xBreakB("") XPRS_EXTRAS(env)}; #ifndef XNOSTARTUPIDNODE static XCONST struct xSignalIdStruct ySigR_Env = {xStartUpSignalEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySymbRootVar xIdNames("-") XCOMMON_EXTRAS, (xptrint)sizeof(XSIGNALHEADERTYPE), 0, 0 xFreS(0) SIGCODE(STARTUPSIGNAL) xBreakB("") XSIG_EXTRAS}; #endifIn this code four IdStructs are declared, the symbol table root node, the node for the system, the node for the env process, and the startup signal for the env process. To look at each individual component, this code should be compared with the type definitions for the IdStructs, see section "Type Definitions from Abstract Data Types and #CODE (#TYPE Section)" on page 2214.
For a system instance a similar sequence of code is generated. The differences are in the IdNode for the system:
/***** * SYSTEM INST systype1 * #SDTREF(TEXT,systype1.pr,2) ******/ XCONST xIdNode ySysP_z_systype1[] = {(xIdNode)&yChaR_z1_C1, (xIdNode)&yChaR_z2_C2, (xIdNode)0}; XCONST struct xSystemIdStruct ySysR_z_systype1 = {xSystemEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySymbRootVar xIdNames("systype1") XCOMMON_EXTRAS, ySysP_z_systype1, (xPrdIdNode *)0, (xSystemIdNode)0 xTrace(-1) xGRTrace(-1) xMSCETrace(-1) XSYS_EXTRAS};Here we see the implementation of the ySysP_z_systype1 list of channels, discussed in the subsection about systems in "Types and Forward References" on page 2203. Note also the ySysP_z_systype1 is stored in the IdStruct for the system instance.
For a system type the following code is generated:
/***** * SYSTEM TYPE S0 * <<PACKAGE slib>> * #SDTREF(TEXT,systype1.pr,7) ******/ XCONST struct xSystemIdStruct ySysR_z_slib_0_S0 = {xSystemTypeEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&yPacR_z_slib__slib xIdNames("S0") XCOMMON_EXTRAS, (xIdNode *)0, (xPrdIdNode *)0, (xSystemIdNode)0 xTrace(-1) xGRTrace(-1) xMSCETrace(-1) XSYS_EXTRAS};
/***** * PACKAGE slib * #SDTREF(TEXT,systype1.pr,5) ******/ struct xPackageIdStruct yPacR_z_slib__slib = {xPackageEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)0 xIdNames("systemlib") XCOMMON_EXTRAS XPAC_EXTRAS};
/***** * SUBSTRUCTURE BType * <<SYSTEM inst6/BLOCK TYPE BType>> * #SDTREF(TEXT,inst6.pr,19) ******/ XCONST struct xBlockSubstIdStruct yBSuR_z80_BType = {xBlocksubstEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&yBloR_z8_BType xIdNames("BType") XCOMMON_EXTRAS XBLS_EXTRAS};
/***** * BLOCK B1 * <<SYSTEM mall>> * #SDTREF(TEXT,mall.pr,28) ******/ XCONST xIdNode yBloP_z0_B1[] = {(xIdNode)&yPrsR_z00_P1, (xIdNode)&yPrsR_z01_P2, (xIdNode)0}; XCONST struct xBlockIdStruct yBloR_z0_B1 = {xBlockEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_mall xIdNames("B1") XCOMMON_EXTRAS, (xBlockIdNode)0, yBloP_z0_B1, (xPrdIdNode *)0, yView_z0_B1, 1 xTrace(-1) xGRTrace(-1) xMSCETrace(-1) xMSCETrace(0) XBLO_EXTRAS};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:
{PrsIdNode for revealing process, revealing service, offset in yVDef struct for value}
XCONST struct xViewListStruct yView_z0_B1[] = { {&yPrsR_z00_P1, xService(0) xOffsetOf(yVDef_z00_P1, z005_revVar)}, {0,0} };For a block type the following BlockIdStruct declaration is generated:
/***** * BLOCK TYPE B1Type * <<PACKAGE slib/SYSTEM TYPE S0>> * #SDTREF(TEXT,systype1.pr,16) ******/ XCONST struct xBlockIdStruct yBloR_z_slib_06_B1Type = {xBlockTypeEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_systemlib_0_S0 xIdNames("B1Type") XCOMMON_EXTRAS, (xBlockIdNode)0, (xIdNode *)0, (xPrdIdNode *)0, (xViewListRec *)0, 1 xTrace(-1) xGRTrace(-1) xMSCETrace(-1) xMSCETrace(0) XBLO_EXTRAS};
/***** * PROCESS P1 * <<SYSTEM mall/BLOCK B1>> * #SDTREF(TEXT,mall.pr,30) ******/ #ifdef XCOVERAGE long int yPrsC_z00_P1[ySym_z00_P1+1]; #endif XCONST XSIGTYPE yPrsS_z00_P1[] = {SIGNAL_NAME(Sig1, &ySigR_z1_Sig1), SIGNAL_NAME(Sig2, &ySigR_z2_Sig2), SIGNAL_NAME(Sig3, &ySigR_z3_Sig3), SIGNAL_NAME(t1, &ySigR_z003_t1), (XSIGTYPE)0}; XCONST xStateIdNode yPrsT_z00_P1[] = {&xStartStateIdRec, &yStaR_z000_State1, &yStaR_z001_State2, &yStaR_z002_State3}; static XPRSNODE yPrsA_z00_P1 = (XPRSNODE)0; static XPRSNODE yPrsB_z00_P1 = (XPRSNODE)0; XCONST struct xPrsIdStruct yPrsR_z00_P1 = {xProcessEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&yBloR_z0_B1 xIdNames("P1") XCOMMON_EXTRAS, yPrsT_z00_P1, yPrsS_z00_P1 xService(0) xOptChan(yPrsO_z00_P2), SDL_INTEGER_LIT(1) xNrInst(1) xNrInst(SDL_INTEGER_LIT(1)), &yPrsB_z00_P1, (xptrint)sizeof(yVDef_z00_P1) xPrsPrioPar(xDefaultPrioProcess), &yPrsA_z00_P1 xTrace(-1) xGRTrace(-1) xBreakB(yRef_z00_P1) xBreakB(ySym_z00_P1) xBreakB(4) xMSCETrace(-1) xCoverage(yPrsC_z00_P1) xCoverage(0) xCoverage(0), yPAD_z00_P1, (xPrsIdNode)0, (xPrdIdNode *)0, (xBlockIdNode)0 xBreakB("#SDTREF(TEXT,mall.pr,30)") XPRS_EXTRAS(z00_P2)}; #ifndef XNOSTARTUPIDNODE static xSignalNode ySigA_z00_P1 = (xSignalNode)0; XCONST struct xSignalIdStruct ySigR_z00_P1 = {xStartUpSignalEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&yBloR_z0_B1 xIdNames("-") XCOMMON_EXTRAS, (xptrint)sizeof(yPDef_z00_P1), &ySigA_z00_P1, 0 xFreS(0) SIGCODE(STARTUPSIGNAL) xBreakB("#SDTREF(TEXT,mall.pr,30)") XSIG_EXTRAS}; #endif XPROCESSDEF_C(P1,"P1",z00_P1,yPAD_z00_P1,yVDef_z00_P1) XCONST_NOPART xIdNode yPrsO_z00_P2[] = {(xIdNode)&yChaR_z07_sr1, (xIdNode)&yChaRR_z08_local, (xIdNode)0}; #endifThe 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.
static struct xRemoteVarListStruct yExpR_z004_remVar = {(xRemoteVarListNode)0, &yPrsR_z00_P1, xService(0) xOffsetOf(yVDef_z00_P1, yExp_z004_remVar)};After that a function is generated that is used to translated a symbol number to a symbol type and a SDT reference.
/*+++++ * GR ref function for process P1 * #SDTREF(TEXT,mall.pr,30) ++++++*/ #ifdef XBREAKBEFORE #ifndef XNOPROTO extern char * yRef_z00_P1 (int SymbolNo, xSymbolType *SymbolType) #else extern char * yRef_z00_P1 (SymbolNo, SymbolType) int SymbolNo; xSymbolType *SymbolType; #endif { switch (SymbolNo) { case 0: *SymbolType = xsStart; return "#SDTREF(TEXT,mall.pr,44)"; case 1: *SymbolType = xsInput; return "#SDTREF(TEXT,mall.pr,54)"; case ....... default : return ""; } } #endifAs 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" on page 2241.
/*+++++ * Function for process P1 * #SDTREF(TEXT,mall.pr,30) ++++++*/ YPAD_FUNCTION(yPAD_z00_P1) { }
----------------------------------------------------------------------- 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 S1 * <<SYSTEM serv3/BLOCK Block1/PROCESS P1>> * #SDTREF(TEXT,serv3.pr,27) ******/ #ifdef XCOVERAGE long int ySrvC_z011_S1[ySym_z011_S1+1]; #endif XCONST XSIGTYPE ySrvS_z011_S1[] = {SIGNAL_NAME(Sig1R, &ySigR_z04_Sig1R), SIGNAL_NAME(TimerS1, &ySigR_z0112_TimerS1), (XSIGTYPE)0}; XCONST xStateIdNode ySrvT_z011_S1[] = {&xStartStateIdRec, &yStaR_z0110_S1State, &yStaR_z0111_S1State2}; static xSrvNode ySrvA_z011_S1 = (xSrvNode)0; XCONST struct xSrvIdStruct ySrvR_z011_S1 = {xServiceEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&yPrsR_z01_P1 xIdNames("S1") XCOMMON_EXTRAS, ySrvT_z011_S1, ySrvS_z011_S1 xOptChan(ySrvO_z011_S1), (xptrint)sizeof(yVDef_z011_S1) xBreakB(yRef_z011_S1) xBreakB(ySym_z011_S1) xBreakB(2) xCoverage(ySrvC_z011_S1) xCoverage(0), &ySrvA_z011_S1, yPAD_z011_S1, (xSrvIdNode)0, (xPrdIdNode *)0 XSRV_EXTRAS}; #ifndef XOPTCHAN XCONST_NOPART xIdNode ySrvO_z011_S1[] = {(xIdNode)&yChaR_z013_P1sr1, (xIdNode)0}; #endifFirst 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 Proc2 * <<SYSTEM mall/BLOCK B1/PROCESS P2>> * #SDTREF(TEXT,mall.pr,89) ******/ #ifdef XCOVERAGE long int yPrdC_z011_Proc2[ySym_z011_Proc2+1]; #endif static XCONST xStateIdNode yPrdT_z011_Proc2[] = {&xStartStateIdRec}; static xPrdNode yPrdA_z011_Proc2 = (xPrdNode)0; XCONST struct xPrdIdStruct yPrdR_z011_Proc2 = {xProcedureEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&yPrsR_z01_P2 xIdNames("Proc2") XCOMMON_EXTRAS, yPrdT_z011_Proc2, yPrsS_z01_P2, z011_Proc2, (xptrint)sizeof(yVDef_z011_Proc2), &yPrdA_z011_Proc2 xBreakB(yRef_z011_Proc2) xBreakB(ySym_z011_Proc2) xBreakB(0) xCoverage(yPrdC_z011_Proc2), (xPrdIdNode)0, (xPrdIdNode *)0 XPRD_EXTRAS};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.
/*+++++ * GR ref function for procedure Proc2 * #SDTREF(TEXT,mall.pr,89) ++++++*/ #ifdef XBREAKBEFORE #ifndef XNOPROTO extern char * yRef_z011_Proc2 (int SymbolNo, xSymbolType *SymbolType) #else extern char * yRef_z011_Proc2 (SymbolNo, SymbolType) int SymbolNo; xSymbolType *SymbolType; #endif { switch (SymbolNo) { case 0: *SymbolType = xsStart; return "#SDTREF(TEXT,mall.pr,91)"; case 1: *SymbolType = xsAssignmentStatement; return "#SDTREF(TEXT,mall.pr,92)"; case 2: *SymbolType = xsReturn; return "#SDTREF(TEXT,mall.pr,93)"; default : return ""; } } #endifLast 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" on page 2241.
/*+++++ * Function for procedure Proc2 * #SDTREF(TEXT,mall.pr,89) ++++++*/ #ifndef XNOPROTO YPRD_FUNCTION(z011_Proc2) { }
/***** * SIGNAL Sig1 * <<SYSTEM mall>> * #SDTREF(TEXT,mall.pr,4) ******/ #ifndef XNOSIGNALIDNODE XCONST struct xSignalIdStruct ySigR_z1_Sig1 = {xSignalEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_mall xIdNames("Sig1") XCOMMON_EXTRAS, (xptrint)sizeof(XSIGNALHEADERTYPE), 0, 0 xFreS(0) SIGCODE(Sig1) xBreakB("#SDTREF(TEXT,mall.pr,4)") XSIG_EXTRAS}; #endifIf the signal contains parameter then one VarIdStruct is generated for each signal parameter:
#ifndef XOPTSIGPARA XCONST struct xVarIdStruct ySPaR1_z3_Sig3 = {xSignalParEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySigR_z3_Sig3 xIdNames(" ") XCOMMON_EXTRAS, &xSrtR_SDL_Integer, xOffsetOf(yPDef_z3_Sig3, Param1), (xptrint)0, (xbool)0 XSPA_EXTRAS}; #endif
/***** * REMOTE PROCEDURE rpc1 * <<SYSTEM rpc1>> * #SDTREF(TEXT,rpc1.pr,8) ******/ struct xRemotePrdIdStruct yRePR_z3_rpc1 = {xRemotePrdEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_rpc1 xIdNames("rpc1") XCOMMON_EXTRAS, 0}; #ifndef XNOSIGNALIDNODE static xSignalNode ySigA_pCALL_z3_rpc1 = (xSignalNode)0; static xSignalNode ySigA_pREPLY_z3_rpc1 = (xSignalNode)0; XCONST struct xSignalIdStruct ySigR_pCALL_z3_rpc1 = {xRPCSignalEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_rpc1 xIdNames("pCALL_rpc1") XCOMMON_EXTRAS, (xptrint)sizeof(yPDef_pCALL_z3_rpc1), &ySigA_pCALL_z3_rpc1, 0 xFreS(0) SIGCODE(pCALL_rpc1) xBreakB("#SDTREF(TEXT,rpc1.pr,8)") XSIG_EXTRAS}; XCONST struct xSignalIdStruct ySigR_pREPLY_z3_rpc1 = {xRPCSignalEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_rpc1 xIdNames("pREPLY_rpc1") XCOMMON_EXTRAS, (xptrint)sizeof(yPDef_pREPLY_z3_rpc1), &ySigA_pREPLY_z3_rpc1, 0 xFreS(0) SIGCODE(pREPLY_rpc1) xBreakB("#SDTREF(TEXT,rpc1.pr,8)") XSIG_EXTRAS}; #endif #ifndef XOPTSIGPARA XCONST struct xVarIdStruct ySPaR1_pCALL_z3_rpc1 = {xSignalParEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySigR_pCALL_z3_rpc1 xIdNames(" ") XCOMMON_EXTRAS, &xSrtR_SDL_Integer, xOffsetOf(yPDef_pCALL_z3_rpc1, Param1), (xptrint)0, (xbool)0 XSPA_EXTRAS}; XCONST struct xVarIdStruct ySPaR2_pCALL_z3_rpc1 = {xSignalParEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySigR_pCALL_z3_rpc1 xIdNames(" ") XCOMMON_EXTRAS, &xSrtR_SDL_Integer, xOffsetOf(yPDef_pCALL_z3_rpc1, Param2), (xptrint)0, (xbool)0 XSPA_EXTRAS}; XCONST struct xVarIdStruct ySPaR2_pREPLY_z3_rpc1 = {xSignalParEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySigR_pREPLY_z3_rpc1 xIdNames(" ") XCOMMON_EXTRAS, &xSrtR_SDL_Integer, xOffsetOf(yPDef_pREPLY_z3_rpc1, Param2), (xptrint)0, (xbool)0 XSPA_EXTRAS}; #endif
/***** * DCL I * <<SYSTEM mall/BLOCK B1/PROCESS P1>> * #SDTREF(TEXT,mall.pr,36) ******/ #ifndef XOPTDCL XCONST struct xVarIdStruct yVarR_z006_I = {xVariableEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&yPrsR_z00_P1 xIdNames("I") XCOMMON_EXTRAS, &xSrtR_SDL_Integer, xOffsetOf(yVDef_z00_P1, z006_I), (xptrint)0, (xbool)0 XVAR_EXTRAS}; #endif
/***** * REMOTE VARIABLE remVar * <<SYSTEM mall>> * #SDTREF(TEXT,mall.pr,26) ******/ #ifndef XNOREMOTEVARIDNODE struct xRemoteVarIdStruct yReVR_z7_remVar = {xRemoteVarEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_mall xIdNames("remVar") XCOMMON_EXTRAS, (xptrint)sizeof(SDL_Integer), (xRemoteVarListNode)0}; #endifThe 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:
xInsertExportedVar(&yExpR_z004_remVar, &yReVR_z7_remVar);
/***** * STATE State3 * <<SYSTEM mall/BLOCK B1/PROCESS P1>> * #SDTREF(TEXT,mall.pr,72) ******/ static XCONST xInputAction yStaH_z002_State3[] = {xDiscard, xDiscard, xInput, xInput, xNotInSignalSet}; static XCONST int yStaI_z002_State3[] = {0, 0, 5, 6, 0}; #ifdef XCOVERAGE static long int yStaC_z002_State3[4+1]; #endif XCONST struct xStateIdStruct yStaR_z002_State3 = {xStateEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&yPrsR_z00_P1 xIdNames("State3") XCOMMON_EXTRAS, z002_State3, yStaH_z002_State3, yStaI_z002_State3, 0, 0, 0 xCoverage(yStaC_z002_State3), (xStateIdNode)0 xBreakB("#SDTREF(TEXT,mall.pr,72)") XSTA_EXTRAS};
/*---------------------------------------------------- -- Enabling condition function for state State2 -----------------------------------------------------*/ #ifndef XNOENABCONDFUNC #ifndef XNOPROTO extern xInputAction yEnab_z001_State2 (XSIGTYPE SignalId, void * VarP) #else extern xInputAction yEnab_z001_State2 (SignalId, VarP) XSIGTYPE SignalId; void * VarP; #endif { yVDef_z00_P1 * yVarP = (yVDef_z00_P1 *)VarP; if ((SignalId == SIGNAL_NAME(Sig1, &ySigR_z1_Sig1))) { /* #SDTREF(TEXT,mall.pr,65) */ if (xGT_SDL_Integer(yVarP->z006_I, SDL_INTEGER_LIT(10))) return xInput; return xSave; } return xSave; } #endif
/*----------------------------------------------------- -- Continuous signal function for state State2 -----------------------------------------------------*/ #ifndef XNOCONTSIGFUNC #ifndef XNOPROTO extern void yCont_z001_State2 (void *VarP, int *Prio, xIdNode *IdNode, int *Addr) #else extern void yCont_z001_State2 (VarP, Prio, IdNode, Addr) void * VarP; int *Prio; xIdNode *IdNode; int *Addr; #endif { yVDef_z00_P1 * yVarP = (yVDef_z00_P1 *)VarP; /* #SDTREF(TEXT,mall.pr,68) */ if (xGT_SDL_Integer(yVarP->z004_remVar, SDL_INTEGER_LIT(20))) { *Prio = 10; *IdNode = (xIdNode)&yPrsR_z00_P1; *Addr = 4; return; }; *Addr = 0; return; } #endif
/***** * CHANNEL C1 * <<PACKAGE systemlib/SYSTEM TYPE S0>> * #SDTREF(TEXT,systype1.pr,9) ******/ #ifndef XOPTCHAN static XCONST XSIGTYPE yChaS1_z1_C1[] = {SIGNAL_NAME(ok1, &ySigR_z_systemlib_04_ok1), (XSIGTYPE)0}; static XCONST XSIGTYPE yChaS2_z1_C1[] = {(XSIGTYPE)0}; XCONST_CHAN struct xChannelIdStruct yChaR_z1_C1 = {xChannelEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_systype1 xIdNames("C1") XCOMMON_EXTRAS, yChaS2_z1_C1, yChaI2_z31_G, &yChaRR_z1_C1 XCHA_EXTRAS}; XCONST_CHAN struct xChannelIdStruct yChaRR_z1_C1 = {xChannelEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_systype1 xIdNames("C1") XCOMMON_EXTRAS, yChaS1_z1_C1, (xIdNode *)&(yBloP_z0_B2[2]), &yChaR_z1_C1 XCHA_EXTRAS}; #endifThe 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 list with names:
yChaI1_Name, yChaI2_Name, yChaO1_Name, yChaO1_Name
are generated and used for such connections.
/***** * NEWTYPE struct1 (BODY section) * <<SYSTEM mall>> * #SDTREF(TEXT,mall.pr,6) ******/ #ifndef XOPTSORT XCONST struct xSortIdStruct ySrtR_z4_struct1 = {xSortEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySysR_z_mall xIdNames("struct1") XCOMMON_EXTRAS xFreF(0) xAssF(0) xEqF(yEq_z4_struct1) xRaWF(0) xRaWF(0) xTestF(0), (xptrint)sizeof(z4_struct1), xStruct, (xSortIdNode)0, (xSortIdNode)0, 0, 0 XSRT_EXTRAS}; #endif #ifndef XOPTSTRUCT /*------------STRUCT COMPONENTS-------------*/ static XCONST struct xVarIdStruct yVarR_z48_a = {xVariableEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySrtR_z4_struct1 xIdNames("a") XCOMMON_EXTRAS, &xSrtR_SDL_Integer, xOffsetOf(z4_struct1, a), (xptrint)0, (xbool)0 XVAR_EXTRAS}; static XCONST struct xVarIdStruct yVarR_z49_b = {xVariableEC xSymbTLink((xIdNode)0, (xIdNode)0), (xIdNode)&ySrtR_z4_struct1 xIdNames("b") XCOMMON_EXTRAS, &xSrtR_SDL_Integer, xOffsetOf(z4_struct1, b), (xptrint)0, (xbool)0 XVAR_EXTRAS}; #endif /*------------------DEFAULT-----------------*/ #ifndef XNOPROTO extern void yDef_z4_struct1( z4_struct1 *yVar ) #else extern void yDef_z4_struct1( yVar ) z4_struct1 *yVar; #endif { xDef_SDL_Integer(&((*yVar).a)); xDef_SDL_Integer(&((*yVar).b)); } /*------------------EQUAL-------------------*/ #ifndef XNOPROTO extern SDL_Boolean yEq_z4_struct1( z4_struct1 yExpr1, z4_struct1 yExpr2 ) #else extern SDL_Boolean yEq_z4_struct1( yExpr1, yExpr2 ) z4_struct1 yExpr1, yExpr2; #endif { if ( yNEqF_SDL_Integer(yExpr1.a, yExpr2.a) ) return SDL_False; if ( yNEqF_SDL_Integer(yExpr1.b, yExpr2.b) ) return SDL_False; return SDL_True; } /*-------------------MAKE-------------------*/ #ifndef XNOPROTO extern z4_struct1 yMake_z4_struct1( SDL_Integer ya, SDL_Integer yb ) #else extern z4_struct1 yMake_z4_struct1( ya, yb ) SDL_Integer ya; SDL_Integer yb; #endif { z4_struct1 yVar; memset((void *)(&yVar), 0, sizeof(z4_struct1)); yAssF_SDL_Integer(yVar.a, ya, XASSMAKE); yAssF_SDL_Integer(yVar.b, yb, XASSMAKE); return yVar; } /* #SDTREF(TEXT,mall.pr,7) */ COMMENT((This is the #body section))
#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 }
#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
Example 139 : #ifndef XNOPROTO extern ResultTypeName OperatorName( ParameterType1 yParam1, ParameterType2 yParam2 ) #else extern ResultTypeName OperatorName (yParam1, yParam2) ParameterType1 yParam1; ParameterType2 yParam2; #endif { ResultTypeName Result; xPrintString( "Operator xx in sort xx is called\n"); xPrintOpParameter("Parameter 1: %s\n", &yParam1, ySrtN_ParameterType1); xPrintOpParameter("Parameter 2: %s\n", &yParam2, ySrtN_ParameterType2); if (! xReadOperator((void *)&Result, ySrtN_ResultTypeName)) yDef_ResultTypeName(&Result); return Result; }
extern void yInit XPP((void)) { int Temp; YINIT_TEMP_VARS BEGIN_YINIT #ifdef XMONITOR xTranslatorVersion = "Program generated by SDT C Code Generator, version 2.0"; #endif xSymbolTableRoot = &ySymbRootVar; xInsertIdNode((xIdNode)&ySymbRootVar); XINIT_SYSTEMIDNODE(ySysR_z_mall) xInsertIdNode((xIdNode)&ySysR_z_mall); xEnvId = &yEnvR_env; xInsertIdNode((xIdNode)&yEnvR_env); XCREATE_ENV_PROCESS #ifndef XNOSTARTUPIDNODE xInsertIdNode((xIdNode)&ySigR_Env); #endif #ifndef XOPTSORT yInit_Predefined(); #endif code to build the symbol table and create static process instances code to initialize the synonyms implemented as variables }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.
xInsertIdNode((xIdNode)&yBloR_B1);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.
xInsertExportedVar(&yExpR_remVar, &yReVR_remVar);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.
INIT_PROCESS_TYPE(P1, yPrsN_z00_P1, "z00_P1", SDL_INTEGER_LIT(1), SDL_INTEGER_LIT(1), yVDef_z00_P1, xDefaultPrioProcess, yPAD_z00_P1) #ifdef SDL_STATIC_CREATE SDL_STATIC_CREATE(P1, z00_P1, yPrsN_z00_P1, "P1", ySigN_z00_P1, yPDef_z00_P1, yVDef_z00_P1, xDefaultPrioProcess, yPAD_z00_P1, 0) #endifThe macro SDL_STATIC_CREATE above is expanded to:
SDL_Create( xGetSignal(ySigN_z00_P1, SDL_NULL, SDL_NULL), yPrsN_z00_P1, 0);
Example 140 : Initialization of synonyms: SynonymName1 = synonym expr 1; yAss_TypeName(&SynonymName2, synonym expr 2, XASS); #ifndef ExtSynonymName xReadSynonym(&ExtSynonymName, xSrtN_TypeName, "ExtSynonymName"); #endifSynonymName1 and SynonymName2 are ordinary synonyms and ExtSynonymName is an external synonym.
#ifndef XNOMAIN #ifndef XMAIN_NAME #define XMAIN_NAME main #endif #ifdef XCONNECTPM #ifndef XNOPROTO int XMAIN_NAME( int argc, char * argv[] ) #else int XMAIN_NAME( argc, argv ) int argc; char * argv[]; #endif #else int XMAIN_NAME XPP(( void )) #endif { #ifdef XCONNECTPM xMainInit(yInit, argc, argv); #else xMainInit(yInit); #endif xMainLoop(); return 0; } #endif
The prototypes for the process and procedure functions contain some macros. These are expanded in the examples below.
Example 141 /*---------- Process ProcessName ----------*/ #ifndef XNOPROTO void yPAD_ProcessName( xPrsNode P ) #else void yPAD_ProcessName( P ) xPrsNode P; #endif { local variable section section handling procedure calls switch statement translation of symbols } Example 142 /*-------- Procedure ProcedureName ---------*/ #ifndef XNOPROTO xbool ProcedureName( xPrsNode P ) #else xbool ProcedureName( P ) xPrsNode P; #endif { local variable section switch statement translation of symbols }
YPAD_YSVARP YPAD_YVARP(yVDef_z00_P1) YPAD_TEMP_VARS YPRSNAME_VAR("P1")which after macro expansion becomes:
void *ySVarP = VarP->Signal; register VDEF_TYPE * yVarP = (VDEF_TYPE *)VarP; xPrdNode yTempPrd; \ xSignalNode yOutputSignal;If it is a procedure that is generated then the following is generated:
YPAD_YSVARP YPRD_YVARP(yVDef_z01_P2) yVDef_z011_Proc2 * yPrdVarP; YPRD_TEMP_VARS YPRDNAME_VAR("Proc2")This is expanded to almost the same code as for the process:
void *ySVarP = VarP->Signal; register VDEF_TYPE * yVarP = (VDEF_TYPE *)VarP; yVDef_z011_Proc2 * yPrdVarP; xPrdNode yTempPrd; \ xSignalNode yOutputSignal;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:
SDL_Integer yDcn_SDL_Integer; SDL_Boolean yDcn_SDL_Boolean; SDL_Real yDcn_SDL_Real; SDL_Character yDcn_SDL_Character; SDL_PId yDcn_SDL_PId;If the process or procedure contains any outputs with a via list then:
xIdNode yViaList[length of longest via plus one];
#ifndef XNOPROCATSTARTUP while (yVarP->ActivePrd != (xPrdNode)0 ) { CALL_PROCEDURE_STARTUP #ifdef XBREAKBEFORE if (yVarP->ActivePrd != (xPrdNode)0 ) { XBETWEEN_SYMBOLS(yVarP->ActivePrd-> RestartAddress, 1361) } else { XBETWEEN_SYMBOLS(yVarP->RestartAddress, 1363) } #endif } #endifwhere CALL_PROCEDURE_STARTUP is defined as:
if ( (*yVarP->ActivePrd->RestartPRD)(VarP) ) return;
If code is generated for a process, the switch statement looks as follows:
switch (yVarP->RestartAddress) {If code is generated for a procedure, the switch statement looks as follows:
switch (yVarP->ActivePrd->RestartAddress) {If the process that is translated contains services, there will be no switch statement. Instead the following code is generated in the PAD function:
CALL_SERVICE /*----- * Initialization (no START symbol) ------*/ BEGIN_START_TRANSITION(yPDef_z00_P1) ... initialization of process variables ... START_SERVICES
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):
XBETWEEN_SYMBOLS(SymbolNumber, LineNo) /*----- * TYPE OF SYMBOL * #SDTREF(TEXT,mall.pr,97) ------*/ #ifdef XCASELABELS case SymbolNumber: #endifwhere 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
#ifdef XCASELABELis replaced by
#ifdef XCASEAFTERPRDLABELSThe 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.
/*----- * START * #SDTREF(TEXT,mall.pr,96) ------*/ case 0: BEGIN_START_TRANSITION(yPDef_z01_P2) yAssF_SDL_Integer(yVarP->z010_I, ((yPDef_z01_P2 *)ySVarP)->Param1, XASS); XAT_FIRST_SYMBOL(0) xDef_SDL_Integer(&yVarP->z012_K);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.
/*----- * INPUT Sig2 * #SDTREF(TEXT,mall.pr,62) ------*/ case 2: XDEBUG_LABEL(State2_Sig2) XAT_FIRST_SYMBOL(2) XOS_TRACE_INPUT("Sig2") yAssF_SDL_Integer(yVarP->z006_I, ((yPDef_z2_Sig2 *)ySVarP)->Param1, XASS);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:
/*----- * CONTINUOUS SIGNAL * #SDTREF(TEXT,mall.pr,68) ------*/ case 4: XAT_FIRST_SYMBOL(4) XBETWEEN_SYMBOLS(23, 992)
/*----- * ASSIGNMENT I := ... * #SDTREF(TEXT,mall.pr,47) ------*/ #ifdef XCASELABELS case 10: #endif yAssF_SDL_Integer(yVarP->z006_I, SDL_INTEGER_LIT(10), XASS); #ifdef XTRACE xTraceAssign("I := ", &(yVarP->z006_I), xSrtN_SDL_Integer); #endifThe 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" on page 2257.
Example 143An OUTPUT of, for example, a signal called Sig2 with one parameter will be translated to:
/*----- * OUTPUT Sig2 * #SDTREF(TEXT,mall.pr,55) ------*/ #ifdef XCASELABELS case 15: #endif ALLOC_SIGNAL_PAR(Sig2, ySigN_z2_Sig2, ToExpr, yPDef_z2_Sig2) SIGNAL_ALLOC_ERROR yAssF_SDL_Integer(((yPDef_z2_Sig2*) OUTSIGNAL_DATA_PTR) ->Param1, yVarP->z006_I, XASS); SDL_2OUTPUT(xDefaultPrioSignal, (xIdNode *)0, Sig2, ySigN_z2_Sig2, ToExpr, sizeof(yPDef_z2_Sig2), "Sig2") SIGNAL_ALLOC_ERROR_ENDThe 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.
Example 144Example of via list containing two channels:
yViaList[0] = yChaN_ChannelName1; yViaList[1] = yChaN_ChannelName2; yViaList[2] = (xIdNode)0;
/*----- * CREATE P2 * #SDTREF(TEXT,mall.pr,49) ------*/ #ifdef XCASELABELS case 12: #endif ALLOC_STARTUP_PAR(P2, ySigN_z01_P2, yPDef_z01_P2) STARTUP_ALLOC_ERROR yAssF_SDL_Integer(((yPDef_z01_P2 *) STARTUP_DATA_PTR)->Param1, yVarP->z006_I, XASS); SDL_CREATE(P2, z01_P2, yPrsN_z01_P2, "P2", ySigN_z01_P2, yPDef_z01_P2, yVDef_z01_P2, xDefaultPrioProcess, yPAD_z01_P2) STARTUP_ALLOC_ERROR_ENDThe macro ALLOC_STARTUP_PAR will be expanded t the call of the function xGetSignal, will SDL_CREATE will be expanded to a call of the function SDL_Create.
There are a number of versions of the ALLOC macro:
#ifdef XTRACE xDcn_SDL_Boolean = QuestionExpression; xTraceDecision(&(xDcn_SDL_Boolean), xSrtN_SDL_Boolean); if (xDcn_SDL_Boolean) { #else if (QuestionExpression) { #endif .... } else { .... }
#ifdef XTRACE yDcn_TypeName = QuestionExpression; xTraceDecision(&(yDcn_TypeName), ySrtN_TypeName); if (Decision condition using yDcn_TypeName) { #else if (Decision condition using QuestionExpression) { #endif .... } else { .... }
yDcn_TypeName = QuestionExpression; #ifdef XTRACE xTraceDecision(&(yDcn_TypeName), ySrtN_TypeName); #endif if (Decision condition 1 using yDcn_TypeName) { .... } else if (Decision condition 2 using yDcn_TypeName) { .... } else { .... }
#ifdef XEDECISION else { xErrorDecision(xWriteSort(&yDcn_TypeName, ySrtN_TypeName)); return; } #endifThe transitions within a decision are included directly in the if statement.
decision any; () : task i := 1; () : task i := 2; () : task i := 3; enddecision;is generated as:
/*----- * DECISION * #SDTREF(TEXT,dec.pr,25) ------*/ #ifdef XCASELABELS case 5: #endif BEGIN_ANY_DECISION(3) DEF_ANY_PATH(1, 6) DEF_ANY_PATH(2, 7) DEF_ANY_PATH(3, 8) END_DEFS_ANY_PATH(3) BEGIN_FIRST_ANY_PATH(1) XBETWEEN_SYMBOLS(6, 375) END_ANY_PATH BEGIN_ANY_PATH(2) XBETWEEN_SYMBOLS(7, 390) END_ANY_PATH BEGIN_ANY_PATH(3) XBETWEEN_SYMBOLS(8, 405) END_ANY_PATH END_ANY_DECISIONXBETWEEN_SYMBOL macros are used to represent the statements in that decision path. An informal decision according to the following example:
decision 'Question1'; ('answer1') : task i := 1; ('answer2') : task i := 2; ('answer3') : task i := 3; enddecision;is generated as:
/*----- * DECISION * #SDTREF(TEXT,dec.pr,45) ------*/ #ifdef XCASELABELS case 19: #endif BEGIN_INFORMAL_DECISION(3, SDL_CHARSTRING_LIT( "LQuestion1", "Question1")) DEF_INFORMAL_PATH(1, SDL_CHARSTRING_LIT( "Lanswer1", "answer1"), 20) DEF_INFORMAL_PATH(2, SDL_CHARSTRING_LIT( "Lanswer2", "answer2"), 21) DEF_INFORMAL_PATH(3, SDL_CHARSTRING_LIT( "Lanswer3", "answer3"), 22) END_DEFS_INFORMAL_PATH(3) BEGIN_FIRST_INFORMAL_PATH(1) XBETWEEN_SYMBOLS(20, 578) END_INFORMAL_PATH BEGIN_INFORMAL_PATH(2) XBETWEEN_SYMBOLS(21, 593) END_INFORMAL_PATH BEGIN_INFORMAL_PATH(3) XBETWEEN_SYMBOLS(22, 608) END_INFORMAL_PATH END_INFORMAL_DECISIONXBETWEEN_SYMBOL macros are used to represent the statements in that decision path.
A set operation on a timer without parameters is generated according to the following example:
/*----- * SET t1 * #SDTREF(TEXT,mall.pr,63) ------*/ #ifdef XCASELABELS case 19: #endif SDL_SET_DUR(xPlus_SDL_Time(SDL_NOW, SDL_DURATION_LIT(5.0, 5, 0)), SDL_DURATION_LIT(5.0, 5, 0), t1, ySigN_z003_t1, yTim_t1, "t1")This macro is expanded to a call of the function SDL_Set. There are three version of the SDL_SET macro:
/*----- * SET timer3 * #SDTREF(TEXT,timer2.pr,37) ------*/ #ifdef XCASELABELS case 12: #endif ALLOC_TIMER_SIGNAL_PAR(timer3, ySigN_z004_timer3, yPDef_z004_timer3) TIMER_SIGNAL_ALLOC_ERROR yAssF_SDL_Integer(((yPDef_z004_timer3 *) TIMER_DATA_PTR)->Param1, SDL_INTEGER_LIT(1), XASS); SDL_SET_DUR_WITH_PARA(xPlus_SDL_Time(SDL_NOW, SDL_DURATION_LIT(5.0, 5, 0)), SDL_DURATION_LIT(5.0, 5, 0), timer3, ySigN_z004_timer3, yPDef_z004_timer3, yEqT_z004_timer3, yTim_timer3, "timer3") TIMER_SIGNAL_ALLOC_ERROR_ENDThe 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:
/*----- * RESET t1 * #SDTREF(TEXT,mall.pr,74) ------*/ #ifdef XCASELABELS case 24: #endif SDL_RESET(t1, ySigN_z003_t1, yTim_t1, "t1")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:
SDL_RESET_WITH_PARA(yEqT_z004_timer3, yTim_timer3, "timer3")This macro is expanded to:
SDL_Reset(&yOutputSignal);
/*----- * EXPORT remVar * #SDTREF(TEXT,mall.pr,46) ------*/ #ifdef XCASELABELS case 9: #endif #ifdef XTRACE xTraceExport("remVar"); #endif yAssF_SDL_Integer(yVarP->yExp_z004_remVar, yVarP->z004_remVar, XASS);
/*----- * CALL Proc2 * #SDTREF(TEXT,mall.pr,99) ------*/ #ifdef XCASELABELS case 4: #endif ALLOC_PROCEDURE(z011_Proc2, yPrdN_z011_Proc2, sizeof(yVDef_z011_Proc2)) PROCEDURE_ALLOC_ERROR yAssF_SDL_Integer(((yVDef_z011_Proc2 *) PROC_DATA_PTR)->z0110_P1, yVarP->z010_I, XASS); ((yVDef_z011_Proc2 *)PROC_DATA_PTR)->z0111_P2 = &(yVarP->z012_K); CALL_PROCEDURE(z011_Proc2, yPrdN_z011_Proc2, 0, 1) PROCEDURE_ALLOC_ERROR_ENDThe 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:
xAddPrdCall(yTempPrd, VarP, levels, restartaddr); if ( yProcedureName (VarP) ) return;where levels is an integer representing the number of declaration levels between the caller and the called procedure. restartadd 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.
Example 145 TASK V1 := (call P(a)) + (call Q(b,1));is translated as if it was transformed to:
CALL P(a, Temp1); CALL Q(b,1,Temp2) TASK V1 := Temp1 + Temp2;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.
CALL rpc1(1, intVar) TO pidVar;is transformed to:
OUTPUT pCALL_rpc1(i, intVar) TO pidVar; NEXTSTATE tempState; STATE tempState; INPUT pREPLY_rpc1(intVar);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:
STATE *; INPUT pCALL_rpc1(variables for in + in/out parameters); CALL rpc1(as in inupt above); OUTPUT pREPLY_rpc1(in/out parameters) TO SENDER; NEXTSTATE -;This is implemented as:
SDL_NEXTSTATE SDL_DASH_NEXTSTATE SDL_NEXTSTATE_PRD (used in procedures) SDL_DASH_NEXTSTATE_PRD (used in procedures) SDL_DASH_NEXTSTATE_SRV (used in service)This macros are expanded to calls of the function SDL_Nextstate followed by a return statement.
goto L_LabelName;
xReleasePrd(VarP); return (xbool)0;
yTstA_TypeName(Expression)where yTstA_TypeName is either a consistency check function or a macro that replaces the macro call by only the expression itself.
yVarP->VariableName1 yPrdVarP->VariableName2 ((yVDP_ProcedureName)VarP->ActivePrd ->StaticFather)->VariableName3 (*(yPrdVarP->VariableName4))The examples are:
(*(SDL_Integer *)SDL_VIEW(SDL_PARENT, (xbool)1, "revVar", (xViewListRec *) &(((xBlockIdNode)XNAMENODE-> Parent)->ViewList[yView_z_predefined_6_revVar]), sizeof(SDL_Integer)))
(*(SDL_Integer *)XGETEXPORTADDR( &yReVR_z7_remVar, SDL_NULL, (xbool)0))
P->Self P->Parent P->Offspring P->Signal->Sender
SDL_ACTIVE(TimerName, ySigN_TimerName, yTim_TimerName)which is expanded to:
SDL_Active(ySigN_TimerName, VarP)A conditional expression in SDL is translated to a conditional expression in C.
typedef struct { xPrsNode PrsP; } xLocalPIdRec; typedef struct { xPrsNode Pre; xPrsNode Suc; int RestartAddress; xPrdNode ActivePrd; YPAD_RESULT_TYPE (*RestartPAD) (); #ifndef XNOUSEOFSERVICE xSrvNode ActiveSrv; xSrvNode SrvList; #endif xPrsNode NextPrs; SDL_PId Self; xPrsIdNode NameNode; int State; xSignalNode Signal; xInputPortRec InputPort; SDL_PId Parent; SDL_PId Offspring; int BlockInstNumber; xSignalIdNode pREPLY_Waited_For; xSignalNode pREPLY_Signal; /* variables and formal parameters in the process */ } yVDef_ProcessName;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:
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 dependant on the declarations in the process. The translation rules for SDL types, both predefined and user defined, can be found in chapter 34, The C Code Generator.
For each process instance set in the system the following number of structs of a different kind will be allocated:
typedef struct xSrvStruct { xSrvNode NextSrv; xPrsNode ContainerPrs; int RestartAddress; xPrdNode ActivePrd; void (*RestartPAD) XPP((xPrsNode VarP)); xSrvIdNode NameNode; int State; XSIGTYPE pREPLY_Waited_For; xSignalNode pREPLY_Signal; } xSrvRec;This means that:
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).
typedef struct { xSignalNode Pre; xSignalNode Suc; int Prio; SDL_PId Receiver; SDL_PId Sender; xIdNode NameNode; /* Signal parameters */ } yPDef_SignalName;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:
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 chapter 34, The C Code Generator.
For each signal type in the system the following number of data areas will be allocated:
------------------------------------------------------------------ Note: There will be one common avail list for all signals without parame ters. ------------------------------------------------------------------
typedef struct { xPrdIdNode NameNode; xPrdNode StaticFather; xPrdNode DynamicFather; int RestartAddress; YPRD_RESULT_TYPE (*RestartPRD) (); xSignalNode pREPLY_Signal; int State; /* Formal parameters and variables */ } 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:
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 chapter 34, The C Code Generator.
For each type of procedure in the system the following number of data areas will be allocated:
There is one implementation of the SDL sort Charstring, which is both flexible in charstring length and can reuse all memory.
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" on page 2267.
Charstrings are also handled correctly if charstrings 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 charstrings there will also be a Free function that is utilized to release all dynamic memory in the structured variable. These Free functions are not used in the standard memory handling procedure, but may be utilized to implement alternatives.
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.
The basic tools are the sctos.c functions:
xGetPId xReleasePId xGetSignal xReleaseSignal xGetPrd xReleasePrd xAllocCharstring xFreeCharstringand the compilation switch XFREEVARS.
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 xAllocCharstring is call each time a new data area for a charstring is needed.
The xRelease and xFree functions listed will be called when a process, signal, procedure, or charstring 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 charstring values among the variables and parameters in the processes, signals and procedures.
The switches that are used can be grouped into five groups.
The following switches define the library version:
-------------------------------------------------------- Switch Corresponds to Library -------------------------------------------------------- SCTDEBCOM Simulation SCTDEBCLCOM RealTimeSimulation SCTAPPLCLENV Application SCTDEBCLENVCOM ApplicationDebugThe 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.
(Simulation with environment) SCTPERFSIM PerformanceSimulation
(Library with simulated time, no environ ment functions, no monitor.) --------------------------------------------------------
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.
These functions have the following prototypes:
extern void xSignalLog (xSignalNode Signal, int NrOfReceivers, xIdNode * Path, int PathLength); extern void xProcessLog (xPrsNode P);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.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.
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 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
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 SetTrace 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 146 :Suitable statements to set trace values in C code:
xSystemId->Trace_Default = value; /* System trace */ xPrsN_ProcessName->Trace_Default = value; /* Process type trace */ PId_Var.LocalPId->PrsP->NameNode->Trace_Default = value /* Process type trace */ PId_Var.LocalPId->PrsP->Trace_Default = value; /* Process instance trace */PId_Var is assumed to be a variable of type PId.
---------------------------------------------------------------------- Note: Note that the variable xPrsN_ProcessName is declared, and there fore only available, in the file containing the block where the pro cess is defined (and in files representing processes contained in the block). ----------------------------------------------------------------------
This feature is used together with the monitor to implement graphical trace and commands like ShowPreviousSymbol and ShowPreviousSymbol. 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.
extern void xMainInit( void (*Init_System) (void) #ifdef XCONNECTPM ,int argc, char *argv[] #endif ); #ifdef XNOMAIN extern void SDL_Execute (void); extern int SDL_Transition_Prio (void); extern void SDL_OutputTimer (void); extern int SDL_Timer_Prio (void); extern SDL_Time SDL_Timer_Time (void); #endifThe 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:
#ifdef XCONNECTPM xMainInit(yInit, argc, argv); #else xMainInit(yInit); #endifThe 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 Now is 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 (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.
extern void xCheckMonitors (void);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 147 while (1) { #ifdef XMONITOR xCheckMonitors(); #endif if ( SDL_Timer_Prio() >= 0 ) SDL_OutputTimer(); else if ( SDL_Transition_Prio() >= 0 ) SDL_Execute(); }
A signal priority is specified with a priority directive (see "Assigning Priorities Directive #PRIO" on page 2042 in chapter 34, The C Code Generator, that is by a comment with the following outline:
/*#PRIO 5 */.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 C 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 148 SIGNAL S1 /*#PRIO 3 */, S2 (Integer) /*#PRIO 5 */;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 Recommen dation Z.100, and that sorting the signals in the input port of a pro cess 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. -----------------------------------------------------------------------
xDefaultPrioProcess xDefaultPrioSignal xDefaultPrioTimerSignal xDefaultPrioContSignal xDefaultPrioCreate
----------------------- XOPTSIGPARA XOPTDCL XOPTFPAR XOPTSTRUCT XOPTLIT XOPTSORT -----------------------For more information, see these switches below. The XOPT switches should not be used together with the monitor.
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.
-------------------------------------------------------------- Caution! An attempt to perform an import operation when
XNOUSEOFEXPORT is defined will result in a compilation error, as the function xGetExportAddr is not defined. --------------------------------------------------------------
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:
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.
-------------------------------------------------------------- Caution! If the XOPTCHAN switch is defined and still OUTPUT without TO clause are used (which the C Code Generator cannot optimize), there will be a C compilation error saying that the name xNotDefPId is not defined. --------------------------------------------------------------
This problem is solved if the C 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 chapter 35, 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.
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. We have solved this by introducing the macro XTRACHANNELSTOENV. The size of the data area will be the number of channels going to the environment in the system plus the value of XTRACHANNELSTOENV (which by default is 50).
A large system containing more that 50 paths that will be redirected to the environment requires XTRACHANNELSTOENV to be redefined to a larger value.
Example 149 state State1; input Sig1; state State2; input *; state *; input Sig2;In the generated code for these input statements the following macros will be found
XDEBUG_LABEL(State1_Sig1) XDEBUG_LABEL(State2_ASTERISK) XDEBUG_LABEL(ASTERISK_Sig2)A suitable macro definition to introduce label would be:
#define XDEBUG_LABEL(L) L: ;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.
The following macro definitions can be inserted:
#define XCONST const #define XCONST_NOPART const #define XCONST_COMP constThis will introduce const in the declaration of most of the IdStructs. It is then up to the compiler to handle const. With partitioning is used, XCONST_NOPART should not be defined.
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 memory that will be save in RAM, as probably 90% of the data area for IdStructs can be made const.
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 SCTDEBCLCOM XPRSPRIO XCLOCK XPARTITION XPRSPRIO XEALL XPARTITION XMONITOR XEALL XTRACE XMONITOR XCTRACE XTRACE XMSCE XCTRACE XCOVERAGE XMSCE XGRTRACE XCOVERAGE XPMCOMM XGRTRACE XSDLENVUI XPMCOMM XITEXCOMM XSDLENVUI XSIMULATORUI XSIMULATORUI SCTAPPLCLENV SCTDEBCLENVCOM XCALENDERCLOCK XCALENDERCLOCK XENV XPRSPRIO XPRSPRIO XPARTITION XOPT XENV XPRSOPT 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.
---------------------------------------------------------------------- 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:
Figure 563 : Directory Structure. ----- (fig) -----sctdir, as well as sdtdir, is an environment variable that is used by SDT to find the current directory.
In the sdtdir directory three important files are found:
In the INCLUDE directory, a there are two important groups of files:
The makeoptions file describes the properties of the library, such as the compiler used, compiler options, linker options, and so on, while sctworld.o is a pre-linked library file.
To guarantee the consistency of, for example, compilation flags between the SDL system and the kernel, the makeoptions 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.
The path to the library can either be the complete path, if the path starts with a `/', or a path relative to the environment variable sdtdir, if the path does not start with a `/'.
Example 150 : Simulation SCTDEBCOM RealTimeSimulation SCTDEBCLCOM Application SCTAPPLCLENV ApplicationDebug /util/sct/SCTDEBCLENVCOMThe 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.
---------------------------------------------------------------- Caution! Do not generate and test libraries in the $sdtrelease directory structure. Create an appropriate copy. ----------------------------------------------------------------
---------------------------------------------------------------- Note: The environment variables sdtdir and sctdir need not refer to di rectories in $sdtrelease. Any directory containing the relevant files may be used. ----------------------------------------------------------------
# makeoptionfile to build #SDT R-T library 'Application'. # Remember to set the environment variables #sdtdir and sctdir to the appropriate values. sctLIBNAME = Application sctIFDEF = -DSCTAPPLCLENV -DSUN4_1_1CC sctEXTENSION = _apa.sct sctOEXTENSION = _apa.o sctuseinclude = $(sctdir)/../INCLUDE sctlinkdir = $(sctdir) sctLINKKERNEL = $(sctlinkdir)/sctworld.o sctCC = cc sctCPPFLAGS = -I$(sctuseinclude) sctCCFLAGS = -c sctLD = cc sctLDFLAGS = sctLIBFLAGS = -xThe information to the right of the equal signs should be seen as an example. These environment variables set in the makeoptions file should specify:
The make file is usually generated and executed by the SDT Organizer. Running the Analyzer stand-alone, the make file is however generated and executed by the C Code Generator.
Example 151 :Below a make file generated for the SDT system Example is shown. This is generated by the C Code Generator. The make files generated by the SDT Organizer is similar but not exactly equal.
# makefile for System: Example include $(sctdir)/makeoptions default: Example$(sctEXTENSION) Example$(sctEXTENSION): Example$(sctOEXTENSION) $(sctLD) $(sctLDFLAGS) \ Example$(sctOEXTENSION) \ $(sctLINKKERNEL) \ -o Example$(sctEXTENSION) Example$(sctOEXTENSION): Example.c $(sctCC) $(sctCPPFLAGS) $(sctCCFLAGS) \ Example.c $(sctIFDEF) \ -o Example$(sctOEXTENSION)
There are two parts of the source code that might need changes:
------------------------------------------------------------------- Caution! When compiling under SUN's Solaris 2.1 (or later versions), we recommend not to use the compiler /usr/ucb/cc Our experience is that the unbundled compiler is subject to generat ing compilation errors. Instead, we recommend to run the unbundled compilerThe following switches defining the compiler are currently handled in scttypes.h:
/opt/SUNWSpro/bin/cc -------------------------------------------------------------------
------------------------------------------------------- SUN4_1_1CC The Sun C compiler for Sun OS 4.1.3 SUN4_1_1GCC The Gnu C compiler for Sun OS 4.1.3 SUN_CXX The Sun C++ compiler SUN4_ANSICC The Sun ANSI C compiler for Sun OS 4.x SUN5_ANSICC The Sun ANSI C compiler for Sun OS 5.x SUN5_CC The Sun C compiler for Sun OS 5.x Linux The Gnu C compiler for Linux HPUXANSICC The HP ANSI C compiler HPUXANSI_RISCCC HPUXCC The HP C compiler HPUX_RISCCC ULTRIXCC The Digital C compiler for ULTRIX AIXV3CC IBM RS/6000 C compiler for AIX 3.2 OASYS_CXX Green Hill/Oasys cross compilerThese 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.
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 -------------------------------------------------------
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:
Example 152 #ifdef COMPILER_NAME #include <string.h> #include <stdlib.h> #include <stdarg.h> #ifdef XREADANDWRITEF #include <stdio.h> #endif #ifdef XCLOCK #include <time.h> #endif #if defined(XMONITOR) && !defined(XNOOSSIGNALS) #include <signal.h> #endif #if defined(XPMCOMM) && !defined(XENV) /* handle getpid, SUN/UNIX: */ extern int getpid XPP((void)); #endif #if defined(XMONITOR) && !defined(XNOSELECT) /* handle xCheckForKeyboardInput, SUN/UNIX: */ #include <sys/types.h> #include <sys/time.h> extern int select XPP((int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)); #endif #if defined(XCLOCK) && !defined(XENV) /* handle xSleepUntil, SUN/UNIX: */ extern void usleep XPP((unsigned useconds)); #endif #endifBefore the compiler definition sections the following macros are defined:
#define XPP(x) x #define XCAT(P1,P2) P1##P2 #define GETINTRAND random() #define GETINTRAND_MAX 2147483647 #define xptrint unsigned #define xint32 long intwhich 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:
#undef XPP #define XPP(x) () #define XNOPROTOwhich 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:
#undef XCAT #define XCAT(P1,P2) P1/**/P2or
#undef XCAT #define XCAT(P1,P2) XCAT1(P1)P2 #define XCAT1(P) PNext 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 C Code Generator system in either the library or in generated code:
string.h memcpy memset strlen strcmp strcpy strncpy strcat strncat only if XREADANDWRITEF stdlib.h calloc free exit getenv only if XMONITOR stdio.h only if XREADANDWRITEF FILE EOF fgetc ungetc printf sprintf fprintf sscanf fscanf fopen fclose time.h only if XCLOCK time_t time signal.h only if XMONITOR and not XNOOSSIGNALS signalIf the compiler does not handle C signals then the statement
should be replaced by:
#define XNOOSSIGNALSThe last three parts in this section handle the utility functions needed by sctos.c to implement some of the operating system dependant functions. Please see below where sctos.c is discussed in detail.
#ifdef XCLOCK extern SDL_Time SDL_Clock (void); #endif #if defined(XCLOCK) && !defined(XENV) extern void xSleepUntil (SDL_Time WakeUpTime); #endif extern void * xAlloc (xptrint Size); extern void xFree (void **P); extern void xHalt (void); #if defined(XPMCOMM) && !defined(XENV) extern int xGlobalNodeNumber (void); #endif #if defined(XMONITOR) && !defined(XNOSELECT) extern xbool xCheckForKeyboardInput ( long xKeyboardTimeout); #endif extern SDL_PId xGetPId ( xPrsIdNode PType, SDL_PId Parent ); extern void xReleasePId (SDL_PId *P); extern xSignalNode xGetSignal ( XSIGTYPE SType, SDL_PId Receiver, SDL_PId Sender ); extern void xReleaseSignal (xSignalNode *S); extern xPrdNode xGetPrd (xPrdIdNode PrdId); extern void xReleasePrd (xPrsNode VarP); extern SDL_Charstring xAlloc_SDL_Charstring ( xptrint Size ); extern void xFree_SDL_Charstring (void **C);
typedef struct { xint32 s; /* for seconds */ xint32 ns; /* for nanoseconds */ } SDL_Time;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 ex ample 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. ------------------------------------------------------------------
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.
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-dependant.
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.
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 UNIX function getpid, and uses thus the UNIX process number as global node number.
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.
xGetPId xReleasePId xGetSignal xReleaseSignal xGetPrd xReleasePrd xAlloc_SDL_Charstring xFree_SDL_Charstringare called to allocate and release memory used for processes, signals, procedures and charstrings. 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" on page 2267.