Exercise 15

The source files are tut12.tv, and counter1.v or counter1.vhd.

All the examples so far have used only sequential functions: main, and any functions called by main. These functions are sequential in the sense that there is a single sequential program flow through them, starting at the entry to main and finishing at the point at which main returns, or at which exit is called. Maia also has two variants of concurrent functions:

  • 'thread' functions are conventional user functions which can be run in a new thread with an exec statement. Thread functions are primarily useful when a DUT has multiple independent clocks, or produces output at times which do not fit in with the natural program flow.
  • 'trigger' functions, which run automatically in response to specified DUT conditions. Trigger functions are primarily useful when a specific combination of DUT outputs must be captured.

Trigger functions work in much the same way as an oscilloscope trigger condition. Trigger functions are posted for later execution in the main sequential program flow, by a trigger statement. The trigger statement specifies a set of conditions, and an associated trigger function. If the condition is later satisified, the trigger function is executed, and runs concurrently with the sequential program flow, and any other thread or trigger functions which happen to be running. The trigger statement can specify that the function should execute only once, or that it should execute whenever the condition is found to be valid (in other words, the trigger is either a one-shot condition, or it re-arms itself on completion of the function).

Trigger functions are useful when it is difficult to predict in advance exactly when a DUT will carry out some action. In this case, we can simply trigger on some condition (a 'data ready' signal, for example); the trigger function can then check the DUT outputs, knowing that data is available.

tut12.tv shows a simple usage of 3 trigger functions. In this case, the DUT is entirely predictable - it is simply a 4-bit up-counter - but the same principles can be used for more general DUTs.

The expected output is:

trigFunctionC: Q is 4; time 40 ns
trigFunctionA: Q is 9; time 80 ns
trigFunctionB: Q is 3; time 160 ns
trigFunctionA: Q is 9; time 208 ns
(Log)        (256 ns) 40 vectors executed (40 passes, 0 fails)