Using typedef with wire in SystemVerilog - verilog

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.

Related

Will 'typedef logic' generate a register when using it instead of a 'wire', in SystemVerilog?

Having the following SystemVerilog code:
module my_module(
input wire [31:0] my_net
);
...
endmodule
...
...
wire [31:0] my_net;
assign my_net = ...;
my_module m(my_net);
What are the consequences (at synthesis time) of change the my_net declaration by:
typedef logic [31:0] my_net_t; // This is actually no longer a net, but a variable.
module my_module(
input my_net_t my_net
);
...
endmodule
my_module m(my_net);
...
...
wire [31:0] my_net;
assign my_net = ...;
my_module m(my_net);
I mean, logic is a variable, not a net, therefore, will the synthesizer generate a register for my_net?
Incorrect. logic is a data type that can be applied to a variable or net.
input wire [31:0] my_net
input my_net_t my_net
are implicitly the same as
input wire logic [31:0] my_net
input wire my_net_t my_net
When internal to a module
logic v;
wire w;
are implicitly
var logic v;
wire logic W;
But regardless of my_net being a variable or net, a continuous assignment to my_net does not create a register.
No.
Continuous assignment using
assign my_net = RHS;
does not infer registers.

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;

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

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;

How to write to "wire" and passing parameters to arrays of instances in Verilog

I have the following code:
module X;
wire [11:0] mga [0:15];
// other code omitted here for clarity
reg [11:0] globalStartAddresses [0:15];
reg [11:0] globalEndAddresses [0:15];
localMMU mmu[0:15](clock, globalStartAddresses, globalEndAddresses, mrw, mdi, mdo, mga);
task dispatcher;
// parameters
output reg dataReady;
input readWrite;
input [7:0] dataIn;
output reg [7:0] dataOut;
input [11:0] globalAddress;
// local variables
integer x, selected;
begin
for(x=0; x<16; x=x+1) begin
if(globalAddress >= globalStartAddresses[x] && globalAddress <= globalEndAddresses[x]) selected=x;
end
mrw[selected]=readWrite;
mdi[selected]=dataIn;
assign mga[selected]=globalAddress;
if(readWrite==1)
wait(mdo[selected]!=0);
else
wait(mdo[selected]!=dataIn);
dataOut=mdo[selected];
end
endtask
endmodule
I get 2 errors in the code:
In the array instance declaration of "localMMU", it states that "globalStartAddress[ ] should be present", but I have declared it just above as is evident.
In the assign statement inside the task, it states that only variables are allowed on LHS.
(I am using VeritakWin 3.84F) Please tell me how can I rectify these 2 problems. Thanks.
globalStartAddresses and globalEndAddresses are both of type array but array can not be passed directly between two modules. You must flatten the array into a vector and then pass it to a module. The problem is answered here :
How to pass array structure between two verilog modules
Left hand side of procedural continuous assignment can not be of type wire while in continuous assignment, left hand side must be just of type wire. As a solution, change mga type to reg. The same problem answered here:
Continuous assignment verilog

Why are output nets also required to be redeclared as either 'wire' or 'reg'?

Why do we have to take the same variable name of an output and also wire for getting the value? eg:
module TEST(INP1,INP2,CIN,COUT,SUM);
input [31:0] INP1;
input [31:0] INP2;
output [31:0] SUM;
input CIN;
output COUT;
wire [31:0] SUM;// Again redefined
wire COUT; // Again Redefined
assign {COUT,SUM} = INP1 + INP2 + CIN ;
Example for getting the Carry-out and the Sum of two numbers and Carry-In taken as the input.
Verilog 1995 did require the port direction to be listed after. Output wire types were implicit and regs could be declared inline with direction.
module TEST(A,B,C,D);
input [31:0] A;
input [31:0] B;
output [31:0] C;
output D;
reg D;
could be written as:
module TEST(A,B,C,D);
input [31:0] A;
input [31:0] B;
output [31:0] C;
output reg D; //Only declared twice
Since Verilog 2001 the extra definition is no longer required and they can be declared inline (ANSI-Style).
module TEST(
input [31:0] A,
input [31:0] B,
output [31:0] C,
output reg D // Declared Once
);
From SystemVerilog (2009) we have the logic type, you no longer have to switch between reg and wire types. The only requirement is that if you need to tri-state use wire or tri.
module TEST(
input [31:0] A,
input [31:0] B,
output logic [31:0] C,
output logic D
);
My understanding of the original requirement for having reg and wire types was for simulation speed or ease of simulator design. The value of a wire is evaluated every simulation delta cycle while a reg is only evaluated when triggered by the sensitivity list.
It is not necessary to declare an output also as a wire. Furthermore, you can avoid duplicating the port list by using ANSI-stlye port declarations:
module TEST (
input [31:0] INP1,
input [31:0] INP2,
output [31:0] SUM,
input CIN,
output COUT
);
assign {COUT,SUM} = INP1 + INP2 + CIN ;
endmodule
In your example, you do not need to declare outputs as reg. But, if you need to for another circuit, you can declare the type on the same line, such as:
output reg [31:0] Q;
Because just declaring a net as output doesn't describe if it is a reg type or a wire type.
An output can either be driven by a wire or reg, you have to tell it what type the driver is going to be.

Resources