Shortening a dist style constraint in SystemVerilog - system-verilog

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

Related

How to pass open_range_list to function for use in 'inside' operator

I have a function that returns 1 or 0 if a queue contains an element. I want to enhance this function to check if the queue contains any element in a set by using the 'inside' operator. For example, my function works like this:
function bit queue_exists(int n);
foreach(m_queue[x]) begin
if (m_queue[x] == n) return 1;
end
return 0;
endfunction
Now I want my function to work like this:
function bit queue_exists(/*open_range_list elements*/);
foreach(m_queue[x]) begin
if (m_queue[x] inside {elements}) return 1;
end
return 0;
endfunction
Is it possible to do this in SystemVerilog? I'm not sure what the syntax should be. I'm referencing "open_range_list" from the SV-LRM 1800-2017 Section 11.4.13:
inside_expression ::= expression inside { open_range_list } // from A.8.3
Declare the function something like this:
function bit queue_exists (int elements []);
Here is a runnable example:
module tb;
int m_queue [$];
function bit queue_exists (int elements []);
foreach(m_queue[x]) begin
if (m_queue[x] inside {elements}) return 1;
end
return 0;
endfunction
initial begin
for (int i=0; i<5; i++) m_queue.push_back(i);
$display(queue_exists('{3, 6}));
$display(queue_exists('{8, 9, 10}));
end
endmodule
Output is:
1
0

I don't understand this SV randomization randc behaviour

This is code for transaction class,
class transaction;
//declaring the transaction items
randc bit [3:0] a;
randc bit [3:0] b;
bit [6:0] c;
function void display(string name);
$display("-------------------------");
$display("- %s ",name);
$display("-------------------------");
$display("- a = %0d, b = %0d",a,b);
$display("- c = %0d",c);
$display("-------------------------");
endfunction
endclass
And this is code for generator class,
class generator;
rand transaction trans;
int repeat_count;
mailbox gen2driv;
event ended;
function new(mailbox gen2driv);
this.gen2driv = gen2driv;
endfunction
task main();
repeat(repeat_count) begin
trans = new();
if( !trans.randomize() ) $fatal("Gen:: trans randomization failed");
trans.display("[ Generator ]");
gen2driv.put(trans);
end
-> ended;
endtask
endclass
The value of repeat_count that I passed is 10, and here's the output:
- a = 2, b = 0
- c = 0
- a = 1, b = 9
- c = 0
- a = 9, b = 9
- c = 0
- a = 7, b = 15
- c = 0
- a = 10, b = 15
- c = 0
- a = 3, b = 1
- c = 0
- a = 13, b = 12
- c = 0
- a = 1, b = 9
- c = 0
- a = 7, b = 5
- c = 0
- a = 3, b = 15
- c = 0
But, values during randomization are not showing cyclic repetition. It is repeating itself before all possible value can occur for variables a and b.
Move the transaction constructor out of the repeat loop. Change:
repeat(repeat_count) begin
trans = new();
to:
trans = new();
repeat(repeat_count) begin
It seems new resets the initial random permutation of the range values each time it is called.
Here is a self-contained, runnable example which demonstrates the issue (and the fix):
class transaction;
randc bit [3:0] a; // 16 values: 0-15
function void display;
$display("a=%0d", a);
endfunction
endclass
class generator;
rand transaction trans;
task main;
//trans = new(); // Un-comment this line for fix
repeat (16) begin
trans = new(); // Comment out this line for fix
if (!trans.randomize()) $fatal(1, "trans randomization failed");
trans.display();
end
endtask
endclass
module tb;
generator gen = new();
initial gen.main();
endmodule
Yeah exactly to what #toolic said...initializing with new operator inside the repeat loop would create a new space every time the loop runs and thus the newly created object (transaction in your case) has no trace of the values that has been previously exercised. Thus giving out a random number making randc of no use. It though works normal with ' rand' keyword.

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

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

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

postgresql create function Euclidean distance n dimensions

I am noob in postgresql and I am trying to create a function to calculate the distances between a specific value and a set of values(records). Here is the table:
CREATE TABLE test
(
id serial NOT NULL,
name text,
values real[]
)
I want to create a function but I can't figure out how to loop every element in values[]
For example, I would like to select the name with the smallest distance. I didn't find any built-in function for this purpose.
I wrote the code in c# of what I am looking for:
List<double> res = new List<double>();
List<double[]> listDataBase=new List<double[]>();
double[] query = new double[] {12, 13, 13, 121};
double[] b = new double[] { 121, 1, 12, 124 };
double[] c = new double[] { 123, 123, 15, 122 };
double[] d = new double[] { 121, 1, 12, 124 };
double[] e = new double[] { 123, 123, 15, 122 };
listDataBase.Add(b);
listDataBase.Add(c);
listDataBase.Add(d);
listDataBase.Add(e);
foreach (double[] k in listDataBase)
{
double sum = 0;
for (int i = 0; i < query.Length; i++)
{
sum += Math.Pow(query[i] - k[i], 2);
}
res.Add(Math.Sqrt(sum));
}
res.Sort();
First I would change the name of the column you called values to vals. values is a keyword ofcourse you can write "values" in your queries but I would prefer to circumvent that issue by changing the name.
If I understand your question correctly I think it would be enough in your case to create a distance function then use that in a query. Here is the function:
CREATE OR REPLACE FUNCTION distance(l real[], r real[]) RETURNS real AS $$
DECLARE
s real;
BEGIN
s := 0;
FOR i IN 1..4 LOOP
s := s + ((l[i] - r[i]) * (l[i] - r[i]));
END LOOP;
RETURN |/ s;
END;
$$ LANGUAGE plpgsql;
If you want the name of the closest the query is:
SELECT name
FROM test
ORDER BY distance(test.values, ARRAY[12, 13, 13, 121]) DESC
LIMIT 1