Drill 1. rand bit [7:0] b[4]: the four bytes total exactly 600.
Drill 2. rand bit [1:0] kind: kind 0 about 70% of the time, kind 1 about 20%, kind 2 about 10%, and never 3.
Drill 3. rand bit [4:0] d[4]: four delays, each 1 to 20 cycles, totalling exactly 40.
Write the three answers before opening the reveal. Copy the starter into the Code Lab, fill in each empty answer_c, and run it on Verilator. The grader solves each class hundreds of times and checks every result, then pins a few values that must be legal; it prints ok or the first rule your answer broke.
// Drill starter: write each answer_c, then run it.
// Drills: sums and weights.
class drill1; // four bytes total exactly 600
rand bit [7:0] b[4];
constraint answer_c { /* your answer here */ }
endclass
class drill2; // kind 0, 1, 2 about 70, 20 and 10 percent; never 3
rand bit [1:0] kind;
constraint answer_c { /* your answer here */ }
endclass
class drill3; // four delays, each 1 to 20 cycles, total exactly 40
rand bit [4:0] d[4];
constraint answer_c { /* your answer here */ }
endclass
kind inside {0, 1, 2} gives every value the same chance. Why can it not do this job?inside only says which values are legal. Only dist sets weights.
One set of answers, run through the same grader:
// Drills: sums and weights.
class drill1; // four bytes total exactly 600
rand bit [7:0] b[4];
constraint answer_c { b.sum() with (int'(item)) == 600; }
endclass
class drill2; // kind 0, 1, 2 about 70, 20 and 10 percent; never 3
rand bit [1:0] kind;
constraint answer_c { kind dist { 0 := 70, 1 := 20, 2 := 10 }; }
endclass
class drill3; // four delays, each 1 to 20 cycles, total exactly 40
rand bit [4:0] d[4];
constraint answer_c { foreach (d[i]) d[i] inside {[1:20]}; d.sum() with (int'(item)) == 40; }
endclass
drill 1, bytes total 600: ok
drill 2, 70 / 20 / 10 weights: ok
drill 3, delay budget of 40: ok
PASS: all 3 drills rightThe standard sums bit [7:0] elements in 8 bits, so b.sum() == 600 can never hold, and a smaller target can be met by bytes whose real total wraps. Widen each item: b.sum() with (int'(item)). State the feasibility bounds aloud too: four bytes reach 0 to 1020, so 600 is inside.
The grader cannot catch an unwidened sum on Verilator 5.048, which computed the total wide and solved it anyway. Another simulator fails every call. Write the widened form, which is right everywhere.
Bin |
|
|
|---|---|---|
| 50 + 50 = 100; | 500 + 50 = 550; |
Single values | Identical: no range to split | Identical: no range to split |
Weights are relative, so 7:2:1 and 70:20:10 agree. Values left out of a dist are illegal, which is what keeps kind 3 away.
A budget is bounded elements plus a pinned total. The per-element bounds matter: without them one delay can take the whole budget and starve the rest. The grader pins 20 + 18 + 1 + 1 to catch an answer that bounds the elements too tightly.
Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown. Verilator prints a harmless WIDTHTRUNC warning for if (!obj.randomize()), because randomize() returns an int, and an UNSATCONSTR warning when a solve fails on purpose. Icarus 13 does not support constraints.
Each starter was run with its answers left empty, and its grader reported all three drills wrong; each revealed answer passed the same grader. The graders also caught an unwidened size * count and an over-tight even rule when tried.
Verilator solved the unwidened b.sum() == 600, so the grader cannot catch that mistake on it.