Creating transition coverage bins using a queue or dynamically - system-verilog

I want to write a transition coverage on an enumeration. One of the parts of that transition is a queue of the enum. I construct this queue in my constructor. Considering the example below, how would one go about it.
In my coverage bin I can create a range like this A => [queue1Enum[0]:queue1Enum[$]] => [queue2Enum[0]:queue2Enum[$]]. But I only get first and last element then.
typedef enum { red, d_green, d_blue, e_yellow, e_white, e_black } Colors;
Colors dColors[$];
Colors eColors[$];
Lcolors = Colors.first();
do begin
if (Lcolors[0].name=='d') begin
dColors.push_back(Lcolors);
end
if (Lcolors[0].name=='e') begin
eColors.push_back(Lcolors);
end
end while(Lcolors != Lcolors.first())
covergroup cgTest with function sample(Colors c);
cpTran : coverpoint c{
bins t[] = (red => dColors =>eColors);
}
endgroup
bins t[] should come out like this(red=>d_blue,d_green=>e_yellow,e_white)

The following worked for me:
bins t[] = (
red =>
[dColors[0] : dColors[$]] =>
[eColors[0] : eColors[$]]);
I got the bins you were expecting:
t[red=>d_green=>e_yellow]
t[red=>d_green=>e_white]
t[red=>d_green=>e_black]
t[red=>d_blue=>e_yellow]
t[red=>d_blue=>e_white]
t[red=>d_blue=>e_black]
I see that you tried this as well, but didn't get what you were expecting. Maybe this is because your tool doesn't support this properly.
One more thing you should check is that you created the dColors and eColors queues properly. The sample code you showed in your question isn't correct and won't put the proper elements in the queues.

Related

How do we correctly exclude an {'1} value from a cover group?

I got the following covergroup implemented:
covergroup my_covergroup_cg (input string name);
enable_reg_cp : coverpoint enabled_reg[PARAM1-1:0] {
illegal_bins no_enable = {0};
}
feature_active_reg_cp : coverpoint feature_active_reg_mask[PARAM2-1:0] { // Interested in covering a PARAM2-width chunk of a 32-bit feature_active_reg
illegal_bins all_features_active = {'1}; // We must not activate all features (1 bit = 1 feature active)
}
my_covergroup_cross : cross enable_reg_cp , feature_active_reg_cp {
illegal_bins il0 = (binsof (enable_reg_cp) intersect {0});
illegal_bins il1 = (binsof (feature_active_reg_cp) intersect {'1});
}
endgroup : my_covergroup_cg
Upon execution, the "il1" illegal bin of my cross gets hit with a value "0x1" of the
feature_active_reg_mask[PARAM2-1:0] - which is completly legal and does not match the {'1} (equivalent to ..111111 : all ones).
Is there a particular issue of how these {'1} are treated in the "binsof" scope ?
This is most likley a tool issue. According to section 19.5.7 Value resolution in the 1800-20167 LRM, All bin expression get evaluated in the context of the coverpoint type. You can use [$:$] as an alternative that represents the largest possible value.
BUT... the illegal_bins in the cross is unnecessary because only the included bins of a coverpoint get crossed. AND... one you define an explicit set of bins, there are no implicitly defined bins, so you should write this as
covergroup my_covergroup_cg (input string name);
enable_reg_cp : coverpoint enabled_reg[PARAM1-1:0] {
bins enable[] = {[1:$]}; // will be split into N bins according to auto_bins_max
}
feature_active_reg_cp : coverpoint feature_active_reg_mask[PARAM2-1:0] { // Interested in covering a PARAM2-width chunk of a 32-bit feature_active_reg
bins some_features_active = {[0:$]};
ignore_bins all_features_active = {[$:$]}; // We must not activate all features (1 bit = 1 feature active)
}
my_covergroup_cross : cross enable_reg_cp , feature_active_reg_cp;
endgroup : my_covergroup_cg
In the 2nd coverpoint, the $ value overlaps the two bin specifications, but the ignore_bins overrides that.
Just to share my workaround for knowledge share:
I have decided to go with using localparam semantic. As it appears the issue is related to the tool interpreting the {'1}.
I did the following:
localparam all_ones = {PARAM2{1'b1}};
covergroup my_covergroup_cg (input string name);
enable_reg_c .... // rest of code
and I passed the alias into my illegal_bins
illegal_bins il1 = (binsof (feature_active_reg_cp) intersect {all_ones});
Cheers,

system verilog 2 dimensional dynamic array randomization

I am trying to use system verilog constraint solver to solve the following problem statement :
We have N balls each with unique weight and these balls need to be distributed into groups , such that weight of each group does not exceed a threshold ( MAX_WEIGHT) .
Now i want to find all such possible solutions . The code I wrote in SV is as follows :
`define NUM_BALLS 5
`define MAX_WEIGHT_BUCKET 100
class weight_distributor;
int ball_weight [`NUM_BALLS];
rand int unsigned solution_array[][];
constraint c_solve_bucket_problem
{
foreach(solution_array[i,j]) {
solution_array[i][j] inside {ball_weight};
//unique{solution_array[i][j]};
foreach(solution_array[ii,jj])
if(!((ii == i) & (j == jj))) solution_array[ii][jj] != solution_array[i][j];
}
foreach(solution_array[i,])
solution_array[i].sum() < `MAX_WEIGHT_BUCKET;
}
function new();
ball_weight = {10,20,30,40,50};
endfunction
function void post_randomize();
foreach(solution_array[i,j])
$display("solution_array[%0d][%0d] = %0d", i,j,solution_array[i][j]);
$display("solution_array size = %0d",solution_array.size);
endfunction
endclass
module top;
weight_distributor weight_distributor_o;
initial begin
weight_distributor_o = new();
void'(weight_distributor_o.randomize());
end
endmodule
The issue i am facing here is that i want the size of both the dimentions of the array to be randomly decided based on the constraint solution_array[i].sum() < `MAX_WEIGHT_BUCKET; . From my understanding of SV constraints i believe that the size of the array will be solved before value assignment to the array .
Moreover i also wanted to know if unique could be used for 2 dimentional dynamic array .
You can't use the random number generator (RNG) to enumerate all possible solutions of your problem. It's not built for this. An RNG can give you one of these solutions with each call to randomize(). It's not guaranteed, though, that it gives you a different solution with each call. Say you have 3 solutions, S0, S1, S2. The solver could give you S1, then S2, then S1 again, then S1, then S0, etc. If you know how many solutions there are, you can stop once you've seen them all. Generally, though, you don't know this beforehand.
What an RNG can do, however, is check whether a solution you provide is correct. If you loop over all possible solutions, you can filter out only the ones that are correct. In your case, you have N balls and up to N groups. You can start out by putting each ball into one group and trying if this is a correct solution. You can then put 2 balls into one group and all the other N - 2 into a groups of one. You can put two other balls into one group and all the others into groups of one. You can start putting 2 balls into one group, 2 other balls into one group and all the other N - 4 into groups of one. You can continue this until you put all N balls into the same group. I'm not really sure how you can easily enumerate all solutions. Combinatorics can help you here. At each step of the way you can check whether a certain ball arrangement satisfies the constraints:
// Array describing an arrangement of balls
// - the first dimension is the group
// - the second dimension is the index within the group
typedef unsigned int unsigned arrangement_t[][];
// Function that gives you the next arrangement to try out
function arrangement_t get_next_arrangement();
// ...
endfunction
arrangement = get_next_arrangement();
if (weight_distributor_o.randomize() with {
solution.size() == arrangement.size();
foreach (solution[i]) {
solution[i].size() == arrangement[i].size();
foreach (solution[i][j])
solution[i][j] == arrangement[i][j];
}
})
all_solutions.push_back(arrangement);
Now, let's look at weight_distributor. I'd recommend you write each requirement in an own constraint as this makes the code much more readable.
You can shorten you uniqueness constraint that you wrote as a double loop to using the unique operator:
class weight_distributor;
// ...
constraint unique_balls {
unique { solution_array };
}
endclass
You already had a constraint that each group can have at most MAX_WEIGHT in it:
class weight_distributor;
// ...
constraint max_weight_per_group {
foreach (solution_array[i])
solution_array[i].sum() < `MAX_WEIGHT_BUCKET;
}
endclass
Because of the way array sizes are solved, it's not possible to write constraints that will ensure that you can compute a valid solution using simple calls randomize(). You don't need this, though, if you want to check whether a solution is valid. This is due to the constraints on array sizes in the between arrangement and solution_array.
Try this.!
class ABC;
rand bit[3:0] md_array [][]; // Multidimansional Arrays with unknown size
constraint c_md_array {
// First assign the size of the first dimension of md_array
md_array.size() == 2;
// Then for each sub-array in the first dimension do the following:
foreach (md_array[i]) {
// Randomize size of the sub-array to a value within the range
md_array[i].size() inside {[1:5]};
// Iterate over the second dimension
foreach (md_array[i][j]) {
// Assign constraints for values to the second dimension
md_array[i][j] inside {[1:10]};
}
}
}
endclass
module tb;
initial begin
ABC abc = new;
abc.randomize();
$display ("md_array = %p", abc.md_array);
end
endmodule
https://www.chipverify.com/systemverilog/systemverilog-foreach-constraint

Parameterizable cross length

I've got a protocol that supports bursts, where each transaction is composed of N individual transfers. Each transfer has a unique index from 0 to N-1. I would like to cover that all transfer orders have been seen (i.e. 0 1 2 3, 1 2 3 0, 0 2 3 1, etc.). The value of N is variable (though in my case I only care about 4 and 8 for now).
The naive approach would be to cover each index individually and cross them, but this would mean I would need multiple covergroups, one per each value of N.
For N = 4:
covergroup some_cg;
coverpoint idxs[0];
coverpoint idxs[1];
coverpoint idxs[2];
coverpoint idxs[3];
cross idxs[0], idxs[1], idxs[2], idxs[3] {
ignore_bins non_unique_idxs[] = some_func_that_computes_bins_for_4_idxs();
}
endgroup
For N = 8:
covergroup some_cg;
coverpoint idx[0];
coverpoint idx[1];
coverpoint idx[2];
coverpoint idx[3];
coverpoint idx[4];
coverpoint idx[5];
coverpoint idx[6];
coverpoint idx[7];
cross idx[0], idx[1], idx[2], idx[3], idx[4], idx[5], idx[6], idx[7] {
ignore_bins non_unique_idxs[] = some_func_that_computes_bins_for_8_idxs();
}
endgroup
The two functions that generate the ignore bins each have to return different types (queue of struct with 4/8 fields), even though conceptually the operation for computing all illegal combinations is similar, regardless of the value of N. This could probably be solved with some clever use of the streaming operator, to stream the contents of the structs into arrays of N elements. The issue of redundancy in the covergroup definitions remains though. The only way I can think of solving this is by generating the code.
Another idea would be to pack all indexes into a packed array of the appropriate size and cover that:
covergroup some_other_cg;
coverpoint packed_idxs {
ignore_bins non_unique_idxs[] = some_func_that_computes_bins_for_N_idxs();
}
endgroup
// Probably won't compile, but it would also be possible to use the streaming op
// Idea is to pack into integral type
foreach (idxs[i])
packed_idxs[i * idx_len +: len] = idxs[i];
It's a pain to debug coverage holes, as it's difficult to figure what transfer order a certain packed value belongs to, especially if the values are shown in decimal radix. I believe the way values are displayed varies from tool to tool and it's not possible to control this. I also don't see any possibility to give names to individual bins using strings.
I would welcome any input that would improve upon any of the two suggestions. The goal is to have one coverage wrapper class with a parameter for the number of transfers and to be able to instantiate that and get the coverage:
class transfer_orders_coverage #(int unsigned NUM_TRANSFERS);
// ...
endclass
Adding as and 'Answer' since it was too long for comment. Pardon me if I am not clear.
Can you add some logic before sampling CG and use some input argument that denotes array position of idxs? For the crosses, you can maintain a packed array of size N and make individual bits 1 when a particular pattern is detected. At the end of sim, you can sample the coverage for that pattern in some different CG.
Basically the idea is to offload logic inside the covergroups and add logic surrounding sample function. Here is a rough idea about what I was thinking.
class transfer_orders_coverage #(int unsigned N = 4);
int idxs[N];
bit [(N -1) : 0] pattern; // Make indexes HIGH according to sampled pattern
// ...
covergroup cross_cg;
mycp_cross: coverpoint pattern{
ignore_bins myignbn = {some_generic_function_for_N(pattern)};
}
endgroup
covergroup indiv_cg with function sample (int index);
mycp_indiv: coverpoint idxs[index]{
// some bins to be covered in ith position of idxs
}
endgroup
function new();
cross_cg = new;
indiv_cg = new;
endfunction
function bit [(N -1) : 0] some_generic_function_for_N(bit [(N -1) : 0] pattern);
// check which bits in "pattern" are to be covered and which are to be ignored
//return some_modified_pattern;
endfunction
function void start();
// Any logic for sampling ith position
foreach(idxs[i]) begin
indiv_cg.sample(i);
pattern[i] = 1'b1;
end
cross_cg.sample();
endfunction
endclass
module top();
transfer_orders_coverage #(4) tr;
initial begin
tr = new;
tr.start();
end
endmodule
Let me know if it seems feasible or not.
I guess, the following solution may work in this case.
covergroup some_cg (int num);
4n_cp : coverpoint ({idxs[0], idxs[1], idxs[2], idxs[3]}) iff (num == 4)
{
option.weight = (num == 4) ? 1 : 0; // Weight might change depending on other coverpoints
ignore_bins non_unique_index[] = <Your Function>;
}
8n_cp : coverpoint ({idxs[0], idxs[1], idxs[2], idxs[3], idxs[4], idxs[5], idxs[6], idxs[7]}) iff (num == 8)
{
option.weight = (num == 8) ? 1 : 0; // Weight might change depending on other coverpoints
ignore_bins non_unique_index[] = <Your Function>;
}
endgroup
// Where you instantiate covergroups
some_cg c1 = new(4);
Let me know, how the above idea works.

Specman coverage: How to cover only that some transition occurred?

I need to make sure that at least 1 change occurred in a specific uint item X, i.e. X had 2 different values (it is unknown what specific values). Something like this:
cover some_event {
item X : uint = some_uint using no_collect;
transition X using when = (prev_X != X);
};
** The code causes compilation error
Is it possible to define such coverage in Specman?
Thank you for your help
what you wrote is almost accurate, but instead of "when" - use "ignore"
cover some_event is {
item X : uint = some_uint using no_collect;
transition X using ignore = (prev_X == X);
};

Specman coverage: Is there a way to define ranges using variable?

I have comp_value that gets values between 1 .. 100.
In addition I have an input variable period (of the same range). I need to cover 2 ranges of comp_values: [1..period] and [period+1 .. 100]. Something like this:
cover some_event_e is {
item period using no_collect;
item comp_val using no_collect,
ranges = {
range([1..period], "Smaller_than_period");
range([period+1..100], "Bigger_than_period");
};
};
(The code causes compilation error since no variable can be written inside range).
Is there a way to collect the coverage?
Thank you for your help.
Ranges must be constant.
But if I understood your intent correctly, you can define new items like
cover some_event_e is {
item smaller_or_equal_than_period: bool = (comp_val in [1..period]) using
ignore = (not smaller_or_equal_than_period);
item greater_than_period: bool = (comp_val in [(min(100,period+1)..100]) using
ignore = (not greater_than_period);
};
Assuming period is always in [1..100].