Drill 1. rand bit [7:0] x: make x even.
Drill 2. rand bit [31:0] addr and rand bit [3:0] size: size is 1, 2, 4 or 8, and addr is a multiple of size. Both are random in the same call.
Drill 3. rand bit [15:0] x: x is between 0 and 1000, but never between 100 and 200.
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: parity, alignment and holes.
class drill1; // x is even
rand bit [7:0] x;
constraint answer_c { /* your answer here */ }
endclass
class drill2; // size is 1, 2, 4 or 8, and addr is a multiple of size
rand bit [31:0] addr;
rand bit [3:0] size;
constraint answer_c { /* your answer here */ }
endclass
class drill3; // x is 0 to 1000 but never 100 to 200
rand bit [15:0] x;
constraint answer_c { /* your answer here */ }
endclass
100 <= x <= 200 constrain?Nothing useful. It parses as (100 <= x) <= 200, a 1-bit result compared with 200, which is always true. Write two relations, or use inside.
One set of answers, run through the same grader:
// Drills: parity, alignment and holes.
class drill1; // x is even
rand bit [7:0] x;
constraint answer_c { x[0] == 1'b0; }
endclass
class drill2; // size is 1, 2, 4 or 8, and addr is a multiple of size
rand bit [31:0] addr;
rand bit [3:0] size;
constraint answer_c { size inside {1, 2, 4, 8}; (addr & (size - 1)) == 0; }
endclass
class drill3; // x is 0 to 1000 but never 100 to 200
rand bit [15:0] x;
constraint answer_c { x inside {[0:1000]}; !(x inside {[100:200]}); }
endclass
drill 1, even x: ok
drill 2, aligned addr: ok
drill 3, range with a hole: ok
PASS: all 3 drills rightForm | Spelling | When to reach for it |
|---|---|---|
Bit slice |
| Production code: a single cheap equality |
Modulo |
| Any divisor, including non-powers of two |
Shift round-trip |
| Showing bit mechanics on a whiteboard |
For alignment, size - 1 is a mask of the low bits only when size is a power of two: for 8 it is 0111, so three address bits go to zero. The solver picks size and addr together, in one call. When size can be 3, the mask fails and addr % size == 0 with size > 0 is the answer.
For the hole, a range and a negated inside combine: x inside {[0:1000]}; !(x inside {[100:200]});. Writing the two outer pieces, x inside {[0:99], [201:1000]}, is the same set.
A note on the grader: Verilator 5.048 spreads this hole range unevenly. Across 400 calls it gave fewer than 15 values below 100, where an even spread over the 900 legal values gives about 44. That is why the grader pins values such as 0 and 99 instead of waiting for random results to land there.
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.