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;