any way how to define msb:lsb range as parameter? - system-verilog

having tons of registers defined in my hardware, containing bit fields, I wanted to 'name' those registers and access in SystemVerilog the bit fields using their names instead of msb:lsb format. So, I made a new package, and declared constant parameters inside, and as well tried those which describe range. Something like this:
package VmeAddressMap;
parameter SYS_INTCONFIG = 32'h00000044;
parameter RSYS_INTCONFIGRORA = 31:16;
parameter RSYS_INTCONFIGENABLE = 15:0;
endpackage // VmeAddressMap
quite evidently, this does not work. So I came with a 'hybrid' solution, i.e. simple constants stay in package, and for ranges I made another file, which contains macros:
package file:
package VmeAddressMap;
parameter SYS_INTCONFIG = 32'h00000044;
endpackage // VmeAddressMap
macro file:
`define RSYS_INTCONFIGRORA 31:16
`define RSYS_INTCONFIGENABLE 15:0
this solution permits me to do things as follow (Read is a task reading data through VME bus):
Read(SYS_INTCONFIG);
`CHECK_EQUAL(LastVmeReadData_b32[`RSYS_INTCONFIGRORA], 15,
"IRQ setup invalid");
This works, and does what I want. However I don't like it. In particular mixing macros with SystemVerilog style of description.
Is there a way how to accomplish the same task directly in the package?

This is exactly what the UVM register abstraction layer does for you. You define fields giving them a name, bit width, and other attributes. Those fields are grouped into a registers, and registers are grouped into blocks with addresses and offsets.
Now that I've told you that, here's a simple solution that does what you are looking for using the let construct.
package VmeAddressMap;
parameter SYS_INTCONFIG = 32'h00000044;
let RSYS_INTCONFIGRORA(field) = field[31:16];
let RSYS_INTCONFIGENABLE(field) = field[15:0];
endpackage // VmeAddressMap
But now you have to put the range in front of the variable.
`CHECK_EQUAL(RSYS_INTCONFIGRORA(LastVmeReadData_b32), 15,
"IRQ setup invalid");

You can use one parameter for the MSB and another for the LSB.
parameter RSYS_INTCONFIGRORA_MSB = 31;
parameter RSYS_INTCONFIGRORA_LSB = 16;
LastVmeReadData_b32[RSYS_INTCONFIGRORA_MSB:RSYS_INTCONFIGRORA_LSB]
That is a bit unwieldy, so if everything is 16 bits wide you can just define the LSB:
parameter RSYS_INTCONFIGRORA = 16;
LastVmeReadData_b32[RSYS_INTCONFIGRORA +: 16]
Or, you can use a struct:
typedef struct packed {
logic [15:0] RSYS_INTCONFIGRORA;
logic [15:0] RSYS_INTCONFIGENABLE;
} some_register_t;
You can further make a union with that struct if some parts of the design need to interact with the whole register object and others with just the bit fields.
These register structs can be built up into a much larger register map struct.
If you are using UVM then you should be building up a RAL module of your registers

Related

passing generated modports to instances of the same module

I'm pretty sure there is no way to do what I am trying, but just in case there is an interesting clever solution, I thought I'd ask around. I have a parameterized SystemVerilog interface, inside of which I am generating modports
interface some_interface #(parameter NUM_READERS=3);
logic [`kBitsPerProgramCounter-1:0] read_addr[NUM_READERS];
logic [`kBitsPerProgramCounter-1:0] write_addr;
genvar i;
generate
// generates Reader[n].Modport
for (i = 0; i < NUM_READERS; ++i) begin : Reader
modport Modport
(
output .read_addr(read_addr[i])
);
end
endgenerate
endinterface
Using this is easy if I have different module types taking different modports. However, what I wanted to try doing is to have multiple instances of the same module. I tried this by parameterizing on type
module some_block#(parameter type SOMETYPE) (
input logic CLK200MHZ,
SOMETYPE aarrgghh);
But getting it to work syntactically has been challenging. Giving SOMETYPE a default value doesn't work because Vivado complains about not allowing hierarchical types, so right off the bat I don't think this will work. When instantiating, I tried using the full modport name, the full modport name with the instantiated interface, and a few others, but nothing seems to work.
So I am curious if there is a clever way I can have multiple instantiations of some_block, each taking a different generated modport. And if not, is there some fun clever trick I can do to use the generated modports? The idea in the first place was that I have a thing that has one writer and multiple readers. I wanted to generate a modport for each reader so that it could only touch it's own read address. I guess I could always just parameterize some_block on an integer, pass some_block the whole interface, and then rely on some_block to only touch the read address corresponding to the passed in integer, but that might be error prone.
Assuming that 'generate' works, there is nothing to be concerned about modules. There is no need to pass a type parameter. The module port is just supposed to be of the type of your interface.
module top();
some_interface ifc;
for (genvar gi = 0; gi < NUM_REASDERS; gi++) begin: inst
some_block sb(ifc.Reader[gi].Modport);
end
endmodule
module some_block (some_interface ifc);
always_comb myvar = ifc.read_addr;
some_block just always references the 'read_addr' which is the modport var. You can use a generate block in the 'top' module.

assignment in SystemVerilog, compilation error - token is 'assign'

I have this code:
integer [31:0]R;
integer [15:0]R_f1;
integer [15:0]R_f2;
assign R_f1 = R[15:0];
assign R_f2 = R[31:16];
But it is not compiled because of assign.
What changes do I need to do ? It can also be in the header file.
There was a bug in the original implementation of Verilog-XL that it ignored the packed dimensions of integer declarations. And integer/int/byte did not have a fixed size. For these reasons, SystemVerilog disallows specifying packed dimensions for any of these built-in types. Use bit or logic instead.
Also, since you tagged this with SystemVerilog make sure the file has a *.sv suffix. An alternative to what you are trying to do is
integer [31:0]R;
let R_f1 = R[15:0];
let R_f2 = R[31:16];
Depending on the language you use. In verilog, only the net types can be assigned using continuous assignment. integer is not a net type, therefore theses assignments are not allowed in verilog. I guess you compiled your code in verilog mode and got the message about assignment statements.
Also packed dimensions on integer types are not allowed. So, the following declaration is illegal: integer [31:0]R;. Some compilers will just ignore the declaration. All integers are 32 bit wide in any case.
So, to fix it in verilog mode you can use always #* instead:
integer R = 10;
integer R_f1;
integer R_f2;
always #* R_f1 = R[15:0];
always #* R_f2 = R[31:16];
Though by the sound of your initial question, you need to use a different type of the data type, which allows you to have real vectors. In verilog they are reg and one of the net types, i.e. wire. With wires you can use assign statement, with reg you need to use always blocks. Something like the following:
reg[31:0] R = 10;
reg[15:0] R_f1;
reg[15:0] R_f2;
always #* R_f1 = R[15:0];
always #* R_f2 = R[31:16];
Since you marked your question as a system verilog question, you can use one of the system verilog types, i.e. logic or bit. If you use those, you can apply both, assign or always blocks to them. BTW, assign will also work for integeres.
logic[31:0] R = 10;
logic[15:0] R_f1;
logic[15:0] R_f2;
assign R_f1 = R[15:0];
assign R_f2 = R[31:16];
just make sure that you compile in a system-verilog mode.

Extract Types/Classnames from flat Modelica code

I was wondering if there already exists a possibility to extract from flat Modelica code all variables AND their corresponding types (classnames respectively).
For example:
Given an extract from a flattened Modelica model:
constant Integer nSurfaces = 8;
constant Integer construction1.nLayers(min = 1.0) = 2 "Number of layers of the construction";
parameter Modelica.SIunits.Length construction1.thickness[construction1.nLayers]= {0.2, 0.1} "Thickness of each construction layer";
Here, the wanted output would be something like:
nSurfaces, Integer, constant;
construction1.nLayers, Integer, constant;
construction1.thickness[construction1.nLayers], Modelica.SIunits.Length, parameter
Ideally, for construction1.thickness there would be two lines (=number of construction1.nLayers).
I know, that it is possible to get a list of used variables from the dsin.txt, which is produced while translating a model. But until now I did not find an already existing way to get the corresponding types. And I really would like to avoid writing an own parser :-).
You could try to generate the file modelDescription.xml as defined by the FMI standard. It contains a ton of information and XML should be easier to parse, e.g. python has a couple of xml parsing/reading packages.
If you are using Dymola you just set the flag Advanced.FMI.GenerateModelDescriptionInterface2 = true to generate the model description file.
The second idea could be to let the compiler/tool parse the Modelica file for you as they need to do that anyway, try searching for AST (abstract syntax tree). In Dymola, this is available through the ModelManagement library, and also through the Python interface.
Third idea could be to use one of the Modelica parsers available, e.g. have a look at:
https://github.com/lbl-srg/modelica-json
https://hackage.haskell.org/package/modelicaparser
https://github.com/xie-dongping/modparc
https://github.com/pymoca/pymoca
https://github.com/pymola/pymola/tree/master/src/pymola
Fourth, if all that did not work, you still do not have to write a full parser, you could use ANTLR, then use an existing grammar file (look for e.g. modelica.g4).

System verilog: Passing parameters to package

I have to update few enumerated data types which are declared inside a package and mine is a special scenario where the size of my enum data type will vary with a parameter value.
I have to make that parameter value somehow visible to the package.
I am aware that packages are not the components that can be instantiated. Hence I cannot pass the parameters directly.
Could anyone help me in getting my requirement done with help of some tweaks.
PS: The requirement is related to TB
What we usually do for types of lengths that have to be parameterized is use defines instead of package parameters:
package some_package_pkg;
`ifndef MAX_DATA_WIDTH
`define MAX_DATA_WIDTH 32
typedef [`MAX_DATA_WIDTH-1:0] bit some_type;
...
endpackage
By default, MAX_DATA_WIDTH is 32, but if we need a bigger width, we just pass the define from the command line. For Incisive it is something like:
irun -D MAX_DATA_WIDTH=64 some_package_pkg.sv
If you want to retrofit an existing package that uses a parameter you could do:
package some_param_package_pkg;
parameter P_MAX_DATA_WIDTH = `MAX_DATA_WIDTH; // just add this line
typedef [P_MAX_DATA_WIDTH-1:0] bit some_type; // all declaration are unchanged
endpackage

Why some variable of struct take preprocessor to function?

Variables of struct declared by data type of language in the header file. Usually data type using to declare variables, but other data type pass to preprocessors. When we should use to a data type send to preprocessor for declare variables? Why data type and variables send to processor?
#define DECLARE_REFERENCE(type, name) \
union { type name; int64_t name##_; }
typedef struct _STRING
{
int32_t flags;
int32_t length;
DECLARE_REFERENCE(char*, identifier);
DECLARE_REFERENCE(uint8_t*, string);
DECLARE_REFERENCE(uint8_t*, mask);
DECLARE_REFERENCE(MATCH*, matches_list_head);
DECLARE_REFERENCE(MATCH*, matches_list_tail);
REGEXP re;
} STRING;
Why this code is doing this for declarations? Because as the body of DECLARE_REFERENCE shows, when a type and name are passed to this macro it does more than just the declaration - it builds something else out of the name as well, for some other unknown purpose. If you only wanted to declare a variable, you wouldn't do this - it does something distinct from simply declaring one variable.
What it actually does? The unions that the macro declares provide a second name for accessing the same space as a different type. In this case you can get at the references themselves, or also at an unconverted integer representation of their bit pattern. Assuming that int64_t is the same size as a pointer on the target, anyway.
Using a macro for this potentially serves several purposes I can think of off the bat:
Saves keystrokes
Makes the code more readable - but only to people who already know what the macros mean
If the secondary way of getting at reference data is only used for debugging purposes, it can be disabled easily for a release build, generating compiler errors on any surviving debug code
It enforces the secondary status of the access path, hiding it from people who just want to see what's contained in the struct and its formal interface
Should you do this? No. This does more than just declare variables, it also does something else, and that other thing is clearly specific to the gory internals of the rest of the containing program. Without seeing the rest of the program we may never fully understand the rest of what it does.
When you need to do something specific to the internals of your program, you'll (hopefully) know when it's time to invent your own thing-like-this (most likely never); but don't copy others.
So the overall lesson here is to identify places where people aren't writing in straightforward C, but are coding to their particular application, and to separate those two, and not take quirks from a specific program as guidelines for the language as a whole.
Sometimes it is necessary to have a number of declarations which are guaranteed to have some relationship to each other. Some simple kinds of relationships such as constants that need to be numbered consecutively can be handled using enum declarations, but some applications require more complex relationships that the compiler can't handle directly. For example, one might wish to have a set of enum values and a set of string literals and ensure that they remain in sync with each other. If one declares something like:
#define GENERATE_STATE_ENUM_LIST \
ENUM_LIST_ITEM(STATE_DEFAULT, "Default") \
ENUM_LIST_ITEM(STATE_INIT, "Initializing") \
ENUM_LIST_ITEM(STATE_READY, "Ready") \
ENUM_LIST_ITEM(STATE_SLEEPING, "Sleeping") \
ENUM_LIST_ITEM(STATE_REQ_SYNC, "Starting synchronization") \
// This line should be left blank except for this comment
Then code can use the GENERATE_STATE_ENUM_LIST macro both to declare an enum type and a string array, and ensure that even if items are added or removed from the list each string will match up with its proper enum value. By contrast, if the array and enum declarations were separate, adding a new state to one but not the other could cause the values to get "out of sync".
I'm not sure what the purpose the macros in your particular case, but the pattern can sometimes be a reasonable one. The biggest 'question' is whether it's better to (ab)use the C preprocessor so as to allow such relationships to be expressed in valid-but-ugly C code, or whether it would be better to use some other tool to take a list of states and would generate the appropriate C code from that.