faq

9
PART 1: HOW DO I? How to drive the reset pin of the interface from the sequence rather than from the top testbench module, as in case of traditional testbenches? Does it provide any advantage over the traditional way of driving reset? Driving the reset pin forms the fundamental part of any testbench. It basically marks the start of the traffic phase in the given setup. The following code snippets illustrates about driving the reset pin. // Defines an interface that provides access to a reset signal. // This interface can be used to write sequences to drive the reset logic. interface reset_if(); logic reset; logic clk; modport reset_modport (input clk, output reset); endinterface //Top-level testbench //TB Interface instance to provide access to the reset signal //Set the reset interface on the sequencer module test_top; . . . bit SystemClock; . . . reset_if reset_if(); assign reset_if.clk = SystemClock; initial uvm_config_db#(virtual reset_if.reset_modport)::set(uvm_root::get(), "uvm_test_top.env.sequencer", "reset_mp", reset_if.reset_modport); endmodule //Example UVM sequence for driving reset pin on the interface class simple_reset_sequence extends uvm_sequence; `uvm_object_utils(simple_reset_sequence) . . . virtual task body(); p_sequencer.reset_mp.reset <= 1'b1; repeat(10) @(posedge p_sequencer.reset_mp.clk);

description

faq

Transcript of faq

Page 1: faq

PART 1: HOW DO I?

How to drive the reset pin of the interface from the sequence rather than from the top testbench module, as in case of traditional testbenches? Does it provide any advantage over the traditional way of driving reset?

Driving the reset pin forms the fundamental part of any testbench. It basically marks the start of the traffic phase in the given setup.

The following code snippets illustrates about driving the reset pin.

// Defines an interface that provides access to a reset signal. // This interface can be used to write sequences to drive the reset logic.interface reset_if(); logic reset; logic clk; modport reset_modport (input clk, output reset);endinterface

//Top-level testbench //TB Interface instance to provide access to the reset signal//Set the reset interface on the sequencermodule test_top; . . . bit SystemClock; . . . reset_if reset_if(); assign reset_if.clk = SystemClock;

initial uvm_config_db#(virtual reset_if.reset_modport)::set(uvm_root::get(), "uvm_test_top.env.sequencer", "reset_mp",

reset_if.reset_modport);endmodule

//Example UVM sequence for driving reset pin on the interfaceclass simple_reset_sequence extends uvm_sequence; `uvm_object_utils(simple_reset_sequence) . . . virtual task body(); p_sequencer.reset_mp.reset <= 1'b1;

repeat(10) @(posedge p_sequencer.reset_mp.clk); p_sequencer.reset_mp.reset <= 1'b0;

repeat(10) @(posedge p_sequencer.reset_mp.clk); p_sequencer.reset_mp.reset <= 1'b1; endtask: bodyendclass

The advantages of driving the reset pin from the sequence over the testbench:1. You can provide configurable delay assertion or deassertion of reset pin depending on the requirement.

Page 2: faq

2. If on-the-fly reset needs to be tested, the testbench code remains unchanged.3. You can use the phase jumps to reset and create various interesting scenarios.

How to implement the watchdog for verification environment?In verification environments, you often need to wait for the signal to have specific value and then continue with the execution of procedural code.

initial begin...wait (my_ifc.sig == 1);$display(...);...

end

However, you should always check if the signal eventually gets its expected value.

Different methodologies (vmm/ovm/uvm) suggest different ways to implement this checker, but in this article, the focus is on methodology independent solution.

Generally, you need to start with the following two threads:1. To wait until the signal gets its desired value2. To terminate the waiting process after a specified delay

If the first thread is completed and the signal receives its desired value, you can terminate the second thread and stop waiting for timeout. Alternatively, if timeout is reached, you need to stop waiting for the signal to get its desired value.

This algorithm can be easily implemented with fork-join_any block

initial begin...// watchdog implementation starts herefork : my_watchdog

begin // start thread of waiting for (my_ifc.sig == 1);wait (my_ifc.sig == 1);

end

begin // start thread of timeoutwait #(watchdog_delay);$display("error:...");

endjoin_anydisable my_watchdog;

// report accordinglyif (status == good)

// report good status...

else// report bad status

Page 3: faq

...// watchdog implementation ends here...

end

In the above example, fork-join_any block and disable my_watchdog statementsare used. Both of them are required, fork-join_any starts separate threads for each begin-end block inside of it.fork-join_any unblocks the execution of its scope after any (first) thread within it is finished. However, other threads continue their execution.Thus, you need to disable the running thread inside the fork-join_any after any other internal thread is finished.

There is also another method to kill threads started within fork-join_xxx.fork

begin...

endbegin

...end

join_anydisable fork;

However, disable fork; statement kills all the fork blocks (and their internal threads) in its scope. If you decide to use disable fork, you need to make sure to enclose your fork-join_any block within its own scope formed by begin-end.

`define watchdog(SIG, VALUE, DELAY) \ begin \

fork \ begin \ wait (SIG === VALUE); \ end \ begin \ #(DELAY); \ $display(`"error: watchdog timer expired waiting for SIG to get VALUE`"); \ end \ join_any \ disable fork; \ end

Page 4: faq

What information should I know about driver-sequencer connection in UVM?

In UVM, it is mandatory to connect the "seq_item_port" provided inside the uvm_driverto a sequencer's export("seq_item_export").

If you try to access "get_next_item" of the port without the mandatory connection, you get a null access error from the uvm base code as the port is trying to accessthe export which is not connected.

To avoid such errors and debug effort, add the below check in the driver (extended from uvm_driver) after the connect_phase.

if (seq_item_port.size()==0) `uvm_fatal("run_phase","seq_item_port unconnected") else seq_item_port.get_next_item(req); ....

Here, the check is present in the run_phase.

There are "Connection Error" checks in the UVM port base class for the "seq_item_port" to check for minimum and maximum number of exports to which it is connected. Since seq_item_port is configured to connect to minimum zero and maximum one export,it does not flag any error when the port is not connected to any export.

How to implement dynamic/soft reset in UVM?

Sometimes dynamic/soft reset is requred in normal simulation flow. UVM offers a mechanisam to make the run-time phasing jump to a specified phase, that is the jump() task of uvm_phase.

For the the jump() task of uvm_phase, if the destination phase of jump is within the current phase schedule, a simple local jump takes place. If the jump-to phase is outside of the current schedule then the jump affects other schedules which share the phase.

You just need to call phase.jump(uvm_reset_phase::get()) in main_phase to implement dynamic reset. Once phase.jump(uvm_reset_phase::get()) is called in main_phase in any object, and then the phase jump to reset_phase.

Page 5: faq

Note that all the components objects of the same uvm_domain will also jump to the reset_phase after main_phase finishes, but the compnents that do not belong to this domain will not jump to the reset_phase and keep their normal flow.

The following example demonstrates how you can achieve the dynamic resets in UVM.In this example top_obj, a_obj and b_obj are in the same uvm_domain.

///////////////Source code/////////////module test; import uvm_pkg::*;

class A extends uvm_component; function new (string name, uvm_component parent); super.new(name,parent); endfunction endclass

class B extends uvm_component; function new (string name, uvm_component parent); super.new(name,parent); endfunction endclass

class top extends uvm_env;

bit first_reset = 1'b1;

A a_obj; B b_obj;

function new (string name, uvm_component parent); super.new(name,parent); endfunction function void build_phase(uvm_phase phase); $display("%0t: %0s: build", $time, get_full_name()); a_obj = new("a_obj", this); b_obj = new("b_obj", this); endfunction function void end_of_elaboration_phase(uvm_phase phase); $display("%0t: %0s: end_of_elaboration", $time, get_full_name()); endfunction function void start_of_simulation_phase(uvm_phase phase); $display("%0t: %0s: start_of_simulation", $time, get_full_name()); endfunction

task reset_phase(uvm_phase phase);

Page 6: faq

phase.raise_objection(this); $display("%0t: %0s: reset phase", $time, get_full_name()); phase.drop_objection(this); endtask task configure_phase(uvm_phase phase); phase.raise_objection(this); $display("%0t: %0s: configure phase", $time, get_full_name()); phase.drop_objection(this); endtask task main_phase(uvm_phase phase); phase.raise_objection(this); $display("%0t: %0s: start main phase", $time, get_full_name()); if (first_reset) begin first_reset = 0; phase.jump(uvm_reset_phase::get()); //<-- calls jump() task end $display("%0t: %0s: end main phase", $time, get_full_name()); phase.drop_objection(this); endtask

task shutdown_phase(uvm_phase phase); $display("%0t: %0s: shutdown phase", $time, get_full_name()); endtask function void extract_phase(uvm_phase phase); $display("%0t: %0s: extract", $time, get_full_name()); endfunction function void check_phase(uvm_phase phase); $display("%0t: %0s: check", $time, get_full_name()); endfunction function void report_phase(uvm_phase phase); $display("%0t: %0s: report", $time, get_full_name()); endfunction function void final_phase(uvm_phase phase); $display("%0t: %0s: final", $time, get_full_name()); endfunction

endclass top top_obj = new("top", null);

initial begin run_test(); end

endmodule

Page 7: faq

///////////////Simulation result/////////////UVM_INFO @ 0: reporter [RNTST] Running test ...0: top: build0: top: end_of_elaboration0: top: start_of_simulation0: top: reset phase0: top: configure phase0: top: start main phaseUVM_INFO /global/apps2/vcs_2011.03/etc/uvm/base/uvm_phases.svh(2189) @ 0: reporter [PH_JUMP] phase main (schedule uvm_sched, domain uvm) is jumping to phase resetUVM_WARNING @ 0: main [OBJTN_CLEAR] Object 'uvm_top' cleared objection counts for main0: top: end main phase0: top: reset phase //<-- all the components phase jump to reset phase and run again0: top: configure phase0: top: start main phase0: top: end main phase0: top: shutdown phase0: top: extract0: top: check0: top: report0: top: final