Repository navigation
Conversation
… area ledger
riscv32i's register file inlined, in mode netlist (macro-placed, then
dissolved) and in mode macro, on ORFS's own riscv32i config, beside
ORFS's riscv32i (flip-flops) to global route. Manual: a study.
ledger.tcl accounts for every um2 of the core on any stage's ODB:
macros, rows cut beyond the macro boxes, standard cells with the
register file's split out, taps, fill and empty row area. On this
commit, at 62 %:
flops 951 ps, core 4012 um2
inlined 954 ps, core 3544 um2
netlist 954 ps, core 4319 um2; the 996 um2 abstract holds 478 um2
of cells, and the floorplan is sized by the abstract
macro MPL-0003
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
…rvice columns netlist.regfile with service_sites 0: the abstract shrinks from 53.46 x 18.63 to 44.82 x 18.63 um (996 to 835 um2) and the core sized by riscv32i's 62 % from 4319 to 4067 um2, and macro placement fails: MPL-0003, no valid tiling, as in mode macro. The 8 um channels (RTLMP_MIN_CHANNEL_SIZE) around the four FakeRAMs and the register file need more core than the cells do; the larger abstract was what gave the placer its room. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
riscv32i's RTLMP_MIN_CHANNEL_SIZE 8 8 is sized for its FakeRAMs; left unset ORFS uses 20 20 and every shape, flops included, fails macro placement. At 2 2, flops, inlined and netlist_service0 reach global route; the core is unchanged (the floorplan is sized by utilization). netlist (the 996 um2 abstract) fails FLW-0004, the register file placed partly outside the core, and macro fails PDN-0233. Minimum period at global route, placement parasitics, 950 ps clock: shape 8 8 2 2 flops 950 ps 992 ps inlined 944 ps 950 ps netlist 953 ps FLW-0004 netlist_service0 MPL-0003 939 ps Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
generate_regfile (patch 0010), mode netlist: the abstract is the bounding box of the cells it leaves placed, plus one row for a parent of the other row parity, moved to the origin; the header column, the address band and the ring margin were the periphery's or nobody's, and initialize_floorplan -utilization charged them as macro area. No service columns by default in mode netlist (service_sites -1: 40 in a macro, none in netlist), the clock tree's buffers go wherever the parent has room. riscv32i's register file: 53.46 x 18.63 um (996 um2, 48 % cells) to 39.58 x 17.01 um (673 um2, 72 %). macro_place.tcl (patch 0089): each register file in mode netlist gets an instance halo of MACRO_ROWS_HALO_X/Y. The rows are cut that far around the other macros as it dissolves; without the halo the macro placer could set a FakeRAM closer and the cut took the rows under the register file's edge cells (FLW-0014). The padded outline hid this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
At riscv32i's 62 % the netlist shape no longer tiles at either channel setting (MPL-0003): the four 42 um tall FakeRAMs and the 17 um register file with its 2 um row halo need 63 um of a 61.6 um core. At 55 %, the utilisation AutoMemories.md measured the padded abstract at (959 ps on 4 644 um2): 938 ps on 4 283 um2, global route, placement parasitics, 950 ps clock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
…here Patch 0010 gave src/ram/test an asap7 symlink to ../../../test/asap7, as Nangate45 and sky130hd are upstream; bazel's patcher does not create symlinks, so the seven generate_regfile tests could not run from this repository (missing input file asap7/...). They now read ../../../test/asap7 and depend on //test:asap7_data and a new //test:asap7_nldm_data, as src/est/test does. test/regfile:openroad_ram_tests runs OpenROAD's ram tests, generate_ram's four and generate_regfile's seven, so CI, which tests this repository's packages and not @openroad's, covers the generator. All eleven pass on the cropped netlist-mode abstract. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
generate_regfile (patch 0010) gets `periphery generator|verilog`. With `verilog` the periphery (address inverters, decode, write muxes, ties) is written into the netlist as assigns of its cells' functions, for synthesis to map with the parent's logic; the clock gates and the core stay cells. `generator`, the default, is what it built before. Neither dominates: it depends on how the array is integrated, so it is an option. Not yet with mode netlist, whose cells the flow dissolves from the netlist; that needs the core in a module of its own. riscv32i, inlined, global route, placement parasitics, 950 ps clock: periphery channels min period core generator 8 8 944 ps 3544 um2 verilog 8 8 938 ps 3516 um2 generator 2 2 950 ps 3544 um2 verilog 2 2 946 ps 3516 um2 The netlist: 418 assigns for the 403 decode ANDs and 15 address inverters, the 31 clock gates kept. test/regfile/sim simulates it beside riscv32i's RTL as it does the other two write styles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
generate_regfile (patch 0010): with `periphery verilog` and `mode netlist` the block is the core alone, <module>_core. The periphery leaves it for a wrapper module in the RTL module's place: the periphery as assigns, the clock gates as cells, around an instance of the core declared a blackbox. A net the core shares with the periphery becomes a core port; a module port only the periphery uses leaves the core. The LEF, DEF and a liberty of area and pins describe the core; -verilog writes the wrapper and <module>_core.v the core's netlist. ORFS patch 0108: gen_memories inlines the wrapper (inline.txt) and makes the core the macro: blackboxes.txt, regfiles.txt, its .lef, .lib and .place, so it is macro-placed with its halo and dissolves. test/regfile/sim simulates the wrapper and core beside riscv32i's RTL. riscv32i at 55 %, global route, placement parasitics, 950 ps clock: 940 ps on 4 287 um2, the generator's periphery 938 ps on 4 283 um2. The ledger matches riscv.dp.rf/*, the wrapper flattened by synthesis. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
…branch
Three gaps that kept Nangate45's cells from simulating:
- A pin's `three_state` was ignored, so a tristate buffer was a plain
buffer and every driver of a shared net drove it at once; it now
releases the net (1'bz) while three_state holds.
- `ff ("IQ" , "IQN")`, Nangate45's quoted state variables, did not
parse, so DFF_X1 assigned Q from an undeclared IQ; ff and latch take
them bare or quoted.
- An asynchronous set or clear branch of a cell with Q and QN assigned
both outputs without begin/end, a syntax error; each branch is now a
block.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The first generate_regfile feature carried onto generate_ram, Austin Rovinski's generator, as OpenROAD #11669's review asked: patch 0011, on 0010, one commit per future pull request. generate_ram took one read/write or one write port (RAM-0030). Now any number of write ports, each with its own decoder, data, write enables and address; one write port keeps its names, and generate_ram's four existing tests pass unchanged. A word written by two ports in a cycle keeps the last port's data, as the behavioral model does; the AO22 for the data is found by truth table, as the AOI22 is (an AOI22 and an inverter where the library has none, as on Nangate45). Not yet with -use_latch or -column_mux_ratio above 1. Tests: make_7x7_1r2w_nangate45, golden LEF, DEF and behavioral model in generate_ram's own format; and test/regfile/sim:ram_2w_sim_test, the netlist beside the behavioral model on Nangate45 under random writes on both ports, a quarter to the same word: 20 008 cycles, no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
… 0012) The second generate_regfile feature carried onto generate_ram, on 0011. generate_ram's read path is a tristate bitline per bit, so a library without a tristate cell, asap7, could not generate (RAM-0010). -read_style and_or reads through a tree per bit column: an AOI22 over each pair of rows, then NAND2 and NOR2 by turns, each node in a row of the span it covers. It is the default where there is no tristate cell, and can be asked for where there is one. A flop whose output is its data inverted is taken on that path, an inverter at each root undoing it. buildPortMap reckoned polarity from the state variable alone and took asap7's DFFHQNx1, whose state holds !D, for a true output; it now counts next_state too. NAND2 and NOR2 are found by truth table, as asap7 writes NAND2 as (!A) + (!B). Tests: make_8x8_2r1w_and_or_asap7, golden DEF and behavioral model in generate_ram's format; test/regfile/sim simulates generate_ram's 8 x 8 two-write RAM against its behavioral model in three shapes, Nangate45's tristates, Nangate45's trees asked for and asap7's: 20 008 cycles each, no mismatch. generate_ram's existing tests are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The third generate_regfile feature carried onto generate_ram, on 0012: -zero_word n reads 0 at word n and drops its writes, as a RISC-V x0. The row keeps its place in the grid without flops or clock gate, and the AND-OR trees are built over the other rows; with an inverted storage output the zero word stays in them with its own select as its term, so the root's inverter reads it as 0. Needs the AND-OR read path. Tests: make_8x8_2r1w_zero_asap7 in generate_ram's format; and the two-write RAM simulated with a zero word on asap7 (QN flops) and on Nangate45's trees (Q flops), 20 008 cycles each, no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The fourth generate_regfile feature carried onto generate_ram, on 0013: -reset_value v resets every word to v asynchronously. Each bit's flop is cleared or preset, the other pin held off by a tie per word slice; the pins come from the flop's ff group, and which gives which value counts the flop's output polarity (asap7's DFFASRHQNx1 stores !D). The reset port takes the flop's polarity, rst_n or rst; a parent adapts any other. An option, off by default: ibex, cva6, ariane, swerv and coralnpu reset their register files, each for reasons of its own. Tests: make_8x8_2r1w_reset_asap7 in generate_ram's format; the two-write RAM with -reset_value 0xa5 simulated on Nangate45 (tristates and trees, DFFRS_X1) and asap7: every word checked after each reset, random resets among 20 000 cycles of writes on both ports, no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The fifth generate_regfile feature carried onto generate_ram, on 0014: the words in banks, contiguous or interleaved in the address, some side by side and the rest stacked, as XiangShan's register files ask (224 words in 4 interleaved banks, 2 side by side). With banks each port decodes every word's whole address, an AND2 tree per word, so a bank need not be a power of two words; a read port is one tristate bitline or one AND-OR tree over every word. Without -banks nothing changes. Also gives each inverter column at least one port: an array with fewer rows than address bits had no address inverters at all. Tests: make_8x8_2r1w_banks_asap7 in generate_ram's format; the two-write RAM simulated in five bank shapes, tristate and AND-OR, contiguous and interleaved, side by side and stacked, with a zero word, and 12 words in banks of 3 (the simulation now takes a word count). No mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The sixth generate_regfile feature carried onto generate_ram, on 0015: -rb_ports n adds read ports with an address and a data output per bank, each bank read independently in the same cycle, as XiangShan's integer register file reads. Each (port, bank) is a read port of its own to the generator, decoding and reading only its bank's words. Tests: make_8x8_rb_asap7 in generate_ram's format; a plain and a banked read port simulated against the behavioral model on Nangate45 (interleaved, tristate) and asap7 (contiguous, AND-OR, zero word), every output every cycle, 20 008 cycles each, no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The seventh generate_regfile feature carried onto generate_ram, on 0016: -read_latency 1 registers every read port's address, a plain positive-edge flop per bit in the address inverter's cell, as XiangShan's register files read. A flop giving the address inverted (asap7's DFFHQNx1) swaps the decoder's literals instead of adding a cell. The storage flop serves where it is a plain one: findMaster passes over two-output cells, as Nangate45's flops all are. Tests: make_8x8_rb_latency_asap7 in generate_ram's format; registered reads simulated on Nangate45 (Q) and asap7 (QN, banks, a banked read port), 20 008 cycles each, no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The eighth generate_regfile feature carried onto generate_ram, on 0017: -write_style mux holds each word without a clock gate, every flop on the clock and an AO22 per bit taking the new data or the flop's own value (through an inverter where the flop's output is inverted), as XiangShan's register files are built by default. clock_gate, the default, is generate_ram's clock gate per word as before. Tests: make_8x8_2r1w_mux_asap7 in generate_ram's format; the hold mux simulated on Nangate45 (tristate) and asap7 (QN flops with banks and registered reads; and with a reset), no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The ninth generate_regfile feature carried onto generate_ram, on 0018: generate_regfile's mode netlist. -periphery unplaced leaves the periphery (address inverters and registers, decoders, select buffers, each word's select cell, the input buffers) for the parent to place, size and buffer; the outline is the placed core and a row; each pin sits where its connections land, on -pin_layer's tracks, for a macro placer before the parent dissolves the core. The same cut that took riscv32i's register file abstract from 996 to 673 um2. Tests: make_8x8_2r1w_unplaced_asap7 in generate_ram's format (176 cells placed inside the outline, 105 unplaced, 35 pins inside); the netlist simulated with its periphery unplaced, no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
-cells {role master ...} picks the cell for each role instead of the
smallest of its function: on asap7 those are the xp cells ORFS marks
dont_use and the hold buffer HB1xp67, which a fixed core cannot resize
after; generate_regfile named its cells for that reason. An AOI22 or
AO22 given is checked and pinned by its truth table, and findMaster4
reads the pins of the cell it picks rather than the last one matched.
-name names the block, so two RAMs of one size can share a design; the
ORFS switch onto generate_ram needs both.
Tests: the two-write RAM on asap7 with every role given, simulated
against its behavioral model; the netlist uses each given cell.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
…ROAD 0021) ORFS patch 0109: a register-file spec generate_ram can build is built by it. memories/regfile_ram.py translates the spec to generate_ram_netlist's options and writes a wrapper in the RTL module's place connecting its ports (widths from the yosys JSON) to generate_ram's, a reset's polarity adapted there; the RAM, <module>_ram, is inlined, or in mode netlist a macro with its periphery unplaced that regfile_dissolve.tcl dissolves as before. Specs with flop names for equivalence checking, folded bits or a Verilog periphery, and macros kept to the end, stay with generate_regfile for now. The translation names generate_regfile's asap7 cells where a spec names none, and NOR2x1, measured: NOR2xp33 at the read tree's root cost 23 ps. OpenROAD patch 0021: -decoder word, a balanced AND2 tree per word, as the banks decode; generate_ram's row decoder is an AND2 chain, about 60 ps of riscv32i's 220 ps read path. riscv32i, global route, placement parasitics, 950 ps clock: shape generator core period inlined, 62 % generate_regfile 3544 um2 944 ps inlined, 62 % generate_ram 3503 um2 943 ps netlist, 55 %, 2 um ch. generate_regfile 4283 um2 938 ps netlist, 55 %, 2 um ch. generate_ram 3968 um2 945 ps netlist, 62 %, 2 um ch. generate_ram 3512 um2 939 ps The macro-placed shape now fits riscv32i's own 62 % and matches the inlined one: the dissolved core is 55.3 x 8.6 um, 93 % cells, where generate_regfile's padded abstract was 48 %. At riscv32i's 8 um channels it does not fit (MPL-0006). test/regfile: the macro is RegFile_ram behind the wrapper; the blackbox, keep-synth and dissolve-probe expectations say so, and the probe finds the dissolved cells under the wrapper's instance. The ledger matches riscv.dp/rf.ram. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
generate_ram puts a word in one row, a bit's cells side by side, so a wide word with many ports is a long thin array: XiangShan's integer register file (64 bits, 12 read and 9 write ports) came out 1458 x 31 um. -bit_folds k lays the word's slices in k rows; the decoder, select-buffer and address-inverter columns take k rows a word. A folded word is written whole, one write enable a port, and its write logic is built in its first fold and shared by the others: as mask slices, the folds had each repeated it. ORFS 0109 translates a spec's bit_folds, and with store_name and read_reg_name now renamed in the database, every XiangShan register-file spec translates to generate_ram. Tests: the two-write RAM folded on Nangate45 (2 folds) and asap7 (4 folds, banks, registered reads, hold mux), simulated against the behavioral model, no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
generate_regfile chose its rows per word itself; generate_ram puts a word in one row unless told. Where a spec names no bit_folds and the first generation comes out more than 8 times as wide as tall, the translation regenerates it folded into the power of two of rows nearest the square: XiangShan's IntRegFile, 1458 x 31 um in one row, 247 x 242 um in 8. A heuristic with a high bar: riscv32i's 55 x 9 um strip, 6 to 1, is the shape that sits under its FakeRAMs, so it stays; a spec names bit_folds to choose. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
…022) With every fold's input buffers in one cell a column, IntRegFile's 72 buffers a column (8 folds, 9 write ports) set its width: 16 columns pitched 246.7 um wide around 182.3 um of widest placed cells, fill 58 %. A row a fold for them, above the words, gives the columns back to the bit cells: IntRegFile folded 8 is 182.3 x 242.2 um, 44 153 um2, below its 44 497 um2 unfolded, where folding had cost 34 %. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
-periphery verilog makes the block the core alone, <name>_core, and writes the periphery as a Verilog module <name> around it (-wrapper_verilog): its logic cells as assigns of their liberty functions, its clock gates, flops and ties as instances. A net the core shares with the periphery becomes a core port, renamed to a Verilog and liberty identifier, its net with it: the netlist names a port's net by the port. ORFS 0109 translates the spec's periphery verilog: the macro, or the inlined core, is <module>_ram_core inside generate_ram's periphery module and the RTL's wrapper; the address registers keep generate_ram's names there. riscv32i, global route, 950 ps clock, periphery as Verilog: shape generate_regfile generate_ram inlined, 62 % 3516 um2, 938 ps 3452 um2, 951 ps netlist, 55 %, 2 um ch. 4287 um2, 940 ps 3999 um2, 933 ps Tests: the two-write RAM with its periphery as Verilog simulated on Nangate45 (tristates, clock gates) and asap7 (AND-OR, banks, hold mux) against the behavioral model, no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
ORFS 0109's translation now covers a register file kept as a macro to the end: its pins placed on its edges by OpenROAD's pin placer on the spec's pin layers (tracks made from those layers' own pitch), and its liberty from write_timing_model, the block's own timing for the parent's STA, with the area the flow costs it by written in. riscv32i's macro arm gets there and stops at the floorplan: 61.5 x 8.9 um with its periphery does not fit a 60.2 um core at 62 %. Every port an `unused` or `reset` line lists is declared, not the first only. test/regfile/cores: regfile_sim_test takes generator = "generate_ram", which builds the spec through ORFS's own regfile_ram.py, the netlist AUTO_MEMORIES_REGFILES inlines. ibex's register file through it matches ibex's RTL under random reads, writes and resets (asynchronous reset to 0, unused inputs, x0); write priority as before; both negative controls fail as they should. regfile_ram.py is exported from the generated flow package for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Nothing uses generate_regfile any more: the equivalence checks (test/structured_gen_lec), structured_gen's golden test, the planner, the scaffolds and the planned parent's probes build or find generate_ram's RAM, through ORFS's regfile_ram.py, in the wrapper that takes the module's place. What the XiangShan register files needed beyond 0011 to 0023, each an option on generate_ram, default unchanged: - 0024 -write_priority or: colliding writes OR'd, as firtool's register files describe them (the mux-write equivalence checks failed without). - 0022, amended: -bit_folds with a short last fold (211 bits in 4, 954 in 8). - 0025 -service_columns: generate_regfile's tap_columns and service_sites, which regfile_ram.py had ignored. - 0026 -bank_column_layout contiguous: a row's words side by side, not interleaved bit by bit; RobEntryFile's parent found 6,483 slew violations on selects running the row, 608 with it, and legalizes. regfile_ram.py: write_priority, bank_column_layout (contiguous by default where a row holds more than one word, as generate_regfile's tile per word), the service keys, a power grid and VDD/VSS pins for a macro kept to the end, and a fold where a word's bits would span more than 150 um (RenameBufferFile, a word a row 258 um wide, did not legalize). The scaffolds' outlines are generate_ram's, and their ring holds the periphery generate_ram leaves to the parent. ideas/tile-generator.md: a tile generator beside generate_ram, for later in the campaign. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Collaborator
Author
|
Superseded by #1234, which carries everything from this study. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Study for The-OpenROAD-Project/OpenROAD#11669: why riscv32i's register file placed as a macro needs a bigger core than the same cells inlined. Draft: the fixes come here one at a time, each measured before it moves to the OpenROAD PR or the ORFS patches.
test/regfile/riscv32ibuilds riscv32i's register file in each shape the generator offers (nowgenerate_ram), on ORFS's own riscv32i config, beside ORFS's riscv32i (flip-flops).ledger.tclaccounts for every µm² of the core on any stage's ODB.riscv32i, 62 %, global route, 950 ps clock. Minimum period from placement parasitics on the global-route ODB (about 5 ps off the route log's reading); the core is sized by utilization, so the channel width doesn't change it.
RTLMP_MIN_CHANNEL_SIZE 8 8(riscv32i)2 2(*_narrow)periphery verilogservice_sites 0, 835 µm² abstractperiphery verilog, 55 %At 55 % with the padded abstract, AutoMemories.md measured 959 ps on 4644 µm².
Left unset, ORFS uses
20 20and every shape fails macro placement, flops included.The register file's abstract is 53.5 × 18.6 µm = 996 µm² and holds 478 µm² of cells. The rest is a decode column
mode netlistleaves to the parent (225 µm²), row ends and service columns (198 µm²) and tile slack (95 µm²).initialize_floorplan -utilizationcharges the whole abstract: 96 % of the 775 µm² larger core.Steps
*_narrowbeside them.service_sites 0, no code change: the abstract drops to 44.8 × 18.6 µm = 835 µm² and the core to 4067 µm², and macro placement fails with MPL-0003. riscv32i'sRTLMP_MIN_CHANNEL_SIZE 8 8, sized for its FakeRAMs, puts the macros at 3279 µm² with channels against 2239 µm² without; the padded abstract was what gave the placer room. So the generator fix needs the ORFS side with it.RTLMP_MIN_CHANNEL_SIZE 2 2on every shape (table). Narrow channels cost flops 42 ps, so the fix is a narrow channel for the register file only, not a global setting.generate_regfile(patch 0010): in mode netlist the abstract is the placed core's bounding box plus one row for row parity, and no service columns by default: 996 → 673 µm², 48 % → 72 % cells.MACRO_ROWS_HALO_X/Y, so the rows cut around the FakeRAMs as it dissolves stay clear of its core (FLW-0014 without it; the padded outline hid this).ramtests (generate_ram's 4 and a golden test per new option) run here as//test/regfile:openroad_ram_tests; the regfile tests read//test's asap7 files instead of a symlink bazel's patcher cannot create.periphery generator|verilog: who builds the periphery.verilogwrites it as assigns for synthesis to map with the parent; an option, since which is better depends on the integration. Simulated against riscv32i's RTL.periphery verilogwith mode netlist: the macro is the core alone,<module>_core, and a wrapper of the periphery is read in the module's place (ORFS patch 0108). Simulated against riscv32i's RTL.generate_ram(Austin's generator), one patch per future PR:generate_ram's existing tests unchanged; a new golden test in its format; simulated against its behavioral model on Nangate45 (tristate bitlines), collisions included.lib_to_veriloglearned tristate outputs and Nangate45's quoted flip-flops to make that simulation possible.-read_style and_or, an AOI22/NAND2/NOR2 tree per bit column, the default where the library has no tristate cell (asap7). A flop whose output is its data inverted (asap7'sDFFHQNx1) taken there;buildPortMapnow countsnext_statein a flop's polarity. Golden asap7 test ingenerate_ram's format; simulated in three shapes against the behavioral model.-zero_word: a word that reads 0 and drops its writes.-reset_value: asynchronous reset of every word, per bit cleared or preset by the flop's own polarity; polarity and synchronous reset adapted outside.-banks,-bank_columns,-bank_order: each word decoded whole, so banks need not be powers of two (XiangShan's 224 words in 4 interleaved banks). Also gives every inverter column a port: arrays with fewer rows than address bits had no address inverters.-rb_ports: banked read ports, an address and data per bank.-read_latency 1: registered read addresses.-write_style mux: a hold mux per bit instead of a clock gate per word.-periphery unplaced: the core alone placed and outlined, pins on a layer's tracks where their nets land (generate_regfile's mode netlist).generate_ram's format;test/regfile/simsimulates 24 shapes of netlist againstgenerate_ram's behavioral model on Nangate45 and asap7, 20 000 cycles each, no mismatch.generate_ram's own tests unchanged.-cells {role master}and-name: cells by role (the smallest asap7 cells are thedont_usexp ones and the hold buffer), blocks named per module.findMaster4now reads the pins of the cell it picks.-decoder word: a balanced AND2 tree per word; the row decoder's AND2 chain was 60 ps of riscv32i's 220 ps read path.-bit_folds k: a word in k rows, its write logic shared by its folds; XiangShan's IntRegFile (12 reads, 9 writes) went from 1458 x 31 um to square.-periphery verilog: the core a block of its own, the periphery a Verilog wrapper.-write_priority or: ports writing one word in a cycle write the OR of their data, as firtool's register files describe it (generate_regfile's default); the mux-write equivalence checks against XiangShan's RTL failed without it.-bit_foldswith a short last fold (FtqMetaQueueRedirect, 211 bits in 4; FtqMetaQueueResolve, 954 in 8).-service_columns {every sites}: empty columns in the array for a parent's buffers,generate_regfile'stap_columns/service_sites.-bank_column_layout contiguous: a row's words side by side instead of interleaved bit by bit (below).generate_ram:memories/regfile_ram.pytranslates a spec togenerate_ram_netlistoptions and writes a wrapper in the RTL module's place (ports from the yosys JSON, reset polarity adapted there); flops renamed tostore_name/read_reg_name. Every spec translates, kept macros included (pins placed, a power grid with VDD/VSS pins, a timing model with its area).riscv32i through
generate_ram(global route, placement parasitics, 950 ps clock):The macro-placed shape now fits riscv32i's own 62 % and matches the inlined one: the dissolved core is 55.3 × 8.6 µm and 93 % cells, where
generate_regfile's padded abstract was 48 %.ORFS onto
generate_ram, 0010 dropped: the equivalence checks (test/structured_gen_lec, all 21 pass), structured_gen's golden test, the planner, the scaffolds and the planned parent's probes findgenerate_ram's RAM in the wrapper.XiangShan's register files at real size in a parent (
test/structured_netlist, through CTS). Tight outlines exposed whatgenerate_regfile's half-empty tiles had hidden: a word's selects and write enables are as long as its bits are spread, and a parent buffers them inside a full array, where nothing legalizes.regfile_ram.pylays out a row's words contiguous by default and folds a word whose bits would span more than 150 µm. The scaffold's ring holds the peripherygenerate_ramleaves to the parent (7,027 µm², 82,040 cells for RenameBufferFile: a balanced decode per word and port).The reply to Austin on OpenROAD#11669 (the planned PRs, each with its use case), and #11669 closed in favour of them.
The breakout: 16 single-concern OpenROAD PRs and the ORFS ones; the usage text and README of the ram module tidied first.
ORFS: the floorplan sized by the register file's cell area. On riscv32i this makes the core smaller, which the FakeRAMs already do not fit; to measure on XiangShan.
Macro mode's MPL-0003: later, with RTL MP placing banks of memories on XiangShan.
Every target is manual. To reproduce:
🤖 Generated with Claude Code