diff --git a/test_regress/driver.py b/test_regress/driver.py index ec61e0534..c7335c9f6 100755 --- a/test_regress/driver.py +++ b/test_regress/driver.py @@ -66,6 +66,142 @@ class staticproperty(property): def __get__(self, owner_self, owner_cls): return self.fget() +####################################################################### +####################################################################### +# SAIF parser utilities + + +class SAIFSignalBit: + def __init__(self): + self.last_val = 0 + self.high_time = 0 + self.low_time = 0 + self.transitions = 0 + + def aggregate(self, dt, new_val): + if int(new_val) != int(self.last_val): + self.transitions += 1 + + if self.last_val: + self.high_time += dt + + self.last_val = new_val + +class SAIFSignal: + def __init__(self, signal_name, signal_width = 0): + self.name = signal_name + self.width = signal_width + self.last_time = 0 + + self.bits = [] + for _ in range(self.width): + self.bits.append(SAIFSignalBit()) + + +class VCDToSAIFParser: + def __init__(self): + self.signal_definitions = {} + self.signal_indirections = {} + self.current_time = 0 + + def parse(self, vcd_filename): + with open(vcd_filename, 'r') as vcd_file: + for line in vcd_file: + line = line.strip() + if not line: + continue + + match = re.match(r'\$var\s+(\w+)\s+(\d+)\s+(\S+)\s+(\S+)\s*(\S*)\s*\$end', line) + if match: + _, signal_width, signal_id, signal_name, _ = match.groups() + if signal_id in self.signal_indirections: + continue + + self.signal_indirections[signal_id] = signal_name + self.signal_definitions[signal_name] = SAIFSignal(signal_name, int(signal_width)) + continue + + match = re.match(r'\#(\d+)', line) + if match: + timestamp = match.groups() + self.current_time = int(timestamp[0]) + continue + + match = re.match(r'b(\d+)\s+(\S+)', line) + if match: + value, signal_id = match.groups() + + dt = self.current_time - self.signal_definitions[self.signal_indirections[signal_id]].last_time + self.signal_definitions[self.signal_indirections[signal_id]].last_time = self.current_time + + index = 0 + for bit in reversed(value): + self.signal_definitions[self.signal_indirections[signal_id]].bits[index].aggregate(dt, int(bit)) + index += 1 + + continue + + match = re.match(r'(\d+)(\S+)', line) + if match: + value, signal_id = match.groups() + + dt = self.current_time - self.signal_definitions[self.signal_indirections[signal_id]].last_time + self.signal_definitions[self.signal_indirections[signal_id]].last_time = self.current_time + + self.signal_definitions[self.signal_indirections[signal_id]].bits[0].aggregate(dt, int(value)) + + for _, signal in self.signal_definitions.items(): + for i in range(signal.width): + if signal.bits[i].last_val == 1: + signal.bits[i].high_time += self.current_time - signal.last_time + + signal.bits[i].low_time = self.current_time - signal.bits[i].high_time + + +class SAIFParser: + def __init__(self): + self.signal_definitions = {} + + def parse(self, saif_filename): + with open(saif_filename, 'r') as saif_file: + for line in saif_file: + line = line.strip() + if not line: + continue + + match = re.search(r'(\w+)\[*(\d*)\]*\s+(\(T(.+)\))+', line) + if match: + signal_name, bit_index, bit_values, _ = match.groups() + + if bit_index == '': + bit_index = 0 + + if signal_name not in self.signal_definitions: + self.signal_definitions[signal_name] = SAIFSignal(signal_name) + + for _ in range(0, int(bit_index) - self.signal_definitions[signal_name].width + 1): + self.signal_definitions[signal_name].bits.append(SAIFSignalBit()) + + self.signal_definitions[signal_name].width = int(bit_index) + 1 + + match = re.search(r'T0 (\d+)', bit_values) + if match: + low_time = match.groups()[0] + + self.signal_definitions[signal_name].bits[int(bit_index)].low_time = low_time + + match = re.search(r'T1 (\d+)', bit_values) + if match: + high_time = match.groups()[0] + + self.signal_definitions[signal_name].bits[int(bit_index)].high_time = high_time + + match = re.search(r'TC (\d+)', bit_values) + if match: + toggle_count = match.groups()[0] + + self.signal_definitions[signal_name].bits[int(bit_index)].transitions = toggle_count + ####################################################################### ####################################################################### @@ -2368,9 +2504,38 @@ class VlTest: self.fst2vcd(fn1, tmp) self.vcd_identical(tmp, fn2) + def compare_saif_contents(self, first, second): + # Golden SAIF contents object should have all bits declared, even if zero transitions + for signal_name, signal in first.signal_definitions.items(): + tested_object_signal = second.signal_definitions[signal_name] + + for bit in range(signal.width): + golden_bit = signal.bits[bit] + + valid_signal_width = tested_object_signal.width > bit + + if int(golden_bit.transitions) <= 0 and valid_signal_width and int(tested_object_signal.bits[bit].transitions) > 0: + print(f"{signal.name}[{bit}] (T0 {golden_bit.low_time}) (T1 {golden_bit.high_time}) (TC {golden_bit.transitions})") + print(f"{signal.name}[{bit}] (T0 {tested_object_signal.bits[bit].low_time}) (T1 {tested_object_signal.bits[bit].high_time}) (TC {tested_object_signal.bits[bit].transitions})") + self.error("Transitions number mismatch!\n") + + if valid_signal_width: + tested_bit = tested_object_signal.bits[bit] + if int(golden_bit.transitions) != int(tested_bit.transitions) or int(golden_bit.high_time) != int(tested_bit.high_time) or int(golden_bit.low_time) != int(tested_bit.low_time): + print(f"{signal.name}[{bit}] (T0 {golden_bit.low_time}) (T1 {golden_bit.high_time}) (TC {golden_bit.transitions})") + print(f"{signal.name}[{bit}] (T0 {tested_bit.low_time}) (T1 {tested_bit.high_time}) (TC {tested_bit.transitions})") + self.error("Signal bit mismatch!\n") + + def saif_identical(self, fn1: str, fn2: str) -> None: """Test if two SAIF files have logically-identical contents""" - #TODO: implement checking if two SAIF file are logically-identical + vcd_to_saif_parser = VCDToSAIFParser() + vcd_to_saif_parser.parse(fn2) + + saif_parser = SAIFParser() + saif_parser.parse(fn1) + + self.compare_saif_contents(vcd_to_saif_parser, saif_parser) def _vcd_read(self, filename: str) -> str: data = {} diff --git a/test_regress/t/t_trace_counter.out b/test_regress/t/t_trace_counter.out new file mode 100644 index 000000000..e19aa8109 --- /dev/null +++ b/test_regress/t/t_trace_counter.out @@ -0,0 +1,625 @@ +$version Generated by VerilatedVcd $end +$timescale 1ps $end + $scope module top $end + $var wire 1 # clk $end + $var wire 8 $ state [7:0] $end + $scope module t $end + $var wire 1 # clk $end + $var wire 1 % rst $end + $var wire 8 $ state [7:0] $end + $var wire 32 & cyc [31:0] $end + $scope module c0 $end + $var wire 1 # clk $end + $var wire 1 % rst $end + $var wire 8 $ out [7:0] $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +0# +b00000000 $ +0% +b00000000000000000000000000000000 & +#10 +1# +1% +b00000000000000000000000000000001 & +#15 +0# +#20 +1# +b00000001 $ +b00000000000000000000000000000010 & +#25 +0# +#30 +1# +b00000010 $ +b00000000000000000000000000000011 & +#35 +0# +#40 +1# +b00000011 $ +b00000000000000000000000000000100 & +#45 +0# +#50 +1# +b00000100 $ +b00000000000000000000000000000101 & +#55 +0# +#60 +1# +b00000101 $ +b00000000000000000000000000000110 & +#65 +0# +#70 +1# +b00000110 $ +b00000000000000000000000000000111 & +#75 +0# +#80 +1# +b00000111 $ +b00000000000000000000000000001000 & +#85 +0# +#90 +1# +b00001000 $ +b00000000000000000000000000001001 & +#95 +0# +#100 +1# +b00001001 $ +b00000000000000000000000000001010 & +#105 +0# +#110 +1# +b00001010 $ +0% +b00000000000000000000000000001011 & +#115 +0# +#120 +1# +b00000000 $ +1% +b00000000000000000000000000001100 & +#125 +0# +#130 +1# +b00000001 $ +b00000000000000000000000000001101 & +#135 +0# +#140 +1# +b00000010 $ +b00000000000000000000000000001110 & +#145 +0# +#150 +1# +b00000011 $ +b00000000000000000000000000001111 & +#155 +0# +#160 +1# +b00000100 $ +b00000000000000000000000000010000 & +#165 +0# +#170 +1# +b00000101 $ +b00000000000000000000000000010001 & +#175 +0# +#180 +1# +b00000110 $ +b00000000000000000000000000010010 & +#185 +0# +#190 +1# +b00000111 $ +b00000000000000000000000000010011 & +#195 +0# +#200 +1# +b00001000 $ +b00000000000000000000000000010100 & +#205 +0# +#210 +1# +b00001001 $ +b00000000000000000000000000010101 & +#215 +0# +#220 +1# +b00001010 $ +b00000000000000000000000000010110 & +#225 +0# +#230 +1# +b00001011 $ +b00000000000000000000000000010111 & +#235 +0# +#240 +1# +b00001100 $ +b00000000000000000000000000011000 & +#245 +0# +#250 +1# +b00001101 $ +b00000000000000000000000000011001 & +#255 +0# +#260 +1# +b00001110 $ +b00000000000000000000000000011010 & +#265 +0# +#270 +1# +b00001111 $ +b00000000000000000000000000011011 & +#275 +0# +#280 +1# +b00010000 $ +b00000000000000000000000000011100 & +#285 +0# +#290 +1# +b00010001 $ +b00000000000000000000000000011101 & +#295 +0# +#300 +1# +b00010010 $ +b00000000000000000000000000011110 & +#305 +0# +#310 +1# +b00010011 $ +b00000000000000000000000000011111 & +#315 +0# +#320 +1# +b00010100 $ +b00000000000000000000000000100000 & +#325 +0# +#330 +1# +b00010101 $ +b00000000000000000000000000100001 & +#335 +0# +#340 +1# +b00010110 $ +b00000000000000000000000000100010 & +#345 +0# +#350 +1# +b00010111 $ +b00000000000000000000000000100011 & +#355 +0# +#360 +1# +b00011000 $ +b00000000000000000000000000100100 & +#365 +0# +#370 +1# +b00011001 $ +b00000000000000000000000000100101 & +#375 +0# +#380 +1# +b00011010 $ +b00000000000000000000000000100110 & +#385 +0# +#390 +1# +b00011011 $ +b00000000000000000000000000100111 & +#395 +0# +#400 +1# +b00011100 $ +b00000000000000000000000000101000 & +#405 +0# +#410 +1# +b00011101 $ +b00000000000000000000000000101001 & +#415 +0# +#420 +1# +b00011110 $ +b00000000000000000000000000101010 & +#425 +0# +#430 +1# +b00011111 $ +b00000000000000000000000000101011 & +#435 +0# +#440 +1# +b00100000 $ +b00000000000000000000000000101100 & +#445 +0# +#450 +1# +b00100001 $ +b00000000000000000000000000101101 & +#455 +0# +#460 +1# +b00100010 $ +b00000000000000000000000000101110 & +#465 +0# +#470 +1# +b00100011 $ +b00000000000000000000000000101111 & +#475 +0# +#480 +1# +b00100100 $ +b00000000000000000000000000110000 & +#485 +0# +#490 +1# +b00100101 $ +b00000000000000000000000000110001 & +#495 +0# +#500 +1# +b00100110 $ +b00000000000000000000000000110010 & +#505 +0# +#510 +1# +b00100111 $ +b00000000000000000000000000110011 & +#515 +0# +#520 +1# +b00101000 $ +b00000000000000000000000000110100 & +#525 +0# +#530 +1# +b00101001 $ +b00000000000000000000000000110101 & +#535 +0# +#540 +1# +b00101010 $ +b00000000000000000000000000110110 & +#545 +0# +#550 +1# +b00101011 $ +b00000000000000000000000000110111 & +#555 +0# +#560 +1# +b00101100 $ +b00000000000000000000000000111000 & +#565 +0# +#570 +1# +b00101101 $ +b00000000000000000000000000111001 & +#575 +0# +#580 +1# +b00101110 $ +b00000000000000000000000000111010 & +#585 +0# +#590 +1# +b00101111 $ +b00000000000000000000000000111011 & +#595 +0# +#600 +1# +b00110000 $ +b00000000000000000000000000111100 & +#605 +0# +#610 +1# +b00110001 $ +b00000000000000000000000000111101 & +#615 +0# +#620 +1# +b00110010 $ +b00000000000000000000000000111110 & +#625 +0# +#630 +1# +b00110011 $ +b00000000000000000000000000111111 & +#635 +0# +#640 +1# +b00110100 $ +b00000000000000000000000001000000 & +#645 +0# +#650 +1# +b00110101 $ +b00000000000000000000000001000001 & +#655 +0# +#660 +1# +b00110110 $ +b00000000000000000000000001000010 & +#665 +0# +#670 +1# +b00110111 $ +b00000000000000000000000001000011 & +#675 +0# +#680 +1# +b00111000 $ +b00000000000000000000000001000100 & +#685 +0# +#690 +1# +b00111001 $ +b00000000000000000000000001000101 & +#695 +0# +#700 +1# +b00111010 $ +b00000000000000000000000001000110 & +#705 +0# +#710 +1# +b00111011 $ +b00000000000000000000000001000111 & +#715 +0# +#720 +1# +b00111100 $ +b00000000000000000000000001001000 & +#725 +0# +#730 +1# +b00111101 $ +b00000000000000000000000001001001 & +#735 +0# +#740 +1# +b00111110 $ +b00000000000000000000000001001010 & +#745 +0# +#750 +1# +b00111111 $ +b00000000000000000000000001001011 & +#755 +0# +#760 +1# +b01000000 $ +b00000000000000000000000001001100 & +#765 +0# +#770 +1# +b01000001 $ +b00000000000000000000000001001101 & +#775 +0# +#780 +1# +b01000010 $ +b00000000000000000000000001001110 & +#785 +0# +#790 +1# +b01000011 $ +b00000000000000000000000001001111 & +#795 +0# +#800 +1# +b01000100 $ +b00000000000000000000000001010000 & +#805 +0# +#810 +1# +b01000101 $ +b00000000000000000000000001010001 & +#815 +0# +#820 +1# +b01000110 $ +b00000000000000000000000001010010 & +#825 +0# +#830 +1# +b01000111 $ +b00000000000000000000000001010011 & +#835 +0# +#840 +1# +b01001000 $ +b00000000000000000000000001010100 & +#845 +0# +#850 +1# +b01001001 $ +b00000000000000000000000001010101 & +#855 +0# +#860 +1# +b01001010 $ +b00000000000000000000000001010110 & +#865 +0# +#870 +1# +b01001011 $ +b00000000000000000000000001010111 & +#875 +0# +#880 +1# +b01001100 $ +b00000000000000000000000001011000 & +#885 +0# +#890 +1# +b01001101 $ +b00000000000000000000000001011001 & +#895 +0# +#900 +1# +b01001110 $ +b00000000000000000000000001011010 & +#905 +0# +#910 +1# +b01001111 $ +b00000000000000000000000001011011 & +#915 +0# +#920 +1# +b01010000 $ +b00000000000000000000000001011100 & +#925 +0# +#930 +1# +b01010001 $ +b00000000000000000000000001011101 & +#935 +0# +#940 +1# +b01010010 $ +b00000000000000000000000001011110 & +#945 +0# +#950 +1# +b01010011 $ +b00000000000000000000000001011111 & +#955 +0# +#960 +1# +b01010100 $ +b00000000000000000000000001100000 & +#965 +0# +#970 +1# +b01010101 $ +b00000000000000000000000001100001 & +#975 +0# +#980 +1# +b01010110 $ +b00000000000000000000000001100010 & +#985 +0# +#990 +1# +b01010111 $ +b00000000000000000000000001100011 & +#995 +0# +#1000 +1# +b01011000 $ +b00000000000000000000000001100100 & diff --git a/test_regress/vcd_to_saif.py b/test_regress/vcd_to_saif.py deleted file mode 100644 index 0d1a23a7f..000000000 --- a/test_regress/vcd_to_saif.py +++ /dev/null @@ -1,148 +0,0 @@ -import re -from collections import defaultdict - -class SAIFSignalBit: - def __init__(self): - self.last_val = 0 - self.high_time = 0 - self.low_time = 0 - self.transitions = 0 - - def aggregate(self, dt, new_val): - if int(new_val) != int(self.last_val): - self.transitions += 1 - - if self.last_val: - self.high_time += dt - - self.last_val = new_val - -class SAIFSignal: - def __init__(self, signal_name, signal_width = 0): - self.name = signal_name - self.width = signal_width - self.last_time = 0 - - self.bits = [] - for _ in range(self.width): - self.bits.append(SAIFSignalBit()) - - -class VCDToSAIFParser: - def __init__(self): - self.signal_definitions = {} - self.signal_indirections = {} - self.current_time = 0 - - def parse(self, vcd_filename): - with open(vcd_filename, 'r') as vcd_file: - for line in vcd_file: - line = line.strip() - if not line: - continue - - match = re.match(r'\$var\s+(\w+)\s+(\d+)\s+(\S+)\s+(\S+)\s*(\S*)\s*\$end', line) - if match: - _, signal_width, signal_id, signal_name, _ = match.groups() - self.signal_indirections[signal_id] = signal_name - self.signal_definitions[signal_name] = SAIFSignal(signal_name, int(signal_width)) - continue - - match = re.match(r'\#(\d+)', line) - if match: - timestamp = match.groups() - self.current_time = int(timestamp[0]) - continue - - match = re.match(r'b(\d+)\s+(\S+)', line) - if match: - value, signal_id = match.groups() - - dt = self.current_time - self.signal_definitions[self.signal_indirections[signal_id]].last_time - self.signal_definitions[self.signal_indirections[signal_id]].last_time = self.current_time - - index = 0 - for bit in reversed(value): - self.signal_definitions[self.signal_indirections[signal_id]].bits[index].aggregate(dt, int(bit)) - index += 1 - - continue - - match = re.match(r'(\d+)(\S+)', line) - if match: - value, signal_id = match.groups() - - dt = self.current_time - self.signal_definitions[self.signal_indirections[signal_id]].last_time - self.signal_definitions[self.signal_indirections[signal_id]].last_time = self.current_time - - self.signal_definitions[self.signal_indirections[signal_id]].bits[0].aggregate(dt, int(value)) - - for _, signal in self.signal_definitions.items(): - for i in range(signal.width): - if signal.bits[i].last_val == 1: - signal.bits[i].high_time += self.current_time - signal.last_time - - signal.bits[i].low_time = self.current_time - signal.bits[i].high_time - - -class SAIFParser: - def __init__(self): - self.signal_definitions = {} - - def parse(self, saif_filename): - with open(saif_filename, 'r') as saif_file: - for line in saif_file: - line = line.strip() - if not line: - continue - - match = re.search(r'(\w+)\[*(\d*)\]*\s+(\(T(.+)\))+', line) - if match: - signal_name, bit_index, bit_values, _ = match.groups() - - if bit_index == '': - bit_index = 0 - - if signal_name not in self.signal_definitions: - self.signal_definitions[signal_name] = SAIFSignal(signal_name) - - for _ in range(0, int(bit_index) - self.signal_definitions[signal_name].width + 1): - self.signal_definitions[signal_name].bits.append(SAIFSignalBit()) - - self.signal_definitions[signal_name].width = int(bit_index) + 1 - - match = re.search(r'T0 (\d+)', bit_values) - if match: - low_time = match.groups()[0] - - self.signal_definitions[signal_name].bits[int(bit_index)].low_time = low_time - - match = re.search(r'T1 (\d+)', bit_values) - if match: - high_time = match.groups()[0] - - self.signal_definitions[signal_name].bits[int(bit_index)].high_time = high_time - - match = re.search(r'TC (\d+)', bit_values) - if match: - toggle_count = match.groups()[0] - - self.signal_definitions[signal_name].bits[int(bit_index)].transitions = toggle_count - -vcd_to_saif_parser = VCDToSAIFParser() -vcd_to_saif_parser.parse("simx.vcd") - -saif_parser = SAIFParser() -saif_parser.parse("simx.saif") - -print("From VCD") -for signal_name, signal in vcd_to_saif_parser.signal_definitions.items(): - for bit in range(signal.width): - print(f"{signal.name}[{bit}] (T0 {signal.bits[bit].low_time}) (T1 {signal.bits[bit].high_time}) (TC {signal.bits[bit].transitions})") - -print() - -print("From SAIF") -for signal_name, signal in saif_parser.signal_definitions.items(): - for bit in range(signal.width): - print(f"{signal.name}[{bit}] (T0 {signal.bits[bit].low_time}) (T1 {signal.bits[bit].high_time}) (TC {signal.bits[bit].transitions})") \ No newline at end of file