Write a module that watches a ready/valid bus through the monitor modport and counts transfers and stalls.
Hardware context: Signal ownership at a DUT bus interface. Connect a real DUT and driver with explicit interface signal directions.
A coverage report says the read channel moved 40 beats, but the scoreboard saw 25. The old counter added one for every cycle with valid high. A cycle where the sink holds ready low is a stall, not a transfer, and the beat is offered again on the next cycle.
Write transfer_counter. It connects to the bus interface rv_if through its monitor modport, which can only read the pins. At each rising edge of bus.clk: if clear is 1, set all three outputs to 0. Otherwise, a cycle with valid and ready both 1 is a transfer: add 1 to transfers and add the data byte to data_sum. A cycle with valid 1 and ready 0 adds 1 to stalls. A cycle with valid 0 changes nothing.
For valid 1 1 1, ready 1 0 1 and data 10 20 20, you count 2 transfers, 1 stall and a sum of 0x30.
Signals in the timeline
| Signal | Width | Role |
|---|---|---|
clk | 1 | stimulus, the same for every design |
valid | 1 | stimulus, the same for every design |
ready | 1 | stimulus, the same for every design |
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
module transfer_counter (
rv_if.monitor bus,
input logic clear,
output int transfers,
output int stalls,
output logic [15:0] data_sum
);
// your counter
endmodule
Each case gives one clearing cycle and then 16 cycles of valid, ready and data, set while the clock is low. It reports the three outputs after the last edge.
Examples
Example 1
Stalls are not transfers- Input
valid 1 1 1 0 1 1, ready 1 0 1 0 0 1, data 10 20 20 -- 30 30
- Output
transfers = 3, stalls = 2, data_sum = 0x60
Beats 10, 20 and 30 move; 20 and 30 each wait one cycle first. Sum 0x60.
Example 2
The sink never accepts- Input
valid high for 4 cycles, ready low
- Output
transfers = 0, stalls = 4, data_sum = 0x0
Four stalls and no transfer: the same beat is offered four times.
Example 3
Ready alone moves nothing- Input
ready high for 5 cycles, valid low
- Output
transfers = 0, stalls = 0, data_sum = 0x0
With nothing offered, every cycle is idle.
Constraints and contract
- data_sum is 16 bits and wraps on overflow.
- Read the pins through the monitor modport only; it has no outputs.
- Keep the module name and ports.
Hints
Hint 1
A beat moves only at an edge where both sides agree. Which two pins must be 1 for that?
Hint 2
There are three kinds of cycle: transfer, stall and idle. Decide which kind each edge is before you update anything.
Hint 3
Inside always @(posedge bus.clk), test clear first, then valid and ready together, then valid alone.
What this judge verifies: Your counter watches 28 traces of 16 cycles, directed and seeded random, each after a clearing cycle. Passing shows it tells transfers, stalls and idle cycles apart on these traces.
28 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