There are two actions that are used to synchronize temporal test activities within e and between the DUT and e simulator. These actions are wait and sync. These actions are called within TCMs. This section discusses these actions.
The wait action suspends the execution of the current TCM until a given temporal expression succeeds. If no temporal expression is provided, the TCM waits for its default sampling event. The syntax for the wait action is shown below. The until keyword is purely optional and has no effect on the behavior of the wait action. The wait action suspends the execution of the TCM until the temporal expression succeeds.
wait [[until] temporal-expression ];
A TCM cannot continue during the same cycle in which it reaches a wait. Even if the temporal expression succeeds in the current simulator callback, the TCM will not proceed. The TCM has to wait at least until the next simulator callback to evaluate the temporal expression and check for success or failure. Therefore, the wait action always requires at least one cycle of the TCMs sampling event before execution can continue. Example 8-5 shows numerous variations of the wait action.
Example shows variations of the wait action. A wait action is called only inside a TCM. <' struct wt { var1: uint (bits: 4); var2: uint (bits: 4); go_wait()@sys.clk is { wait [3]*cycle; // Continue on the fourth cycle from now wait delay(30); // Wait 30 simulator time units wait [var1 + var2]*cycle; // Calculate the number of cycles to wait wait until [var1 + var2]*cycle; // Same as wait [var1 + var2]*cycle wait true(sys.time >= 200); // Continue when sys.time is greater than or equal to 200 wait cycle @sys.reset; // Continue on reset even if it is not synchronous with // the TCMs default sampling event wait @sys.reset; // Continue on the next default sampling event after reset }; //End of TCM go_wait() run() is also { //Start the go_wait TCM from the run() method. start go_wait(); }; }; extend sys { wt_i: wt; event clk; event reset; }; '>
The sync action suspends execution of the current TCM until the temporal expression succeeds. Evaluation of the temporal expression starts immediately when the sync action is reached. If the temporal expression succeeds within the current simulator callback, the execution continues immediately. The syntax for the sync action is shown below.
sync [temporal-expression];
The TCM suspends until the emission of its sampling event, or continues immediately if the sampling event has been emitted in the current simulator callback. The sync action is similar to the wait action, except that a wait action always requires at least one cycle of the TCMs sampling event before execution can continue. With a sync action, execution can continue in the same simulator callback. Example 8-6 shows one variation of the sync action.
Example shows the sync action. A sync action is called only inside a TCM. Differences between wait and sync are also shown. <' struct data_drive { event clk is rise('top.clk') @sim; data: list of int; driver() @clk is { for each in data { wait true('~/top/data_ready'== 1); // Will not fall through, even if the condition // holds when the wait is evaluated. '~/top/in_reg' = it; }; stop_run(); //Finish the simulation run. }; shadow() @clk is { while TRUE { sync true('~/top/data_ready' == 0); // If the condition holds, the sync falls through // as soon as the sync is evaluated. out("Shadow read ", '~/top/in_reg'); wait cycle; // This wait is necessary to prevent // a zero time loop. //Even though this is a while TRUE (infinite) loop, //the stop_run() call in driver() TCM will ensure //that the simulation finishes. }; }; run() is also { //The run method must be extended. start driver(); // Spawn the driver TCM thread start shadow(); // Spawn the shadow TCM thread. }; }; '>
The sync action is similar to the wait action, except that a wait action always requires at least one cycle of the TCMs sampling event before execution can continue. With a sync action, execution can continue in the same simulator callback. Figure 8-3 shows the fundamental difference in the usage of wait and sync actions.
Figure 8-4 explains the difference between wait and sync further. Only a portion of the code from a TCM block is shown in this example. The print a; action happens exactly at time t0. The wait and sync actions are both evaluated at time t0. At this time, the temporal expression true('~/top/enable' == 1)@clk evaluates successfully. Therefore, the sync action falls through right away and print c; action also happens at time t0. However, the wait action still must wait until the next success of true('~/top/enable' == 1)@clk which happens only at time t1. Therefore, the print b; action is executed at time t1.
Figure 8-5 shows a scenario in which wait and sync behave identically. The print a; action happens exactly at time t0. The wait and sync actions are both evaluated at time t0. At this time, the temporal expression true('~/top/enable' == 1)@clk does not evaluate successfully. Therefore, both wait and sync must wait until the next success of true('~/top/enable' == 1)@clk which happens only at time t1. Therefore, both print b; and print c; actions are executed at time t1.
There is always an implicit sync on the sampling event at the beginning of every TCM. This means that even though the TCM is called or started, it begins execution immediately only if the sampling event has been emitted in the current simulator callback. Otherwise, the TCM suspends execution until the first emission of the sampling event. Figure 8-6 shows how an implicit sync is present at the beginning of every TCM.