Generating Timing Diagrams from VHDL Simulations

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 VHDL simulations. This application note shows you a way to use VHDL to generate Python scripts that will automatically build timing diagrams.

The VHDL Example

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

Download all the VHDL for this Example vhdl_app_note.

Initialize the Timing Diagram Functions

The first part of the process defines variables and generates the beginning of the timing diagram script. The process monitors the signals in the sensitivity list and adds a new edge to the signal every time an event is detected if the simulation time now is greater than the start_time and less then the end_time defined in the variables section. These will set the timing diagram start and end time. The Python script name is defined by py_output as “sram_td_script.py”. This could easily be changed to a process argument.

 1-- initialize the TimingAnalyzer application if use Jython
 2--print(py_output, "execfile('./start_app.py')");
 3--print(py_output, "");
 4print(py_output, "from ta_py_lib.ta.app import *");
 5print(py_output, "from ta_py_lib.td.logic import *");
 6print(py_output, "from ta_py_lib.td.commands import *");
 7print(py_output, "");
 8print(py_output, "td = new_timing_diagram(taApp)");
 9print(py_output, "start_script(td)");
10print(py_output, "");

Add and Monitor Each Signal Functions

A monitor block for every signal is included in the body of the process. The code below shows what’s needed to monitor the write address signal, waddr(9 downto 0). When an event is detected, an new edge is added to the signal. You can use this as a template for other signals.

 1if (waddr'event) then
 2  if (waddr_first = '0') then
 3    print(py_output, "waddr = add_digital_bus(td, " & "'waddr[9:0]'" &
 4                     ",'" & hstr(waddr) & "','Hex')");
 5    waddr_first <= '1';
 6  else
 7    print(py_output, "add_edge(" & "waddr" & "," & integer'image(time_now) &
 8                                 ".0" & ",'" & hstr(waddr) & "')");
 9  end if;
10end if;

Finalize Timing Diagram Functions

To complete the timing diagram script, the start time and end time are specified, then we “zoomIn” to show the complete diagram, then the stopScript() function actually draws the diagram.

1elsif (now > end_time) then
2  if (finish = '0') then
3     print(py_output, "set_start_time(td," & integer'image(scaled_start_time) & ")");
4     print(py_output, "set_end_time(td," & integer'image(scaled_end_time) & ")");
5     print(py_output, "zoom_in_full(td)");
6     print(py_output, "stop_script(td)");
7     finish <= '1';
8  end if;
9end if;

The SRAM Timing Diagram Component

  1library IEEE;
  2use IEEE.std_logic_1164.all;
  3use STD.textio.all;
  4use work.txt_util.all;
  5
  6
  7entity sram_timing_diagram is
  8  generic (
  9    start_time  : time := 0 ns;
 10    end_time    : time := 500 ns);
 11  port (
 12    clk50     : in std_logic;
 13    enable    : in std_logic;
 14    write     : in std_logic;
 15    waddr     : in std_logic_vector(9 downto 0);
 16    din       : in std_logic_vector(7 downto 0);
 17    read      : in std_logic;
 18    raddr     : in std_logic_vector(9 downto 0);
 19    dout      : in std_logic_vector(7 downto 0));
 20end sram_timing_diagram;
 21
 22architecture sram_timing_diagram_rtl of sram_timing_diagram is
 23
 24  signal start  : std_logic := '0';
 25  signal finish : std_logic := '0';
 26
 27  signal enable_first   : std_logic := '0';
 28  signal write_first    : std_logic := '0';
 29  signal waddr_first    : std_logic := '0';
 30  signal read_first     : std_logic := '0';
 31  signal raddr_first    : std_logic := '0';
 32  signal clk50_first    : std_logic := '0';
 33  signal din_first      : std_logic := '0';
 34  signal dout_first     : std_logic := '0';
 35
 36begin
 37
 38  build_timing_diagram : process(enable,write,waddr,read,raddr,clk50,din,dout)
 39    variable in_line            : line;
 40    variable out_line           : line;
 41    variable time_now           : integer;
 42    variable scaled_start_time  : integer;
 43    variable scaled_end_time    : integer;
 44    file py_output      : text open write_mode is "sram_td_script.py";
 45  begin
 46    if ( now >= start_time and now <= end_time) then
 47      if (start = '0') then
 48
 49        -- initialize the TimingAnalyzer application if use Jython
 50        --print(py_output, "execfile('./start_app.py')");
 51        --print(py_output, "");
 52        print(py_output, "from ta_py_lib.ta.app import *");
 53        print(py_output, "from ta_py_lib.td.logic import *");
 54        print(py_output, "from ta_py_lib.td.commands import *");
 55        print(py_output, "");
 56        print(py_output, "td = new_timing_diagram(taApp)");
 57        print(py_output, "start_script(td)");
 58        print(py_output, "");
 59
 60        scaled_start_time   := (start_time / 1 ns);
 61        scaled_end_time     := (end_time / 1 ns);
 62        start <= '1';
 63      else
 64
 65        time_now := ( now / 1 ns);
 66
 67
 68        if (clk50'event) then
 69          if (clk50_first = '0') then
 70            print(py_output, "clk50 = add_digital_signal(td," & "'clk50'" &
 71                                                            ",'" & str(clk50) & "')");
 72            clk50_first <= '1';
 73          else
 74            print(py_output, "add_edge(" & "clk50" & "," & integer'image(time_now) &
 75                                       ".0" & ",'" & str(clk50) & "')");
 76          end if;
 77        end if;
 78
 79        if (enable'event) then
 80          if (enable_first = '0') then
 81            print(py_output, "enable = add_digital_signal(td," & "'enable'" &
 82                                                             ",'" & str(enable) & "')");
 83            enable_first <= '1';
 84          else
 85            print(py_output, "add_edge(" & "enable" & "," & integer'image(time_now) &
 86                                       ".0" & ",'" & str(enable) & "')");
 87          end if;
 88        end if;
 89
 90        if (write'event) then
 91          if (write_first = '0') then
 92            print(py_output, "write = add_digital_signal(td," & "'write'" &
 93                                                            ",'" & str(write) & "')");
 94            write_first <= '1';
 95          else
 96            print(py_output, "add_edge(" & "write" & "," & integer'image(time_now) &
 97                                       ".0" & ",'" & str(write) & "')");
 98          end if;
 99        end if;
100
101        if (waddr'event) then
102          if (waddr_first = '0') then
103            print(py_output, "waddr = add_digital_bus(td," & "'waddr[9:0]'" &
104                                                         ",'" & hstr(waddr) & "','Hex')");
105            waddr_first <= '1';
106          else
107            print(py_output, "add_edge(" & "waddr" & "," & integer'image(time_now) &
108                                       ".0" & ",'" & hstr(waddr) & "')");
109          end if;
110        end if;
111
112        if (din'event) then
113          if (din_first = '0') then
114            print(py_output, "din = add_digital_bus(td," & "'din[7:0]'" &
115                                                       ",'" & hstr(din) & "','Hex')");
116            din_first <= '1';
117          else
118            print(py_output, "add_edge(" & "din" & "," & integer'image(time_now) &
119                                       ".0" & ",'" & hstr(din) & "')");
120          end if;
121        end if;
122
123        if (read'event) then
124          if (read_first = '0') then
125            print(py_output, "read = add_digital_signal(td," & "'read'" &
126                                                           ",'" & str(read) & "')");
127            read_first <= '1';
128          else
129            print(py_output, "add_edge(" & "read" & "," & integer'image(time_now) &
130                                       ".0" & ",'" & str(read) & "')");
131          end if;
132        end if;
133
134        if (raddr'event) then
135          if (raddr_first = '0') then
136            print(py_output, "raddr = add_digital_bus(td," & "'raddr[9:0]'" &
137                                                         ",'" & hstr(raddr) & "','Hex')");
138            raddr_first <= '1';
139          else
140            print(py_output, "add_edge(" & "raddr" & "," & integer'image(time_now) &
141                                       ".0" & ",'" & hstr(raddr) & "')");
142          end if;
143        end if;
144
145        if (dout'event) then
146          if (dout_first = '0') then
147            print(py_output, "dout = add_digital_bus(td," & "'dout[7:0]'" &
148                                                        ",'" & hstr(dout) & "','Hex')");
149            dout_first <= '1';
150          else
151            print(py_output, "add_edge(" & "dout" & "," & integer'image(time_now) &
152                                       ".0" & ",'" & hstr(dout) & "')");
153          end if;
154        end if;
155
156      end if;
157    elsif (now > end_time) then
158      if (finish = '0') then
159         print(py_output, "set_start_time(td," & integer'image(scaled_start_time) & ")");
160         print(py_output, "set_end_time(td," & integer'image(scaled_end_time) & ")");
161         print(py_output, "zoom_in_full(td)");
162         print(py_output, "stop_script(td)");
163         finish <= '1';
164      end if;
165    end if;
166  end process;
167
168end sram_timing_diagram_rtl;