Lecture 07 – Debugging and Monitoring Statements
Ryan Robucci
1. Simulation Commands
- These commands are provided for use in procedural code.All are stripped from code before synthesis
$displayis evaluated and displayed immediately$writeis same as$display, but doesn’t add newline- use
\nas desired instead
- use
$strobeis scheduled to be evaluated and displayed at the end of the time step.- Use it to report at the end of the timestep what the variables values are at the end of the timestep
$monitoris scheduled immediately and at the end of future time steps when the inputs change- Only runs once per time step
- Use it to set up automatic repeated reporting of value changes
2. Example monitor, display, strobe
DUT module with some inbuilt debugging statements: $display and $strobe
module and4( y_out, x_in); input [3:0] x_in; output y_out; reg y_out; integer k; always @ (x_in) begin:and_loop y_out = 1; for(k=0; k<=3; k=k+1) begin if (x_in[k] == 0) begin y_out = 0; // disable and_loop; // faster sim end $display("$display at time=%0d: x_in='b%b y_out='b%b", $time, x_in,y_out); $strobe ("$strobe at time=%0d: x_in='b%b y_out='b%b", $time, x_in,y_out); end //end for end //end always endmodule
Testbench with $monitor
`timescale 1ns / 1ps module and4_tb; // Design Unit Testbench parameter STOP_TIME = 10000; reg [3:0] x_in; wire y_out; and4 M1 (y_out,x_in);// Instantiate DUT // Create DUT response monitor initial $monitor ($time, " $monitor x_in = %b y_out = %b", x_in, y_out); initial begin // Create DUT stimulus generator #10 x_in = 4'b0000; #10 x_in = 4'b0011; end initial #STOP_TIME $finish; endmodule
0 $monitor x_in = xxxx y_out = x
$display at time=10: x_in='b0000 y_out='b0
$display at time=10: x_in='b0000 y_out='b0
$display at time=10: x_in='b0000 y_out='b0
$display at time=10: x_in='b0000 y_out='b0
10 $monitor x_in = 0000 y_out = 0
$strobe at time=10: x_in='b0000 y_out='b0
$strobe at time=10: x_in='b0000 y_out='b0
$strobe at time=10: x_in='b0000 y_out='b0
$strobe at time=10: x_in='b0000 y_out='b0
$display at time=20: x_in='b0011 y_out='b1
$display at time=20: x_in='b0011 y_out='b1
$display at time=20: x_in='b0011 y_out='b0
$display at time=20: x_in='b0011 y_out='b0
20 $monitor x_in = 0011 y_out = 0
$strobe at time=20: x_in='b0011 y_out='b0
$strobe at time=20: x_in='b0011 y_out='b0
$strobe at time=20: x_in='b0011 y_out='b0
$strobe at time=20: x_in='b0011 y_out='b0
3. Testbench with $strobe and $display
`timescale 1ns / 1ps module and_tb; // Design Unit Testbench parameter STOP_TIME = 10000; reg [3:0] a; wire y; // Instantiate DUT and I1 (y,a[3],a[2],a[1],a[0]); initial begin // Create DUT stimulus generator with print #10; a = 4'b1100; #10; $strobe ($time,"%0t:$strobe1 a = %b y = %b", $time, a, y); $display ($time,"%0t:$display1 a = %b y = %b", $time, a, y); a[0] = 1'b1; $strobe ($time,"%0t:$strobe2 a = %b y = %b", $time, a, y); $display ($time,"%0t:$display2 a = %b y = %b", $time, a, y); a[1] = 1'b1; $strobe ($time,"%0t:$strobe3 a = %b y = %b", $time, a, y); $display ($time,"%0t:$display3 a = %b y = %b", $time, a, y); end // initial begin endmodule // and_tb #end_src #+begin_src result 2020000:$display1 a = 1100 y = 0 2020000:$display2 a = 1101 y = 0 2020000:$display3 a = 1111 y = 0 2020000:$strobe1 a = 1111 y = 1 2020000:$strobe2 a = 1111 y = 1 2020000:$strobe3 a = 1111 y = 1
4. More on Monitor
- Only one
$monitormay be active at a time - subsequent
$monitorcalls while a monitor is active do not have an effect $monitoron,$monitoroffcan be used to disable (deactivate) and enable (activate) the monitor task$monitoris typically only called once during a simulation unlike$displayand$strobe
5. Printing Current Context in Hierarchy
When printing, it is often useful to know from the log/printout which instance made the call using %m in a format string "%m":
module (...) inv1 M1(a,b); inv1 M1(c,d); endmodule module inv1(y,x); output y input x; always @ (x) begin $display(“Instance %m is doing something”); end endmodule
6. Variable Scope and Hierarchy Reference using identifiers
Variable scope is defined by the name of the module instance,task,function, or named procedural block (begin…end) in which they are defined For simulation, you will often want to peek downward into the hierarchy. Use names such as module instance names and block names:
Ex:
my_block M1 (a,b,c); $monitor(M1.I1.my_procedure.count);
(Upward searching for a variable not locally defined is automatic, but adhere to sensible coding practices.)
7. File Output
- File access is performed using system tasks and functions $fdisplay,$fwrite,$fstrobe
- Files must be opened before used and should be closed: $fopen and $fclose
- Open files are managed/tracked using a 32-bit reg that must be declared before use
- STDIN is pre-opened for reading, and STDOUT andSTDERR are pre-opened for append and correspond to 0,1,2
8. File output example
module fw_test; initial begin:block1 //naming a block allows //creating local variables reg [31:0] fd1; reg [7:0] x; x = 8'b1; fd1 = $fopen("output.txt"); //default mode // is overwrite if (fd1 == 0) begin $display("file open error"); $finish(); end $fdisplay(fd1,"x:"); //without a formating string $fdisplay(fd1,x); //without a variable $fdisplay(fd1,"display:%08b",x); $fwrite(fd1,"write:%08b",x); $fstrobe(fd1,"strobe:%08b",x); #1 //required last time advance to make strobe // output before file close $fclose(fd1); end endmodule // file
Result in output.txt:
x: 1 display:00000001 write:00000001strobe:00000001
9. File I/O
$readmemhand$readmemballow reading ascii-encoded hex and binary from files- (see data source example
memory_hex_in.txtbelow)
- (see data source example
$fopenand output varients like$fstrobe,$fdisplay, and$fwritefacilitate textual file output- Note that the procedural construct for can be used to create simulation code loops.
module adder(sum,a,b,en,clk); output logic [7:0] sum; input [7:0] a,b; input en; input clk; always @(posedge clk) begin if (en) sum <= a+b; end endmodule // adder module adder_tb; logic clk; logic [7:0] sum; logic [7:0] a,b; logic en; adder DUT (.*); wire data_out; reg [3:0] addr; reg [15:0] input_buff [0:7]; // 8 entries each of 16-bits integer idx; integer file; initial begin clk = 0; forever #10 clk = ~clk; end initial begin //$monitor($time,"a:",a," b:",b," sum:",sum); $readmemh("memory_hex_in.txt", input_buff); //init input_buff from file file = $fopen("memory_hex_out.txt"); //open a file for writing results @ (posedge clk); en <= 0; for (idx=0; idx<8; i++) begin //write to mem @ (posedge clk); en <= 1; {a,b} <= input_buff[idx]; @ (posedge clk); en <= 0; {a,b} <= '0; @ (posedge clk); //$strobe(sum); $fstrobe(file,"%2H",sum); end @ (posedge clk); $fclose(file); $finish; end endmodule
memory_hex_in.txt:
A001 A002 A003 A004 A005 A006 A007 A008
Result:
memory_hex_out.txt:
a1 a2 a3 a4 a5 a6 a7 a8
10. Testing an asynchronous memory
wire data_out; reg write; reg [3:0] addr; reg [7:0] memory_buffer [0:15]; // 16 entries 8 bit #'s reg [7:0] data_in; integer i; integer file; my_mem DUT (data_out,data_int,addr,write); initial begin $readmemh("memory_hex_in.txt", memory_buff); //init memory_buff from file file = $fopen(“memory_hex_out.txt”); //open a file for writing results #5 write <= 0; addr <= 0; for (i=0; i<16; i++) begin //write to mem #5 write <= 0; data_in <= memory_buff[i]; addr <= i; #5 write <= 1; end #10 write <= 0; //reading and writing to file for (i=0; i<16; i++) begin #5 addr <=i; $fstrobe(file,“%2H”,data_out); end $fclose(file); end
11. VCD Control
- Minimal code for genearation of VCD:
typically added to testbench
initial begin $dumpfile("simulation_result.vcd"); $dumpvars; end
- For large designs dumping all signals may significantly slow simulation, increase file size, and slow loading and analysis of VCD data limiting which singals are saved to file can have a significant impact on simulation time.
Details from IEEE Std 1364â„¢-2005 https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=1620780
$dumpfile("filename.vcd")$dumpvars;: dumps all variables$dumpvars(1);: dumps all variables in the current scope$dumpvars(level, list$dumpvars (1, top): dump vars in moduletop$dumpvars (0, top): dump vars in and below leveltop$dumpvars (0, top.module1, top.module2.net1);dump vars in and below leveltop.module1as well asnet1inmodule2
To record waveforms only during certain phases of simulation (such as post-initialization) use…
$dumpoff;disables dumping$dumpon;enables dumping Example codeinitial begin #10 $dumpvars( . . . ); #200 $dumpoff; #800 $dumpon; #900 $dumpoff; end
$dumpall;create checkpoint with the value of all selected variables$dumplimit ( filesize ) ;maximum size before dumping is disabled$dumpflush: flushes output, useful before crashing code, or perhaps before external library calls that potentially read dump file