Skip to main content

System Tasks and Compiler Directives

System tasks (prefixed $) and compiler directives (prefixed `) are Verilog's built-in tooling vocabulary — not hardware description at all, but the debugging, file I/O, and preprocessing mechanisms that make writing and building real Verilog projects practical.

Display system tasks​

initial begin
$display("Reset complete at time %0t", $time);
$monitor("t=%0t a=%b b=%b sum=%b cout=%b", $time, a, b, sum, cout);
end
TaskBehavior
$displayPrints its arguments once, immediately, like a formatted print statement
$monitorPrints its arguments automatically, once per simulation time step, whenever any listed variable changes — a "live watch," not a one-shot print
$strobeLike $display, but prints at the very end of the current time step, after every other statement scheduled for that step has executed — useful for guaranteeing you're printing the settled value rather than one mid-update
$time / $realtimeReturns the current simulation time, typically used as an argument to the tasks above

All of these are simulation-only — they have no synthesis meaning whatsoever, and appear exclusively in initial/always blocks used for debugging or in testbenches, never in RTL meant to become real hardware.

Ending or pausing a simulation​

Two more system tasks control the simulation run itself rather than printing anything: $finish ends the simulation entirely, exactly as if the testbench had run off the end of its code — most simulators exit back to the shell (or the GUI's "simulation ended" state) once it executes. $stop instead suspends the simulation, dropping into the simulator's interactive command prompt without actually ending the run — useful for pausing mid-simulation to inspect signals by hand before deciding whether to continue or finish. Without an explicit $finish (or a forever loop that never calls it, timing out on some simulators' default time limit instead), a testbench with nothing left to execute simply idles at whatever time its last statement ran.

Reading memory contents from a file​

initial begin
$readmemh("rom_contents.hex", mem); // hex-formatted file
// $readmemb("rom_contents.bin", mem); // binary-formatted file, same idea
end

$readmemh/$readmemb load an array (like the ROM array from Arrays and Memories) from an external text file, one value per line — the practical, scalable alternative to hand-writing dozens of mem[n] = ...; assignment lines for real ROM content.

Compiler directives​

Directives are processed by Verilog's preprocessor, before the compiler proper ever sees the code — textual substitution and conditional inclusion, conceptually identical to the C preprocessor:

`define WIDTH 8
`define ADD_OP 2'b00

module alu (
input [`WIDTH-1:0] a,
input [`WIDTH-1:0] b,
input [1:0] op,
output reg [`WIDTH-1:0] result
);
DirectivePurpose
`defineText macro substitution — `WIDTH is replaced with 8 everywhere it appears, textually, before compilation
`includePastes another file's contents in at that point — used for sharing common definitions across multiple modules
`timescaleSets the time unit and precision ( `timescale 1ns/1ps — 1ns per time unit, simulated with 1ps resolution) that #delay values and $time are interpreted against
`ifdef / `ifndef / `else / `endifConditional compilation — include or exclude a block of code depending on whether a macro is defined, commonly used to gate simulation-only debug code out of a synthesis run
`ifdef SIMULATION
initial $display("Testbench starting");
`endif

`ifdef SIMULATION/ `endif here means the $display line only exists in builds where a SIMULATION macro was defined (typically via a simulator command-line flag) — a clean way to keep debug-only code physically present in the source for anyone reading it, while guaranteeing it's compiled out entirely for synthesis, rather than relying on synthesis tools to silently ignore $display (which they do, but making the exclusion explicit is more robust and self-documenting).

What's next​

Debugging tools and directives round out the practical vocabulary needed to actually build and simulate a Verilog project. The next page puts it to use directly — writing a minimal, stand-alone testbench in plain Verilog, the bridge into the much deeper verification content covered by Testbench and UVM.