Adding a page on additional info regarding JTAG/pinmux test code
[libreriscv.git] / docs / gtkwave_tutorial.mdwn
1 [[!img 2020-08-15_12-04.png size="800x" ]]
2
3 This tutorial is about generating better GTKWave documents (*.gtkw)
4 from Python. The goal is to ease analysis of traces generated by
5 unit-tests, and at the same time to better understand the inner working
6 of modules, for which we are writing such tests.
7
8 # Stylish GTKWave Documents
9
10 In this tutorial, you will learn how to:
11
12 1. Use individual trace colors.
13 For instance, use different color styles for input, output, debug and
14 internal traces.
15 2. Use numeric bases besides the default hex.
16 3. Create collapsible trace groups
17 Useful to hide and show, at once, groups of debug, internal and
18 sub-module traces.
19 Select the opening or closing brace, then use the T key.
20 4. Add comments in the signal names pane
21 5. Change the displayed name of a trace
22 6. Use a sane default for initial zoom level
23 7. Place markers on interesting places
24 8. Put the generating file name as a comment in the file
25
26 ## Basic trace display
27
28 First, we need a VCD file. Try:
29
30 python -m nmutil.test.example_gtkwave
31
32 Among other files, it will generate ``test_shifter.vcd``.
33
34 Lets write a simple GTKW document. First, import the function:
35
36 from nmutil.gtkw import write_gtkw
37
38 Create a list of the traces you want to see. Some hints:
39
40 1. Put all trace names in quotes.
41 2. Use the same names as you would see in the trace pane of GTKWave
42 3. If a trace is multi-bit, use array notation 'name[max:min]'
43
44 For example:
45
46 traces = [
47 'clk',
48 # prev port
49 'op__sdir', 'p_data_i[7:0]', 'p_shift_i[7:0]', 'p_valid_i', 'p_ready_o',
50 # internal signals
51 'fsm_state', 'count[3:0]', 'shift_reg[7:0]',
52 # next port
53 'n_data_o[7:0]', 'n_valid_o', 'n_ready_i'
54 ]
55
56 Now, create the document:
57
58 write_gtkw("simple.gtkw", "test_shifter.vcd", traces, module='top.shf')
59
60 Remarks:
61
62 1. ``simple.gtkw`` is the name of our GTKWave document
63 2. ``test_shifter.vcd`` is the VCD file
64 3. ``traces`` is a list of trace names
65 4. ``top.shf`` is the hierarchy path of the module
66
67 Now try:
68
69 gtkwave simple.gtkw
70
71 Notice:
72
73 1. No need to press the "zoom to fit" button. The default zoom level is
74 adequate for a 1 MHz clock.
75 2. If you made a mistake, there will be no warning. The trace will
76 simply not appear
77 3. The reload button will only reload the VCD file, not the GTKW document. If you regenerate the document, you need to close and open a
78 new tab, or exit GTKWave and run again: ``gtkwave simple.gtkw``
79 4. If you feel tired of seeing the GTKWave splash window every time,
80 do: ``echo splash_disable 1 >> ~/.gtkwaverc``
81 5. If you modify the document manually, better to save it with another
82 name
83
84 ## Adding color
85
86 Go back to the trace list and replace the ``'op__sdir'`` string with:
87
88 ('op__sdir', {'color': 'orange'})
89
90 Recreate the document (you can change the file name):
91
92 write_gtkw("color.gtkw", "test_shifter.vcd", traces, module='top.shf')
93
94 If you now run ``gtkwave color.gtkw``, you will see that ``op__sdir``
95 has the new color.
96
97 ## Writing GTKWave documents, with style
98
99 Let's say we want all input traces be orange, and all output traces be
100 yellow. To change them one by one, as we did with ``op__sdir``, would be
101 very tedious and verbose. Also, hardcoding the color name will make it
102 difficult to change it later.
103
104 To solve this, lets create a style specification:
105
106 style = {
107 'in': {'color': 'orange'},
108 'out': {'color': 'yellow'}
109 }
110
111 Then, change:
112
113 ('op__sdir', {'color': 'orange'})
114
115 to:
116
117 ('op__sdir', 'in')
118
119 then (notice how we add ``style``):
120
121 write_gtkw("style1.gtkw", "test_shifter.vcd", traces, style, module='top.shf')
122
123 If you now run ``gtkwave style1.gtkw``, you will see that ``op__sdir``
124 still has the new color.
125
126 Let's add more color:
127
128 traces = [
129 'clk',
130 # prev port
131 ('op__sdir', 'in'),
132 ('p_data_i[7:0]', 'in'),
133 ('p_shift_i[7:0]', 'in'),
134 ('p_valid_i', 'in'),
135 ('p_ready_o', 'out'),
136 # internal signals
137 'fsm_state',
138 'count[3:0]',
139 'shift_reg[7:0]',
140 # next port
141 ('n_data_o[7:0]', 'out'),
142 ('n_valid_o', 'out'),
143 ('n_ready_i', 'in'),
144 ]
145
146 Then
147
148 write_gtkw("style2.gtkw", "test_shifter.vcd", traces, style, module='top.shf')
149
150 If you now run ``gtkwave style2.gtkw``, you will see that input, output and internal signals have different color.
151
152 # New signals at simulation time
153
154 At simulation time, you can declare a new signal, and use it inside
155 the test case, as any other signal. By including it in the "traces"
156 parameter of Simulator.write_vcd, it is included in the trace dump
157 file.
158
159 Useful for adding "printf" style debugging for GTKWave.
160
161 # String traces
162
163 When declaring a Signal, you can pass a custom decoder that
164 translates the Signal logic level to a string. nMigen uses this
165 internally to display Enum traces, but it is available for general
166 use.
167
168 Some applications are:
169
170 1. Display a string when a signal is at high level, otherwise show a
171 single horizontal line. Useful to draw attention to a time interval.
172 2. Display the stages of a unit test
173 3. Display arbitrary debug statements along the timeline.
174
175 from the documentation for Signal:
176
177 ```
178 decoder : function or Enum
179 A function converting integer signal values to human-readable
180 strings (e.g. FSM state names). If an ``Enum`` subclass is
181 passed, it is concisely decoded using format string
182 ``"{0.name:}/{0.value:}"``, or a number if the signal value
183 is not a member of the enumeration.
184 ```
185
186 An [example how to do this](https://git.libre-soc.org/?p=nmutil.git;a=blob;f=src/nmutil/test/example_gtkwave.py;h=1b8c3b9c1b0bb5cde23c6896fc5cbde991790384;hb=HEAD#l262):
187
188 ```
189 262 # demonstrates adding extra debug signal traces
190 263 # they end up in the top module
191 264 #
192 265 zero = Signal() # mark an interesting place
193 266 #
194 267 # demonstrates string traces
195 268 #
196 269 # display a message when the signal is high
197 270 # the low level is just an horizontal line
198 271 interesting = Signal(decoder=lambda v: 'interesting!' if v else '')
199 272 # choose between alternate strings based on numerical value
200 273 test_cases = ['', '13>>2', '3<<4', '21<<0']
201 274 test_case = Signal(8, decoder=lambda v: test_cases[v])
202 275 # hack to display arbitrary strings, like debug statements
203 276 msg = Signal(decoder=lambda _: msg.str)
204 277 msg.str = ''
205 ```
206
207 Then, in the Simulation, an arbitrary debug message can be inserted at
208 exactly the right required point. remember to "waggle" the Signal itself
209 so that the Simulation knows to put the change *of the string*
210 into the VCD file:
211
212 ```
213 289 # show current operation operation
214 290 if direction:
215 291 msg.str = f'{data}>>{shift}'
216 292 else:
217 293 msg.str = f'{data}<<{shift}'
218 294 # force dump of the above message by toggling the
219 295 # underlying signal
220 296 yield msg.eq(0)
221 297 yield msg.eq(1)
222 ```
223
224 Also very important is to explicitly add the debug Signal to the
225 gtkwave list of Signals to watch for. As the debug Signal is at
226 the top-level, without them being explicitly added they will be
227 *removed* from the vcd file.
228
229 ```
230 352 sim.add_sync_process(producer)
231 353 sim.add_sync_process(consumer)
232 354 sim_writer = sim.write_vcd(
233 355 "test_shifter.vcd",
234 356 # include additional signals in the trace dump
235 357 traces=[zero, interesting, test_case, msg],
236 358 )
237 359 with sim_writer:
238 360 sim.run()
239 ```
240
241 Here is an [actual practical use](https://git.libre-soc.org/?p=soc.git;a=commitdiff;h=ca3d417a6946dfde083a7c34d76c7572d4132be0)
242 where a "debug_status" message has been added (and toggled) to
243 show the different phases as a unit test progresses. This
244 unit test (MMU Virtual Memory Page-Table fault, and PTE insertion into
245 the I-Cache) is particularly complex and so is a three-stage process
246 that needed some context in order to see which phase of the test
247 is underway.
248
249 [[!img 2021-12-09_20-21.png size="800x" ]]