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.

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

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.

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

The SRAM Timing Diagram Component

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
`timescale 1ns / 1ps

module sram_timing_diagram ( clk, addr,
                             data, cs, we, oe);

input       clk;
input [9:0] addr;
input [7:0] data;
input       cs;
input       we;
input       oe;

parameter integer start_time = 0;
parameter integer end_time   = 500;


integer file;

reg clk_first  = 0;
reg addr_first = 0;
reg data_first = 0;
reg cs_first   = 0;
reg we_first   = 0;
reg oe_first   = 0;

//initial $monitor("%d %b %h %h %b %b %b",$time,clk,addr,data,cs,we,oe);
//initial $display("start_time = %d", start_time);
//initial $display("end_time = %d", end_time);

initial
begin
   file = $fopen("sram_td_script.py","w");
   $fwrite(file,"from ta_py_lib.ta.app import \*\n");
   $fwrite(file,"from ta_py_lib.td.logic import \*\n");
   $fwrite(file,"from ta_py_lib.td.commands import \*\n");
   $fwrite(file,"td = new_timing_diagram(taApp)\n");
   $fwrite(file,"start_script(td)\n");
   #end_time
   $fwrite(file,"set_end_time(td, %0d)\n",end_time);
   $fwrite(file,"zoom_in_full(td)\n");
   $fwrite(file,"stop_script(td)\n");
   $fclose(file);
end

always @ (clk)
begin
  if ($time >= start_time && $time < end_time)
  begin
    if (clk_first == 0)
    begin
      $fwrite(file, "clk = add_digital_signal(td,'clk','%b')\n",clk);
      clk_first = 1;
    end
    else
      $fwrite(file, "add_edge(clk,%0d,'%b')\n",$time,clk);
  end
end

always @ (addr)
begin
  if ($time >= start_time && $time < end_time)
  begin
    if (addr_first == 0)
    begin
      $fwrite(file, "addr = add_digital_bus(td,'addr[9:0]','%h','Hex')\n",addr);
      addr_first = 1;
    end
    else
      $fwrite(file, "add_edge(addr,%0d,'%h')\n",$time,addr);
  end
end

always @ (data)
begin
  if ($time >= start_time && $time < end_time)
  begin
    if (data_first == 0)
    begin
      $fwrite(file, "data = add_digital_bus(td,'data[7:0]','%h','Hex')\n",data);
      data_first = 1;
    end
    else
      $fwrite(file, "add_edge(data,%0d,'%h')\n",$time,data);
  end
end

always @ (cs)
begin
  if ($time >= start_time && $time < end_time)
  begin
    if (cs_first == 0)
    begin
      $fwrite(file, "cs = add_digital_signal(td,'cs','%b')\n",cs);
      cs_first = 1;
    end
    else
      $fwrite(file, "add_edge(cs,%0d,'%b')\n",$time,cs);
  end
end

always @ (we)
begin
  if ($time >= start_time && $time < end_time)
  begin
    if (we_first == 0)
    begin
      $fwrite(file, "we = add_digital_signal(td,'we','%b')\n",we);
      we_first = 1;
    end
    else
      $fwrite(file, "add_edge(we,%0d,'%b')\n",$time,we);
  end
end

always @ (oe)
begin
  if ($time >= start_time && $time < end_time)
  begin
    if (oe_first == 0)
    begin
      $fwrite(file, "oe = add_digital_signal(td,'oe','%b')\n",oe);
      oe_first = 1;
    end
    else
      $fwrite(file, "add_edge(oe,%0d.0e-9,'%b')\n",$time,oe);
  end
end

endmodule