Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
17268 Discussions

uvm_config_db fails to get interface UVM QuestaSim

AlexBeasley
New Contributor I
2,103 Views

Hi there 

 

I am trying to get a simulation working in QuestaSim - Intel FPGA Edition using UVM. 

Below is the design with all the UVM class extensions

 

`timescale 1ns/1ps 
`include "uvm_macros.svh"
`define LENGTH 4

	import uvm_pkg::*;
	
	
	class Item extends uvm_sequence_item; 
		`uvm_object_utils(Item)
		
		rand bit in; 
		bit 	 out; 
		
		virtual function string convert2str(); 
			return $sformatf("in=%0d, out=%0d", in, out);
		endfunction 
		
		function new(string name = "Item"); 
			super.new(name);
		endfunction 
		
		constraint c1 {in dist {0:/20, 1:/80}; }
		
	endclass 
	
	class gen_item_seq extends uvm_sequence;
		`uvm_object_utils(gen_item_seq)
		
		function new(string name="gen_item_seq"); 
			super.new(name);
		endfunction 
		
		rand int num; 		// config total number of items to be sent 
		
		constraint c1 { soft num inside {[10:50]}; }

		virtual task body ();
			for(int i = 0; i < num; i++) begin 
				Item m_item = Item::type_id::create("m_item");
				start_item(m_item); 
				m_item.randomize();
				`uvm_info("SEQ", $sformatf("Generate new item: %s", m_item.convert2str()), UVM_HIGH)
				finish_item(m_item);		
			end
			`uvm_info("SEQ", $sformatf("Done generation of %0d items", num), UVM_LOW)
		endtask
	endclass 
	
	//The driver is responsible for driving transactions to the DUT
	// All it does it to get a transaction from the mailbox if it is
	// available and drive it out into the DUT interface 
	
	class driver extends uvm_driver #(Item);
		`uvm_component_utils(driver)
		
		function new(string name = "driver", uvm_component parent=null); 
			super.new(name, parent); 
		endfunction 
		
		virtual des_if vif; 
		
		virtual function void build_phase(uvm_phase phase); 
			super.build_phase(phase); 
			if(!uvm_config_db#(virtual des_if)::get(this, "", "des_if", vif))
				`uvm_fatal("DRV", "Could not get vif")
		endfunction 
			
			
		virtual task run_phase(uvm_phase phase);
			super.run_phase(phase);
		
			forever begin 
				Item m_item; 
				`uvm_info("DRV", $sformatf("Wait for item from sequencer"), UVM_HIGH)
				seq_item_port.get_next_item(m_item); 
				drive_item(m_item); 
				seq_item_port.item_done();			
			end 
		endtask 
	
		virtual task drive_item(Item m_item); 
			@(vif.cb); 
			  vif.cb.in <= m_item.in; 
		endtask 
	
	endclass 
	
	// The monitor has a virtual interface handl with which 
	// it can monitor the events happening on the interface 
	// It sees new transcations then captures information 
	// into a packet and sends it to the scoreboard 
	// using another mailbox 
	
	class monitor extends uvm_monitor; 
		`uvm_component_utils(monitor)
		
		function new(string name="monitor", uvm_component parent=null); 
			super.new(name, parent); 
		endfunction 
		
		uvm_analysis_port #(Item) mon_analysis_port; 
		virtual des_if vif; 
		
		virtual function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			
			if(!uvm_config_db#(virtual des_if)::get(this, "", "des_vif", vif))
				`uvm_fatal("MON", "Could not get vif")
			
			mon_analysis_port = new ("mon_analysis_port", this); 
		
		endfunction 
		
		virtual task run_phase(uvm_phase phase); 
			super.run_phase(phase);
			
			//This task monitors the interface for a complete 
			// transaction and writes into analysis port when complete 
			
			forever begin 
				@(vif.cb);
				if(vif.rstn) begin 
					Item item = Item::type_id::create("item"); 
					item.in = vif.in; 
					item.out = vif.cb.out; 
					mon_analysis_port.write(item);
					
					`uvm_info("MON", $sformatf("Saw item %s", item.convert2str()), UVM_HIGH)
				end 		
			end 
		endtask 
	endclass 
	
	// The scoreboard is reponsible for checking design functionality and 
	// should track input and try to match the pattern and ensure that 
	// the design has found the pattern as well. The scoreboard should 
	// flag an error if the design didn't find the pattern and ensure 
	// that "out" remains zero, and if the design found the pattern, 
	// "out" is set to the correct value 
	
	class scoreboard extends uvm_scoreboard; 
		`uvm_component_utils(scoreboard)
		function new(string name="scoreboard", uvm_component parent=null);
			super.new(name, parent); 
		endfunction 
		
		bit [`LENGTH-1:0] ref_pattern; 
		bit [`LENGTH-1:0] act_pattern; 
		bit				  exp_out; 
		
		uvm_analysis_imp #(Item, scoreboard) m_analysis_imp; 
		
		virtual function void build_phase(uvm_phase phase); 
			super.build_phase(phase); 
			
			m_analysis_imp = new("m_analysis_imp", this); 
			if(!uvm_config_db#(bit[`LENGTH-1:0])::get(this, "*", "ref_pattern", ref_pattern))
				`uvm_fatal("SCBD", "Did not get ref_pattern !")
		endfunction 
		
		
		virtual function write(Item item); 
		
			act_pattern = act_pattern << 1 | item.in; 
			
			`uvm_info("SCBD", $sformatf("in=%0d out=%0d ref=0b%0b act=0b%0b", item.in, item.out, ref_pattern, act_pattern), UVM_LOW)
			
			// Always check that expected out value is the actual obseved value,
			// Since it takes 1 clock for out to be updated after pattn match, 
			//do the check first then update exp_out value 
			
			if(item.out != exp_out) begin 
				`uvm_error("SCBD", $sformatf("ERROR ! out=%0d exp=%0d", item.out, exp_out)) 
			end else begin 
				`uvm_info("SCBD", $sformatf("Pass ! out=%0d exp=%0d", item.out, exp_out), UVM_HIGH)
			end 
			
			// If current index has reached the full pattern, then set exp_out to be 1
			// which will be checked in the next clock. If pattern is not complete, keep 
			// exp_out to zero 
			if(!(ref_pattern ^ act_pattern)) begin 
				`uvm_info("SCBD", $sformatf("Pattern found to match, next one should be 1!"), UVM_LOW)
				
				exp_out = 1; 
			
			end else begin 
				exp_out = 0;
			
			end 
		endfunction
	endclass 
	
	
	// Create an intermediate container called "agent" to hold 
	// driver, monitor and sequencer 
	
	class agent extends uvm_agent; 
		`uvm_component_utils(agent)
		function new(string name="agent", uvm_component parent=null);
			super.new(name, parent);
		endfunction 	
		
		driver 		d0; 			//Driver handle
		monitor 	m0;				//Monitor handle
		uvm_sequencer #(Item) s0;	//Sequence Handle 
		
		virtual function void build_phase(uvm_phase phase);
			super.build_phase(phase); 
			s0 = uvm_sequencer#(Item)::type_id::create("s0", this); 
			d0 = driver::type_id::create("d0", this); 
			m0 = monitor::type_id::create("m0", this);
		endfunction 
		
		virtual function void connect_phase(uvm_phase phase);
			super.connect_phase(phase); 
			d0.seq_item_port.connect(s0.seq_item_export);
		endfunction 
	endclass 
	
	// The environment is a contain objet simply to hold 
	// all verification components together. This environment can
	// then be reused later and all components in it would be 
	// automatically connected and available for use 
	
	class env extends uvm_env;
		`uvm_component_utils(env);
		
		function new(string name="env", uvm_component parent=null);
			super.new(name, parent);
		endfunction 
		
		agent 		a0; 	//agent handle
		scoreboard	sb0;	//scoreboard handle 
		
		virtual function void build_phase(uvm_phase phase); 
			super.build_phase(phase); 
			
			a0 = agent::type_id::create("a0", this); 
			sb0 = scoreboard::type_id::create("sb0", this);
		
		endfunction 
		
		virtual function void connect_phase(uvm_phase phase);
			super.connect_phase(phase);
			a0.m0.mon_analysis_port.connect(sb0.m_analysis_imp);
		endfunction 
	endclass 
	
	
	// Test class instantiates the environment and starts it.
	
	class base_test extends uvm_test; 
		`uvm_component_utils(base_test) 
		function new(string name="base_test", uvm_component parent=null);
			super.new(name, parent); 
		endfunction
		
		env				e0; 
		bit[`LENGTH-1:0] pattern = 4'b1011;
		gen_item_seq	seq; 
		
		virtual des_if vif; 
		
		virtual function void build_phase(uvm_phase phase); 
			super.build_phase(phase); 
			
			// create the environment
			e0 = env::type_id::create("e0", this); 
			
			// Get virtual IF handle from the top level and pass it to everything 
			// in the env level 
			
			if(!uvm_config_db#(virtual des_if)::get(this, "", "des_if", vif))
				`uvm_fatal("TEST", "Did not get vif") 
				
			uvm_config_db#(virtual des_if)::set(this, "e0.a0.*", "des_if", vif);
			
			// Setp pattern queue and place into config db
			uvm_config_db#(bit[`LENGTH-1:0])::set(this, "*", "ref_pattern", pattern);
			
			// Create sequence and randomise it 
			seq = gen_item_seq::type_id::create("seq");
			seq.randomize();
		endfunction 
		
		virtual task run_phase(uvm_phase phase);
			phase.raise_objection(this); 
			apply_reset();
			seq.start(e0.a0.s0);
			#200;
			phase.drop_objection(this);
		endtask 
		
		virtual task apply_reset(); 
			vif.rstn <= 0;
			vif.in 	 <= 0; 
			repeat(5) @ (posedge vif.clk); 
			vif.rstn <= 1; 
			repeat(10) @ (posedge vif.clk);
		endtask 
	endclass 
	
	
	class test_1011 extends base_test; 
		`uvm_component_utils(test_1011) 
		function new (string name="test_1011", uvm_component parent=null); 
			super.new(name, parent);
		endfunction 
		
		virtual function void build_phase(uvm_phase phase); 
			pattern = 4'b1011;
			super.build_phase(phase);
			seq.randomize() with { num inside {[300:500]}; };		
		endfunction
	
	endclass 
	
	
	// This interface allows verification components to access DUT signals 
	// using a virtual interface handle 
	interface des_if (input bit clk); 
		logic rstn; 
		logic in; 
		logic out;
		
		clocking cb @ (posedge clk); 
			default input #1step output #3ns;
			input out; 
			output in; 
		endclocking
		
	endinterface 
	

	
	

module tb();

	reg clk; 
	always #10 clk =~ clk;

	des_if _if(clk);
	
	det_1011 u0 (
		.clk(clk), 
		.rstn(_if.rstn), 
		.in(_if.in),
		.out(_if.out)	
	);
	
	initial begin 
		
		clk <= 0;
		uvm_config_db#(virtual des_if)::set(null, "uvm_test_top", "des_vif", _if); 
		run_test("test_1011");
	
	
	end 



endmodule : tb


// Design v1.0

module det_1011 (input clk, 
				 input rstn, 
				 input in, 
				 input out); 
				 
	parameter IDLE  = 0, 
			  S1 	= 1, 
			  S10   = 2, 
			  S101  = 3, 
			  S1011 = 4;
				 
				 
	reg [2:0] cur_state, next_state; 

	assign out = cur_state == S1011 ? 1 : 0;
	
	
	always @ (posedge clk) 
	begin 
		if(!rstn)
			cur_state <= IDLE; 
		else 
			cur_state <= next_state;
	end 
	
	always @ (cur_state or in) 
	begin 
		case(cur_state) 
			IDLE: begin 
				if (in) next_state = S1; 
				else next_state = IDLE; 
			end 
			S1 : begin 
				if (in) next_state = IDLE; 
				else 	next_state = S10; 
			
			end 
			S10 : begin 
				if (in) next_state  = S101; 
				else 	next_state 	= IDLE; 
			end 
			S101: begin 
				if (in) next_state = S1011;
				else 	next_state = IDLE;
			
			end 
			S1011 : begin 
				next_state = IDLE;
			end 
		
		endcase 
	
	end 
	
endmodule 

 

 

Which I then attempt to run in QuestaSim using the following commands 

(The example file above has been saved as "tb.sv")

 

vlib work 
vmap work work 

set UVM_HOME C:/Data/uvm-1.2/

vlog +acc -work work +incdir+$UVM_HOME C:/Data/uvm_example/tb.sv

vsim -t fs -vopt -voptargs="+acc +cover" +incdir+$UVM_HOME work.tb

 

 

However I am getting a fatal error when the test routine checks for the connected interface: 

 

# UVM_FATAL C:/Data/uvm_example/tb.sv(274) @ 0: uvm_test_top [TEST] Did not get vif

 

 

I cannot spot the error. Can anyone see it? 

 

I also am not sure whether QuestaSim will support using UVM like this?

 

Thanks 

Alex 

0 Kudos
1 Solution
AlexBeasley
New Contributor I
2,065 Views

The problem has been spotted. 

Note: there is a typo in some of the 

uvm_config_db#()::get()/set()

lines, where I have mixed up "des_vif" and "des_if" for the handle! 

Totally didn't spot it! 

View solution in original post

0 Kudos
4 Replies
RichardTanSY_Altera
2,075 Views

I am using Questa Intel FPGA Edition-64 2022.1 Revision: 2022.01


I run using the tb.sv provided, along with the command, and does not see any fatal error.


Best Regards,

Richard Tan


0 Kudos
RichardTanSY_Altera
2,073 Views

The fatal error is generated from the tb.sv itself. You might need to check line 274.


0 Kudos
AlexBeasley
New Contributor I
2,066 Views

The problem has been spotted. 

Note: there is a typo in some of the 

uvm_config_db#()::get()/set()

lines, where I have mixed up "des_vif" and "des_if" for the handle! 

Totally didn't spot it! 

0 Kudos
RichardTanSY_Altera
2,064 Views

Great to hear that! With the issue resolved, I will now transition this thread to community support. If you have a new question, feel free to open a new thread to get the support from Intel experts. Otherwise, the community users will continue to help you on this thread. Thank you.

 

Best Regards,

Richard Tan

 

p/s: If any answer from the community or Intel Support are helpful, please feel free to give best answer or rate 9/10 survey.


0 Kudos
Reply