Skip to content

AUTO_MEMORIES_REGFILES: register files of placed standard cells, built by generate_ram - #4781

Open
oharboe wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
oharboe:auto-memories-regfiles
Open

oharboe wants to merge 1 commit into
The-OpenROAD-Project:masterfrom
oharboe:auto-memories-regfiles

Conversation

@oharboe

@oharboe oharboe commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Before, a register file in an ORFS design was synthesised to flops and mux trees, placed by a placer that does not know they are an array, or rewritten as a FakeRAM macro whose single-port model does not describe it.
Now AUTO_MEMORIES_REGFILES lists register-file specs, and OpenROAD's generate_ram builds each one from placed standard cells, using its register-file options (OpenROAD#11723, in tools/OpenROAD).

This wires up more of generate_ram's experimental features in the flow. It is one of three changes needed before asap7/coralnpu (#4653) can go in, with #4782 (pdn: the supply pins of dont_touch instances) and #4783 (a parameterized memory module as a macro). The three are independent of each other.

  • A spec names the RTL module, its words, bits, read and write ports, reset, zero word, write style and priority. memories/regfile_ram.py translates it to generate_ram_netlist options and checks it against the module's ports from synthesis; a stray, missing or mis-sized port stops the build.
  • A wrapper in the module's place connects the RTL ports to generate_ram's.
  • Inlined by default: the cells are placed, sized and buffered with the rest of the design.
  • Named in AUTO_MEMORIES_MACRO_PLACE: a macro to synthesis and macro placement, which dissolves into its cells after macro placement (regfile_dissolve.tcl). The core stays FIRM where the macro placer put it; global placement and the resizer handle the periphery.
  • mode netlist is the only mode. A spec with mode macro stops: a timing model written before any clock tree would have the whole unbuffered clock net as one pin. A register file wanted as a macro is run through the flow as its own design.
  • A module whose memory has an initial value stops the build, since generate_ram's storage has none.

Tests: detect_test.py and gen_memories_test.py cover the spec checks, the initial-value stop and the mode check. variables.json and FlowVariables.md are the generators' output.

🤖 Generated with Claude Code

oharboe added a commit to oharboe/OpenROAD-flow-scripts that referenced this pull request Nov 3, 2026
CoreMiniAxi.sv is regenerated from coralnpu b50b85a9 by
src/coralnpu/generate, and the design is configured for it:

- The five TCM banks (ITCM one, DTCM four) are coralnpu's Sram, 512 x
  128 with one read-write port and a 16-lane byte mask. sram.memories
  names its pins (ADDITIONAL_MEMORIES) and AUTO_MEMORIES replaces it
  with a generated macro, write mask and all. The previous build swapped
  in USE_ASAP7 fakerams, which have no write mask, so a masked write
  wrote all 16 bytes.
- Regfile and FRegfile keep their words as separate registers, with no
  array for yosys to infer. surgery.py (SYNTH_VERILOG_SURGERY) moves
  them into Regfile_rf and FRegfile_rf, which AUTO_MEMORIES_REGFILES has
  generate_ram build as standard cells, every word with its
  asynchronous reset: Regfile 32 x 32 with x0 reading zero, nine reads
  and six writes; FRegfile 32 x 32, four reads and two writes.
- The clock is 1,900 ps in the platform's picoseconds (it was 10.00),
  with the platform's set_max_delay IO budgets; the asynchronous reset
  is not timed. The kept hierarchy is coralnpu's units by name, with
  OPENROAD_HIERARCHICAL=1.
- The divider's 128 x 83 SRT table is a ROM yosys maps to logic; a
  ROM is not counted against SYNTH_MEMORY_MAX_BITS.

surgery.py recognises each register file token for token and stops the
build on anything else. Each was simulated before and after the
surgery, and generate_ram's netlists against the behavioural modules
the surgery writes, on the same random inputs, every output compared
every cycle, with a negative control for each that is caught.

Needs AUTO_MEMORIES_REGFILES (The-OpenROAD-Project#4781), the supply pins of dont_touch
instances connected (The-OpenROAD-Project#4782) and a parameterized module as a macro
(The-OpenROAD-Project#4783).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for register files in the AUTO_MEMORIES flow, allowing them to be built as arrays of placed standard cells rather than synthesized into flip-flops. It adds new configuration variables (AUTO_MEMORIES_REGFILES, AUTO_MEMORIES_MACRO_PLACE), updates the build flow to handle register file generation and dissolution, and includes robust scripts for netlist translation and placement. Review feedback suggests adding more comprehensive validation for spec files, correcting a typo in an error message, and improving the robustness of the Yosys JSON parsing.

Comment thread flow/scripts/memories/regfile_ram.py Resolved
Comment thread flow/scripts/memories/regfile_ram.py Resolved
Comment thread flow/scripts/memories/detect.py Resolved
…t by generate_ram

A register file, many ports over few words, is not an SRAM: FakeRAM's
single-port model does not describe it, and synthesised to flops its
mux trees are placed by a placer that does not know they are an array.

AUTO_MEMORIES_REGFILES lists spec files, one per RTL module.
memories/regfile_ram.py translates each to OpenROAD's
generate_ram_netlist options (ports, banks, folds, the zero word,
reset, read latency, write style and priority, cells), checks it
against the module's ports from synthesis (a stray, missing or
mis-sized port stops the build), and writes a wrapper in the module's
place around the RAM, <m>_ram: an active-high reset inverted for an
active-low flop, addresses narrowed or widened.

A register file is inlined unless AUTO_MEMORIES_MACRO_PLACE names it:
its cells are then placed, sized and buffered with the rest of the
design. A named one is a macro to synthesis and macro placement (an
abstract LEF and a liberty of its area beside the FakeRAM views, in
blackboxes.txt; a parameterized module's instances lose parameters the
netlist does not declare), and dissolves into its cells at the end of
macro placement (regfile_dissolve.tcl): the core FIRM where the placer
put the macro, flipped as it was, row parity kept; the periphery left
to global placement and the resizer; then eliminate_dead_logic.

Where a row holds several words they sit side by side, and a word whose
bits would run more than 150 um is folded into more rows: XiangShan's
RobEntryFile and RenameBufferFile, dissolved into a parent, did not
legalize otherwise (the parent buffers the word's selects inside the
full array).

`mode netlist`, the default, is the only mode. A spec with `mode macro`
stops: a timing model written from generate_ram's netlist before any
clock tree is built has the whole unbuffered clock net as its clock
pin, 8.5 pF for 64 words of 256 bits on asap7, 32 pF for XiangShan's
954-bit Ftq queue, whose clock then arrived 7.7 ns late in its parent.
A register file wanted as a macro is a design of its own: run it
through the flow, where CTS builds its clock tree, and give the parent
its abstract as a macro.

A module named in a spec whose memory has an initial value stops the
build: generate_ram's storage has none, and the value would be lost
without a word. The spec's read_latency is generate_ram's
-register_read_address.

The RAMs the wrappers instantiate as macros are listed in
regfile_cores.txt: they are in blackboxes.txt but no module of the
sources, so the check that every AUTO_MEMORIES module is a black box
after read_slang skips them.

Uses generate_ram's register-file options (OpenROAD#11723), in
tools/OpenROAD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@oharboe
oharboe force-pushed the auto-memories-regfiles branch from b9008ea to e82ccee Compare November 3, 2026 08:16
@oharboe
oharboe marked this pull request as ready for review November 3, 2026 08:28
@oharboe
oharboe requested a review from maliberty November 3, 2026 08:37
oharboe added a commit to oharboe/OpenROAD-flow-scripts that referenced this pull request Nov 3, 2026
CoreMiniAxi.sv is regenerated from coralnpu b50b85a9 by
src/coralnpu/generate, and the design is configured for it:

- The five TCM banks (ITCM one, DTCM four) are coralnpu's Sram, 512 x
  128 with one read-write port and a 16-lane byte mask. sram.memories
  names its pins (ADDITIONAL_MEMORIES) and AUTO_MEMORIES replaces it
  with a generated macro, write mask and all. The previous build swapped
  in USE_ASAP7 fakerams, which have no write mask, so a masked write
  wrote all 16 bytes.
- Regfile and FRegfile keep their words as separate registers, with no
  array for yosys to infer. surgery.py (SYNTH_VERILOG_SURGERY) moves
  them into Regfile_rf and FRegfile_rf, which AUTO_MEMORIES_REGFILES has
  generate_ram build as standard cells, every word with its
  asynchronous reset: Regfile 32 x 32 with x0 reading zero, nine reads
  and six writes; FRegfile 32 x 32, four reads and two writes.
- The clock is 1,900 ps in the platform's picoseconds (it was 10.00),
  with the platform's set_max_delay IO budgets; the asynchronous reset
  is not timed. The kept hierarchy is coralnpu's units by name, with
  OPENROAD_HIERARCHICAL=1.
- The divider's 128 x 83 SRT table is a ROM yosys maps to logic; a
  ROM is not counted against SYNTH_MEMORY_MAX_BITS.

surgery.py recognises each register file token for token and stops the
build on anything else. Each was simulated before and after the
surgery, and generate_ram's netlists against the behavioural modules
the surgery writes, on the same random inputs, every output compared
every cycle, with a negative control for each that is caught.

Needs AUTO_MEMORIES_REGFILES (The-OpenROAD-Project#4781), the supply pins of dont_touch
instances connected (The-OpenROAD-Project#4782) and a parameterized module as a macro
(The-OpenROAD-Project#4783).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@openroad-ci

openroad-ci commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

🔍 QoR check

Metrics reflect the PR merge build — i.e. what will land on the target branch.

Commit daf443b · Jenkins build #2 · Baseline: build · View build on dashboard

62 design(s) checked — 0 with regression(s), 1 without a comparable baseline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants