Weighted Round Robin Arbiter Verification

Hello,

What is the best way to verify a Weighted Round Robin Arbiter ?
There are 3 Requests and 3 Grants
Req0, Req1, Req2 with weights 50, 30, 20 ( Higher the weights means more priority )
Gnt0, Gnt1, Gnt2

What is the best method to Verify this scenario.

Is it by Assertions ?
Is it by using a Reference Model

How will the Testbench/Test verify that the Weighted Round Robin Arbiter
followed the weights priority?

Assertion can check only if Grant is asserted after a Request go high.

Thanks
JeffD

This is a complex case for SVA assertions. I recommend that you do something like what I explained in my paper SVA Alternative for Complex Assertions
Verification Horizons - March 2018 Issue | Verification Academy

Below is an attempt at my understanding of your requirements, and an incomplete solution (needs to be tuned, definitely). Here I am assuming this algorithm
if($countones({req0, req1, req2}) ==1) then provide grant to requester
If multiple requests, if req0, I keep on granting to req0 unltil I exhaust the maximum number of requests (i.e., the weight). I use max0, max1, max2 variables to keep track of when that max is reached.
// else if(!max0) then grant0 and ++wgt0
// else if(!max1) then grant1 and ++wgt1
// else if(!max2) then grant2 and ++wgt2
// else max1=1, max2=0, max3=0 and grant
I use a task that is forked at every cycle, thus each task has a life of its own, just like a concurrent assertion. Try to follow my code, and if you have any questions let me know. Note that I did not necessarily cover all the conditions, but this start should get you thinking at a possible solution that meet your specific needs.


// Weighted Round Robin Arbiter ?
// There are 3 requests and 3 Grants

import uvm_pkg::*; `include "uvm_macros.svh" 
module top; 
  bit clk, req0, req1, req2; //with weights 50, 30, 20  
  bit gnt0, gnt1, gnt2, max0, max1, max2; 
  bit[2:0] wgt0, wgt1, wgt2;  
  let MAXWGT0=3'b101; let MAXWGT1=3'b100; let MAXWGT2=3'b010;
  // Assuming this algorithm 
  // if($countones({req0, req1, req2}) ==1) then provide grant to requester
  // else if(!max0) then grant0 and ++wgt0
  // else if(!max1) then grant1 and ++wgt1
  // else if(!max2) then grant2 and ++wgt2
  // else max1=1, max2=0, max3=0 and grant1 
  
  default clocking @(posedge clk); endclocking
    initial forever #10 clk=!clk;   
    
    task automatic t_reqgrnt();
      if($countones({req0, req1, req2}) ==1) begin : rq000
        // provide grant to requester at next cycle
        @ (posedge clk); // at next cycle 
        // could not use concurrent assertions because 
        // Concurrent assertions are not allowed in tasks/class methods
        ap1_rq0: assert (gnt0 && $past(req0, 1, 1, @ (posedge clk)));  
        ap1_rq1: assert (gnt1 && $past(req1, 1, 1, @ (posedge clk))); 
        ap1_rq2: assert (gnt2 && $past(req2, 1, 1, @ (posedge clk))); 
      end : rq000
      //more than one request 
      else if(req0 && !max0) begin : gnt0_only// grant1 and ++wgt0)
        // req0 has higher priority, did not exhaust its percentage
        wgt0 <= wgt0 + 1'b1; 
        if(max0==MAXWGT0) max0 <= 1'b1;
        @ (posedge clk); // at next cycle 
        ap_gnt0_only: assert (gnt0 && !gnt1 && !gnt2);        
      end : gnt0_only
      //
      else if(req1 && !max1) begin : gnt1_only// grant1 and ++wgt1)
        // req1 has higher priority, did not exhaust its percentage, req1 did
        wgt1 <= wgt1 + 1'b1; 
        if(max1==MAXWGT1) max1 <= 1'b1;
        @ (posedge clk); // at next cycle 
        ap_gnt1_only: assert (gnt1 && !gnt0 && !gnt2);         
      end : gnt1_only
      //
      else if(req2 && !max2) begin : gnt2_only// grant2 and ++wgt)
        // req1 has higher priority, did not exhaust its percentage, req1 did
        wgt2 <= wgt2 + 1'b1; 
        if(max2==MAXWGT2) max2 <= 1'b1;
        @ (posedge clk); // at next cycle 
        ap_gnt2_only: assert (gnt2 && !gnt0 && !gnt1); 
      end : gnt2_only
      //       
      else  begin : allmaxed // max1=1, max2=0, max3=0 and grant1  
        // MISSING cases, check the algorithm 
        wgt0 <= 3'b001; // grant to gnt1
        wgt1 <= 3'b000;
        wgt2 <= 3'b000; 
        @ (posedge clk); // at next cycle 
        ap_gnt0_at_allmax: assert (gnt0 && !gnt1 && !gnt2);        
      end : allmaxed
    endtask : t_reqgrnt
    
    always_ff @(posedge clk) begin // emulate the assertion firing
      fork
        t_reqgrnt();
      join_none
    end
    
    initial begin // a testbench 
      repeat(200) begin 
        @(posedge clk);   
        if (!randomize(req0, req1, req2)  with 
        {req0 dist {1'b1:=1, 1'b0:=1};
         req1 dist {1'b1:=1, 1'b0:=1};
         req2 dist {1'b1:=1, 1'b0:=1};
      }) `uvm_error("MYERR", "This is a randomize error")
    end 
    $finish; 
  end 
endmodule   

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


  1. SVA Alternative for Complex Assertions
    Verification Horizons - March 2018 Issue | Verification Academy
  2. SVA: Package for dynamic and range delays and repeats | Verification Academy
  3. SVA in a UVM Class-based Environment
    SVA in a UVM Class-based Environment | Verification Horizons | Verification Academy

Hi Ben,

Thank you very much for your detailed reply.
I have another question on the variation of this problem.
Assume we have a 3 input port and 1 output port Switch.
3 inputs ports are giving weights Input1 ( Weight 50 ),
Input2 ( Weight 30 ) and Input3 ( Weight 20 ). Each of the input
ports can drive a total of 100GBs traffic. Maximum output port
traffic can only be 100 GBs. How will we Verify that the 100GBs
maximum output traffic is distributed based on Weights of Input ports

We cannot use Assertions in this scenario.

  1. If we take a Window of 1 second, there should be 50MB from port1,
    30 MB from port2 and 20MB from port3 distributed based on the Weights
  2. How will you make sure , it was equally distributed, each 0.1 seconds
    If you take a window of 1 second, it can be that first 0.5 seconds,
    full traffic was from port1, next 0.3 seconds, full traffic was from
    port2 and remaining 0.2 seconds traffic was from Port3
    This is a Error scenario
    Because if we take a window of first 0.5 seconds, the Weights
    are not being taken care

Which is the best Verification Strategy to verify this scenario.

Please help

Thansk
JeffD

In reply to dvuvmsv:
In reply to dvuvmsv:
[b]In reply to dvuvmsv:

Quote:
// How will you make sure , it was equally distributed, each 0.1 seconds
// If you take a window of 1 second, it can be that first 0.5 seconds,
// full traffic was from port1, next 0.3 seconds, full traffic was from
// port2 and remaining 0.2 seconds traffic was from Port3

As you expressed, probabilities need to be measured over several samplings, and the larger the samplings, the better the measurement of the probabilities.
For each port that is enabled to drive the single output port, there is an enable (or grant) for it. Assuming that you want to measure these probabilities increment of T cycles representing 1 second, you could gather those statistics in counters and then compute the ratios of the counts for each of the grants. Thus, you could do something like the following:


  int window;
  real count0, count1, count2; // for the collection of statistics
  let MAXWGT0=3'b101; let MAXWGT1=3'b100; let MAXWGT2=3'b010;
  let T = 1000; // 1000 cycles take 1 second
  // For greater resolution, use a larger number for T, i.e., more samplings
  initial begin  : the_init
    automatic real sum; 
    forever begin : the_forever
      while (window <= T) begin  : the_while 
        @(posedge clk) if(gnt0)  count0 += 1'b1; 
        if(gnt1)  count1 += 1'b1;
        if(gnt2)  count2 += 1'b1;
        window += 1'b1; 
      end : the_while
      // Collected 1000 samplings, now check stats
      // resets counts or let count increment for more samplings. 
      // weights 50 30 20 
      sum=count0+count1+count2; 
      a_stat0: assert (count0/sum < 0.505 && count0/sum > 0.495); // 50%
      a_stat1: assert (count1/sum < 0.305 && count1/sum > 0.295); // 30%
      a_stat2: assert (count2/sum < 0.205 && count2/sum > 0.195); // 20% 
      window = 0; 
      // reset the counts if needed
    end : the_forever
  end  : the_init
 

the complete model I have is below. Note the addition of
if($countones({req0, req1, req2}) ==0) return; // <— NEW


// Weighted Round Robin Arbiter ?
// There are 3 requests and 3 Grants

import uvm_pkg::*; `include "uvm_macros.svh" 
module top; 
  bit clk, req0, req1, req2; //with weights 50, 30, 20  
  bit gnt0, gnt1, gnt2, max0, max1, max2; 
  bit[2:0] wgt0, wgt1, wgt2;  
  int window;
  real count0, count1, count2; // for the collection of statistics
  let MAXWGT0=3'b101; let MAXWGT1=3'b100; let MAXWGT2=3'b010;
  let T = 1000; // 1000 cycles take 1 second
  // For greater resolution, use a larger number for T, i.e., more samplings

  // Assuming this algorithm 
  // if($countones({req0, req1, req2}) ==1) then provide grant to requester
  // else if(!max0) then grant0 and ++wgt0
  // else if(!max1) then grant1 and ++wgt1
  // else if(!max2) then grant2 and ++wgt2
  // else max1=1, max2=0, max3=0 and grant1 
  
  default clocking @(posedge clk); endclocking
    initial forever #10 clk=!clk;   

  // How will you make sure , it was equally distributed, each 0.1 seconds
  // If you take a window of 1 second, it can be that first 0.5 seconds,
  // full traffic was from port1, next 0.3 seconds, full traffic was from
  // port2 and remaining 0.2 seconds traffic was from Port3
  initial begin  : the_init
    automatic real sum; 
    forever begin : the_forever
      while (window <= T) begin  : the_while 
        @(posedge clk) if(gnt0)  count0 += 1'b1; 
        if(gnt1)  count1 += 1'b1;
        if(gnt2)  count2 += 1'b1;
        window += 1'b1; 
      end : the_while
      // Collected 1000 samplings, now check stats
      // resets counts or let count increment for more samplings. 
      // weights 50 30 20 
      sum=count0+count1+count2; 
      a_stat0: assert (count0/sum < 0.505 && count0/sum > 0.495); // 50%
      a_stat1: assert (count1/sum < 0.305 && count1/sum > 0.295); // 30%
      a_stat2: assert (count2/sum < 0.205 && count2/sum > 0.195); // 20% 
      window = 0; 
      // reset the counts if needed
    end : the_forever
  end  : the_init
    
    task automatic t_reqgrnt();
      if($countones({req0, req1, req2}) ==0) return;  // <--- NEW 
      if($countones({req0, req1, req2}) ==1) begin : rq000
        // provide grant to requester at next cycle
        @ (posedge clk); // at next cycle 
        // could not use concurrent assertions because 
        // Concurrent assertions are not allowed in tasks/class methods
        ap1_rq0: assert (gnt0 && $past(req0, 1, 1, @ (posedge clk)));  
        ap1_rq1: assert (gnt1 && $past(req1, 1, 1, @ (posedge clk))); 
        ap1_rq2: assert (gnt2 && $past(req2, 1, 1, @ (posedge clk))); 
      end : rq000
      //more than one request 
      else if(req0 && !max0) begin : gnt0_only// grant1 and ++wgt0)
        // req0 has higher priority, did not exhaust its percentage
        wgt0 <= wgt0 + 1'b1; 
        if(max0==MAXWGT0) max0 <= 1'b1;
        @ (posedge clk); // at next cycle 
        ap_gnt0_only: assert (gnt0 && !gnt1 && !gnt2);        
      end : gnt0_only
      //
      else if(req1 && !max1) begin : gnt1_only// grant1 and ++wgt1)
        // req1 has higher priority, did not exhaust its percentage, req1 did
        wgt1 <= wgt1 + 1'b1; 
        if(max1==MAXWGT1) max1 <= 1'b1;
        @ (posedge clk); // at next cycle 
        ap_gnt1_only: assert (gnt1 && !gnt0 && !gnt2);         
      end : gnt1_only
      //
      else if(req2 && !max2) begin : gnt2_only// grant2 and ++wgt)
        // req1 has higher priority, did not exhaust its percentage, req1 did
        wgt2 <= wgt2 + 1'b1; 
        if(max2==MAXWGT2) max2 <= 1'b1;
        @ (posedge clk); // at next cycle 
        ap_gnt2_only: assert (gnt2 && !gnt0 && !gnt1); 
      end : gnt2_only
      //       
      else  begin : allmaxed // max1=1, max2=0, max3=0 and grant1  
        // MISSING cases, check the algorithm 
        wgt0 <= 3'b001; // grant to gnt1
        wgt1 <= 3'b000;
        wgt2 <= 3'b000; 
        @ (posedge clk); // at next cycle 
        ap_gnt0_at_allmax: assert (gnt0 && !gnt1 && !gnt2);        
      end : allmaxed
    endtask : t_reqgrnt
    
    always_ff @(posedge clk) begin // emulate the assertion firing
      fork
        t_reqgrnt();
      join_none
    end
    
    initial begin 
      repeat(200) begin 
        @(posedge clk);   
        if (!randomize(req0, req1, req2)  with 
        {req0 dist {1'b1:=1, 1'b0:=1};
         req1 dist {1'b1:=1, 1'b0:=1};
         req2 dist {1'b1:=1, 1'b0:=1};
      }) `uvm_error("MYERR", "This is a randomize error")
    end 
    $finish; 
  end 
endmodule  
 

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


  1. SVA Alternative for Complex Assertions
    Verification Horizons - March 2018 Issue | Verification Academy
  2. SVA: Package for dynamic and range delays and repeats | Verification Academy
  3. SVA in a UVM Class-based Environment
    SVA in a UVM Class-based Environment | Verification Horizons | Verification Academy

Thank you Ben for your detailed reply
JeffD