Are are any standard or recommended ways of verifying the functionality of the round-robin arbiter and more specifically checking the fairness?
I’m looking for something that is scalable with the number of requestors.
PS: Assume, the request and grant is asserted on the same cycle
I faced this issue before. As far as I know, there is no standard ways to verify round-robin arbiter. Depend on your specification, it would be from simple (using about 3 properties or something like that) to more complicated (I myself used a function with “global” variables).
This is my solution. Not necessarily the best one. Suggestions for improvements are welcome.
/*
Assume there are 3 requestors namely: A,B and C with reqA, reqB and reqC being the requests
and gntA, gntB and gntC being the grants.
Assumes the request and grant are on the same cycle
Similar sequence and assertions need to be replicated for each requestor. Can concatenate the requests and grants
into a bit vector, in order to save some redundant code
*/
//Denotes there is request and grant for the requestor A. Does not care about other requestors
logic requestorA_req_and_gnt;
//Denotes there is request and grant for requestor A and there is atleast one other requestor active
logic requestorA_req_and_gnt_with_other_requestors_active;
//There are requests other than requestor A
logic other_req_except_requestorA;
//There are grants other than requestor A
logic other_gnt_except_requestorA;
assign other_req_except_requestorA = reqB | reqC; //High when any one of the other requestor's are active
assign other_gnt_except_requestorA = gntB | gntC;
assign requestorA_req_and_gnt = reqA & gntA;
assign requestorA_req_and_gnt_with_other_requestors_active = reqA && other_req_except_requestorA && gntA;
//-----------------------------------------------------------------------------------------------------------------------------------------------
// Covers the case where there is request and grant on one cycle for requestorA, followed by no other requests. And then few cycles later there
// are multiple requests(reqA and atleast one other request). In this case, requestorA should NOT be granted again
//-----------------------------------------------------------------------------------------------------------------------------------------------
sequence requestorA_req_and_gnt_followed_by_other_req_seq;
requestorA_req_and_gnt ##0 (!other_req_except_requestorA)[*1:$] ##1 reqA && other_req_except_requestorA;
endsequence
//-----------------------------------------------------------------------------------------------------------------------------------------------
//Covers the case where there are more than one requestor active(reqA and any one of the other requests) followed by cycles of no other request at all
// and again followed by more than one requestor active. First time during multiple requests, reqA is granted, so, the second time when multiple
// requests are active, gntA should not be asserted again, and one of the other requests should be granted
//-----------------------------------------------------------------------------------------------------------------------------------------------
sequence multiple_requests_with_requestorA_req_and_gnt_followed_by_other_req_seq;
requestorA_req_and_gnt_with_other_requestors_active ##1 (!other_req_except_requestorA)[*0:$] ##1 reqA && other_req_except_requestorA;
endsequence
//-----------------------------------------------------------------------------------------------------------------------------------------------
//Covers the case where there are multiple requestors active in one cycle and next cycle may or may not have reqA, but will have other requests.
// If reqA is granted in the previous cycle, it should not be granted again in the next cycle, rather other requestor should be granted
//-----------------------------------------------------------------------------------------------------------------------------------------------
sequence back_to_back_multiple_requests_active_with_requestorA_gnted_followed_by_other_req_seq;
requestorA_req_and_gnt_with_other_requestors_active ##1 other_req_except_requestorA;
endsequence
//-----------------------------------------------------------------------------------------------------------------------------------------------
//Assertion to check if reqA do not hog the round robin arbiter
//-----------------------------------------------------------------------------------------------------------------------------------------------
assert_fairness_wrt_requestorA: assert property( @(posedge clk) disable iff(!resetn)
(requestorA_req_and_gnt_followed_by_other_req_and_no_bts_seq or
multiple_requests_with_requestorA_req_and_gnt_followed_by_other_req_and_no_bts_seq or
back_to_back_multiple_requests_active_with_requestorA_gnted_followed_by_other_req_and_no_bts_seq
) |-> other_gnt_except_requestorA && !gntA
)
`uvm_info("ARB_ASSERT",$sformatf("Requestor A was previously granted, and not granted again, round robin scheme followed!"),UVM_LOW)
else
`uvm_error("ARB_ASSERT_ERR",$sformatf("Requestor A was previously granted, and gets granted again, round robin scheme not followed"))
I think this is not a scalable solution. In my case, there were 16 requestors. Here was my approach:
1 - Assume that req[15:0] and gnt[15:0] is vector of request and grant signals.
2 - Check these properties:
a - $onehot0(gnt)
b - gnt [i] |-> req [i] in which i was generated by “generate” statement from 0 to 15 for all requestors.
c - Developed a function called rr_scheme in which updated the “pivot” (if req[i] & gnt[i] then pivot = i) and returned the expected gnt vector (in my case, expected gnt = the very first req[i] with i > pivot or very first req[i] from req[0] if there was no req[i] with i > pivot). The last assertion compared gnt with rr_scheme returned.
I have used following code to verify round robin arbitrator using SystemVerilog Assertions, can anyone of you correct me if I’m wrong, or kindly share if you have an efficient code than the following, thank you!!
I’m particularly looking for a long/lengthy chain of requests/grant
here gnt = Grant of length 16
req = Request of length 16
generate
for (genvar i = 0; i<16; i++)
for (genvar j=i+1; j!=i; j++)
begin
if(j==16)
j=0;
assert property
(
@posedge clk
(gnt[i] && req[j]) |=> (gnt[j] && !req[i])
)
end
endgenerate
// Below code is to make sure only one gnt is high at any point of time
assert property
(
@posedge (clk)
$onehot(gnt) ==1;
)
If you wanted to formally verify a rr arbiter with any number of requestors, then you don’t need to model it like above.
Instead, you can define ‘fairness’ across any 2 requestors. You let the fv tool choose any 2 random requestors. Intuitively I feel that any fairness bug can be reproduced by a failing trace using 2 requestors. So my simple-minded solution would be to use the assertion as described by Harry Foster