Write a class-based driver that keeps a virtual interface handle to the bus it was given and checks it before driving.
Hardware context: Class-based agents connected to separate DUT interface instances. Require a valid DUT interface binding before a driver begins timed work.
A test builds two drivers for two identical buses, plus a spare driver that was never connected. A class cannot have a port, so each driver gets its bus as a virtual interface handle in its constructor and keeps it for every later call.
Write the three members of beat_driver. The constructor stores the ID and the handle. configured() returns 1 when the driver has a bus, and 0 for a null handle. send(value) waits for the next falling edge of the bus’s clock, drives valid = 1 and data = value, waits for the following falling edge, drives valid = 0 and adds 1 to sent.
A driver with no bus must not touch anything: send returns at once and sent stays 0. Driver 1 must never move bus_b, and driver 2 must never move bus_a.
Signals in the timeline
| Signal | Width | Role |
|---|---|---|
clk | 1 | stimulus, the same for every design |
bus_a.valid | 1 | stimulus, the same for every design |
bus_a.ready | 1 | stimulus, the same for every design |
bus_a.data | 8 | stimulus, the same for every design |
bus_b.valid | 1 | stimulus, the same for every design |
bus_b.ready | 1 | stimulus, the same for every design |
bus_b.data | 8 | stimulus, the same for every design |
Full specification
interface rv_if (input logic clk);
logic valid = 0;
logic ready = 0;
logic [7:0] data = 0;
modport source (input clk, ready, output valid, data);
modport sink (input clk, valid, data, output ready);
modport monitor (input clk, valid, ready, data);
endinterface
// Drives one beat at a time onto the bus it was given.
class beat_driver;
virtual rv_if vif;
int id;
int sent;
function new(input int id, virtual rv_if vif);
endfunction
// 1 when the driver has a bus to drive.
function bit configured();
endfunction
// Drive valid = 1 with data = value from one falling edge to the next.
task send(input logic [7:0] value);
endtask
endclass
Each case builds driver 1 on bus_a, driver 2 on bus_b and driver 3 with a null handle, makes three send calls in order and runs 8 clock cycles. A recorder counts each bus’s cycles with valid high at the rising edge and sums their data. The case reports both buses, each driver’s sent count and configured() for all three.
Examples
Example 1
Each driver reaches only its own bus- Input
send(11) on driver 1, send(22) on driver 2, send(33) on driver 1
- Output
bus_a_beats = 2, bus_a_sum = 0x44, bus_b_beats = 1, bus_b_sum = 0x22, sent_1 = 2, sent_2 = 1, sent_3 = 0, configured_1 = yes, configured_2 = yes, configured_3 = no
bus_a sees two beats (sum 0x44), bus_b one (0x22).
Example 2
A driver with no bus- Input
three sends on driver 3
- Output
bus_a_beats = 0, bus_a_sum = 0x0, bus_b_beats = 0, bus_b_sum = 0x0, sent_1 = 0, sent_2 = 0, sent_3 = 0, configured_1 = yes, configured_2 = yes, configured_3 = no
Nothing moves, no send is counted, and configured() is 0 for driver 3 only.
Example 3
Back-to-back sends- Input
send(80), send(81) on driver 2, then send(99) on driver 3
- Output
bus_a_beats = 0, bus_a_sum = 0x0, bus_b_beats = 2, bus_b_sum = 0x101, sent_1 = 0, sent_2 = 2, sent_3 = 0, configured_1 = yes, configured_2 = yes, configured_3 = no
bus_b sees two beats with sum 0x101.
Constraints and contract
- One send drives exactly one cycle of valid on its own bus.
- A driver without a bus never dereferences its handle.
- Keep the class, field and method names.
Hints
Hint 1
The constructor’s argument has the same name as the field. How do you say "the field" inside the class?
Hint 2
A virtual interface handle can be compared with null, like a class handle.
Hint 3
In send, check the handle before the first wait; then wait on vif.clk, never on a signal of the test module.
What this judge verifies: Every order of three sends over two connected drivers and one unconnected driver is run, and both buses are recorded at every edge. Passing shows each driver reaches only its own bus.
30 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 5 steps and the final capstone