diff --git a/CLAUDE.md b/CLAUDE.md index a26fead..b350917 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -181,10 +181,12 @@ Pure function, no state. `execute(op, left, right, const) -> (result: int, bool_ 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 +- `frames: list[list[FrameSlotValue]]` -- 2D array [frame_id][slot_idx] holding FrameDest objects and constants (shared across all lanes) - `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 +- `match_data: list[list[list[Optional[int]]]]` -- 3D array [frame_id][match_slot][lane] for operand values waiting for partner +- `presence: list[list[list[bool]]]` -- 3D array [frame_id][match_slot][lane] for dyadic operand waiting state +- `port_store: list[list[list[Optional[Port]]]]` -- 3D array [frame_id][match_slot][lane] for operand port metadata +- `lane_count: int` -- number of matching lanes per frame - `free_frames: list[int]` -- pool of unallocated frame IDs - `iram: dict[int, Instruction]` -- instruction memory indexed by offset @@ -194,10 +196,12 @@ Frame-based processing element with activation context management. - Monadic CMToken: 4 cycles (dequeue + IFETCH + EXECUTE + EMIT) **Matching Logic:** -- DyadToken arrives with act_id: look up frame_id via tag_store, then check presence[frame_id][iram_offset] -- If slot empty: store token.data and token.port, set presence bit, wait for partner -- If slot occupied: retrieve partner data and port, clear presence bit, fire instruction with both operands +- DyadToken arrives with act_id: look up (frame_id, lane) via tag_store +- Match slot is derived from token.offset: match_slot = token.offset % matchable_offsets +- If presence[frame_id][match_slot][lane] is False: store token.data in match_data[frame_id][match_slot][lane], store token.port in port_store[frame_id][match_slot][lane], set presence bit to True, wait for partner +- If presence[frame_id][match_slot][lane] is True: retrieve partner data and port from match_data and port_store, clear presence bit, fire instruction with both operands - Port ordering: partner with Port.L goes to left operand; Port.R to right operand +- Match data, presence, and port storage are per-lane; frame constants/destinations (in frames) remain shared across all lanes **Output Routing** (determined by `Instruction.output`): - `OutputStyle.INHERIT` -- routes to destinations specified in frame slots @@ -321,7 +325,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 with tag_store mapping act_id → (frame_id, lane) tuples +- `PESnapshot(pe_id, frames, tag_store, presence, port_store, match_data, free_frames, lane_count, iram, input_queue, output_log)` -- frame-based PE state with 3D match storage (presence, port_store, match_data are all [frame_id][match_slot][lane]), tag_store mapping act_id → (frame_id, lane) tuples, and lane_count field - `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 a8bf24b..14db2bf 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 mapping act_id → (frame_id, lane) tuples, 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, match_data all 3D [frame_id][match_slot][lane], lane_count, 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