OR-1 dataflow CPU sketch
at main 70 lines 4.8 kB view raw view rendered
1# OR1 Monitor (monitor/) 2 3Last verified: 2026-03-07 4 5## Purpose 6 7Interactive simulation monitor for OR1 dataflow CPU programs. Provides a threaded simulation backend with a command/result protocol, exposed through both a CLI REPL and a web UI with real-time graph visualization and execution overlay. 8 9## Contracts 10 11- **Exposes**: `SimulationBackend` (threaded controller), command types (`LoadCmd`, `StepTickCmd`, `StepEventCmd`, `RunUntilCmd`, `InjectCmd`, `SendCmd`, `ResetCmd`, `StopCmd`), result types (`GraphLoaded`, `StepResult`, `ErrorResult`), `StateSnapshot`, `capture(system)` 12- **Guarantees**: Backend owns SimPy environment in a dedicated daemon thread. Commands are sent via `queue.Queue` and processed sequentially. Results include full state snapshots and event lists. Invalid programs return `ErrorResult` without crashing the backend. Reset tears down state cleanly. 13- **Expects**: Valid dfasm source for `LoadCmd`. Running backend thread (`start()` called before `send_command()`). 14 15## Command/Result Protocol 16 17Commands are frozen dataclasses sent to the backend thread via queue: 181. `LoadCmd(source)` -> `GraphLoaded(ir_graph, snapshot)` or `ErrorResult` 192. `StepTickCmd()` -> `StepResult` (all events at current sim time) 203. `StepEventCmd()` -> `StepResult` (exactly one `env.step()`) 214. `RunUntilCmd(until)` -> `StepResult` (batched events up to target time) 225. `InjectCmd(token)` -> `StepResult` (direct inject, no backpressure) 236. `SendCmd(token)` -> `StepResult` (via `store.put()`, respects backpressure) 247. `ResetCmd(reload)` -> `StepResult` or `GraphLoaded` (if `reload=True`) 258. `StopCmd()` -> terminates backend thread 26 27## Dependencies 28 29- **Uses**: `cm_inst` (MemOp, Port, Instruction, FrameSlotValue), `tokens` (Token types), `sm_mod` (Presence), `emu/` (events, types, network), `asm/` (run_pipeline, codegen, ir), `dfgraph/categories` (opcode categorisation for graph JSON) 30- **Used by**: CLI entry point (`python -m monitor`), test suite 31- **Boundary**: `cm_inst`, `tokens`, `sm_mod`, `emu/`, and `asm/` must NEVER import from `monitor/` 32 33## Key Decisions 34 35- **Threaded backend**: SimPy is not async-safe, so the simulation runs in a dedicated thread with queue-based IPC. The FastAPI server bridges async/sync via `asyncio.to_thread()`. 36- **Frozen command/result types**: All protocol types are frozen dataclasses for thread safety and predictability. 37- **Event callback wiring**: Backend uses `dataclasses.replace()` to inject `on_event` into PEConfig/SMConfig during `LoadCmd`, avoiding mutation of user-provided configs. 38- **StateSnapshot as frozen copy**: `capture()` reads live PE/SM state and produces frozen dataclasses suitable for serialization, ensuring no aliasing with mutable simulation state. 39- **REPL uses `cmd.Cmd`**: Standard library module, no external deps for CLI mode. 40 41## Invariants 42 43- Backend thread processes exactly one command at a time (sequential dispatch) 44- `StepResult.finished == True` when `env.peek() == inf` (no more events) 45- `StepResult.events` contains only events from the most recent command execution 46- `StateSnapshot` is always captured after the step completes 47- `GraphLoaded.snapshot` reflects state after seed token injection 48- `ResetCmd` always clears `_env`, `_system`, `_events`, `_ir_graph`; preserves `_last_source` 49 50## Key Files 51 52- `__init__.py` -- Public API exports 53- `backend.py` -- `SimulationBackend` class with thread lifecycle and command dispatch 54- `commands.py` -- All command and result frozen dataclasses, `SimCommand` union type 55- `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()` 56- `graph_json.py` -- JSON serialization with execution overlay (extends dfgraph patterns) 57- `server.py` -- `create_app(backend)` FastAPI factory, `ConnectionManager`, WebSocket handler 58- `repl.py` -- `MonitorREPL(cmd.Cmd)` interactive CLI 59- `formatting.py` -- ANSI colour formatting with `NO_COLOUR` flag for testing 60- `frontend/` -- TypeScript browser UI (Cytoscape.js, WebSocket client, event log, state inspector) 61 62## Gotchas 63 64- Backend must be `start()`ed before any `send_command()` call; otherwise commands sit in queue forever 65- `SendCmd` internally creates a one-shot SimPy process and steps once; this means it may process other pending events too 66- `RunUntilCmd` batches events per tick internally but returns all events in a single `StepResult` 67- The `formatting.NO_COLOUR` global flag must be set before calling format functions (used by tests to get predictable output) 68- Frontend requires `npm install && node build.mjs` in `monitor/frontend/` to produce `dist/bundle.js` 69 70<!-- freshness: 2026-03-07 -->