Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 0 additions & 169 deletions patches/fakeram/0001-Add-ORFS-ASAP7-backend.patch

This file was deleted.

1 change: 1 addition & 0 deletions tools/FakeRAM2.0/orfs_asap7/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# ORFS ASAP7 package
88 changes: 88 additions & 0 deletions tools/FakeRAM2.0/orfs_asap7/generate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
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())
Comment thread
oharboe marked this conversation as resolved.
Resolved
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)
Comment thread
oharboe marked this conversation as resolved.
Resolved

(out_dir / "blackboxes.txt").write_text(
"".join(f"{m['name']}\n" for m in converted)
)
return 0
15 changes: 14 additions & 1 deletion tools/FakeRAM2.0/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -26,10 +27,22 @@ 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)
Expand All @@ -50,4 +63,4 @@ def main(args: argparse.Namespace):
### Entry point
if __name__ == "__main__":
args = get_args()
main(args)
sys.exit(main(args))
5 changes: 5 additions & 0 deletions tools/FakeRAM2.0/utils/class_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ 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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did 3.5 come from?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I can't find a source. It came in as a bare literal in the original AUTO_MEMORIES patch (a632406, patches/fakeram/0001), with no rationale. This PR moves it verbatim. Since snap_height_nm = 1400 rounds up after the floor, the effective minimum height is 4.2 µm.

I don't see a PDN reason for a height floor. The macro's M4 power rails are horizontal and the M5 straps are vertical, so strap coverage depends on the macro's width, not its height. That's the floor that will follow (#4597), derived from the 5.4 µm M5 pitch in grid_strategy-M1-M2-M5-M6.tcl. The PDK doesn't expose that pitch to FakeRAM today, so it would be a commented constant next to ASAP7_PROCESS_CONFIG too.

I'd rather keep this PR a verbatim move and decide in a follow-up whether to drop the 3.5 floor or move it into generate.py with a reason. Dropping it changes the generated macros, so it deserves its own diff.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine but please do follow up

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up: #4608. Nothing in the history explained the 3.5, so the first commit drops it and a forced 4×25 memory fails with "not enough tracks". The second commit sizes the height from the pin count instead: 2 * y_offset + num_pins * pin_pitch.

Other cleanup that came up in the sweep:

)
total_height = max(total_height, min_height)

return (total_width, total_height)

def get_tech_nm(self):
Expand Down
Loading