Turn the FIFO’s acceptance rules into one function that a monitor and a model can both call.
Hardware context: Single-clock FIFO with pre-edge full/empty acceptance. Derive accepted operations at empty, interior and full occupancy.
Every later layer of the FIFO testbench asks the same question at each rising edge: given the occupancy before the edge and the request pins, which operations does the FIFO accept? If the model and the monitor answer it differently, the scoreboard reports bugs that are not there.
Write acceptance(depth, used, reset, write_en, read_en). A write is accepted only when write_en is 1 and the FIFO is not full; a read only when read_en is 1 and the FIFO is not empty. Both decisions use the occupancy from before the edge. Reset wins over both and empties the FIFO.
Return four bytes: the flags before the edge, which operations were accepted, the occupancy after the edge, and the flags after it. At empty with both enables only the write is accepted; at full with both enables only the read is.
Signals in the timeline
| Signal | Width | Role |
|---|---|---|
depth | 5 | input of each check |
used | 5 | input of each check |
reset | 1 | input of each check |
write_en | 1 | input of each check |
read_en | 1 | input of each check |
Full specification
function automatic bit [31:0] acceptance(input int depth, used, input bit reset, write_en, read_en);
// returns {pre_flags[31:24], accepted[23:16], next_used[15:8], post_flags[7:0]}
| Byte | Bits |
|---|---|
| pre_flags, post_flags | bit 0 = empty (occupancy 0), bit 1 = full (occupancy = depth), other bits 0 |
| accepted | bit 0 = write accepted, bit 1 = read accepted, other bits 0 |
| next_used | occupancy after the edge: 0 after reset, else used + write - read |
pre_flags describe the old state even when reset is 1. A refused operation changes nothing.
Examples
Example 1
Both enables at empty, depth 1- Input
depth = 1, used = 0, reset = 0, write_en = 1, read_en = 1
- Output
pre_empty = yes, pre_full = no, write_accepted = yes, read_accepted = no, next_used = 1, post_empty = no, post_full = yes
The FIFO is empty before the edge, so only the write is accepted. Afterwards it is full.
Example 2
Both enables at full- Input
depth = 3, used = 3, reset = 0, write_en = 1, read_en = 1
- Output
pre_empty = no, pre_full = yes, write_accepted = no, read_accepted = yes, next_used = 2, post_empty = no, post_full = no
The FIFO is full before the edge, so the write is refused even though the read frees a slot. Occupancy drops to 2.
Example 3
Reset wins- Input
depth = 3, used = 2, reset = 1, write_en = 1, read_en = 1
- Output
pre_empty = no, pre_full = no, write_accepted = no, read_accepted = no, next_used = 0, post_empty = yes, post_full = no
Nothing is accepted and the FIFO is empty afterwards; the flags before the edge still show occupancy 2.
Constraints and contract
- depth is 1 to 16 and used is 0 to depth.
- All inputs are known bits.
- Keep the function name and arguments.
Hints
Hint 1
Work out the two accept decisions first, both from used, before you compute anything else.
Hint 2
A full FIFO with read_en and write_en: does the read make room for the write at this edge? The rule says which occupancy decides.
Hint 3
Reset forces both decisions to 0 and the next occupancy to 0, but the flags before the edge still come from used.
What this judge verifies: Your function is called for every depth from 1 to 16, every legal occupancy and every combination of reset and the two enables. Passing shows it matches the FIFO rules for one edge.
435 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 6 steps and the final capstone