Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the tage_update design, which models one cycle of a TAGE branch predictor's training based on XiangShan's Frontend, including the top-level logic, individual tables, and SRAM models. The review feedback highlights two critical issues: first, the write buffer in tage_table.sv does not preserve FIFO ordering, potentially causing Write-After-Write hazards and simulation X-propagation; second, in tage_update.sv, a lack of hit in any TAGE table results in an incorrect fallback prediction using an invalid entry from table 0 instead of a default prediction.
|
@jhkim-pii @maliberty FYI - trying to extract friendly ORFS idiomatic tests that are readable and don't give up domain knowledge representative of real problems in XiangShan with OpenROAD. |
A single-concern test design mined from XiangShan's TAGE branch predictor: one register-to-register cycle that starts at every table's SRAM read registers, decides a provider in the middle and ends at a write buffer beside every table's SRAMs. Readable parameterised SystemVerilog read by slang, AUTO_MEMORIES SRAMs in the firtool port convention, the platform's constraints.sdc, and a FLOW_VARIANT ladder small|medium|large with base = large, the smallest that shows the effect. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The FakeRAM width fix this design needs is in #4597. It has to be hooked up before tage_update can be added to CI. With the fix, all three variants have been tested locally on this ORFS master and run through final; the numbers are in the description. |
The write buffer took the first free slot for every write and drained the lowest dirty one, so after a drain freed a low slot a newer write to a set could sit below an older write to the same set and drain first, leaving the older entry in the SRAM. XiangShan's WriteBuffer avoids that by updating a pending entry for the same set (hitMask) rather than allocating; the buffer here does the same, and keeps the lowest-dirty drain, which is XiangShan's and the end of the path this design measures. With no hitting table the prediction fell back to an alternate counter read from a miss; it is now not taken, the base prediction's job in XiangShan. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🔍 QoR checkMetrics reflect the PR merge build — i.e. what will land on the target branch. Commit 62 design(s) checked — 0 with regression(s), 0 without a comparable baseline. |
The TAGE's stage-2 direction now decides the next stage-0 read, as in XiangShan's Bpu.scala: an override of the stage-1 prediction flushes stage 1 and stage 0 reads from the stage-2 target, at the bank that pc hashes to. bpu_ctrl.sv is that stage control; the targets are inputs, read from the BTBs, which are not this design's concern. RTLMP_MIN_CHANNEL_SIZE 8 8: with 4 4 the new netlist's macro placement left an M2 channel the power grid could not repair (PDN-0179) on medium. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured against XiangShan's Frontend, the first revision's path was a third of XiangShan's (486 against 1,717 ps at global route) and the override loop alone did not move it: XiangShan's path travels six times the distance between its ends and this design's did not. The detour comes from the main BTB. Stage 2's prediction is the first taken slot of the main BTB's result, with the TAGE's direction for its conditional branches (Bpu.scala s2_takenMask, s2_firstTakenBranchOH, s2_override), so the logic that decides needs both sets of SRAMs' outputs and sits between them. mbtb.sv models the main BTB at XiangShan's shape (two halves, internal banks, one-way 256x46 SRAMs, the slot order compared at stage 1 and registered); bpu_ctrl.sv is the stage-2 selection and the override. With it, large travels 13.9 times the distance between its ends, and its path is 829 ps at global route. base is now medium, the smallest variant that shows the detour (6.2 times), in 10 minutes; large is XiangShan's size and takes 46. CORE_UTILIZATION 30, which large's 160 macros need (MPL-0008 at 35). Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@vvbandeira @maliberty CI snags... |
The design inherited asap7's MAX_ROUTING_LAYER of M7, while XiangShan, whose path it reproduces, routes every block and its top level to M9. asap7's power grid uses M1, M2, M5 and M6 only, so M8 and M9 are free for signals. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
RTLMP_MIN_CHANNEL_SIZE 8 8 was there to get past a power grid failure (PDN-0179) on medium with 4 4. With ORFS's defaults every rung now passes floorplan, power grid included, and 8 8 itself fails macro placement on large (The-OpenROAD-Project/OpenROAD#11628). Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The results table measured a revision that routed to M7 and timed the generated SRAMs as black boxes, and any table of this kind is out of date at the next bump. The README now says what the design adds to the tests, where the worst path ends (an SRAM's read address or enable, the banks the next pc reads), how the path changes along the size ladder, and what to look at. Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
Brings flow/designs/asap7/tage_update up to the design as it stands in The-OpenROAD-Project/OpenROAD-flow-scripts#4595: the main BTB, the decision between the TAGE's SRAMs and the main BTB's; routing to M9, as XiangShan does; no macro placer options; and a README that says what the design adds to the tests and what its worst path does along the size ladder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
It fails for me: gen_memories: FAKERAM_RUN_PY not set and FakeRAM run.py not found. |
|
The branch predated #4611, which moved FakeRAM in-tree and dropped On master the design then needs these fixes:
With all of them applied, base runs through #4661 makes the first one a hard stop right after the sources are read, naming the modules, instead of the memory-size error. |
slang's --keep-hierarchy elaborates one module per instance and names it `<definition>$<instance path>`. The detector named a memory after its module, so a memory module instanced twice produced two entries, two liberty views of one array, and two uniquified names in blackboxes.txt. read_slang's --blackboxed-module matches the definition's name only and ignores a name it does not know, so nothing was blackboxed: every array was elaborated, flattened into its parent, and synthesis stopped at SYNTH_MEMORY_MAX_BITS. asap7/tage_update (#4595) instances each of its SRAM definitions 8 to 16 times and hits this. The detector now cuts a module name at the first `$` when an identifier precedes it (yosys's own `$paramod\...` names have nothing before it and stay whole) and collapses the copies into one entry. Copies that disagree in shape or pins are an error: one liberty view per definition cannot serve a definition parameterised on its memory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
The GDS merge reads the final DEF through a KLayout technology built from the tech, standard-cell and ADDITIONAL_LEFS LEFs. The LEFs AUTO_MEMORIES generates were not among them, so the merge stopped at the first generated macro: Macro not found in LEF file: mbtb_entry_sram And a generated macro has no GDS, while a platform's GDS_ALLOW_EMPTY pattern (asap7: fakeram.*) only matches the platform's own memories, so with the LEF found, every generated macro would have been reported as an empty cell. With AUTO_MEMORIES=1, klayout.lyt now takes the generated LEFs, the ones load.tcl reads, and is rebuilt when they change; def2stream.py allows the modules listed in memories/blackboxes.txt to be empty, taking the first column of each line. Found with asap7/tage_update (#4595), which now writes 6_final.gds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
@maliberty fixed problems. This has been helpful for me, is this something that ORFS/OpenROAD maintainers would find useful? Possibly something it would be useful to have in CI, but certainly useful in my case for more specialized testing. |
|
|
|
TL;DR: tage_update is a test design for the full AUTO_MEMORIES solution. Merge it now, and we can use it for testing as the PRs trickle in. It is not hooked up to CI. Status: with master merged in, it stops at To run it today, use bazel-orfs, which carries the open PRs as patches: git clone https://github.com/The-OpenROAD-Project/bazel-orfs
git clone https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts
cd bazel-orfs
bazelisk build -c opt @openroad//:openroad @yosys//:yosys @sv-elab//src/yosys_plugin:slang.so
B=$PWD/bazel-bin/external
cd ../OpenROAD-flow-scripts
git checkout $(grep -A1 '^orfs.source(' ../bazel-orfs/MODULE.bazel | grep -o '[0-9a-f]\{40\}')
for p in $(sed -n '/^ORFS_PATCHES = \[/,/^\]/p' ../bazel-orfs/orfs_source.bzl | grep -o '[0-9]*-orfs-[^"]*\.patch'); do
git apply ../bazel-orfs/patches/$p
done
git fetch origin pull/4595/head
git checkout FETCH_HEAD -- flow/designs/asap7/tage_update flow/designs/src/tage_update
cd flow
YOSYS_PLUGIN_PATH=$B/sv-elab+/src/yosys_plugin make DESIGN_CONFIG=./designs/asap7/tage_update/config.mk \
OPENROAD_EXE=$B/openroad+/openroad YOSYS_EXE=$B/yosys+/yosysRun that way, it goes through final: 40 SRAM macros, WNS -225.95 ps at the 473 ps clock, 447 s. The worst paths start at |
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
|
@maliberty 🥹 ? |
asap7/tage_updateadds to the variety, relevance and fast turnaround of the ORFS tests: generated SRAMs at scale (6 / 40 / 160 macros throughAUTO_MEMORIES) on ORFS's default flow settings, the structure of a TAGE branch predictor as in XiangShan, and a size ladder whose 10-minute base variant already shows the effect.The design is one cycle of the predictor's stage-2 decision, between the TAGE's SRAMs and the main BTB's, and back to the banks the next pc reads. It is readable SystemVerilog read by slang, and the sources cite the XiangShan lines each piece models. README.md describes what the path does as the field of SRAMs grows.
The default variant (medium, 40 macros) and large (160 macros):
cd flow make DESIGN_CONFIG=./designs/asap7/tage_update/config.mk make DESIGN_CONFIG=./designs/asap7/tage_update/config.mk FLOW_VARIANT=small make DESIGN_CONFIG=./designs/asap7/tage_update/config.mk FLOW_VARIANT=large🤖 Generated with Claude Code