ics-jku / wal

WAL enables programmable waveform analysis.
https://wal-lang.org
BSD 3-Clause "New" or "Revised" License
131 stars 18 forks source link

access signals that are arrays? #28

Closed jiahzhang closed 4 months ago

jiahzhang commented 5 months ago

May be a dumb question, but how does one index into signals that are really SV arrays? This doesn't seem to work:

#array[0].something
LucasKl commented 5 months ago

Hi, I think this depends a bit on how your simulator outputs array elements. For example, Verilator creates a signal arra[0], array[1], etc., for each element of the array. Since in WAL [] gets you bit ranges from a signal, those signal names are translated to array<0>

I just updated WAL's trace readers to improve this., so if you install from the latest main branch, it hopefully works.

jiahzhang commented 5 months ago

I installed from main, and still see the same error

Traceback (most recent call last):
  File "/home/jzhang/.local/bin/wal", line 8, in <module>
    sys.exit(run())
             ^^^^^
  File "/home/jzhang/.local/lib/python3.11/site-packages/wal/wal.py", line 44, in run
    sys.exit(main())
             ^^^^^^
  File "/home/jzhang/.local/lib/python3.11/site-packages/wal/wal.py", line 95, in main
    resolved = resolve(optimized, start=wal.eval_context.global_environment.environment)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jzhang/.local/lib/python3.11/site-packages/wal/passes.py", line 182, in resolve
    return(resolve_vars(expr))
           ^^^^^^^^^^^^^^^^^^
  File "/home/jzhang/.local/lib/python3.11/site-packages/wal/passes.py", line 165, in resolve_vars
    return WList([resolve_vars(sub) for sub in expr], line_info=expr.line_info)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jzhang/.local/lib/python3.11/site-packages/wal/passes.py", line 165, in <listcomp>
    return WList([resolve_vars(sub) for sub in expr], line_info=expr.line_info)
                  ^^^^^^^^^^^^^^^^^
  File "/home/jzhang/.local/lib/python3.11/site-packages/wal/passes.py", line 165, in resolve_vars
    return WList([resolve_vars(sub) for sub in expr], line_info=expr.line_info)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jzhang/.local/lib/python3.11/site-packages/wal/passes.py", line 165, in <listcomp>
    return WList([resolve_vars(sub) for sub in expr], line_info=expr.line_info)
                  ^^^^^^^^^^^^^^^^^
  File "/home/jzhang/.local/lib/python3.11/site-packages/wal/passes.py", line 138, in resolve_vars
    env[binding[0].name] = True
        ~~~~~~~^^^
TypeError: 'Symbol' object is not subscriptable
LucasKl commented 5 months ago

I see. Can you share the trace file or the signal names generated for your array?

jiahzhang commented 5 months ago

I just noticed it fails even if I comment out the array reference. Does this syntax look right to you?

(load "example.vcd")
(in-groups '("something.something.")
  (print CG ":")
  (print SIGNALS)
  (whenever (&& #clk #reset_n)
    (let [d 0]
     (print "d: " d)
    )
  )
)
LucasKl commented 5 months ago

You miss a pair of parentheses in the let. But that is probably my fault, I didn't keep the documentation up to date (fixed that now too).

(load "example.vcd")
(in-groups '("something.something.")
  (print CG ":")
  (print SIGNALS)
  (whenever (&& #clk #reset_n)
    (let ([d 0])
     (print "d: " d))))

With the parentheses and the counter example trace I get:

something.something.:
("tb.overflow" "tb.clk" "tb.reset" "tb._tmp" "tb.dut.clk" "tb.dut.reset" "tb.dut.overflow" "tb.dut.counter")
jiahzhang commented 5 months ago

Runs now thanks. I'll close this issue.

LucasKl commented 5 months ago

Great. If anything else comes up, feel free to contact me.

jiahzhang commented 5 months ago

Actually when I try to access a signal within the array of structs I just see a bunch of Nones. Any ideas? It works fine when I print like like an integer from the top-level -- not within the array (print #clocks)

jiahzhang commented 5 months ago

@LucasKl FWIW, this does work

(in-scope "something" (print #something))

so maybe something wrong with the frontend parsing?

jiahzhang commented 5 months ago

and this doesn't

(in-scope "something.something" (print #something))
LucasKl commented 5 months ago

There are two systems for evaluating signals at different places. Scopes and groups. They work similarly but require different operators to resolve a signal.

If you use groups you need to use #signal, and if you use scopes you need to use ~signal.

So try either (in-scope "something.something" (print ~something)) or (in-group "something.something." (print #something)). Please note the added . for the group (scopes add the dot automatically).

jiahzhang commented 5 months ago

I don't think either works, are we allowed to nest in-group/in-scope within another in-groups for example? Also, in general, whether in-scope or in-group I can't access fields within a struct

LucasKl commented 5 months ago

In WAL there are no structs, only signals from the waveform. How structs are mapped to signals is up to the simulator. If you can produce a minimal example, I can try to improve support for your use-case.

jiahzhang commented 5 months ago

It just looks like

struct obj {
  logic [2:0] something;
}

struct obj2 {
  obj data;
}

What's confusing is the SIGNALS represents this how I would expect (.'s). But it doesn't get picked up when running. Perhaps it would be helpful if it does some fuzzy search on available variable names within the scope and/or outside of the scope to figure out what the var name should look like in WAL.

jiahzhang commented 5 months ago

also why do undeclared signals return None values? Would it be better to throw an error? Let me know if you'd like help implementing these if you think they might take a while to add support for.

LucasKl commented 4 months ago

Ok, I spend a little more time with SV arrays and structs. This is something which I have not worked with much in the past. I simulated the following code using Verilator:

typedef struct {
  logic [2:0] something;
} obj;

typedef struct {
  obj data;
} obj2;

module tb();
  obj2 data [0:1];

  initial begin
    $dumpfile("trace.vcd");
    $dumpvars;
    data[0].data.something = 3'b101;
    #10
    data[0].data.something = 3'b010;
  end
endmodule

And then got this vcd:

$version Generated by VerilatedVcd $end
$timescale 1ps $end

 $scope module TOP $end
  $scope module tb $end
   $scope module data[0] $end
    $scope module data $end
     $var wire  3 # something [2:0] $end
    $upscope $end
   $upscope $end
   $scope module data[1] $end
    $scope module data $end
     $var wire  3 $ something [2:0] $end
    $upscope $end
   $upscope $end
  $upscope $end
 $upscope $end
$enddefinitions $end

#0
b101 #
b000 $
#10
b010 #

This already mostly worked as expected. I only had to slighlty correct the handling of scopes names in commit b7972b7.

Now WAL behaves like this:

WAL 0.8.1
Exit to OS or terminate running evaluations with CTRL-C
>-> (load "trace.vcd")
t0(0) >-> SIGNALS
("TOP.tb.data<0>.data.something" "TOP.tb.data<1>.data.something")
t0(0) >-> SCOPES
("TOP" "TOP.tb" "TOP.tb.data<0>" "TOP.tb.data<0>.data" "TOP.tb.data<1>" "TOP.tb.data<1>.data")
t0(0) >-> TOP.tb.data<0>.data.something
5
t0(0) >-> (in-scope 'TOP.tb.data<0>.data ~something)
5
t0(0) >->

WAL will now also throw an error if a scope or group resolution leads to an undefined signal. Thanks for the pointer.

LucasKl commented 4 months ago

Can you try the latest commit and let me know if that works for you? I have not used much "advanced SystemVerilog" constructs, so I am very happy to hear your comments.

jiahzhang commented 4 months ago

Works great now thanks