Use the function form of $cast and its result before touching any write-only field.
Hardware context: Typed optional extensions in a hardware transaction pipeline. Safely access a supported transaction subtype after a checked downcast.
A coverage collector ignored the result of $cast. When an ordinary read arrived, the cast failed and left the handle pointing at the previous write, and that write was counted again: 40 error samples from 12 error transactions.
Write inspect_write(item). Packets arrive as bus_packet handles. If item is null, return status 1. If it cannot be cast to write_packet, return status 2. Otherwise return status 0 with its uid, address, data and strobes. A diagnostic_write is a write_packet too, so it succeeds.
Decide by the cast’s result, never by field values: a read can have the same address as a write, and a write can have zero strobes.
Signals in the timeline
| Signal | Width | Role |
|---|---|---|
kind | 3 | input of each check |
identifier | 8 | input of each check |
address | 16 | input of each check |
data | 16 | input of each check |
strobes | 2 | input of each check |
Full specification
class bus_packet;
byte unsigned uid;logic[15:0] address;
function new(input int identifier,addr);uid=8'(identifier);address=16'(addr);endfunction
endclass
class write_packet extends bus_packet;
logic[15:0] data;logic[1:0] strobes;
function new(input int identifier,addr,value,lanes);super.new(identifier,addr);data=16'(value);strobes=2'(lanes);endfunction
endclass
class read_packet extends bus_packet;
byte unsigned beats;
function new(input int identifier,addr,length);super.new(identifier,addr);beats=8'(length);endfunction
endclass
class diagnostic_write extends write_packet;
byte unsigned diagnostic_tag;
function new(input int identifier,addr,value,lanes);super.new(identifier,addr,value,lanes);diagnostic_tag=8'hd7;endfunction
endclass
function automatic logic [63:0] inspect_write(input bus_packet item);
// returns {status[7:0], uid[7:0], address[15:0], data[15:0], strobes[7:0], 8'b0}
On status 1 or 2 every field other than status is 0. Do not change the object.
Examples
Example 1
Writes and their subclass- Input
a write (uid 17, address 0024, data ABCD, strobes 11) then a diagnostic_write (uid 18, address 0026, data 5500, strobes 00)
- Output
status = OK (0), uid = 17, address = 0x24, data = 0xabcd, strobes = 'b11 status = OK (0), uid = 18, address = 0x26, data = 0x5500, strobes = 'b00
Both casts succeed. Zero strobes is still a write.
Example 2
A read is not a write- Input
a read (uid 23, address 0028, 4 beats)
- Output
status = NOT_A_WRITE (2), uid = 0, address = 0x0, data = 0x0, strobes = 'b00
The cast fails: status NOT_A_WRITE and every field 0.
Example 3
Null first- Input
a null handle
- Output
status = NULL (1), uid = 0, address = 0x0, data = 0x0, strobes = 'b00
Status NULL, checked before any cast.
Constraints and contract
- item may be null or any of the four classes.
- Use the function form of $cast and test its result.
- Keep the function signature.
Hints
Hint 1
What happens to a handle when $cast fails, and how do you find out that it failed?
Hint 2
Handle null before anything else: you cannot ask a null handle what type it is.
Hint 3
Return 2 as soon as the cast reports failure; read the write fields only from the handle the cast filled in.
What this judge verifies: Your function is called with null, plain, read, write and diagnostic packets with seeded fields, including zero strobes and reads that look like writes. Passing shows the cast result decides every answer.
164 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