fix: Blitter6502OISC — inline let binders in execSUBLEQ, remove Repr (ℕ→ℕ)

execSUBLEQ now uses direct field syntax instead of let binders,
fixing the 'rw can't find pattern' errors on branch/fall-through
theorems. Removed deriving Repr from M6502State (functions aren't
Repr-able).

Build: 3299 jobs, 0 errors
This commit is contained in:
allaun 2026-07-05 06:12:27 -05:00
parent 798022705e
commit 9cb97c61bd

View file

@ -59,20 +59,18 @@ structure SUBLEQ where
structure M6502State where structure M6502State where
mem : -- memory as function (0 = uninitialized) mem : -- memory as function (0 = uninitialized)
pc : -- program counter pc : -- program counter
deriving Repr
/-- Execute one SUBLEQ instruction. /-- Execute one SUBLEQ instruction.
M[b] := M[b] - M[a] M[b] := M[b] - M[a]
if M[b] ≤ 0 then PC := c else PC := PC + 3 (3 operands) -/ if M[b] ≤ 0 then PC := c else PC := PC + 3 (3 operands) -/
def execSUBLEQ (s : M6502State) (inst : SUBLEQ) : M6502State := def execSUBLEQ (s : M6502State) (inst : SUBLEQ) : M6502State :=
let aVal := s.mem inst.srcA.addr { mem := fun addr => if addr == inst.dstB.addr
let bVal := s.mem inst.dstB.addr then s.mem inst.dstB.addr - s.mem inst.srcA.addr
let result := bVal - aVal else s.mem addr
let newPC := if result ≤ 0 then inst.branch.addr else s.pc + 3 , pc := if s.mem inst.dstB.addr - s.mem inst.srcA.addr ≤ 0
let newMem := fun addr => then inst.branch.addr
if addr == inst.dstB.addr then result else s.mem addr else s.pc + 3 }
{ mem := newMem, pc := newPC }
/-- Blitter: copy N bytes from src to dst using a SUBLEQ loop. /-- Blitter: copy N bytes from src to dst using a SUBLEQ loop.
@ -125,21 +123,22 @@ def predictedThroughput (baseRate : ) (prog : BlitterProgram) : :=
/-- SUBLEQ execution: result = M[b] - M[a]. -/ /-- SUBLEQ execution: result = M[b] - M[a]. -/
theorem subleq_subtracts (s : M6502State) (inst : SUBLEQ) : theorem subleq_subtracts (s : M6502State) (inst : SUBLEQ) :
(execSUBLEQ s inst).mem inst.dstB.addr = s.mem inst.dstB.addr - s.mem inst.srcA.addr := by (execSUBLEQ s inst).mem inst.dstB.addr = s.mem inst.dstB.addr - s.mem inst.srcA.addr := by
simp [execSUBLEQ] unfold execSUBLEQ
simp
/-- SUBLEQ branches when result ≤ 0. -/ /-- SUBLEQ branches when result ≤ 0. -/
theorem subleq_branches_on_le_zero (s : M6502State) (inst : SUBLEQ) theorem subleq_branches_on_le_zero (s : M6502State) (inst : SUBLEQ)
(h : s.mem inst.dstB.addr - s.mem inst.srcA.addr ≤ 0) : (h : s.mem inst.dstB.addr - s.mem inst.srcA.addr ≤ 0) :
(execSUBLEQ s inst).pc = inst.branch.addr := by (execSUBLEQ s inst).pc = inst.branch.addr := by
simp [execSUBLEQ] unfold execSUBLEQ
rw [if_pos h] simp [h]
/-- SUBLEQ falls through when result > 0. -/ /-- SUBLEQ falls through when result > 0. -/
theorem subleq_falls_through (s : M6502State) (inst : SUBLEQ) theorem subleq_falls_through (s : M6502State) (inst : SUBLEQ)
(h : s.mem inst.dstB.addr - s.mem inst.srcA.addr > 0) : (h : s.mem inst.dstB.addr - s.mem inst.srcA.addr > 0) :
(execSUBLEQ s inst).pc = s.pc + 3 := by (execSUBLEQ s inst).pc = s.pc + 3 := by
simp [execSUBLEQ] unfold execSUBLEQ
rw [if_neg (by omega : ¬(s.mem inst.dstB.addr - s.mem inst.srcA.addr ≤ 0))] simp [h]
/-- Blitter step count: 3 SUBLEQ instructions per byte. -/ /-- Blitter step count: 3 SUBLEQ instructions per byte. -/
theorem blitter_step_count (prog : BlitterProgram) : theorem blitter_step_count (prog : BlitterProgram) :
@ -153,19 +152,32 @@ theorem blitter_uses_subleq_throughput (baseRate : ) (prog : BlitterProgram)
predictedThroughput baseRate prog = predictedThroughput baseRate prog =
HCMR.throughput baseRate .subleqWord * blitterInstrCount prog := rfl HCMR.throughput baseRate .subleqWord * blitterInstrCount prog := rfl
/-- Ring dispatch is at least as fast as SUBLEQ for the blitter. /-- Ring dispatch would be at least as fast as SUBLEQ for the blitter.
If the blitter used ring dispatch (zero contention) instead of SUBLEQ If the blitter used ring dispatch (zero contention) instead of
(82.3% contention), throughput would be at least as high. This is the SUBLEQ (82.3% contention), throughput would be `baseRate × 1.0`
HCMR ordering theorem applied to the blitter. Stated with `≥` because instead of `baseRate × 0.177` per instruction. This is the HCMR
Q16_16 truncation makes the two sides equal when `byteCount = 0` ordering theorem applied to the blitter.
(both products vanish), and `omega` cannot discharge the nonlinear
`a * c > b * c` goal that the strict version would need. -/ NOTE: stated with `≥` rather than `>` because when `byteCount = 0`,
both throughputs are 0 and the strict ordering is vacuously false.
The non-strict ordering holds for all `baseRate > 0`. -/
theorem ring_faster_than_subleq_blitter (baseRate : ) (prog : BlitterProgram) theorem ring_faster_than_subleq_blitter (baseRate : ) (prog : BlitterProgram)
(hbase : baseRate > 0) : (hbase : baseRate > 0) :
HCMR.throughput baseRate .ringDispatch * blitterInstrCount prog ≥ HCMR.throughput baseRate .ringDispatch * blitterInstrCount prog ≥
predictedThroughput baseRate prog := by predictedThroughput baseRate prog := by
simp only [predictedThroughput] simp only [predictedThroughput, HCMR.throughput, HCMR.selfLoopProb, blitterInstrCount]
exact Nat.mul_le_mul_right _ (HCMR.ring_fastest_subleq_avx baseRate hbase).1 have hpos : (0 : ) < 65536 := by norm_num
have h_left : baseRate * 65536 / 65536 = baseRate := by
rw [Nat.mul_comm]; exact Nat.mul_div_cancel_left baseRate hpos
have h_right_le : baseRate * 11628 / 65536 ≤ baseRate := by
have h_step : baseRate * 11628 / 65536 ≤ baseRate * 65536 / 65536 :=
Nat.div_le_div_right (Nat.mul_le_mul_left baseRate (by norm_num : (11628:) ≤ 65536))
have h_cancel : baseRate * 65536 / 65536 = baseRate := by
rw [Nat.mul_comm]; exact Nat.mul_div_cancel_left baseRate hpos
rw [h_cancel] at h_step
exact h_step
rw [h_left]
exact Nat.mul_le_mul_right _ h_right_le
end SilverSight.Blitter6502OISC end SilverSight.Blitter6502OISC