bug 1034: making room for crfbinlog/crfternlogi/crbinlog/crternlogi
[libreriscv.git] / docs / gtkwave_tutorial.mdwn
index 6a1132d11e92e6f0d232389d6e57e868ee005032..d2832e3787dc9767df489b6a40aa49bd23048394 100644 (file)
@@ -1,10 +1,14 @@
 [[!img 2020-08-15_12-04.png size="800x" ]]
 
-This tutorial is about generating better GTKWave documents (*.gtkw)
+This tutorial is about generating better GTKWave documents (\*.gtkw)
 from Python. The goal is to ease analysis of traces generated by
 unit-tests, and at the same time to better understand the inner working
 of modules, for which we are writing such tests.
 
+There is a FOSDEM 2022 talk about writing GTKwave documents, with style,
+<https://fosdem.org/2022/schedule/event/gtkwavecss/>
+<https://video.fosdem.org/2022/D.open-hardware/gtkwavecss.webm>
+
 # Stylish GTKWave Documents
 
 In this tutorial, you will learn how to:
@@ -46,11 +50,11 @@ For example:
     traces = [
         'clk',
         # prev port
-        'op__sdir', 'p_data_i[7:0]', 'p_shift_i[7:0]', 'p_valid_i', 'p_ready_o',
+        'op__sdir', 'p_i_data[7:0]', 'p_i_shift[7:0]', 'p_i_valid', 'p_o_ready',
         # internal signals
         'fsm_state', 'count[3:0]', 'shift_reg[7:0]',
         # next port
-        'n_data_o[7:0]', 'n_valid_o', 'n_ready_i'
+        'n_o_data[7:0]', 'n_o_valid', 'n_i_ready'
     ]
 
 Now, create the document:
@@ -73,7 +77,7 @@ Notice:
 1. No need to press the "zoom to fit" button. The default zoom level is
 adequate for a 1 MHz clock.
 2. If you made a mistake, there will be no warning. The trace will
-simply not appear
+simply not appear (*the properties of the dropped trace will be given to the next signal, be careful*)
 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
 new tab, or exit GTKWave and run again: ``gtkwave simple.gtkw``
 4. If you feel tired of seeing the GTKWave splash window every time,
@@ -129,18 +133,18 @@ Let's add more color:
         'clk',
         # prev port
         ('op__sdir', 'in'),
-        ('p_data_i[7:0]', 'in'),
-        ('p_shift_i[7:0]', 'in'),
-        ('p_valid_i', 'in'),
-        ('p_ready_o', 'out'),
+        ('p_i_data[7:0]', 'in'),
+        ('p_i_shift[7:0]', 'in'),
+        ('p_i_valid', 'in'),
+        ('p_o_ready', 'out'),
         # internal signals
         'fsm_state',
         'count[3:0]',
         'shift_reg[7:0]',
         # next port
-        ('n_data_o[7:0]', 'out'),
-        ('n_valid_o', 'out'),
-        ('n_ready_i', 'in'),
+        ('n_o_data[7:0]', 'out'),
+        ('n_o_valid', 'out'),
+        ('n_i_ready', 'in'),
     ]
 
 Then
@@ -171,3 +175,79 @@ Some applications are:
    single horizontal line. Useful to draw attention to a time interval.
 2. Display the stages of a unit test
 3. Display arbitrary debug statements along the timeline.
+
+from the documentation for Signal:
+
+```
+    decoder : function or Enum
+        A function converting integer signal values to human-readable
+        strings (e.g. FSM state names). If an ``Enum`` subclass is
+        passed, it is concisely decoded using format string
+        ``"{0.name:}/{0.value:}"``, or a number if the signal value
+        is not a member of the enumeration.
+```
+
+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):
+
+```
+ 262     # demonstrates adding extra debug signal traces
+ 263     # they end up in the top module
+ 264     #
+ 265     zero = Signal()  # mark an interesting place
+ 266     #
+ 267     # demonstrates string traces
+ 268     #
+ 269     # display a message when the signal is high
+ 270     # the low level is just an horizontal line
+ 271     interesting = Signal(decoder=lambda v: 'interesting!' if v else '')
+ 272     # choose between alternate strings based on numerical value
+ 273     test_cases = ['', '13>>2', '3<<4', '21<<0']
+ 274     test_case = Signal(8, decoder=lambda v: test_cases[v])
+ 275     # hack to display arbitrary strings, like debug statements
+ 276     msg = Signal(decoder=lambda _: msg.str)
+ 277     msg.str = ''
+```
+
+Then, in the Simulation, an arbitrary debug message can be inserted at
+exactly the right required point.  remember to "waggle" the Signal itself
+so that the Simulation knows to put the change *of the string*
+into the VCD file:
+
+```
+ 289         # show current operation operation
+ 290         if direction:
+ 291             msg.str = f'{data}>>{shift}'
+ 292         else:
+ 293             msg.str = f'{data}<<{shift}'
+ 294         # force dump of the above message by toggling the
+ 295         # underlying signal
+ 296         yield msg.eq(0)
+ 297         yield msg.eq(1)
+```
+
+Also very important is to explicitly add the debug Signal to the
+gtkwave list of Signals to watch for.  As the debug Signal is at
+the top-level, without them being explicitly added they will be
+*removed* from the vcd file.
+
+```
+ 352     sim.add_sync_process(producer)
+ 353     sim.add_sync_process(consumer)
+ 354     sim_writer = sim.write_vcd(
+ 355         "test_shifter.vcd",
+ 356         # include additional signals in the trace dump
+ 357         traces=[zero, interesting, test_case, msg],
+ 358     )
+ 359     with sim_writer:
+ 360         sim.run()
+```
+
+Here is an [actual practical use](https://git.libre-soc.org/?p=soc.git;a=commitdiff;h=ca3d417a6946dfde083a7c34d76c7572d4132be0)
+where a "debug_status" message has been added (and toggled) to
+show the different phases as a unit test progresses.  This
+unit test (MMU Virtual Memory Page-Table fault, and PTE insertion into
+the I-Cache) is particularly complex and so is a three-stage process
+that needed some context in order to see which phase of the test
+is underway.
+
+[[!img 2021-12-09_20-21.png size="800x" ]]