Waveform data
Cycle-indexed values you assert on directly, plus a VCD rendering for when you want eyes.
This crate exists because a waveform viewer is a debugging tool and an assertion is a test. Both are useful and they answer different questions: the viewer tells you what happened, the assertion tells you whether it should have.
So the data model is a value per cycle per port, and the primary API is assert_series. The VCD rendering is a secondary function of the same data, not a separate capture path.
Step by step
- 01
Register the ports, with their widths
registerandregister_shapeattach a port to the dataset;topnames the scope andidentifiersgives the names used in the output.use ferrite_lithic_wave::WaveData; let mut wave = WaveData::new("top"); wave.register(&port, "count")?; - 02
Record a cycle
recordtakes the cycle number and a lookup closure, so the data can be gathered from a snapshot without the wave crate knowing what a snapshot is.wave.record(cycle, |signal| { Ok(snapshot.value(signal)) })?; - 03
Assert the series, not the last value
assert_seriescompares the whole cycle-indexed sequence and reports the first cycle that differs. This is the single most useful function in the crate: a decoder that retires 39 of 40 symbols produces a correct final answer and a failing series.wave.assert_series(&port, &[ Bits::constant(0, 8)?, Bits::constant(1, 8)?, Bits::constant(3, 8)?, ])?; - 04
Read the changes when the series is long
series_changesreturns(cycle, value)pairs for the cycles where the value moved, which is what makes a 40-cycle run of mostly-zeros readable in a failure message. - 05
Write VCD when you want to look at it
writeconsumes the dataset into aWrite, andrendergives a string. Same data either way, so a waveform can never disagree with the assertion that passed.
What bites
Series are indexed by cycle, not by position
A gap in cycle numbers is a gap, not a shift. A design that stops clocking produces a short series and a failing assertion rather than a silently compressed one.