Not able to compile my UVM classes - system-verilog

I have two files sequence_item.sv and sequencer.sv respectively with the contents below. I am not able to compile sequencer.sv, with the error
** Error: /afs/asu.edu/users/s/m/u/smukerji/UVM_practice/sequencer.sv(6): (vlog-2730) Undefined variable: 'Packet'.
Probably it is a simple mistake. My two classes are as
//Sequence item
import uvm_pkg::*;
`include "uvm_macros.svh"
class Packet extends uvm_sequence_item;
typedef enum bit [1:0] {NO_ERROR, SINGLE_ERROR, DOUBLE_ERROR, MULTIPLE_ERROR} err_type;
rand logic [127:0] correct_data_in;
rand logic valid_in;
logic [136:0] corrupted_data_in;
rand logic corrupt_valid_in;
rand bit error;
rand bit [127:0] err_pos;
randc err_type error_type;
logic [136:0] corrupt_data;
constraint type_of_error { (error == 0) -> error_type == NO_ERROR; }
constraint error_sequence {
if (error_type == SINGLE_ERROR) $countones(err_pos) inside {0,1};
else if (error_type == DOUBLE_ERROR) $countones(err_pos) inside {1,2};
else if (error_type == MULTIPLE_ERROR) $countones(err_pos) inside {2,127};
else err_pos inside {0, 0};
}
`uvm_object_utils_begin(Packet)
`uvm_field_enum(err_type, error_type, UVM_ALL_ON)
`uvm_field_int(correct_data_in, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(valid_in, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(corrupted_data_in, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(corrupt_valid_in, UVM_ALL_ON|UVM_NOPACK)
`uvm_field_int(error, UVM_ALL_ON)
`uvm_field_int(err_pos, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name="Packet");
super.new(name);
endfunction
function logic [136:0] create_corrupt_data;
logic [136:0] corrupt_data;
corrupt_data = err_pos ^ correct_data_in;
return corrupt_data;
endfunction
//virtual function void do_pack (uvm_packer packer);
//super.do_pack(packer);
//`uvm_pack_int(correct_data_in);
//`uvm_pack_int(valid_in);
//`uvm_pack_int(corrupted_data_in);
//`uvm_pack_int(corrupt_valid_in);
//packer.pack_field_int(correct_data_in,$bits(correct_data_in));
//packer.pack_field_int(valid_in,$bits(valid_in));
//packer.pack_field_int(corrupted_data_in,$bits(corrupted_data_in));
//packer.pack_field_int(corrupt_valid_in,$bits(corrupt_valid_in));
//endfunction
//virtual function void do_unpack (uvm_packer packer );
//super.do_unpack(packer);
//correct_data_in = packer.unpack_field_int($bits(correct_data_in));
//valid_in = packer.unpack_field_int($bits(valid_in));
//corrupted_data_in = packer.unpack_field_int($bits(corrupted_data_in));
//corrupt_valid_in = packer.unpack_field_int($bits(corrupt_valid_in));
//endfunction
endclass
And, my sequencer.sv as
//Sequencer
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef uvm_sequencer #(Packet) packet_sequencer;

You most likely compiled these two code classes separately in separate files. Code compiled in one compilation unit is not visible to another compilation unit. You should be compiling classes into a package.
package my_stuff;
`include "Packet.svh"
`include "packet_sequencer.svh"
endpackage

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

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

Dynamic cast fail issue

class base;
int a = 15;
endclass
class extended extends base;
int b = 2;
endclass
module top;
initial begin
base base;
extended extend;
extend = new();
base = new();
$cast(extend, base);
$display(extend.a);
end
endmodule
I'm trying to undersatnd $cast method in systemverilog as the above code, But I've got error messages.
ncsim> source /incisiv/15.20/tools/inca/files/ncsimrc
ncsim> run
$cast(extend, base);
|
ncsim: *E,BCLCST (./testbench.sv,18|8): Invalid cast: a value with the class datatype '$unit_0x4ccdf83b::base' cannot be assigned to a class variable with the datatype '$unit_0x4ccdf83b::extended'.
15
ncsim: *W,RNQUIE: Simulation is complete.
ncsim> exit
Exit code expected: 0, received: 1
Why does it make a error?
update 2
I've got some more test code for understanding the $cast().
test code.1
class base;
int a = 15;
endclass
class extended extends base;
int b = 2;
endclass
module top;
initial begin
base b;
extended e;
e = new();
b = new();
$cast(b, e);
//b=e;
$display(e.a);
end
endmodule
test code 2
class base;
int a = 15;
endclass
class extended extends base;
int b = 2;
endclass
module top;
initial begin
base b;
extended e;
e = new();
b = new();
//$cast(b, e);
b=e;
$display(e.a);
end
endmodule
When I compiled the both test code.1 and test code.2, the result the same.
So I'm confused that why do we use '$cast()' methods?
Your $cast is failing correctly as specified by the LRM. You have constructed a base class type object and stored its handle in a base class variable. (BTW, a bad idea to use the same name for both as you have now hidden the base type name). Now you are trying to assign the base handle to class variable of class type extend. $cast fails because the object your are tying to assign a handle to extended never constructed an extend object. Had the cast been allowed to succeed, the original handle in extended would have been replaced with a handle to a base object, and the reference to extend.b would be fatal since that variable does not exist.
The purpose of $cast is when you have handle stored in a base class variable, and that handle refers to an extended class object. The $cast allows you to move that handle to an extended class variable by checking the object it refers to first before making the assignment.
Please see my seminar on SystemVerilog OOP as well as short post on class terminology.
I suggest the following example for studying. the last 'printer()' statement will fail because you cannot cast non descendant of ext to 'ext' int he function
class base;
local string a;
function new();
a = "I am a";
endfunction
function print();
$display(a);
endfunction
endclass
class ext extends base;
local string b;
function new();
b = "i am b";
endfunction
function print();
$display(b);
endfunction
endclass
function printer(base p);
ext e;
$cast(e, p);
e.print();
p.print();
endfunction
program P;
base b = new();
ext e = new();
initial begin
printer(e);
printer(b); // << this will fail
end
endprogram

Is this mandantory to use 'new' to function in the class of systemverilog?

Now I'm trying to study about clss of systemverilog.
From many class of example, I found the 'new' in 2 types.
The case of the 'new' is existed in class.
The case of the 'new' is existed in initial.
Is there any difference between those implementation of constructor?
One more, what is in the function new()?
I'm not sure what purpose is in the function new()
update
For example 1 is.
Class xxx
...
Function new();
...
Endfunction
Endclass
Example2 is
program
class xxxx
endclass
Initial begin
xxxx x = new;
end
endprogram
update 2
Thanks for let me know.
I've got a question. What Is the difference between
Class xxx
...
Function new();
(Variable initialization)
...
Endfunction
Endclass
And
Class xxx
...
Function new();
(Nothing variable initialization)
Endfunction
Endclass
But in this case to pass the value in the intial statement or tasks.
What is in the function new() endfunction? I'm not sure should I have to initialize the variables?
update3
class packet;
//class properties
bit [31:0] addr;
bit [31:0] data;
bit write;
string pkt_type;
//constructor
function new(bit [31:0] addr,data,bit write,string pkt_type);
addr = addr;
data = data;
write = write;
pkt_type = pkt_type;
endfunction
//method to display class prperties
function void display();
$display("---------------------------------------------------------");
$display("\t addr = %0h",addr);
$display("\t data = %0h",data);
$display("\t write = %0h",write);
$display("\t pkt_type = %0s",pkt_type);
$display("---------------------------------------------------------");
endfunction
endclass
module sv_constructor;
packet pkt;
initial begin
pkt = new(32'h10,32'hFF,1,"GOOD_PKT");
pkt.display();
end
endmodule
This is what I've a code.
you can see that,
two types declare of function block.
1. is with new
function new(bit [31:0] addr,data,bit write,string pkt_type);
addr = addr;
data = data;
write = write;
pkt_type = pkt_type;
endfunction
2. is without new.
//method to display class prperties
function void display();
$display("---------------------------------------------------------");
$display("\t addr = %0h",addr);
$display("\t data = %0h",data);
$display("\t write = %0h",write);
$display("\t pkt_type = %0s",pkt_type);
$display("---------------------------------------------------------");
endfunction
Calling the new() method of a class is the only way to construct a class object. There are a few reasons you might want to define a class and never call the new() method on it, but you should ask that question later when you have a better understanding of SystemVerilog.
Update
I think you may be asking what is the difference between a class with declared function new() inside the class
class xxxx;
int x;
function new;
...
endfucntion
endclass
versus a class without it
class xxxx;
int x;
endclass
If you do not declare a function new() inside your class, SystemVerilog defines an implicit one for you. The reason you might want to declare a function new inside your class is if you want to pass in arguments to the constructor, or you have something that requires more complex procedural code to initialize.

System Verilog: enum inside interface

I have an interface:
interface my_intf();
typedef enum logic [1:0] {
VAL_0 = 2'b00,
VAL_1 = 2'b01,
VAL_2 = 2'b10,
VAL_3 = 2'b11
} T_VAL;
T_VAL val;
endinterface
My module uses this interface:
my_intf intf;
The problem is to assign the val with a value from the enum.
I can assign it as:
intf.val = 0; (and receiving warning or error)
but not as:
intf.val=VAL_0;
Nor as
intf.val = my_intf.T_VAL.VAL_0
How I overcome that problem?
I have only dealt with packages for containing enums before, and avoid interfaces. This is how I use packages. Import the package before the module definition with which you want to use it:
import my_intf_pkg::* ;
module bla(
output my_val_t intf
);
initial begin
intf = VAL_0 ;
end
endmodule
The package containing enums might look like:
package my_intf_pkg;
typedef enum logic [1:0] {
VAL_0 = 2'b00,
VAL_1 = 2'b01,
VAL_2 = 2'b10,
VAL_3 = 2'b11
} my_val_t;
endpackage : my_intf_pkg
Note that the VAL_0 etc are global and not tied to the T_VAL typedef. Therefore I often make them a bit more unique including the typedef in the name. T_VAL_0 for T_VAL typedefs etc.
Here is an example on EDAplayground.
intf.val = 0; should be an error because you are trying to assign a integral type to an enum without a cast.
intf.val = VAL_0; is an error because VAL_0 is not defined in the current scope.
You should be able to do
intf.val = intf.VAL_0;
However, the best solution in to put shared types in a package, an import the package where needed.