Constraint for random Memory access

Hi,

I am trying to write e constraint to generate a memory transaction with

  1. First transaction always write
  2. read addr = write addr

Not sure what’s wrong with the below code.

class mem;
rand int addr;
rand int w_r; //w_r=0 write 
int q[$];

function void post_randomize();
    int sz;
    int idx;
    q.push_back(addr);
    sz = q.size();
    idx = $urandom_range(0, sz-1);
    if(sz==1)  w_r = 0;
    if(w_r==1) addr = q[idx]; //if read use addr from Q
endfunction
endclass

module test;

    mem a;

    initial begin
       a=new;
       repeat(20) begin
           a.randomize();
          $display("sz=%0d addr=%x w_r=%x", a.q.size(), a.addr, a.w_r);
       end
    end
endmodule

sz=1 addr=42530054 w_r=0
sz=2 addr=275f13e3 w_r=1
sz=3 addr=c04397e1 w_r=1
sz=4 addr=42530054 w_r=1
sz=5 addr=6a5d80c4 w_r=0
sz=6 addr=16331382 w_r=1
sz=7 addr=0365cf2e w_r=0
sz=8 addr=6a780b36 w_r=1
sz=9 addr=6a780b36 w_r=1
sz=10 addr=c04397e1 w_r=1
sz=11 addr=818a3c8f w_r=0
sz=12 addr=42530054 w_r=1
sz=13 addr=cfd4fbcc w_r=1
sz=14 addr=2720a7f2 w_r=0
sz=15 addr=6a5d80c4 w_r=1
sz=16 addr=a658a7c6 w_r=0
sz=17 addr=87c8507f w_r=0
sz=18 addr=9935adce w_r=0
sz=19 addr=2720a7f2 w_r=1
sz=20 addr=69ddeeb5 w_r=1

I dont see the exact output by running your code on EDA playground… but i have made some assumptions for your requirements. Below meets ur requirements.



class mem;
rand int addr;
int r_addr;  
rand bit w_r;//w_r=0 write 
bit temp=1;  
int q[$];
  
  
  
  constraint ab {temp != w_r;
                 w_r -> r_addr == addr;
                }
 
function void post_randomize();
    temp = w_r;
    r_addr = addr;
    
endfunction
endclass
 
module test;
 
    mem a;
 
    initial begin
       a=new;
       repeat(20) begin
           a.randomize();
          $display("sz=%0d addr=%x w_r=%x", a.q.size(), a.addr, a.w_r);
       end
    end
endmodule


The bug here is as follows : (using example values)

First attempt. : addr = 1234, w_r = 0, q = {1234}, sz = 1, idx = 0,
Second attempt : addr = 5678, w_r = 1, q = {1234, 5678}, sz = 2, idx = either 0 or 1

Because your idx can be 0 or 1, you are not quaranteeing that it is indeed address that has already been written into.

I would simplify the code to the below :


class mem;
  rand int addr;
  rand bit w_r; //w_r=0 write 
  int write_addr_q[$];
  
  constraint w_r_cons {(write_addr_q.size()==0) -> (w_r == 0) ;};
  constraint read_addr_cons { (w_r == 1)  -> (addr inside {write_addr_q}); } ;
 
              
  function void post_randomize();
    if(w_r == 0) write_addr_q.push_back(addr);
  endfunction
  
endclass

Note : running this on edaplayground’s ncsim gave me all w_r = 0. But vcs gave me both 0’s and 1’s.

In reply to KillSteal:

Thanks @KillSteal
I could see the problem you mentioned with ncsim.
The problem is with “read_addr_cons” not sure what tough.
I did that in post_randomization and it looks good. Not sure if that’s the optimized way.

class mem;
rand int addr;
rand int w_r; //w_r=0 write 
int q[$];

constraint w_r_cons {(write_addr_q.size()==0) -> (w_r == 0) ;};

function void post_randomize();
    int sz;
    int idx;
    q.push_back(addr);
    sz = q.size();
    idx = $urandom_range(0, sz-1);
    //if(sz==1)  w_r = 0;
    if(w_r==1) addr = q[idx]; //if read use addr from Q
endfunction
endclass
 
module test;
 
    mem a;
 
    initial begin
       a=new;
       repeat(20) begin
           a.randomize();
          $display("sz=%0d addr=%x w_r=%x", a.q.size(), a.addr, a.w_r);
       end
    end
endmodule