Randomization of req signal in priority arbiter

Hi All,

I have 4-bit request signal which is an input to priority arbiter.

Suppose the 1st call to randomize() results in 4’b0001 ( highest index set is bit 0 )

Next call to randomize must be a value greater than 4’b0001 with the lsb set ( as highest index set in previous call to randomize() was bit 0 )

Expected values would be :: 4’b0011 / 4’b0111 / 4’b0101 / 4’b1111 / 4’b1001 / 4’b1101 / 4’b1011

If the 2nd call to randomize() gives 4’b0011 ( highest index set is bit 1 ) then 3rd call should have bit position 1 set

Expected values would be :: 4’b111x / 4’b011x / 4’b101x ( where lsb could be 0 / 1 )

The max chain that one could have would be 4’b0001 → 4’b0011 → 4’b0111 → 4’b1111.

After it reaches max value of 4’b1111 ( or any value where bit 3 is set ) there should be no constraint in terms of highest bit position set

i.e we can have any value with $countones( req ) >= 1 in the next call to randomize()

rand bit [3:0] req;

constraint no_of_ones { $countones(req) >= 1 ; }

constraint successive_values { ( const'(req[3]) != 1 ) -> req > const'(req); }

However constraint successive_values doesn’t guarantee that the same bit position is set b/w consecutive calls

Eg: If previous call gives req as 4’b0001 ( bit 0 is set ) then next call could possibly give me 4’b1000 ( bit 0 isn’t set ).

Any suggestions ?

EDIT: A friend suggested a solution using non-random variable that stores the highest bit set in post_randomize() and within constraint we simply use

(const'(req[3]) != 1) -> (req > const'(req) ) && (req[ind] == 1) .

Although this works as per intention, both of us are now looking for a possible solution using purely constraints ( w/o using helper variable ) for practice purposes

Thanks

You can use pre_randomize() to calculate the position of the MSB from the previous value.

class A;
  rand bit[3:0] req;
  bit [3:0] prev_req;
  int msb;
  constraint c {
    req != '0; // must be non-zero
    msb < 3 -> {
      req > prev_req;
      req[msb] == '1; // msb of previous value must be set
    }
    // attempt at a "better" distribution of values
    1 dist { req==4'b0001 := 1, req[3:1]==3'b001 :=1, req[3:2]== 2'b01 :=1 , req[3]==1'b1 :=1 }; 
  }
  function void pre_randomize();
    // req must never be 0
    if (req==0) req = '1;
    for (int i = $bits(req)-1; i >= 0; i--)
      if (req[i]) begin
        msb = i;
        break;
      end
    prev_req = req;
  endfunction
endclass
module top;
  
  A h = new;
  initial repeat(20) begin
    assert(h.randomize());
    $display("%b %d", h.req, h.msb);
  end
endmodule

Apologies for editing my original post at the last moment Dave.

Would there exist a solution without using helper variable ?

Actually, I started my solution without using any helper variables, and found it less desirable. You can compare the two approaches to decide which one is more manageable for yourself

class A;
  rand bit[3:0] req;
  constraint c {
    req != '0; // must be non-zero
    fmsb(const'(req)) < 3 -> {
      req > const'(req);
      req[fmsb(const'(req))] == '1; // msb of previous value must be set
    }
    // attempt at a "better" distribution of values
    1 dist { req==4'b0001 := 1, req[3:1]==3'b001 :=1, req[3:2]== 2'b01 :=1 , req[3]==1'b1 :=1 }; 
  }
  function void pre_randomize();
    // req must never be 0
    if (req==0) req = '1;
  endfunction
  function int fmsb(type(req) x);
    // assume x is never 0
    for (int i = $bits(req)-1; i >= 0; i--)
      if (x[i]) return i;
  endfunction
endclass
module top;
  
  A h = new;
  initial repeat(20) begin
    assert(h.randomize());
    $display("%b %d", h.req, h.fmsb(h.req));
  end
endmodule
1 Like

When msb is 1 next randomization is any number but zero. I have used helper variable here. This is my approach

class req_txn;

rand bit [3:0] val;
bit [3:0] prev = 0;

constraint c1 {
if(prev[2])                (val[2]==1 && val[3]==1);
else if(prev[1])        (val[1] ==1 && (val[3] || val[2]));
else if(prev[0])        (val[0] ==1 && (val[3] || val[2] || val[1]));
}

constraint c2 { $countones(req) >=1; }

function void post_randomize;
   prev = val;
endfunction

endclass

Last line needs to be else if(prev[0]) (val[0] ==1 && (val[3] || val[2] || val[1]));

If the bit-width of val is large, then it would be difficult to use this logic

yes you are correct