UVM-RAL logging into file after DUT initializaton - system-verilog

I want log all the UVM RAL register's along with their fields into separate file. for quick debugging. Do RAL supports any easiest way of doing it.
Thanks
Saravanan

One way to to that is by using the uvm built-in sprint() and directing all of its output to a file.
Below is an example on how to do that, assuming your register is implemented in test level:
class my_test extends uvm_test;
my_reg_block my_rm;
UVM_FILE my_file;
//...
function new(string name="", uvm_component parent=null);
my_file = $fopen("register_initial.txt", "w");
set_report_id_file("MY_REG", my_file);
set_report_id_action("MY_REG", UVM_LOW | UVM_DISPLAY);
endfunction
// create your register
function void print_register();
`uvm_info("MY_REG", $sformatf("%s", my_rm.sprint()), UVM_LOW)
endfunction
endclass
The above print_register() function will write the output of my_rm.sprint() to file "register_initial.txt".

Related

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

SystemVerilog task that can force any signal in interface module

interface dut_if();
logic sig_a_i;
logic [1:0] sig_b_i;
endinterface
module tb();
dut_top dut(
.sig_a_i (vif.sig_a_i);
.sig_b_i (vif.sig_b_i);
);
dut_if vif();
endmodule
How to create a task() method inside the interface class such that I can easily call it within my test class to force/release any DUT signal I like?
class dut_testA_vseq extends dut_base_vseq;
...
virtual task body();
p_sequencer.vif.force_dut_signal(0);
endtask
endclass
I'm new to SV and I don't know how to write force_dut_signal() that can cater to any signal (single bit or a bus).
task force_dut_signal(logic? port_name, bit? force_val) begin
force port_name? = force_val;
endtask
The ? in the code snippet above are parts I don't know if possible or what.
Thanks in advance!
There is nothing in SystemVerilog that allows you to pass a hierarchical reference to a signal as a reference to a task/function argument. Inside your interface, you will need to create a function for each signal or group of signals you need to force. Then call that function from class.
BTW, always use functions instead of tasks for non-time-consuming procedures.
You could pass a signal by reference into your task. However the data types must match and you can't use a fork, join_any, join_none inside your task. This works for sig_a_i only:
interface dut_if();
logic sig_a_i;
logic [1:0] sig_b_i;
endinterface
module dut_top(
input logic sig_a_i,
input logic [1:0] sig_b_i);
endmodule
module tb();
dut_top dut(
.sig_a_i (vif.sig_a_i),
.sig_b_i (vif.sig_b_i)
);
dut_if vif();
function automatic force_1bit_logic(ref logic signal, input bit value);
signal = value;
endfunction
initial begin
#1;
force_1bit_logic(vif.sig_a_i, 0);
#10;
force_1bit_logic(vif.sig_a_i, 1);
end
endmodule

What is the purpose the 'new' and 'virtual' in systemverilog?

I'm trying to learn about SystemVerilog. While reading about it, I came across the following code, which I cannot fully understand:
Test1.
class A ; 
task disp();
$display(" This is class A "); 
endtask 
endclass 
class EA extends A ; 
task disp (); 
$display(" This is Extended class A "); 
endtask 
endclass 
program main ; 
EA my_ea; 
A my_a; 
initial 
begin 
my_a.disp(); 
my_a = my_ea; 
my_a.disp(); 
end 
endprogram 
Test2.
class A ; 
virtual task disp (); 
$display(" This is class A "); 
endtask 
endclass 
class EA extends A ; 
task disp (); 
$display(" This is Extended class A "); 
endtask 
endclass 
program main ; 
EA my_ea; 
A my_a; 
initial 
begin 
my_a = new(); 
my_a.disp(); 
my_ea = new(); 
my_a = my_ea; 
my_a.disp(); 
end 
endprogram 
I have some questions about the test1 code above. There is a call to some 'new' function, but the implementation of that is not provided anywhere. How can this code compile and run then?
Also in the test2, you can see the 'virtual' keyword. I do not understand the reason behind using 'virtual'. Can you please explain why do we have to use 'virtual' in this context?
update
I'd like to implement the example code from Greg.
But I've got some problem as the below
Chronologic VCS (TM)
Version J-2014.12-SP1-1 -- Wed Aug 8 08:33:23 2018
Copyright (c) 1991-2014 by Synopsys Inc.
ALL RIGHTS RESERVED
This program is proprietary and confidential information of Synopsys Inc.
and may be used and disclosed only as authorized in a license agreement
controlling such use and disclosure.
Parsing design file 'design.sv'
Parsing design file 'testbench.sv'
Error-[SE] Syntax error
Following verilog source has syntax error :
"testbench.sv", 21: token is '('
function(A a);
^
1 error
CPU time: .073 seconds to compile
Exit code expected: 0, received: 1
Done
The new keyword is a constructor, it creates the object. Since new is not defined it is inferring the default constructor:
function new();
endfunction
Objects must be constructed before you call any of there methods. Test1 should through a null pointer error because you call an object's method that hasn't been constructed.
The virtual keyword and concept is the same in C++, Java, etc. There are plenty of explanations of this already answered on the virtual topic and polymorphism, such as : Why do we need virtual functions in C++?
In a nutshell a parent handle pointing to a child object can execute the object's method if it is virtual. Best way understant this is the create a class and child class that has both a virtual and non-virtual methods. Example:
module main ;
class A ;
function void disp ();
$display(" Non-Virtual from A ");
endfunction
virtual function void vdisp ();
$display(" Virtual from A ");
endfunction
endclass
class EA extends A ;
function void disp ();
$display(" Non-Virtual from EA ");
endfunction
virtual function void vdisp ();
$display(" Virtual from EA ");
endfunction
endclass
function void disp(A a);
a.disp();
a.vdisp();
endfunction
EA my_ea;
A my_a;
initial
begin
my_a = new();
my_ea = new();
disp(my_a);
disp(my_ea);
my_a = my_ea;
disp(my_a);
end
endmodule

SystemVerilog: registering UVM test with the factory

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

Does UVM support nested/inner classes?

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