Choose four ready/valid traces that make five broken hold checkers give themselves away.
Hardware context: Elastic ready/valid datapath with packet boundaries. Choose ready/valid traces that separate a correct hold-rule checker from copies with planted bugs.
The hold rule of a ready/valid bus says: once a source offers a beat and the sink stalls it, the source must offer the same beat on the next cycle, with valid still 1 and the same data. Only a beat that moved may be replaced.
first_hold_break checks an 8-cycle trace and returns the first cycle that breaks the rule, or 0 for a clean trace. The version in the specification is correct. Five copies of it each hide one bug.
In the task stimulus, call try_trace once for each trace you want to check, at most four times. A trace is three numbers: valid and ready, one bit per cycle with bit 0 for cycle 1, and data, one 4-bit nibble per cycle with the lowest nibble for cycle 1.
A copy is caught when its answer differs from the correct one on at least one of your traces. Clean traces count too.
Signals in the timeline
| Signal | Width | Role |
|---|---|---|
hidden_bug | 8 | input of each check |
Full specification
// First cycle (1 to 8) that breaks the hold rule, or 0 when the trace is clean.
// Cycle c uses valid[c-1], ready[c-1] and the 4-bit data nibble data[4*(c-1) +: 4].
// A stall is a cycle with valid = 1 and ready = 0. The cycle after a stall must
// offer the same beat: valid = 1 and the same data.
function automatic int first_hold_break(input bit [7:0] valid, input bit [7:0] ready, input bit [31:0] data);
for (int i = 1; i < 8; i++)
if (valid[i-1] && !ready[i-1])
if (!valid[i] || data[4*i +: 4] != data[4*(i-1) +: 4]) return i + 1;
return 0;
endfunction
task automatic stimulus();
// valid, ready, data (nibble per cycle, cycle 1 lowest)
try_trace(8'b0000_0011, 8'b0000_0010, 32'h0000_0055);
endtask
| Trace | valid | ready | data | Answer |
|---|---|---|---|---|
| stall, then the same beat moves | 8'b011 | 8'b010 | 32'h055 | 0 |
| stall, then valid drops | 8'b001 | 8'b000 | 32'h055 | 2 |
| a beat moves, then a new one | 8'b011 | 8'b011 | 32'h065 | 0 |
Examples
Example 1
Your traces follow the rules- Input
stimulus() makes 4 calls
- Output
inputs_legal = yes
Four traces is the limit.
Example 2
A changed beat after a stall- Input
try_trace(8'b011, 8'b010, 32'h065)
- Output
caught = yes
Cycle 1 stalls beat 5, cycle 2 offers 6: the correct answer is 2. A copy that ignores data says 0.
Example 3
A dropped offer after a stall- Input
try_trace(8'b001, 8'b000, 32'h055)
- Output
caught = yes
Cycle 1 stalls beat 5, then valid drops while the data pins keep their value. The correct check reports a break in cycle 2; a copy that misses dropped offers reports none.
Constraints and contract
- Call try_trace at most 4 times inside stimulus.
- Any 8-bit valid and ready and any 32-bit data are allowed.
- Do not call first_hold_break yourself.
Hints
Hint 1
List the ways a source can break the rule after a stall, and the one thing it is allowed to do after a beat moves.
Hint 2
A trace with exactly one event in it tells you most: one stall, followed by exactly one kind of change.
Hint 3
Where in the trace a break happens matters as well as whether it happens. Try one at the very end.
What this judge verifies: Your traces are run through the correct checker and five broken copies, and the answers are compared. Passing shows your traces separate each broken copy from the correct one.
6 checks on Verilator · local server. Run the examples first, then check the full regression. The suite is local and inspectable. A passing result establishes the tested cases, not a proof for all possible inputs.
See all 9 steps and the final capstone