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
  • $display is evaluated and displayed immediately
  • $write is same as $display, but doesn’t add newline
    • use \n as desired instead
  • $strobe is 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
  • $monitor is 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 $monitor may be active at a time
  • subsequent $monitor calls while a monitor is active do not have an effect
  • $monitoron, $monitoroff can be used to disable (deactivate) and enable (activate) the monitor task
  • $monitor is typically only called once during a simulation unlike $display and $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

  • $readmemh and $readmemb allow reading ascii-encoded hex and binary from files
    • (see data source example memory_hex_in.txt below)
  • $fopen and output varients like $fstrobe, $fdisplay, and $fwrite facilitate 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 module top
        • $dumpvars (0, top) : dump vars in and below level top
        • $dumpvars (0, top.module1, top.module2.net1); dump vars in and below level top.module1 as well as net1 in module2

      To record waveforms only during certain phases of simulation (such as post-initialization) use…

      • $dumpoff; disables dumping
      • $dumpon; enables dumping Example code

        initial 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

Author: Dr. Ryan Robucci

Created: 2025-02-28 Fri 11:04

Validate