SystemVerilog Coverage: Create a bin for each element of an enum - system-verilog

Say I have a enum which contains a list of valid commands or opcodes.
Is there a way to create a bin for each element of the enum?
class command_coverage;
enum {SEQ_WRITE_16_BIT = 32'hBEEFFOOD, SEQ_READ_16_BIT = 32'hFACEFACE,
... } my_valid_commands
covergroup cg();
command_cp : coverpoint cmd {
bins valid_commands[] = each element of enum;
}
endgroup
...
endclass
I tried something like:
bins valid_commands[] = my_valid_commands;
or
bins valid_commands[] = {[0:$] inside my_valid_commands};
But it didn't work as I wanted.

It can be done:
command_cp : coverpoint my_valid_commands {
bins valid_commands[] = {[my_valid_commands.first:my_valid_commands.last]};
first and last are methods of the enum, which return the first and last values respectively. These are then used as part of a range.
Here's the display from Mentor Questa (other simulators are available - I have Questa installed on my PC):
Here's an MCVE:
https://www.edaplayground.com/x/5rUu
module enum_cg;
enum {SEQ_WRITE_16_BIT, SEQ_READ_16_BIT} my_valid_commands;
covergroup cg();
command_cp : coverpoint my_valid_commands {
bins valid_commands[] = {[my_valid_commands.first:my_valid_commands.last]};
}
endgroup
cg cg0 = new;
initial begin
my_valid_commands = SEQ_WRITE_16_BIT;
cg0.sample;
end
endmodule

Related

Shortening a dist style constraint in SystemVerilog

I have a constraint of the form:
s dist {0:= 20, 1:= 25, 2:= 30, <many more, possibly hundreds>};
Instead of writing down the constraint this way, I found in my application the RHS (i.e. the weights - 20, 25, 30, etc,) could come from an array my_array whose i-th element contains the weight for the i-th element.
Is there any way to shorten it to something like below? This is just to show the concept and is syntactically incorrect:
s dist {foreach rhsArray[j] {j: rhsArray}};
One brute-force approach is populating an array with each value appearing the number of times the weight of each element.
module top;
typedef int unsigned uint;
class A;
uint my_array[$];
uint rhsArray[] = {20, 25, 30, 25};
rand uint s,index;
function new;
foreach(rhsArray[j]) repeat (rhsArray[j]) my_array.push_back(j);
endfunction
constraint curve {
s == my_array[index];
index < my_array.size;
}
endclass
A a = new;
uint my_dist[uint] = '{default:0};
initial begin
repeat(10000) begin
assert(a.randomize);
my_dist[a.s]++;
end
$display("%p",my_dist);
end
endmodule
There is another variation of this where you construct an array of structures with ranges based on the weights (i.e. range[0]: 0-19, range[1]: 20-44, range[2]: 45-74, range[3]: 75-99). Then pick a random number between 0-99 and the number that is inside the range[j] becomes j==s.
A more convoluted approach is creating a another class for each element, where each element has a distribution for being picked or not.
class element;
uint weight, sum;
rand bit picked;
constraint d { picked dist {0:=sum, 1:= weight}; }
endclass
class A;
uint rhsArray[] = {20, 25, 30, 25};
rand element e[];
rand uint s,index;
function new;
uint sum = rhsArray.sum();
e = new[rhsArray.size];
foreach(rhsArray[j]) begin
e[j] = new;
e[j].weight = rhsArray[j];
e[j].sum = sum;
end
endfunction
constraint curve {
e.sum() with (uint'(item.picked)) == 1;
foreach(e[j]) e[j].picked -> j == s;
}
endclass

Parameterize parameters?

I would like to parameterize localparam parameters.
My module definition:
module native #(
parameter SIM_ONLY = 0,
parameter FREQ = 500
)(
...
);
I have lots of instantiations using the same localparam parameter A.
if (FREQ == 550) begin
localparam A = 987;
end else begin
localparam A = 122;
end
AA #(
.A_VALUE (A),
) AA_inst (
...
);
But that isn't allowed in the specification, is there a different proper way to do it?
/!\ The A value is a magic number, not something that can be calculated from FREQ.
I've tried:
if (FREQ == 550) begin
shortreal A = 987;
end else begin
shortreal A = 122;
end
but I get The expression for a parameter actual associated with the parameter name... must be constant.
Use the conditional operator ?:
localparam A = (FREQ==550) 987 : 122;
You can also put more complicated expressions into a constant function
localparam A = some_function(FREQ);
function int some_function(int F);
case(F)
550: return 987;
123: return 456;
default: return 122;
endcase
endfunction

SystemVerilog error in multiplexing channels : nonconstant index into instance array

I'm designing a module that accepts multiple channels and outputs one channel.
Each channel consists of valid signal and data of some widths.
If a channel has valid data, the module should output that channel. If multiple channels have valid data, the module should output one of them (in my case, channel with highest index) and rests are dropped.
My simple implementation looks like this:
module test1 #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
input logic [DATA_WIDTH - 1 : 0] data_in [NUM_CHANNEL],
input logic valid_in [NUM_CHANNEL],
output logic [DATA_WIDTH - 1 : 0] data_out,
output logic valid_out
);
always_comb begin
valid_out = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (valid_in[i]) begin
valid_out = 1;
data_out = data_in[i];
end
end
end
endmodule
This works perfectly in both simulation and real circuit (FPGA).
However, channel can be complex type so I used interface like this:
interface channel #(
parameter DATA_WIDTH = 512
);
logic valid;
logic [DATA_WIDTH - 1 : 0] data;
modport in (
input valid,
input data
);
modport out (
output valid,
output data
);
endinterface // sub_csr_if
module test #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
channel.in in[NUM_CHANNEL],
channel.out out
);
always_comb begin
out.valid = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (in[i].valid) begin
out.valid = 1;
out.data = in[i].data;
end
end
end
endmodule
Then, this code gets Nonconstant index into instance array 'sub_port'. error in ModelSim, and i is not a constant error in Quartus.
If I unroll the loop, it works but it becomes non-parametric code. (only works for fixed NUM_CHANNEL)
Why the latter one does not work, while the first one works flawlessly?
An array of instances (module or interface) is not a true array type. As your error message indicates, you cannot select a particular instance with a variable index. With a true array, every element is identical. Because of the way parameterization, defparam, and port connections work, each instance element could have differences. The elaboration process essentially flattens all hierarchy before simulation begins.
What you can do is use a generate construct to select your instance as follows
;
module test #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
channel.in in[NUM_CHANNEL],
channel.out out
);
logic _valid[NUM_CHANNEL];
logic [DATA_WIDTH - 1 : 0] _data[NUM_CHANNEL];
for (genvar ii=0;ii<NUM_CHANNEL;ii++) begin
assign _valid[ii] = in[ii].valid;
assign _data[ii] = in[ii].data;
end
always_comb begin
out.valid = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (_valid[i]) begin
out.valid = 1;
out.data = _data[i];
end
end
end
endmodule

matlab oop "use data of hole class" for calculation

First, sorry for the bad title - I'm new to OO programming - basically I'd like to understand how Matlab works with oop classes.
Before I ask my question, here is a basic example of what I want to do:
I have two houses and some data about them and I got the idea, to work with oop classes. Here is my .m file.
classdef building
properties
hohe = 0;
lange = 0;
breite = 0;
xabstandsolar = 0;
yabstandsolar = 0;
end
methods
function obj = building(hohe, lange, breite, xabstandsolar, yabstandsolar)
obj.hohe = hohe;
obj.lange = lange;
obj.breite = breite;
obj.xabstandsolar = xabstandsolar;
obj.yabstandsolar = yabstandsolar;
end
function hohenwinkel(h)
h = h
d = sqrt(obj.xabstandsolar^2 + yabstandsolar^2);
gamma_v = atand((obj.hohe - h)/(d));
end
end
end
I filled it with some data - for example
>>H1 = building(10,8,6,14,8)
>>H2 = building(18,8,6,14,0)
And now I want to calculate "gamma_v" (as an 1x2 array) for each building. Any ideas, how I can archive this?
Edit:
I want to create gamma_v (as an array) automatically for all objects in the class "building". There will be a lot more "houses" in the final script.
Your hohenwinkel method needs to accept two input arguments. The first argument for non-static methods is always the object itself (unlike C++, you'll have to explicitly list it as an input argument) and the second input will be your h variable. You'll also want to actually return the gamma_v value using an output argument for your method.
function gamma_v = hohenwinkel(obj, h)
d = sqrt(obj.xabstandsolar^2 + obj.yabstandsolar^2);
gamma_v = atand((obj.hohe - h)/(d));
end
Then you can invoke this method on each building to get the value
gamma_v1 = hohenwinkel(H1);
gamma_v2 = hohenwinkel(H2);
If you want to have an array of buildings, you can create that array
houses = [building(10,8,6,14,8), building(18,8,6,14,0)];
gamma_v = hohenwinkel(houses);
and then construct your hohenwinkel function to operate on each one and return the result
function gamma_v = hohenwinkel(obj, h)
if numel(obj) > 1
% Compute hohenwinkel for each one
gamma_v = arrayfun(#(x)hohenwinkel(x, h), obj);
return
end
d = sqrt(obj.xabstandsolar^2 + obj.yabstandsolar^2);
gamma_v = atand((obj.hohe - h)/(d));
end
there is some tricky solution (and its not recommended)(#Suever solution is better)
you should create a handle class
classdef gvclass<handle
properties
gvarr=[];
end
methods
function setgvarr(obj,value)
obj.gvarr=[obj.gvarr,value];
end
end
end
then use this class in your building class
classdef building<handle
properties
gv
hohe = 0;
lange = 0;
breite = 0;
xabstandsolar = 0;
yabstandsolar = 0;
end
methods
function obj = building(hohe, lange, breite, xabstandsolar, yabstandsolar,handle_of_your_gv_class,h)
obj.hohe = hohe;
obj.lange = lange;
obj.breite = breite;
obj.xabstandsolar = xabstandsolar;
obj.yabstandsolar = yabstandsolar;
obj.gv=handle_of_your_gv_class;
obj.hohenwinkel(h);
end
function hohenwinkel(obj,h)
d = sqrt(obj.xabstandsolar^2 + yabstandsolar^2);
gamma_v = atand((obj.hohe - h)/(d));
obj.gv.setgvarr(gamma_v);
end
end
end
finally before creating any building you should create an object of gv class and pass it to the building constructor,
Egv=gvclass();
H1 = building(10,8,6,14,8,Egv,2)
H2 = building(18,8,6,14,0,Egv,3)
and to access gv array:
Egv.gvarr
you should do more effort on this issue to debug possible errors.

Specman on-the-fly generation for multiple constrained items

I have this multiple fields that need to be constrained in this manner:
struct my_struct {
a : uint;
b : uint;
c : uint;
d : uint;
keep 3*a + 4*b + 5*c + 6*d == 206 and a + b + c + d == 50;
my_method() #clk_event is {
while (TRUE) {
if (ctr == 0) {
gen a;
gen b;
gen c;
gen d;
};
if (ctr == 50) {
ctr = 0;
} else {
ctr += 1;
};
wait cycle;
};
};
};
I basically want to generate a new set of values for a, b, c, and d periodically. The above code is not working as their values did not change in my simulation. Any idea how to do it?
When you generate one field, other fields can't change their values, they are inputs for the constraints. Given your constraints, there can be only one correct value for a field if three other can't change.
You probably need to modify the design and put the fields with constraints under a struct, and have a field of this struct type. So instead of four separate gens, you will have only one, and it will do the job right.