//INTERFACE ///////////////////////////////////
interface clk_interface();
import clk_rst_agent_pkg::*;
//control
logic start_clk;
//output interrfaced
logic clk_o;
logic rst_o;
always
begin
while(start_clk == 1'b1)
begin
#12.5ns;
clk_o = ~clk_o; end
end
endinterface: clk_rst_interface
The first problem is that you’re not initializing the 4-state value clk_o, so
clk_o = ~clk_o;
will always yield an ‘x’ value.
Your second problem is in your driver:
task run_phase(uvm_phase phase);
vif.start_clk = 1'b0; //Disable clk
forever begin
clk_rst_seq_item seq_item;
seq_item_port.get_next_item(seq_item);
phase.raise_objection(this);
case (seq_item.cmd)
START : begin
vif.start_clk = 1'b1; //Enable clk
end
STOP : begin
vif.start_clk = 1'b0; //Disable clk
end
endcase
`uvm_info("CLK Driver", seq_item.convert2string(), UVM_HIGH)
seq_item_port.item_done();
phase.drop_objection(this);
end
endtask
First problem: get_next_item() is blocking, so if there’s any delay in returning, the run_phase() will terminate before you can raise the objection. You must call raise_objection() before any blocking call.
Second problem: You are raising and dropping the objection once for each get_next_item/item_done call, which means that you’ll exit run_phase immediately after processing the first transaction (unless you raise another objection somewhere else). We don’t recommend raising and dropping objections inside the driver anyway, so you can just remove these. Instead, you should raise the run_phase objection from your test before starting the sequence that will issue the instructions. That way you don’t have to worry about the forever loop keeping run_phase going forever.
You should implement phase_ready_to_end in your driver if you want to make sure that you turn off the clock before exiting the phase. See the Cookbook for more detail on phase_ready_to_end.