Honeycomb

8. Synchronous-Read Cell🔗

The generated cell reads its memories combinationally: it presents an address and uses the returned word in the same cycle. A technology SRAM macro, like the sky130 macro bound in the synthesis chapter, is synchronous-read: the word is registered and valid one cycle after the address. A cell that binds such macros for every memory must therefore stage each read. This chapter gives that fully synchronous cell an abstract model and proves it commits exactly what the combinational cell does.

The model runs each instruction as three non-overlapped phases. A fetch phase presents the program counter and latches the instruction register. A read phase presents the operand addresses and latches the loaded data word, resident weight, and streamed operand. An execute phase applies the latched instruction and operands. Because the phases never overlap, no architectural state changes between reading an operand and using it, so a latched read equals a live read: the load-use argument is a stability argument, not a hazard argument.

namespace Honeycomb inductive SyncPhase where | fetch | read | exec deriving Repr, DecidableEq structure SyncCell where arch : State defaultConfig imem : Nat -> DecodedInstr busy : Bool phase : SyncPhase ir : DecodedInstr ldv : Word defaultConfig wv : Elem defaultConfig sv : Elem defaultConfig

execLatched is the execute-phase transition. It is execDecoded with its three memory reads replaced by latched values: the loaded data word for ld, and the resident weight and streamed operand for kmac. Every other instruction reads only registers and immediates and is unchanged.

def execLatched (d : DecodedInstr) (ldw : Word defaultConfig) (wv sv : Elem defaultConfig) (s : State defaultConfig) : State defaultConfig := match d.op with | .mac => let x := elemOfWord defaultConfig (readReg s d.ra) let y := elemOfWord defaultConfig (readReg s d.rb) retire (setAcc s (accAddProduct defaultConfig s.acc x y)) (nextPC defaultConfig s.pc) | .kmac => let s1 := setAcc s (accAddProduct defaultConfig s.acc wv sv) retire (setPtrs s1 (nextLocal defaultConfig s.wptr) (nextLocal defaultConfig s.sptr)) (nextPC defaultConfig s.pc) | .clracc => retire (setAcc s 0) (nextPC defaultConfig s.pc) | .movacc => let v := wordOfInt defaultConfig s.acc.toInt retire (setRegs s (updReg s.regs d.rd v)) (nextPC defaultConfig s.pc) | .li => let v := wordOfInt defaultConfig d.imm retire (setRegs s (updReg s.regs d.rd v)) (nextPC defaultConfig s.pc) | .ld => retire (setRegs s (updReg s.regs d.rd ldw)) (nextPC defaultConfig s.pc) | .st => let addr := memIndexOfWord defaultConfig (readReg s d.ra) let value := readReg s d.rb retire (setData s (updMem s.data addr value)) (nextPC defaultConfig s.pc) | .setwptr => retire (setPtrs s (localAddrOfNat defaultConfig d.addr) s.sptr) (nextPC defaultConfig s.pc) | .setsptr => retire (setPtrs s s.wptr (localAddrOfNat defaultConfig d.addr)) (nextPC defaultConfig s.pc) | .blz => let pc' := if (readReg s d.ra).toInt <= 0 then branchPC defaultConfig s.pc d.imm else nextPC defaultConfig s.pc retire s pc' | .alu => execAlu (functOf d.addr) d.rd d.ra d.rb s | .jr => retire s (jumpPC defaultConfig (readReg s d.ra)) | .stw => let addr := memIndexOfWord defaultConfig (readReg s d.ra) let value := elemOfWord defaultConfig (readReg s d.rb) retire (setWeights s (updWeight s.weights addr value)) (nextPC defaultConfig s.pc) | .halt => retireHalt s -- Latching the operands from a state and then executing equals executing that -- state directly: the latched reads are exactly the reads `execDecoded` makes. theorem execLatched_eq (d : DecodedInstr) (s : State defaultConfig) : execLatched d (readData s (memIndexOfWord defaultConfig (readReg s d.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded d s := d:DecodedInstrs:State defaultConfigexecLatched d (readData s (memIndexOfWord defaultConfig (readReg s d.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded d s s:State defaultConfigop:CellOprd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := op, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := op, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := op, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } s s:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.mac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.mac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.mac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.kmac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.kmac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.kmac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.clracc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.clracc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.clracc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.movacc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.movacc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.movacc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.li, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.li, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.li, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.ld, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.ld, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.ld, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.st, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.st, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.st, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.setwptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.setwptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.setwptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.setsptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.setsptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.setsptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.blz, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.blz, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.blz, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.halt, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.halt, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.halt, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.alu, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.alu, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.alu, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.jr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.jr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.jr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.stw, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.stw, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.stw, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } s s:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.mac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.mac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.mac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.kmac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.kmac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.kmac, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.clracc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.clracc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.clracc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.movacc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.movacc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.movacc, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.li, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.li, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.li, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.ld, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.ld, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.ld, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.st, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.st, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.st, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.setwptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.setwptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.setwptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.setsptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.setsptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.setsptr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.blz, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.blz, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.blz, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.halt, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.halt, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.halt, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.alu, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.alu, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.alu, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.jr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.jr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.jr, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } ss:State defaultConfigrd:Reg defaultConfigra:Reg defaultConfigrb:Reg defaultConfigimm:Intaddr:NatexecLatched { op := CellOp.stw, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } (readData s (memIndexOfWord defaultConfig (readReg s { op := CellOp.stw, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr }.ra))) (readWeight s (memIndexOfLocal defaultConfig s.wptr)) (readStream s (memIndexOfLocal defaultConfig s.sptr)) s = execDecoded { op := CellOp.stw, rd := rd, ra := ra, rb := rb, imm := imm, addr := addr } s All goals completed! 🐙

One clock advances one phase. Fetch and read leave the architectural state untouched; only execute changes it.

def syncStep (c : SyncCell) : SyncCell := if c.busy then if c.arch.halted then c else match c.phase with | .fetch => { c with ir := c.imem (memIndexOfNat defaultConfig c.arch.pc.toNat), phase := .read } | .read => { c with ldv := readData c.arch (memIndexOfWord defaultConfig (readReg c.arch c.ir.ra)), wv := readWeight c.arch (memIndexOfLocal defaultConfig c.arch.wptr), sv := readStream c.arch (memIndexOfLocal defaultConfig c.arch.sptr), phase := .exec } | .exec => let arch' := execLatched c.ir c.ldv c.wv c.sv c.arch { c with arch := arch', phase := .fetch, busy := !arch'.halted } else c

A fetch, a read, and an execute together advance the architectural state by exactly one decoded instruction, the same value the combinational cell produces in one cycle. The synchronous reads change when each result is committed, not what it is.

theorem syncCell_three_cycles (c : SyncCell) (hbusy : c.busy = true) (hhalt : c.arch.halted = false) (hphase : c.phase = .fetch) : (syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig c.arch.pc.toNat)) c.arch := c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetch(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetchexecLatched (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) (readData c.arch (memIndexOfWord defaultConfig (readReg c.arch (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))).ra))) (readWeight c.arch (memIndexOfLocal defaultConfig c.arch.wptr)) (readStream c.arch (memIndexOfLocal defaultConfig c.arch.sptr)) c.arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch All goals completed! 🐙 theorem syncCell_returns_to_fetch (c : SyncCell) (hbusy : c.busy = true) (hhalt : c.arch.halted = false) (hphase : c.phase = .fetch) : (syncStep (syncStep (syncStep c))).phase = .fetch := c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetch(syncStep (syncStep (syncStep c))).phase = SyncPhase.fetch All goals completed! 🐙

The synchronous cell commits the same architectural state as the combinational cellExecCycle, and by the execute-path refinement it refines the ISA step function across its three cycles.

theorem syncCell_matches_combinational (c : SyncCell) (hbusy : c.busy = true) (hhalt : c.arch.halted = false) (hphase : c.phase = .fetch) : (syncStep (syncStep (syncStep c))).arch = (cellExecCycle { arch := c.arch, imem := c.imem, busy := c.busy }).arch := c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetch(syncStep (syncStep (syncStep c))).arch = (cellExecCycle { arch := c.arch, imem := c.imem, busy := c.busy }).arch c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetchexecDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch = (cellExecCycle { arch := c.arch, imem := c.imem, busy := c.busy }).arch All goals completed! 🐙 theorem syncCell_refines_isa (c : SyncCell) (hbusy : c.busy = true) (hhalt : c.arch.halted = false) (hphase : c.phase = .fetch) : step defaultConfig (programOf c.imem) c.arch = some (syncStep (syncStep (syncStep c))).arch := c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetchstep defaultConfig (programOf c.imem) c.arch = some (syncStep (syncStep (syncStep c))).arch c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetchstep defaultConfig (programOf c.imem) c.arch = some (execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch) All goals completed! 🐙

Running the cell is iterating the clock; an n-instruction program retires in 3 * n cycles because each instruction is a fetch/read/execute triple, and after each triple the cell is back in its fetch phase.

def syncRun : Nat -> SyncCell -> SyncCell | 0, c => c | k + 1, c => syncRun k (syncStep c) def syncCellCycles (n : Nat) : Nat := 3 * n theorem syncCellCycles_three_per_instr (n : Nat) : syncCellCycles (n + 1) = syncCellCycles n + 3 := n:NatsyncCellCycles (n + 1) = syncCellCycles n + 3 n:Nat3 * (n + 1) = 3 * n + 3; All goals completed! 🐙 end Honeycomb

This model is emitted as generated SystemVerilog. Alongside the combinational honeycomb_cell, the renderer produces rtl/honeycomb_cell_sync.sv: a second cell whose program, resident-weight, and stream memories are registered-read honeycomb_sram_sync_32 adapters and whose scalar-data load port is the registered port of a honeycomb_sram_sync_64 adapter. The SRAM output registers are the cell's instruction and operand latches, so synchronous SRAM macros bind directly with no extra logic. A separate combinational debug port keeps host inspection async. The generated cell follows the same three-phase sequence proved above and passes the same golden program suite as the combinational cell, retiring identical architectural results over three times as many clocks.

This closes the cycle-faithfulness gap left by the macro-adapter synthesis: every architectural read in the cell is now a registered-read stage with a proved refinement and a generated RTL cell, matching synchronous SRAM macros instead of combinational arrays. The kernel operand path also has its throughput counterpart in the scheduling chapter, whose conservation law accounts for overlapping the MAC reads at any latency. Overlapping the phases for throughput, and timing the synchronous cell through place-and-route, are the remaining steps toward a fully macro-timed physical tile.

8.1. The whole run, machine-checked🔗

The per-triple theorems above compose, and the composition is itself a theorem rather than prose (review R4): iterating the clock 3 * n times from the fetch phase is exactly n iterations of the combinational cycle model — through running, halting, and stopped states alike — and, as long as the machine keeps executing, exactly n ISA steps. "Retires the sequential trace" is now a simulation theorem, not an induction sketched in words.

namespace Honeycomb /-- The cycle-model view of a synchronous cell: architectural state, program, and the busy flag — the state `cellExecCycle` steps. -/ def SyncCell.toCellState (c : SyncCell) : CellState := { arch := c.arch, imem := c.imem, busy := c.busy } /-- A stopped or halted cell holds every register through a clock. -/ theorem syncStep_stalls (c : SyncCell) (h : ¬(c.busy = true c.arch.halted = false)) : syncStep c = c := c:SyncCellh:¬(c.busy = true c.arch.halted = false)syncStep c = c c:SyncCellh:¬(c.busy = true c.arch.halted = false)hb:c.busy = truesyncStep c = cc:SyncCellh:¬(c.busy = true c.arch.halted = false)hb:¬c.busy = truesyncStep c = c c:SyncCellh:¬(c.busy = true c.arch.halted = false)hb:c.busy = truesyncStep c = c c:SyncCellh:¬(c.busy = true c.arch.halted = false)hb:c.busy = truehh:c.arch.halted = truesyncStep c = c All goals completed! 🐙 c:SyncCellh:¬(c.busy = true c.arch.halted = false)hb:¬c.busy = truesyncStep c = c All goals completed! 🐙 /-- The busy flag after a committing triple is the model's: the cell keeps running exactly while the committed instruction did not halt. -/ theorem syncCell_busy_after (c : SyncCell) (hbusy : c.busy = true) (hhalt : c.arch.halted = false) (hphase : c.phase = .fetch) : (syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig c.arch.pc.toNat)) c.arch).halted := c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetch(syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).halted c:SyncCellhbusy:c.busy = truehhalt:c.arch.halted = falsehphase:c.phase = SyncPhase.fetch(execLatched (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) (readData c.arch (memIndexOfWord defaultConfig (readReg c.arch (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))).ra))) (readWeight c.arch (memIndexOfLocal defaultConfig c.arch.wptr)) (readStream c.arch (memIndexOfLocal defaultConfig c.arch.sptr)) c.arch).halted = (execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).halted All goals completed! 🐙 /-- The program memory is read-only to the pipeline. -/ theorem syncStep_imem (c : SyncCell) : (syncStep c).imem = c.imem := c:SyncCell(syncStep c).imem = c.imem c:SyncCellhb:c.busy = true(syncStep c).imem = c.imemc:SyncCellhb:¬c.busy = true(syncStep c).imem = c.imem c:SyncCellhb:c.busy = true(syncStep c).imem = c.imem c:SyncCellhb:c.busy = truehh:c.arch.halted = true(syncStep c).imem = c.imemc:SyncCellhb:c.busy = truehh:¬c.arch.halted = true(syncStep c).imem = c.imem c:SyncCellhb:c.busy = truehh:c.arch.halted = true(syncStep c).imem = c.imem All goals completed! 🐙 c:SyncCellhb:c.busy = truehh:¬c.arch.halted = true(syncStep c).imem = c.imem c:SyncCellhb:c.busy = truehh:¬c.arch.halted = truehp:c.phase = SyncPhase.fetch(syncStep c).imem = c.imemc:SyncCellhb:c.busy = truehh:¬c.arch.halted = truehp:c.phase = SyncPhase.read(syncStep c).imem = c.imemc:SyncCellhb:c.busy = truehh:¬c.arch.halted = truehp:c.phase = SyncPhase.exec(syncStep c).imem = c.imem c:SyncCellhb:c.busy = truehh:¬c.arch.halted = truehp:c.phase = SyncPhase.fetch(syncStep c).imem = c.imemc:SyncCellhb:c.busy = truehh:¬c.arch.halted = truehp:c.phase = SyncPhase.read(syncStep c).imem = c.imemc:SyncCellhb:c.busy = truehh:¬c.arch.halted = truehp:c.phase = SyncPhase.exec(syncStep c).imem = c.imem All goals completed! 🐙 c:SyncCellhb:¬c.busy = true(syncStep c).imem = c.imem All goals completed! 🐙 /-- Three clocks at a time. -/ theorem syncRun_add3 (m : Nat) (c : SyncCell) : syncRun (m + 3) c = syncRun m (syncStep (syncStep (syncStep c))) := rfl /-- **The run-level simulation.** From the fetch phase, `3 * n` clocks of the synchronous cell are `n` iterations of the combinational cycle model — same architectural state, same program, same busy flag — and the cell is back in its fetch phase. Holds through halting: once the committed instruction halts, both machines hold state, so the equation is unconditional in `n`. -/ theorem syncRun_refines_cellExecCycleN (n : Nat) (c : SyncCell) (hphase : c.phase = .fetch) : (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = .fetch := n:Natc:SyncCellhphase:c.phase = SyncPhase.fetch(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetch induction n generalizing c with c:SyncCellhphase:c.phase = SyncPhase.fetch(syncRun (3 * 0) c).toCellState = cellExecCycleN 0 c.toCellState (syncRun (3 * 0) c).phase = SyncPhase.fetch All goals completed! 🐙 n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetch(syncRun (3 * (n + 1)) c).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * (n + 1)) c).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3(syncRun (3 * (n + 1)) c).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * (n + 1)) c).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:c.busy = true c.arch.halted = false(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetchn:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:c.busy = true c.arch.halted = false(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = false(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = falseharch:(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = falseharch:(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.archhbusy':(syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).halted(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = falseharch:(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.archhbusy':(syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).haltedhph':(syncStep (syncStep (syncStep c))).phase = SyncPhase.fetch(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = falseharch:(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.archhbusy':(syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).haltedhph':(syncStep (syncStep (syncStep c))).phase = SyncPhase.fetchhsim:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN n (syncStep (syncStep (syncStep c))).toCellStatehph:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = falseharch:(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.archhbusy':(syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).haltedhph':(syncStep (syncStep (syncStep c))).phase = SyncPhase.fetchhsim:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN n (syncStep (syncStep (syncStep c))).toCellStatehph:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = falseharch:(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.archhbusy':(syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).haltedhph':(syncStep (syncStep (syncStep c))).phase = SyncPhase.fetchhsim:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN n (syncStep (syncStep (syncStep c))).toCellStatehph:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetchcellExecCycleN n (syncStep (syncStep (syncStep c))).toCellState = cellExecCycleN n (cellExecCycle c.toCellState) n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = falseharch:(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.archhbusy':(syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).haltedhph':(syncStep (syncStep (syncStep c))).phase = SyncPhase.fetchhsim:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN n (syncStep (syncStep (syncStep c))).toCellStatehph:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch(syncStep (syncStep (syncStep c))).toCellState = cellExecCycle c.toCellState n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hb:c.busy = truehh:c.arch.halted = falseharch:(syncStep (syncStep (syncStep c))).arch = execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.archhbusy':(syncStep (syncStep (syncStep c))).busy = !(execDecoded (c.imem (memIndexOfNat defaultConfig (BitVec.toNat c.arch.pc))) c.arch).haltedhph':(syncStep (syncStep (syncStep c))).phase = SyncPhase.fetchhsim:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN n (syncStep (syncStep (syncStep c))).toCellStatehph:(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetchhimem:(syncStep (syncStep (syncStep c))).imem = c.imem(syncStep (syncStep (syncStep c))).toCellState = cellExecCycle c.toCellState All goals completed! 🐙 n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = c(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetch(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).toCellState = cellExecCycleN (n + 1) c.toCellState (syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch refine ?_, n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetch(syncRun (3 * n) (syncStep (syncStep (syncStep c)))).phase = SyncPhase.fetch All goals completed! 🐙 n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetchcellExecCycleN n c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState) n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetchc.toCellState = cellExecCycle c.toCellState n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetchhb:c.busy = truec.toCellState = cellExecCycle c.toCellStaten:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetchhb:¬c.busy = truec.toCellState = cellExecCycle c.toCellState n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetchhb:c.busy = truec.toCellState = cellExecCycle c.toCellState n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetchhb:c.busy = truehh:c.arch.halted = truec.toCellState = cellExecCycle c.toCellState All goals completed! 🐙 n:Natih: (c : SyncCell), c.phase = SyncPhase.fetch (syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellState (syncRun (3 * n) c).phase = SyncPhase.fetchc:SyncCellhphase:c.phase = SyncPhase.fetchh3:3 * (n + 1) = 3 * n + 3hunf:cellExecCycleN (n + 1) c.toCellState = cellExecCycleN n (cellExecCycle c.toCellState)hrun:¬(c.busy = true c.arch.halted = false)hstall:syncStep c = chsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatehph:(syncRun (3 * n) c).phase = SyncPhase.fetchhb:¬c.busy = truec.toCellState = cellExecCycle c.toCellState All goals completed! 🐙 /-- **The ISA trace.** While the machine keeps executing — busy and not halted at each of the `n` commit points — `3 * n` clocks of the synchronous cell compute exactly `n` ISA steps: the pipeline retires the sequential trace. -/ theorem syncRun_commits_trace (n : Nat) (c : SyncCell) (hphase : c.phase = .fetch) (hlive : k, k < n (cellExecCycleN k c.toCellState).busy = true (cellExecCycleN k c.toCellState).arch.halted = false) : stepN (programOf c.imem) n c.arch = some (syncRun (3 * n) c).arch := n:Natc:SyncCellhphase:c.phase = SyncPhase.fetchhlive: (k : Nat), k < n (cellExecCycleN k c.toCellState).busy = true (cellExecCycleN k c.toCellState).arch.halted = falsestepN (programOf c.imem) n c.arch = some (syncRun (3 * n) c).arch n:Natc:SyncCellhphase:c.phase = SyncPhase.fetchhlive: (k : Nat), k < n (cellExecCycleN k c.toCellState).busy = true (cellExecCycleN k c.toCellState).arch.halted = falseh:stepN (programOf c.toCellState.imem) n c.toCellState.arch = some (cellExecCycleN n c.toCellState).archstepN (programOf c.imem) n c.arch = some (syncRun (3 * n) c).arch n:Natc:SyncCellhphase:c.phase = SyncPhase.fetchhlive: (k : Nat), k < n (cellExecCycleN k c.toCellState).busy = true (cellExecCycleN k c.toCellState).arch.halted = falseh:stepN (programOf c.toCellState.imem) n c.toCellState.arch = some (cellExecCycleN n c.toCellState).archhsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatestepN (programOf c.imem) n c.arch = some (syncRun (3 * n) c).arch n:Natc:SyncCellhphase:c.phase = SyncPhase.fetchhlive: (k : Nat), k < n (cellExecCycleN k c.toCellState).busy = true (cellExecCycleN k c.toCellState).arch.halted = falseh:stepN (programOf c.toCellState.imem) n c.toCellState.arch = some (cellExecCycleN n c.toCellState).archhsim:(syncRun (3 * n) c).toCellState = cellExecCycleN n c.toCellStatestepN (programOf c.imem) n c.arch = some (cellExecCycleN n c.toCellState).arch All goals completed! 🐙 end Honeycomb