From cc67c77f4fd1392a3a4a96d26697d9769c03f3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Fri, 2 Oct 2026 09:09:17 +0200 Subject: [PATCH 1/2] FakeRAM2.0: apply the ORFS asap7 backend to the vendored copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AUTO_MEMORIES calls tools/FakeRAM2.0/run.py --orfs_asap7_backend (flow/scripts/memories/gen_memories.py). The backend was shipped as patches/fakeram/0001-Add-ORFS-ASAP7-backend.patch, which ORFS's MODULE.bazel applied to the external FakeRAM2.0 repository. FakeRAM is now vendored here and ORFS no longer builds with bazel, so nothing applied the patch and run.py rejected the flag. Apply it to tools/FakeRAM2.0 and remove patches/fakeram. The patch's BUILD.bazel and MODULE.bazel are left out: they only made FakeRAM a bazel module. Signed-off-by: Øyvind Harboe --- .../fakeram/0001-Add-ORFS-ASAP7-backend.patch | 169 ------------------ tools/FakeRAM2.0/orfs_asap7/__init__.py | 1 + tools/FakeRAM2.0/orfs_asap7/generate.py | 83 +++++++++ tools/FakeRAM2.0/run.py | 12 +- tools/FakeRAM2.0/utils/class_process.py | 3 + 5 files changed, 98 insertions(+), 170 deletions(-) delete mode 100644 patches/fakeram/0001-Add-ORFS-ASAP7-backend.patch create mode 100644 tools/FakeRAM2.0/orfs_asap7/__init__.py create mode 100644 tools/FakeRAM2.0/orfs_asap7/generate.py diff --git a/patches/fakeram/0001-Add-ORFS-ASAP7-backend.patch b/patches/fakeram/0001-Add-ORFS-ASAP7-backend.patch deleted file mode 100644 index d2ae3cd83a..0000000000 --- a/patches/fakeram/0001-Add-ORFS-ASAP7-backend.patch +++ /dev/null @@ -1,169 +0,0 @@ -diff --git a/BUILD.bazel b/BUILD.bazel -new file mode 100644 -index 0000000..16e9be4 ---- /dev/null -+++ b/BUILD.bazel -@@ -0,0 +1,5 @@ -+filegroup( -+ name = "all_files", -+ srcs = glob(["**/*"]), -+ visibility = ["//visibility:public"], -+) -diff --git a/MODULE.bazel b/MODULE.bazel -new file mode 100644 -index 0000000..f12bf1f ---- /dev/null -+++ b/MODULE.bazel -@@ -0,0 +1,4 @@ -+module( -+ name = "fakeram", -+ version = "2.0.0", -+) -diff --git a/orfs_asap7/__init__.py b/orfs_asap7/__init__.py -new file mode 100644 -index 0000000..edcf578 ---- /dev/null -+++ b/orfs_asap7/__init__.py -@@ -0,0 +1 @@ -+# ORFS ASAP7 package -diff --git a/orfs_asap7/generate.py b/orfs_asap7/generate.py -new file mode 100644 -index 0000000..58fef20 ---- /dev/null -+++ b/orfs_asap7/generate.py -@@ -0,0 +1,83 @@ -+import json -+import sys -+from pathlib import Path -+ -+from utils.class_process import Process -+from utils.memory_config import MemoryConfig -+from utils.memory_factory import MemoryFactory -+from utils.timing_data import TimingData -+from utils.ram_liberty_exporter import RAMLibertyExporter -+from utils.lef_exporter import LefExporter -+ -+ASAP7_PROCESS_CONFIG = { -+ "tech_nm": 7, -+ "voltage": 0.7, -+ "metal_prefix": "M", -+ "metal_layer": "M4", -+ "pin_width_nm": 24, -+ "pin_pitch_nm": 48, -+ "metal_track_pitch_nm": 48, -+ "manufacturing_grid_nm": 1, -+ "contacted_poly_pitch_nm": 54, -+ "fin_pitch_nm": 27, -+ "column_mux_factor": 1, -+ "snap_width_nm": 190, -+ "snap_height_nm": 1400, -+} -+ -+ASAP7_TIMING_CONFIG = { -+ "cycle_time": 1.0, -+ "access_time": 0.5, -+ "setup_time": 0.1, -+ "hold_time": 0.05, -+ "leakage": 0.001, -+} -+ -+def run_orfs_asap7(platform: str, out_dir: Path, json_path: Path): -+ if platform != "asap7": -+ sys.stderr.write(f"FakeRAM2.0 orfs_asap7: unsupported platform {platform}\n") -+ return 1 -+ -+ try: -+ data = json.loads(json_path.read_text()) -+ memories = data.get("memories", []) -+ except Exception as e: -+ sys.stderr.write(f"FakeRAM2.0 orfs_asap7: failed to read {json_path}: {e}\n") -+ return 1 -+ -+ out_dir.mkdir(parents=True, exist_ok=True) -+ converted = sorted((m for m in memories if m.get("idiomatic")), key=lambda m: m["name"]) -+ -+ process = Process(ASAP7_PROCESS_CONFIG) -+ timing_data = TimingData(ASAP7_TIMING_CONFIG) -+ -+ for m in converted: -+ name = m["name"] -+ bits = m.get("bits", 32) -+ rows = m.get("rows", 128) -+ -+ sram_dict = { -+ "name": name, -+ "width": bits, -+ "depth": rows, -+ "banks": 1, -+ } -+ mem_config = MemoryConfig.from_json(sram_dict) -+ ram = MemoryFactory.create(mem_config, "RAM", "SP", process, timing_data) -+ -+ # Export Liberty -+ lib_path = out_dir / f"{name}.lib" -+ with open(lib_path, "w") as f: -+ RAMLibertyExporter(ram).export(f) -+ -+ pre_lib_path = out_dir / f"{name}_pre_layout.lib" -+ with open(pre_lib_path, "w") as f: -+ RAMLibertyExporter(ram).export(f) -+ -+ # Export LEF -+ lef_path = out_dir / f"{name}.lef" -+ with open(lef_path, "w") as f: -+ LefExporter(ram).export(f) -+ -+ (out_dir / "blackboxes.txt").write_text("".join(f"{m['name']}\n" for m in converted)) -+ return 0 -diff --git a/run.py b/run.py -index f525c5f..06ae626 100755 ---- a/run.py -+++ b/run.py -@@ -8,6 +8,7 @@ from utils.class_process import Process - from utils.memory_config import MemoryConfig - from utils.memory_factory import MemoryFactory - from utils.timing_data import TimingData -+from orfs_asap7.generate import run_orfs_asap7 - - - def get_args() -> argparse.Namespace: -@@ -28,10 +29,19 @@ def get_args() -> argparse.Namespace: - required=False, - default="results", - ) -+ parser.add_argument( -+ "--orfs_asap7_backend", -+ action="store_true", -+ help="Use ORFS ASAP7 backend (expects JSON in memories.json format)", -+ ) - return parser.parse_args() - - - def main(args: argparse.Namespace): -+ if args.orfs_asap7_backend: -+ from pathlib import Path -+ return run_orfs_asap7(platform="asap7", out_dir=Path(args.output_dir), json_path=Path(args.config)) -+ - json_data = RunUtils.get_config(args.config) - # Create a process object (shared by all srams) - process = Process(json_data) -@@ -52,4 +62,4 @@ def main(args: argparse.Namespace): - ### Entry point - if __name__ == "__main__": - args = get_args() -- main(args) -+ sys.exit(main(args)) -diff --git a/utils/class_process.py b/utils/class_process.py -index e1cfac3..745285c 100644 ---- a/utils/class_process.py -+++ b/utils/class_process.py -@@ -119,6 +119,9 @@ class Process: - - total_height += additional_height - -+ min_height = max(3.5, self.snap_height_nm / 1000.0 if self.snap_height_nm else 0) -+ total_height = max(total_height, min_height) -+ - return (total_width, total_height) - - def get_tech_nm(self): diff --git a/tools/FakeRAM2.0/orfs_asap7/__init__.py b/tools/FakeRAM2.0/orfs_asap7/__init__.py new file mode 100644 index 0000000000..edcf5785fb --- /dev/null +++ b/tools/FakeRAM2.0/orfs_asap7/__init__.py @@ -0,0 +1 @@ +# ORFS ASAP7 package diff --git a/tools/FakeRAM2.0/orfs_asap7/generate.py b/tools/FakeRAM2.0/orfs_asap7/generate.py new file mode 100644 index 0000000000..58fef202b0 --- /dev/null +++ b/tools/FakeRAM2.0/orfs_asap7/generate.py @@ -0,0 +1,83 @@ +import json +import sys +from pathlib import Path + +from utils.class_process import Process +from utils.memory_config import MemoryConfig +from utils.memory_factory import MemoryFactory +from utils.timing_data import TimingData +from utils.ram_liberty_exporter import RAMLibertyExporter +from utils.lef_exporter import LefExporter + +ASAP7_PROCESS_CONFIG = { + "tech_nm": 7, + "voltage": 0.7, + "metal_prefix": "M", + "metal_layer": "M4", + "pin_width_nm": 24, + "pin_pitch_nm": 48, + "metal_track_pitch_nm": 48, + "manufacturing_grid_nm": 1, + "contacted_poly_pitch_nm": 54, + "fin_pitch_nm": 27, + "column_mux_factor": 1, + "snap_width_nm": 190, + "snap_height_nm": 1400, +} + +ASAP7_TIMING_CONFIG = { + "cycle_time": 1.0, + "access_time": 0.5, + "setup_time": 0.1, + "hold_time": 0.05, + "leakage": 0.001, +} + +def run_orfs_asap7(platform: str, out_dir: Path, json_path: Path): + if platform != "asap7": + sys.stderr.write(f"FakeRAM2.0 orfs_asap7: unsupported platform {platform}\n") + return 1 + + try: + data = json.loads(json_path.read_text()) + memories = data.get("memories", []) + except Exception as e: + sys.stderr.write(f"FakeRAM2.0 orfs_asap7: failed to read {json_path}: {e}\n") + return 1 + + out_dir.mkdir(parents=True, exist_ok=True) + converted = sorted((m for m in memories if m.get("idiomatic")), key=lambda m: m["name"]) + + process = Process(ASAP7_PROCESS_CONFIG) + timing_data = TimingData(ASAP7_TIMING_CONFIG) + + for m in converted: + name = m["name"] + bits = m.get("bits", 32) + rows = m.get("rows", 128) + + sram_dict = { + "name": name, + "width": bits, + "depth": rows, + "banks": 1, + } + mem_config = MemoryConfig.from_json(sram_dict) + ram = MemoryFactory.create(mem_config, "RAM", "SP", process, timing_data) + + # Export Liberty + lib_path = out_dir / f"{name}.lib" + with open(lib_path, "w") as f: + RAMLibertyExporter(ram).export(f) + + pre_lib_path = out_dir / f"{name}_pre_layout.lib" + with open(pre_lib_path, "w") as f: + RAMLibertyExporter(ram).export(f) + + # Export LEF + lef_path = out_dir / f"{name}.lef" + with open(lef_path, "w") as f: + LefExporter(ram).export(f) + + (out_dir / "blackboxes.txt").write_text("".join(f"{m['name']}\n" for m in converted)) + return 0 diff --git a/tools/FakeRAM2.0/run.py b/tools/FakeRAM2.0/run.py index a89ce07234..8257419d8c 100755 --- a/tools/FakeRAM2.0/run.py +++ b/tools/FakeRAM2.0/run.py @@ -8,6 +8,7 @@ from utils.memory_config import MemoryConfig from utils.memory_factory import MemoryFactory from utils.timing_data import TimingData +from orfs_asap7.generate import run_orfs_asap7 def get_args() -> argparse.Namespace: @@ -26,10 +27,19 @@ def get_args() -> argparse.Namespace: required=False, default="results", ) + parser.add_argument( + "--orfs_asap7_backend", + action="store_true", + help="Use ORFS ASAP7 backend (expects JSON in memories.json format)", + ) return parser.parse_args() def main(args: argparse.Namespace): + if args.orfs_asap7_backend: + from pathlib import Path + return run_orfs_asap7(platform="asap7", out_dir=Path(args.output_dir), json_path=Path(args.config)) + json_data = RunUtils.get_config(args.config) # Create a process object (shared by all srams) process = Process(json_data) @@ -50,4 +60,4 @@ def main(args: argparse.Namespace): ### Entry point if __name__ == "__main__": args = get_args() - main(args) + sys.exit(main(args)) diff --git a/tools/FakeRAM2.0/utils/class_process.py b/tools/FakeRAM2.0/utils/class_process.py index 487a853e6a..71975c690b 100644 --- a/tools/FakeRAM2.0/utils/class_process.py +++ b/tools/FakeRAM2.0/utils/class_process.py @@ -119,6 +119,9 @@ def get_macro_dimensions(self, width_in_bits, depth, num_banks, additional_heigh total_height += additional_height + min_height = max(3.5, self.snap_height_nm / 1000.0 if self.snap_height_nm else 0) + total_height = max(total_height, min_height) + return (total_width, total_height) def get_tech_nm(self): From b54a8449132eefc1fbeec59fb566ca05cefeade6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Fri, 2 Oct 2026 09:18:20 +0200 Subject: [PATCH 2/2] FakeRAM2.0: black-format the files the asap7 backend touches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch predates black-formatting FakeRAM2.0 (3388907ee7), so the code it carried was never formatted. Formatting only. Signed-off-by: Øyvind Harboe --- tools/FakeRAM2.0/orfs_asap7/generate.py | 9 +++++++-- tools/FakeRAM2.0/run.py | 5 ++++- tools/FakeRAM2.0/utils/class_process.py | 4 +++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/FakeRAM2.0/orfs_asap7/generate.py b/tools/FakeRAM2.0/orfs_asap7/generate.py index 58fef202b0..be30f8f927 100644 --- a/tools/FakeRAM2.0/orfs_asap7/generate.py +++ b/tools/FakeRAM2.0/orfs_asap7/generate.py @@ -33,6 +33,7 @@ "leakage": 0.001, } + def run_orfs_asap7(platform: str, out_dir: Path, json_path: Path): if platform != "asap7": sys.stderr.write(f"FakeRAM2.0 orfs_asap7: unsupported platform {platform}\n") @@ -46,7 +47,9 @@ def run_orfs_asap7(platform: str, out_dir: Path, json_path: Path): return 1 out_dir.mkdir(parents=True, exist_ok=True) - converted = sorted((m for m in memories if m.get("idiomatic")), key=lambda m: m["name"]) + converted = sorted( + (m for m in memories if m.get("idiomatic")), key=lambda m: m["name"] + ) process = Process(ASAP7_PROCESS_CONFIG) timing_data = TimingData(ASAP7_TIMING_CONFIG) @@ -79,5 +82,7 @@ def run_orfs_asap7(platform: str, out_dir: Path, json_path: Path): with open(lef_path, "w") as f: LefExporter(ram).export(f) - (out_dir / "blackboxes.txt").write_text("".join(f"{m['name']}\n" for m in converted)) + (out_dir / "blackboxes.txt").write_text( + "".join(f"{m['name']}\n" for m in converted) + ) return 0 diff --git a/tools/FakeRAM2.0/run.py b/tools/FakeRAM2.0/run.py index 8257419d8c..3e10151b7f 100755 --- a/tools/FakeRAM2.0/run.py +++ b/tools/FakeRAM2.0/run.py @@ -38,7 +38,10 @@ def get_args() -> argparse.Namespace: def main(args: argparse.Namespace): if args.orfs_asap7_backend: from pathlib import Path - return run_orfs_asap7(platform="asap7", out_dir=Path(args.output_dir), json_path=Path(args.config)) + + return run_orfs_asap7( + platform="asap7", out_dir=Path(args.output_dir), json_path=Path(args.config) + ) json_data = RunUtils.get_config(args.config) # Create a process object (shared by all srams) diff --git a/tools/FakeRAM2.0/utils/class_process.py b/tools/FakeRAM2.0/utils/class_process.py index 71975c690b..c11dae3d6a 100644 --- a/tools/FakeRAM2.0/utils/class_process.py +++ b/tools/FakeRAM2.0/utils/class_process.py @@ -119,7 +119,9 @@ def get_macro_dimensions(self, width_in_bits, depth, num_banks, additional_heigh total_height += additional_height - min_height = max(3.5, self.snap_height_nm / 1000.0 if self.snap_height_nm else 0) + min_height = max( + 3.5, self.snap_height_nm / 1000.0 if self.snap_height_nm else 0 + ) total_height = max(total_height, min_height) return (total_width, total_height)