How to pass parameterized class to a module instance? - system-verilog

include "cls.sv"
module top();
int x;
spl_cls #(10) o_spl_cls;
/*Code Continues, here o_spl_cls object has been created using
new();*/
dummy i_dummy(o_spl_cls); //I instantiated another module and passed
//object
endmodule
//This is my dummy module
module dummy(spl_cls i_spl_cls);
....
endmodule
//my spl_cls is
class spl_cls#(int data=0);
//...rest code
endclass
I am getting Error.
How to pass parameterized object to another module instance or class?

You will need to parameterize all references to spl_cls that you want to make assigments to.
module dummy(spl_cls#(10) i_spl_cls);
....
endmodule
A better solution would be to use a typedef
module top();
typedef spl_cls #(10) spl_cls_10;
int x;
spl_cls_10 o_spl_cls;
/*Code Continues, here o_spl_cls object has been created using
new();*/
dummy #(spl_cls_10) i_dummy(o_spl_cls); //I instantiated another module and passed
//object
endmodule
//This is my dummy module
module dummy #(type C)(C i_spl_cls);
....
endmodule

Related

SystemVerilog macro through task

How to send macros as parameters through a task?
In the testbench:
`define CPU1 tb.top.dual_processor_db_wrapper_i.dual_processor_db_i.cpu1.inst
`define CPU2 tb.top.dual_processor2_db_wrapper_i.dual_processor2_db_i.cpu2.inst
initial begin
fork
cpu_init(`CPU1);
cpu_init(`CPU2);
join
// Other stuff with `CPU1 and `CPU2
`CPU1.write_data(addr, 4, data, resp); // Works
end
task cpu_init(cpu);
cpu.por_srstb_reset(1'b1); // Does not work
// Other init stuff
endtask
Error when compiling:
ERROR: [VRFC 10-2991] 'por_srstb_reset' is not declared under prefix
'cpu'
The type of the `CPUs is unknown (to me). Perhaps Xilinx has a type for it, since it references their MPSoC VIP?
I assume por_srstb_reset and write_data are tasks or functions from Xilinx MPSoC VIP, but I'm not sure.
Xilinx documentation is very sparse
I general, it is possible to pass a macro as an argument to a task. However, it is not possible to pass a hierarchical reference as an argument to a task (it is illegal).
Operations on hierarchical references are very limited, in general.
Your task declaration is equivalent to the following:
task cpu_init (input logic cpu);
The cpu variable is a 1-bit type. So, the following is legal:
`define CPU1 1'b1
cpu_init(`CPU1);
The type of the argument must match between the declaration and the task call.
There is another approach to this problem by using bind and abstract/concrete classes
package pkg;
interface class abstract_init;
pure virtual task init; // prototype for each method you need
endclass
abstract_init lookup[string]; // database of concrete classes for each instance
endpackage
module bind_module #(string lookup_name);
import pkg::*;
class concrete_init implements abstract_init;
function new;
lookup[lookup_name] = this; // register this instance
endfunction
virtual task init;
processor.reset(); // upwards reference
endtask
endclass
concrete_init c = new; // each instance of this module gets registered in lookup
endmodule
`define cpu1 top.dut.cpu1
`define cpu2 top.dut.cpu2
// macro turns any argument into a quoted string
`define Q(arg) `"arg`"
module top;
dut dut();
bind `cpu1 bind_module #(.lookup_name(`Q(`cpu1))) b();
bind `cpu2 bind_module #(.lookup_name(`Q(`cpu2))) b();
initial fork
pkg::lookup[`Q(`cpu1)].init;
pkg::lookup[`Q(`cpu2)].init;
join
endmodule
module dut;
processor cpu1();
processor cpu2();
endmodule
module processor;
initial $display("Starting %m");
task reset;
#1 $display("executing reset on %m");
endtask
endmodule
This is described more detail in my DVCon paper: The Missing Link: The Testbench to DUT Connection.

what does "virtual" mean when applied to a SystemVerilog interface?

What is the meaning of "virtual tinyalu_bfm" in the SystemVerilog code below? example:
uvm_config_db #(virtual tinyalu_bfm)::set(null, "*", "bfm", bfm);
would it make any difference if i omitted the virtual keyword? Just curious, because the usually oop meaning of virtual is applied only to classes or class members and here's an example where its applied to an interface being passed into a static function that's part of UVM package... just wanted to know why I need to call it virutal in this case and what its purpose is to make it virtual.
module top;
// UVM Framework
import uvm_pkg::*;
`include "uvm_macros.svh"
import tinyalu_pkg::*; //import all tb classes and types
tinyalu_bfm bfm();
// invoke APIs from uvm_pkg to start test...
initial begin
uvm_config_db #(virtual tinyalu_bfm)::set(null, "*", "bfm", bfm);
run_test();
end
endmodule : top
interface tinyalu_bfm;
byte unsigned A;
byte unsigned B;
bit clk;
bit reset_n;
initial begin
clk = 0;
forever begin
#10;
clk = ~clk;
end
end
task reset_alu();
reset_n = 1'b0;
#(negedge clk);
#(negedge clk);
reset_n = 1'b1;
start = 1'b0;
endtask : reset_alu
task send_op(input byte iA, input byte iB, input operation_t iop, output shortint alu_result);
// ...
endtask : send_op
endinterface : tinyalu_bfm
see here again... the interface object is declared virtual as well...why?
// FILE: random_test.svh
class random_test extends uvm_test;
// ...
virtual tinyalu_bfm bfm;
function new (string name, uvm_component parent);
super.new(name,parent);
if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm))
$fatal("Failed to get BFM");
endfunction : new
task run_phase(uvm_phase phase);
//...
endtask : run_phase
endclass
SystemVerilog was created to be fully backward compatible with Verilog with the exception being newly reserved keywords. So SystemVerilog re-uses, or overloads existing keywords as much as possible to reduce keyword bloat. The virtual keyword in front of an interface name means you are declaring variable type that contains a handle to an actual interface instance, and not an actual interface instance,
Analog to a virtual interface in normal programming languages is a pointer or a reference (to the interface object). It is used as a reference in system verilog test bench components, passing it as function or task arguments or storing it in classes or other places.
System verilog is a huge language with a lot of ugliness in it. The virtual keyword is definitely overused, as in this case. There could have been a better choice.
|
I suggest the following define macro to make up for bad language choose by the designers of SystemVerilog to overload virtual keyword is a strange way:
`define REFERENCE virtual
module top;
// UVM Framework
import uvm_pkg::*;
`include "uvm_macros.svh"
import tinyalu_pkg::*; //import all tb classes and types
tinyalu_bfm bfm();
// invoke APIs from uvm_pkg to start test...
initial begin
uvm_config_db #(`REFERENCE tinyalu_bfm)::set(null, "*", "bfm", bfm);
run_test();
end
endmodule : top
interface tinyalu_bfm;
// ...
endinterface : tinyalu_bfm
see here again... the interface object is declared virtual as well...why?
// FILE: random_test.svh
class random_test extends uvm_test;
// ...
`REFERENCE tinyalu_bfm bfm;
function new (string name, uvm_component parent);
super.new(name,parent);
if(!uvm_config_db #(`REFERENCE tinyalu_bfm)::get(null, "*","bfm", bfm))
$fatal("Failed to get BFM");
endfunction : new
task run_phase(uvm_phase phase);
//...
endtask : run_phase
endclass

copy an object to a handle in systemverilog

i have one module, mod1, which includes one class, my_test. Inside mod1 there is an instance of another module mod2 and mod2 includes a class, my_config. the "my_test" class also includes the my_config class.
I want to copy the object of my_config class to another handle of this class which is instantiated inside mod2 module. Below are the code snippets, you can follow. my_test, my_config, mod1, mod2 are in different files.
class my_test;
my_config cfg_2; // instance of my_config class
// here the object is created
// here i have assigned some values to the properties of my_config class
...
endclass : my_test
module mod2;
my_config cfg_1; // instance of my_config class
// mod2 file includes my_config class
...
endmodule : mod2
`include "my_test.sv" // included inside the file "mod1"
module mod1;
mod2 m2(..); // module instance of module mod2
// mod1 file includes my_test class
m2.cfg_1 = cfg_2; // cfg_1 is instance of my_config, inside mod2
// In the above line i am trying to copy the object cfg_2 to the handle cfg_1
// I AM GETTING ERROR IN THE ABOVE LINE.
...
endmodule : mod1
Can anyone please help me out. Thanks
You don't show the instance of my_test here, but assuming you create it under the name my_test_inst, then do the following:
module mod1();
//...
// you can only add procedural code in initial blocks
initial
m2.cfg_1 = my_test_inst.cfg_2
endmodule

Getting the hierarchical scope from where a function was called

When calling a function, is it possible for that function to get the hierarchical scope of the location where it was called?
Let me give you an example. I have the following code:
package some_pkg;
function void some_function();
$display("%m");
endfunction
endpackage
module top;
import some_pkg::*;
initial
some_function();
endmodule
When running it, it will display "some_pkg::some_function". Is there any way that I can get the function to display "top"? Or if I would have some other sub-module where it is called from, could it display "top.submodule"?
This is going to be tool specific and requires extra debugger information to dynamically track scopes. Modelsim/Questa has $stacktrace that will display the scope and filename/linenumber
I kind of got it working using a macro:
`timescale 1ns/1ns
`define here_str $sformatf("%s::%0d %m", `__FILE__, `__LINE__)
`define here(DUMMY="") $display("I am here: %s", `here_str);
package some_pkg;
function void some_function();
$display("%m");
endfunction
endpackage : some_pkg
module top;
import some_pkg::*;
initial begin
some_function(); // Gives the wrong scope https://stackoverflow.com/q/24454395/1219634
$stacktrace; // Does not return the stacktrace as a string value
`here() // This works, but I would rather not use a macro as I
// would like to make this portable in a package
$finish;
end
endmodule : top
Tested on Cadence/Xcelium 18.09-s014.

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