Generating Timing Diagrams from Verilog Simulations

Introduction

It’s very handy to generate timing diagrams directly from simulations. Once you have a timing diagram version of the simulation, you can then edit the diagram, add text annotations to show signal relationships, and then save it as an PNG, PDF, or PS file. Then just paste the diagram into the document. This is nice for specifications, review presentations, and design notes.

With the new Python scripting feature, you can generate the timing diagrams automatically from Verilog simulations. This application note shows you a way to use Verilog to generate Python scripts that will automatically build timing diagrams.

The Verilog Example

The DUT (Device under Test) is a simple model of a 8 bit memory, sram_1024_8.v. The testbench, sram_tb.v, contains the code needed to generate stimulus for the DUT and sram_timing_diagram.v generates the Python script to automatically build a timing diagram which contains all the signals used by the memory model.

Download all the Verilog for this Example

Output Start and Finish Timing Diagram Functions

The first part of the initial block outputs the scripts needed to initialize the timing diagram script. After the simulation reaches the end time, a few more script functions are needed to zoom into the complete timing diagram. These set the timing diagram start and end time and then zoom in. The Python script name is “sram_td_script.py”. This could be changed to a verilog parameter.

 1initial
 2begin
 3   file = $fopen("sram_td_script.py","w");
 4   $fwrite(file,"from ta_py_lib 'ta.app' import \*\n");
 5   $fwrite(file,"from ta_py_lib 'ta.logic' import \*\n");
 6   $fwrite(file,"from ta_py_lib 'ta.commands' import \*\n");
 7   $fwrite(file,"td = new_timing_diagram('taApp')"\n");
 8   $fwrite(file,"start_script(td)\n");
 9   #end_time
10   $fwrite(file,"set_end_time(td, %0d)\n",end_time);
11   $fwrite(file,"zoom_in_full(td)\n");
12   $fwrite(file,"stop_script(td)\n");
13   $fclose(file);
14end

Add and Monitor Each Signal Functions

An always block is needed for every signal. The code below shows what’s needed to monitor the address signal, addr[9:0]. The first time an event is detected, the signal is added to the timing diagram. After, an new edge is added to the signal when an event is detected. You can use this as a template for other signals.

 1always @ (addr)
 2begin
 3   if ($time >= start_time && $time < end_time)
 4   begin
 5      if (addr_first == 0)
 6      begin
 7         $fwrite(file, "addr = add_digital_bus(td, 'addr[9:0]','%h','Hex')\n",addr);
 8         addr_first = 1;
 9      end
10      else
11         $fwrite(file, "add_edge(td, addr,%0d,'%h')\n",$time,addr);
12   end
13end

The SRAM Timing Diagram Component

  1`timescale 1ns / 1ps
  2
  3module sram_timing_diagram ( clk, addr,
  4                             data, cs, we, oe);
  5
  6input       clk;
  7input [9:0] addr;
  8input [7:0] data;
  9input       cs;
 10input       we;
 11input       oe;
 12
 13parameter integer start_time = 0;
 14parameter integer end_time   = 500;
 15
 16
 17integer file;
 18
 19reg clk_first  = 0;
 20reg addr_first = 0;
 21reg data_first = 0;
 22reg cs_first   = 0;
 23reg we_first   = 0;
 24reg oe_first   = 0;
 25
 26//initial $monitor("%d %b %h %h %b %b %b",$time,clk,addr,data,cs,we,oe);
 27//initial $display("start_time = %d", start_time);
 28//initial $display("end_time = %d", end_time);
 29
 30initial
 31begin
 32   file = $fopen("sram_td_script.py","w");
 33   $fwrite(file,"from ta_py_lib.ta.app import \*\n");
 34   $fwrite(file,"from ta_py_lib.td.logic import \*\n");
 35   $fwrite(file,"from ta_py_lib.td.commands import \*\n");
 36   $fwrite(file,"td = new_timing_diagram(taApp)\n");
 37   $fwrite(file,"start_script(td)\n");
 38   #end_time
 39   $fwrite(file,"set_end_time(td, %0d)\n",end_time);
 40   $fwrite(file,"zoom_in_full(td)\n");
 41   $fwrite(file,"stop_script(td)\n");
 42   $fclose(file);
 43end
 44
 45always @ (clk)
 46begin
 47  if ($time >= start_time && $time < end_time)
 48  begin
 49    if (clk_first == 0)
 50    begin
 51      $fwrite(file, "clk = add_digital_signal(td,'clk','%b')\n",clk);
 52      clk_first = 1;
 53    end
 54    else
 55      $fwrite(file, "add_edge(clk,%0d,'%b')\n",$time,clk);
 56  end
 57end
 58
 59always @ (addr)
 60begin
 61  if ($time >= start_time && $time < end_time)
 62  begin
 63    if (addr_first == 0)
 64    begin
 65      $fwrite(file, "addr = add_digital_bus(td,'addr[9:0]','%h','Hex')\n",addr);
 66      addr_first = 1;
 67    end
 68    else
 69      $fwrite(file, "add_edge(addr,%0d,'%h')\n",$time,addr);
 70  end
 71end
 72
 73always @ (data)
 74begin
 75  if ($time >= start_time && $time < end_time)
 76  begin
 77    if (data_first == 0)
 78    begin
 79      $fwrite(file, "data = add_digital_bus(td,'data[7:0]','%h','Hex')\n",data);
 80      data_first = 1;
 81    end
 82    else
 83      $fwrite(file, "add_edge(data,%0d,'%h')\n",$time,data);
 84  end
 85end
 86
 87always @ (cs)
 88begin
 89  if ($time >= start_time && $time < end_time)
 90  begin
 91    if (cs_first == 0)
 92    begin
 93      $fwrite(file, "cs = add_digital_signal(td,'cs','%b')\n",cs);
 94      cs_first = 1;
 95    end
 96    else
 97      $fwrite(file, "add_edge(cs,%0d,'%b')\n",$time,cs);
 98  end
 99end
100
101always @ (we)
102begin
103  if ($time >= start_time && $time < end_time)
104  begin
105    if (we_first == 0)
106    begin
107      $fwrite(file, "we = add_digital_signal(td,'we','%b')\n",we);
108      we_first = 1;
109    end
110    else
111      $fwrite(file, "add_edge(we,%0d,'%b')\n",$time,we);
112  end
113end
114
115always @ (oe)
116begin
117  if ($time >= start_time && $time < end_time)
118  begin
119    if (oe_first == 0)
120    begin
121      $fwrite(file, "oe = add_digital_signal(td,'oe','%b')\n",oe);
122      oe_first = 1;
123    end
124    else
125      $fwrite(file, "add_edge(oe,%0d.0e-9,'%b')\n",$time,oe);
126  end
127end
128
129endmodule