diff --git a/CLAUDE.md b/CLAUDE.md index 46d348c..a26fead 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -182,7 +182,7 @@ Frame-based processing element with activation context management. **Frame Storage:** - `frames: list[list[FrameSlotValue]]` -- 2D array [frame_id][slot_idx] holding FrameDest objects and constants -- `tag_store: dict[int, int]` -- maps act_id → frame_id for activation-to-frame lookup +- `tag_store: dict[int, tuple[int, int]]` -- maps act_id → (frame_id, lane) for activation-to-frame-and-lane lookup - `presence: list[list[bool]]` -- [frame_id][match_slot] for dyadic operand waiting state - `port_store: list[list[Optional[Port]]]` -- [frame_id][match_slot] for operand port metadata - `free_frames: list[int]` -- pool of unallocated frame IDs @@ -262,9 +262,9 @@ SimPy process with I-structure (single-assignment) semantics. - `System.load(tokens: list[Token])` -- spawns SimPy process that calls send() for each token in order **PEConfig (emu/types.py):** -- `pe_id: int`, `iram: dict[int, Instruction] | None`, `frame_count: int = 8`, `frame_slots: int = 64`, `matchable_offsets: int = 8` +- `pe_id: int`, `iram: dict[int, Instruction] | None`, `frame_count: int = 8`, `frame_slots: int = 64`, `matchable_offsets: int = 8`, `lane_count: int = 4` - `initial_frames: Optional[dict[int, list[FrameSlotValue]]]` -- pre-loaded frame data -- `initial_tag_store: Optional[dict[int, int]]` -- pre-loaded act_id -> frame_id mappings +- `initial_tag_store: Optional[dict[int, tuple[int, int]]]` -- pre-loaded act_id → (frame_id, lane) mappings - `allowed_pe_routes: Optional[set[int]]` -- if set, restrict PE route_table to these PE IDs - `allowed_sm_routes: Optional[set[int]]` -- if set, restrict PE sm_routes to these SM IDs - `on_event: EventCallback | None` -- if set, PE fires `SimEvent` for every token receive, match, execute, emit, frame alloc/free, slot write, and rejection @@ -321,7 +321,7 @@ Interactive simulation monitor providing both CLI REPL and web UI for controllin **StateSnapshot (monitor/snapshot.py):** - `capture(system) -> StateSnapshot` reads live PE/SM state into frozen dataclasses - `StateSnapshot(sim_time, next_time, pes: dict[int, PESnapshot], sms: dict[int, SMSnapshot])` -- `PESnapshot(pe_id, frames, tag_store, presence, port_store, free_frames, iram, input_queue, output_log)` -- frame-based PE state +- `PESnapshot(pe_id, frames, tag_store, presence, port_store, free_frames, iram, input_queue, output_log)` -- frame-based PE state with tag_store mapping act_id → (frame_id, lane) tuples - `SMSnapshot(sm_id, cells: dict[int, SMCellSnapshot], deferred_read, t0_store, input_queue)` **WebSocket protocol (monitor/server.py):** diff --git a/monitor/CLAUDE.md b/monitor/CLAUDE.md index e7831f1..a8bf24b 100644 --- a/monitor/CLAUDE.md +++ b/monitor/CLAUDE.md @@ -52,7 +52,7 @@ Commands are frozen dataclasses sent to the backend thread via queue: - `__init__.py` -- Public API exports - `backend.py` -- `SimulationBackend` class with thread lifecycle and command dispatch - `commands.py` -- All command and result frozen dataclasses, `SimCommand` union type -- `snapshot.py` -- `StateSnapshot`, `PESnapshot` (frame-based: frames, tag_store, presence, port_store, free_frames), `SMSnapshot`, `SMCellSnapshot`, `capture()` +- `snapshot.py` -- `StateSnapshot`, `PESnapshot` (frame-based: frames, tag_store mapping act_id → (frame_id, lane) tuples, presence, port_store, free_frames), `SMSnapshot`, `SMCellSnapshot`, `capture()` - `graph_json.py` -- JSON serialization with execution overlay (extends dfgraph patterns) - `server.py` -- `create_app(backend)` FastAPI factory, `ConnectionManager`, WebSocket handler - `repl.py` -- `MonitorREPL(cmd.Cmd)` interactive CLI diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index a95fa31..53d616c 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -123,7 +123,7 @@ class TestCaptureWithSinglePEAndSM: assert isinstance(frame, tuple) # Each frame has slots - # tag_store should be dict mapping act_id to frame_id + # tag_store should be dict mapping act_id to (frame_id, lane) tuple assert isinstance(pe_snap.tag_store, dict) # presence should be a tuple of tuples (frame_count x matchable_offsets) @@ -183,7 +183,7 @@ class TestCaptureWithSinglePEAndSM: snapshot = capture(system) pe_snap = snapshot.pes[0] - # tag_store should be a dict mapping act_id to frame_id + # tag_store should be a dict mapping act_id to (frame_id, lane) tuple assert isinstance(pe_snap.tag_store, dict) assert hasattr(pe_snap, 'frames') assert hasattr(pe_snap, 'free_frames')