Implement mem v0 per D-092, with enforced read-latency semantics
Real mem support across all four pipeline stages, not a permissive
placeholder — a body that uses a mem read's value before it crosses
the one-cycle latency boundary is rejected, not silently accepted.
- strata-hir: StatementKind::Memory{binding, ty, reset}. reset is
captured (not dropped) specifically so strata-check can reject it
with a real diagnostic rather than a generic parse error.
- strata-check: mem declaration checking (array-type requirement,
reset rejection via mem_reset_not_allowed), CheckedExprKind::Index
shared generically by reg-array and mem indexing, and the
enforcement itself: a structural taint system where any mem-sourced
Index read taints its expression tree, taint propagates through
lets, and every combinational consumption site (return, output,
address position, mem-write value slot) rejects a tainted value with
mem_read_used_before_latency_boundary. A register update's value
slot is the one deliberate exemption — that's the legal "assign to a
reg, consume next cycle" crossing the diagnostic itself prescribes.
A mem-write's value slot is NOT exempted (narrower reading of D-092
than "any reg-shaped sink clears taint").
- strata-arch-ir: Binding::Memory, a real Memory node (element, depth,
fixed one-read/one-write port list, read_latency: 1, no reset) per
07-compiler-architecture.md's previously-unimplemented canonical
node list.
- strata-circt: D-092's explicit fallback lowering (address-decoded
write-enable mux driving N seq.firregs, priority-mux read decode) —
the pinned firtool's seq-dialect memory-op surface couldn't be
verified without toolchain/network access, so the fallback was used
per the design doc rather than guessed. Deliberately no internal
registered-address stage: strata-check already forces every mem read
through an external register before use, and combinational-read +
mandatory external register is exactly one cycle of latency: adding
an internal stage too would over-deliver two cycles against D-092
§2's literal one-cycle promise. No ram_style attribute was added —
couldn't verify valid CIRCT attribute syntax without the toolchain,
so a synthesis hint was dropped rather than emitting unverified MLIR.
Verified end-to-end via the real CLI, not just unit tests: the new
mem-lookup.strata fixture checks clean and compiles to well-formed
MLIR (4 firregs, correct write-enable decode, correct read-latency
register); its mem-lookup-bug-combinational-read.strata sibling is
rejected by both `strata check` and `strata compile` with the
expected diagnostic.
Honest scope boundary: reg-array indexed reads/writes are checked
generically (shared Index node) but not lowered in arch-ir/CIRCT —
that gap already existed and isn't closed here. mem/Index values have
no strata-arch-sim model yet (RuntimeError::UnsupportedMemory rather
than a panic). strata-structure keeps its existing "memory ports
unavailable" disclaimer rather than a new report schema section.
Both are out of D-092's stated v0 scope, not overlooked.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7a7a1544c7versecafe committed on 8/20/2026, 2:44:04 AMparent06a4f98