Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
16603 Discussions

uvm_config_db fails to get interface UVM QuestaSim

AlexBeasley
New Contributor I
699 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
661 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_Intel
671 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_Intel
669 Views

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


0 Kudos
AlexBeasley
New Contributor I
662 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_Intel
660 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