23Implementation
Build a generic hold register
Problem
Intended behavior. Hold[T <: Data](gen) is a register for any payload
type. On every clock edge where en is high it captures in; on other edges
it keeps what it has. out always shows the most recently captured value, so
a capture appears on out immediately after the edge that took it. Before the
first capture the output is unspecified. PixelHold is the same generator
fixed to a three-field Pixel.
Current behavior. The starter connects in straight to out. The output
follows the input in every cycle and nothing is held.
Task. Give Hold the register it needs. The body must work for every
T: the public run builds both Hold(UInt(8.W)) and PixelHold. Keep the
class names, the type parameter, and the ports.
Read the starter
Find where gen is used. It shapes in and out; en is always a Bool.
The template itself is never connected to anything. Ask what the body knows about T and what it does not: it cannot
name a width or a field, only use what gen describes.
Predict before running
The public run steps the clock after each poke and then prints out. For the
UInt test the inputs are 7, 8, 9, 10, 11 with en high only for 7 and 10.
Predict the five out values, then the three Pixel rows. Compare with the
starter's output, where every row simply repeats its input.
Run and explain
Run your change. In the UInt trace, out may change only on rows where en is
true, because each row is printed after its edge. Each Pixel row must hold all three fields together. Explain how one
body built an 8-bit register for one instance and a three-field register for
the other without naming either type.
Completion check
outchanges only after an edge whereenwas high.- With
enlow,outkeeps its value for any number of cycles whileinchanges. - All fields of a
Bundlepayload are captured together. - The same body compiles and behaves correctly for
UIntandPixel.
Progressive hints
Hint 1
Holding a value across cycles needs state. Which hardware construct from the
sequential circuits chapter stores a value and is updated by :=?
Hint 2
The register's type must be T, and the only description of T you have is
gen. A fixed type such as UInt(8.W) fails to compile for the Pixel
instance.
Hint 3
Update the register under when(io.en), and drive out from the register,
not from the input.
Concept
gen is a Chisel type, a template. Input(gen), Output(gen), and
Reg(gen) each make a separate hardware value with that shape. The generic
body works on that hardware only through operations every Data supports,
such as := and when, so the same code builds an 8-bit register in one
instance and a 24-bit Bundle register in another.
Extension experiment
Predict what changes if you write Reg(io.in) instead of using gen. Then
predict the elaboration result of new Hold(0.U(8.W)), and in which phase it
fails.