Free Online Training Events
Free Technical Resources
The following code fragments may be downloaded for use by readers of the Doulos UVM Golden Reference Guide. You may freely use them in your projects subject to the Apache 2.0 License both privately and commercially. Please do not publish or re-distribute to others except by recommending they get a copy of our UVM Golden Reference Guide. If you wish to use some fragment in a presentation or article you are writing, please request permission from Doulos.
Click here to download the examples below as a zip file, or use the links below to jump to a particular example.
Click on the links under each section to run prepared examples in a live simulation environment using EDA Playground.
Click here to use EDA Playground to run your own sample code.
Try out an example using this feature in EDA Playground
class example_agent_t extends uvm_agent; `uvm_component_utils(example_agent_t) example_sequencer_t #(example_transaction_t) m_sequencer; example_driver_t m_driver; example_monitor_t m_monitor; uvm_analysis_port #(example_transaction_t) monitor_ap; virtual dut_if v_dut_if; function new( string name, uvm_component parent ); super.new(name, parent); endfunction: new virtual function void build_phase(uvm_phase phase); super.build_phase(phase); m_monitor = example_monitor_t::type_id::create("m_monitor", this); monitor_ap = new("monitor_ap", this); if ( get_is_active() == UVM_ACTIVE ) begin m_sequencer = example_sequencer_t::type_id::create( "m_sequencer", this); m_driver = example_driver_t ::type_id::create( "m_driver", this); end endfunction: build_phase virtual function void connect_phase(uvm_phase phase); m_monitor.monitor_ap.connect(monitor_ap); // code to connect monitor's virtual interface //... if ( get_is_active() == UVM_ACTIVE ) begin m_driver.seq_item_port.connect(m_sequencer.seq_item_export); // code to connect driver's virtual interface //... end endfunction: connect_phase //... endclass: example_agent_t
Try out an example using this feature in EDA Playground
class cpu_scoreboard_t extends uvm_scoreboard; `uvm_component_utils(cpu_scoreboard_t) // Fetched instructions are observed here: uvm_analysis_export #(fetch_xact_t) af_fetch_export; // Execution results are observed here: uvm_analysis_export #(exec_xact_t) af_exec_export; Instr_Set_Simulator m_iss; uvm_algorithmic_comparator #(.BEFORE(fetch_xact_t), .AFTER(exec_xact_t), .TRANSFORMER(Instr_Set_Simulator) ) m_comp; function new( string name, uvm_component parent ); super.new(name, parent); endfunction: new virtual function void build_phase(uvm_phase phase); super.build_phase(phase); // Create the transformer object m_iss = Instr_Set_Simulator::type_id::create("m_iss", this); // Create analysis exports af_fetch_export = new("af_fetch_export", this); af_exec_export = new("af_exec_export", this); // Supply the transformer object to the comparator m_comp = new("comp", this, m_iss); endfunction: build_phase virtual function void connect_phase(uvm_phase phase); af_fetch_export.connect( m_comp.before_export ); af_cpu_export.connect( m_comp.after_export ); endfunction: connect_phase integer m_logfile; virtual function void start_of_simulation_phase(uvm_phase phase); m_logfile = $fopen("cpu_comparator_log.txt"); set_report_id_action_hier("Comparator Match",UVM_LOG); set_report_id_file_hier ("Comparator Match",m_logfile); set_report_id_action_hier("Comparator Mismatch",UVM_LOG); set_report_id_file_hier("Comparator Mismatch",m_logfile); endfunction: start_of_simulation_phase endclass: cpu_scoreboard_t
Try out an example using this feature in EDA Playground
class custom_subscr_1_t extends uvm_subscriber #(example_transaction_t); // code for first custom subscriber //... class custom_subscr_2_t extends uvm_subscriber #(example_transaction_t); // code for second custom subscriber //... class example_double_subscriber_t extends uvm_component; `uvm_component_utils(example_double_subscriber_t) custom_subscr_1_t subscr1; custom_subscr_2_t subscr2; uvm_analysis_export #(example_transaction_t) analysis_export; function new(string name, uvm_component parent); super.new(name, parent); endfunction : new function void build_phase(uvm_phase phase); subscr1 = custom_subscr_1_t::type_id::create("subscr1", this ); subscr2 = custom_subscr_2_t::type_id::create("subscr2", this ); analysis_export = new ( "analysis_export", this ); endfunction function void connect_phase(uvm_phase phase); // Connect the analysis export to both internal components analysis_export.connect(subscr1.analysis_export); analysis_export.connect(subscr2.analysis_export); endfunction endclass
Try out an example using this feature in EDA Playground
class usb_driver_t extends uvm_driver#(usb_trans_t); `uvm_component_utils(usb_driver_t) uvm_barrier m_barrier; //... task post_reset_phase(uvm_phase phase); // Wait for the barrier before proceeding m_barrier.wait_for(); endtask endclass class spi_driver_t extends uvm_driver#(spi_trans_t); `uvm_component_utils(spi_driver_t) uvm_barrier m_barrier; //... task pre_main_phase(uvm_phase phase); // Wait for the barrier before proceeding m_barrier.wait_for(); endtask endclass class top_env extends uvm_env; `uvm_component_utils(top_env) uvm_barrier m_barrier; usb_driver_t m_usb_drv; spi_driver_t m_spi_drv; //... function void build_phase(uvm_phase phase); super.build_phase(phase); // Create a barrier for 2 processes m_barrier = new("m_barrier", 2); m_usb_drv = usb_driver_t::type_id::create("m_usb_drv",this); m_spi_drv = spi_driver_t::type_id::create("m_spi_drv",this); // Pass the barrier object to the drivers m_usb_drv.m_barrier = m_barrier; m_spi_drv.m_barrier = m_barrier; endfunction /... endclass
uvm_callback_iter#(mycomp_t,mycb_t) iter = new(this); for (mycb_t cb = iter.first();cb != null;cb = iter.next()) cb.dosomething();
Try out an example using this feature in EDA Playground
typedef class my_driver; virtual class driver_cbs_t extends uvm_callback; `uvm_object_utils(driver_cbs_t) // Constructor function new(string name = "driver_cbs_t"); super.new(name); endfunction // Callback method virtual task trans_received(my_driver_t drv, trans_t tr); drv.uvm_report_info("callback", "In trans_received()"); endtask // Callback method virtual task trans_executed(my_driver_t drv, trans_t tr); endtask endclass : driver_cbs_t
class my_driver_t extends uvm_driver#(trans_t); `uvm_register_cb(my_driver_t,driver_cbs_t)//Register callbacks `uvm_component_utils(my_driver_t) //... task run_phase(uvm_phase phase); forever begin seq_item_port.get_next_item(tr); // Call callback task `uvm_do_callbacks(my_driver, driver_cbs, trans_received(this,tr)) // Drive the transaction //... // Call callback task `uvm_do_callbacks(my_driver, driver_cbs, trans_executed(this,tr)) seq_item_port.item_done(tr); end endtask : run_phase endclass : my_driver_t
class error_cb_t extends driver_cbs_t; `uvm_object_utils(error_cb_t) // Constructor function new(string name = "error_cb_t"); super.new(name); endfunction task trans_received(my_driver_t drv, trans_t tr); bit [2:0] i; // Twiddle up to 8 bits repeat ($urandom_range(8)) assert(std::randomize(i)) begin tr.data[i] = ~tr.data[i]; // Corrupt the data end else drv.uvm_report_warning("Error Callback", "Unable to select bit to twiddle!" ); endtask task trans_executed(my_driver_t drv, trans_t tr); // Implement the trans_executed callback endtask endclass : error_cb_t
class error_injector_test_t extends uvm_test; `uvm_component_utils(error_injector_test_t) //... function void start_of_simulation_phase(uvm_phase phase); my_driver_t drv; // Driver in the environment error_cb_t e_cb; // User defined callbacks class e_cb = new( "e_cb" ); // Create the error injecting callbacks // Find the driver where the callbacks will be installed $cast(drv, uvm_top.find( "*.m_drv" )); // Install the callbacks in the driver uvm_callbacks #(my_driver, driver_cbs)::add(drv, e_cb); endfunction : start_of_simulation_phase endclass : error_injector_test_t
string all_cmdline_args[$]; string all_uvm_cmdline_args[$]; uvm_cmdline_proc.get_args(all_cmdline_args); uvm_cmdline_proc.get_uvm_args(all_uvm_cmdline_args); `uvm_info("", $sformatf( {"There were %0d command-line arguments, ", "including %0d UVM ones"}, all_cmdline_args.size(), all_uvm_cmdline_args.size()), UVM_NONE)
% simulator \ +uvm_set_verbosity=uvm_test_top.m_env.m_driver,_ALL_,UVM_FULL,build ...
% simulator \ +uvm_set_verbosity=uvm_test_top.*,_ALL_,UVM_FULL,time,200 ...
Try out an example using this feature in EDA Playground
function bit My_transaction_t::do_compare(uvm_object rhs, uvm_comparer comparer); My_transaction_t t; bit result = 1; $cast(t,rhs); result &= comparer.compare_field("op", op, t.op, $bits(op)); if (op != NOP) result &= comparer.compare_field("dst", dst, t.dst, $bits(dst)); //... return result; endfunction : do_compare
% compiler +define+UVM_NO_DEPRECATED ...
% compiler +define+UVM_NO_DPI ...
% compiler +define+UVM_CB_TRACE_ON ...
class lookup_table_t #(WIDTH=10) extends uvm_component; uvm_blocking_get_imp #(int,lookup_table_t#(WIDTH)) get_export; int lut [WIDTH]; int index = 0; // when using field automation - must be after definitions `uvm_component_param_utils_begin(lookup_table_t#(WIDTH)) `uvm_field_sarray_int(lut,UVM_ALL_ON + UVM_DEC) `uvm_component_utils_end function new (string name, uvm_component parent); super.new(name,parent); endfunction : new function void build_phase(uvm_phase phase); super.build_phase(phase); foreach (lut[i]) lut[i] = i * 10; get_export = new("get_export",this); endfunction: build_phase task get (output int val); #10 val = lut[index++]; if (index > WIDTH-1) index = 0; endtask: get endclass: lookup_table_t
uvm_config_db #(int)::set(this,"*driver", "iterations", 50);
uvm_config_db #(int)::set(this,"/.*driver/", "iterations", 50);
if ( !uvm_config_db #(int)::get(this,"","iterations", n_iterations) ) // In the absence of a config setting, use a default value: n_iterations = 20;
uvm_config_db#(uvm_sequence_base)::set( null, "/.*m_env.m_sequencer.run_phase/", // Regular expression "default_sequence", my_sequence::type_id::get());
class verif_env_t extends uvm_env; int m_n_cycles; string m_lookup; instruction_t m_template; typedef enum {IDLE,FETCH,WRITE,READ} bus_state_t; bus_state_t m_bus_state; // remember when using field automation - must be after definitions `uvm_component_utils_begin(verif_env_t) `uvm_field_string(m_lookup,UVM_DEFAULT) `uvm_field_object(m_template,UVM_DEFAULT) `uvm_field_enum(bus_state_t,m_bus_state,UVM_DEFAULT) `uvm_component_utils_end //... endclass: verif_env_t class test2 extends uvm_test; `uvm_component_utils(test2) register_instruction_t inst = new(); string str_lookup; //... function void build_phase(uvm_phase phase); //... uvm_config_db #(bus_state_t)::set( null,"*env1.*","m_bus_state",verif_env::IDLE); uvm_config_db #(string)::set( null,"*","m_lookup",str_lookup); uvm_config_db #(register_instruction_t)( null,"*","m_template",inst); //... endfunction : build_phase //... endclass : test2
// In a test, create an entry "count" in the global configuration // settings table ... uvm_config_db#(int)::set(this,"*","count",1000); // ... and retrieve the value of "count" if (!uvm_config_db#(int)::get(this,"","count",m_n_cycles)) m_n_cycles = 1500; // use default value
class my_factory_t extends uvm_delegate_factory; virtual function void set_inst_override_by_type( uvm_object_wrapper original_type, uvm_object_wrapper override_type, string full_inst_path ); `uvm_info("FACTORY","",UVM_DEBUG) delegate.set_inst_override_by_type(original_type, override_type, full_inst_path); endfunction endclass //... function my_test::new(...); super.new(...); uvm_coreservice_t cs = uvm_coreservice_t::get(); my_factory_t f = new(); f.delegate = uvm_factory::get(); cs.set_factory(f); endfunction
Try out an example using this feature in EDA Playground
class example_driver_t extends uvm_driver#(my_transaction_t); `uvm_component_utils(example_driver_t) //... virtual task run_phase(uvm_phase phase); forever begin seq_item_port.get_next_item(req); phase.raise_objection(this); // Code to generate physical signal activity // as specified by transaction data in req seq_item_port.item_done(); phase.drop_objection(this); end endtask endclass: example_driver_t
class example_push_driver_t extends uvm_push_driver #(my transaction_t); `uvm_component_utils(example_push_driver_t) //... // Called by push_sequencer through TLM export task put (my_transaction_t item); // code to generate physical signal activity // as specified by transaction data in item endtask : put //... endclass: example_push_driver_t
class my_sequence extends uvm_sequence#(my_transaction); `uvm_object_utils(my_sequence) // pre_start() is called before start() task pre_start(); // raise objection if started as a root sequence starting_phase = get_starting_phase(); // UVM 1.2 if ( starting_phase != null ) starting_phase.raise_objection(this); endtask // start() handshakes the sequence's main activity - body() task body(); // do interesting activity //... endtask // post_start() is called after start() completes task post_start(); // drop objection if started as a root sequence if ( starting_phase != null ) starting_phase.drop_objection(this); endtask endclass
class my_test_t extends uvm_test; `uvm_component_utils(my_test_t) my_env_t m_env; my_sequence_t seq; //... task main_phase(uvm_phase phase); seq.starting_phase = phase; // UVM-1.1 seq.set_starting_phase(phase); // UVM-1.2 seq.start(m_env.m_sequencer); endtask //... endclass
class my_test_t extends uvm_test; `uvm_component_utils(my_test_t) my_env_t m_env; my_sequence_t seq; //... task main_phase(uvm_phase phase); phase.raise_objection(this); // blocks until the sequence has completed on the sequencer seq.start(m_env.m_sequencer); // Set a 'drain time' for the test uvm_objection obj = phase.get_objection(); obj.set_drain_time( this, 100ns ); phase.drop_objection(this); endtask //... endclass
class verif_env_t extends uvm_env; `uvm_component_utils(verif_env_t) // Testbench methodology components //... function new(string name, uvm_component parent); super.new(name,parent); endfunction : new function void build_phase(uvm_phase phase); // Instantiate top-level components using "new" or // the factory, as appropriate //... endfunction: build_phase virtual function void connect_phase(uvm_phase phase); // Connect ports-to-exports //... endfunction: connect_phase virtual task run_phase(uvm_phase phase); // Prevent simulation from ending - do this before the first wait. // Not needed here if it is in the test class phase.raise_objection(this); // Control stimulus generation //... // Allow simulation to end phase.drop_objection(this); endtask: run_phase endclass: verif_env_t
Try out an example using this feature in EDA Playground
typedef uvm_event basic_tr_event_t; class C extends uvm_component; `uvm_component_utils(C) basic_tr_event_t e1; function new (string name, uvm_component parent); super.new(name,parent); endfunction : new function void build_phase(uvm_phase phase); super.build_phase(phase); e1 = new ("e1"); endfunction: build_phase task run_phase(uvm_phase phase); basic_transaction_t tx,rx; tx = new(); fork begin tx.data = 10; tx.addr = 1; #10 e1.trigger(tx); end begin e1.wait_ptrigger(); $cast(rx, e1.get_trigger_data()); rx.print(); end join endtask: run_phase endclass: C
class my_e_callback_t extends uvm_event_callback; function new (string name=""); super.new(name); endfunction : new function void post_trigger(uvm_event e, uvm_object data=null); basic_transaction_t rx; if (data) begin $cast(rx,data); `uvm_info("CBACK",$sformatf("Received %s", rx.convert2string()),UVM_NONE) end endfunction: post_trigger endclass: my_e_callback_t
my_e_callback_t cb1; //... cb1 = new ("cb1"); //in build_phase //... e1.add_callback(cb1); //in run_phase
class verif_env_t extends uvm_env; // Register the environment with the factory `uvm_component_utils(verif_env_t) //... instruction_t m_template; //... function void build_phase(uvm_phase phase); super.build_phase(phase); //... // Use the factory to create the m_template object m_template = instruction_t::type_id::create("m_template", this); endfunction : build_phase endclass: verif_env_t class test1 extends uvm_test; `uvm_component_utils(test1) verif_env_t env1; //... function void build_phase(uvm_phase phase); uvm_factory factory = uvm_factory::get(); //... // Change type of m_template from instruction to // register_instruction using factory method factory.set_inst_override_by_name("instruction", "register_instruction","*env?.m_template"); // Type overrides have lower precedence than inst overrides factory.set_type_override_by_type( instruction_t::get_type(), same_regs_instruction_t::get_type() ); // Print all factory overrides and registered classes factory.print(); // Call factory method to create top-level environment // (requires cast so type_id::create is generally preferred) $cast(env1,factory.create_component_by_type( verif_env_t::get_type(),"","env1",null) ); endfunction : build_phase //... endclass : test1
class basic_transaction extends uvm_sequence_item; rand bit[7:0] addr, data; //... `uvm_object_utils_begin(basic_transaction) `uvm_field_int(addr,UVM_ALL_ON) `uvm_field_int(data,UVM_ALL_ON | UVM_BIN) `uvm_object_utils_end endclass : basic_transaction
uvm_get_to_lock_dap#(string) version; version.set("Initial version"); version.set("Second version"); // Overwrite initial value `uvm_info("DAP example",version.get(),UVM_MEDIUM); assert(version.try_get(text) == 1); assert(version.try_set(text) == 0); version.set("cause an error");
Try out an example using this feature in EDA Playground
// Create an objection for heartbeat monitoring uvm_callbacks_objection hb_objection = new("hb_objection"); // An instance of this class will be monitored class my_driver_t extends uvm_driver #(trans_t); //... task run_phase(uvm_phase phase); //... // This must happen between every two event triggers in my_env // This in effect says "I'm alive" hb_objection.raise_objection(this); //... endtask //... endclass : my_driver_t class my_env_t extends uvm_env; //... uvm_event#(uvm_object) hb_event; my_driver_t m_driver; uvm_heartbeat hb; function new (string name, uvm_component parent); super.new(name,parent); // Create a heartbeat for my_env using hb_objection. hb = new("hb", this, hb_objection); hb.add(m_driver); endfunction //... task run_phase(uvm_phase phase); hb_event = new ("hb_event"); //... hb.set_mode(UVM_ALL_ACTIVE); hb.start(hb_event); fork forever // At least one raise or drop must occur // between successive triggers #10 hb_event.trigger(this); //... join_any hb.stop(); hb.remove(m_driver); endtask //... endclass : my_env_t
class fullchip_sb_t extends uvm_scoreboard; //... // Analysis port method that compares the returned value from the // design's interface with the RTL's current value function void write(input AXItran_t t); uvm_hdl_data_t value; // Probe into the design assert (uvm_hdl_read("top_tb.dut.csr", value)) else `uvm_error("FULLCHIPSB", "Cannot read top_tb.dut.csr"); assert ( t.data === value ) `uvm_error("FULLCHIPSB", $sformatf("Returned value (%h) != RTL value (%h)", t.data, value )) endfunction endclass : fullchip_sb_t
Try out an example using this feature in EDA Playground
class cpu_scoreboard_t extends uvm_scoreboard; `uvm_component_utils(cpu_scoreboard_t) uvm_analysis_export #(exec_xact) af_iss_export; uvm_analysis_export #(exec_xact) af_cpu_export; uvm_in_order_class_comparator #(exec_xact) m_comp; function new(string name, uvm_component parent); super.new(name, parent); endfunction: new virtual function void build_phase(uvm_phase phase); super.build_phase(phase); af_iss_export = new("af_iss_export", this); af_cpu_export = new("af_cpu_export", this); m_comp = new("comp", this); endfunction: build_phase virtual function void connect_phase(uvm_phase phase); af_iss_export.connect( m_comp.before_export ); af_cpu_export.connect( m_comp.after_export ); endfunction: connect_phase integer m_log_file; virtual function void start_of_simulation_phase(uvm_phase phase); m_log_file = $fopen("cpu_comparator_log.txt"); set_report_id_action_hier("Comparator Match",UVM_LOG); set_report_id_file_hier ("Comparator Match", m_log_file); set_report_id_action_hier("Comparator Mismatch", UVM_LOG); set_report_id_file_hier ("Comparator Mismatch", m_log_file); endfunction: start_of_simulation_phase virtual function void report_phase(uvm_phase phase); string txt; $sformat(txt, "#matches = %d, #mismatches = %d", m_comp.m_matches, m_comp.m_mismatches); `uvm_info("", txt,UVM_NONE) endfunction: report_phase endclass: cpu_scoreboard_t
class example_monitor_t extends uvm_monitor; `uvm_component_utils (example_monitor_t) uvm_analysis_port #(example_transaction_t) monitor_ap; virtual example_virtual_if vif; virtual function void build_phase(uvm_phase phase); super.build_phase(phase); monitor_ap = new("monitor_ap", this); endfunction: build_phase //... virtual task run_phase(uvm_phase phase); example_transaction_t tr; forever begin // Start with a new, clean transaction so that // already-monitored transactions are unaffected tr = new; // code to observe physical signal activity // and assemble transaction data in tr monitor_ap.write(tr); end endtask endclass: example_monitor_t
Try out an example using this feature in EDA Playground
task run_phase(uvm_phase phase); phase.raise_objection(this); forever begin my_transaction_t tx; #10 phase.drop_objection(this); seq_item_port.get_next_item(tx); phase.raise_objection(this); seq_item_port.item_done(); end endtask: run_phase
class mytest extends uvm_test; //... virtual task run_phase(uvm_phase phase); uvm_objection obj; obj = phase.get_objection(); obj.set_drain_time(10ns); phase.raise_objection(this); `uvm_do_on(seq, seqr); phase.drop_objection(this); endtask endclass
// Create a global pool somewhere like in a package package my_pkg; uvm_pool #(string,axi_cfg_t) m_global_pool = uvm_pool#(string,axi_cfg_t)::get_global_pool(); endpackage
// Add config objects to the global pool in the testcase begin axi_cfg_t axi_cfg1, axi_cfg2, axi_cfg3; axi_cfg1 = new(...); axi_cfg2 = new(...); axi_cfg3 = new(...); axi_cfg1.randomize with { data < 8'h7fff; ... }; axi_cfg2.randomize with { ... }; axi_cfg3.randomize with { ... }; my_pkg::m_global_pool.add("axi_cfg1", axi_cfg1); my_pkg::m_global_pool.add("axi_cfg2", axi_cfg2); my_pkg::m_global_pool.add("axi_cfg2", axi_cfg3); end
// Retrieve the config object in a test sequence task body(); axi_cfg_t cfg; cfg = my_pkg::m_global_pool.get("axi_cfg1"); `uvm_do_with(req, { req.data == cfg.data, ... }) endtask
Try out an example using this feature in EDA Playground
class my_object_t extends uvm_object; int addr = 198; int data = 89291; string name = "This is my test string"; `uvm_object_utils_begin( my_object_t ) `uvm_field_int( addr, UVM_ALL_ON ) `uvm_field_int( data, UVM_ALL_ON ) `uvm_field_string( name, UVM_ALL_ON ) `uvm_object_utils_end //... endclass : my_object_t module top; my_object_t my_obj = new("my_obj"); initial begin // Print using the table printer uvm_default_printer = uvm_default_table_printer; $display("# This is from the table printer\n"); my_obj.print(); // Print using the tree printer uvm_default_printer = uvm_default_tree_printer; $display("# This is from the tree printer\n"); my_obj.print(); // Print using the line printer $display("# This is from the line printer\n"); my_obj.print(uvm_default_line_printer); end endmodule : top
class my_printer_t extends uvm_table_printer; // Print out the time and name before printing an object function void print_object( string name, uvm_object value, byte scope_separator="."); // Header information to print out (use write_steam()) write_stream( $sformatf( "Printing object %s at time %0t:\n",name, $time) ); // Call the parent function to print out object super.print_object(name, value, scope_separator ); endfunction : print_object endclass : my_printer_t my_printer_t my_special_printer = new(); module top; my_object_t my_obj = new( "my_obj" ); initial begin #100; // Print using my_printer my_obj.print( my_special_printer ); end endmodule : top
Try out an example using this feature in EDA Playground
// Using default printer: uvm_default_printer.knobs.indent = 5; // Indent by 5 spaces uvm_default_printer.knobs.type_name = 0; // No type values
// Using tree printer: uvm_default_printer = uvm_default_tree_printer; uvm_default_printer.knobs.hex_radix = "0x"; // Change radix uvm_default_printer.knobs.separator = "@@";
// Turning off identifiers (not very useful in practice): uvm_default_printer = uvm_default_line_printer; uvm_default_printer.knobs.identifier = 0;
Try out an example using this feature in EDA Playground
`uvm_analysis_imp_decl(_pci) `uvm_analysis_imp_decl(_usb) class top_sb extends uvm_scoreboard; `uvm_component_utils(top_sb) uvm_analysis_imp_usb #(usb_trans_t,top_sb) usb_ap; uvm_analysis_imp_pci #(pci_trans_t,top_sb) pci_ap; uvm_queue #(usb_trans_t) expected_queue; function new( string name, uvm_component parent ); super.new(name, parent); endfunction: new function void build_phase(uvm_phase phase); super.build_phase(phase); usb_ap = new("usb_ap",this); pci_ap = new("pci_ap",this); // Create the queue expected_queue = new(); endfunction : build_phase function void write_pci(pci_trans_t t); // Save expected result in queue expected_queue.push_back( compute_result(t) ); endfunction : write_pci function void write_usb(usb_trans_t t); // Compare the transaction with expected value from the queue assert ( t.compare( expected_queue.pop_front() )) else `uvm_error("TOP_SB", "Actual != Expected!") endfunction : write_usb endclass
Try out an example using this feature in EDA Playground
class verif_env_t extends uvm_env; `uvm_component_utils(verif_env_t) uvm_random_stimulus #(basic_transaction_t) m_stimulus; dut_driver_t m_driver; uvm_tlm_fifo #(basic_transaction_t) m_fifo; int test_length; //... virtual function void build_phase(uvm_phase phase); super.build_phase(phase); uvm_config_db#(int)::get(this,"","run_test_length",test_length); m_stimulus = new ("m_stimulus",this); m_fifo = new("m_fifo",this); m_driver = dut_driver_t::type_id::create("m_driver",this); endfunction: build_phase virtual function void connect_phase(uvm_phase phase); m_stimulus.blocking_put_port.connect(m_fifo.put_export); m_driver.tx_in_port.connect(m_fifo.get_export); endfunction: connect_phase virtual task run_phase(uvm_phase phase); m_stimulus.generate_stimulus(null,test_length); endtask: run_phase endclass: verif_env_t
Try out an example using this feature in EDA Playground
class basic_trans_t extends uvm_sequence_item; `uvm_object_utils(basic_trans_t) //... function void do_record(uvm_recorder recorder); super.do_record(recorder); // recorder.tr_handle (UVM 1.1) replaced with // recorder.get_record_attribute_handle() in UVM 1.2 `uvm_record_attribute(recorder.get_record_attribute_handle(), "cmd", cmd); `uvm_record_attribute(recorder.get_record_attribute_handle(), "addr", addr); `uvm_record_attribute(recorder.get_record_attribute_handle(), "data", data); // -- OR -- // recorder.record_field_int("cmd", cmd, 2, UVM_UNSIGNED); // recorder.record_field_int("addr", addr, $bits(addr), UVM_UNSIGNED); // recorder.record_field_int("data", data, $bits(data), UVM_UNSIGNED); endfunction endclass: basic_trans_t class my_driver_t extends uvm_driver #(basic_trans_t); `uvm_component_utils(my_driver_t) //... task run_phase(uvm_phase phase); //... // Start transaction recording void'( begin_tr(req, "basic_trans") ); //... // End transaction recording end_tr(req); //... endtask: run_phase endclass: my_driver_t module top; //... initial begin //... // Enable transaction recording. uvm_config_db#(int)::set(null, "*", "recording_detail", 1); //... end endmodule : top
uvm_config_db#(bit)::set( uvm_top???? {"REG::",regmodel.blk.get_full_name(),".*"}, "NO_REG_TESTS", 1, this);
class smoke_test extends uvm_test; my_env_t m_env; //... task main_phase(uvm_phase phase); uvm_reg_hw_reset_test test_seq = new(); phase.raise_objection(this, "Running hw_reset test"); test_seq.model = m_env.regmodel; test_seq.start(null); phase.drop_objection(this, "End of hw_reset test"); endtask : main_phase endclass : smoke_test
class my_model_t extends uvm_reg_block; `uvm_object_utils(my_model_t) //... endclass : my_model_t
class reg_to_bus_adapter_t extends uvm_reg_adapter; `uvm_object_utils(reg_to_bus_adapter_t) function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); bus_trans_t tx = bus_trans_t::type_id::create("bus_item"); tx.addr = rw.addr[7:0]; //... return tx; endfunction : reg2bus function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); //... endfunction : bus2reg endclass : reg_to_bus_adapter_t
class my_env_t extends uvm_env; my_model_t regmodel; bus_agent_t agt; function void build_phase(uvm_phase phase); super.build_phase(phase); agt = bus_agent_t::type_id::create(...); if (regmodel == null) begin regmodel = my_model_t::type_id::create(...); regmodel.build(); // Lock the register model to prevent further structural changes // and build the address map(s) regmodel.lock_model(); end endfunction : build_phase function void connect_phase(uvm_phase phase); if (regmodel.get_parent() == null) begin // Create an instance of the register-to-bus adapter reg_to_bus_adapter_t adapter = reg_to_bus_adapter_t::type_id::create(...); // Set the sequencer for the register model's default map to be // the sequencer in the bus agent and connect it to the adapter regmodel.default_map.set_sequencer( agt.m_sequencer, adapter); // Turn on implicit prediction regmodel.set_auto_predict(1); end //... endfunction : connect_phase endclass : my_env_t
class my_test extends uvm_test; my_env_t env; virtual function void run_phase(uvm_phase phase); // Create and start a user-defined or built-in sequence my_reg_sequence_t seq = my_reg_sequence_t::type_id::create("seq",this); seq.start(env.agt.m_sequencer); endfunction : run_phase endclass : my_test
class high_addr_first_t extends uvm_reg_transaction_order_policy; virtual function void order(ref uvm_reg_bus_op q[$]); q.rsort with (item.addr); endfunction //... endclass high_addr_first_t p = new("high_addr_first_policy"); someregmap.set_transaction_order_policy(p);
Try out an example using this feature in EDA Playground
class my_error_demoter extends uvm_report_catcher; function new(string name="my_error_demoter_t"); super.new(name); endfunction // This example demotes "MY_ID" errors to an info message function action_e catch(); if (get_severity() == UVM_ERROR && get_id() == "MY_ID") set_severity(UVM_INFO); return THROW; endfunction endclass
// Instantiate the new report catcher my_error_demoter demoter = new; initial begin // Catch messages for all reporters uvm_report_cb::add(null, demoter); // To affect some specific object use the specific reporter uvm_report_cb::add(mytest.myenv.myagent.mydriver, demoter); // To affect some set of components using the component name uvm_report_cb::add_by_name("*.*driver", demoter, this); `uvm_error("MY_ID", "This message will be demoted to UVM_INFO") // Disable demotion void'(demoter.callback_mode(0)); `uvm_error("MY_ID", "This message will NOT be demoted") end
uvm_report_message msg = uvm_report_message::type_id::create("msg"); `uvm_info_begin("MY_ID2", "My info message", UVM_LOW, msg) `uvm_message_add_tag("my_color", "red") //uses add string `uvm_message_add_int(my_int, UVM_HEX) `uvm_message_add_object(object) `uvm_info_end uvm_text_tr_database db = new("my_msg_log.txt"); uvm_tr_stream stream = db.open_stream("my_stream"); uvm_recorder rec = stream.open_recorder("my_recorder"); msg.record(rec); uvm_process_report_message(msg);
class my_test extends uvm_test; //... // Turn off messages tagged with the id = "debug" for the my_env // component only my_env.set_report_id_action ("debug", UVM_NO_ACTION); // Turn all UVM_INFO messages off - // (Use set_report_[]_hier version [from uvm_component] // to recursively traverse the hierarchy and set the action) set_report_severity_action_hier(UVM_INFO, UVM_NO_ACTION); // Turn all messages back on set_report_severity_action_hier( UVM_INFO, UVM_DISPLAY | UVM_LOG ); set_report_severity_action_hier( UVM_WARNING, UVM_DISPLAY | UVM_LOG ); set_report_severity_action_hier( UVM_ERROR, UVM_DISPLAY | UVM_COUNT | UVM_LOG ); set_report_severity_action_hier( UVM_FATAL, UVM_DISPLAY | UVM_EXIT | UVM_LOG ); // Setup the global reporting for messages that use uvm_top as a // global report handler (like the sequences machinery) uvm_top.set_report_verbosity_level( UVM_ERROR ); uvm_top.dump_report_state(); // Print out state // Configure the environment to quit/die after one UVM_ERROR message set_report_max_quit_count( 1 ); endclass : my_test
// Example with user-definable report hooks class my_env_t extends uvm_env; `uvm_component_utils(my_env_t) bit under_reset = 0; // Indicates device under reset UVM_FILE f; //... // Override the report_hook function function bit report_hook(input id, string message, int verbosity, string filename, int line); // Turn off all reporting during the boot-up, // initialization, and reset period if (!under_reset && ( $time > 100ns )) return 1; else return 0; // Either under_reset or time less than // 100ns so do not issue report messages endfunction : report_hook function void start_of_simulation_phase(uvm_phase phase); // Duplicate report messages to a file f = $fopen( "sim.log", "w" ); set_report_default_file_hier( f ); // Setup the environment to not print INFO, WARNING, // and ERROR message during reset or initialization by // adding the UVM_CALL_HOOK reporting action set_report_severity_action_hier( UVM_INFO, UVM_DISPLAY | UVM_CALL_HOOK ); set_report_severity_action_hier( UVM_WARNING, UVM_DISPLAY | UVM_CALL_HOOK ); set_report_severity_action_hier( UVM_ERROR, UVM_DISPLAY | UVM_COUNT | UVM_CALL_HOOK ); endfunction : start_of_simulation_phase endclass : my_env_t
uvm_resource_db #(int)::set("shared_resources", "max_count", 100, null);
max_count = uvm_resource_db #(int)::get_by_name("shared_resources", "max_count");
max_count = uvm_resource_db #(int)::get_by_type("shared_resources");
module top; import uvm_pkg::*; import my_pkg::*; // Instance of the interface that connects the DUT and TB dut_if dut_if1 (); // Instance the DUT dut dut1 ( .i_f(dut_if1) ); initial begin // Set virtual interface of driver to point to actual interface uvm_resource_db #(virtual dut_if)::set("DUT", "m_dut_if", dut_if1); run_test(); end endmodule: top class my_driver_t extends uvm_driver #(my_transaction_t); //... virtual dut_if m_dut_if; function void connect_phase(uvm_phase phase); if ( ! uvm_resource_db #(virtual dut_if)::read_by_name( "DUT", "m_dut_if", m_dut_if) ) `uvm_fatal("NOVIF", {"No virtual interface set for", get_full_name(),".m_dut_if"}) endfunction : connect_phase //... endclass : my_driver_t
module top; //... initial begin uvm_top.enable_print_topology = 1; uvm_top.finish_on_completion = 0; run_test("test1"); end endmodule: top
class test1 extends uvm_test; `uvm_component_utils(test1) verif_env_t env1; uvm_component c; uvm_component cq[$]; function new (string name, uvm_component parent); super.new(name,parent); endfunction : new virtual function void build_phase(uvm_phase phase); super.build_phase(phase); env1 = verif_env_t::type_id::create("env1",this); endfunction : build_phase function void end_of_elaboration_phase(uvm_phase phase); c = uvm_top.find("env1.m_driver"); uvm_top.find_all("*",cq,c); foreach(cq[i]) `uvm_info("FIND_ALL", $sformatf("Found %s of type %s", cq[i].get_full_name(),cq[i].get_type_name()), UVM_NONE) endfunction: end_of_elaboration_phase endclass: test1
Try out an example using this feature in EDA Playground
class my_seq_item_t extends uvm_sequence_item; rand int data; rand bit [4:0] addr; //... `uvm_object_utils_begin ( my_seq_item_t ) `uvm_field_int ( data, UVM_ALL_ON + UVM_HEX ) `uvm_field_int ( addr, UVM_ALL_ON + UVM_HEX ) //... `uvm_object_utils_end //... endclass : my_seq_item_t
typedef uvm_sequencer #(my_seq_item_t) my_sequencer_t;
class my_sequence_t extends uvm_sequence #(my_seq_item_t); `uvm_object_utils ( my_sequence_t ) my_seq_item_t m_seq_item; function new ( string name = "my_sequence" ); super.new ( name ); endfunction : new virtual task body(); // Create a sequence item using a macro `uvm_do ( m_seq_item ) // Manually create another sequence item m_seq_item = my_seq_item::type_id::create(); start_item(m_seq_item); m_seq_item.randomize with { ... }; finish_item(m_seq_item); endtask : body endclass : my_sequence_t
Try out an example using this feature in EDA Playground
typedef enum { read, write } dir_t; class my_seq_item extends uvm_sequence_item; rand bit [31:0] data; rand bit [9:0] addr; rand dir_t dir; function new (string name = ""); super.new(name); endfunction // Register sequence item with the factory and add the // field automation macros `uvm_object_utils_begin( my_seq_item_t ) `uvm_field_int( data, UVM_ALL_ON ) `uvm_field_int( addr, UVM_ALL_ON ) `uvm_field_enum( dir_t, dir, UVM_ALL_ON ) `uvm_object_utils_end endclass : my_seq_item
class my_seq extends uvm_sequence #(my_seq_item); `uvm_object_utils (my_seq) // my_seq_item req; // built-in sequence item my_other_seq_t subseq; // A nested subsequence // Define a constructor function new ( string name = "my_seq"); super.new (name); endfunction : new // Define the sequence functionality in the body() using macros virtual task body(); `uvm_info ( get_name(), "Starting the sequence ...", UVM_NONE ) // Use the do action macros on the sequence item `uvm_do_with( req,{ addr > 10'hfff; dir == read; } ) // Invoke a nested subsequence `uvm_do_with( subseq, { ctrl_flag == `TRUE; } ) //... endtask : body endclass : my_seq
class my_seq_alt extends uvm_sequence #(my_seq_item); `uvm_object_utils (my_seq_alt) `uvm_declare_p_sequencer(uvm_sequencer #(my_seq_item)) //... virtual task body(); // Generate a sequence item req = my_seq_item::type_id::create("req"); start_item(req); randomize(req) with { addr > 10'hfff; dir == read; }; finish_item(req); // Invoke a nested subsequence subseq = my_other_seq_t::type_id::create("subseq"); subseq.start(p_sequencer); //... endtask : body endclass : my_seq_alt
// Examples of `uvm_do and `uvm_do_with class example_sequence extends uvm_sequence #(example_sequence_item_t); //... task body(); // Send the sequence item to the driver `uvm_do( req ) // Send item again, but add constraints `uvm_do_with( req, { addr > 0 && addr < 'hffff; }) endtask : body endclass : example_sequence
// Examples of `uvm_create and `uvm_rand_send class fixed_size_sequence extends uvm_sequence #(example_sequence_item_t); //... task body(); // Allocate the sequence item `uvm_create ( req ) // Modify the sequence item before sending req.size = 128; req.size.rand_mode(0); // No randomization // Now send the sequence item `uvm_rand_send ( req ) endtask : body endclass : fixed_size_sequence
// Example of `uvm_do_on in a virtual sequence class virtual_sequence extends uvm_sequence; `uvm_object_utils(virtual_sequence_t) `uvm_declare_p_sequencer(my_sequencer_t) write_sequence_t wr_seq; read_sequence_t rd_seq; //... task body(); fork // Launch the virtual sequences in parallel `uvm_do_on_with ( wr_seq, p_sequencer.seqr_a, { parity == 1; addr > 48; }) `uvm_do_on_with ( rd_seq, p_sequencer.seqr_b, { width == 32; type == LONG; }) join endtask : body endclass : virtual_sequence
typedef enum { RX, TX } kind_t; class my_seq_item extends uvm_sequence_item; rand bit [4:0] addr; rand bit [31:0] data; rand kind_t kind; // Constructor function new ( string name = "my_seq_item" ); super.new ( name ); endfunction : new // Register with UVM factory and use field automation `uvm_object_utils_begin( my_seq_item_t ) `uvm_field_int ( addr, UVM_ALL_ON + UVM_DEC) `uvm_field_int ( data, UVM_ALL_ON + UVM_DEC) `uvm_field_enum ( kind_t, kind, UVM_ALL_ON ) `uvm_object_utils_end endclass : my_seq_item
class my_seq_lib_t extends uvm_sequence_library #(my_item_t); `uvm_object_utils(my_seq_lib_t) `uvm_sequence_library_utils(my_seq_lib_t) function new(string name=""); super.new(name); init_sequence_library(); endfunction //... endclass
class my_seq_t extends uvm_sequence #(my_item_t); `uvm_object_utils(my_seq_t) `uvm_add_to_seq_lib (my_seq_t, my_seq_lib_t) //... endclass
class my_test extends uvm_test; `uvm_component_utils (my_test) //... function void build_phase(uvm_phase phase); uvm_sequence_library_cfg cfg; super.build_phase(phase); // Create an instance of the configuration convenience class cfg = new("seqlib_cfg", UVM_SEQ_LIB_RANDC, 1000, 2000); uvm_config_db #(uvm_sequence_library_cfg)::set( null, "*.env.agent.sequencer.main_phase", "default_sequence.config", cfg); // Configure the sequence library and cause it to be run on a // sequencer - it is a sequence and is run in exactly the same // way, either by setting the sequencer's default_sequence or // starting it manually. uvm_config_db #(uvm_sequencer_base)::set( this,"*.my_sequencer.main_phase", "default_sequence", my_seq_lib_t::type_id::get()); endfunction //... endclass : my_test
Try out an example using this feature in EDA Playground
// Define a uvm_sequence_item typedef enum { read, write } dir_t; class my_seq_item_t extends uvm_sequence_item; rand bit [31:0] data; rand bit [9:0] addr; rand dir_t dir; function new (string name = ""); super.new(name); endfunction // Register sequence item with the factory and add the // field automation macros `uvm_object_utils_begin( my_seq_item_t ) `uvm_field_int( data, UVM_ALL_ON ) `uvm_field_int( addr, UVM_ALL_ON ) `uvm_field_enum( dir_t, dir, UVM_ALL_ON ) `uvm_object_utils_end endclass : my_seq_item_t // Define a sequence - generates between 1 and 20 transactions class my_sequence_t extends uvm_sequence #(my_seq_item_t); `uvm_object_utils ( my_sequence_t ) rand int num_items = 5; constraint c_num_items { num_items > 0; num_items <= 20;} function new ( string name = "my_sequence_t"); super.new (name); endfunction : new task body; uvm_phase starting_phase = get_starting_phase(); // UVM 1.2 if ( starting_phase != null ) starting_phase.raise_objection(this); repeat (num_items) begin my_seq_item tx; `uvm_do(tx) end if ( starting_phase != null ) starting_phase.drop_objection(this); endtask : body endclass : my_sequence_t // Create a typedef for the sequencer typedef uvm_sequencer #(my_seq_item) my_sequencer_t; // Connect the sequencer to the driver class my_env_t extends uvm_env; `uvm_component_utils (my_env_t) //... my_sequencer_t m_seqr; my_driver_t m_drv; function new (string name, uvm_component parent); super.new(name, parent); endfunction function void connect_phase(uvm_phase phase); // Hook up the sequencer to the driver m_drv.seq_item_port.connect(m_seqr.seq_item_export); endfunction : connect_phase //... endclass : my_env_t // Create a test class my_test extends uvm_test; `uvm_component_utils (my_test) my_env_t m_env; function new(string name, uvm_component parent); super.new(name,parent); endfunction : new function void build_phase(uvm_phase phase); super.build_phase(phase); // Use the factory to create the environment m_env = my_env_t::type_id::create("m_env", this); // Set the sequencer's default sequence uvm_config_db #(uvm_object_wrapper)::set( null, "/.*m_seqr.main_phase/", "default_sequence", my_sequence_t::get_type() ); endfunction : build_phase endclass : my_test
Try out another example using this feature in EDA Playground
class my_transaction_t extends uvm_sequence_item; //... class my_program_t extends uvm_sequence_item; `uvm_object_utils(my_program_t) // my_program_t contains a dynamic array of my_transactions my_transaction_t tx_h[]; //... // When a my_program object is randomized, a random number (n) of // randomized my_transactions are created and stored in the dynamic // array function void pre_randomize; int n = $urandom_range(3, 6); tx_h = new[n]; for (int i = 0; i < n; i++) begin tx_h[i] = new; assert( tx_h[i].randomize() ); end endfunction endclass : my_program_t class my_program_seq_t extends uvm_sequence#(my_program_t); `uvm_object_utils(my_program_seq_t) function new (string name = ""); super.new(name); endfunction: new // Create one my_program item, which contains n my_transaction items task body; my_program_t tx; tx = my_program_t::type_id::create("tx"); start_item(tx); assert( tx.randomize() ); finish_item(tx); endtask: body endclass: my_program_seq_t // The sequencer for my_transactions contains a uvm_seq_item_pull_port; // the my_program sequencer will pull my_program items through this class my_tx_sqr_t extends uvm_sequencer#(my_transaction_t); `uvm_component_utils(my_tx_sqr_t) uvm_seq_item_pull_port #(my_program_t) seq_item_port; function new(string name, uvm_component parent); super.new(name, parent); endfunction: new function void build_phase(uvm_phase phase); seq_item_port = new("seq_item_port", this); endfunction: build_phase endclass: my_tx_sqr_t class my_tx_seq_t extends uvm_sequence#(my_transaction_t); `uvm_object_utils(my_tx_seq_t) // Includes the p_sequencer member - points to this // sequence's sequencer `uvm_declare_p_sequencer(my_tx_sqr_t) my_program_t my_program_h; function new (string name = ""); super.new(name); endfunction: new task body; fork forever begin int n; // Get a my_program_t item from the my_program_t sequencer using // the interface that connects it to the my_transaction_t sequencer p_sequencer.seq_item_port.get(my_program_h); // Find out how many my_transaction items there are n = my_program_h.tx_h.size(); // Create the same number here, copy across and generate for (int i = 0; i < n; i++) begin my_transaction tx; tx = my_transaction_t::type_id::create("tx"); start_item(tx); tx.cmd = my_program_h.tx_h[i].cmd; tx.addr = my_program_h.tx_h[i].addr; tx.data = my_program_h.tx_h[i].data; finish_item(tx); end end join_none endtask: body endclass: my_tx_seq_t class my_env_t extends uvm_env; `uvm_component_utils(my_env_t) uvm_sequencer #(my_program_t) my_program_sqr_h; my_tx_sqr_t my_tx_sqr_h; //... function void build_phase(uvm_phase phase); super.build_phase(phase); // Create the sequencers (and other components) my_program_sqr_h = uvm_sequencer #(my_program_t)::type_id::create( "my_program_sqr_h", this); my_tx_sqr_h = my_tx_sqr_t::type_id::create("my_tx_sqr_h", this); //... endfunction: build_phase function void connect_phase(uvm_phase phase); // Connect the sequencers' port and export my_tx_sqr_h.seq_item_port.connect(my_program_sqr_h.seq_item_export ); // Other component connections //... endfunction: connect_phase endclass: my_env_t class my_test extends uvm_test; `uvm_component_utils(my_test) my_env_t my_env_h; function new(string name, uvm_component parent); super.new(name, parent); endfunction: new function void build_phase(uvm_phase phase); super.build_phase(phase); my_env_h = my_env_t::type_id::create("my_env_h", this); endfunction: build_phase task run_phase(uvm_phase phase); my_program_seq_t program_seq; my_tx_seq_t tx_seq; // Create and start a my_tx_seq tx_seq = my_tx_seq_t::type_id::create("tx_seq"); tx_seq.start( my_env_h.my_tx_sqr_h ); // Create and start a my_program_seq program_seq = my_program_seq_t::type_id::create("program_seq"); assert( program_seq.randomize() ); program_seq.start( my_env_h.my_program_sqr_h ); phase.phase_done.set_drain_time( this, 30ns ); endtask: run_phase endclass: my_test
class my_driver_t extends uvm_driver #(my_trans_t); //... task run_phase(uvm_phase phase); forever begin // Pull a sequence item from the interface. We could use get // instead of get_next_item, in which case we don't need to call // to call item_done. seq_item_port.get_next_item( req ); // Apply transaction to DUT interface //... // Set the response id and indicate that item is done rsp = new("rsp"); rsp.set_id_info(req); seq_item_port.item_done( rsp ); end endtask : run_phase endclass : my_driver_t // Connect the sequencer and driver together class my_env_t extend uvm_env; //... function void connect_phase(uvm_phase phase); my_drv.seq_item_port.connect( my_seqr.seq_item_export ); endfunction : connect_phase endclass : my_env_t
// Define a specialized subscriber class. This class does nothing except to // report all transactions it receives. class example_subscriber_t extends uvm_subscriber #(example_transaction_t); `uvm_component_utils(example_subscriber_t) int transaction_count; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void write (example_transaction_t t); `uvm_info("WRITE", $sformatf( "Received transaction number %0d:\n%s", transaction_count++, t.sprint() ), UVM_NONE ) endfunction endclass : example_subscriber_t // In the enclosing environment class: class subscriber_test_env_t extends uvm_env; `uvm_component_utils(subscriber_test_env_t) example_subscriber_t m_subscriber; example_monitor_t m_monitor; // see uvm_monitor //... function void build_phase(uvm_phase phase); //... m_monitor = example_monitor_t::type_id::create( "m_monitor",this); m_subscriber = example_subscriber_t::type_id::create( "m_ subscriber",this); //... endfunction function void connect_phase(uvm_phase phase); // Connect monitor's analysis port (requires) // to subscriber's export (provides) m_monitor.monitor_ap.connect ( m_subscriber.analysis_export ); endfunction //... endclass : subscriber_test_env_t
module top; class test1 extends uvm_test; // Register test with factory `uvm_component_utils(test1) //... function new (string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); // Create environment endfunction: build_phase function void connect_phase(uvm_phase phase); // Connect test environment's virtual interface to the // DUT's interface m_env.m_mon.m_bus_if = tf.cpu_if.mon; endfunction: connect_phase task run_phase(uvm_phase phase); // Call methods in environment to control test (optional) endtask: run_phase endclass: test1 initial begin run_test("test1"); // Use test1 by default // Can override using +UVM_TESTNAME end // Contains DUT, DUT interface, clock/reset, ancillary modules etc. test_harness tf (); endmodule
`uvm_analysis_imp_decl(_ahb) `uvm_analysis_imp_decl(_pci) class fullchip_sb_t extends uvm_scoreboard; `uvm_component_utils(fullchip_sb_t) uvm_analysis_imp_ahb #(ahb_trans_t, fullchip_sb) ahb_ap; uvm_analysis_imp_pci #(pci_trans_t, fullchip_sb) pci_ap; //... function void write_ahb(ahb_trans_t t) { // AHB implementation expected_queue.push_back( compute_result(t) ); } function void write_pci(pci_trans_t t) { // PCI implementation assert ( t.compare( expected_queue.pop_front() )) else `uvm_error("FULLCHIP_SB", "Actual != Expected!") } endclass
uvm_master_port #(my_req_t,my_rsp_t) m_master;
m_master.put(req1); m_master.get(req1);
class uvm_tlm_req_rsp_channel #( type REQ = int , type RSP = REQ ) extends uvm_component; typedef uvm_tlm_req_rsp_channel #( REQ , RSP ) this_type_t; protected uvm_tlm_fifo #( REQ ) m_request_fifo; protected uvm_tlm_fifo #( RSP ) m_response_fifo; //... uvm_master_imp #( REQ , RSP , this_type_t , uvm_tlm_fifo #( REQ ) , uvm_tlm_fifo #( RSP ) ) master_export; uvm_slave_imp #( REQ , RSP ,this_type_t , uvm_tlm_fifo #( REQ ) , uvm_tlm_fifo #( RSP ) ) slave_export; //... endclass
master_export = new( "master_export" , this , m_request_fifo, m_response_fifo ); slave_export = new( "slave_export" , this , m_request_fifo , m_response_fifo );
class compA_t extends uvm_component; `uvm_component_utils(compA_t) `uvm_blocking_put_port #(int) p0; function new(string name, uvm_component parent); super.new(name,parent); endfunction: new virtual function void build_phase(uvm_phase phase); super.build_phase(phase); p0 = new("p0",this,1,UVM_UNBOUNDED_CONNECTIONS); endfunction: build_phase task run_phase(uvm_phase phase); p0.debug_connected_to(); for (int i=1; i<= p0.size(); i++) begin p0.put(i); p0.set_if(i); // next port index end endtask: run_phase endclass: compA_t
class compB_t extends uvm_component; `uvm_component_utils(compB_t) uvm_blocking_put_imp #(int,compB_t) put_export; function new(string name, uvm_component parent); super.new(name,parent); endfunction: new virtual function void build_phase(uvm_phase phase); super.build_phase(phase); put_export = new("put_export",this); endfunction: build_phase task put(int val); // interface method `uvm_info("compB_t ",$sformatf("Received %0d",val), UVM_NONE) endtask: put endclass: compB_t
class compC_t extends uvm_component; `uvm_component_utils(compC_t) compA_t A; compB_t B00,B01; uvm_blocking_put_port #(int) put_port; function new(string name, uvm_component parent); super.new(name,parent); endfunction: new virtual function void build_phase(uvm_phase phase); super.build_phase(phase); put_port = new("put_port", this, 1, UVM_UNBOUNDED_CONNECTIONS); A = compA_t::type_id::create("A", this); B00 = compB_t::type_id::create("B00",this); B01 = compB_t::type_id::create("B01",this); endfunction: build_phase function void connect_phase(uvm_phase phase); // The order of these statements does not matter A.p0.connect(B00.put_export); A.p0.connect(B01.put_export); A.p0.connect(put_port); endfunction: connect_phase endclass: compC_t
class sve_t extends uvm_env; `uvm_component_utils(sve_t) compC_t C; compB_t ZB1,B2,B03; //... function void connect_phase(uvm_phase phase); C.put_port.connect(ZB1.put_export); C.put_port.connect(B03.put_export); C.put_port.connect(B2.put_export); endfunction: connect_phase endclass: sve_t
class initiator_t extends uvm_component; `uvm_component_utils(initiator_t) // Blocking initiator socket uvm_tlm_b_initiator_socket#(my_seq_item_t) tlm2_sock; function new(string name, uvm_component parent); super.new(name, parent); // Create the socket tlm2_sock = new("tlm2_sock", this); endfunction : new // During simulation, use the socket to pass transactions to the target virtual task run_phase(uvm_phase phase); my_seq_item_t rw; uvm_tlm_time delay = new; phase.raise_objection(this); rw = my_seq_item_t::type_id::create("rw",, get_full_name()); //... // Pass a transaction through the socket tlm2_sock.b_transport(rw, delay); //... phase.drop_objection(this); endtask : run_phase endclass : initiator_t
// Target component class target_t extends uvm_component; `uvm_component_utils(target_t) uvm_tlm_b_target_socket#(target_t, my_seq_item_t) tlm2_sock; function new(string name = "target", uvm_component parent = null); super.new(name, parent); tlm2_sock = new("tlm2_sock", this); endfunction : new // Implementation of the blocking transport method. // The initiator calls this through the socket. task b_transport(my_seq_item_t rw, uvm_tlm_time delay); // Process the transaction // ... endtask : b_transport endclass : target_t
// Environment that instantiates the initiator and target class tb_env_t extends uvm_component; `uvm_component_utils(tb_env_t) initiator_t m_initiator; target_t m_target; // Construct the environment function new(string name, uvm_component parent); super.new(name, parent); endfunction : new // Build the initiator and target components function void build_phase(uvm_phase phase); m_initiator = initiator_t::type_id::create("m_initiator", this); m_target = target_t::type_id::create("m_target", this); endfunction : build_phase // Connect the target and the initiator sockets function void connect_phase(uvm_phase phase); m_initiator.tlm2_sock.connect(m_target.tlm2_sock); endfunction : connect_phase endclass : tb_env_t
class master_t extends uvm_component; `uvm_component_utils(master_t) // Non-blocking initiator socket - is a forward port and has a // backward imp uvm_tlm_nb_initiator_socket #(master_t, trans_t, uvm_tlm_phase_e) initiator_socket; function new (string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); // Construct the socket, hence the port and imp // the first 'this' is the 'parent' object, the second 'this' is a // reference to the object where the implementation for the *_bw_* // functions are initiator_socket = new("initiator_socket", this, this); endfunction // Required implementation function uvm_tlm_sync_e nb_transport_bw( trans t, ref uvm_tlm_phase_e p, input uvm_tlm_time delay); transaction = t; state = p; return UVM_TLM_ACCEPTED; endfunction //... endclass
class example_env_t extends uvm_env; `uvm_component_utils(example_env) uvm_tlm_analysis_fifo #(example_transaction_t) an_fifo; example_monitor_t m_monitor; // has analysis port example_analyzer_t m_analyzer; // has "get" port //... virtual function void build_phase(uvm_phase phase); m_monitor = ...; // Create m_analyzer = ...; // Create an_fifo = new("an_fifo", this); endfunction virtual function void connect_phase(uvm_phase phase); m_monitor.monitor_ap.connect(an_fifo.analysis_export); m_analyzer.get_port.connect(an_fifo.get_export); endfunction //... endclass
// Extension class class my_extension_t extends uvm_tlm_extension#(my_extension_t); `uvm_object_utils(my_extension_t) int when; endclass // Add an extension to a payload uvm_tlm_gp gp = new; my_extension ext = new; ext.when= $time; gp.set_extension( ext ); // Retrieve the extension value my_extension_t ext; if ( $cast( ext, gp.get_extension( my_extension_t::ID()) ) // Extension present //... else `uvm_error( ... )
uvm_get_port #(basic_transaction_t) m_trans_in;
m_trans_in.get(tx);
class verif_env_t extends uvm_env; 'uvm_component_utils(verif_env_t) uvm_random_stimulus #(basic_transaction_t) m_stimulus; dut_driver_t m_driver; uvm_tlm_fifo #(basic_transaction_t) m_fifo; //... virtual function void build_phase(uvm_phase phase); super.build_phase(phase); m_stimulus = ... // Create m_fifo = ... // Create m_driver = dut_driver_t::type_id::create("m_driver",this); endfunction: build_phase virtual function void connect_phase(uvm_phase phase); m_stimulus.blocking_put_port.connect(m_fifo.put_export); m_driver.m_trans_in.connect(m_fifo.get_export); endfunction: connect_phase //... endclass: verif_env_t
// Create a generic payload transaction using the factory: m_tlm_gptx = uvm_tlm_gp::type_id::create("m_tlm_gptx");
// Randomize the transaction assert( m_tlm_gptx.randomize() with { m_address >= 0 && m_address < 256; m_length== 4 || m_length == 8; m_data.size == m_length; m_byte_enable_length <= m_length; (m_byte_enable_length % 4) == 0; m_byte_enable.size == m_byte_enable_length; m_streaming_width == m_length; m_response_status == UVM_TLM_INCOMPLETE_RESPONSE; } ) else `uvm_error("Initiator", "m_tlm_gptx.randomize() failed")
// Create a copy of the transaction tx.copy(m_tlm_gptx); // Use the blocking transport, which is implemented in the target initiator_socket.b_transport(tx, delay); // Was the bus transaction successful? assert( tx.is_response_ok() );
class Target_t extends uvm_component; `uvm_component_utils(Target_t) local byte unsigned m_data[4]; // Declaration of target socket uvm_tlm_b_target_socket #(Target_t, my_transaction_t) t_socket; function new(string name, uvm_component parent); super.new(name, parent); endfunction : new function void build_phase(uvm_phase phase); super.build_phase(phase); t_socket = new( "t_socket", this, this ); endfunction : build_phase // Called by initiator through the socket task b_transport(my_transaction_t t, uvm_tlm_time delay); if ( t.get_address() == 64'HC000) if ( t.get_command() == UVM_TLM_READ_COMMAND ) t.set_data(m_data); else t.get_data(m_data); #(delay.get_realtime(1ns)); endtask : b_transport endclass : Target_t
`timescale 100ps/1ps //... // Create a new uvm_tlm_time value uvm_tlm_time delay = new("delay"); // Value will be 0ns delay.set_abstime(10.5,1.0e-9); // Set to 10.5ns delay.incr(25,1ns); // Increment by 25 x 100ps (timescale) = 2.5ns delay.incr(25ns,1ns); // Increment by 25ns // Display value in ns and ps `uvm_info("",$sformatf("delay is %.3f ns, %.3 ps", delay.get_abstime(1.0e-9) delay.get_abstime(1.0e-12)),UVM_NONE) // Display value using the current timescale `uvm_info("",$sformatf("delay is %.3f x100ps", delay.get_realtime(1ns)),UVM_NONE)
uvm_text_tr_database db = new("my_msg_db"); uvm_tr_stream stream; db.set_filename("my_msg_db.txt"); void'(db.open_db()); assert(db.is_open()) else `uvm_error("","open_db failed!"); stream = db.open_stream("my_stream"); //... assert(db.close_db()) else `uvm_error("","close_db failed");
uvm_text_stream stream; stream = db.open_stream("my_stream");
class basic_trans_t extends uvm_sequence_item; rand bit[7:0] m_var1, m_var2; static int tx_count = 0; `uvm_object_utils_begin(basic_trans_t) `uvm_field_int(m_var1,UVM_ALL_ON | UVM_DEC) `uvm_field_int(m_var2,UVM_ALL_ON | UVM_DEC) `uvm_object_utils_end function new (string name = "", uvm_component initiator=null); super.new(name,initiator); tx_count++; endfunction: new virtual protected function int do_begin_tr(); `uvm_info("TRX",$sformatf( "Transaction %0d beginning",tx_count), UVM_NONE) endfunction: do_begin_tr virtual protected function void do_end_tr(); `uvm_info("TRX",$sformatf( "Transaction %0d ended",tx_count), UVM_NONE) endfunction: do_end_tr endclass : basic_trans_t
// Generating constrained random transactions: virtual task generate_stimulus( basic_trans_t t = null, input int max_count = 30 ); basic_trans_t temp; uvm_event_pool tx_epool; uvm_event tx_end; if( t == null ) t = new("trans",this); for( int i = 0; (max_count == 0 || i < max_count-1);i++ ) begin assert( t.randomize() ); $cast( temp , t.clone() ); `uvm_info("stimulus generation", temp.convert2string(), UVM_NONE ) tx_epool = temp.get_event_pool(); blocking_put_port.put( temp ); tx_end = tx_epool.get("end"); tx_end.wait_trigger(); end endtask: generate_stimulus
class basic_trans_t extends uvm_sequence_item; rand bit[7:0] addr, data; `uvm_object_utils_begin(basic_trans_t) `uvm_field_int(addr,UVM_ALL_ON) `uvm_field_int(data,UVM_ALL_ON) `uvm_object_utils_end //... endclass : basic_trans_t
class dut_driver_t extends uvm_driver #(basic_trans_t); uvm_get_port #(basic_trans_t) m_trans_in; vif_wrapper vif; `uvm_component_utils_begin(dut_driver_t) `uvm_field_object(vif,UVM_ALL_ON) `uvm_component_utils_end //... endclass: dut_driver_t
`uvm_info($sformatf("","Using %s",`UVM_VERSION_STRING),UVM_NONE)
// To enforce use of UVM 1.2: // Require at least UVM 1.2 `ifndef UVM_POST_VERSION_1_1 // UVM 1.1 and earlier here (or possibly forgot UVM altogether) assert("This code requires UVM 1.2 or later."==0); `endif
// Backward compatibility (requires testing under each version): `ifdef UVM_POST_VERSION_1_1 // UVM 1.1 stuff goes here `else // UVM 1.2 stuff goes here `endif
Try out an example using this feature in EDA Playground
// Create a virtual sequencer class my_virtual_sequencer_t extends uvm_sequencer; // Variables to reference the sequencers we will control uvm_sequencer #(seq_item_t) m_write_sqr; uvm_sequencer #(seq_item_t) m_read_sqr; // Register this sequencer with the factory `uvm_component_utils ( my_virtual_sequencer_t ) function new ( string name, uvm_component parent = null ); super.new ( name, parent ); endfunction : new endclass : my_virtual_sequencer_t
// Create a virtual sequence class read_write_seq_t extends uvm_sequence; `uvm_object_utils(read_write_seq_t) `uvm_declare_p_sequencer(my_virtual_sequencer_t) my_read_seq_t read_seq; // Sequences on sequencers my_write_seq_t write_seq; function new ( string name = "read_write_seq_t" ); super.new ( name ); endfunction : new // Define the virtual sequence functionality. // Note the use of `uvm_do_on() instead of `uvm_do() !! virtual task body(); // Write to a bunch of register locations for ( int i = 0; i < 32; i += 4 ) begin `uvm_do_on_with ( write_seq, p_sequencer.m_write_sqr, { addr == i; }) end // Now read the results on another interface `uvm_do_on ( read_seq, p_sequencer.m_read_sqr ) //... endtask : body endclass : read_write_seq_t
// Connect the sequencer to the driver class my_env_t extends uvm_env; `uvm_component_utils(my_env_t) //... my_virtual_sequencer_t m_vseqr; uvm_sequencer #(seq_item_t) m_seqr_w; uvm_sequencer #(seq_item_t) m_seqr_r; function new (string name, uvm_component parent); super.new(name, parent); endfunction : new // Build the components function void build_phase(uvm_phase phase); super.build_phase(phase); m_vseqr = my_virtual_sequencer_t::type_id::create("m_vseqr", this); m_seqr_w = uvm_sequencer_t#(seq_item_t)::type_id::create("m_seqr_w", this); m_seqr_r = uvm_sequencer_t#(seq_item_t)::type_id::create("m_seqr_r", this); endfunction : build_phase // Connect up the sequencers to the virtual sequencer function void connect_phase(uvm_phase phase); m_vseqr.m_write_sqr = m_seqr_w; m_vseqr.m_read_sqr = m_seqr_r; endfunction : connect_phase //... endclass : my_env_t