- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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!
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The fatal error is generated from the tb.sv itself. You might need to check line 274.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page