mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +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