Skip to content

cva6: D-cache data RAM drops its byte enables, so every cache write corrupts the other way #4769

Closed

Description

@saikatchatrg

Where: flow/designs/src/cva6/core/cache_subsystem/hpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv (unchanged
since cb73ed6; same at 26Q4 ecb3cfdeb), used by designs/asap7/cva6.

What: the wrapper replaces upstream's hpdcache_sram_wbyteenable_1rw with fakeram7_128x64, which has no write
mask, and leaves its wbyteenable input unconnected. cv32a65x packs both ways of a D-cache set into each 64-bit RAM
word (cva6_hpdcache_subsystem.sv: dataWaysPerRamWord = min(2, 128/32) = 2). hpdcache_memctrl.sv replicates the
write data into both 32-bit lanes and selects the way only through the byte enables. With them dropped, every refill and
every store hit, full-word ones included, also overwrites the other way's word at that address. Any program that fills
both ways of a set reads wrong data. The I-cache is not affected (one macro per way, byte enables all ones).

Shown in simulation: upstream cva6 at 3a389af (the commit designs/src/cva6 is based on) with this tree's changed
files, upstream's Verilator testharness, target cv32a65x, Verilator 5.008, behavioural models of the four fakeram7
macros (read on a rising clock with ce_in high, write when we_in, hold otherwise). A 40-line C program writes two
16-byte lines 1 KB apart (one set, both ways), then reads them back alternately and returns the mismatch count:

RTL result cva6 iss_cmp against Spike
upstream's hpdcache_sram_wbyteenable_1rw pass, 525 cycles 100 GPR updates matched
this hpdcache_sram_wbyteenable.sv fail (tohost = 1), 525 cycles first mismatch at c.lw a2, 8(a5): Spike 0x11110002, RTL 0x22220002 (the other way's word)

Consequence: the cva6 netlist the flow builds does not compute correctly; its timing and area are not affected, but
any gate-level or activity-based use of it is.

Possible fixes: a data-RAM macro with a byte write mask connected to wbyteenable, or one macro per way.

Activity

  1. oharboe commented on Oct 30, 2026

    @oharboe
    Collaborator

    @maliberty FYI.... generate_ram and patches carried in bazel-orfs will fix this hope. LEC could help too ...

  2. saikatchatrg commented on Oct 31, 2026

    @saikatchatrg
    Author

    As far as I can see, none of the bazel-orfs patches replaces hpdcache_sram_wbyteenable yet. A generated data RAM with a byte mask on wbyteenable would fix it. LEC between flow stages wouldn't catch this one, because the netlists match the RTL; it shows up in simulation, or against upstream's byte-enabled wrapper.

  3. oharboe commented on Oct 31, 2026

    @oharboe
    Collaborator

    You're right, and sorry: I misremembered. I thought I had used cva6 in bazel-orfs's CoreMark/Joule study, where a simulation would have caught this, but cva6 is only a literature point there. No carried patch replaced this wrapper, and LEC between flow stages can't see it: the netlists match the RTL, and the RTL is what's wrong.

    A fix, carried in bazel-orfs for now: The-OpenROAD-Project/bazel-orfs#1484 (draft). It puts hpdcache_sram_wbyteenable.sv back to upstream's, unchanged, with upstream's behavioural hpdcache_sram_wbyteenable_1rw, and lets AUTO_MEMORIES make that RAM a 128 x 64 macro with 8 byte-mask lanes, its pins named by a .memories override as asap7/coralnpu does for its Sram. cv32a65x's MSHR uses the flip-flop register bank, so the data RAM is the only instance, and the I-cache is unaffected as you said.

    It is not tested yet, not even built past analysis. Feel free to try your two-way test program on it.

  4. saikatchatrg commented on Oct 31, 2026

    @saikatchatrg
    Author

    Ran the two-way test on #1484's RTL. The two files patch 0202 restores, hpdcache_sram_wbyteenable.sv and macros/behav/hpdcache_sram_wbyteenable_1rw.sv, are byte-identical to the ones in the tree the test passed on (upstream cva6 3a389af with ORFS's other changes to designs/src/cva6, upstream's Verilator testharness, cv32a65x, behavioural models of the other fakeram7 macros). Re-run today: SUCCESS (tohost = 0) after 525 cycles, and cva6's iss_cmp against Spike: 100 matched. So with the behavioural RAM the core computes correctly. Not covered here: the generated 128 x 64 macro's own model in place of the behavioural RAM, which your kepler-formal check covers at depths 2 and 4.

  5. saikatchatrg commented on Nov 1, 2026

    @saikatchatrg
    Author

    Thank you for turning this around so quickly and so thoroughly: all four RAMs back to upstream's RTL, each macro checked by LEC with controls, and the change upstreamed as #4776 and #4777. It was a pleasure to check against.

  6. maliberty commented on Nov 4, 2026

    @maliberty
    Member

    Resolved?

  7. oharboe commented on Nov 4, 2026

    @oharboe
    Collaborator

    Resolved?

    The PRs are in flight. I would normally close the issue as I'm happy using only PRs to track work, but this project generally keeps issues open until PRs are merged. To me this is a matter of preferences.

  8. added a commit that references this issue on Nov 6, 2026
    5494310
  9. saikatchatrg commented on Nov 6, 2026

    @saikatchatrg
    Author

    Thanks @oharboe for the fix, and @maliberty for the review.

    We reran the test from this issue on #4777's merge (8d33f937f): ORFS master's designs/src/cva6 with asap7/cva6/surgery.py applied to the techno cut, the rest as above (upstream cva6 at 3a389af, its Verilator testharness, cv32a65x, Verilator 5.008). The six RAM files in master are byte-identical to upstream's.

    RTL two-way test CoreMark, 1 iteration
    master after #4777 pass, 525 cycles; iss_cmp 100 GPR updates matched; RVFI trace identical to the upstream-wrapper run above pass, 281,221 cycles; iss_cmp 191,314 matched, 9 mismatches, all mcycle/minstret reads around the timed loop (Spike's counters are not cycle-accurate)
    26Q4 (ecb3cfdeb), as a control fail (tohost = 1), same first mismatch as above fail: no exit within the 2,000,000-cycle time-out

    So the RTL the flow now synthesizes keeps the D-cache byte enables. We simulated the RTL only, not the macros AUTO_MEMORIES makes from it.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions