Before invoking a TCM, you must create an instance of the struct that contains it. TCMs can be called or started. Table 8-2 shows the rules for calling or starting TCMs and methods (regular methods).
Calling Procedure | Can Call | Can Start |
---|---|---|
Method | Another Method | A TCM |
TCM | Another TCM Another Method | Another TCM |
You can execute a TCM by calling it from another TCM. The TCM that is called may or may not return a value. A call of a TCM that does not return a value is syntactically an action.
A called TCM begins execution either when its sampling event is emitted or immediately, if the sampling event has already been emitted for the current simulator callback. The calling TCM is blocked until the called TCM returns before continuing execution. For this reason, a called TCM is considered a subthread of the calling TCM and shares the same thread handle (thread ID) with the calling TCM.
Figure 8-1 shows the sequence for executing a called TCM (TCM2). The calling TCM (TCM1) must wait for TCM2 to complete before continuing execution. Therefore, TCM1 blocks until TCM2 completes execution.
Example 8-2 shows the calling of a TCM.
Example shows how to call a TCM from another TCM. In this example init_dut() TCM is called from the my_tcm() TCM. <' struct meth { event pclk is rise('~/top/pclk')@sim; //Define event event ready is rise('~/top/ready')@sim; //Define event event init_complete; //Define event init_dut() @pclk is { //Define TCM init_dut. @pclk is the //default sampling event. wait [5] @ready; //Wait for five occurrences of @ready signal wait [1]; //Wait for one cycle of @pclk signal out("Finishing the init_dut TCM"); }; my_tcm() @pclk is { //Define a TCM called my_tcm(). //@pclk is the default sampling event. wait @ready; //Wait until the ~/top/ready HDL signal rises wait [2]; //Wait for two occurrences of @pclk (default //sampling event of the TCM) wait [3] @ready; //Wait for three occurrences of @ready //(Override default sampling event of the //TCM that is @pclk) init_dut(); //Call the init_dut() TCM. Wait until init_dut() //finishes. emit init_complete; //Manually trigger the init_complete event }; //end of my_tcm() definition }; '>
You can execute a TCM in parallel with other TCMs by starting it from another method or TCM using the keyword start. A TCM that is started may not be a value returning TCM.
A started TCM begins execution either when its sampling event is emitted or immediately, if the sampling event has already been emitted for the current simulator callback.
A started TCM runs in parallel with the TCM that started it in a separate thread. A started TCM has a unique thread handle (thread ID) that is assigned to it automatically by the Specman Elite scheduler. The recommended way is to start an initial TCM by extending the related struct's predefined run() method. This initial TCM can then call other TCMs.
Figure 8-2 shows the sequence for executing a started TCM (TCM2). The starting TCM (TCM1) does not wait for TCM2 to complete before continuing execution. TCM1 simply spawns TCM2 in zero simulation time and continues execution.
Example 8-3 shows the starting of a TCM.
Example shows how to start a TCM from another method or TCM. In this example my_tcm() TCM is started from the run() method of the struct. <' struct meth { event pclk is rise('~/top/pclk')@sim; //Define event event ready is rise('~/top/ready')@sim; //Define event event init_complete; //Define event my_tcm() @pclk is { //Define a TCM called my_tcm() //@pclk is the default sampling event wait @ready; //Wait until the ~/top/ready HDL signal rises wait [2]; //Wait for two occurrences of @pclk (default //sampling event of the TCM) wait [3] @ready; //Wait for three occurrences of @ready //(Override default sampling event of the //TCM which is @pclk) emit init_complete; //Manually trigger the init_complete event }; //end of my_tcm() definition run() is also { //Predefined run() method in every struct //Needs to be extended to start my_tcm() out("Starting my_tcm..."); //Print message start my_tcm(); //my_tcm() is spawned off as a new thread //at simulation time 0 from the run() method }; }; '>
A TCM can be extended in the same way as a method by means of the is also, is first, and is only keywords. Example 8-4 illustrates a TCM extension.
Example shows how to extend a TCM. Can use the following syntax is also - Adds to the end of existing TCM code. is first - Adds to the beginning of existing TCM code. is only - Replaces existing TCM code. <' type ctrl_cmd_kind: [RD, WR]; struct ctrl_cmd { kind: ctrl_cmd_kind; addr: int; }; struct ctrl_stub { init_commands: list of ctrl_cmd; event cclk is rise('top.control_clk') @sim; init_dut() @cclk is { //TCM for each (cmd) in init_commands { execute(cmd); }; }; execute(cmd: ctrl_cmd) @cclk is { //Original definition of TCM out(appendf("Executing a %s (addr %s) control command", cmd.kind, cmd.addr)); case cmd.kind { RD: { wait [2]; }; WR: { wait [3]; }; }; }; }; extend ctrl_stub { execute(cmd: ctrl_cmd) @cclk is first { //Extension of TCM if ('top.interrupt' == 1) then { //Add code to the beginning //of existing TCM code return; }; }; }; '>