Reputation: 445
Please help to resolve one randomization-constraint related issue that I am facing.
So in my seqItem, I have a write_addr
random variable. This variable controls the location in memory where the data should be written.
I want to implement different writing address changing modes like random-address, given range address, ascending and descending type.
I have params_pkg, where user defines the address change type and my TB generates write_addr values correspondingly.
I was thinking to implement this using constraints, like by enableing/disabling the constrains get the required behavioral:
class seqItem extends uvm_sequence_item;
`uvm_object_param_utils(seqItem)
randc logic [541-1:515] wfifo_addr;
if (params_pkg::writeAddressType == "WriteGivenRangeAddress") begin
constraint wArrdGivnRangCnstr {
this.wfifo_addr inside {[params_pkg::addrLowValue:params_pkg::addrHighValue]};
}
end
function new (string name="seqItem");
super.new(name);
this.wArrdGivnRangCnstr.constraint_mode(0);
endfunction
endclass
However there is no way to generate ascending or descending address values using constraints. Because to have ascending address, the seqitem code needs to know the write_addr
variable value from the previous randomization, which I could not implement.
My question is: whether it is possible to have ascending write_addr
values using constraints?
And second, the example code that I posted is not working, simulator gives error saying that generate constraints are not allowed. Most probably this is something not supported in System Verilog. Am I right?
Upvotes: 1
Views: 3737
Reputation: 13987
One solution to your problem of changing randomisation modes, is to turn constraints on and off:
You can turn a constraint off using the implicit constraint_mode
method:
s.wArrdGivnRangCnstr.constraint_mode(0);
and then turn it on again:
s.wArrdGivnRangCnstr.constraint_mode(1);
(where s is a reference to your seqItem
class). You can't put constraints inside an if
statement as your error message demonstrates.
Upvotes: 0
Reputation: 7755
Second part first: I suspect "Generate constraints" are constraints contained within a generate
block. Generate blocks are only allowed within modules
, programs
, and checkers
not classes, hence "Generate constraints" are illegal (although the term is oddly specific. I'd expect an error saying "Generates are not allowed in classes"). You can rewrite your constraints by moving the conditional inside the constraint block:
constraint wArrdGivnRangCnstr {
if (params_pkg::writeAddressType == "WriteGivenRangeAddress") {
this.wfifo_addr inside {[params_pkg::addrLowValue:params_pkg::addrHighValue]
};
}
BTW: you might want to consider an enum
for the writeAddressType
variable. That way typos are caught at compile time.
Another thing...
You have your random variable defined as randc
.
Variables declared with the randc keyword are random-cyclic variables that cycle through all the values in a random permutation of their declared range.
If you limit the range on a randc
variable, it can't "cycle through all the values...of [it's] declared range". It's not clear from the SystemVerilog LRM what will happen here, but I suspect that once all the values between low and high are exhausted randomisation will fail.
Also, the variable is 26-bits in size. That's 67,108,864 different values you're asking the simulator to keep track of to see if they've been used before. It will need 8MB of flags just for this one variable.
I expect what you really want here is to define the variable as rand
and not randc
.
On to your main question...
You are right, you need some kind of storage of the last value in order to get incrementing values, and because this is a sequence item I suspect that you're creating a new instance each time, hence we can't store the last value in an instance variable as all instance variables are destroyed.
So there's two options:
Store the last value in a static instance variable.
class seqItem extends uvm_sequence_item;
`uvm_object_param_utils(seqItem)
rand logic [541-1:515] write_addr;
static logic [541-1:515] last_write_addr = 0;
constraint wAddrIncr {
write_addr > last_write_addr;
}
function new (string name="seqItem");
super.new(name);
endfunction
function post_randomize();
last_write_add = write_addr;
endfunction
endclass
Add a constraint in the sequence when randomising the sequence item
class someSequence extends uvm_sequence;
...stuff omitted...
task body();
seqItem item;
seqItem last_item;
last_item = null;
repeat (4728346) begin
item = new(); // or create to use factory
if (last_item) begin
item.randomize() with {
write_addr > last_item.write_addr
};
end else begin
item.randomize();
end
last_item = item;
// Send to driver or whatever
end
endtask
endclass
Number 2 is better in my opinion, because it doesn't bake the increasing address behaviour into the sequence item. Incrementing addresses is really a property of the sequence of items, not of any single item. I can now write some sequences that have increasing addresses, decreasing addresses, or any other pattern.
Upvotes: 3
Reputation: 13987
One solution to your problem of generating ascending (or descending) addresses is to keep a note of the last value generated and to use this as the lower bound in the constraint:
class seqItem;
randc logic [0:15] wfifo_addr;
static logic [0:15] last_wfifo_addr = '0;
constraint wArrdGivnRangCnstr {
this.wfifo_addr inside {[last_wfifo_addr:params_pkg::addrHighValue]};
}
function void post_randomize;
last_wfifo_addr = wfifo_addr;
if (last_wfifo_addr >= params_pkg::addrHighValue)
last_wfifo_addr= params_pkg::addrLowValue;
endfunction
endclass
http://www.edaplayground.com/x/3QxX
The post_randomize
function is a built-in method that can be overrided. It is called implicitly after the (built-in) randomize
method. There is also a built-in pre_randomize
, which of course you can override, too.
Upvotes: 0