Ive wriiten uvm testbench for full adder which does not operates on clk and reset. I used event control like @(posedge intf.a,intf.b,intf.cin) , is it the right way to do it?
In reply to Kamran:
Driver code:
class mem_driver extends uvm_driver #(mem_seq_item);
`uvm_component_utils(mem_driver)
// Virtual Interface
virtual mem_if intf;
mem_seq_item item;
// Constructor
function new (string name = "mem_driver", uvm_component parent);
super.new(name, parent);
endfunction : new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(virtual mem_if)::get(null,"*","vif",intf))
begin
`uvm_error("Driver Class","Failed to get vif from config_db")
end
endfunction: build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("DRIVER_CLASS", "Connect Phase!", UVM_HIGH)
endfunction: connect_phase
// run phase
task run_phase(uvm_phase phase);
item = mem_seq_item::type_id::create("item");
super.run_phase(phase);
`uvm_info("DRIVER_CLASS", "Inside Run Phase!", UVM_HIGH)
forever begin
seq_item_port.get_next_item(item);
drive(item);
seq_item_port.item_done();
end
endtask : run_phase
// drive
virtual task drive(mem_seq_item item);
`uvm_info(get_type_name(), "before Posedge", UVM_MEDIUM)
@(posedge intf.a,intf.b,intf.cin)
`uvm_info(get_type_name(), "before Posedge", UVM_MEDIUM)
if(intf.a==8'bxxxxxxxx && intf.b==8'bxxxxxxxx && intf.cin==1'bx)
begin
intf.a = item.a;
intf.b = item.b;
intf.cin = item.cin;
end
`uvm_info(get_type_name(),"Before Dont care",UVM_NONE)
`uvm_info(get_type_name(),$sformatf("a =%d,b=%d,cin=%d",intf.a,intf.b,intf.cin),UVM_NONE)
if(intf.a != 8'bxxxxxxxx && intf.b != 8'bxxxxxxxx && intf.cin != 1'bx)
begin
intf.a = item.a;
intf.b = item.b;
intf.cin = item.cin;
end
`uvm_info(get_type_name(),"After Dont care",UVM_NONE)
`uvm_info(get_type_name(),$sformatf("a =%d,b=%d,cin=%d",intf.a,intf.b,intf.cin),UVM_NONE)
$display("------------------------------------------------------------------");
endtask : drive
endclass : mem_driver
Monitor1 code:
class mem_monitor extends uvm_monitor;
`uvm_component_utils(mem_monitor)
// Virtual Interface
virtual mem_if intf;
bit[7:0] q[$]; // a
//bit[7:0] q2[$]; // b
//bit q3[$]; //cin
uvm_analysis_port #(mem_seq_item) item_collected_port; // port for mon to scb
mem_seq_item item;
// new - constructor
function new (string name = "mem_monitor", uvm_component parent);
super.new(name, parent);
item_collected_port = new("item_collected_port", this);
endfunction : new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db #(virtual mem_if)::get(null,"*","vif",intf))
begin
`uvm_error("Monitor1 Class","Failed to get vif from config_db")
end
endfunction: build_phase
//connect
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("MONITOR1_CLASS", "Connect Phase!", UVM_NONE)
endfunction: connect_phase
// run phase
task run_phase(uvm_phase phase);
item = mem_seq_item::type_id::create("item");
super.run_phase(phase);
forever begin
//sample inputs
`uvm_info(get_type_name(), "before Posedge", UVM_MEDIUM)
@(posedge intf.a,intf.b,intf.cin)
`uvm_info(get_type_name(), "after Posedge", UVM_MEDIUM)
if(intf.a==8'bxxxxxxxx && intf.b==8'bxxxxxxxx && intf.cin==1'bx)
begin
item.a = intf.a ;
item.b = intf.b;
item.cin = intf.cin;
end
`uvm_info(get_type_name(),"Before Dont Care",UVM_NONE)
if(intf.a != 8'b00000000 && intf.b != 8'b00000000 && intf.cin != 1'b0)
begin
item.a = intf.a ;
item.b = intf.b;
item.cin = intf.cin;
end
`uvm_info(get_type_name(),"After Dont care",UVM_NONE)
q.push_front(item.a);
q.push_front(item.b);
q.push_front(item.cin);
if(intf.a== 8'bxxxxxxxx && intf.b== 8'bxxxxxxxx && intf.cin == 1'bx )
begin
item.s=8'bxxxxxxxx;
item.cout = 1'bx;
end
else
begin
item.s=q.pop_front();
item.cout=q.pop_front();
end
`uvm_info(get_type_name(),$sformatf("a =%d,b=%d,cin=%d",intf.a,intf.b,intf.cin),UVM_NONE)
`uvm_info(get_type_name(),"------------------------------------------------------",UVM_NONE)
item_collected_port.write(item);
end
endtask : run_phase
endclass : mem_monitor
My output log is:
UVM_INFO @ 0: reporter [RNTST] Running test mem_model_test…
UVM_INFO scoreboard.sv(14) @ 0: uvm_test_top.env.mem_scb [Scb Class] Inside constructor
UVM_INFO scoreboard.sv(21) @ 0: uvm_test_top.env.mem_scb [Scb Class] Build phase
UVM_INFO driver.sv(24) @ 0: uvm_test_top.env.mem_agnt1.driver [DRIVER_CLASS] Connect Phase!
UVM_INFO monitor1.sv(31) @ 0: uvm_test_top.env.mem_agnt1.monitor [MONITOR1_CLASS] Connect Phase!
UVM_INFO test.sv(21) @ 0: uvm_test_top [TEST_CLASS] Connect Phase!
UVM_INFO scoreboard.sv(28) @ 0: uvm_test_top.env.mem_scb [Scb Class] Inside Run phase
UVM_INFO C:/questasim64_10.7c/verilog_src/uvm-1.1d/src/seq/uvm_sequencer_base.svh(1384) @ 0: uvm_test_top.env.mem_agnt1.sequencer [PHASESEQ] No default phase sequence for phase ‘run’
UVM_INFO monitor1.sv(43) @ 0: uvm_test_top.env.mem_agnt1.monitor [mem_monitor] before Posedge
UVM_INFO driver.sv(34) @ 0: uvm_test_top.env.mem_agnt1.driver [DRIVER_CLASS] Inside Run Phase!
UVM_INFO C:/questasim64_10.7c/verilog_src/uvm-1.1d/src/seq/uvm_sequencer_base.svh(1384) @ 0: uvm_test_top.env.mem_agnt1.sequencer [PHASESEQ] No default phase sequence for phase ‘pre_reset’
UVM_INFO driver.sv(46) @ 0: uvm_test_top.env.mem_agnt1.driver [mem_driver] before Posedge
UVM_INFO C:/questasim64_10.7c/verilog_src/uvm-1.1d/src/base/uvm_phase.svh(1215) @ 0: reporter [PH_READY_TO_END] Phase ‘uvm.uvm_sched.pre_reset’ (id=172) PHASE READY TO END
UVM_INFO C:/questasim64_10.7c/verilog_src/uvm-1.1d/src/seq/uvm_sequencer_base.svh(1384) @ 0: uvm_test_top.env.mem_agnt1.sequencer [PHASESEQ] No default phase sequence for phase ‘reset’
UVM_INFO C:/questasim64_10.7c/verilog_src/uvm-1.1d/src/base/uvm_phase.svh(1215) @ 0: reporter [PH_READY_TO_END] Phase ‘uvm.uvm_sched.reset’ (id=184) PHASE READY TO END
In reply to Kamran:
You still should use an external clock even if your DUT is purely combinational.
The problem with using input signals as events in your driver is your are waiting for your inputs to change, but it will never reach the code that changes the inputs that follows. It hangs. You need to apply stimulus at a regular interval giving enough time for the inputs values to propagate through the DUT to the outputs.
And there are problems using the input signals as events in your monitor. Even if you do fix your driver, you have a race condition with the outputs as you don’t know if they have been updated to reflect the new values of the inputs or still using the old values.
The best way to do this is creating an external clock (a clock that does not go into your DUT) and using that to synchronize driving each input transaction using nonblocking assignments, and have the monitor sample the inputs/outputs using the same external clock.