Define type in generate block and use it outside - system-verilog

I'm attempting to define a user-defined type in a generate block and then access it in the scope outside the generate block. Something like this:
generate
if (SOME_PARAM == 0) begin
typedef struct packed {
logic [A-1:0][B-1:0] field1;
logic [C-1:0] field2;
} struct_id_t;
end
else begin
typedef struct packed {
logic [SOME_PARAM-1:0] other_field;
logic [A-1:0][B-1:0] field1;
logic [C-1:0] field2;
} struct_id_t;
end
endgenerate
struct_id_t some_struct_instance;
The last line of code triggers an error indicating that struct_id_t is undefined. Apparently, generate blocks create a local scope, which would explain the error.
Is there another way to accomplish this?
Before discussing what I've considered/tried, I'll first say that I understand one solution to this is to place all uses of struct_id_t in the local scope created by the generate block. However, this would require quite a bit of code duplicated between the blocks that I'd really prefer to avoid.
Other things I've considered:
A compiler directive does not create a local scope like a generate block. Unfortunately, (System)Verilog does not have an ifeq compiler directive, so I don't think this will work.
I also tried to forward declare the type. Something like:
typedef struct struct_id_t;
generate
if (SOME_PARAM == 0) begin
typedef struct packed {
logic [A-1:0][B-1:0] field1;
logic [C-1:0] field2;
} struct_id_t;
end
else begin
typedef struct packed {
logic [SOME_PARAM-1:0] other_field;
logic [A-1:0][B-1:0] field1;
logic [C-1:0] field2;
} struct_id_t;
end
endgenerate
struct_id_t some_struct_instance;
The resulting error complains about struct_id_t never being defined. Section 6.18 of the 1800-2012 standard explains the error:
The actual data type definition of a forward typedef declaration shall be resolved within the same local scope or generate block.
So, the definition needs to be in the same scope.
I tried to create a label for the generate blocks that includes the parameter definition. That way I believe I could access the type hierarchically. Something along the lines of gen_name[SOME_PARAM].struct_id_t. But it seems that's not a valid name for a generate block.
What are my options?

There is no way to declare a type in a generate block this way. But, you can define a variable inside a block as the following and use it with a structural name:
if (SOME_PARAM == 0) begin: def
typedef struct packed {
logic [A-1:0][B-1:0] field1;
logic [C-1:0] field2;
} struct_id_t;
struct_id_t some_struct_instance;
end
else begin: def
typedef struct packed {
logic [SOME_PARAM-1:0] other_field;
logic [A-1:0][B-1:0] field1;
logic [C-1:0] field2;
} struct_id_t;
struct_id_t some_struct_instance;
end
assign def.some_struct_instance = 1;
The other approach is to pass the type to the instance of your module (mod):
module top#(SOME_PARAM = 0, A=1, B=1, C=1)();
typedef struct packed {
logic [A-1:0][B-1:0] field1;
logic [C-1:0] field2;
} struct1_id_t;
typedef struct packed {
logic [SOME_PARAM-1:0] other_field;
logic [A-1:0][B-1:0] field1;
logic [C-1:0] field2;
} struct2_d_t;
mod #(.stuct_id_t(struct1_id_t)) mod1();
mod #(.stuct_id_t(struct1_id_t)) mod2();
endmodule
module mod#(type struct_id_t = logic) ();
struct_id_t some_struct_instance;
// ...
endmodule

Related

How to derive a parent class?

#1
To understand the behavior of new() and inheritance, I made a simple class and added class child_class:
// Example 1
class parent_class;
logic [31:0] addr;
logic [7:0] data;
bit parity;
function new(logic [31:0] add, logic [7:0] dat);
addr = add;
data = dat;
endfunction
endclass
class child_class extends parent_class;
bit [31:0] data;
static int count;
function new();
count++;
data = count;
endfunction
endclass
module inheritence;
initial begin
parent_class p;
p = new(32'h1234, 8'hff);
$display("Value of addr = %0d data = %0d",p.addr,p.data);
p.addr = 10;
p.data = 20;
$display("Value of addr = %0d data = %0d",p.addr,p.data);
end
endmodule
But, when I executed it, I got the error message:
class child_class extends parent_class;
|
xmvlog: *E,FAABP1 (testbench.sv,21|38): Task/function call, or property/sequence instance does not specify all required formal arguments.
function new(logic [31:0] add, logic [7:0] dat);
Q1. Why can't I make the child class? How do I correctly derive the class and use it?
#2
If I remove class child_class in my code above,
class parent_class;
logic [31:0] addr;
logic [7:0] data;
bit parity;
function new(logic [31:0] add, logic [7:0] dat);
addr = add;
data = dat;
endfunction
endclass
module inheritence;
initial begin
parent_class p;
p = new(32'h1234, 8'hff);
$display("Value of addr = %0d data = %0d",p.addr,p.data);
p.addr = 10;
p.data = 20;
$display("Value of addr = %0d data = %0d",p.addr,p.data);
end
endmodule
There is no error message for child class. What's the difference between them?
From IEEE Std 1800-2017, section 8.7 Constructors:
The new method of a derived class shall first call its base class
constructor [super.new() as described in 8.15].
From section 8.15 Super:
A super.new call shall be the first statement executed in the
constructor. This is because the superclass shall be initialized
before the current class and, if the user code does not provide an
initialization, the compiler shall insert a call to super.new
automatically.
The error message is telling you that the new function in the child_class class is implicitly making a call to the new function in the parent_class class, but that new function requires 2 arguments.
One way to fix the error is to explicitly call spuer.new in child_class with 2 arguments. For example, this code fixes the error:
class child_class extends parent_class;
bit [31:0] data;
static int count;
function new();
super.new(0, data);
count++;
data = count;
endfunction
endclass
You must decide if this how you want your code to behave.
To answer the 2nd question, since you no longer have the derived class (child_class) which has the syntax error, you no longer get an error. Your module properly calls new from parent_class with the correct number of arguments (2).
I am not from system-verilog and from C C++/shell.
Assume that I created a character variable "testing" and I am not using that variable anywhere inside my program. Due to that, one byte wasted when my program at execution mode.
Assume that I wrote that in a server program inside an infinite loop.
In this case, it will affect the performance of server program since it is using a variable which is not being used.Hence wastage of memory.This may affect other program when that program is waiting for free space at RAM/cache from disk.
Hence better to remove all warnings when we obtain during compilation.
This is applicable to all living beings at each planet/universe handling the space across the planets/universe [if applicable:) ]
You need to learn parent class, constructor, destructor/uploaded functions at parent/child class when performing inheritance.
https://www.chipverify.com/systemverilog/systemverilog-inheritance

System Verilog Conditional Type Definition

Is there a way to conditionally select between two types based on a parameter value?
typedef struct packed {
logic a;
} my_type_1_t;
typedef struct packed {
logic [1:0] a;
} my_type_2_t;
parameter type type_t = my_type_1_t;
if (MY_PARAM == 1) begin
typedef my_type_1_t type_t;
do something...
end else begin
typedef my_type_2_t type_t;
do the same something as above with different struct...
end
type_t my_signal;
As you can see, I need to do the same operations in the else clause as in the if clause, but on a different struct. This seems redundant to me, and I am curious if there is a way to avoid duplication.
No, you can't do this because the type_t name will be local to the generate-if block. But it wouldn't make much sense if you could because code that references my_signal is going to want to access my_signal.b and it would not exist in certain cases.
The only way to mimic the behavior you want is to use parameterized modules.
Here is a simple example:
typedef struct {
logic a, b;
} type1_t;
typedef struct {
logic [1:0] a1, b1;
} type2_t;
module top(input logic clk);
pmod#(.T(type1_t)) inst1(clk);
pmod#(.T(type2_t)) inst2(clk);
endmodule
module pmod#(type T=int) (input logic clk);
logic [1:0] a, b;
T t;
if ($typename(T) == "type1_t") begin
always #(posedge clk) begin
a = t.a;
b = t.b;
end
end
else if ($typename(T) == "type2_t") begin
always #(posedge clk) begin
a = t.a1;
b = t.b1;
end
end
// do something with a and b
endmodule
First, question to ask yourself is whether you are needing synthesizable code?
If not, you simply can use a parameterized class with different struct definitions, effectively giving you parameterized structs.
Note that it would be possible for synthesis tools to synthesize such code, yet your mileage with each tool varies, and last time I checked, most synthesis tools didn't even support this limited use of class construct as a scoping mechanism.
Packages, which have much more synthesis tool support unfortunately do not have an option for parameterizing packages/structs. The best I've done is to emulate parameterizable structs using macros, e.g.:
// Macro and struct definitions could be moved to common header file if shared across multiple modules
// Acts like a parameterized typedef
// Note: You could even extend multiple nested levels if needed
// This mechanism requires that the struct definitions take the same form, i.e., logic[0:0] instead of just logic
`define my_type_t(W) struct packed { logic [W-1:0] a; }
// module used as example, but would work in most contexts
module mod;
parameter MY_PARAM = 1;
// In a particular parameterized context, can resolve the macro
// into a real typedef if desired
typedef my_type_t(MY_PARAM) type_t;
type_t my_signal;
// do something that works with either struct definition
endmodule;
Please check my syntax above as I took a previously working example and modified it to match the question from OP, without testing final code segment.

How to match `an array of struct` with `arrays of signals`? (unpacked)

I have a module:
module test(
inout logic [3:0] data [NUM],
...
inout logic anything [NUM]
);
by
struct {
logic [3:0] data; // tri-states, can't use tri in struct
...
logic anything;
} dut [NUM];
test test_i(
.data (dut.data), // should be same as [3:0] data [NUM]
...
.anything (dut.anything)
);
I get: Cannot select data in dut due to dimension mismatch.
Why? What can I do to match my unpacked struct to the modport?
There are a lot of signals, that's why I'd like to use struct instead of several logic array signals.
You can use a struct as a datatype for a wire, you just need a typedef
typedef struct {
logic [3:0] data;
...
logic anything;
} dut_t;
tri dut_t dut[NUM];
(See this post for a more detailed explanation)
But the bigger problem is you cannot slice an array of a struct to get an array of struct members. You can only select an element of the array, and then select a member, i.e. dut[0].data
You would have to do
typedef struct {
logic [3:0] data[NUM];
...
logic anything[NUM];
} dut_t;
tri dut_t dut;
Which probably defeats the purpose of what you wanted to do.

How do I convert strings to enums in SystemVerilog?

I have command-line plusargs that I want to map to enumerated values.
vsim foo +MY_PLUSARG=BAR
How do I get the string "BAR" to become the enum BAR?
If you are using UVM 1.2 or have access to the library, you may want to use uvm_enum_wrapper class to do the conversion. It is a template class wrapper defined in uvm_globals.svh and you can use it as follows:
typedef enum {BISTRO, COFFEE_SHOP, BAR} places_e;
typedef uvm_enum_wrapper#(places_e) places_wrapper;
places_e place;
places_wrapper::from_name("BAR", place);
Quite like the code you provided in this solution, the wrapper class works by traversing the enum entries and creating an assoc array for a enum[string] map for the given enum (supplied as template parameter). So if you are using UVM 1.2, don't repeat.
The idea behind this solution is to avoid a case statement that hardcodes the members of your enumerated type. You want to be able to change the type in one play.
Let's say you have the following enum:
typedef enum {BISTRO, COFFEE_SHOP, BAR} places_e;
You want your user to be able to type:
vsim top +MEET_PLACE=BAR
Now you want to translate the string "BAR" to the enum 'Bar'.
You can do this:
typedef enum {BISTRO, COFFEE_SHOP, BAR} places_e;
module top;
places_e place_map[string];
function void make_map;
places_e pl;
pl = pl.first();
do begin
place_map[pl.name()]=pl;
pl = pl.next();
end while (pl != pl.first());
endfunction // make_map
function string get_list;
string ss;
places_e pl;
pl = pl.first();
ss = "";
do begin
ss = {ss, " ",pl.name()};
pl = pl.next();
end while (pl != pl.first());
return ss;
endfunction // get_list
initial begin
string place_str;
places_e place;
make_map;
if (!$value$plusargs("MEET_PLACE=%s", place_str)) begin
$display("You must choose a MEET_PLACE");
$finish;
end
if (! place_map.exists(place_str)) begin
$display("You must choose from this list: %s", get_list());
$finish;
end
place = place_map[place_str];
$display("Let's meet at a %s!", place.name());
end // initial begin
endmodule // top

Using parameterized aggregate datatype in ANSI-style module port list

The following code
module test #(A = 1, B = 2) (output t_my sig);
typedef struct {
logic [A-1:0] fA;
logic [B-1:0] fB;
} t_my;
initial $display("hello\n");
endmodule
returns the VCS error
Error-[SV-UIOT] Undefined interface or type
test.vs, 1
t_my, "sig"
The definition for the forward-referenced interface 't_my' is missing or
't_my' is the name of an undefined user type.
Check to see if the interface definition file/work library is missing or the
definition of the user type is missing.
If I instead do
typedef struct {
logic [A-1:0] fA;
logic [B-1:0] fB;
}t_my;
module test #(A = 1, B = 2) (output t_my sig);
initial $display("hello\n");
endmodule
then I get
Error-[IND] Identifier not declared
test.vs, 2
Identifier 'A' has not been declared yet. If this error is not expected,
please check if you have set `default_nettype to none.
Error-[IND] Identifier not declared
test.vs, 3
Identifier 'B' has not been declared yet. If this error is not expected,
please check if you have set `default_nettype to none.
Is there a way to do what I want using ANSI style module port lists? Note that I can accomplish this without ANSI style port lists as follows:
module test #(A = 1, B = 2) (sig);
typedef struct packed {
logic [A-1:0] fA;
logic [B-1:0] fB; } t_my;
output t_my sig;
initial $display("hello\n");
endmodule
module top;
logic topsig [2:0];
test test1 (.sig ({>>{topsig}}) );
endmodule
When you have a user-defined aggregate type in a port list, you need to put that type in a place where it will be compatible to make a connection, i.e. the module test, and the module above it that will make a connection to that port. There are two ways to accomplish this:
Pass the data type down from from a higher level using a type parameter.
module test#(type T) (input T sig);
parameter A = $bits(sig.fA);
parameter B = $bits(sig.fB);
initial #1 $display(A,, B);
endmodule
module top;
typedef struct {
logic [3:0] fA;
logic [4:0] fB;
} my_t;
my_t s;
test #(my_t) t2(s);
endmodule
displays
# 3 4
or you can put the type in a common package. However to make the struct parameterized, you need to wrap the type in a class. See section 6.25 of the 1800-2012 LRM (This is supposed to be synthesiable)
package p;
class T#(int A,B);
typedef struct {
logic [A-1:0] fA;
logic [B-1:0] fB;
} my_t;
endclass
endpackage : p
module test#(int A=1, B=2) (input p::T#(A,B)::my_t sig);
initial #1 $displayb(sig.fA,, sig.fB);
endmodule
module top;
import p::T;
T#(2,3)::my_t s = '{'1, '1};
test #(2,3) t(s);
endmodule