Skip to content

x86 L1 Data Cache Simulator#3

Open
bugparty wants to merge 3 commits into
mainfrom
cpu-l1-cache-sim-4675641926694390111
Open

x86 L1 Data Cache Simulator#3
bugparty wants to merge 3 commits into
mainfrom
cpu-l1-cache-sim-4675641926694390111

Conversation

@bugparty

@bugparty bugparty commented Jan 26, 2026

Copy link
Copy Markdown
Owner

Implemented a Python-based CPU L1 Cache simulator mimicking x86 architecture features (32KB, 8-way, 64B line, Write-back, MESI). Added a SimulatedArray class to allow user code to interface with the simulated memory and track access patterns. Verification script included.


PR created automatically by Jules for task 4675641926694390111 started by @bugparty

Summary by CodeRabbit

  • New Features

    • L1 cache simulation (32 KB, 8‑way, 64 B lines) with write‑back MESI‑like states, LRU behavior, and per‑access statistics
    • Memory‑backed array abstraction providing indexable reads/writes through the cache
  • Visualization

    • Utilities to plot rolling miss rate, access heatmap, and 3D access frequency
    • Example runner that generates and saves these visualizations
  • Documentation

    • Added cache specification describing architecture and policies
  • Tests

    • Unit tests covering locality, associativity/eviction, write‑back, and data integrity

✏️ Tip: You can customize this high-level summary in your review settings.

This commit introduces a detailed simulation of an x86 L1 Data Cache.
- Capacity: 32KB
- Line Size: 64 Bytes
- Associativity: 8-way
- Policy: Write-back, LRU Replacement
- Protocol: MESI (Single core implementation)

Includes `SimulatedArray` helper for Python integration and `verify_cache.py` for testing.

Co-authored-by: bugparty <1510776+bugparty@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Jan 26, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a new in-process L1 data cache simulation (32 KB, 8-way, 64 B lines) with MainMemory, MESI-like states, LRU replacement, write-back behavior, a SimulatedArray abstraction, unit tests, documentation, and visualization utilities for analysis.

Changes

Cohort / File(s) Summary
L1 Cache Implementation
cpu_l1_cache.py
New full cache simulation: CacheLine, MainMemory, L1Cache (address decomposition, 64B lines, 8-way/64-set lookup, LRU victim selection, hit/miss handling, write-back on M eviction, per-access stats) and SimulatedArray (Python array API over cache-backed memory).
Cache Verification Tests
verify_cache.py
New unit tests (TestCacheSimulator) validating spatial locality, associativity/evictions (8-way behavior), write-back correctness, and basic data integrity.
Specification Doc
CACHE_SPECS.md
New documentation describing cache parameters (32 KB, 64 B line, 8-way, 64 sets), policies (write-back, MESI-like, LRU), address decomposition, and verification guidance.
Visualization Utilities
cache_viz.py
New plotting helpers: plot_miss_rate, plot_access_heatmap, plot_access_3d (matplotlib / numpy) to visualize miss-rate and access patterns from L1Cache / SimulatedArray.
Visualization Runner
verify_viz.py
New script run_simulation() that exercises access patterns (sequential, stride, random) against the cache and emits miss-rate, heatmap, and 3D visualizations.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Cache as L1Cache
    participant Mem as MainMemory

    App->>Cache: read/write(address, size, data?)
    activate Cache
    Cache->>Cache: decompose address -> tag, set_index, offset
    Cache->>Cache: _find_line(set_index, tag)
    alt Hit
        Cache->>Cache: update LRU / state (on write)
        Cache-->>App: return data / ack
    else Miss
        Cache->>Cache: _get_victim(set_index)
        alt Victim state == M
            Cache->>Mem: write_back_block(evict_addr, block)
            activate Mem
            Mem-->>Cache: ack
            deactivate Mem
        end
        Cache->>Mem: read_block(block_addr)
        activate Mem
        Mem-->>Cache: block_data
        deactivate Mem
        Cache->>Cache: install line, set state (E/M), update LRU
        Cache-->>App: return data / ack
    end
    deactivate Cache
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hop through lines of bytes and code,
I stash them safe in cache-line mode.
With MESI whispers, LRU dance,
I save a miss and spare a glance.
Hooray — a burrowed memory road 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.34% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'x86 L1 Data Cache Simulator' directly and accurately summarizes the main change: introduction of a complete L1 cache simulator with x86 specifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3cc9db54e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cpu_l1_cache.py
Comment on lines +212 to +216
# Check if cache has an allocator, otherwise use a static global counter on class or something
# For now, start at 0x1000 and increment?
# Let's just default to 0x1000 if user doesn't specify, but warn.
# Ideally the user manages layout.
self.base_addr = 0x1000

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allocate distinct base addresses for default arrays

When base_addr is omitted, every SimulatedArray defaults to 0x1000, so two arrays created without an explicit base will alias the same memory region. That causes writes in one array to overwrite the other and corrupt cache statistics or data reads (e.g., creating two arrays back-to-back and writing to both yields cross-contamination). Consider tracking a monotonically increasing allocator (or reserving length * item_size) so each default allocation gets a unique base.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@cpu_l1_cache.py`:
- Around line 85-154: The access method lacks bounds validation for offset+size
against self.line_size causing IndexError or silent truncation; add an early
check at the start of access (in function access) that computes
tag,set_index,offset = self._get_addr_components(address) then verifies offset +
size <= self.line_size and if not either raise a clear ValueError (e.g. "access
spans cache line") or split the request into multiple cache-line accesses;
ensure this single check prevents out-of-bounds access in the write loop (where
line.data[offset + i] / victim.data[offset + i] is written) and guarantees the
read return slices (line.data[offset:offset+size] /
victim.data[offset:offset+size]) always contain the requested bytes.

In `@verify_cache.py`:
- Around line 14-16: The loop in verify_cache.py reads values into an unused
variable `val` (for i in range(32): val = arr[i]); change the assignment to use
the conventional discard name so intent is clear—assign the read to `_` (e.g.,
`_ = arr[i]`) or otherwise avoid creating `val`—so the read remains for cache
side effects but no unused-variable remains; update the loop in the same
function/block that references `arr` and `val`.
🧹 Nitpick comments (3)
cpu_l1_cache.py (3)

67-72: Minor style: unused loop variable.

The loop index i is not used within the loop body.

Suggested fix
     def _find_line(self, set_index, tag):
         cache_set = self.sets[set_index]
-        for i, line in enumerate(cache_set):
+        for line in cache_set:
             if line.state != 'I' and line.tag == tag:
                 return line
         return None

74-83: Rename ambiguous variable l.

The variable l in the lambda can be confused with 1 or I in certain fonts.

Suggested fix
         # Use LRU
-        victim = min(cache_set, key=lambda l: l.last_accessed)
+        victim = min(cache_set, key=lambda line: line.last_accessed)
         return victim

123-131: Consider handling 'S' state eviction for completeness.

Eviction of lines in 'M' and 'E' states are counted, but 'S' state (Shared) is not handled. While the comment notes 'S' shouldn't occur in single-core mode, adding this case would make the MESI implementation complete if multi-core support is added later.

Suggested fix
             if victim.state == 'M':
                 # Write Back
                 self.stats['evictions'] += 1
                 self.stats['write_backs'] += 1
                 victim_addr = (victim.tag * self.num_sets * self.line_size) + (set_index * self.line_size)
                 self.memory.write(victim_addr, victim.data)
             elif victim.state == 'E':
-                 # Clean eviction
-                 self.stats['evictions'] += 1
+                # Clean eviction
+                self.stats['evictions'] += 1
+            elif victim.state == 'S':
+                # Clean eviction (shared line)
+                self.stats['evictions'] += 1

Comment thread cpu_l1_cache.py
Comment thread verify_cache.py
Comment on lines +14 to +16
# Read all
for i in range(32):
val = arr[i]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Unused variable val.

The value is read for its cache side effects but never used. Assign to _ to indicate intentional discard.

Suggested fix
         # Read all
         for i in range(32):
-            val = arr[i]
+            _ = arr[i]  # Read for cache side effects
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Read all
for i in range(32):
val = arr[i]
# Read all
for i in range(32):
_ = arr[i] # Read for cache side effects
🧰 Tools
🪛 Ruff (0.14.14)

16-16: Local variable val is assigned to but never used

Remove assignment to unused variable val

(F841)

🤖 Prompt for AI Agents
In `@verify_cache.py` around lines 14 - 16, The loop in verify_cache.py reads
values into an unused variable `val` (for i in range(32): val = arr[i]); change
the assignment to use the conventional discard name so intent is clear—assign
the read to `_` (e.g., `_ = arr[i]`) or otherwise avoid creating `val`—so the
read remains for cache side effects but no unused-variable remains; update the
loop in the same function/block that references `arr` and `val`.

google-labs-jules Bot and others added 2 commits January 26, 2026 22:59
- Added `CACHE_SPECS.md` detailing architecture specifications.
- Updated `cpu_l1_cache.py` to track access history and per-address counts.
- Created `cache_viz.py` to generate miss rate plots, 2D heatmaps, and 3D access plots.
- Created `verify_viz.py` to demonstrate visualization generation.

Co-authored-by: bugparty <1510776+bugparty@users.noreply.github.com>
Ensures that low-level access calls do not span across cache line boundaries, raising a ValueError if they do.
This enforces the design where `read` and `write` helper methods are responsible for splitting requests.

Previous changes included:
- x86 L1 Cache Simulator Visualization Tools
- CACHE_SPECS.md
- Updated cpu_l1_cache.py to track access history and per-address counts.
- Created cache_viz.py and verify_viz.py.

Co-authored-by: bugparty <1510776+bugparty@users.noreply.github.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.

1 participant