Hello,
I want to write an assertion to check round robin behavior .
assume we have two require signals : req1 req2__ , and two grant signals : gnt1 , gnt2;
then if req1 and req2__ are high , and as a result gnt1__ is high , then next gnt1__ must occur after gnt2 __is up.
In reply to Jad:
For 2 signals, it is easy. However, if you have a large vector, you’ll need to add some supporting logic to keep track as to who next can get the grant if the req is asserted.
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[j]) // Edit: previous error has been correct here
)
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;
)
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;
)
Your approach in using the generate statement is good, but your implementation is incorrect. For a round robin, you need to add some supporting logic to keep track as to who next can get the grant if the req is asserted. For example, assume that req[4] got the grant. Now req[3] and req[7] both want the grant; who gets it? Next in line to get is #5, but req[5]==0.
Below is a link from my SVA book for an arbiter with 16 bit inputs where there could be multiple requests, but there is a single grant with bits of higher order having higher priority. http://systemverilog.us/arbiter_cohen.pdf
For your round robin model, you’ll need some supporting logic to hold which grant was previously granted. You may need some additional logic to predict which ones can get the next grant. Below is a model that I started (using 4 bits to ease the verification. It is not fully tested, and may not even do what you want. However, it may be a step in the right direction. Basically, it uses the previous grant along with an arbiter. You’ll need to do the verification. I provided test vectors using constrained-random tests. Let me know how this works for you.
import uvm_pkg::*; `include "uvm_macros.svh"
module top;
bit clk;
bit[3:0] req, gnt, prev_grnt;
default clocking @(posedge clk); endclocking
initial forever #10 clk=!clk;
generate for (genvar i=0; i<=4; i++)
begin
property p_arbiter;
bit[16:0] v;
(req[i]==1'b1, v=prev_grnt, v[i+1]=1'b1) ##0 req < v |->
gnt[i]==1'b1 ##0 $onehot(gnt);
endproperty : p_arbiter
ap_arbiter: assert property(@(posedge clk) p_arbiter);
end
endgenerate
ap_zero_req0: assert property(@(posedge clk) req==0 |-> gnt==0);
initial begin
repeat(200) begin
@(posedge clk);
if (!randomize(req, gnt, prev_grnt) with
{ req inside {0, 1, 2, 4}; // dist {1'b1:=1, 1'b0:=3};
gnt inside {0, 1, 2, 4}; // dist {1'b1:=1, 1'b0:=2};
prev_grnt inside {0, 1, 2, 4};
}) `uvm_error("MYERR", "This is a randomize error")
end
$finish;
end
endmodule
Hey Ben thanks for taking time to reply.
Just to make sure we both are in same page and understanding same. I still feel that my code works good for round robin.
To clarify any confusion in the problem, i will write it down below,
Problem statement:
Even though i have considered 16 variables in my solution for understanding purpose lets consider 4 variable round robin arbitrator,
A = req[0], B = req[1], C = req[2], D = req[3]
grant should be cyclic: A → B → C → D → A . . .
if all the request is preset then grant follows above order, if not then it will grant the next available request in the cyclic order i.e if C - request is absent then it will follow this order, A → B → D → A → . .
Here we also assume that we give only 1-grant clk tick to serve the request.
So for the above problem i feel my solution will work and i don’t think we need to keep a track of request and grant sequence in round-robin fashion.
In my solution, variable ‘i’ will keep a track of request in order and ‘j’ will track the grant, i don’t think we need to keep a track of previous grant in this case.
Please correct me if i’m missing out anything.
Or any good example in which my solution fails will be good to get a better solution and cover the corner cases
assert property
(
@posedge clk
(gnt[i] && req[j]) |=> (gnt[j] && !req[j]) // Sorry i had made a mistake !req[j] variable which i have corrected
)
In reply to vvv:
You have not compiled or run your model did you?
With your for (genvar i = 0; i<4; i++)
for (genvar j=i+1; j!=i; j++)
I got error message like
** Error: roundrb.sv(23): (vopt-2134) Evaluation of a generate loop has exceeded the iteration limit of 100000.
# ** Note: roundrb.sv(23): (vopt-2129) Design elaboration has evaluated 100001 loop generated blocks....
To verify your model, get one that compiles and eleborates OK.
Use constrained-random tests to test a small dample, and check it out. Below is an example for a simple driver:
initial begin
repeat(200) begin
@(posedge clk);
if (!randomize(req, gnt, prev_grnt) with
{ req inside {0, 1, 2, 4}; // dist {1'b1:=1, 1'b0:=3};
gnt inside {0, 1, 2, 4}; // dist {1'b1:=1, 1'b0:=2};
prev_grnt inside {0, 1, 2, 4};
}) `uvm_error("MYERR", "This is a randomize error")
end
$finish;
end
endmodule
assign prev_grnt=gnt; // <---- NOTICE this per your assumptions
// generate ...
bit[16:0] v;
(req[i]==1'b1, v=prev_grnt, v[i+1]=1'b1) ##0 req < v |=>
gnt[i]==1'b1 ##0 $onehot(gnt);
This was derived from my model for an arbiter with 16 bit inputs where there could be multiple requests, but there is a single grant with bits of higher order having higher priority.
Since you are pressing me to explain my update for the round robin, my explanation below needs more analysis. It words for the arbiter in the book, which is not round robin, but works with priority based on the order of the bits. http://systemverilog.us/arbiter_cohen.pdf // from the book
To better understand this, consider some simple scenarios:
req==4'b0111 (i.e., req==7), gnt==prev_grnt==0001
**[3] for the gen of req[3], v=prev_grnt=0001, v[i+1] i.e., v[4]==1; thus v=10001 (i.e., v==17).
req[3]==0, so assertion is vacuous, req(which is==7) < 17 is true, but req[3]==0
**[2] for the gen of req[2], v=prev_grnt=0001, v[i+1] i.e., v[3]==1; thus v=1001 (i.e., v==9).
req(which is==7) < 9 is true, thus this assertion for req[2] is true, and gnt[2] must be true
** [1]for the gen of req[1], v=prev_grnt=0001, v[i+1] i.e., v[2]==1; thus v=0101 (i.e., v==5).
req(==7] < 5 is false, thus this assertion for req[1] is false, and gnt[1] must be 0
Basically, the v[i+1]is used to set the priority.
The fact that v is 16 bits is immaterial here.
The end condition might be problematic and needs to be considered.
@user49 came across this post today and am trying to understand your code. In case of a 2 signal round-robin arbiter, these are the following scenarios that would arise. Am I missing anything?
Only req[0] is high. req[1] is low. Then grnt[0] is set to high in the next cycle
Only req[1] is high. req[0] is low. Then grnt[1] is set to high in the next cycle
Both req[0] and req[1] are high. On the first occurrence, in the following cycle grnt[0] needs to set high and grnt[1] remains low. On the second occurrence, in the following cycle grnt[1] needs to set high and grnt[0] remains low. This round-robin pattern needs to be followed.
Neither req[0] and req[1] are high. grnt[0] and grnt[1] remain low too.
Is your code (pasting it below) covering all of these scenarios?