I was adding in the ubiquitous "what is this code doing" debug statements to some SystemVerilog to trace what was happening and finally had a chance to consider deeply the application of: $monitor, $display and $strobe. All three print to the display and all use the same syntax and formatting in their arguments. The difference in the three is when they actually execute. I read a pretty good starting article Verilog subtleties – $monitor vs. $display vs. $strobe that gave me a start to creating my own teaching version of their example.
You can check out the code below on github.
Example Tutorial Code
module dut; reg a,b,c; initial begin : abc $monitor("%t %m MON0 a: %b b: %b c: %b", $time, a, b, c); #100; {a,b} = 2'b01; c = 1; b <= 1'b0; #100; {a,b} = 2'b10; c = 1'bz; #100; {a,b} = 2'b11; c = 0; #1000; $finish; end // block: abc initial begin : ext #1; $monitor("%t %m MON1 a: %b b: %b c: %b", $time, a, b, c); $monitor("%t %m MON2 c: %b b: %b c: %b", $time, a, b, c); end always_comb begin : str $strobe("%t %m STROBE+ALWAYS : a: %b b: %b c: %b", $time, a, b, c); end always_comb begin : alw $display("%t %m ALWAYS : a: %b b: %b c: %b", $time, a, b, c); end endmodule // dut
Only One $monitor per Simulation
> rm -rf work; qverilog dms.sv -R -c -do "run -all" | grep MON # 0 dut.abc MON0 a: x b: x c: x # 1 dut.ext MON2 c: x b: x c: x # 100 dut.ext MON2 c: 0 b: 0 c: 1 # 200 dut.ext MON2 c: 1 b: 0 c: z # 300 dut.ext MON2 c: 1 b: 1 c: 0
There are a few interesting things here to learn. The first being, that even though there are three $monitor lines in the example code only one at a time can be active. That is why we get a message from MON0, but then it gets overwritten by MON1 and finally MON2. MON1 doesn't even get used because it was immediately overwritten.
The design choice to have only one $monitor statement active at a time is not what I would expect and there isn't a way to activate multiple $monitor.
The Difference Between Strobe and Display
The original article from Verification on Web had a good explanation for showing the difference between $strobe and $display. I thought i would give my own crack at it too.
> rm -rf work; qverilog dms.sv -R -c -do "run -all" | grep ALWAYS # 0 dut.alw ALWAYS : a: x b: x c: x # 0 dut.str STROBE+ALWAYS : a: x b: x c: x # 100 dut.alw ALWAYS : a: 0 b: 1 c: 1 # 100 dut.alw ALWAYS : a: 0 b: 0 c: 1 # 100 dut.str STROBE+ALWAYS : a: 0 b: 0 c: 1 # 200 dut.alw ALWAYS : a: 1 b: 0 c: z # 200 dut.str STROBE+ALWAYS : a: 1 b: 0 c: z # 300 dut.alw ALWAYS : a: 1 b: 1 c: 0 # 300 dut.str STROBE+ALWAYS : a: 1 b: 1 c: 0
The operand $display works just as you expect. Whenever it is called it executes. But $strobe is a little different, it waits until the end of the time unit to execute. And since there is only one end of a time unit, $strobe only executes once per time unit.
You can see that at time 100 the always_comb with the standard $display executed twice during that unit and the always_comb - will execute at time 0 unlike the normal always @(*) - with the $strobe executed just once. Fitting the behavior that $strobe only executes once at the end of the time unit.