#!/usr/bin/env python3
"""Run the pre-layout Yosys synthesis (and optional OpenSTA check) for a wrapper.

usage: run_synth.py {x1|gemv|gemv_nomem} --build DIR --liberty LIB [--sta STA_BINARY]

Run from anywhere; Yosys runs with the repository root as working directory so
that the scripts in integration/syn/ use repository-relative source paths.
Outputs in DIR: synth.ys (substituted), yosys.log, stat_hier.log, stat_flat.log,
mapped.v, mapped.json, and with --sta: sta.tcl, sta.log.
"""
import argparse
import hashlib
import os
import pathlib
import subprocess

REPO = pathlib.Path(__file__).resolve().parents[2]
CFG = {
    "x1":   {"ys": "integration/syn/cv_x1_pro_axi.ys", "sdc": "integration/sdc/cv_x1_pro_axi.sdc",
             "top": "cv_x1_pro_axi"},
    "gemv": {"ys": "integration/syn/cv_gemv_axi.ys", "sdc": "integration/sdc/cv_gemv_axi.sdc",
             "top": "cv_gemv_axi"},
    "gemv_nomem": {"ys": "integration/syn/cv_gemv_axi_nomem.ys", "sdc": "integration/sdc/cv_gemv_axi.sdc",
                   "top": "cv_gemv_axi"},
}


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("ip", choices=sorted(CFG))
    ap.add_argument("--build", required=True)
    ap.add_argument("--liberty", required=True)
    ap.add_argument("--sta")
    a = ap.parse_args()
    cfg = CFG[a.ip]
    build = pathlib.Path(a.build).resolve()
    build.mkdir(parents=True, exist_ok=True)
    lib = pathlib.Path(a.liberty).resolve()
    script = (REPO / cfg["ys"]).read_text().replace("@LIBERTY@", str(lib)).replace("@BUILD@", str(build))
    (build / "synth.ys").write_text(script)
    (build / "abc.constr").write_text("set_driving_cell BUF_X4\nset_load 10\n")
    with open(build / "yosys.log", "w") as log:
        subprocess.run(["yosys", "-q", "-l", str(build / "yosys.log"), "-s", str(build / "synth.ys")],
                       cwd=REPO, check=True, stdout=log, stderr=subprocess.STDOUT)
    print("liberty sha256", hashlib.sha256(lib.read_bytes()).hexdigest())
    if a.sta:
        # OpenSTA's netlist reader does not accept the 'signed' keyword on wires.
        import re
        net = (build / "mapped.v").read_text()
        (build / "mapped_sta.v").write_text(re.sub(r"\b(wire|input|output|reg)\s+signed\b", r"\1", net))
        tcl = f"""read_liberty {lib}
read_verilog {build / 'mapped_sta.v'}
link_design {cfg['top']}
read_sdc {REPO / cfg['sdc']}
check_setup -verbose
report_checks -path_delay max -digits 4
report_checks -path_delay min -digits 4
report_wns -digits 4
report_tns -digits 4
report_worst_slack -max -digits 4
report_clock_min_period
exit
"""
        (build / "sta.tcl").write_text(tcl)
        with open(build / "sta.log", "w") as log:
            subprocess.run([a.sta, "-no_init", "-exit", str(build / "sta.tcl")], cwd=REPO,
                           check=True, stdout=log, stderr=subprocess.STDOUT)


if __name__ == "__main__":
    main()
