Difficulty: Medium · Puzzle 2 of 6 · Topic: Sequences and Sequencers
UVM 1.2. A sequence sends two items with start_item / finish_item and prints the time after each finish_item. Driving one item takes 10 ns. Driver A calls item_done immediately after get_next_item and then drives; driver B drives first and calls item_done at the end. At which times (relative to the start) does each driver let the sequence print?
// sequence body
repeat (2) begin
start_item(req);
assert(req.randomize());
finish_item(req);
`uvm_info("SEQ", "finish_item returned", UVM_LOW)
end
// driver A
seq_item_port.get_next_item(req);
seq_item_port.item_done();
#10; // drive pins
// driver B
seq_item_port.get_next_item(req);
#10; // drive pins
seq_item_port.item_done();finish_item returns when the driver calls item_done, not when it calls get_next_item and not when the pins finish wiggling.
1) finish_item blocks until the driver calls item_done for that item.
2) Driver B calls item_done after the 10 ns drive: the prints are at 10 ns and 20 ns.
3) Driver A calls item_done at once: the first print is at 0 ns. The sequence immediately offers item 2, but the driver is busy driving item 1 until 10 ns and only then calls get_next_item, so the second print is at 10 ns.
4) So A: 0 and 10 ns; B: 10 and 20 ns.Answer: Driver A: 0 ns and 10 ns. Driver B: 10 ns and 20 ns.
Checked by running the code in Verilator 5; the printed output supports the answer above. Hand-written model of the documented UVM 1.2 behaviour in plain SystemVerilog (Verilator), not the UVM library: mailbox hand-over with an acknowledgement stands for the sequencer: finish_item blocks until item_done.
Calling item_done early frees the sequence while the item is still being driven; if the sequence reuses or edits the same `req` object, the driver is then reading a changing object. item_done belongs after the item is truly consumed.
If the driver B samples a read response from the bus, where in the handshake should it put the data for the sequence? Model answer: before item_done: either write the read data into the request item itself (the sequence still holds the same handle once finish_item returns) or send a response with `item_done(rsp)`/`put_response`, which the sequence then collects with get_response.