Add multi-layered L1/L2 data cache and per-block shared memory#61
Open
mouryadwarapudii wants to merge 1 commit into
Open
Conversation
Implements the first item from the README's advanced-functionality list: a non-blocking, set-associative L1 (per-core, flushed per block) and L2 (shared, persists per kernel) cache hierarchy in front of the memory controller, plus an on-chip shared memory scratchpad with new LDS/STS instructions so threads in a block can exchange data without round-tripping through global memory. Existing matadd/matmul kernels pass unmodified; new test_shared_memory and test_cache kernels cover the new functionality. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
cachemodule (src/cache.sv) used for both a private per-core L1 (flushed on each new block, avoiding cross-core coherence complexity) and a shared L2 (persists per kernel) sitting in front of the existing memory controller.src/shared_memory.sv+src/shared_lsu.sv) local to each core, with two new ISA instructionsLDS/STSso threads in a block can exchange data without round-tripping through global memory. The existing lockstep scheduler gives this implicit barrier semantics for free.Testing done
All four kernel-level tests were run locally with Icarus Verilog 13.0 + cocotb 1.9.2 + sv2v, via the project's existing
make test_%flow (make compile→sv2v→iverilog→vvpw/ cocotb). Results:make test_mataddmake test_matmulCMP/BRnzplooping), unmodified - confirms branching/looping control flow is unaffected.make test_shared_memorySTStheir own%threadIdxinto shared memory, then eachLDSs a different thread's slot (3 - threadIdx) and stores it to global memory. Verifies cross-thread visibility of shared memory and that the lockstep scheduler acts as an implicit barrier (every thread's write is guaranteed visible before any thread's read).make test_cachedut.cores[0].core_l1_hit_count/core_l1_miss_countdirectly, that the L1 cache actually recorded ≥1 miss (the cold load) and ≥4 hits (the repeat loads) rather than just happening to produce correct results some other way.Beyond the kernel-level tests, correctness of the cache's line-fill and multi-channel arbitration logic was verified in isolation with standalone Icarus Verilog testbenches (not part of this PR, used only for local debugging) driving the
cachemodule directly with concurrent read/write requests and a simple synchronous backing-memory model, both single-cache and chained L1→L2 configurations, before wiring it into the full GPU. This is how two real races were caught and fixed:mem_read_validcontinuously asserted let the downstream memory answer with stale data for one cycle.readyto actually deassert before reissuing the next word's request, instead of a fixed one-cycle wait.How to test this PR
Prerequisites (see README's Simulation section):
Then, from the repo root:
Each target prints a cocotb
PASS/FAILsummary line and writes a full cycle-by-cycle execution trace + before/after data-memory dump totest/logs/log_<timestamp>.txt, in the same format the existingtest_matadd/test_matmullogs use.To inspect cache behavior directly (e.g. while modifying
src/cache.sv), the per-core L1 stats are reachable from a cocotb test viadut.cores[<i>].core_l1_hit_count/core_l1_miss_count, and the shared L2's via the top-leveldut.l2_hit_count/dut.l2_miss_countports -test/test_cache.pyshows a working example of reading these mid-simulation (they get reset along with the rest of the core's state right when its last block finishes, so they need to be sampled during the run rather than afterdut.done).