[#74021] format verilator_saif_diff script
This commit is contained in:
parent
e296d90328
commit
bdb7050411
|
|
@ -1,26 +1,26 @@
|
|||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,C0114,C0115,C0116,C0209,C0302,R0902,R0903,R0904,R0912,R0913,R0914,R0915,R0916,W0212,W0511,W0603,W1201
|
||||
# pylint: disable=C0114,C0115,C0116,R0902,R0903,R0912,R0915,W0719,W0718
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
import re
|
||||
|
||||
SUCCESS_CODE = 0
|
||||
FAILURE_CODE = 1
|
||||
|
||||
INSTANCE_TYPE = "INSTANCE"
|
||||
NET_LIST_TYPE = "NET"
|
||||
SIGNAL_TYPE = "SIGNAL"
|
||||
|
||||
EOF_ERROR = "Unexpected EOF"
|
||||
|
||||
|
||||
def saif_assert(expression, message):
|
||||
if not expression:
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
def saif_error(message):
|
||||
raise Exception(message)
|
||||
|
||||
|
||||
class SAIFSignalBit:
|
||||
name: str
|
||||
high_time: int
|
||||
|
|
@ -55,12 +55,9 @@ class SAIFParser:
|
|||
|
||||
def __init__(self):
|
||||
self.token_stack = []
|
||||
|
||||
# for parsing simplicity
|
||||
self.token_stack.append(SAIFToken('saif_root'))
|
||||
|
||||
self.current_instance = None
|
||||
|
||||
self.has_saifile_header = False
|
||||
self.direction = ''
|
||||
self.saif_version = ''
|
||||
|
|
@ -71,144 +68,107 @@ class SAIFParser:
|
|||
|
||||
def parse(self, saif_filename):
|
||||
file_contents = ''
|
||||
|
||||
with open(saif_filename, 'r', encoding="utf8") as saif_file:
|
||||
content = saif_file.readlines()
|
||||
filtered_lines = [line for line in content if not line.strip().startswith('//')]
|
||||
file_contents = ''.join(filtered_lines)
|
||||
|
||||
tokens = file_contents.replace('(', ' ( ').replace(')', ' ) ').split()
|
||||
num_of_tokens = len(tokens)
|
||||
|
||||
index = 0
|
||||
while index < num_of_tokens:
|
||||
token = tokens[index]
|
||||
index += 1
|
||||
|
||||
if token == '(':
|
||||
self.token_stack.append(SAIFToken(token))
|
||||
self.token_stack[-1].type = self.token_stack[-2].type
|
||||
self.token_stack[-1].value = self.token_stack[-2].value
|
||||
|
||||
continue
|
||||
|
||||
if token == ')':
|
||||
if self.token_stack[-1].type == INSTANCE_TYPE:
|
||||
self.current_instance = self.current_instance.parent_instance
|
||||
|
||||
self.token_stack.pop()
|
||||
continue
|
||||
|
||||
if re.match(r'SAIFILE', token):
|
||||
self.has_saifile_header = True
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'DIRECTION', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.direction = tokens[index].replace('\"', '')
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'SAIFVERSION', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.saif_version = tokens[index].replace('\"', '')
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'DESIGN|DATE|VENDOR|PROGRAM_NAME|VERSION', token):
|
||||
# noop, only skip value
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'DIVIDER', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.divider = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'TIMESCALE', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.timescale = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'DURATION', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.duration = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'INSTANCE', token):
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
instance_name = tokens[index]
|
||||
index += 1
|
||||
|
||||
self.token_stack[-1].type = INSTANCE_TYPE
|
||||
self.token_stack[-1].value = instance_name
|
||||
|
||||
instance = SAIFInstance(instance_name)
|
||||
|
||||
if self.current_instance is None:
|
||||
self.top_instances[instance_name] = instance
|
||||
else:
|
||||
self.current_instance.child_instances[instance_name] = instance
|
||||
|
||||
instance.parent_instance = self.current_instance
|
||||
self.current_instance = instance
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'NET', token):
|
||||
self.token_stack[-1].type = NET_LIST_TYPE
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'T1', token):
|
||||
net_name = self.token_stack[-1].value
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.current_instance.nets[net_name].high_time = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'T0', token):
|
||||
net_name = self.token_stack[-1].value
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.current_instance.nets[net_name].low_time = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'TC', token):
|
||||
net_name = self.token_stack[-1].value
|
||||
saif_assert(index < num_of_tokens, EOF_ERROR)
|
||||
self.current_instance.nets[net_name].transitions = tokens[index]
|
||||
index += 1
|
||||
|
||||
continue
|
||||
|
||||
if re.match(r'TZ|TX|TB|TG|IG|IK', token):
|
||||
# noop, only skip value
|
||||
index += 1
|
||||
continue
|
||||
|
||||
if self.token_stack[-2].type == NET_LIST_TYPE:
|
||||
self.token_stack[-1].type = SIGNAL_TYPE
|
||||
self.token_stack[-1].value = token
|
||||
self.current_instance.nets[token] = (SAIFSignalBit(token))
|
||||
|
||||
self.current_instance.nets[token] = SAIFSignalBit(token)
|
||||
saif_assert(self.has_saifile_header, "SAIF file doesn't contain a SAIFILE keyword")
|
||||
saif_assert(self.direction == "backward", f"SAIF file doesn't have a valid/compatible direction: {self.direction}")
|
||||
saif_assert(self.saif_version == "2.0", f"SAIF file doesn't have a valid/compatible version: {self.saif_version}")
|
||||
|
||||
saif_assert(self.direction == "backward",
|
||||
f"SAIF file doesn't have a valid/compatible direction: {self.direction}")
|
||||
saif_assert(self.saif_version == "2.0",
|
||||
f"SAIF file doesn't have a valid/compatible version: {self.saif_version}")
|
||||
# only 'saif_root' token should be left
|
||||
saif_assert(len(self.token_stack) == 1, "Incorrect nesting of scopes")
|
||||
|
||||
|
|
@ -216,78 +176,58 @@ class SAIFParser:
|
|||
def compare_saif_instances(first: SAIFInstance, second: SAIFInstance):
|
||||
if len(first.nets) != len(second.nets):
|
||||
saif_error(f"Number of nets doesn't match in {first.scope_name}: "
|
||||
f"{len(first.nets)} != {len(second.nets)}")
|
||||
|
||||
f"{len(first.nets)} != {len(second.nets)}")
|
||||
for signal_name, saif_signal in first.nets.items():
|
||||
if signal_name not in second.nets:
|
||||
saif_error(f"Signal {signal_name} doesn't exist in the second object\n")
|
||||
|
||||
other_signal = second.nets[signal_name]
|
||||
|
||||
if (saif_signal.high_time != other_signal.high_time
|
||||
or saif_signal.low_time != other_signal.low_time
|
||||
or saif_signal.transitions != other_signal.transitions):
|
||||
saif_error("Incompatible signal bit parameters in "
|
||||
f"{signal_name}\n")
|
||||
|
||||
f"{signal_name}\n")
|
||||
if len(first.child_instances) != len(second.child_instances):
|
||||
saif_error(f"Number of child instances doesn't match in {first.scope_name}: "
|
||||
f"{len(first.child_instances)} != {len(second.child_instances)}")
|
||||
|
||||
f"{len(first.child_instances)} != {len(second.child_instances)}")
|
||||
for instance_name, instance in first.child_instances.items():
|
||||
if instance_name not in second.child_instances:
|
||||
saif_error(f"Instance {instance_name} doesn't exist in the second object\n")
|
||||
|
||||
compare_saif_instances(instance, second.child_instances[instance_name])
|
||||
|
||||
|
||||
def compare_saif_contents(first_file: str, second_file: str):
|
||||
"""Test if second SAIF file has the same values as the first"""
|
||||
|
||||
first_saif = SAIFParser()
|
||||
first_saif.parse(first_file)
|
||||
|
||||
second_saif = SAIFParser()
|
||||
second_saif.parse(second_file)
|
||||
|
||||
if first_saif.duration != second_saif.duration:
|
||||
saif_error(f"Duration of trace doesn't match: {first_saif.duration} != {second_saif.duration}")
|
||||
|
||||
saif_error("Duration of trace doesn't match: "
|
||||
f"{first_saif.duration} != {second_saif.duration}")
|
||||
if first_saif.divider != second_saif.divider:
|
||||
saif_error(f"Dividers don't match: {first_saif.divider} != {second_saif.divider}")
|
||||
|
||||
if first_saif.timescale != second_saif.timescale:
|
||||
saif_error(f"Timescale doesn't match: {first_saif.timescale} != {second_saif.timescale}")
|
||||
|
||||
if len(first_saif.top_instances) != len(second_saif.top_instances):
|
||||
saif_error("Number of top instances doesn't match: "
|
||||
f"{len(first_saif.top_instances)} != {len(second_saif.top_instances)}")
|
||||
|
||||
f"{len(first_saif.top_instances)} != {len(second_saif.top_instances)}")
|
||||
for top_instance_name, top_instance in first_saif.top_instances.items():
|
||||
if top_instance_name not in second_saif.top_instances:
|
||||
saif_error(f"Top instance {top_instance_name} missing in other SAIF")
|
||||
|
||||
compare_saif_instances(top_instance, second_saif.top_instances[top_instance_name])
|
||||
|
||||
return SUCCESS_CODE
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""""")
|
||||
|
||||
parser.add_argument('--first',
|
||||
action='store',
|
||||
help='First SAIF file')
|
||||
|
||||
parser.add_argument('--second',
|
||||
action='store',
|
||||
help='Second SAIF file')
|
||||
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""verilator_saif_diff checks if two SAIF files are logically-identical. It returns first encountered difference as output.
|
||||
Run as:
|
||||
cd $VERILATOR_ROOT
|
||||
nodist/code_coverage --first example.saif --second other.saif""")
|
||||
parser.add_argument('--first', action='store', help='First SAIF file')
|
||||
parser.add_argument('--second', action='store', help='Second SAIF file')
|
||||
parser.set_defaults(stop=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
compare_saif_contents(args.first, args.second)
|
||||
except Exception as error:
|
||||
|
|
|
|||
Loading…
Reference in New Issue