What is advantage of structure? - system-verilog

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

Related

In DPI-C, How to map data type to reg or wire

I am writing a CRC16 function in C to use in System Verilog.
Requirement as below:
Output of CRC16 has 16 bits
Input of CRC16 has bigger than 72 bits
The difficulty is that I don't know whether DPI-C can support map data type with reg/wire in System Verilog to C or not ?
how many maximum length of reg/wire can support to use DPI-C.
Can anybody help me ?
Stay with compatible types across the language boundaries. For output use shortint For input, use an array of byte in SystemVerilog which maps to array of char in C.
Dpi support has provision for any bit width, converting packed arrays into c-arrays. The question is: what are you going to do with 72-bit data at c side?
But, svBitVecVal for two-state bits and svLogicVecVal for four-stat logics could be used at 'c' side to retrieve values. Look at H.7.6/7 of lrm for more info.
Here is an example from lrm H.10.2 for 4-state data (logic):
SystemVerilog:
typedef struct {int x; int y;} pair;
import "DPI-C" function void f1(input int i1, pair i2, output logic [63:0] o3);
C:
void f1(const int i1, const pair *i2, svLogicVecVal* o3)
{
int tab[8];
printf("%d\n", i1);
o3[0].aval = i2->x;
o3[0].bval = 0;
o3[1].aval = i2->y;
o3[1].b = 0;
...
}

How to initialize unpacked array of unpacked union of unpacked structs?

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.

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.

Why I get a syntax error when using typedef in verilog?

I don not know what is wrong here. I use a modelsim SE 6.5b. Then when I use "typedef" I get a syntax error.
`timescale 1ns/10ps
// Type define a struct
typedef struct {
byte a;
reg b;
shortint unsigned c;
} myStruct;
module typedef_data ();
// Full typedef here
typedef integer myinteger;
// Typedef declaration without type
typedef myinteger;
// Typedef used here
myinteger a = 10;
myStruct object = '{10,0,100};
initial begin
$display ("a = %d", a);
$display ("Displaying object");
$display ("a = %b b = %b c = %h", object.a, object.b, object.c);
#1 $finish;
end
typedef is a SystemVerilog keyword, not Verilog.
To enable SystemVerilog on Modelsim you need to add the -sv compile option and/or rename the file to with a .sv extension.
Your code works fine on Modelsim 10.1d. See example on EDA Playground (I had to add an endmodule but it's otherwise unmodified).
I'd suggest checking your compile flags to ensure you're enabling support for SystemVerilog during compilation.

Connecting hierarchical modules: struct vs interface in SystemVerilog

In SystemVerilog hierarchical modules can be connected by simple data types, complex data types (structs, unions, etc), or interfaces. The feature that I am interested in is aggregating all signals between two modules in one place which simplifies maintenance of the code.
For example in the following one change s_point's definition without changing the declarations of m1, m2, and top:
typedef struct {
logic [7:0] x;
logic [7:0] y;
} s_point; // named structure
module m1 (output s_point outPoint);
//
endmodule
module m2 (input s_point inPoint);
//
endmodule
module top ();
s_point point;
m1 m1_inst (point);
m2 m2_inst (point);
endmodule
Alternatively, this could have been done using interfaces.
However, I believe using structures are easier and they are supported by more CAD tools, and they don't need to be instantiated as is the case for interfaces (although one still has to declare them in the top module).
My question is if only aggregating signals is required (i.e. no interest in interface's task, functions, modports, generic interface, internal always blocks etc) for a synthesizable design, which one is preferred?
interface is preferred.
A struct okay to use only when all the signals within the struct all follow the same port direction; input, output, or inout wire. It becomes challenging to use structs when driving directions become mixed. Mixed direction is a allow using the ref keyword, however the ref keyword is not supported by many synthesis tools, yet. inout cannot be used because logic is considered a variable, IEEE Std 1800-2012 § 6.5 Nets and variables. However, inout wire can be used to cast the struct as a net. The components of a stuct can not be assigned within an always-block and needs an assign statement instead; just like a regular wire.
An interface should be grouping signals where the port direction is not consistent. Tri-states need to be defined as wire and the variable types do not require explicit port direction when used in conjunction with always_{ff|comb|latch}. It should also be used if the signals are part of a protocol. This way assertions can be added and it can be connected to a classes for an UVM test-bench or other SVTB environment.
Use a sturct when only passing a explicit direction data type. Use an interface for passing shared signals.
Example Senario:
Imagine there is a collection of signals x,y,&z, where module m_x drives x and reads y&z, module m_b drive y and reads x&z, and module m_z drives z and reads x&y. Each signals have only one driver and always_ff can be used to guarantee this.
If we try adding a bidirectional tri-state bus, to the mix then the struct cannot be used. A wire resolves conflicting drivers while logic/reg clobber and keep the scheduler running.
Sample code:
Using struct using ref (no tri-state allowed):
typedef struct {logic [7:0] x, y, z, bus; } s_point;
module m_x_st (ref s_point point, input clk);
always_ff #(posedge clk)
point.x <= func(point.y, point.z);
//assign point.bus = (point.y!=point.z) ? 'z : point.x; // NO tir-state
endmodule
module m_y_st (ref s_point point, input clk);
always_ff #(posedge clk)
point.y <= func(point.x, point.z);
//assign point.bus = (point.x!=point.z) ? 'z : point.y; // NO tir-state
endmodule
module m_z_st (ref s_point point, input clk);
always_ff #(posedge clk)
point.z <= func(point.x, point.y);
//assign point.bus = (point.x!=point.y) ? 'z : point.z; // NO tir-state
endmodule
module top_with_st (input clk);
s_point point;
m_x_st mx_inst (point,clk);
m_y_st my_inst (point,clk);
m_z_st mz_inst (point,clk);
endmodule
Using struct using inout wire (nets must be driven with assign, loses single driver guarantee):
typedef struct {logic [7:0] x, y, z, bus; } s_point;
module m_x_wst (inout wire s_point point, input clk);
logic [$size(point.x)-1:0] tmp;
assign point.x = tmp;
always_ff #(posedge clk)
tmp <= func(point.y, point.z);
assign point.bus = (point.y!=point.z) ? 'z : point.x; // tir-state
endmodule
module m_y_wst (inout wire s_point point, input clk);
logic [$size(point.y)-1:0] tmp;
assign point.y = tmp;
always_ff #(posedge clk)
tmp <= func(point.x, point.z);
assign point.bus = (point.x!=point.z) ? 'z : point.y; // tir-state
endmodule
module m_z_wst (inout wire s_point point, input clk);
logic [$size(point.z)-1:0] tmp;
assign point.z = tmp;
always_ff #(posedge clk)
tmp <= func(point.x, point.y);
assign point.bus = (point.x!=point.y) ? 'z : point.z; // tri-state
endmodule
module top_with_wst (input clk);
wire s_point point; // must have the 'wire' keyword
m_x_wst mx_inst (point,clk);
m_y_wst my_inst (point,clk);
m_z_wst mz_inst (point,clk);
endmodule
Using interface (with tri-state):
interface if_point;
logic [7:0] x, y, z;
wire [7:0] bus; // tri-state must be wire
endinterface
module m_x_if (if_point point, input clk);
always_ff #(posedge clk)
point.x <= func(point.y, point.z);
assign point.bus = (point.y!=point.z) ? 'z : point.x;
endmodule
module m_y_if (if_point point, input clk);
always_ff #(posedge clk)
point.y <= func(point.x, point.z);
assign point.bus = (point.x!=point.z) ? 'z : point.y;
endmodule
module m_z_if (if_point point, input clk);
always_ff #(posedge clk)
point.z <= func(point.x, point.y);
assign point.bus = (point.x!=point.y) ? 'z : point.z;
endmodule
module top_with_if (input clk);
if_point point();
m_x_if mx_inst (point,clk);
m_y_if my_inst (point,clk);
m_z_if mz_inst (point,clk);
endmodule
Running code: http://www.edaplayground.com/s/6/1150