File size: 3,096 Bytes
0ba037b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# Verification Contract

Applies to `rtl/bit_accelerator.sv`.

## Interface

- Reset is synchronous and active-high. Reset cancels any uncompleted operation
  and suppresses its result. `op_ready` is low while `reset` is high.
- An operation is accepted on a cycle with `op_valid && op_ready`. `op_ready`
  stays low until the operation's result pulse.
- A read request completes on `mem_valid && !mem_write && mem_ready`; its data
  completes on `mem_rvalid`. A read fault is signalled with `mem_fault` instead
  of `mem_rvalid`.
- A write request completes on `mem_valid && mem_write && mem_ready`. The cycle
  after the write handshake, `mem_fault` reports a write fault.
- `mem_addr` is `((base_address << 3) + bit_offset) >> 6 << 3` (64-bit
  arithmetic); `mem_wstrb` is all ones.
- `result_valid` is a one-cycle pulse. `error` and `result_bit` are valid in the
  same cycle. On `error`, `result_bit` keeps its previous value.

## Operations

| Opcode | Op | Writes | `result_bit` |
|---|---|---|---|
| 000 | GET | no | bit value |
| 001 | TEST | no | bit value |
| 010 | SET | yes | 1 |
| 011 | CLEAR | yes | 0 |
| 100 | TOGGLE | yes | new bit value |
| 101-111 | undefined | no | `error = 1` |

A read fault ends the operation with `error = 1` and no write. A write fault
reports `error = 1`; whether the memory kept the write is up to the memory.

## Evidence

| Check | Tool | Result |
|---|---|---|
| Lint | `verilator --lint-only -Wall` | clean |
| Simulation | `verification/tb_bit_accelerator.sv`, Icarus 12 and Verilator 5.020 | 0 failures; 23 directed operations, 12 reset-cancellation cases, 2000 random operations per seed with backpressure, read latency 0-3 and fault injection |
| Mutation | 7 hand-made RTL mutants (wrong bit index, wrong address, SET as XOR, ...) | all detected |
| Proofs | `formal/*.mlw`, Why3 1.6 + Z3 4.8.12 | 38/38 goals valid |
| Timing model | `spice/bit_extract.sp`, ngspice 42 | tpd ≈ 94 ps (RC model, not extracted silicon) |
| FPGA wrapper | `fpga/tb/tb_fpga_top.sv` over the UART: RTL (Icarus, Verilator), iCE40 and ECP5 gate-level netlists | 0 failures on each |
| Host tool | `fpga/sim/cosim.sh`: `bitacc selftest` against the RTL through a pseudo-terminal | 2000 operations, 0 mismatches |
| FPGA place-and-route | nextpnr, 5 seeds | iCE40UP5K 39.06 MHz, ECP5-25F 73.22 MHz; both meet board clocks |
| ASIC synthesis | Yosys + ABC on sky130_fd_sc_hd, OpenSTA | 1538 cells, 10,063 µm², netlist proved equal to RTL, 500 MHz pre-layout |

`formal/bit_address.mlw` proves that the RTL's shift/mask datapath equals the
integer address specification when `(base << 3) + offset` does not overflow.
Its trusted base is four facts from the Why3 bit-vector library (listed in the
file), restated because the SMT drivers do not pass them to the solver.
`formal/bit_extract.mlw` proves GET/SET/CLEAR/TOGGLE on 64-bit words change
exactly the target bit.

The proofs are about the datapath expressions; the state machine is checked by
simulation. Random seeds reproduce within one simulator only (Icarus and
Verilator implement `$random` differently).