Track outstanding reads by ID in an associative array, and catch a response for an ID nobody issued.
Hardware context: Tagged request/response interconnect with out-of-order completion. Look up the outstanding request for a returned hardware transaction ID.
A bit flipped in the DUT’s ID path, and a response came back with ID 9, which the testbench never issued. The scoreboard read exp_data[9], got the default 0, and the data happened to be 0 too. The check passed and nothing in the log mentioned ID 9.
Write four routines that share an associative array keyed by the 32-bit read ID. clear_requests forgets every outstanding read. put_request(id, value) remembers that a read with this ID will return value. take_response(id) answers a response: if the ID is outstanding, return status 0 with the remembered value and forget the ID; if not, return status 1, UNEXPECTED, with value 0. request_count says how many reads are outstanding.
Responses may arrive in any order. In this first version the test never issues an ID that is already outstanding, and never has more than four outstanding at once.
Signals in the timeline
| Signal | Width | Role |
|---|---|---|
operation | 2 | input of each check |
id | 32 | input of each check |
value | 32 | input of each check |
Full specification
task automatic clear_requests();
function automatic int put_request(input bit [31:0] id, value);
function automatic logic [39:0] take_response(input bit [31:0] id); // {status[7:0], value[31:0]}
function automatic int request_count();
| Call | Effect | Reported |
|---|---|---|
| clear_requests() | forget every outstanding read | status 0, value 0 |
| put_request(id, value) | remember value for id; returns 0 | status 0, value 0 |
| take_response(id), id outstanding | forget id | status 0 OK, the remembered value |
| take_response(id), id not outstanding | nothing changes | status 1 UNEXPECTED, value 0 |
Every 32-bit ID is legal, including 0 and 0xFFFFFFFF. Each case reports the status and value of its call and request_count() after it.
Examples
Example 1
Start empty- Input
clear_requests()
- Output
status = OK (0), pending = 0, value = 0x0
Nothing is outstanding.
Example 2
The largest ID is legal- Input
put_request(32'hFFFFFFFF, 32'h12345678)
- Output
status = OK (0), pending = 1, value = 0x0
One read is outstanding. Storing an expectation does not return a value yet.
Example 3
The response retires that exact ID- Input
take_response(32'hFFFFFFFF)
- Output
status = OK (0), pending = 0, value = 0x12345678
The value comes back and the ID is forgotten, so nothing is outstanding.
Constraints and contract
- IDs and values are known 32-bit unsigned numbers.
- Calls happen one at a time, in order; state lasts between calls until clear_requests.
- Keep the four signatures.
Hints
Hint 1
Reading a key that is not in an associative array does not fail; it quietly returns a default. How do you ask whether a key is there?
Hint 2
A response must remove exactly its own ID, and only after you have read its value.
Hint 3
request_count can come straight from the array: it knows how many keys it holds.
What this judge verifies: Your routines run through long seeded sequences of requests, responses in any order, unexpected IDs and clears, with sparse 32-bit IDs. Passing shows every status, value and count is right on these sequences.
378 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