Skip to content

FakeRAM asap7: pick a column mux factor instead of hardcoding 1 - #4659

Merged
maliberty merged 3 commits into
The-OpenROAD-Project:masterfrom
oharboe:fakeram-asap7-column-mux
Oct 12, 2026
Merged

maliberty merged 3 commits into
The-OpenROAD-Project:masterfrom
oharboe:fakeram-asap7-column-mux

Conversation

@oharboe

@oharboe oharboe commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

The ASAP7 backend hardcodes "column_mux_factor": 1, so a generated array is rows bit cells tall and bits wide with nothing folding it. asap7/tage_update's (#4595) 512x17 SRAM comes out 2.28 x 166.6 um, 73:1, and with 40 such macros macro placement stops with MPL-0065, "The movable cells do not fit in the macro placement area".

The platform's own views are not built this way. Height scales as rows/column_mux_factor and width as bits*column_mux_factor, and the shipped LEFs read back through that relation give the factor each was generated with:

macro size (um) column_mux_factor
fakeram7_2048x39 20.33 x 166.60 4
fakeram7_256x32 8.36 x 42.00 2
fakeram7_256x256 33.25 x 84.00 1

column_mux_factor is now optional in the FakeRAM2.0 process config. When it is absent, FakeRAM2.0 picks one per memory: the power of two that brings rows/factor closest to bits*factor, after banking. The asap7 config leaves it out; a config that sets it keeps its value, so every existing cfg is unchanged. The picked factor reproduces 256x256 exactly and 256x32 and 2048x39 within one step. Area does not change: column muxing moves bit cells between the two dimensions. The 512x17 SRAM becomes 8.93 x 42.0 um, 4.7:1, and tage_update gets through macro placement. The test generates that shape and fails at 73:1 without the change.

A follow-up gives a generated macro a minimum width of one power-strap pitch: tage_update's 64x16 SRAM is 4.18 um wide after this change and floorplan stops with PDN-0179.

🤖 Generated with Claude Code

The ASAP7 backend hardcodes `"column_mux_factor": 1`, so a generated
array is `rows` bit cells tall and `bits` wide with nothing folding it.
A deep, narrow memory comes out as a sliver: asap7/tage_update's
512x17 SRAM is 2.28 x 166.6 um, 73:1, and with 40 such macros macro
placement stops with MPL-0065, "The movable cells do not fit in the
macro placement area".

The platform's own views are not built this way. Height scales as
rows/column_mux_factor and width as bits*column_mux_factor, and the
shipped LEFs read back through that relation give the factor each was
generated with:

    fakeram7_2048x39   20.33 x 166.60 um   -> column_mux_factor 4
    fakeram7_256x32     8.36 x  42.00 um   -> column_mux_factor 2
    fakeram7_256x256   33.25 x  84.00 um   -> column_mux_factor 1

The factor is now chosen per memory: the power of two that brings
rows/factor closest to bits*factor. That reproduces 256x256 exactly and
256x32 and 2048x39 within one step. Area does not change: column
muxing moves bit cells between the two dimensions. The 512x17 SRAM
becomes 4.7:1, and tage_update gets through macro placement.

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 a mechanism to fold tall memory arrays into square shapes by calculating an appropriate column multiplexer factor, and adds a unit test to verify this behavior. The review feedback suggests improving the mathematical calculation in generate.py by using math.log2 and removing redundant type casting, as well as adding a safety check in the unit test to handle potential regex search failures gracefully.

Comment thread tools/FakeRAM2.0/orfs_asap7/generate.py Resolved
…t SIZE

Review: math.log2 instead of math.log(x, 2), and math.floor already
returns an int. Same factor for every shape: checked over rows 1..70000
and bits 1..300. The test now says so when the generated LEF has no
SIZE, instead of failing on None.groups().

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

openroad-ci commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

🔍 QoR check

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

Commit ee3bcc3 · Jenkins build #3 · Baseline: build · View build on dashboard

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

Comment thread tools/FakeRAM2.0/orfs_asap7/generate.py Outdated
rows = m.get("rows", 128)

process_config = dict(ASAP7_PROCESS_CONFIG)
process_config["column_mux_factor"] = pick_column_mux_factor(rows, bits)

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.

This does not change it just for asap7 but unconditionally overwrites the value. Better would be if it is undefined in the json then select one and undefine it for asap7 by default.

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.

Thanks, that is better. In 7f37494 column_mux_factor is optional in the process config: get_macro_dimensions picks one per memory only when the config leaves it out (after banking), and the asap7 config no longer sets it. A config that sets it keeps its value, so all the existing cfgs and their tests are unchanged; macro_dim_test.py now covers picked, explicit and banked.

… out

Review: the asap7 backend overwrote column_mux_factor unconditionally,
so a config could not choose one. column_mux_factor is now optional in
the process config. When it is absent, get_macro_dimensions picks the
power of two that squares the array, after banking has folded it; when
it is set, it is kept. The asap7 config no longer sets it, so asap7
picks one per memory as before. Every config that sets it, including
all the test cfgs, is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@oharboe
oharboe requested a review from maliberty October 11, 2026 06:54
@maliberty
maliberty merged commit e5cc6e7 into The-OpenROAD-Project:master Oct 12, 2026
12 checks passed
maliberty pushed a commit that referenced this pull request Nov 2, 2026
A generated macro's power pins are horizontal M4 rails; the platform's
macro grid connects them to the core's vertical M5 straps, one per net
every 5.4 um (grid_strategy-M1-M2-M5-M6.tcl). The backend sizes a macro
from its bit cells alone, with a floor on height and none on width, so
a small memory can come out narrower than the strap pitch, land between
two straps of a net, and fail pdngen for the whole design. In
asap7/tage_update, with the column mux of #4659, the 64x16 SRAM is
4.18 um wide and floorplan stops with PDN-0179, "Unable to repair all
channels".

The process gets a min_width_um floor beside the existing height floor,
and the asap7 backend sets it to one pitch plus one strap plus the
rails' inset at both edges, 5.616 um: a strap of each net then crosses
the rails wherever the macro is placed. Wider macros are unchanged. The
64x16 SRAM becomes 5.70 um wide and tage_update gets through PDN.

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

3 participants