I am trying to write constraint for generating sequence for a given say ‘n’ AXI transactions with same burst size and burst length. However consecutive generated AXI transaction addresses needs to be sequential only i.e.
transaction1 start address should follow transaction0 end address …
transaction2 start address should follow transaction1 end address …
…
transactionN start address should follow transactionN-1 end address …
To achieve same I have written following, which does work correctly. But with higher values of ‘n’ is causing either simulation running long or constraint solver hanging.
class tr_gen;
rand bit[1:0] bsz;
rand bit[31:0] s_addr[$];
rand bit[31:0] e_addr[$];
rand bit[2:0] bl;
bit[31:0] addr_4KB_msk = ~((32'('h1) << 12)-1);
rand bit[5:0] num;
constraint c_tr_n {
s_addr.size() == (num+1); // number of transactions
e_addr.size() == s_addr.size();
}
constraint c_s_addrs {
foreach(s_addr[it]) if(it>0) {
s_addr[it] == s_addr[it-1]+((bl+1)*(2**bsz)); // consecutive start addr = addr + total num bytes in transasction
}
}
constraint c_e_addrs {
foreach(e_addr[it]) if(it>0) {
e_addr[it] == e_addr[it-1]+((bl+1)*(2**bsz)-1); // end addr = start addr + total num bytes in transaction - 1
}
}
constraint c_4kb_boundary {
foreach(s_addr[it]) {
(s_addr[it] & addr_4KB_msk) == (e_addr[it] & addr_4KB_msk); // for every transaction ensure 4kb boundary
}
}
constraint c_s_addr_byte_align {
foreach(s_addr[it]) {
bsz == 1 -> s_addr[it][0:0] = 0; // 2 byte
bsz == 2 -> s_addr[it][1:0] = 0; // 4 byte
bsz == 3 -> s_addr[it][2:0] = 0; // 8 byte
}
}
endclass
module try;
initial begin
tr_gen tr;
tr = new();
void'(tr.randomize() with {
num == 5;
});
// use tr
end
endmodule
For higher values of num, simulator is hanging. Any suggestions to make it more optimized or simulator friendly?
I was able to get a result for num == 63, which is the largest possible value, for all simulators on EDAPlayground. I noticed you had some typos (= instead of ==), so maybe you did not copy the example correctly and missed something. Or maybe you have hit a tool specific issue. Some comments for optimizations:
Use dynamic arrays instead of queues [$] for quicker access unless you plan on pushing or popping values.
You only need to check s_addr[0] for byte alignment.
You could calculate bsz, bl, and the array sizes in pre_randomize to simplify the constraint equations.
You could calculate e_addr in post_randomize to simplify the constraint equations.
In reply to dave_59:
Thanks Dave, without above suggestions, especially using dynamic array instead of queues has improved performance a lot.
Also since end address we were only using to calculate for 4kb boundary, so removed it altogether.
However considering for me num value is in range of close to more than 'd3000+ so still seeing some hangs on max values.
One trivial query:
You could calculate bsz, bl, and the array sizes in pre_randomize to simplify the constraint equations.
By this you meant that in pre_randomize() following needs to be done :
class tr_gen;
rand bit[1:0] bsz;
rand bit[31:0] s_addr[];
rand bit[2:0] bl;
bit[31:0] addr_4KB_msk = ~((32'('h1) << 12)-1);
rand bit[5:0] num;
constraint c_tr_n {
s_addr.size() == (num+1); // number of transactions
}
constraint c_s_addrs {
foreach(s_addr[it]) if(it>0) {
s_addr[it] == s_addr[it-1]+((bl+1)*(2**bsz)); // consecutive start addr = addr + total num bytes in transasction
}
}
constraint c_4kb_boundary {
foreach(s_addr[it]) {
(s_addr[it] & addr_4KB_msk) == (s_addr[it]+((bl+1)*(2**bsz)-1)) & addr_4KB_msk); // for every transaction ensure 4kb boundary
}
}
// constraint only s_addr[0]
constraint c_s_addr_byte_align {
bsz == 1 -> s_addr[0][0:0] == 0; // 2 byte
bsz == 2 -> s_addr[0][1:0] == 0; // 4 byte
bsz == 3 -> s_addr[0][2:0] == 0; // 8 byte
}
function void pre_randomize();
randomize(bsz,bl); // randomize
bsz.rand_mode(0); // no further randomize required for bsz
bl.rand_mode(0); // no further randomize required for bl
// num is passed as inline constraint will reflect here ?
s_addr = new [num+1];
c_tr_n.constraint_mode(0); // no further constraint required
endfunction
endclass
module try;
initial begin
tr_gen tr;
tr = new();
void'(tr.randomize() with {
num == 5;
});
// use tr
end
endmodule
You could do that although it’s probably easier declaring bsz and bl as non-rand, then calling std::randomize(bsz,bl). That way you don’t have to deal with rand_mode/constraint_mode.