How to initialize unpacked array of unpacked union of unpacked structs? - system-verilog

What is the legal method of initializing this?
module tb();
typedef struct {
logic [3:0] A;
} a_t;
typedef struct {
logic [7:0] B;
} b_t;
typedef union {
a_t a;
b_t b;
} a_b_t;
a_b_t a_b [8];
initial begin
a_b <= '{default: '{default: 0}};
end
endmodule
xrun gives this error:
xmelab: *E,APBLHS (./tmp.sv,14|23): Assignment pattern - LHS must be an array or structure [SystemVerilog].
I've tried a variety of other ways, and I can't quite get this right. I'm working around it right now by initializing each entry separately with 2 lines of initialization.

As the error message state, assignment patterns only work with struct and arrays, not unions. You would need to use a foreach loop to assign each union member.
initial
foreach (a_b[i]) begin
a_b[i].a <= '{default:0};
a_b[i].b <= '{default:0};
end
Note that unless you are using the DPI for C compatibility, unpacked unions have little usefulness in SystemVerilog. Use packed unions instead.

Related

What is meant by this SystemVerilog typedef enum statement?

typedef enum logic [1:0] {S0, S1, S2} statetype;
Does this statement mean that any variable declared as 'statetype' can only take three values, 2'b00, 2'b01, and 2'b10? If so, what happens if I assign the said variable with the value 2'b11?
The IEEE Std 1800-2017, section 6.19.3 Type checking, states:
Enumerated types are strongly typed; thus, a variable of type enum
cannot be directly assigned a value that lies outside the enumeration
set unless an explicit cast is used or unless the enum variable is a
member of a union. This is a powerful type-checking aid, which
prevents users from accidentally assigning nonexistent values to
variables of an enumerated type. The enumeration values can still be
used as constants in expressions, and the results can be assigned to
any variable of a compatible integral type.
Enumerated variables are type-checked in assignments, arguments, and
relational operators.
What I observe in practice is that some simulators issue a compile warning while others issue a compile error. You can see what happens on multiple simulators on edaplayground (if you sign up for a free account there).
For example, with VCS, the following code:
module tb;
typedef enum logic [1:0] {S0, S1, S2} statetype;
statetype s;
initial begin
s = S0;
$display("n=%s,s=%0d,", s.name(), s);
s = 3;
$display("n=%s,s=%0d,", s.name(), s);
end
endmodule
issues this warning:
Warning-[ENUMASSIGN] Illegal assignment to enum variable
tb.v, 16
tb, "s = 3;"
Only expressions of the enum type can be assigned to an enum variable.
The type int is incompatible with the enum 'statetype'
Expression: 3
Use the static cast operator to convert the expression to enum type.
but, it still runs the simulation and prints:
n=S0,s=0
n=,s=3
I believe the question should be rephrased to say that what is this is happening in our test-bench and how to avoid it. This will gives us more cleaner and bug free code.
efficient code to avoid the confusion:
typedef enum logic [1:0] {S0, S1, S2} statetype;
module top();
statetype st_e;
initial begin
for(int val=0;val<4; val++) begin
// casting for avoid confusion and gotchas
if (!$cast(st_e,val)) begin
$error("Casting not possible -> statetype:%0s and val:%0d",st_e,val);
end else begin
$display("statetype:%0s and val:%0d",st_e,val);
end
end
end
endmodule: top
This code is already there in edaplayground feel free to try it and update it. This could be replace with the sv macro for more efficiency. Please let me know I will provide the example for macros.
Output will be:
# run -all
# statetype:S0 and val:0
# statetype:S1 and val:1
# statetype:S2 and val:2
# ** Error: Casting not possible -> statetype:S2 and val:3
# Time: 0 ns Scope: top File: testbench.sv Line: 14
# exit

Concatenating elements of unpacked array together

I am using the following function in my System Verilog code. I wondered if there was an idiomatic way of achieving the same effect that perhaps would not require the width to be hardwired. I tried streaming operators, but could not quite get them to work. I need to use unpacked arrays. Many thanks.
function bit [64:0] cat8 (bit [7:0] a[8]);
return { a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0] };
endfunction;
since you reversing the array in concat, there is no good way to express it.
you have:
bit [7:0] a[8];
which is equivalent to
bit [7:0] a[0:7];
in your concat you start with a[7] in the most significant bits whether 7 is the least significant index in the array.
This is the reason why the streaming operators did not work in your case.
So, if you really need to reverse the array, than you have what you have, otherwise you can find that these 2 things are equivalent:
{ a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7] }
and
{ >> {a}}
of course you can declare your array as bit [7:0] a[7:0] and keep index ordering in concat as you have. But it will not reverse the array again, as in the above case.
you can define a new datatype through typedef.
typedef bit[7:0] octet;
typedef octet upack[7:0];
function bit [64:0] cat8 (upack a);
// your code
endfunction;
Below should work for you
module top;
function bit [63:0] cat8 (bit [7:0] a[8]);
return { <<8{a}};
endfunction;
bit [7:0] arr[8];
initial begin
arr= '{1,2,3,4,5,6,7,8};
foreach (arr[i])$display("%h", arr[i]);
$display("%h", cat8(arr));
end
endmodule

Decode name of packed struct member based on bit position

I have a register map which is generated with a script. The output of the module is one huge packed struct. This is normally not a problem, but when I lint my code I get warnings like this:
*W,UNCONO (./module_name.v,158):: 'reg[1415]' is not connected.
So I can see that one of my register bits isn't getting used, which is bad, but which one is it? How do I map the bit position in the packed struct back to the named struct member?
To clarify I am looking for a function of some sort that will take a bit position as input and returns the struct member name as an output.
In a packed struct, the bits are numbered right to left, 0 to N-1. So, if you have
typedef struct packed {
logic sign;
logic [7:0] exponent;
logic [22:0] mantissa;
} Float32;
Float32 F;
then
assert (F.sign === F[31]);
assert (F.exponent === F[30:23]);
assert (F.mantissa === F[22:0]);

Passing unpacked array type as parameter

I created a module to soemthing simple like add some pipeline delay. I made the data type a parameter so it could handle complex things like structs. I have something like this:
module pipe
#(parameter type T = int,
parameter DELAY = 0)
(
input clk,
input T data_in,
output T data_out);
T pipe[DELAY];
always_ff #(posedge clk) begin
pipe[0] <= data_in;
for(int i = 1; i<DEPTH; i++) begin
pipe[i] <= pipe[i-1];
end
end
assign data_out = pipe[DELAY-1];
endmodule
This works great but then I found myself wanting to use it with an unpacked array and I couldn't figure out how to instance it. It would look something like this, but I don't think this is right:
logic [7:0] my_data [16];
logic [7:0] my_data_delayed [16];
pipe #(.T(logic [7:0] [16]), .DELAY(2)) i_pipe
(
.clk(clk),
.data_in(my_data),
.data_out(my_data_delayed)
);
Is there a way to get the type of a variable so it can be passed to this parameter?
You can use typedef do define the data type:
typedef logic [7:0] my_type [16];
my_type my_data;
my_type my_data_delayed;
pipe #(.T(my_type), .DELAY(2)) i_pipe
(
.clk(clk),
.data_in(my_data),
.data_out(my_data_delayed)
);
The remaining question is if it will work with your simulator. I tried it out at EDAplayground, worked with VCS but not Riviera-PRO (got a "not supported in this release" message)
I was able to get typedef struct { logic [7:0] data [16]; } my_type; to work. Less clean but it is a workaround.
While typing the question I figured out one answer. The type operator (section 6.23 in IEEE 1800-2012) spec does what I need. So my instance would look like this:
logic [7:0] my_data [16];
logic [7:0] my_data_delayed [16];
pipe #(.T(type(my_data)), .DELAY(2)) i_pipe
(
.clk(clk),
.data_in(my_data),
.data_out(my_data_delayed)
);
Of course this results in a compile error in my tool so it doesn't look to be universally supported.
My work-around is going to be to make an array of instances of the pipe module.

What is advantage of structure?

I'm Verilog user, so I am unfamiliar with SystemVerilog.
Now I'm trying to study structure literals.
What is advantage of using structure?
Structure in SystemVerilog is more or less similar to structure usage in C-language, structure is a collection of different data types, variables or constants under single name. For more details you can always refer SystemVerilog LRM IEEE Std 1800-2012 ♦ 7.2 Structures
I will here explain the more common usage and advantage of structures.
The declaration of structure can be done by variable or nets, A structure as a whole can be declared as variable by using var keyword and a structure can be defined as net using Verilog data type wire or tri, when defined as net type all members of structure should be 4-state types.
structure variable:
var struct {
logic [15:0] a, b;
logic [ 7:0] data;
logic [31:0] width;
} data_word_var;
structure net:
wire struct {
logic [15:0] a, b;
logic [ 7:0] data;
logic [31:0] width;
} data_word_net;
If we don't mentioned the type of structure by default it will be net type and note that a net type variable cannot be declared inside a structure despite a whole structure can be of net type.
Structure can be initialized as a whole
data_word_net dw = ’{16'hf0f0, 16'h1010, 8’d3, 0};
or individual members can be initialized
data_word_net dw;
dw.data = 8'b1011_1111;
It is also possibe that we can initialize using member names
data_word_net dw = ’{a:16'hf0f0, b:16'h1010, data:8’d3, width:0}; // legal
data_word_net dw = ’{a:16'hf0f0, data:8’d3, b:16'h1010, width:0}; // legal
data_word_net dw = ’{a:16'hf0f0, 8’d3, 16'h1010, width:0}; // illegal(all members should be mentioned do not mix both)
Also members can be initialized to their default values by using default keyword
typedef struct {
real r0, r1;
int i0, i1;
logic [ 7:0] a;
logic [23:0] addr;
} data_word;
data_word dw;
dw = ’{ real:1.0, default:0, r1:3.1415 };
Structure can be used through module ports
package my_pkg;
typedef struct {
logic [31:0] a, b;
} input_ports;
typedef struct {
logic [63:0] y;
} output_ports;
endpackage
module alu
(input my_pkg::input_ports inp,
output my_pkg::output_ports outp,
input wire clock);
...
endmodule
Structure can also be used as arguments to tasks and functions
module dut (...);
...
typedef struct {
logic [31:0] a, b;
logic [63:0] width;
logic [15:0] addr;
} i_pins;
function alu (input i_pins connect);
...
endfunction
endmodule
In addition to the above advantages language also supports array of structures in packed and unpacked format as shown below
typedef struct packed { // packed structure
logic [7:0] a;
logic [7:0] b;
} packet_t;
packet_t [15:0] packet_array; // packed array of 16 structures
typedef struct { // unpacked structure
int a;
real b;
} data_t;
data_t data_array [15:0]; // unpacked array of 16 structures