OR-1 dataflow CPU sketch

docs: update project context for dfgraph feature

Orual ec68f9d1 232434e4

+77 -6
+23 -4
CLAUDE.md
··· 72 72 - `asm/allocate.py` — IRAM offset and context slot allocation 73 73 - `asm/codegen.py` — Code generation (direct mode + token stream mode) 74 74 - `asm/serialize.py` — IRGraph to dfasm source serializer 75 + - `dfgraph/` — Interactive dataflow graph renderer (see `dfgraph/CLAUDE.md`) 76 + - `dfgraph/__main__.py` — CLI: `python -m dfgraph path/to/file.dfasm [--port 8420]` 77 + - `dfgraph/pipeline.py` — Progressive pipeline runner (parse -> lower -> resolve -> place -> allocate with error accumulation) 78 + - `dfgraph/categories.py` — Opcode-to-category mapping via isinstance dispatch on ALUOp hierarchy 79 + - `dfgraph/graph_json.py` — IRGraph-to-JSON conversion for frontend consumption 80 + - `dfgraph/server.py` — FastAPI backend with WebSocket push and file watcher (watchdog, 300ms debounce) 81 + - `dfgraph/frontend/` — TypeScript frontend: Cytoscape.js graph with ELK layout, SVG/PNG export 75 82 - `tests/` — pytest + hypothesis test suite 76 83 - `tests/conftest.py` — Hypothesis strategies for token/op generation 77 84 - `docs/` — Design documents, implementation plans, test plans ··· 81 88 - Python 3.12 82 89 - SimPy 4.1 (discrete event simulation) 83 90 - Lark (Earley parser for dfasm grammar) 91 + - FastAPI + uvicorn (dfgraph web server) 92 + - watchdog (file system monitoring for dfgraph live reload) 93 + - Cytoscape.js + cytoscape-elk (frontend graph rendering and layout) 84 94 - pytest + hypothesis (property-based testing) 85 95 - Nix flake for dev environment 86 96 ··· 185 195 186 196 ### Module Dependency Graph 187 197 188 - `cm_inst.py` defines ISA enums and instruction types (no dependencies). `tokens.py` imports from `cm_inst.py` and defines the token hierarchy. `sm_mod.py` is independent. The `emu/` package imports from root-level modules but root-level modules never import from `emu/`. The `asm/` package imports from both root-level modules and `emu/types.py` (for PEConfig/SMConfig), but neither root-level modules nor `emu/` import from `asm/`. 198 + `cm_inst.py` defines ISA enums and instruction types (no dependencies). `tokens.py` imports from `cm_inst.py` and defines the token hierarchy. `sm_mod.py` is independent. The `emu/` package imports from root-level modules but root-level modules never import from `emu/`. The `asm/` package imports from both root-level modules and `emu/types.py` (for PEConfig/SMConfig), but neither root-level modules nor `emu/` import from `asm/`. The `dfgraph/` package imports from `cm_inst`, `asm/` (ir, lower, resolve, place, allocate, errors, opcodes), and internally between its own modules. Neither root-level modules, `emu/`, nor `asm/` import from `dfgraph/`. 189 199 190 200 ``` 191 201 cm_inst.py <-- tokens.py <-- emu/types.py ··· 200 210 | | | 201 211 v v v 202 212 asm/lower.py asm/resolve.py asm/allocate.py 203 - | 204 - asm/place.py 213 + | | 214 + | asm/place.py 215 + | | 216 + +--- dfgraph/pipeline.py ----------+ 217 + | 218 + dfgraph/categories.py dfgraph/graph_json.py 219 + (cm_inst) (asm/ir, asm/opcodes) 220 + | 221 + dfgraph/server.py 222 + | 223 + dfgraph/frontend/ 205 224 ``` 206 225 207 - <!-- freshness: 2026-02-23 --> 226 + <!-- freshness: 2026-02-24 -->
+2 -2
asm/CLAUDE.md
··· 23 23 ## Dependencies 24 24 25 25 - **Uses**: `cm_inst` (Port, MemOp, CfgOp, ALUOp, ALUInst, SMInst, Addr), `tokens` (MonadToken, SMToken, CfgToken, LoadInstToken, RouteSetToken), `sm_mod` (Presence), `emu/types` (PEConfig, SMConfig), `lark` (parser) 26 - - **Used by**: Test suite, user programs 26 + - **Used by**: Test suite, user programs, `dfgraph/` (pipeline, graph_json use ir, lower, resolve, place, allocate, errors, opcodes) 27 27 - **Boundary**: `emu/` and root-level modules must NEVER import from `asm/` 28 28 29 29 ## Key Decisions ··· 52 52 - `MemOp.WRITE` arity depends on const: monadic when const is set (cell_addr from const), dyadic when const is None (cell_addr from left operand) 53 53 - `RoutingOp.FREE_CTX` (ALU context deallocation) and `MemOp.FREE` (SM free) are disambiguated by mnemonic: assembler uses `free_ctx` for ALU and `free` for SM 54 54 55 - <!-- freshness: 2026-02-23 --> 55 + <!-- freshness: 2026-02-24 -->
+52
dfgraph/CLAUDE.md
··· 1 + # Dataflow Graph Renderer (dfgraph/) 2 + 3 + Last verified: 2026-02-24 4 + 5 + ## Purpose 6 + 7 + Interactive visualisation tool for dfasm dataflow programs. Renders the assembler's IR as a live-updating graph in the browser, enabling developers to see node placement, edge routing, and pipeline errors as they edit source files. 8 + 9 + ## Contracts 10 + 11 + - **Exposes**: `python -m dfgraph path/to/file.dfasm [--port 8420]` launches a web server with WebSocket-driven graph updates 12 + - **Guarantees**: Progressive pipeline captures the deepest successful IRGraph even when later passes fail, so partial graphs are always shown. Parse errors are fatal (no graph); resolve/place/allocate errors accumulate in `IRGraph.errors` and are displayed alongside the partial graph. File changes trigger reassembly within 300ms debounce window. 13 + - **Expects**: Valid path to a `.dfasm` file. The `dfasm.lark` grammar file at project root. Node modules installed in `dfgraph/frontend/` for the TypeScript build. 14 + 15 + ## Dependencies 16 + 17 + - **Uses**: `cm_inst` (ArithOp, LogicOp, RoutingOp, MemOp, CfgOp, Addr), `asm/` (ir, lower, resolve, place, allocate, errors, opcodes), `lark` (parser), `fastapi`/`uvicorn` (server), `watchdog` (file watcher), `cytoscape`/`cytoscape-elk` (frontend) 18 + - **Used by**: Developer tooling only (not imported by any other package) 19 + - **Boundary**: `cm_inst`, `asm/`, `emu/`, and root-level modules must NEVER import from `dfgraph/` 20 + 21 + ## Key Decisions 22 + 23 + - **isinstance dispatch for categories** (`categories.py`): ALUOp subclasses (ArithOp, LogicOp, RoutingOp) share IntEnum values across types, so dict/set lookup would collide. isinstance checks on the type hierarchy avoid this. 24 + - **LogicOp split**: EQ/LT/LTE/GT/GTE map to COMPARISON; AND/OR/XOR/NOT map to LOGIC. This gives visually distinct colours for boolean-producing vs bitwise ops. 25 + - **CONST and FREE_CTX as CONFIG**: RoutingOp.CONST and FREE_CTX are categorised as CONFIG (not ROUTING) since they are infrastructure ops, not data-movement ops. 26 + - **ELK layout engine**: Uses Eclipse Layout Kernel (via cytoscape-elk) for layered DAG layout with orthogonal edge routing. Replaced dagre for better edge routing. 27 + - **Progressive pipeline**: Unlike `asm._run_pipeline()` which raises on error, `run_progressive()` runs each pass independently so the frontend can show partial graphs with error annotations. 28 + 29 + ## Invariants 30 + 31 + - `dfgraph/` never imports from `emu/` -- it only needs the assembler IR, not the simulator 32 + - `categorise()` covers all ALUOp/MemOp/CfgOp values; raises `ValueError` on unknown types 33 + - `graph_to_json()` always returns a dict with `type: "graph_update"` -- even on parse failure (with empty node/edge lists) 34 + - WebSocket protocol: server sends `GraphUpdate` JSON on connect and on every file change; client sends nothing meaningful (receive loop is just for keepalive) 35 + 36 + ## Key Files 37 + 38 + - `pipeline.py` -- `PipelineStage` enum, `PipelineResult` dataclass, `run_progressive()` function 39 + - `categories.py` -- `OpcodeCategory` enum, `CATEGORY_COLOURS` dict, `categorise()` function 40 + - `graph_json.py` -- `graph_to_json(PipelineResult) -> dict` serialisation 41 + - `server.py` -- `create_app(source_path) -> FastAPI`, `ConnectionManager`, `DebouncedFileHandler` 42 + - `frontend/src/types.ts` -- TypeScript interfaces matching `graph_to_json` output shape 43 + - `frontend/src/main.ts` -- Cytoscape graph rendering, logical/physical view toggle 44 + - `frontend/src/layout.ts` -- ELK layout configurations for both views 45 + 46 + ## Gotchas 47 + 48 + - The Lark parser is lazily initialised and cached globally in `pipeline.py` (`_parser` module var) -- safe for single-process use but not for parallel test runners that fork 49 + - `DebouncedFileHandler` runs its callback on a `threading.Timer` thread, so `_on_file_change` uses `asyncio.run_coroutine_threadsafe` to bridge into the async event loop 50 + - Frontend `dist/` directory must contain the compiled TypeScript bundle; the server mounts it as static files at `/dist` 51 + 52 + <!-- freshness: 2026-02-24 -->