The Signal and Signal.reg you have been writing are not just Lean values — each one corresponds to a real piece of hardware. This chapter connects the abstraction to the physical element level: what a register, a clock, and a gate actually are, how a design's speed (static timing analysis) and size (gate count) are measured, and how the same design maps onto ASIC standard cells versus FPGA primitives (LUT4, DFF, BSRAM, DSP). It is the conceptual bridge between Ch 8 (Yosys netlists), Ch 8b (simulation), and Ch 9 (#verify_fpga + FPGA bring-up).
import Sparkle
open Sparkle.Core.Domain
open Sparkle.Core.Signal
namespace Notebooks.Ch08c
8c.1 The register is a D flip-flop
Every Signal.reg (and the lower-level Signal.register init d) becomes one D flip-flop (DFF) per stored bit. A DFF samples its D input on the rising clock edge and holds it on Q until the next edge:
That defining behaviour is exactly the .val semantics of the register: the value at reset is init, and the value at cycle t+1 is the input sampled at cycle t. Both hold by rfl — the register literally is a DFF.
-- Q at reset is `init`.
example {dom : DomainConfig} (init : BitVec 8) (d : Signal dom (BitVec 8)) :
(Signal.register init d).val 0 = init := rfl
-- Q at cycle t+1 is D sampled at cycle t.
example {dom : DomainConfig} (init : BitVec 8) (d : Signal dom (BitVec 8))
(t : Nat) :
(Signal.register init d).val (t + 1) = d.val t := rfl
The init is the DFF's reset value. On real hardware that reset is either synchronous (applied on a clock edge) or asynchronous (applied immediately) — a choice carried by the DomainConfig, not by the register itself.
8c.2 The clock and clock domains
There is no explicit clock wire in a Sparkle expression, and that is deliberate: the cycle index `t` is the clock. One rising edge advances t → t+1; every register samples its input at that edge.