How do I access elements in a packed struct by index? - verilog

I have the following structs:
typedef struct packed {
type1_t info1;
type2_t info2;
} module_info_registers_t;
typedef struct packed {
logic [0:0] data1;
logic [2:0] data2;
logic [11:0] data3;
logic [15:0] data4;
} info1;
typedef struct packed {
logic [1:0] data1;
logic [3:0] data2;
logic [10:0] data3;
logic [14:0] data4;
} info2;
As you can see, type1_t and type2_t are defined as 32-bit data structures.
I want to instantiate the following:
module_info_registers_t myregs;
and I want to access the registers based on index (rather than having to type myreqs.info2.data4):
myregs[1].data4
This is because the definition of module_info_registers_t will change from time to time and is autogenerated, so I don't want to hardcode 'info2' in my RTL
However, I am getting an error saying that I can't have a slice on a scalar object.
I understand that for some reason I can't access the data in the way I want to. Is there another way I can do what I am trying to achieve?

There is no way in verilog to do what you want. You might get around using macros, or bit-level access to the struct fields.
Macros can be done like this:
`define ACCESS_REG(R, NUM) R.info``NUM
module_info_registers_t regs;
`ACCESS_REG(regs, 1).data1 = 0;
The above will work, assuming certain naming conventions applied to the fields.
with bit-level access you need to be able to calculate offset and width of every struct member, making declaration and usage more complicated. Here is a very simplified System Verilog example for clarity:
typedef struct packed {
logic [1:0] f1;
logic [2:0] f2;
logic [3:0] f3;
} sp_t;
sp_t sp;
sp[$bits(sp.f3) + $bits(sp.f2) +: $bits(sp.f3)] = 2'b10;
The above example will set 'sp.f1'.
So, in your case you can create arrays of parameters describing offset and widths of the corresponding fields and use them for indexing. So, something like that might work in your case:
parameter int info[2] = {0, 32};
parameter int data1Offset[2] = {31, 30};
parameter int data1Width[2] = {1, 2};
module_info_registers_t regs;
regs[info[1] + data1Offset[1] +: data1Width[1]] = 0;

Related

Using typedef with wire in SystemVerilog

When using typedef to declare a user-defined type, both these forms are accepted by EDA Playground:
typedef reg[4:0] reg5;
typedef logic[4:0] logic5;
However, if doing something similar based on wire type, then this format fails:
typedef wire[4:0] wire5;
I get "Syntax Error".
How can that be explained?
It is illegal to declare a typedef with a wire type, according to the IEEE Std 1800-2017. Refer to section 6.18 User-defined types:
type_declaration ::= // from A.2.1.3
typedef data_type type_identifier { variable_dimension } ;
A wire is not a data_type, whereas reg and logic are. A wire is a net_type.
A typedef defines a datatype that can be applied to a net or variable object kinds. Things are confusing to maintain backward compatibility with Verilog because of implicit definitions.
When you see
logic [4:0] v;
This is implicitly a variable declaration a with an explicit 5-bit 4-state packed array datatype.
var logic [4:0] v;
When you see
wire [4:0] w;
This is explicitly a net declaration a with a 5-bit implicit 4-state packed array datatype.
wire logic [4:0] w;
You can use a typedef for both:
typedef logic [4:0] uint5;
var uint5 v; // var can be implicit
wire uint5 w;
Note that module input and inout ports have wire as the implicit object kind. Also reg and logic are synonyms for 4-state types with logic being the preferred keyword. A reg is not always associated with a register.

Mask a field on a packed struct in SystemVerilog

I am looking for the best way to mask a field inside a packed struct.
Imagine you have:
typedef struct packed {
logic [5:0] add;
logic [3:0] data;
logic [1:0] control;
} mytype;
I want to assign to a new signal a signal with the data masked to zero. In my case, the struct has many fields so I prefer not to assign them one by one if possible, like this:
my_type new_signal;
assign new_signal.add = old_signal.add;
assign new_signal.data = '0;
assign new_signal.control = old_signal.control;
I need it to compare the old signal against a different signal, except for 3 fields.
You can do this in procedural code by assigning the whole signal first, then assigning the individual fields you want to mask out.
always_comb begin
new_signal = old_signal;
new_signal.data = '0;
end
Another way is to use 'packed' vector for the struct. If you know your offsets in the struct you can build a mask. In your case the following will work:
new_signal = old_signal & 12'b111111_0000_11;
------------------------------^^^^^^_----_^^
add....data.control

Using SystemVerilog structs that contain parameters as input/output ports to a module

My struct contains parameters that vary per module. I'd like to use this struct to pass input/outputs to these modules. I'm using this for design so it has to be synthesizable and my toolchain doesn't support Interfaces unfortunately.
For example:
`ifdef MY_STRUCTS
`define MY_STRUCTS
typedef struct packed {
logic [PARAMETER_VAL-1:0] field1;
logic [PARAMETER1_VAL-1:0] field2;
} myStruct_t;
`endif
module top #(
parameter PARAMETER_VAL = 8;
parameter PARAMETER1_VAL = 16;
) (
input myStruct_t in_packet,
output myStruct_t out_packet,
);
Unfortunately, this seems to be a chicken-or-egg problem. The struct definition can't be compiled because it relies on the module parameters to define it. However, the input/output declarations can't be declared because it relies on the struct to know what to declare.
Does anyone have a solution to this? Would definitely appreciate suggestions.
Potentially you can also use a parameterized interface.
Disclaimer: the following code works with synopsys but fails with cadence in eda playground. I think that Cadence is in violation of the standard here (They might have fixed it in the latest version).
Anyway, here is the example
interface top_if #(int PARAMETER_VAL = 8, PARAMETER1_VAL = 16) ();
typedef struct packed {
logic [PARAMETER_VAL-1:0] field1;
logic [PARAMETER1_VAL-1:0] field2;
} myStruct_t;
myStruct_t in_packet, out_packet;
modport in (input in_packet);
modport out (output out_packet);
endinterface
module caller();
top_if #(8,16) top_if();
always_comb top_if.in_packet = '{11, 22};
top top(top_if.in, top_if.out);
logic [top_if.PARAMETER1_VAL-1:0] field2;
always_comb field2 = top_if.out_packet.field2;
always #* begin
$display("out.field2=%0d", field2);
end
endmodule
module top(
top_if in,
top_if out
);
logic [in.PARAMETER_VAL-1:0] field1;
always_comb field1 = in.in_packet.field1;
always_comb out.out_packet = '{field1, field1+55};
always #* begin
$display("input.field1=%d", field1);
end
endmodule
Two options:
Instead of passing a list of parameter values, pass a single struct typedef with the field widths you need. You would likely want to use the struct in the upper level anyway.
module upper;
typedef struct packed {
logic [7:0] field1;
logic [16:0] field2;
} myStruct_t;
my_Struct in, out;
lower #(.T(my_Struct_t) ins1 (in, out);
...
endmodule
module lower #(type T) (
input T in_packet,
output T out_packet,
);
...
endmodule
Create the struct type inside the lower level module, but keep the ports as packed arrays. This works because the struct is packed as well.
module top #(
parameter PARAMETER_VAL = 8;
parameter PARAMETER1_VAL = 16;
) (
input logic [PARAMETER_VAL+PARAMETER_VAL1-1:0] in,
output logic [PARAMETER_VAL+PARAMETER_VAL1-1:0] out,
);
typedef struct packed {
logic [PARAMETER_VAL-1:0] field1;
logic [PARAMETER1_VAL-1:0] field2;
} myStruct_t;
myStruct_t in_packet, out_packet;
assign in_packet = in;
assign out = out_packet;

Using the struct datatype in module in systemverilog

I need to use a struct datatype in the module in SystemVerilog. Some members of the struct contain an array. I get the error "incompatible complex type assignment". I have the following structs contained in common.sv:
typedef struct {
logic[1:0] num;
logic val;
} lit;
typedef lit lit_array[1:0];
typedef struct {
lit_array lits;
logic[1:0] len;
} clause;
typedef clause clause_array[2:0];
typedef struct {
clause_array clauses;
logic[2:0] len;
} formula;
typedef formula formula_array[4:0];
When I try to use the "formula" datatype in module as below, I get the "incompatible complex type assignment" error. The following is the code.
`include "common.sv"
module propagateliteral(input logic clock, reset, find,
input lit in_lit,
input formula in_formula,
output logic ended, empty_clause, empty_formula);
//my system-verilog code
The testbench code:
`include "common.sv"
module pl_test();
logic clock, reset, find;
lit in_lit;
formula in_formula;
logic ended, empty_clause, empty_formula;
propagateliteral test1(clock, reset, find, in_lit, in_formula, ended,
empty_clause, empty_formula);
always
begin
clock=1'b1; #50; clock=1'b0; #50;
end
initial
begin
reset=1'b1; find=1'b0;
#160;
reset=1'b0; find=1'b0;
#100;
reset=1'b0; find=1'b1; in_lit='{2'b01,1'b1};
in_formula='{{{{{2'b01,1'b1},{2'b10,1'b1},{2'b00,1'b1}},2'b10}, //clause0
{{{2'b10,1'b1},{2'b11,1'b1},{2'b00,1'b1}},2'b10}, //clause1
{{{2'b01,1'b1},{2'b10,1'b1},{2'b11,1'b1}},2'b11}, //clause2
{{{2'b01,1'b0},{2'b10,1'b1},{2'b11,1'b0}},2'b11}, //clause3
{{{2'b01,1'b0},{2'b10,1'b1},{2'b11,1'b0}},2'b11}, //clause4
{{{2'b01,1'b0},{2'b10,1'b1},{2'b11,1'b0}},2'b11}, //clause5
{{{2'b01,1'b0},{2'b10,1'b1},{2'b11,1'b0}},2'b11}},3'b100}; //clause6
end
endmodule
After I did some searching, I found that I can not pass unpacked struct datatype. Is there a better way to redefine those structs so that I can use them in the module. Sorry, I'm a newbie to SystemVerilog and I may have not used the correct technical terms in describing my problem. Any help is appreciated.
You need to make sure the struct definition comes from the same package, then repeatedly import the same package for each module. See http://go.mentor.com/package-import-versus-include

SystemVerilog TypeDef Can;t index object with zero packed or unpacked array dimensions

I am currently attempting to use TypeDef in SystemVerilog in order to define a new data structure object containing a 8 bit unsigned register and an 32-bit signed integer but I keep getting the error:
Error (10053): Verilog HDL error at UART.v(35): can't index object "data" with zero packed or unpacked array dimensions
I have recreated a simple implementation below where the topLevelModule instances a lowLevelModule which determines the values of both the integer and 8-bit unsigned register in which the structure is made up of and outputs them to the topLevelModule.
Using a separate UART module I am attempting to send this structure/object (which is 40bits long) to a host computer- to simplify the code below I have omitted this module and left out the majority of the non-associated code.
typedef struct {
reg[7:0] identifier;
integer currentSynapticWeight;
} dataPacket;
module topLevel(clk, reset, UART_TXD);
input clk; // Clock Signal
input reset; // Reset Signal
output UART_TXD; // Output Signal
dataPacket data; // Instance the dataPacket Object
lowLevelModule LLM1(clk, reset, data);
// CODE TO DRIVE THE UART CONNECTION OMMITED
endmodule
module lowLevelModule(clk, reset, data);
input clk; // Clock Signal
input reset; // Reset Signal
output dataPacket data; // Instance the dataPacket Object
reg[7:0] someUnsigned8BitUnsignedReg = 8'b10001000;
integer someIntegerValue = 25;
always #(*)
begin
data[39:32] = someUnsigned8BitUnsignedReg;
data[31:0] = someIntegerValue;
end
endmodule
Any help would be greatly appreciated, I am not sure if I have used TypeDef in the correct manor.
You declared data as an unpacked structure - you cannot access it as an integral packed array. Either change your assignments to unpacked members of the struct:
data.identifier = someUnsigned8BitUnsignedReg;
data.currentSynapticWeight = someIntegerValue;
Or change your typedef to define a packed struct
typedef struct packed {
reg[7:0] identifier;
integer currentSynapticWeight;
} dataPacket;

Resources