I create my own macros file:
`ifndef MY_MACROS_SV
`define MY_MACROS_SV
// MACRO: 'my_fatal_err
// calls uvm_fatal in case the assertion is not correct
`define my_fatal(condition, msg)\
assert (condition) else\
`uvm_fatal("FATAL ERROR", msg)
`define add_rand(mem_type, mem) \
begin \
case (mem_type) \
"int": add_rand_int(mem); \
"bit": add_rand_bit(mem); \
default: `uvm_fatal("FATAL ERROR", "type is not supported") \
endcase\
end
`endif //MY_MACROS_SV
I got the following error:
** at ..\sv\tx_transaction.sv(21): near "(": syntax error, unexpected '(', expecting IDENTIFIER or '='.
Line 21 in tx_transaction.sv:
add_rand_macro();
add_rand is a function which defined in the base_transaction (tx_transaction extends it):
class base_transaction extends uvm_sequence_item();
int rand_int_list [];
bit rand_bit_list [];
bit [31:0] data [$];
//add to list functions
function void add_rand_int(int mem);
rand_int_list.push_back(mem);
endfunction: add_rand_int
......
endclass: base_transaction
The code for tx_transaction:
class tx_transaction extends base_transaction;
bit [15:0] data_xi;
bit [15:0] data_xq;
int mem_int; //TODO- delete
//uvm_object_utils\
`uvm_object_utils(tx_transaction)
//constructor
function new(string name = "tx_transaction");
super.new(name);
endfunction: new
function void add_rand_macro();
`add_rand("int", mem_int)
endfunction: add_rand_macro
add_rand_macro();
//TODO - DELETE
function void foo();
$display("rand mem int: %d", mem_int);
endfunction: foo
endclass: tx_transaction
Since the macro expands to a case statement, it must be called from inside a function in your class:
function ...
...
`add_rand("int", mem_int)
...
endfunction
UPDATED: Make sure you use a semicolon to end the function statement:
function void add_rand_macro();
`add_rand("int", mem_int)
endfunction
UPDATED: You cannot call the add_rand_macro function in the body of a class; it must be called inside another function.
Related
I have a class with a rand data member i. This class (child) is a member of class parent, which also has a data member i. I would like to constrain the value of i in the child class to be the same as the value of i in the parent class. I want to do something like:
c.randomize with {i==this.i;};
but the this.i doesn't seem to refer to the i data member of the parent class. (Why?)
I can do this:
function void f;
int dummy = i;
c.randomize with {i==dummy;};
endfunction
or this:
function void f;
c.randomize with {i==m.blk.p.i;}; // yuck!
endfunction
but wonder if there is a better (built-in, non-hacky) way of distinguishing between the two is.
MCVE:
class child;
rand int i;
endclass
class parent;
child c = new;
int i=1;
function void f;
c.randomize with {i==this.i;};
endfunction
endclass
module m;
initial begin : blk
parent p = new;
p.f;
$display("%p", p);
end
endmodule
https://www.edaplayground.com/x/2_8P
You want {i==local::i}. See section 18.7.1 of the 1800-2017 LRM
The reason this.i does not do what you expect is the combination of these two rules:
all class methods, including the built-in randomize method, have a built-in this argument. So c.method(args) is really method(args, c) and this becomes a variable local to the method set to the value of c
Identifiers within the with clause try to bind into the scope being randomized first before searching locally at the point where calling randomize().
So i and this.i refer to the same class variable just as if you wrote
class A;
bit i;
function void method;
i = 1;
this.i = 2;
endfunction
endclass
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
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
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
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.