diff --git a/tests/test_trace_eq.py b/tests/test_trace_eq.py index 743afe3..40b13db 100644 --- a/tests/test_trace_eq.py +++ b/tests/test_trace_eq.py @@ -59,6 +59,41 @@ def test_rising_clocks(self): def test_overflow(self): self.eval_eq('(count tb.overflow') + def test_signals(self): + self.eval_eq('SIGNALS') + + def test_scopes(self): + self.eval_eq('SCOPES') + + def test_local_scopes(self): + self.eval_eq('LOCAL-SCOPES') + self.eval_eq("(in-scope 'tb CS)") + self.eval_eq("(in-scope 'tb LOCAL-SCOPES)") + + def test_local_signals(self): + wal = "(in-scope 'tb LOCAL-SIGNALS)" + res = list(map(lambda t: self.wal_eval([t, wal]), self.traces)) + + for pair in combinations(res, 2): + self.assertEqual(sorted(pair[0]), sorted(pair[1])) + + +class SVArrayEqualTest(TraceEqTest, unittest.TestCase): + '''Test counter traces for equality''' + + def setUp(self): + self.traces = ['sv_struct_array.vcd', 'sv_struct_array.fst'] + super().setUp() + + def test_group_clk(self): + self.eval_eq('(groups something)') + + def test_signals(self): + self.eval_eq('SIGNALS') + + def test_scopes(self): + self.eval_eq('SCOPES') + def test_local_scopes(self): self.eval_eq('LOCAL-SCOPES') self.eval_eq("(in-scope 'tb CS)") diff --git a/tests/test_trace_reader.py b/tests/test_trace_reader.py index e09a5f3..9e17048 100644 --- a/tests/test_trace_reader.py +++ b/tests/test_trace_reader.py @@ -2,6 +2,7 @@ import unittest from wal.core import Wal +from wal.ast_defs import WalEvalError class BasicParserTest(unittest.TestCase): '''Test trace readers''' @@ -10,6 +11,24 @@ def test_sv_arrays(self): '''Test SystemVerilog arrays''' for trace_format in ['vcd', 'fst']: wal = Wal() - wal.load(f'tests/traces/array.{trace_format}') - self.assertEqual(wal.eval_str('TOP.tb.data<0>'), 2) - self.assertEqual(wal.eval_str('TOP.tb.data<1>'), 0) + wal.load(f'tests/traces/sv_struct_array.{trace_format}') + self.assertEqual(wal.eval_str('TOP.tb.data<0>.data.something'), 5) + + +class ReadUndefinedSignalTest(unittest.TestCase): + '''Test trace readers''' + + def test_read_undefined_signals(self): + '''Test SystemVerilog arrays''' + for trace_format in ['vcd', 'fst']: + wal = Wal() + wal.load(f'tests/traces/sv_struct_array.{trace_format}') + + with self.assertRaises(WalEvalError): + wal.eval_str('TOP.tb.data<0>.wrongname') + + with self.assertRaises(WalEvalError): + wal.eval_str('(in-scope "TOP.tb.data<0>" ~wrongname)') + + with self.assertRaises(WalEvalError): + wal.eval_str('(in-group "TOP.tb.data<0>" #.wrongname)') diff --git a/tests/traces/array.fst b/tests/traces/array.fst deleted file mode 100644 index d6b3325..0000000 Binary files a/tests/traces/array.fst and /dev/null differ diff --git a/tests/traces/array.vcd b/tests/traces/array.vcd deleted file mode 100644 index c55f8cf..0000000 --- a/tests/traces/array.vcd +++ /dev/null @@ -1,33 +0,0 @@ -$version Generated by VerilatedVcd $end -$timescale 1ps $end - - $scope module TOP $end - $scope module tb $end - $var wire 8 # data[0] [7:0] $end - $var wire 8 $ data[1] [7:0] $end - $var wire 8 % data[2] [7:0] $end - $var wire 8 & data[3] [7:0] $end - $var wire 8 ' data[4] [7:0] $end - $var wire 8 ( data[5] [7:0] $end - $var wire 8 ) data[6] [7:0] $end - $var wire 8 * data[7] [7:0] $end - $var wire 8 + data[8] [7:0] $end - $var wire 8 , data[9] [7:0] $end - $upscope $end - $upscope $end -$enddefinitions $end - - -#0 -b00000010 # -b00000000 $ -b00000000 % -b00000000 & -b00000000 ' -b00000000 ( -b00000000 ) -b00000000 * -b00000000 + -b00000000 , -#10 -b00000100 # diff --git a/tests/traces/sv_struct_array.fst b/tests/traces/sv_struct_array.fst new file mode 100644 index 0000000..6131c47 Binary files /dev/null and b/tests/traces/sv_struct_array.fst differ diff --git a/tests/traces/sv_struct_array.vcd b/tests/traces/sv_struct_array.vcd new file mode 100644 index 0000000..9804a80 --- /dev/null +++ b/tests/traces/sv_struct_array.vcd @@ -0,0 +1,25 @@ +$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 # diff --git a/wal/implementation/core.py b/wal/implementation/core.py index 9b2e34b..45850ac 100644 --- a/wal/implementation/core.py +++ b/wal/implementation/core.py @@ -431,10 +431,8 @@ def op_resolve_scope(seval, args): else: # if scope is not a real scope it must be a group name, no dot required name = seval.global_environment.read('CS') + args[0].name - if seval.traces.contains(name): - return seval.traces.signal_value(name) - - return None + assert seval.traces.contains(name), f'resolve-scope: No signal with name "{name}"' + return seval.traces.signal_value(name) def op_set_scope(seval, args): @@ -542,10 +540,8 @@ def op_resolve_group(seval, args): name = seval.group + args[0].name - if seval.traces.contains(name): - return seval.traces.signal_value(name) - - return None + assert seval.traces.contains(name), f'resolve-group: No signal with name "{name}"' + return seval.traces.signal_value(name) def op_slice(seval, args): diff --git a/wal/trace/fst.py b/wal/trace/fst.py index d7403c3..5087d10 100644 --- a/wal/trace/fst.py +++ b/wal/trace/fst.py @@ -22,6 +22,12 @@ def __init__(self, file, tid, container, from_string=False, keep_signals=None): (self.scopes, signals) = fst.get_scopes_signals2(self.fst) self.references_to_ids = signals.by_name + # rename grouped scopes + self.scopes = [ + re.sub(r'\(([0-9]+)\)', r'<\1>', scope) for scope in self.scopes] + self.scopes = [ + re.sub(r'\[([0-9]+)\]', r'<\1>', scope) for scope in self.scopes] + # get mapping from name to tid and remove trailing signal width, ' [31:0]' etc. self.references_to_ids = {re.sub(r' *\[\d+:\d+\]', '', k): v for k, v in self.references_to_ids.items()} diff --git a/wal/trace/vcd.py b/wal/trace/vcd.py index 56bbb7c..639bbe5 100644 --- a/wal/trace/vcd.py +++ b/wal/trace/vcd.py @@ -41,7 +41,13 @@ def parse(self, vcddata): # header section while (not header_done) and tokens: if tokens[i] == '$scope': - scope.append(tokens[i + 2]) + name = tokens[i + 2] + + # array entries should not clash with WAL operators + name = re.sub(r'\[([0-9]+)\]', r'<\1>', name) + name = re.sub(r'\(([0-9]+)\)', r'<\1>', name) + + scope.append(name) self.scopes.append('.'.join(scope)) i += 4 elif tokens[i] == '$var':