diff --git a/test_regress/driver.py b/test_regress/driver.py index c7335c9f6..5fd4c5110 100755 --- a/test_regress/driver.py +++ b/test_regress/driver.py @@ -72,17 +72,22 @@ class staticproperty(property): class SAIFSignalBit: + last_val: int + high_time: int + low_time: int + transitions: int + 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): + def aggregate(self, dt: int, new_val: int): + if new_val != self.last_val: self.transitions += 1 - if self.last_val: + if self.last_val == 1: self.high_time += dt self.last_val = new_val @@ -97,70 +102,17 @@ class SAIFSignal: 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 SAIFInstance: + def __init__(self, scope_name): + self.scope_name = scope_name + self.parent_instance = None + self.nets = {} + self.child_instances = {} class SAIFParser: def __init__(self): - self.signal_definitions = {} + self.top_instance = None + self.current_instance = None def parse(self, saif_filename): with open(saif_filename, 'r') as saif_file: @@ -169,6 +121,21 @@ class SAIFParser: if not line: continue + match = re.search(r'INSTANCE\s+(\w*)', line) + if match: + instance_name = match.groups()[0] + + instance = SAIFInstance(instance_name) + + if instance_name == "top": + self.top_instance = instance + else: + self.current_instance.child_instances[instance_name] = instance + + instance.parent_instance = self.current_instance + self.current_instance = instance + + line = line.replace('\\', '') match = re.search(r'(\w+)\[*(\d*)\]*\s+(\(T(.+)\))+', line) if match: signal_name, bit_index, bit_values, _ = match.groups() @@ -176,31 +143,38 @@ class SAIFParser: if bit_index == '': bit_index = 0 - if signal_name not in self.signal_definitions: - self.signal_definitions[signal_name] = SAIFSignal(signal_name) + if signal_name not in self.current_instance.nets: + signal = SAIFSignal(signal_name) + self.current_instance.nets[signal_name] = signal - for _ in range(0, int(bit_index) - self.signal_definitions[signal_name].width + 1): - self.signal_definitions[signal_name].bits.append(SAIFSignalBit()) + current_signal = self.current_instance.nets[signal_name] + + for _ in range(0, int(bit_index) - current_signal.width + 1): + current_signal.bits.append(SAIFSignalBit()) - self.signal_definitions[signal_name].width = int(bit_index) + 1 + current_signal.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 + current_signal.bits[int(bit_index)].low_time = int(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 + current_signal.bits[int(bit_index)].high_time = int(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 + + current_signal.bits[int(bit_index)].transitions = int(toggle_count) + + match = re.match(r'\s+\)\s+', line) + if match and self.current_instance != self.top_instance: + self.current_instance = self.current_instance.parent_instance ####################################################################### @@ -2504,38 +2478,42 @@ 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] + def compare_saif_instances(self, first: SAIFInstance, second: SAIFInstance): + for signal_name, signal in first.nets.items(): + if signal_name not in second.nets: + self.error(f"Signal {signal_name} doesn't exist in the second object\n") + for instance_name, instance in first.child_instances.items(): + if instance_name not in second.child_instances: + self.error(f"Instance {instance_name} doesn't exist in the second object\n") + + self.compare_saif_instances(instance, second.child_instances[instance_name]) + + def compare_saif_contents(self, first: SAIFParser, second: SAIFParser): + """Test if second SAIF file has the same values as the first""" + self.compare_saif_instances(first.top_instance, second.top_instance) + + def print_saif_instance_tree(self, saif_instance: SAIFInstance): + print(f"INSTANCE: {saif_instance.scope_name}") + + print("NET:") + for signal_name, signal in saif_instance.nets.items(): 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") + print(f"{signal.name}[{bit}] (T0 {signal.bits[bit].low_time}) (T1 {signal.bits[bit].high_time}) (TC {signal.bits[bit].transitions})") + for instance_name, instance in saif_instance.child_instances.items(): + self.print_saif_instance_tree(instance) def saif_identical(self, fn1: str, fn2: str) -> None: """Test if two SAIF files have logically-identical contents""" - vcd_to_saif_parser = VCDToSAIFParser() - vcd_to_saif_parser.parse(fn2) + test_result_saif = SAIFParser() + test_result_saif.parse(fn1) - saif_parser = SAIFParser() - saif_parser.parse(fn1) + golden_saif = SAIFParser() + golden_saif.parse(fn2) - self.compare_saif_contents(vcd_to_saif_parser, saif_parser) + self.compare_saif_contents(test_result_saif, golden_saif) + self.compare_saif_contents(golden_saif, test_result_saif) def _vcd_read(self, filename: str) -> str: data = {}