Dear all,
I am new to UVM and I am now in the process of producing a simple yet complete example of a small RAM. For the UVM part I would like to randomly generate Write or Read requests (either one or the other) with random address and data, spaced one another by a random amount of time. Everything’s good except that I always experience Writes only, never Reads.
The sequence item class is:
class mem_sequence_item extends uvm_sequence_item;
rand bit [6:0] addr;
rand bit wr_en;
rand bit rd_en;
rand bit [7:0] wdata;
bit [7:0] rdata;
// Write and Read constraints
constraint write_read_c {
// Either Write or Read
wr_en != rd_en;
// Address and Data (for Writes) are cleared out when operation is not selected
if(wr_en == 1'b0)
wdata == 0;
}
`uvm_object_utils(mem_sequence_item)
function new(string name = "mem_sequence_item");
super.new(name);
endfunction
endclass
What am I missing? Shall I configure something additional in the environment? Are the constraints wrong?
Do an exercise for yourself and try to figure out all the possible results you could get from calling randomize() that satisfy the constraints, then read the link in my answer. Or do it in the reverse order.
In reply to scorbetta:
Do an exercise for yourself and try to figure out all the possible results you could get from calling randomize() that stratify the constraints, then read the link in my answer. Or do it in the reverse order.
What kind of answer is this? Don’t you think I have already tried to find the possible solutions and, maybe, there’s something I am missing since it does not match your results?
In reply to scorbetta:
Then tell me how many possible solutions do you think there are for just wr_em and wr_data? If you disagree with my answer of 256, and don’t understand how it was calculated from the link I gave you (or the LRM), then I don’t know how to help you.
The if-constraint is bidirectional. There are 256 possible values for wdata. Since only one of the 256 possible values is wdata==0, there is only a 1/256 chance that wr_en will be 0.
Try this:
constraint write_read_c {
// Either Write or Read
wr_en != rd_en;
// Address and Data (for Writes) are cleared out when operation is not selected
if(wr_en == 1'b0)
wdata == 0;
solve wr_en before wdata;
}
Aside wr_en and wr_data there are rd_en and addr. So why don’t I have to consider them as well?
Considering the width of each of those signals, you have ~128k different samples in the space (product of those width). For half of them wr_en is 1’b1 and rd_en is 1’b-. For a fourth wr_en is 1’b1 and rd_en is 1’b0. Solutions are when wr_en is 1’b1 and rd_en is 1’b0 or viceversa. No operation at all or concurrent operations are not permitted, thus ~64k solutions. The same as saying that for wr_en=1’b1 and rd_en=1’b0 there are 256*128 different cases.
So, where is the error in reasoning? What am I missing?
The if-constraint is bidirectional. There are 256 possible values for wdata. Since only one of the 256 possible values is wdata==0, there is only a 1/256 chance that wr_en will be 0.
Try this:
constraint write_read_c {
// Either Write or Read
wr_en != rd_en;
// Address and Data (for Writes) are cleared out when operation is not selected
if(wr_en == 1'b0)
wdata == 0;
solve wr_en before wdata;
}
this indeed solves my problem. So, using solve/before is always the way to go in such cases, is it?
In reply to scorbetta:
Yes. That’s what solve-before is for. Please read the link that Dave suggested above, as well as the additional page linked from there.