tasks.fdivp.Spec
task statement
- Lines
- 109
- file
svgolf/tasks/fdivp/Spec.lean- sha256
71e46a4ce975b44f690c98d1170b9c5c83b21db7243bff4a526ff7852a1979b4- statements that rely on it
fdivp- download
tasks.fdivp.Spec.lean
svgolf/tasks/fdivp/Spec.leantasks.fdivp.Spec.lean
import SvGolf.Task
import tasks.fdivp.IEEE754
/-!
# Task `fdivp` (trusted statement): IEEE 754 division, PARAMETRIC in the format
The variant of the statement that needs NO change to `SvGolf/Task.lean` (`design/fdiv-param/TASK.md`
explains the choice of this form, "Option C", and `design/fdiv-param/Task.lean.patch` is the unapplied
`CombTask2` alternative): the two-parameter family is a family of fixed-size `CombTask`s, one per `(W, P)`,
and the statement quantifies over the pairs with `CombTask.StatementFixed` at each.
Module (two parameters, in this order; port order as written):
```systemverilog
module fdiv #(parameter int W = 5, parameter int P = 11) (
input logic [W+P-1:0] a,
input logic [W+P-1:0] b,
output logic [W+P-1:0] q
);
```
`W` is the width of the biased-exponent field and `P` the precision (the significand digits
including the implicit leading bit), so the trailing significand has `P - 1` bits and a pattern
has `1 + W + (P - 1) = W + P` bits: binary16 is `W = 5, P = 11`, bfloat16 `W = 8, P = 8`,
binary32 `W = 8, P = 24`, binary64 `W = 11, P = 53`.
Statement: for every `W ≥ 2` and `P ≥ 2` (the spec's own well-formedness `Format.hw`, `Format.hp`)
with `W + P + 1 < 2^31` (so that the widths `W + P` and `W + P + 1`, `int` expressions of the module,
stay below `2^31`, the values an `int` holds), the design has exactly the ports `a`, `b`
(inputs, `W + P` bits) and `q` (output, `W + P` bits), no process is clocked, there is no
combinational loop, every run terminates, and in every cycle whose stimulus drives `a` and
`b` with known values the snapshot's `q` is `SvGolf.IEEE754.divide ⟨W, P⟩ .roundTiesToEven a b`,
the trusted spec of `svgolf/tasks/fdivp/IEEE754.lean` at that format. `REVIEW.md` lists the modelling choices.
-/
namespace SvGolf.Tasks.FdivP
open SvGolf SvGolf.IEEE754
/-- The storage width of the format `⟨W, P⟩`: `1 + W + (P - 1) = W + P`. -/
theorem k_eq (W P : Nat) (hP : 1 ≤ P) : 1 + W + (P - 1) = W + P := by omega
/-- **The function of the task**: `divide ⟨W, P⟩ .roundTiesToEven` on `(W + P)`-bit patterns,
for `2 ≤ W` and `2 ≤ P` (the spec's `Format` requires both). The `BitVec.cast`s only transport a
pattern along the equation `Format.k = W + P` (they leave `toNat` unchanged:
`fdivBits_toNat`); outside the range the function is `0`, which no statement looks at. -/
def fdivBits (W P : Nat) (a b : BitVec (W + P)) : BitVec (W + P) :=
if h : 2 ≤ W ∧ 2 ≤ P then
let f : Format := ⟨W, P, h.1, h.2⟩
have hk : f.k = W + P := k_eq W P (by omega)
(divide f .roundTiesToEven (a.cast hk.symm) (b.cast hk.symm)).cast hk
else 0#(W + P)
/-- The task at the format `⟨W, P⟩`, as a fixed-size `CombTask` (its own parameter is ignored and
taken at `0`, as in `CombTask.StatementFixed`): inputs `a b : BitVec (W + P)`, output
`q = fdivBits W P a b`. -/
def task (W P : Nat) : CombTask where
inRange K := K = 0
inputs _ := [("a", W + P), ("b", W + P)]
outputs _ := [("q", W + P)]
fn _ := fun (a, b, ()) => (fdivBits W P a b, ())
/-- Which parameter pairs the statement covers: the spec's own `Format` well-formedness, and
`W + P + 1 < 2^31`, so that the port width `W + P` and the exponent width `W + P + 1` a design computes
in (the ports' `[W+P-1:0]` and a `localparam integer EW = W + P + 1`, evaluated as `int`s) stay below
`2^31`, the values an `int` holds. -/
def inRange (W P : Nat) : Prop := 2 ≤ W ∧ 2 ≤ P ∧ W + P + 1 < 2 ^ 31
/-- **The challenge statement** for the two-parameter design family
`Submission.design.sem : Nat → Nat → Design2`: at every `W, P ≥ 2` in range the design satisfies the
fixed-size task at that format. A submission proves
`SvGolf.Tasks.FdivP.Statement Submission.design.sem`. -/
abbrev Statement (sem : Nat → Nat → LeanModels.Sv.Design2) : Prop :=
∀ W P, inRange W P → (task W P).StatementFixed (sem W P)
/-! Sanity checks on the statement's data (closed, by `decide`/`rfl`). -/
/-- binary16, bfloat16-like and binary32 are in range. -/
example : inRange 5 11 ∧ inRange 8 8 ∧ inRange 8 24 := by
simp [inRange]
/-- The range ends where `W + P + 1` reaches `2^31`, the first value an `int` does not hold. -/
example : inRange (2 ^ 31 - 4) 2 ∧ ¬ inRange (2 ^ 31 - 3) 2 ∧ inRange 2 (2 ^ 31 - 4) ∧
¬ inRange 2 (2 ^ 31 - 3) := by
simp [inRange]
/-- The input names are distinct (the non-vacuity theorem `CombTask.SatisfiedAt.exists_run`
needs it), at every parameter pair. -/
example (W P : Nat) : (((task W P).inputs 0).map Prod.fst).Nodup := by
simp [task]
/-- The casts do not change values. -/
theorem fdivBits_toNat (W P : Nat) (h : 2 ≤ W ∧ 2 ≤ P) (a b : BitVec (W + P)) :
(fdivBits W P a b).toNat =
(divide ⟨W, P, h.1, h.2⟩ .roundTiesToEven
(a.cast (k_eq W P (by omega)).symm) (b.cast (k_eq W P (by omega)).symm)).toNat := by
simp [fdivBits, h]
/-- Golden vectors of the spec through the task's function: `1 / 3 = 0x3555` in binary16,
`1 / 3 = 0x3EAAAAAB` in binary32, and bfloat16-like `(8, 8)`: `1 / 3 = 0x3EAB`. -/
example : ((task 5 11).fn 0 (0x3C00#16, 0x4200#16, ())).1 = 0x3555#16 := by decide
example : ((task 8 24).fn 0 (0x3F800000#32, 0x40400000#32, ())).1 = 0x3EAAAAAB#32 := by decide
example : ((task 8 8).fn 0 (0x3F80#16, 0x4040#16, ())).1 = 0x3EAB#16 := by decide
/-- `0 / 0` is the canonical NaN of the format (`0x7E00` in binary16). -/
example : ((task 5 11).fn 0 (0x0000#16, 0x0000#16, ())).1 = 0x7E00#16 := by decide
/-- The smallest formats are in range: `W = 2, P = 2` is 4 bits. -/
example : ((task 2 2).fn 0 (0b0011#4, 0b0100#4, ())).1 = fdivBits 2 2 0b0011#4 0b0100#4 := rfl
end SvGolf.Tasks.FdivP