Difficulty: Medium · Puzzle 6 of 6 · Topic: Scoreboard Puzzles: Mismatch or Ordering Bug?
Protocol note: a request marked retry=1 was NACKed and completes nothing; the master reissues it as a new request with the same id and retry=0, and the slave completes only the final attempt (one completion per id). Scoreboard reports 'unexpected actual' and duplicate expected ids under retry traffic. Find the predictor-side overcounting.
function void predictor::write_req(req_t r);
// bug: every attempt gets an expectation, and a NACKed (retry=1) attempt gets two
exp_ap.write(model_rsp(r));
if (r.retry) begin
exp_ap.write(model_rsp(r));
end
endfunctionRetry metadata does not always mean a second architectural completion.
1) Compare expected-id histogram against actual-id histogram.
2) Observe the excess expected entries only for ids that had a retry-marked request: a NACKed request plus its reissue gives 3 expectations (2 + 1) for 1 completion.
3) Review protocol: a retry=1 attempt was NACKed and completes nothing; only the reissue (retry=0) completes. Deleting just the second write would still leave 2 expectations for 1 completion.
4) Fix: if (!r.retry) exp_ap.write(model_rsp(r)); so the NACKed attempt creates no expectation and the reissue creates exactly one: 1 expectation for 1 completion.
5) Add protocol-aware predictor test covering retries and replays.Answer: Bug: the predictor creates expectations for the NACKed attempt (two of them) as well as for the reissue, so one completion has 3 expectations. Fix: write an expectation only when the request is not a retry (if (!r.retry) exp_ap.write(model_rsp(r))), giving one expectation per completion.
Checked by running the code in Verilator 5 and Icarus Verilog 13; the printed output supports the answer above. Plain-SV counting model of the predictor: the NACKed attempt adds phantom expectations, the filtered version gives one per completion. Plain-SV counting model of the predictor: the NACKed attempt adds phantom expectations, the filtered version gives one per completion.
It looks like the DUT dropped data, but the predictor created phantom expectations. The protocol note matters: if a retried request completed twice, this code would be right.
How would you key expected entries when request id can be reused after retry windows? Model answer: An equally valid alternative to the retry filter is to keep a set of outstanding ids and replace the pending expectation when the same id is reissued while still outstanding. For id reuse after completion: key by (id, generation) where the generation increments when an id is re-issued after its completion, or keep a set of outstanding ids and remove the entry on completion; either way a reissue never adds a second pending expectation.
It looks like the DUT dropped data, so first I count expectations against completions for the failing transfer. The root cause is that the predictor creates expectations for the NACKed attempt, two of them, as well as for the reissue, so one completion has three expectations. I confirm it by logging each expectation write with its retry flag. The fix is to write an expectation only when the request is not a retry, giving one expectation per completion.