3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-07-24 13:18:56 +00:00

Support for BTOR witness to Yosys witness conversion

This commit is contained in:
Jannis Harder 2023-01-03 14:45:41 +01:00
parent 3e25e61778
commit 636b9f2705
5 changed files with 312 additions and 20 deletions

View file

@ -110,6 +110,10 @@ class AigerMap:
def __init__(self, mapfile):
data = json.load(mapfile)
version = data.get("version") if isinstance(data, dict) else {}
if version != "Yosys Witness Aiger map":
raise click.ClickException(f"{mapfile.name}: unexpected file format version {version!r}")
self.latch_count = data["latch_count"]
self.input_count = data["input_count"]
@ -250,5 +254,132 @@ def yw2aiw(input, mapfile, output):
click.echo(f"Converted {len(inyw)} time steps.")
class BtorMap:
def __init__(self, mapfile):
self.data = data = json.load(mapfile)
version = data.get("version") if isinstance(data, dict) else {}
if version != "Yosys Witness BTOR map":
raise click.ClickException(f"{mapfile.name}: unexpected file format version {version!r}")
self.sigmap = WitnessSigMap()
for mode in ("states", "inputs"):
for btor_signal_def in data[mode]:
if btor_signal_def is None:
continue
if isinstance(btor_signal_def, dict):
btor_signal_def["path"] = tuple(btor_signal_def["path"])
else:
for chunk in btor_signal_def:
chunk["path"] = tuple(chunk["path"])
@cli.command(help="""
Convert a BTOR witness trace into a Yosys witness trace.
This requires a Yosys witness BTOR map file as generated by 'write_btor -ywmap'.
""")
@click.argument("input", type=click.File("r"))
@click.argument("mapfile", type=click.File("r"))
@click.argument("output", type=click.File("w"))
def wit2yw(input, mapfile, output):
input_name = input.name
click.echo(f"Converting BTOR witness trace {input_name!r} to Yosys witness trace {output.name!r}...")
click.echo(f"Using Yosys witness BTOR map file {mapfile.name!r}")
btor_map = BtorMap(mapfile)
input = filter(None, (line.split(';', 1)[0].strip() for line in input))
sat = next(input, None)
if sat != "sat":
raise click.ClickException(f"{input_name}: not a BTOR witness file")
props = next(input, None)
t = -1
line = next(input, None)
frames = []
bits = {}
while line and not line.startswith('.'):
current_t = int(line[1:].strip())
if line[0] == '#':
mode = "states"
elif line[0] == '@':
mode = "inputs"
else:
raise click.ClickException(f"{input_name}: unexpected data in BTOR witness file")
if current_t > t:
t = current_t
values = WitnessValues()
frames.append(values)
line = next(input, None)
while line and line[0] not in "#@.":
if current_t > 0 and mode == "states":
line = next(input, None)
continue
tokens = line.split()
line = next(input, None)
btor_sig = btor_map.data[mode][int(tokens[0])]
if btor_sig is None:
continue
if isinstance(btor_sig, dict):
addr = tokens[1]
if not addr.startswith('[') or not addr.endswith(']'):
raise click.ClickException(f"{input_name}: expected address in BTOR witness file")
addr = int(addr[1:-1], 2)
if addr < 0 or addr >= btor_sig["size"]:
raise click.ClickException(f"{input_name}: out of bounds address in BTOR witness file")
btor_sig = [{
"path": (*btor_sig["path"], f"\\[{addr}]"),
"width": btor_sig["width"],
"offset": 0,
}]
signal_value = iter(reversed(tokens[2]))
else:
signal_value = iter(reversed(tokens[1]))
for chunk in btor_sig:
offset = chunk["offset"]
path = chunk["path"]
for i in range(offset, offset + chunk["width"]):
key = (path, i)
bits[key] = mode == "inputs"
values[key] = next(signal_value)
if next(signal_value, None) is not None:
raise click.ClickException(f"{input_name}: excess bits in BTOR witness file")
if line is None:
raise click.ClickException(f"{input_name}: unexpected end of BTOR witness file")
if line.strip() != '.':
raise click.ClickException(f"{input_name}: unexpected data in BTOR witness file")
if next(input, None) is not None:
raise click.ClickException(f"{input_name}: unexpected trailing data in BTOR witness file")
outyw = WriteWitness(output, 'yosys-witness wit2yw')
outyw.signals = coalesce_signals((), bits)
for clock in btor_map.data["clocks"]:
outyw.add_clock(clock["path"], clock["offset"], clock["edge"])
for values in frames:
outyw.step(values)
outyw.end_trace()
click.echo(f"Converted {outyw.t} time steps.")
if __name__ == "__main__":
cli()

View file

@ -175,8 +175,9 @@ class WitnessSig:
return self.sort_key < other.sort_key
def coalesce_signals(signals):
bits = {}
def coalesce_signals(signals, bits=None):
if bits is None:
bits = {}
for sig in signals:
for bit in sig.bits():
if sig.init_only: