I create sequence class like this:
`define SEQ_NAME(sub_name) ``sub_name``_test_seq
class base_sequence extends uvm_sequence;
`uvm_object_utils(base_sequence)
......
endclass
class `SEQ_NAME(abc) extends base_sequence;
`uvm_object_utils(`SEQ_NAME(abc))
......
endclass
and then I want to use set_type_override_by_name to override base_sequence :
factory.set_type_override_by_name("base_sequence","abc_test_seq"); //fatal, abc_test_seq is not registered with the factory
I find that the `uvm_object_utils(`SEQ_NAME(abc)) is expanded like this:
typedef uvm_object_registry#(abc_test_seq,"`SEQ_NAME(abc)") type_id;
......
I modify my override code :
factory.set_type_override_by_name("base_sequence","`SEQ_NAME(abc)"); //PASS
So, if I want to use the string "abc_test_seq" in override factory, should the uvm_obeject_utils be passed the abc_test_seq argument? Is there any ways to use macro like my second class?
A back-tick (`) inside a double quotes is treated as a string character and not the prefix of a macro. You should create a new macro that add quotes around it input argument. The argument will be evaluated before the quotes added. For example:
`define STR(str) `"str`"
Then you can do:
typedef uvm_object_registry#(abc_test_seq,`STR(`SEQ_NAME(abc))) type_id;
...
factory.set_type_override_by_name("base_sequence",`STR(`SEQ_NAME(abc)));
In this case, `STR(`SEQ_NAME(abc) will resolve as to "abc_test_seq"
Related
I'd like to store a reference to an array/queue inside a class. It's doesn't seem possible to do this, though.
I'd like to do something like this:
class some_class;
// class member that points to the 'q' supplied as a constructor arg
??? q_ref;
function new(ref int q[$]);
this.q_ref = q;
endfunction
endclass
If q_ref is merely defined as int q_ref[$], then the assignment operator will create a copy, which isn't what I want. I'd like changes in 'q' to be visible inside the class.
Is there some hidden section in the LRM that shows how this can be done?
I'm not looking for the obvious "you have to wrap the array/queue in a class answer", but for something that allows me to interact with code that uses native arrays/queues.
There are only three variable types in SystemVerilog that can store references: class, event, and virtual interfaces variables.
You have to wrap the array/queue as a member in a class object. Then, any method of that class can be used in an event expression. Any change to a member of the class object causes a re-evaluation of that method. See the last paragraph and example in section 9.4.2 Event control of the 1800-2012 LRM.
So, the only solution for you would be to wrap the queue in a class. The latter is always assigned by a reference, as in this example:
class QueueRef #(type T = int);
T queue[$];
function void push_back(T t);
queue.push_back(t);
endfunction // push_back
endclass // Queue
class some_class;
QueueRef q_ref;
function new(QueueRef q);
this.q_ref = q;
endfunction
endclass
program test;
QueueRef q = new;
some_class c = new (q);
initial begin
q.push_back(1);
q.push_back(2);
$display(c.q_ref.queue);
end
endprogram // test
Is there any way to pass the value of an enum by name from the commandline? Rather what's the cleanest solution?
I tried the below,
typedef enum int unsigned { white, black, red } colour_e;
class house;
rand colour_e colour;
string n_colour = "white";
constraint c_colour {
colour.name() == n_colour;
}
endclass: house
program top;
house paradise;
initial begin
paradise = new();
void'($value$plusargs("colour=%0s", paradise.n_colour));
if (!paradise.randomize())
$display("not randomized");
else
$display("paradise.colour = %s",paradise.colour);
end
endprogram: top
I would want to pass something like this +colour=black. so that the paradise.colour is assigned black.
vcs cribbed for using enum.name() in the constraints.
below is the error.
Error-[NYI-CSTR-SYS-FTC] NYI constraint: sys function calls
T-enum_1.sv, 9 $unit, "this.colour.name" System function calls are
not yet implemented in constraints. Remove the function call or if
possible replace it with an integral state variable assigned in
pre_randomize().
while Riviera cried as below
ERROR VCP7734 "Type of 'this.colour.name()' is not allowed in a
constraint block. Only integral types are allowed in a constraint
block." "design.sv" 9 1 ERROR VCP7734 "Type of 'n_colour' is not
allowed in a constraint block. Only integral types are allowed in a
constraint block." "design.sv" 9 1 WARNING VCP7114 "STRING value
expected for format specifier %s as parameter
paradise.colour." "testbench.sv" 13 54
which brings the question to me, does everything in the contraint block has to be of integral type (just like we cannot declare a string as rand variable)?
ANyone wants to play around the code please have a look at the code at EDA playground here
Use uvm_enum_wrapper class to do the conversion from string to corresponding enum value. It is a template class wrapper defined in uvm_globals.svh (part of UVM 1.2) and you can use it as follows:
typedef enum {white, black, red} colour_e;
typedef uvm_enum_wrapper#(colour_e) colour_wrapper;
string colour_str;
void'($value$plusargs("colour=%0s", colour_str));
colour_wrapper::from_name(colour_str, paradize.n_colour);
The wrapper class uvm_enum_wrapper works by traversing the enum entries and creating an assoc array for a enum[string] map for the given enum type (supplied as template parameter). For more details take a look at the documentation.
There is another solution for the same. If you are not using UVM 1.2 version then there is like you can take string as an input argument and convert that string argument into int type. After that you can directly cast int to enum type by $cast.
Because there is no way to convert string to enum type (except UVM 1.2) so you have to add one extra step for the same.
module Test;
typedef enum {black,red,blue} color_e; //enum declaration
color_e color; //type of enum
string cmd_str; //Commandline string input
int cmd_int; //Input string is first converted into int
initial
begin
$value$plusargs("enum_c=%0s",cmd_str); //Take input argument as string it may be 0,1 or 2
cmd_int=cmd_str.atoi(); //Now convert that string argument into int type
$cast(color,cmd_int); //Casting int to enum type
$display("Value of color is --> %p",color); //Display value of enum
end
endmodule
Is it possible to use a string as a SystemVerilog interface paramter. I have 4 instances of the same interface, and I was wondering if I can `include different assertion files for each instance.
My interface looks like this:
interface dai_if #(P_WD_DATA = 24,
string P_FILE_NAME = "assertion_file_name")();
//Internal Signal Defined Here
`include "assertion_file_name"
endinterface : dai_if
In the top level, where I instantiate the four instances I have the following code:
module tb_top;
parameter P_WD_DATA = 24;
parameter string DAI_SER_IN_FILE = "dai_ser_in_checkers.v";
parameter string DAI_SER_OUT_FILE = "dai_ser_out_checkers.v";
parameter string DAI_PAR_IN_FILE = "dai_par_in_checkers.v";
parameter string DAI_PAR_OUT_FILE = "dai_par_out_checkers.v";
Then I instanced each of the interfaces like this:
dai_if #(.P_WD_DATA(P_WD_DATA),
.P_FILE_NAME(DAI_SER_IN_FILE))
dai_ser_ivif();
Is this the correct method, or am I missing something?
Thanks
You cannot use parameters to define include files as the `include macro is performed long before the parameters are evaluated (note that marcos such as `include and `define are run as part of preprocessing while parameters are defined and used during elaboration; a stage of compilation).
However, there are ways to get the desired behavior. Instead of using the parameter string to directly include a file, you can use it to conditionally instantiate the code from an include file like so:
module top;
...
myInterface #(.assertType("TYPE1")) myInstance();
...
interface myInterface #(parameter assertType = "TYPE0") ();
...
// NOTE: This is NOT inside any process block (like always, initial, etc)
case (assertType)
"TYPE0": begin
`include "assert_type0.sv"
end
"TYPE1": begin
`include "assert_type1.sv"
end
"TYPE2": begin
`include "assert_type2.sv"
end
endcase
...
endinterface
In the above, during compilation, all the assertion code from all the files will be included, but the only ones to take affect will be those included in the file from branch of the case specified by the parameter, and the others will be left uninstantiated.
I am confused with the following SystemVerilog construct used for registering the UVM test with the factory:
class random_test extends uvm_test;
`uvm_component_utils(random_test);
...
function new (...
Here we have a definition of the class random_test, and inside of the definition we call a method whereas its argument is the class that is being defined.
So here are my questions:
Is `uvm_component_utils being called at time 0 even before any object was constructed out of random_test class?
How can we pass a class to `uvm_component_utils in that class definition?
Thanks.
`uvm_component_utils is not a method, it is a macro which is evaluated at compile time.
You can see what the macro does in the UVM source code. Take a look at src/macros/uvm_object_defines.svh within the UVM distribution.
Your example for class random_test will expand to something like this:
typedef uvm_component_registry #(random_test,"random_test") type_id;
static function type_id get_type();
return type_id::get();
endfunction
virtual function uvm_object_wrapper get_object_type();
return type_id::get();
endfunction const static string type_name = "random_test";
virtual function string get_type_name ();
return type_name;
endfunction
I was studying UVM and building some tests and had the same error. After some time searching about i figure out a detail that is your code too.
in:
class random_test extends uvm_test;
`uvm_component_utils(random_test);
...
function new (...
We don't need the semicolon after `uvm_component_utils(random_test)
So, the correct code is:
class random_test extends uvm_test;
`uvm_component_utils(random_test)
...
function new (...
Best Regards
The code guideline for our verification environment is one class per file.
Sometimes a uvm_object is only needed by 1 other uvm_component, so, following object-oriented theory, we should use nested/inner classes.
Nested classes are fully supported by SystemVerilog. However, are they supported by UVM?
Is it possible to compile something like the following:
class inception_level_1 extends uvm_test;
`uvm_component_utils(inception_level_1)
function new(string name = "inception_level_1", uvm_component parent = null);
super.new(name, parent);
endfunction
class inception_level_2 extends uvm_object;
int a;
`uvm_object_utils_begin(inception_level_2)
`uvm_field_int(a, UVM_DEFAULT)
`uvm_object_utils_end
function new(string name = "inception_level_2");
super.new(name);
endfunction
endclass
endclass
Currently the above code gives a compile error:
** Error: testbench.sv(20): (vlog-2889) Illegal to access non-static method 'uvm_report_warning' outside its class scope.
Full code example here: http://www.edaplayground.com/x/3r8
SystemVerilog has packages, which is the preferred mechanism to "hide" class declarations from other packages.
You will have problems using the field macros, or anything else that tries to reference identifiers from inside the inner class that are defined with the same name in both the global uvm_pkg and the outer class. All the uvm_report_... methods are defined in both because uvm_component is extended from uvm_report_object, and uvm_report_... is in the global uvm_pkg.
You will also have problems using the factory with nested classes. Only the outer class will be able to provide overrides by type, but string based overrides by name are global. So even if you nested the inner class, scopes other than the outer class will be able to provide it as an override by string name.
I changed the code to remove the field macros and this runs. So it seems like this is supported if you can give up the field automation macros: http://www.edaplayground.com/x/i5
class inception_level_1 extends uvm_test;
`uvm_component_utils(inception_level_1)
function new(string name = "inception_level_1", uvm_component parent = null);
super.new(name, parent);
endfunction
class inception_level_2 extends uvm_object;
int a;
`uvm_object_utils(inception_level_2)
function new(string name = "inception_level_2");
super.new(name);
endfunction
endclass
endclass
in general it does work. however there are situations where UVM uses shortcuts which conflict with the class-in-class scenario. examples are
string based factory (inception_level_2 can only be registered once despite that foo:inception_level_2 and bla::inception_level_2 would be different classes)
name lookup collision (here for uvm_report_warning which should goto uvm_pkg::uvm_report_warning and not to the enclosing class uvm_component::uvm_report_warning)
... etc