Making multiple constraint testbench on SystemVerilog

Hi,

I am trying to make a simple testbench where I create a class that takes a 32-bit address constrainted to all zeroes and then constraint the first 7 bits to 0110011.

This was my attempt:

class bit32_address;
  rand bit [31:0] addr;
  
  constraint all_zero {addr inside {0};}
  constraint setADD {addr[6:0] == 7'b0110011;}
  endclass  : bit32_address

Now when I use this class, terminal would say the following:

Error-[CNST-CIF] Constraints inconsistency failure
  Constraints are inconsistent and cannot be solved.
  Please check the inconsistent constraints being printed above and rewrite 
  them.

Is there a way I could use multiple constraint blocks? Or is one constraint block optimal?

Actually I fixed the problem - I made a task that helps me designate how much bits I would like to be constrained. Then once I randomize the entire 32 bits of address, I then concatenate parts of the 32-bit address with the designated bits that I have “set” beforehand in the constrained block using the task I have made.

Just have another question though, why doesnt the terminal recognize both constraint block statements, but instead only recognize one?

By default, both constraint blocks are active. The problem is that the 2 constraints conflict with each other for some bits of address.

For example, consider bit address[0]. The all_zero constraint tells the simulator to set this bit to 0. The setADD constraint tells the simulator to set this bit to 1. This is a conflict, and the simulator correctly generates an error message.

1 Like

A constraint block contains a set of constraint expressions. A class may contain zero or more constraint blocks. All of the constraint expressions get treated as if they are logically ANDed together.

The purpose of having multiple constraint blocks is so you can control them as a group with block_name.constraint_mode() to turn them on or off, or override them when you extend the class.

It is possible to do what you are looking for with a soft constraint. A soft constraint turns itself off when faced with a conflict.

class A;
   rand bit [31:0] addr;
  constraint all_zero {
   foreach(addr[i]) soft addr[i] == 0;
  }
  constraint setADD {addr[6:0] == 7'b0110011;}
endclass

Note that I had to apply an individual soft constraint on each bit of addr. If had soft addr == 0, then the entire constraint would be turned off by the setADD constraint conflict. The upper bits would become random.

1 Like

Hi Dave,

I managed to produce the results I wanted using task within my Class block as the following:

class bit32_address;
  rand bit [31:0] addr;
  logic [6:0] opcode, last_7bit;
  logic [2:0] funct3;

  task hardcode (logic[2:0] funct3_type, logic[6:0]opcode_in, logic[6:0] last_7);
    funct3 = funct3_type;
    opcode = opcode_in;
    last_7bit = last_7;

  endtask

  constraint set_addr {addr[6:0] == opcode;
                       addr[14:12] == funct3;
                       addr[31:25] == last_7bit;}

  endclass  : bit32_address

This allowed me to produce the result I want, and I was wondering if this is also an alternative to your method of using soft constraints.

Thank you!

With the code you just showed, addr [31:25], [14:12], and [6:0] are never randomized, regardless of calling hardcode() They always get the current values stored in opcode, funct3, last_7bit. If you have a more complex set of constraints with different fields you want set, this strategy will not work. Otherwise, why not just set the addr fields you want after calling randomize()

BTW, use functions, not tasks for routines that do not consume time (have no blocking delays).

Hi Dave,

Thank you for suggesting the idea of using functions. Really did make a difference here.

Just another question, what do you mean by “more complex set of constraints with different fields?”

Thanks,

Sangwoo

I wouldn’t worry about it if it doesn’t make sense. I’m am not sure I know everything you are trying to do.

1 Like

Thank you so much Dave!