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:
parent
3e25e61778
commit
636b9f2705
5 changed files with 312 additions and 20 deletions
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue