I am trying a simple example in UVM. I am expecting the clock edge to be detected and print the transactions collected from interface. But, the posedge of clock written inside task ‘run_phase’ is not detected, in the sense, nothing after that clock edge statement is executed. FYI, I don’t have any clocking block declared in the interface. If I don’t use clock edge then it will become an infinite loop and print forever. How to fix this ? Thanks.
class ahb_monitor extends uvm_monitor;
`uvm_component_utils(ahb_monitor);
uvm_analysis_port#(ahb_tx) ap; // analysis port used for broadcasting
virtual ahb_if vif;
ahb_tx tx;
function new (string name ="", uvm_component parent = null); // constructing monitor component
super.new(name,parent);
ap = new ("ap", this); // object for analysis port
endfunction
function void build_phase(uvm_phase phase);
uvm_config_db#(virtual ahb_if)::get(this,"","phy_intf_var",vif);
endfunction
task run_phase(uvm_phase phase);
//$display("mon run phase when reset high at %g", $time);
forever begin
tx = ahb_tx::type_id::create("tx"); // for every new collection, new tx item is created
@(posedge vif.hclk); // here is the problem
tx.addr = vif.addr;
tx.dataQ = vif.dataQ;
tx.wr_rd = vif.wr_rd;
tx.burst_type = vif.burst_type;
$display("displaying monitor contents");
tx.print();
$display("------------------------------");
ap.write(tx); // broadcast Tx
end
endtask
endclass
An additional remark: Move the creation of your transaction outside of the forever loop:
task run_phase(uvm_phase phase);
tx = ahb_tx::type_id::create(“tx”); // for every new collection, new tx item is created
forever begin
@(posedge vif.hclk); // here is the problem
tx.addr = vif.addr;
…
end
endtask
I am not getting UVM fatal print, so which means I am getting virtual interface to monitor, right ?
Below you can see the top and interface. As you can see I have included hclk in interface. Any other reason for the cause of this issue ?
interface ahb_if (input bit hclk, hresetn);
bit [31:0] addr;
bit [31:0] dataQ;
bit wr_rd;
bit [2:0] burst_type;
endinterface
module top;
`include "test_lib.sv"
reg hclk, hresetn;
initial begin
hclk = 1'b0;
forever begin
#5 hclk = ~hclk;
end
end
initial begin // active low reset generation
hresetn = 1'b0;
repeat(10) @(posedge hclk);
hresetn = 1'b1;
end
ahb_if inf(hclk, hresetn); // instantiating interface
initial begin
uvm_config_db #(virtual ahb_if)::set(null,"*","phy_intf_var",inf); // registering physical interface to config_db with field name phy_intf_var
end
initial begin
run_test();
end
endmodule
You are not using monitor component at all? Add and check for any other display messages. Like, “MON: getting interface”, “MON: Entered run phase” etc. See if you are creating monitor component, and not just compiling!
Or run phase is ending immediately, in that case check if you are using objections correctly.
It is better to use setting of virtual interface and run_test() in same initial block as it might cause fail to get method because of execution order of initial block.
initial
begin
uvm_config_db #(virtual ahb_if)::set(null,"*","phy_intf_var",inf);
run_test();
end
I guess you have the classical setter-no-getters issue here. The set should be done to the agent level typically. I see you are doing at null & * - sort of global name-space. You should be able to debug this quite easily through check_config_settings, see my DVCon US slides @ http://www.go2uvm.org/2016/07/advanced-uvm-tutorial-from-dvcon-us-2016-slides-now-available/
I am getting display messages like for example, ‘getting interface’ inside build phase and ‘entered run phase’. I have made run_test and set interface in the same initial block as suggested. No monitor output yet. Could you check if I am raising and dropping objections correctly as shown below:
class ahb_base_seq extends uvm_sequence #(ahb_tx); // created base sequence
`uvm_object_utils(ahb_base_seq);
function new (string name ="");
super.new(name);
endfunction
task pre_body();
if (starting_phase !=null)
starting_phase.raise_objection(this);
endtask
task post_body();
if (starting_phase !=null)
starting_phase.drop_objection(this);
endtask
endclass
// functional sequence
class ahb_10_tx_seq extends ahb_base_seq;
`uvm_object_utils(ahb_10_tx_seq);
function new (string name ="");
super.new(name);
endfunction
task body();
super.pre_body();
repeat(10) `uvm_do_with(req,{ req.wr_rd==1'b1; });
super.post_body();
endtask
endclass
Never raise objections in a sequence. Objections should be raised and dropped only at the test level. This is due to the performance overhead related to the raising and dropping of the objection, as well as the complexity required to determine if it should be raised or dropped.
I found the problem. Sorry, this was due to my carelessness. The driver was finishing at zero simulation time, because while driving I didn’t include clock edge in driver. Thanks to all of your valuable comments, I learned new things from your answers. As I didn’t post my driver code here so all the answers/suggestions are valid and helped me to narrow down to the root cause of the problem. Thank you all.
I used NULL while setting interface in top file because here the context represents its parent name and there is no parent for top file and that is why I kept it NULL and for instance argument I used *, so that the interface is set to all instances below top. This is my understanding. Correct me if I am wrong.