mirror of
https://github.com/TinyTapeout/tt-support-tools.git
synced 2026-11-03 12:46:08 +01:00
feat: add DRC & LVS for ORFS (#72)
Co-authored-by: htfab <mpw@htamas.net>
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/sg13g2_full.lylvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/sg13g2_full.lylvs
|
||||||
|
index 86c8955..8a9614d 100644
|
||||||
|
--- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/sg13g2_full.lylvs
|
||||||
|
+++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/sg13g2_full.lylvs
|
||||||
|
@@ -4657,6 +4657,41 @@ schematic.purge_nets if PURGE_NETS
|
||||||
|
max_res(1e9)
|
||||||
|
min_caps(1e-18)
|
||||||
|
|
||||||
|
+# === EQUIVALENT STANDARD CELL PINS ===
|
||||||
|
+equivalent_pins("sg13g2_a21o_1", "A1", "A2")
|
||||||
|
+equivalent_pins("sg13g2_a21o_2", "A1", "A2")
|
||||||
|
+equivalent_pins("sg13g2_a21oi_1", "A1", "A2")
|
||||||
|
+equivalent_pins("sg13g2_a21oi_2", "A1", "A2")
|
||||||
|
+equivalent_pins("sg13g2_a221oi_1", "A1", "A2")
|
||||||
|
+equivalent_pins("sg13g2_a221oi_1", "B1", "B2")
|
||||||
|
+equivalent_pins("sg13g2_a22oi_1", "A1", "A2")
|
||||||
|
+equivalent_pins("sg13g2_a22oi_1", "B1", "B2")
|
||||||
|
+equivalent_pins("sg13g2_and2_1", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_and2_2", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_and3_1", "A", "B", "C")
|
||||||
|
+equivalent_pins("sg13g2_and3_2", "A", "B", "C")
|
||||||
|
+equivalent_pins("sg13g2_and4_1", "A", "B", "C", "D")
|
||||||
|
+equivalent_pins("sg13g2_and4_2", "A", "B", "C", "D")
|
||||||
|
+equivalent_pins("sg13g2_nand2_1", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_nand2_2", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_nand3_1", "A", "B", "C")
|
||||||
|
+equivalent_pins("sg13g2_nand4_1", "A", "B", "C", "D")
|
||||||
|
+equivalent_pins("sg13g2_nor2_1", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_nor2_2", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_nor3_1", "A", "B", "C")
|
||||||
|
+equivalent_pins("sg13g2_nor3_2", "A", "B", "C")
|
||||||
|
+equivalent_pins("sg13g2_nor4_1", "A", "B", "C", "D")
|
||||||
|
+equivalent_pins("sg13g2_nor4_2", "A", "B", "C", "D")
|
||||||
|
+equivalent_pins("sg13g2_o21ai_1", "A1", "A2")
|
||||||
|
+equivalent_pins("sg13g2_or2_1", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_or2_2", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_or3_1", "A", "B", "C")
|
||||||
|
+equivalent_pins("sg13g2_or3_2", "A", "B", "C")
|
||||||
|
+equivalent_pins("sg13g2_or4_1", "A", "B", "C", "D")
|
||||||
|
+equivalent_pins("sg13g2_or4_2", "A", "B", "C", "D")
|
||||||
|
+equivalent_pins("sg13g2_xnor2_1", "A", "B")
|
||||||
|
+equivalent_pins("sg13g2_xor2_1", "A", "B")
|
||||||
|
+
|
||||||
|
# === COMPARISON ===
|
||||||
|
logger.info('Starting SG13G2 LVS Comparison')
|
||||||
|
compare
|
||||||
+90
-1
@@ -562,7 +562,11 @@ class Project:
|
|||||||
if self.args.orfs:
|
if self.args.orfs:
|
||||||
shutil.rmtree("runs/wokwi", ignore_errors=True)
|
shutil.rmtree("runs/wokwi", ignore_errors=True)
|
||||||
os.makedirs("runs/wokwi", exist_ok=True)
|
os.makedirs("runs/wokwi", exist_ok=True)
|
||||||
harden_cmd = f"make -B -C $ORFS_ROOT/flow all generate_abstract"
|
cdl = os.path.join(
|
||||||
|
self.local_dir,
|
||||||
|
"runs/wokwi/objects/ihp-sg13g2/tt-submission/base/6_final_concat.cdl",
|
||||||
|
)
|
||||||
|
harden_cmd = f"make -B -C $ORFS_ROOT/flow all generate_abstract {cdl}"
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
if "ORFS_ROOT" not in env:
|
if "ORFS_ROOT" not in env:
|
||||||
env["ORFS_ROOT"] = os.path.join(self.local_dir, "OpenROAD-flow-scripts")
|
env["ORFS_ROOT"] = os.path.join(self.local_dir, "OpenROAD-flow-scripts")
|
||||||
@@ -602,6 +606,11 @@ class Project:
|
|||||||
logging.error("harden failed")
|
logging.error("harden failed")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
# DRC & LVS aren't included in the default ORFS flow
|
||||||
|
if self.args.orfs:
|
||||||
|
self.run_drc()
|
||||||
|
self.run_lvs()
|
||||||
|
|
||||||
# Write commit information
|
# Write commit information
|
||||||
if self.args.orfs:
|
if self.args.orfs:
|
||||||
commit_id_json_path = (
|
commit_id_json_path = (
|
||||||
@@ -685,6 +694,86 @@ class Project:
|
|||||||
|
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
def run_drc(self):
|
||||||
|
if self.args.orfs:
|
||||||
|
gds_path = os.path.join(
|
||||||
|
self.local_dir,
|
||||||
|
"runs/wokwi/results/ihp-sg13g2/tt-submission/base/6_final.gds",
|
||||||
|
)
|
||||||
|
drc_script = os.path.join(
|
||||||
|
os.environ["IHP_PDK_ROOT"],
|
||||||
|
"ihp-sg13g2/libs.tech/klayout/tech/drc/sg13g2_maximal.lydrc",
|
||||||
|
)
|
||||||
|
drc_report = os.path.join(
|
||||||
|
self.local_dir,
|
||||||
|
"runs/wokwi/reports/ihp-sg13g2/tt-submission/base/6_drc.lyrdb",
|
||||||
|
)
|
||||||
|
drc_log = os.path.join(
|
||||||
|
self.local_dir,
|
||||||
|
"runs/wokwi/logs/ihp-sg13g2/tt-submission/base/6_drc.log",
|
||||||
|
)
|
||||||
|
drc_cmd = f"klayout -b -rd in_gds={gds_path} -rd report_file={drc_report} -rd density=false -r {drc_script} | tee {drc_log}"
|
||||||
|
p = subprocess.run(drc_cmd, shell=True)
|
||||||
|
if p.returncode != 0:
|
||||||
|
logging.error("DRC job exited abnormally")
|
||||||
|
exit(1)
|
||||||
|
with open(drc_report) as f:
|
||||||
|
drc_ok = True
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if m := re.match("<category>'([^']*)'</category>", line):
|
||||||
|
if m[1] != "Pin.f.M5":
|
||||||
|
drc_ok = False
|
||||||
|
break
|
||||||
|
if drc_ok:
|
||||||
|
logging.info("DRC passed")
|
||||||
|
else:
|
||||||
|
logging.error("DRC failed")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
logging.warning(
|
||||||
|
"DRC is already included in OpenLane hardening job, skipping"
|
||||||
|
)
|
||||||
|
|
||||||
|
def run_lvs(self):
|
||||||
|
if self.args.orfs:
|
||||||
|
gds_path = os.path.join(
|
||||||
|
self.local_dir,
|
||||||
|
"runs/wokwi/results/ihp-sg13g2/tt-submission/base/6_final.gds",
|
||||||
|
)
|
||||||
|
cdl_path = os.path.join(
|
||||||
|
self.local_dir,
|
||||||
|
"runs/wokwi/objects/ihp-sg13g2/tt-submission/base/6_final_concat.cdl",
|
||||||
|
)
|
||||||
|
lvs_script = os.path.join(
|
||||||
|
os.environ["IHP_PDK_ROOT"],
|
||||||
|
"ihp-sg13g2/libs.tech/klayout/tech/lvs/sg13g2_full.lylvs",
|
||||||
|
)
|
||||||
|
lvs_report = os.path.join(
|
||||||
|
self.local_dir,
|
||||||
|
"runs/wokwi/reports/ihp-sg13g2/tt-submission/base/6_lvs.lvsdb",
|
||||||
|
)
|
||||||
|
lvs_log = os.path.join(
|
||||||
|
self.local_dir,
|
||||||
|
"runs/wokwi/logs/ihp-sg13g2/tt-submission/base/6_lvs.log",
|
||||||
|
)
|
||||||
|
lvs_cmd = f"klayout -b -rd in_gds={gds_path} -rd cdl_file={cdl_path} -rd report_file={lvs_report} -rd run_mode=deep -r {lvs_script} | tee {lvs_log}"
|
||||||
|
p = subprocess.run(lvs_cmd, shell=True)
|
||||||
|
if p.returncode != 0:
|
||||||
|
logging.error("LVS job exited abnormally")
|
||||||
|
exit(1)
|
||||||
|
with open(lvs_log) as f:
|
||||||
|
ok_msg = "Congratulations! Netlists match."
|
||||||
|
if any(ok_msg in line for line in f):
|
||||||
|
logging.info("LVS passed")
|
||||||
|
else:
|
||||||
|
logging.error("LVS failed")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
logging.warning(
|
||||||
|
"LVS is already included in OpenLane hardening job, skipping"
|
||||||
|
)
|
||||||
|
|
||||||
def create_fpga_bitstream(self):
|
def create_fpga_bitstream(self):
|
||||||
logging.info(f"Creating FPGA bitstream for {self}")
|
logging.info(f"Creating FPGA bitstream for {self}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user