Generating random values in increasing order

I was working on an academic project and designing a memory controller. The input to the controller is a file of CPU requests with 3 field, namely, address, operation(Read/write) and Arrival time.

I was trying to generate random values, The CPU arrival time is also random, however I want the CPU arrival times in the ascending order.
Attached below is the code for that and, address and opcodes are fine. However, Arrival time is not working.

Can someone please guide me through this:

module rand_test;
logic [31:0] address;
logic [3:0] opcode;
int unsigned arr_time;

int last_value = 0;
class intruction_rand;
	
	randc logic[31:0] r_address;

	randc logic[3:0] opcode;

	randc int at;

	constraint r_opcode {opcode inside { 4'b0000, 4'b0001};}

	//last_value = at;
	
endclass:intruction_rand


intruction_rand instruction;

initial
begin
      instruction=new();
	for(int i=0;i<1000;i++)
	begin
		assert(instruction.randomize());
		
		address = instruction.r_address;
		opcode = instruction.opcode;
		//arr_time = randomize with {arr_time > last_value;}; 

		arr_time = instruction.at;
		last_value = arr_time;
		$display ("add = %h, opcode = %h, arr_time = %d", address, opcode, arr_time);
	end
end
endmodule

In reply to Bhaskar44:

You probably want

	constraint r_delta {at > const'(at);}

More likely, you want

	constraint r_delta {at inside {[const'(at)+min_delta: const'(at)+max_delta]};}

where the deltas are to keep the arrival times within some range.

Also use
rand
instead of
randc
for very large random numbers. randc may be very costly.

In reply to dave_59:

Thanks a lot! It indeed works! I was never aware of the keyword const’…

Thanks for the reply, Dave. However, I couldn’t understand the mechanics of the construct “const’” and I am just curious to know how it helped arrive at the solution.

Could you please briefly explain how the const’ construct is used in this context? The LRM doesn’t give much explanation on the same.

Thanks and Regards,

In reply to kautilya87:
The LRM says

When casting an expression as a constant, the type of the expression to be cast shall pass through unchanged. The only effect is to treat the value as though it had been used to define a
const
variable of the type of the expression.

So SystemVerilog treats the expression as a constant, not as a random variable.

Hi Dave,
I was trying to randomize an integer variable for 10 iterations in ascending order using the constraint you mentioned in the post dated Nov 28th. Following is the code:

module top;
    class rand_ex;
        rand int unsigned b;
        constraint c1 {b > const'(b) ;}
    endclass
    rand_ex r1;
    initial begin
        r1 = new();
        for (int j=0; j<10; j++) begin
            assert (r1.randomize());
            $display ("Iteration_number:%0d b:%0d", j, r1.b);
        end 
    end
endmodule

I get this compilation error: Const cast for expressions is only supported in procedural assertions
Tool:Questasim

Your feedback on this would be much appreciated. Also please help me understand as to how does the constraint “b > const’(b)” imply variable b of the current iteration should be greater than in the previous iteration.
Thanks and Regards,

In reply to vinitk:
This forum is not for tool specific support, but you may have an older version. A “const” cast is a relatively new construct. Contact Mentor support directly for details.

Whenever you call randomize(), the constraint solver evaluates all the expressions using the constants and non-random values at the point of the call to randomize(). The random variables have their values from the previous call to randomize(), or any other direct assignment. They only get updated if randomize() succeeds; before calling post_randomize(). The const cast simply says to evaluate the expression as a constant value, so all it sees is the resulting value from the current state of the random variable, it does not see there was a random variable in the expression.

Thanks for the clarification Dave.

In reply to dave_59:

A couple of further comments:

  • Your original intent can be implemented easily using the post_randomize hook to save the most recent randomization value. Something like this:
int last_value=0; // or whatever your minimum should be
constraint ascending { at > last_value; }
function void post_randomize(); last_value = at; endfunction

post_randomize is called automatically just after each randomization, so it will capture the just-randomized value ready to use in the constraint for the next attempt.

  • Dave’s point about setting limits on the increment is important. Without it, you’ll get all the values bunched-up in the upper part of your available range, which is probably not what you want.
  • Many thanks to Dave for sharing a very elegant solution (which I haven’t seen mentioned elsewhere) for something I asked for years ago: the ability to use the current value of a rand variable as a state value in a constraint. Unfortunately, tool support for const-cast is very limited at present. I’m also just a little bit worried about Dave’s interpretation of the LRM here. It’s not at all obvious to me that the rule he quotes is sufficient to allow for the use of const-cast in a constraint. After all, you wouldn’t normally expect to be able to declare a variable within a constraint, and that’s effectively what const-cast does.

In reply to Jonathan Bromley:

But that is the definition of a cast in any context - i.e. as if being in the context of an assignment to a variable of the target type.

Does VCS need special switch to compile this code?
It is giving this error…

Error-[SE] Syntax error
Following verilog source has syntax error :
“…/sim_files/mdio/mdio_incr_sequence.sv”, 12: token is ‘const’
constraint r_delta { dev_addr > const’(dev_addr);}
^
SystemVerilog keyword ‘const’ is not expected to be used in this context.

In reply to SVaustin:
This forum is not for tool specific support, but you may have an older version. A “const” cast is a relatively new construct. Contact your tool vendor for help.

Hi Dave,

I want to generate data in incrementing/decrementing order only for particular cases in UVM,

So I can’t use this constraint in sequence_item, but only in some sequences.

So How can I achieve the same in sequences?

Hi,

I have done for incrementing order
`uvm_do_with(req,{foreach(data[i]) {data[i] == i+1;}})

but how to for decrementing order?

In reply to J_M:

Your questions are not very clear. You should ask this new question thread and give some examples of the values you are looking for that would meet the constraints you are trying to write.

Hi,

In my sequence_item class, I have fields like
rand [5:0] length
rand [7:0]data

now according to length data should be randomized for that I have used,
constraint data_length {data.size == length;}

but for a few scenarios only I have to generate in incrementing/decrementing order.

So in the sequence, I have used constraint like
`uvm_do_with(req,{foreach(data[i]) {data[i] == i+1;}}) // for incrementing order

So how can I achieve the same for decrementing order?


// descr:	This code shows a simple example of generating sequence of incrementing/decrementing/no-change/delta>1 values when randomizing

typedef enum bit [1:0] {NC = 0, INC = 1, DEC = 2, ERR = 3 } data_dist_e;

class a;  
  rand data_dist_e          data_dist;
  static bit unsigned [3:0] data_prev; // previous data stored as static for retaining prev value of 'data'
  bit unsigned [3:0] data;	// actual data of interest
  
  function new(string name = "");
  endfunction
  
  constraint data_dist_c {
    // define distribution of scenarios
    data_dist dist {
                    INC:/40,
                    DEC:/40,
                    ERR:/10,
                    NC:/10
                   };
  }

  function post_randomize();
    // determine the data based on the previously latched 'data_prev' 
    if (data_dist == INC) begin // incr
        data = data_prev + 1; 
    end else if (data_dist == DEC) begin // decr
        data = data_prev - 1; 
    end else if (data_dist == NC) begin // error
        data = data_prev;
    end else begin // if (data_dist == NC)// no change
      do begin 
        data = $urandom;
      end while (data != data_prev && data != data_prev+1 && data != data_prev-1);
    end 
    // actuallly store the data for next iter
    data_prev = data;

  endfunction : post_randomize

endclass