How to create a named constant in the SystemVerilog generate block? - constants

I need to transmit a set of values between the SystemVerilog and VHDL code. To do that, I have to flatten the SV structures into the bit vectors, transmit the bit vectors, and rebuild the structures at the VHDL side.
Unfortunately, I have faced a serious problem at the SV side. My "flattener" has the following code:
generate
for(genvar i=0;i<nlinks;i++)
for(genvar j=0;j<2;j++)
begin
const int base = 2 * i + j;
assign vf[base] = lct_aligned[i][j].vf;
assign hs[(8*base+7):8*base] = lct_aligned[i][j].hs;
assign wg[(7*base+6):7*base] = lct_aligned[i][j].wg;
assign ql[(4*base+3):4*base] = lct_aligned[i][j].ql;
assign cp[(4*base+3):4*base] = lct_aligned[i][j].cp;
assign lr[base] = lct_aligned[i][j].lr;
assign bc0[base] = lct_aligned[i][j].bc0;
assign bx0[base] = lct_aligned[i][j].bx0;
assign ser[base] = lct_aligned[i][j].ser;
assign cid[(4*base+3):4*base] = lct_aligned[i][j].cid;
end
endgenerate
Unfortunately, it gives "base is not a constant error" in each "assign" line.
When I replace "base" with "(2*i+j)" the code compiles correctly, but is significantly less visible and mantainable.
generate
for(genvar i=0;i<nlinks;i++)
for(genvar j=0;j<2;j++)
begin
//const int base = 2 * i + j;
assign vf[(2*i+j)] = lct_aligned[i][j].vf;
assign hs[(8*(2*i+j)+7):8*(2*i+j)] = lct_aligned[i][j].hs;
assign wg[(7*(2*i+j)+6):7*(2*i+j)] = lct_aligned[i][j].wg;
assign ql[(4*(2*i+j)+3):4*(2*i+j)] = lct_aligned[i][j].ql;
assign cp[(4*(2*i+j)+3):4*(2*i+j)] = lct_aligned[i][j].cp;
assign lr[(2*i+j)] = lct_aligned[i][j].lr;
assign bc0[(2*i+j)] = lct_aligned[i][j].bc0;
assign bx0[(2*i+j)] = lct_aligned[i][j].bx0;
assign ser[(2*i+j)] = lct_aligned[i][j].ser;
assign cid[(4*(2*i+j)+3):4*(2*i+j)] = lct_aligned[i][j].cid;
end
endgenerate
Is there any way to define constants for complex expressions in the SystemVerilog generate blocks?

A const variable is not really a constant. It's a variable with a write once at run-time value. A parameter or localparam is a compile time constant. Simply replace const with parameter.

Related

Is there a way to cast an SystemVerilog assignment pattern into a packed struct?

Per the System Verilog LRM "Assignment pattern format", a data structure can be printed into a string as follows:
module top;
typedef enum {ON, OFF} switch_e;
typedef struct {switch_e sw; string s;} pair_t;
pair_t va[int] = '{10:'{OFF, "switch10"}, 20:'{ON, "switch20"}};
initial begin
$display("va[int] = %p;",va);
$display("va[int] = %0p;",va);
$display("va[10].s = %p;", va[10].s);
end
endmodule : top
This example may print:
va[int] = '{10:'{sw:OFF, s:"switch10"}, 20:'{sw:ON, s:"switch20"}} ;
va[int] = '{10:'{OFF, "switch10"}, 20:'{ON, "switch20"}} ;
va[10].s = "switch10";
Is there a way to do the reverse? What I'd like to do is to take an assignment pattern string as a plusarg or a line read from a file, and assign that to a variable at run time, e.g.:
string assign_pattern = "'{10:'{sw:OFF, s:"switch10"}, 20:'{sw:ON, s:"switch20"}}";
$cast(va, assign_pattern); // ** This doesn't work **
If not generally possible, is there a way to do that specifically for packed struct types?
You can't do the reverse. SystemVerilog was designed as a compiled language—there's no parser available at run-time. You would have to create a parser in SystemVerilog or C smart enough to decode the assignment patterns you expect to read in.
Another option is converting the file of assignment patterns into code that could be compiled in with the rest of your code.
Another option based on your comments
You can use a bit-stream or streaming operator to parse a bit-string into a struct. The struct does not need to be packed, it just needs to be made up from fixed-sized, integral values.
module top;
typedef enum bit [1:0] {ON, OFF, INBETWEEN} switch_e;
typedef struct {switch_e sw; bit [8*8:1] s; bit [5:0] value;} trio_s; // 72 bits
typedef bit [71:0] uint72_t;
trio_s v,x;
uint72_t l;
initial begin
x = '{sw:OFF, s:"switch10", value:'h0a};
l = uint72_t'(x);
$displayh(l);
v = trio_s'(l);
$displayh("v = %p",v);
$display("v.s = %s",v.s);
end
endmodule
This displays
# 5cddda5d18da0c4c0a
# v = '{sw:OFF, s:8320234785195176240, value:10}
# v.s = switch10
pair_t va[int] = '{10:'{OFF, "switch10"}, 20:'{ON, "switch20"}};
is the same as
pair_t va[int]
initial begin
va[10].sw = OFF;
va[10].s = "switch10";
..
Saying that, you can write your own parser of a +arg string (or strings) which will assign values to the array fields in a task. This is the only possibility. For exmple:
string indx = "1";
string sw = "off";
initial begin
int i = indx.atoi();
va[i].sw = sw == "off" ? OFF : ON;
...

matlab with classes - save struct in empty double array

I try to create a class in matlab
It has a property children
properties
children
If this variable is written to - it is supposed to be an arrays of structs
it fails with
function obj = Init(obj, valueList)
%INIT Initialise with vector of new parameter sets
newSet = obj.ParamSet;
newSet.values = valueList;
obj.children(end + 1) = newSet; % <<< error
Error is :
Conversion to double from struct is not possible.
This is the struct that is used
methods(Static)
function paramset = ParamSet()
newset.('values') = [];
newset.('fitness') = 0;
paramset = newset;
end
end
The simple solution is to assign if it’s empty:
if isempty(obj.children)
obj.children = newSet;
else
obj.children(end + 1) = newSet;
end

Assigning an array to a vector 32 bits at the time

I have an array 32 bit wide of n elements and I am trying to assign these elements to a vector, I have the following code:
function automatic logic [SIZE-1:0] my_function (my_array x_map);
logic SIZE-1:0] y_map = '0;
int fctr = (SIZE)/32;
int top_bnd = 31;
int lwr_bnd = 0;
for(int k0 = 0; k0 < fctr; k0++)
begin
y_map[top_bnd:lwr_bnd] = x_map[k0];
top_bnd = (top_bnd + 32'hFFFF);
lwr_bnd = (lwr_bnd + 32'hFFFF);
end
return y_map;
endfunction
However this is not working and I get two errors:
1) "the range of the part select is illegal"
2) "Cannot evaluate the expression in left slicing expression, the expression must be compile time constant"
Thanks
You might want to use the streaming operators for this
y_map = {<<32{x_map}};
BTW, you should show the declarations of all identifiers in your example, i.e. my_array.

Matlab coder & dynamic field references

I'm trying to conjure up a little parser that reads a .txt file containing parameters for an algorithm so i don't have to recompile it everytime i change a parameter. The application is C code generated from .m via coder, which unfortunately prohibits me from using a lot of handy matlab gimmicks.
Here's my code so far:
% read textfile
string = readfile(filepath);
% do fancy rearranging
linebreaks = zeros(size(string));
equals = zeros(size(string));
% find delimiters
for n=1:size(string,2)
if strcmp(string(n),char(10))
linebreaks(n) = 1;
elseif strcmp(string(n), '=')
equals(n) = 1;
end
end
% write first key-value pair
idx_s = find(linebreaks);idx_s = [idx_s length(string)];
idx_e = find(equals);
key = string(1:idx_e(1)-1);
value = str2double(string(idx_e(1)+1:idx_s(1)-1));
parameters.(key) = value;
% find number of parameters
count = length(idx_s);
% write remaining key-value pairs
for n=2:count
key = string(idx_s(n-1)+1:idx_e(n)-1);
value = str2double(string(idx_e(n)+1:idx_s(n)-1));
parameters.(key) = value;
end
The problem is that seemingly coder does not support dynamic fieldnames for structures like parameters.(key) = value.
I'm a bit at a loss as to how else i am supposed to come up with a parameter struct that holds all my key-value pairs without hardcoding it. It would somewhat (though not completely) defeat the purpose if the names of keys were not dynamically linked to the parameter file (more manual work if parameters get added/deleted, etc.). If anybody has an idea how to work around this, i'd be very grateful.
As you say, dynamic fieldnames for structures aren't allowed in MATLAB code to be used by Coder. I've faced situations much like yours before, and here's how I handled it.
First, we can list some nice tools that are allowed in Coder. We're allowed to have classes (value or handle), which can be quite handy. Also, we're allowed to have variable sized data if we use coder.varsize to specifically designate it. We also can use string values in switch statements if we like. However, we cannot use coder.varsize for properties in a class, but you can have varsized persistent variables if you like.
What I'd do in your case is create a handle class for storing and retrieving the values. The following example is pretty basic, but will work and could be expanded. If a persistent variable were used in a method, you could even create a varsized allocated storage for the data, but in my example, it's a property and has been limited in the number of values it can store.
classdef keyval < handle %# codegen
%KEYVAL A key and value class designed for Coder
% Stores an arbitrary number of keys and values.
properties (SetAccess = private)
numvals = 0
end
properties (Access = private)
intdata
end
properties (Constant)
maxvals = 100;
maxkeylength = 30;
end
methods
function obj = keyval
%KEYVAL Constructor for keyval class
obj.intdata = repmat(struct('key', char(zeros(1, obj.maxkeylength)), 'val', 0), 1, obj.maxvals);
end
function result = put(obj, key, value)
%PUT Adds a key and value pair into storage
% Result is 0 if successful, 1 on error
result = 0;
if obj.numvals >= obj.maxvals
result = 1;
return;
end
obj.numvals = obj.numvals + 1;
tempstr = char(zeros(1,obj.maxkeylength));
tempstr(1,1:min(end,numel(key))) = key(1:min(end, obj.maxkeylength));
obj.intdata(obj.numvals).key = tempstr;
obj.intdata(obj.numvals).value = value;
end
function keystring = getkeyatindex(obj, index)
%GETKEYATINDEX Get a key name at an index
keystring = deblank(obj.intdata(index).key);
end
function value = getvalueforkey(obj, keyname)
%GETVALUEFORKEY Gets a value associated with a key.
% Returns NaN if not found
value = NaN;
for i=1:obj.numvals
if strcmpi(keyname, deblank(obj.intdata(i).key))
value = obj.intdata(i).value;
end
end
end
end
end
This class implements a simple key/value addition as well as lookup. There are a few things to note about it. First, it's very careful in the assignments to make sure we don't overrun the overall storage. Second, it uses deblank to clear out the trailing zeros that are necessary in the string storage. In this situation, it's not permitted for the strings in the structure to be of different length, so when we put a key string in there, it needs to be exactly the same length with trailing nulls. Deblank cleans this up for the calling function.
The constant properties allocate the total amount of space we're allowed in the storage array. These can be increased, obviously, but not at runtime.
At the MATLAB command prompt, using this class looks like:
>> obj = keyval
obj =
keyval with properties:
numvals: 0
>> obj.put('SomeKeyName', 1.23456)
ans =
0
>> obj
obj =
keyval with properties:
numvals: 1
>> obj.put('AnotherKeyName', 34567)
ans =
0
>> obj
obj =
keyval with properties:
numvals: 2
>> obj.getvalueforkey('SomeKeyName')
ans =
1.2346
>> obj.getkeyatindex(2)
ans =
AnotherKeyName
>> obj.getvalueforkey(obj.getkeyatindex(2))
ans =
34567
If a totally variable storage area is desired, the use of persistent variables with coder.varsize would work, but that will limit the use of this class to a single instance. Persistent variables are nice, but you only get one of them ever. As written, you can use this class in many different places in your program for different storage. If you use a persistent variable, you may only use it once.
If you know some of the key names and are later using them to determine functionality, remember that you can switch on strings in MATLAB, and this works in Coder.

Progress 4GL: Labelling a field from a variable

I am having trouble labelling a field(s) on a frame. The number of fields and the required labels are determined at run-time.
the required labels are stored in char array:
w-indarray[]
I am using the following loop to add the required fields to the frame
do i = 1 to w-nooff:
form w-sstrings[i] with frame f1.
w-sstrings[i]:label in frame f1 = w-indarray[i].
end.
But I get an error:
Widget array-element requires constant subscript.
I have googled but the only occurrence looks slightly different and I'm not sure if the solution is applicable. http://www.mofeel.net/258-comp-databases-progress/5295a6889.aspx
I am assuming that being able to reference the elements of w-indarray[] as literals would resolve this as i could just do:
form w-sstrings[i] label "abc" with frame f1.
is there any way of referencing the elements of the w-indarray[] as literals that I am missing?
Thanks for your time.
You can do this without using static numbers for the extent by getting all widget handles and modifying their labels. It works but it's kind of a lot code to do something that really should be easier.
Something like this:
DEFINE VARIABLE cLabel AS CHARACTER NO-UNDO EXTENT 10 INIT ["One","Two","three","Four","Five","Six","Seven","Eight","Nine","Ten"].
DEFINE VARIABLE cField AS CHARACTER NO-UNDO EXTENT 10.
DEFINE VARIABLE hFieldGroup AS HANDLE NO-UNDO.
DEFINE VARIABLE hFirstWidget AS HANDLE NO-UNDO.
DEFINE VARIABLE iExtent AS INTEGER NO-UNDO.
DEFINE VARIABLE iLoop AS INTEGER NO-UNDO.
DEFINE FRAME f1 WITH SIDE-LABELS 1 COLUMN.
DISPLAY
cField
WITH FRAME f1.
/* Static will be done like this
Commenting out this
ASSIGN
cField[1]:LABEL = cLabel[1]
cField[2]:LABEL = cLabel[2]
cField[3]:LABEL = cLabel[3]
cField[4]:LABEL = cLabel[4]
cField[5]:LABEL = cLabel[5]
cField[6]:LABEL = cLabel[6]
cField[7]:LABEL = cLabel[7]
cField[8]:LABEL = cLabel[8]
cField[9]:LABEL = cLabel[9]
cField[10]:LABEL = cLabel[10].
*/
ASSIGN
hFieldGroup = FRAME f1:FIRST-CHILD
hFirstWidget = hFieldGroup:FIRST-CHILD.
/* Widget-loop. Could really be done prettier... */
REPEAT:
iLoop = iLoop + 1.
hFirstWidget = hFirstWidget:NEXT-SIBLING NO-ERROR.
IF hFirstwIDGET = ? THEN LEAVE.
IF hFirstWidget:TYPE = "FILL-IN" THEN DO:
iExtent = iExtent + 1.
/* Set dynamic label */
hFirstWidget:LABEL = cLabel[iExtent].
END.
END.
The error message says you need to use a constant in the array instead of a variable. This means you'll need to do a CASE statement to get the functionality you're looking for - like so:
CASE i:
WHEN 1 THEN w-sstrings[1]:label in frame f1 = w-indarray[i].
WHEN 2 THEN w-sstrings[2]:label in frame f1 = w-indarray[i].
WHEN 3 THEN w-sstrings[3]:label in frame f1 = w-indarray[i].
WHEN 4 THEN w-sstrings[4]:label in frame f1 = w-indarray[i].
WHEN 5 THEN w-sstrings[5]:label in frame f1 = w-indarray[i].
END CASE.
The reason for the constant array element is the compiler can't discern which field the array element corresponds to when you give it a variable designation.