From 1d4fa2db3d660510ebeceb650188c6fcf3127fd4 Mon Sep 17 00:00:00 2001 From: Cesar Strauss Date: Fri, 14 Aug 2020 08:25:36 -0300 Subject: [PATCH] Demonstrates string traces When declaring a Signal, you can pass a custom decoder that translates the Signal logic level to a string. nMigen uses this internally to display Enum traces, but it is available for general use. Some applications are: 1) Display a string when a signal is at high level, otherwise show a 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. --- src/soc/experiment/alu_fsm.py | 38 ++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/soc/experiment/alu_fsm.py b/src/soc/experiment/alu_fsm.py index 2cdc7c32..9668535a 100644 --- a/src/soc/experiment/alu_fsm.py +++ b/src/soc/experiment/alu_fsm.py @@ -237,6 +237,9 @@ def write_gtkw(base_name, top_dut_name, loc): # change the displayed name in the panel gtkw.trace("top.zero", alias='zero delay shift', color=style_debug) + gtkw.trace("top.interesting", color=style_debug) + gtkw.trace("top.test_case", alias="test case", color=style_debug) + gtkw.trace("top.msg", color=style_debug) with gtkw.group("internal"): gtkw.trace(dut + "fsm_state") gtkw.trace(dut + "count[3:0]") @@ -270,6 +273,18 @@ def test_shifter(): # they end up in the top module # zero = Signal() # mark an interesting place + # + # demonstrates string traces + # + # display a message when the signal is high + # the low level is just an horizontal line + interesting = Signal(decoder=lambda v: 'interesting!' if v else '') + # choose between alternate strings based on numerical value + test_cases = ['', '13>>2', '3<<4', '21<<0'] + test_case = Signal(8, decoder=lambda v: test_cases[v]) + # hack to display arbitrary strings, like debug statements + msg = Signal(decoder=lambda _: msg.str) + msg.str = '' def send(data, shift, direction): # present input data and assert valid_i @@ -281,6 +296,15 @@ def test_shifter(): # wait for p.ready_o to be asserted while not (yield dut.p.ready_o): yield + # show current operation operation + if direction: + msg.str = f'{data}>>{shift}' + else: + msg.str = f'{data}<<{shift}' + # force dump of the above message by toggling the + # underlying signal + yield msg.eq(0) + yield msg.eq(1) # clear input data and negate p.valid_i yield dut.p.valid_i.eq(0) yield dut.p.data_i.data.eq(0) @@ -300,6 +324,10 @@ def test_shifter(): yield dut.n.ready_i.eq(0) # check result assert result == expected + # finish displaying the current operation + msg.str = '' + yield msg.eq(0) + yield msg.eq(1) def producer(): # 13 >> 2 @@ -307,28 +335,36 @@ def test_shifter(): # 3 << 4 yield from send(3, 4, 0) # 21 << 0 + # use a debug signal to mark an interesting operation + # in this case, it is a shift by zero + yield interesting.eq(1) yield from send(21, 0, 0) + yield interesting.eq(0) def consumer(): # the consumer is not in step with the producer, but the # order of the results are preserved # 13 >> 2 = 3 + yield test_case.eq(1) yield from receive(3) # 3 << 4 = 48 + yield test_case.eq(2) yield from receive(48) # 21 << 0 = 21 + yield test_case.eq(3) # you can look for the rising edge of this signal to quickly # locate this point in the traces yield zero.eq(1) yield from receive(21) yield zero.eq(0) + yield test_case.eq(0) sim.add_sync_process(producer) sim.add_sync_process(consumer) sim_writer = sim.write_vcd( "test_shifter.vcd", # include additional signals in the trace dump - traces=[zero] + traces=[zero, interesting, test_case, msg], ) with sim_writer: sim.run() -- 2.30.2