Mutual exclusive (random) Write or Read requests

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?

Many thanks for your help
Kind regards

Simone

In reply to scorbetta:

I’m seeing that wr_en is almost always true. That’s because there are 256 solutions where wr_en is true, and only one solution for wr_en to be false.

See Randomization result with and without (solve x before y) | Verification Academy

In reply to dave_59:

Implementing a mutual exclusive access would be useful if you have a WR- and a RD agent. Then you have to make sure only 1 agent is accessing the DUT.

In reply to dave_59:

In reply to scorbetta:
I’m seeing that wr_en is almost always true. That’s because there are 256 solutions where wr_en is true, and only one solution for wr_en to be false.
See Randomization result with and without (solve x before y) - SystemVerilog - Verification Academy

@dave_59
How did you conclude that there are 256 solutions where we_e is true? What do you mean? Does this mean the above constraint does not work?

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 satisfy the constraints, then read the link in my answer. Or do it in the reverse order.

In reply to dave_59:

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;
   }

In reply to dave_59:

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?

In reply to tfitz:

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.