3
0
Fork 0
mirror of https://github.com/YosysHQ/sby.git synced 2025-12-06 21:42:27 +00:00
sby/tools/btor2aig_yw/btor2aig_yw.py
Krystine Sherwin 99e704e6cb
btor2aiger: Get assertions from .btor file
Assertions show up in the .btor file as 'bad' statements, assuming btor2aiger maintains the same order this should get us the list of assertions in the order they appear in the .aig file.
2024-04-06 13:40:01 +13:00

133 lines
3.4 KiB
Python

from __future__ import annotations
import argparse
import asyncio
import json
import re
from pathlib import Path
def arg_parser():
parser = argparse.ArgumentParser()
parser.add_argument(
"btor_file",
type=Path
)
parser.add_argument(
"-d", "--dest",
dest="dest",
required=False,
type=Path
)
return parser
def fix_path(path: str) -> list[str]:
if path[0] == '$':
fixed = [path]
else:
fixed = [f"\\{s}" for s in path.replace('[','.[').split('.')]
return fixed
async def main() -> None:
args = arg_parser().parse_args()
work_dir: Path = args.dest or Path()
proc = await asyncio.create_subprocess_shell(
f"btor2aiger {args.btor_file}",
stdout=asyncio.subprocess.PIPE
)
data = True
# output aig
aig_file = work_dir / "design_aiger.aig"
aigf = open(aig_file, mode="wb")
data = await proc.stdout.readline()
aig_header = data.decode()
while data:
aigf.write(data)
data = await proc.stdout.readline()
if b'i0' in data:
break
end_pos = data.find(b'i0')
aigf.write(data[:end_pos])
aigf.close()
# initialize yw aiger map
aig_MILOA = aig_header.split()
ywa = {
"version": "Yosys Witness Aiger map",
"generator": "btor2aig_yw.py",
"latch_count": int(aig_MILOA[3]),
"input_count": int(aig_MILOA[2]),
"clocks": [],
"inputs": [],
"seqs": [],
"inits": [],
"latches": [],
"asserts": [],
"assumes": []
}
# output aim & build ywa
aim_file = work_dir / "design_aiger.aim"
aimf = open(aim_file, mode="w")
data = data[end_pos:]
while data:
# decode data
string = data.decode().rstrip()
pattern = r"(?P<type>[cil])(?P<input>\d+) (?P<path>.*?)(\[(?P<offset>\d+)\])?$"
m = re.match(pattern, string)
md = m.groupdict()
if md['type'] == 'i':
md['type'] = 'input'
elif md['type'] == 'c':
md['type'] = 'clk'
elif md['type'] == 'l':
md['type'] = 'latch'
else:
raise ValueError(f"Unknown type identifier {md['type']!r}")
for k in ['input', 'offset']:
if md[k]:
md[k] = int(md[k])
else:
md[k] = 0
# output to aim
if md['type'] in ['input', 'latch']:
print("{type} {input} {offset} {path}".format(**md), file=aimf)
# update ywa
md_type = md.pop('type')
md['path'] = fix_path(md['path'])
if md_type == 'clk':
md['edge'] = "posedge" # always?
ywa['clocks'].append(md)
elif md_type == 'input':
ywa['inputs'].append(md)
elif md_type == 'latch':
ywa['latches'].append(md)
# get next line
data = await proc.stdout.readline()
aimf.close()
# find assertions by looking for 'bad' statements in the btor
with open(args.btor_file, mode='r') as f:
data = f.readline()
while data:
if "bad" in data:
m = re.match(r"^\d+ bad \d+ (\S+)", data)
path = fix_path(m.group(1))
ywa['asserts'].append(path)
data = f.readline()
with open(work_dir / "design_aiger.ywa", mode="w") as f:
json.dump(ywa, f, indent=2)
if __name__ == "__main__":
asyncio.run(main())