// Base Virtual Sequence Class
class base_vseq extends uvm_sequence #(uvm_sequence_item);
`uvm_object_utils(base_vseq)
// Target Agent Sequencers
uvm_sequencer #(ahb_txn) SQR_AHB;
uvm_sequencer #(axi_txn) SQR_AXI;
// Constructor
function new (string name = "base_vseq");
super.new(name);
endfunction: new
endclass: vseq_base
// Virtual Sequence Class
class my_vseq extends base_vseq;
`uvm_object_utils(my_vseq)
// Constructor
function new (string name = "my_vseq");
super.new(name);
endfunction: new
// Sequence Body Task
task body();
ahb_seqeunce ahb_seq;
axi_sequence axi_seq;
ahb_seq = ahb_sequence::type_id::create("ahb_seq");
axi_seq = axi_sequence::type_id::create("axi_seq");
fork
abh_seq.start(SQR_AHB);
axi_seq.start(SQR_AXI);
join
endtask
endclass: my_vseq
// Base Test Class
class base_test extends uvm_test;
`uvm_component_utils(base_test);
// Environment Class Instantiation
top_env Env;
// Constructor
function new (string name = "base_test", uvm_component parent = null);
super.new(name, parent);
endfunction: new
// Build Phase
function void build_phase (uvm_phase phase);
Env = top_env::type_id::create("Env");
endfunction: build_phase
// Method to Connect Sequencer Handles in VSEQ
function void init_vseq (base_vseq vseq);
vseq.SQR_AHB = test.env.ahb_agent.SQR_AHB;
vseq.SQR_AXI = test.env.axi_agent.SQR_AXI;
endfunction: init_vseq
endclass: base_test
// Main Test
class test extends base_test;
`uvm_component_utils(test)
// Constructor
function new (string name = "test", uvm_component parent = null);
super.new(name, parent);
endfunction: new
// Run Phase
task run_phase (uvm_phase phase);
// Create the Virtual Sequence
my_vseq vseq = my_vseq::type_id::create("vseq");
phase.raise_objection(this);
// Virtual Sequence Initialization
init_vseq(vseq);
// Start the Virtual Sequence
vseq.start(null);
phase.drop_objection(this);
endtask: run_phase
endclass: test
Showing posts with label uvm. Show all posts
Showing posts with label uvm. Show all posts
Sunday, October 30, 2016
UVM Virtual Sequence Example.
UVM AHB Driver Example.
////////// Sequence Item //////////
class ahb_seq_item extends uvm_sequence_item;
`uvm_object_utils(ahb_seq_item)
// Master to Slave Data Flow
rand logic [31:0] HADDR;
rand logic [31:0] HWDATA;
rand logic HWRITE;
ahb_burst_e HBURST;
// Slave to Master Data Flow
logic [31:0] HRDATA;
ahb_resp_e HRESP;
// Constructor
function new (string name);
super.new(name);
endfunction: new
// Constraints
constraint addr_for_32bit {HADDR[1:0] == 0;}
endclass: ahb_seq_item
////////// AHB Interface //////////
interface ahb_interface;
// TO both Master & Slave
logic HCLK;
logic RESETn;
// Master to Slave
logic [31:0] HADDR;
logic [31:0] HWDATA;
logic HWRITE;
ahb_burst_e HBURST;
// Slave to Master
logic [31:0] HRDATA;
ahb_resp_e HRESP;
logic HREADY;
endinterface: ahb_interface
////////// Pipelined UVM Driver //////////
class ahb_pipelined_driver extends uvm_driver #(ahb_seq_item);
`uvm_component_utils(ahb_pipelined_driver)
// Virtual Interface
virtual ahb_interface ahb_if;
// Constructor
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction: new
// Semaphore Declaration
semaphore pipeline_lock = new(1);
// Run Phase Task
task run_phase (uvm_phase phase);
@(posedge ahb_if.HRESETn);
@(posedge ahb_if.HCLK);
fork
do_pipelined_transfer;
do_pipelined_transfer;
join
endtask: run_phase
// do_pipelined_transfer task
task automatic do_pipelined_transfer;
ahb_seq_item req;
forever begin
pipeline_lock.get();
seq_item_port.get(req);
accept_tr(req, $time);
void'(begin_tr(req, "pipelined_driver");
ahb_if.HADDR <= req.HADDR;
ahb_if.HWRITE <= req.HWRITE;
ahb_if.HBURST <= req.HBURST;
@(posedge ahb_if.HCLK);
while(!ahb_if.HREADY == 1) begin
@(posedge ahb_if.HCLK);
end
// Command phase ends here
// Unlock semaphore
pipeline_lock.put();
// Data phase starts here
if (req.HWRITE == 0) begin
@(posedge ahb_if.HCLK);
while(ahb_if.HREADY != 1) begin
@(posedge ahb_if.HCLK);
end
req.HRDATA = ahb_if.HRDATA;
req.HRESP = ahb_if.HRESP;
end
else begin
ahb_if.HWDATA <= req.HWDATA;
@(posedge ahb_if.HCLK);
while(ahb_if.HREADY != 1) begin
@(posedge ahb_if.HCLK);
end
req.HRESP = ahb_if.HRESP;
end
// Return the Request as Response
seq_item_port.put(req);
end_tr(req);
end
endtask: do_pipelined_transfer
endclass: ahb_pipelined_driver
////////// Pipelined Sequence //////////
class ahb_pipelined_seq extends uvm_sequence #(ahb_seq_item);
`uvm_object_utils(ahb_pipelined_seq)
logic [31:0] addr[10]; // To save addresses
int count; // To ensure that the seq does'nt complete too early
// Constructor
function new (string name);
super.new(name);
endfunction: new
// Task body()
task body;
ahb_seq_item req;
req = ahb_seq_item::type_id::create("req", this);
use_response_handler(1); // Enable Response Handler
count = 0;
for(int i=0; i<10; i++) begin
start_item(req);
assert(req.randomize()
with {MWRITE == 1; HBURST == SINGLE; HADDR
inside {[32'h0010_1000:32'h0010_1FFC]};});
addr[i] = req.HADDR;
finish_item(req);
end
foreach (addr[i]) begin
start_item(req);
req.HADDR = addr[i];
req.HWRITE = 0;
finish_item(req);
end
// Wait till last seq item is over
wait(count == 20);
endtask: body
// This response_handler function is enabled
// to keep the sequence response FIFO empty
function void response_handler(uvm_sequence_item response);
count++;
endfunction: response_handler
endclass: ahb_pipelined_seq
UVM PCM Driver Example.
// Interface Declaration
interface adpcm_int;
logic clk;
logic frame;
logic [3:0] data;
endinterface: adpcm_int
// Transaction item class adpcm_txn
class adpcm_txn extends uvm_sequence_item;
`uvm_object_util(adpcm_txn)
rand logic[3:0] data;
rand int delay;
function new (string name);
super.new(name);
endfunction: new
constraint del_bet_pac {delay inside {[1:20]};}
endclass: adpcm_txn
// Driver class adpcm_drv
class adpcm_drv extends uvm_driver #(adpcm_txn);
`uvm_component_utils (adpcm_drv)
adpcm_txn req;
virtual adpcm_int adpcm_if;
function new(string name, uvm_components parent)
super.new(name, parent);
endfunction: new
task run_phase (uvm_phase phase);
// Default conditions
adpcm_if.frame <= 0;
adpcm_if.data <= 0;
forever begin
seq_item_port.get_next_item(req);
repeat(req.delay) begin
@(posedge adpcm_if.clk);
end
adpcm_if.frame <= 1;
for (int i = 0; i < 8; i++) begin
@(posedge adpcm_if.clk);
adpcm_if.data <= req.data[3:0];
req.data = req.data >> 4;
end
adpcm_if.frame <= 0;
seq_item_port.item_done();
end
endtask: run_phase
endclass: adpcm_drv
// Sequence Class adpcm_seq
class adpcm_seq extends uvm_sequence #(adpcm_txn);
`uvm_component_utils (adpcm_seq)
adpcm_txn req;
rand int no_of_reps = 10;
function new (string name);
super.new(name);
endfunction: new
task body;
req = adpcm_txn::type_id::create("req", this);
for (int i = 0; i < no_of_reps; i++) begin
start_item(req);
if (!req.randomize()) begin
`uvm_error("BODY", "req randomization failed")
end
finish_item(req);
`uvm_info("ADPCM_SEQ BODY",
$sformatf("Transmitted frame %0d", i), UVM_LOW)
end
endtask: body
endclass: adpcm_seq
Saturday, October 29, 2016
UVM Coverage.
Basics
- Put all covergroups in a class or module
- Use local variables in the class or module
- Make covergroups sensitive to a variable or explicitly sample a variable
- Have a coverage test plan
- Use automatic bins for simple covergroup
- Code coverage is not functional coverage
- line coverage
- block / statement coverage
- branch coverage
- path coverage
- toggle coverage
- expression coverage
- FSM coverage
- transition coverage
<coverpoint_name> : coverpoint <expression> { bins <bin_name> = { <list of values > } }
class coverage extends uvm_agent;
`uvm_component_utils (coverage)
tlm_analysis_fifo #(mem_req) req_fifo;
mem_req req;
mem_op op;
logic [15:0] addr;
covergroup mem_ops;
coverpoint memop {
bins action[] = {read, write};
}
coverpoint addr {
bins zeros = {0};
bins others = {[1 : 16'hFFFE]};
bins ones = {16'hFFFF};
}
edges : cross op, addr;
endgroup
covergroup alu_cv;
all_ops : coverpoint op;
a_op: coverpoint A {bins Ais0 = {'h00};}
b_op: coverpoint B {bins Bis0 = {'h00};}
endgroup
function new (string name, uvm_component parent);
super.new(name, parent);
mem_ops = new();
alu_cv = new();
endfunction : new
task run();
mem_data cln;
mem_req req_tx;
forever begin : run_loop
req_fifo.get (req_tx);
op = req_tx.op;
addr = req_tx.addr;
mem_ops.sample();
end
endtask : run
endclass
Example: automatic bins
typedef enum {add, and, xor, mul, rst, nop} op_t;
covergroup opcov;
coverpoint op;
endgroup : opcov
task sample_req;
A = req.A;
B = req.B;
op = req.op;
opcov.sample();
endtask
covergroup alu_cv2;
coverpoint op;
coverpoint A;
coverpoint B;
option.auto_bin_max = 4; // default to 64 bins
endgroup
Example: Basic Bins
covergroup opcov;
coverpoint op;
A00FF : coverpoint A {
bins zeros = { 0 };
bins ones = { 8'hFF };
}
B00FF : coverpoint B {
bins zeros_ones = { 0, 8'hFF };
}
endgroup
Bins with Ranges, Bins with sequences
typedef enum {add, and, xor, mul, rst, nop} op_t;
covergroup opcov;
coverpoint op {
bins single_cyc = {[add : xor] , rst, nop};
bins multi_cyc = {mul};
}
endgroup : opcov
// Automatic bins with ranges
bins onepervalue [] = {< list of="" values="" >};
bins n_bins [n] = { < list of="" values="" >};
bins threebins [3] = {[1:2],[2:6]};
// same as
// bins threebins [3] = {1,2,2,3,4,5,6};
// Bins with sequences
// run multi-cycle after reset
// bins bin_name = ( < value1 > => < value2 >);
covergroup opcov;
coverpoint op {
bins single_cycle = {[add : xor], rst, nop};
bins multi_cycle = {mul};
bins mult_rst = (mul => rst);
bins rst_mult = (rst => mul);
}
endgroup
Bins with multiple value transitions in sequences
// Bins with multiple value transitions // bins bin_name = (< value list > => < value list >); // 1, 2 => [3:5], 7 // 1=>3, 2=>3, 1=>4, 2=>4, 1=>5, 2=>5, 1=>7, 2=>7 bins op_rst[] = ( [add : nop ] => rst ); bins rst_mult[] = ( rst => [add : nop]); // multi-cycle after single-cycle bins singl_mul[] = ( [add : xor ], nop => mul ); // single-cycle after multi-cycle bins mul_sngl[] = ( mul => [add : xor ], nop ); // Run all operations twice in a row // bins <name> = (<value list> [* n]); bins <name> = (<value list> [* n:m]); // Ex: Run 3-5 Multiplies in a row bins twoops[] = ([add:nop] [*2]); bins manymult = (mul [* 3:5]); // Nonconsecutive Repetition // <value list> [= n:m]; // nonconsecutive operator // <value list> [-> n:m]; // goto operator // • Nonconsecutive Operator (=) matches if n:m values occur // in a list of value regardless of the terminating value. // • Goto Operator (->) matches if n:m values occur in a list // of values and then a terminating value appears. bins rstmulrst = (rst => mul [= 2] => rst); // rstmulrst (match): rst => mul => xor => mul => and => rst bins rstmulrstim = (rst => mul [-> 2] => rst); // rstmulrst and rstmulrstim (match): rst => mul => xor => and => mul => rst
Cross Coverage : Use Cross and Binsof to capture combinations of values
covergroup zeros_ones_ops;
all_ops : coverpoint op {
ignore_bins null_ops = {rst, nop};
}
a_op: coverpoint A {
bins zeros = {'h00};
bins others = {['h01:'hFE]};
bins ones = {'hFF};
}
b_op: coverpoint B {
bins zeros = {'h00};
bins others = {['h01:'hFE]};
bins ones = {'hFF};
}
basic : cross a_op, b_op, all_ops;
with_a0bin : cross a_op, b_op, all_ops {
bins a0bin = binsof (a_op.zeros);
}
// bins <bin> = binsof(<somebins>) && binsof(<otherbins>);
// bins <bin> = binsof(<somebins>) || binsof(<otherbins>);
zeros_ones : cross a_op, b_op, all_ops {
bins AorBzero = binsof (a_op.zeros) || binsof (b_op.zeros);
bins AorBones = binsof (a_op.ones) || binsof (b_op.ones);
ignore_bins the_others =
binsof (a_op.others) && binsof (b_op.others);
}
// intersect qualifier
// bins <bin> = binsof(<somebins> intersect (<value_list>))
zeros_ones_2 : cross a_op, b_op, all_ops {
bins add_bin = binsof (all_ops) intersect {add};
ignore_bins x = ! binsof (all_ops) intersect {add};
}
endgroup
Friday, October 28, 2016
Randomization.
- $random : return an 32-bit signed random number.
- $urandom : return an 32-bit unsigned random number.
- $srandom(seed) : set random seed for $urandm.
- use run-time switch : +ntb_random_seed=seed_value
- $urandom_range(min, max)
- randcase
randcase 10 : f1(); 20 : f2(); 30 : x = 100; 50 : randcase ... endcase; // nested endcase
Thursday, October 27, 2016
UVM Report.
- Formatting
- $sformat (str, "%m : a = $2h", a);
- $timeformat (-9, 2, " ps", 4);
- timeunit 100ps;
- timeprecision 10ps;
- System Calls
- $display
- $fdisplay - to write to files.
- $time, $stime, $realtime,
- Opening Files
- integer fha = $fopen("fileaname");
- integer fhb = $fopen("filebname");
- integer fhboth = filea | fileb;
- $fdisplay (fha, "string");
- $fclose (fhboth);
- UVM_macros for Reporting
- $display (`__FILE__);
- `uvm_info ("message_ID", "This is info message", verbose_level, UVM_INFO);
- `uvm_warning ("message_ID", "message", Severity);
- `uvm_error ("message_ID", "message", Severity);
- `uvm_fatal ("message_ID", "message", Severity);
- Each reporting method call gets a verbosity number
- The object has a reporting verbosity number
- The method acts only if its verbosity number is below the object's verbosity number
- inst.set_report_verbosity_level_hier (800);
- UVM Report Control
- Verbosity level set
- Reporting methods for actions
- in end_of_elaboration_phase
- UVM_DISPLAY
- UVM_LOG - write to a file
- Open the file(s) and get the MCDs
- Set the logging action on the ID's
- Attach the MCDs to the severities or ID's
- set_report_default_file()
- set_report_id_file ("printer", printer_file);
- set_report_severity_action
(UVM_WARNING, UVM_DISPLAY | UVM_LOG); - set_report_severity_file (UVM_WARNING, warning_file);
- dump_report_state();
- set_report_max_quit_count (10);
- UVM_COUNT
- UVM_EXIT
- UVM_CALL_HOOK - call user defined method
- UVM_STOP
- Reporting action controls
- set_severity_action (severity sv, action a)
- set_id_action (string id, action a)
- set_severity_id_action (severity sv, string id, action a)
- set_severity_action_hier (severity sv, action a)
- set_id_action_hier (string id, action a)
- set_severity_id_action_hier (severity sv, string id, action a)
- Default:
- UVM_INFO : UVM_DISPLAY
- UVM_WARNING : UVM_DISPLAY
- UVM_ERROR : UVM_DISPLAY | UVM_COUNT
- UVM_FATAL : UVM_DISPLAY | UVM_EXIT
- File ID
UVM Test Analysis.
Analysis Layer
- Scoreboard / Subscriber / Monitor / Predictor
- Watch / Observe
- Recognize transactions
- Place the transactions to the analysis ports
- Coverage
- Reporting
- Simulation
- Tests/Transactions -> Drivr -> DUT -> Responder -> TLM models
- Can connect to multiple objects (unlike uvm_put_port)
- Analysis Ports, Exports, Imps
- Port, Export and Imp
Example of Monitor Class
class monitor extends interface_base;
`uvm_component_utils(monitor)
uvm_analysis_port #(mem_data) rspa;
uvm_analysis_port #(mem_req) reqa;
function new (string name = "driver",
uvm_component parent = null);
super.new (name, parent);
endfunction : new
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
reqa = new ("reqa", this);
rspa = new ("rspa", this);
endfunction: build_phase
task run_phase(uvm_phase phase);
mem_req req = new(), c_req;
mem_data rsp = new(), c_rsp;
forever begin : monitor_loop
@(posedge mif.clk);
#UNIT_DELAY;
req.load_data (mif.addr, mif.data, nop);
rsp.load_data (mif.addr, mif.data);
if (mif.wr) req.op = write;
if (mif.rd) req.op = read;
if (req.op != nop) begin
$cast(c_req, req.clone());
reqa.write (c_req);
end
if (mif.rd) begin
$cast (c_rap, rsp.clone());
rspa.write (c_rsp);
end
end : monitor_loop
endtask
endclass : monitor
Create a Subscriber
- Instantiate a "uvm_tlm_analysis_fifo"
- Connect to the analysis_port at the top level
- Use get() to block and take data out of the analysis fifo
Create a Predictor
- It gets a request from the analysis_port connected to the monitor.
- It predicts what response transaction will appear.
class predictor extends uvm_agent;
`uvm_component_utils (predictor)
logic [15:0] mem [2**16-1 : 0];
uvm_tlm_analysis_fifo #(mem_req) reqfifo;
uvm_put_port #(mem_data) rsp_p; // to connect to comparator
mem_data rsp = new();
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);
req_fifo = new("req_fifl", this);
rsp_p = new ("rsp_po", this);
endfunction : build_phase
task run_phase (uvm_phase phase);
mem_data cln;
mem_req req_txn;
forever begin : run_loop
req_fifo.get (req_tx);
case (req_tx.op)
write : mem[req_tx.addr] = req_tx.data;
read : begin : read_op
rsp.load_data (req_tx.addr, mem[req_tx.addr]);
$case (cln, rsp.clong());
rsp_p.put(cln);
end : read_op
endcase
end : run_loop
endtask : run_phase
endclass : predictor
Create a Comparator and a Printer to Report
- It gets a response transaction from the monitor.
- It compares the actual response transaction to the predicted response transaction.
class comparator extends uvm_agent;
`uvm_component_utils (comparator)
uvm_tlm_analysis_fifo #(mem_data) actual_f;
uvm_get_port #(mem_data) predicted_p;
mem_data actual_rsp, predicted_rsp;
function new ...
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
actual_f = new ("actual_f", this);
predicted_p = new ("predicted_p", this);
endfunction : build_phase
task run_phase (uvm_phase phase);
forever begin : run_loop
actual_f.get (actual_rsp);
predicted_p.get (predicted_rsp);
if (actual_rsp.comp(predicted_rsp))
uvm_report_info ("run",
$psprintf ("passed: %s",
actual_rsp.convert2string()) );
else
uvm_report_info ("run",
$psprintf ("ERROR: expected: %s does not match actual: %s",
predicted_rsp.convert2string(),
actual_rsp.convert2string()) );
end : run_loop
endtask : run_phase
endclass : comparator
class printer #(type T = mem_data) extends uvm_agent;
`uvm_component_utils (printer#(T))
uvm_tlm_analysis_fifo #(T) a_fifo;
function new ...
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
a_fifo = new ("a_fifo", this);
endfunction : build_phase
task run_phase (uvm_phase phase);
forever begin
T data;
a_fifo.get(data);
uvm_report_info ("run", data.convert2string());
end
endtask : run_phase
endclass : printer
class mem_data extends uvm_transaction;
`uvm_object_utils (mem_data)
rand logic [15:0] data;
rand lobic [15:0] addr;
virtual function bit comp (uvm_object rhs);
mem_data RHS;
$cast (RHS, rhs);
return ((RHS.addr == addr) && (RHS.data == data));
endfunction : comp
endclass : mem_data
class mem_req extends mem_data;
...
endclass : mem_req
Top Leven Test Environment
class test_env extends uvm_env;
`uvm_component_utils (test_env)
tester tst;
driver drv;
uvm_tlm_fifo #(mem_req) tester2driv;
printer #(mem_req) req_prt;
printer #(mem_data) rsp_prt;
monitor mon;
predictor pred;
comparator cmp;
uvm_tlm_fifo #(mem_data) pred2cmp;
function new (string name = "tester_env",
uvm_component parent = null );
super.new (name, parent);
endfunction : new
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
tst = tester::type_id::create ("tst", this);
drv = driver::type_id::create ("drv", this);
tester2drv = new ("tester2drv");
req_prt = printer#(mem_req)::type_id::create("req_prt", this);
rsp_prt = printer#(mem_data)::type_id::create("rsp_prt", this);
mon = monitor::type_id::create ("mon", this);
pred = predictor::type_id::create ("pred", this);
cmp = comparator;:type_id::create ("cmp", this);
pred2cmp = new("pred2cmp"< this);
endfunction : build_phase
virtual function void connect_phase (uvm_phase phase);
super.connect_phase(phase);
tst.tb_port.connect (tester2drv.put_export);
drv.req_f.connect (tester2drv.get_export);
cmp.predicted_p.connect (pred2cmp.get_export);
pred.rsp_p.connect(pred2cmp.put_export);
mon.req_a.connect (pred.req_fifo.analysis_export);
mon.rsp_a.connect (cmp.req_fifo.analysis_export);
mon.req_a.connect (req_prt.a_fifo.analysis_export);
mon.rsp_a.connect (rsp_prt.a_fifo.analysis_export);
endfunction : connect_phase
endclass : test_env
class bucket #(type T = mem_data) extends printer #(T);
typedef bit_bucket#(T) thistype;
`uvm_component_param_utils (thistype)
function new ...
task run_phase (uvm_phase phase);
forever begin
T data;
a_fifo.get(data);
end
endtask : run_phase
endclass : bucket
class qtest extends uvm_test;
`uvm_component_utils (qtest)
test_env t_env;
function new ...
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
printer#(mem_data)::type_id::set_type_override
(bucket#(mem_data)::get_type());
printer#(mem_req)::type_id::set_type_override
(bucket#(mem_data)::get_type());
t_env = test_env::type_id::create ("t_env", this);
endfunction : build_phase
endclass : qtest
Wednesday, October 26, 2016
UVM Configuration DB Gotchas.
- Missing super.build_phase()
- Missing field macro
- UVM_READONLY on field
- Missing get() after set() changes the entry
- uvm_config_object::set() writes a null object
- Wrong or mismatched types
- Missing $cast in explicit get()
- Wrong string in field names, wrong context
- Not a good practice to use wildcard in ::set() - creating too much visibility
References:
UVM Configuration DB.
Concepts
- Share information between
- Test
- Top environment
- sub environment
- agents
- sequencers
- monitors
- drivers
- Need a consistent way of storing shared data
- Need simple, flexible access from anywhere
- Need automatic access (done by uvm_component::build_phase())
- Compare to traditional
- enclosing pushes
- ex. env.m_this_config = m_cfg
How to Use
- Share the information of Physical IFs (between DUT and uvm_test)
- Put into configuration db at top test module and get it in
uvm_env.uvm_agent
uvm_env.uvm_agent.uvm_driver
uvm_env.uvm_agent.uvm_sequencer
uvm_env.uvm_agent.uvm_monitor - Share DUT specific information
Syntax
// // UVM 1.1 set_config_int(...) => uvm_config_db#(uvm_bitstream_t)::set(cntxt,...) set_config_string(...) => uvm_config_db#(string)::set(cntxt,...) set_config_object(...) => uvm_config_db#(uvm_object)::set(cntxt,...) // // UVM 1.2 // type T=int // class uvm_config_db#(type T=int) extends uvm_resource_db#(T) // // context, inst, key, value uvm_config_db#(T)::set(cntxt,"inst","field",value); // modify central entries uvm_config_db#(T)::get(cntxt,"inst","field",value); // update local variabbles // There is a uvm11-to-uvm12.pl conversion script uvm_config_db#(T)::exists(cntxt,"inst","field"); uvm_config_db#(T)::wait_modified(cntxt,"inst","field"); // For objects use this set_config_object::set(this,"env.agent1","config", m_config); // For enums use this set_config_int::set(this,"env.agent1","bus_sz", SZ_128 ); // cntxt must be of type uvm_component, null or uvm_root::get() // m_config: recommend to use uvm_object and $cast // Examples: uvm_config_db#(T)::set(uvm_root::get(),”test1.env.agent1”, ”config”, m_config); uvm_config_db#(T)::set(this,”env.agent*”,”config”, m_config); uvm_config_db#(T)::set(null,”*”,”global_cfg”, m_global_cfg); // to fetch the entry if (!uvm_config_db#(uvm_object)::get(this, "","config",m_config)) begin `uvm_fatal(...) end // check if it exists if(!uvm_config_db#(int)::exists(this,"","low_power_mode")) begin // do something interesting end // To automate field configuration // Use uvm_config_object typedef // Use uvm_object and $cast to concrete type for get() function void uvm_component::build_phase(...); // find fields, do get(), $cast apply_config_settings(...); endfunction // Gotchas: 1. Don't miss field-macro // 2. Make sure it's not UVM_READONL / 3. remember to use super.build class my_comp extends uvm_component; `uvm_component_utils_begin(my_comp) `uvm_field_int(my_field,UVM_DEFAULT) `uvm_field_object(my_special,(UVM_DEFAULT|UVM_READONLY)) `uvm_field_object(my_config,UVM_DEFAULT) function void build_phase(...); super.build_phase(...); ... endfunction // Using uvm_object and $cast in set() and get() my_config m_config; ... uvm_config_object::set(..., m_config); uvm_object tmp; uvm_config_object::get(..., tmp); $cast(m_config, tmp); // back to original type // Using enums (can be int, uvm_bitstream_t or uvm_integral_t my_enum_t m_bus_sz; uvm_config_int::set(... , "m_bus_sz", SZ16); int tmp; uvm_config_int::get(... ,"m_bus_sz", tmp) m_bus_sz = my_enum_t'(tmp); // back to original type // Recommend use the factory m_srio_config = uvc_srio_config::type_id::create("m_srio_config");
Hierarchy of Configuration Objects
class top_env_config extends uvm_object;
env1_config m_env1_config;
env2_config m_env2_config;
...
endclass
class env1_config extends uvm_object;
int some_var;
int some_other_var;
agent1_config m_agent1_config;
agent2_config m_agent2_config;
...
endclass
class top_env extends uvm_env;
env1 m_env1;
env2 m_env2;
top_env_config m_config;
...
'uvm_component_utils_begin(top_env)
'uvm_field_object(m_config, UVM_DEFAULT)
'uvm_component_utils_end
function build_phase();
super.build_phase();
set_config_object(this, "env1","m_config",
m_config.m_env1_config);
set_config_object(this, "env2","m_config",
m_config.m_env2_config);
m_env1 = env1::type_id::create("m_env1");
m_env2 = env2::type_id::create("m_env2");
endfunction
endclass
// Next Level Down
class env1 extends uvm_env;
env1_config m_config;
...
'uvm_component_utils_begin(top_env)
'uvm_field_object(m_config, UVM_DEFAULT)
'uvm_component_utils_end
function void build_phase();
super.build_phase();
set_config_object(this, "m_agent1","m_config",
m_config.m_agent1_config);
set_config_object(this, "m_agent2","m_config",
m_config.m_agent2_config);
m_agent1 = env1::type_id::create("m_agent1");
m_agent2 = env2::type_id::create("m_agent2");
endfunction
endclass
Turn on the debugging in simulation
% sim_cmd +UVM_TESTNAME=my_test +UVM_CONFIG_DB_TRACE
UVM Scoreboard Methodology.
Principles and Concepts
- Verify transaction functional correctness with the following approaches
- constrained-randomization
- coverage driven
- transaction-level compartment
- Use sequences
- Use scoreboard
- Use configuration-db
- Use SystemVerilog to provide aggregate types for transaction storage and search
- Dynamic Arrays, Associative Arrays, Queues, Classes
- UVM analysis ports is easier to use than callbacks
- UVM_transaction provides compare() / do_compare() methods
- UVM factor for extension, replacement and reuse.
Plan of Attack
- Analysis_port
- port, export and imp classes used for transaction analysis
- uvm_analysis_port - broadcasts a value to all subscribers implementing a uvm_analysis_imp
- uvm_analysis_imp - receives all transactions broadcasted by a uvm_analysis_port.
- Transaction Predictor
- Required when the compared transaction is not the same format as input (ex. protocol bridges)
- Design transforms data (ex. encryption, filter, encoder)
- To Re-Use
- encapsulation : a separate class
- uvm_analysis_port / imp to connect
- UVM factory to extend, replace existing objects
- Replace complex predictors with several simpler scoreboards
- Storage (for read scoreboard and for write scoreboard)
- FIFO : queues
- OOO : dynamic arrays, queues
- MEM : associative array (indexed by address)
- Associative array of queues
- TLM Model
- Used when you have multiple different transaction paths/routes
- Used when behavior depends on the address or opcodes or other attributes of transactions
- Using Factory
- Interconnect
- Automate by Randomization
- Checks and Coverage
- Assertions
- Pool
Transactions
- Transaction content
- Data, address, Attributes, Opcode, Response,
- Data types:
- memory -> scalar, bytes, integers,
- Data path:
- Scalar
- Transaction Item Class
- Transaction ordering
- FIFO
- OOO
- Precedence relationship
- Test Data/Transactions -> Item of Sequences -> Sequences -> Sequencer -> Driver -> VIF -> DUT
- DUT -> monitor -> Analysys_ports -> Scoreboard
Monday, October 24, 2016
UVM / System Verilog - Threads and Synchronization.
- In SystemVerilog, when you instantiate static modules, you create multiple threads running the procedures within each instances.
- Synchronization
- Mailbox
- Streams
- Semaphore
- Use Ports, Exports and TLM_FIFOs
- uvm_put_port # (int) p1;
p1 = new("put_port", this); - uvm_get_port #(int) p2;
- uvm_tlm_fifl #(int) p3;
- m1.p1.connect (p3.put_export);
m2.p2.connect (p3.get_export); - Put shared variable in a package, together with all the classes that share that variable (using `include);
- Blocking Methods vs Non-Blocking Methods
- blocking method
- myport.put(<data>);
- myport.get(<data>);
- non-blocking method (returns 0 if failed)
- myport.try_put();
- myport.try_get();
// in f1.svh, for class c1
uvm_put_port # (int) p1;
p1 = new("put_port", this);
// in f2.svh, for class c2
uvm_get_port #(int) p2;
p2 = new("p2", this);
// in f3.svh, which contains the
// test env for c1 and c2
uvm_tlm_fifo #(int) p3;
p3 = new("p3", this);
c1.p1.connect (p3.put_export);
c2.p2.connect (p3.get_export0;
// c1.p1 -> (put_export of env)
// ->(p3)->
// (get_export of env) -> c2.p2
endtask : run
virtual task run();
integer i;
for (i = 1; i < cnt; i++) begin : loop
uvm_report_info ("run", $psprintf(...));
my_pkg::shared = i; // used by other classes
// for synchronization
// i = my_pkg::shared; // to read from the shared
end : loop
endtask : run
Example
class c1 extends uvm_agent;
uvm_put_port #(int)p1;
`uvm_component_utils(c1)
function new...
virtual function void build_phase (uvm_phase phase);
super.build_phase(phase);
p1 = new("p1", this);
endfunction : build_phase
virtual task run_phase (uvm_phase phase);
phase.raise_objection(this);
for (int i = 0; i < cnt; i++) begin
p1.put(i);
uvm_report_info("run_phase",...);
end : loop
phase.drop_objection(this);
endtask : run_phase
endclass : c1
class c2 extends uvm_agent;
uvm_put_port #(int)p2;
`uvm_component_utils(c2)
function new...
virtual function void build_phase (uvm_phase phase);
super.build_phase(phase);
p2 = new("p2", this);
endfunction : build_phase
virtual task run_phase (uvm_phase phase);
int i;
forever begin : loop
p2.get(i);
uvm_report_info("run_phase",...);
end : loop
endtask : run_phase
endclass : c2
class c3 extends uvm_agent;
`uvm_component_utils(c3)
c1 p1;
c2 p2;
uvm_tlm_fifo #(int) p3;
function new...
virtual function void build_phase (uvm_phase phase);
super.build_phase(phase);
p1 = c1::type_id::create("p1", this);
p2 = c2::type_id::create("p2", this);
p3 = new("p3", this);
endfunction : build_phase
virtual function void connect_phase (uvm_phase phase);
super.connect_phase(phase);
c1.p1.connect(p3.put_export);
c2.p2.connect(p3.get_export);
endfunction : connect_phase
virtual task run_phase (uvm_phase phase);
endtask : run_phase
endclass : c3
Example : Blocking Communication vs Non-blocking Communication
// blocking
// @(posedge clk); // this could be missed
// and block the following
// my_port.get(data);
// bus <= data;
// non-blocking
// @(posedge clk)
// my_port.try_get(data); // won't suspend
// bus <= data;
//
class c1 extends uvm_agent;
`uvm_component_utils(c1)
uvm_put_port #(int)p1;
function new...
virtual function void build_phase (uvm_phase phase);
super.build_phase(phase);
p1 = new("p1", this);
endfunction : build_phase
virtual task run_phase (uvm_phase phase);
phase.raise_objection(this);
for (int i = 0; i < cnt; i++) begin
// p1.put(i);
// uvm_report_info("run_phase",...);
#UNIT_DELAY; // to delay this thread so the following
// is always slower than p2 and
// should never fail
assert (p1.try_put(i)) else
uvm_report_info("run_phase: p1 not connected");
uvm_report_info("run_phase", $psprintf("put: %0d",i));
end : loop
phase.drop_objection(this);
endtask : run_phase
endclass : c1
class c2 extends uvm_agent;
`uvm_component_utils(c2)
uvm_put_port #(int)p2;
function new...
virtual function void build_phase (uvm_phase phase);
super.build_phase(phase);
p2 = new("p2", this);
endfunction : build_phase
virtual task run_phase (uvm_phase phase);
int i;
forever begin : loop
// p2.get(i);
// uvm_report_info("run_phase",...);
if (p2.try_get(i))
uvm_report_info ("run",
$psprintf ("got: %0d",i));
else
uvm_report_info ("run","got nothing");
end : loop
endtask : run_phase
endclass : c2
UVM - Scoreboard, Checking and Reporting.
- Scoreboard
- Reporting printer
- Using create
Scoreboard
- Scoreboard could hold the entire self-checking structure including the transfer function or reference model, the expected data storage mechanism and the output comparison function . It could also be limited to the data structure used to hold the expected data for ease of comparison against the monitored output values.
- Stimulus Generator or Sequencer
- DUT -> Response Monitor
- TLM or transfer function
- Output from the DUT responses are compared with expected result from transfer model
class scoreboard extends uvm_agent;
`uvm_component_utils(scoreboard)
virtual interface mem_if vif;
logic [15:0] exp [2**16-1:0];
function new (string name = "scoreboard", uvm_component parent = null);
super.new (name, parent);
endfunction : new
task run_phase (uvm_phase phase);
forever begin
@ (vif.cb)
if (vif.rd) begin
#`UNIT_DELAY
assert (vif.data === exp[vif.addr]) else
uvm_report_error ("run",
$psprintf("expected %0h actual: %0h",
exp[vif.addr], vif.data));
end
if (vif.wr) begin
exp[vif.addr] = vif.data;
end
end
endtask : run_phase
Reporting
class reporter extends uvm_agent;
`uvm_component_utils (reporter)
virtual interface mem_if vif;
function new (string name = "reporter", uvm_component parent = null);
super.new (name parent);
endfunction : new
task run_phase (uvm_phase phase);
forever begin
@(vif.cb);
uvm_report_info ("run",
$psprintf ("addr: %1h data:%4h rd:%1b wr: %1b",
vif.addr, vif.data, vif.rd, vif.wr));
end
endtask : run_phase
endclass : reporter
class bucket extends reporter;
`uvm_component_util(bucket)
function new ...
task run_phase (uvm_phase phase); // override to do nothing
endtask : run_phase
endclass : bucket
Create Tests
// In the test class file
class test1 extends uvm_test;
`uvm component_utils(test1)
test_env tenv;
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
virtual function void build_phase (uvm_phase phase);
tenv = test_env::type_id::create("tenv", this);
endfunction : build_phase
endclass
class test2 extends uvm_test;
`uvm component_utils(test2)
test_env tenv;
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
virtual function void build_phase (uvm_phase phase);
// When you call the overriding run_phase in bucket,
// the test will run without printing line by line data in
// in default reporter.run_phase
reporter::type_id::set_type_override(bucket::get_type());
tenv = test_env::type_id::create("tenv", this);
endfunction : build_phase
endclass : test2
class test_env extends uvm_env;
`uvm_component_utils (test_env)
driver drv;
scoreboard sb;
reporter rpt;
function new ...
virtual function void build_phase (uvm_phase phase);
drv = driver::type_id::create("drv", this);
sb = scoreboard::type_id::create("sb", this);
rpt = reporter::type_id::create("rpt", this);
endfunction : build_phase
endclass
UVM Connections.
Using Interface
- Virtual interface
- Static interface
Example 1
`include "uvm_macros.svh" package my_pkg; import uvm_pkg::*; int shared_int; int shared_count; virtual interface mem_if global_vmi; `include "uvm_macros.svh" `include "test_1.svh" `include "test_2.svh" endpackage: my_pkg import uvm_pkg::*; import my_pkg::*; module top; mem_if mi(); sram dut (mi.mem_modport); initial begin string test_name; my_pkg::global_vmi = mi; run_test(); end endmodule: top // typedef struct packed typedef struct { bit sign; bit[24:0] mantissa; bit[ 5:0] exponent; } ieee_sp_float; union packed { bit [7:0] data[1500]; struct packed { bit [7:0] dsap; bit [7:0] ssap; bit [7:0] control; bit [7:0] data[1497]; } label; } payload; class test_1 extends uvm_test; `uvm_component_utils(test_1) ieee_sp_float v1, v2; v1 = {1, 24'h800, 6'h0}; v1 = abs(v1); virtual interface mem_if mi; function new (string name, uvm_component base); super.new(name, base); endfunction : new virtual function void build_phase(uvm_phase phase); super.build_phase(phase); mi = my_pkg::global_vmi; endfunction : build_phase virtual task run_phase(uvm_phase phase); int cnt=5; logic [3:0] sub_addr; rand logic [11:0] upper_addr; sub_addr = $urandom($random); phase.raise_objection(this); mi.wr = 1'b1; mi.rd = ~mi.wr; mi.wr_data = $urandom($random); `uvm_info("TESTER", $psprintf("addr: %2h data: %2h rd: %1b wr: %1b", mi.addr, mi.data, mi.rd, mi.wr), UVM_INFO); super.run(); mi.addr = {upper_addr, sub_addr}; repeat (cnt) begin @(posedge mi.clk); ... end @(posedge mi.clk); phase.drop_objection(this); endtask // run_phase
Example 2
import my_pkg::*; // Virtual interface in driver class my_driver extends uvm_driver #(my_transaction); `uvm_component_utils(my_driver) virtual dut_if dut_vi; function new(string name, uvm_component parent); super.new(name, parent); endfunction: new // function void build; virtual function void build_phase (uvm_phase phase); super.build(); dut_vi = global_dutvi; endfunction : build_phase // task run; task run_phase (uvm_phase phase); repeat(4) begin phase.raise_objection(this); my_transaction tx; @(posedge dut_vi.clock); // Driver consumes the transactions generated by // my_transaction and wiggles the pins on the DUT seq_item_port.get(tx); // Pin Wiggling dut_vi.cmd = tx.cmd; dut_vi.addr = tx.addr; dut_vi.data = tx.data; end @(posedge dut_vi.clock) top.stop_request(); phase.drop_objection(this); endtask: run endclass : my_driver
Example 3, connecting sequencer to driver
class my_sequencer extends uvm_sequencer;
...
uvm_put_port #(int) port1;
port1 = new ("port1", this);
endclass
class my_driver extends uvm_driver;
...
uvm_get_port #(int) port2;
port2 = new ("port2", this);
endclass
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent) // register for type_id
my_sequencer my_sequencer_h;
my_driver my_driver_h;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction: new
function void build;
super.build();
my_sequencer_h =
my_sequencer::type_id::create("my_sequencer_h", this);
// instance name, parent
my_driver_h =
my_driver::type_id::create ("my_driver_h" , this);
endfunction: build
// Lower level connection in another function is good practice
// seq_item_port is the handler of the ports
function void connect;
my_driver_h.seq_item_port.connect(
my_sequencer_h.seq_item_export );
endfunction: connect
endclass : my_agent
Example 4, connecting through top module
`timescale 1ns/1ns module top; mem_if mi(); sram dut (mi.mem_modport); tester tst (mi.test_modport); endmodule // top interface mem_if; bit clk, rd, wr; logic [15:0] wr_data; wire [15:0] data; logic [15:0] addr; modport mem_modport ( inout data, input addr, input clk, input rd, input wr ); modport test_modport ( input clk, output wr_data, output addr, output rd, output wr ); clocking cb @ (negedge clk); output data <= ...; output addr <= ...; endclocking: cb initial begin @(cb) ; wr_data <= ...; @(cb) ; wr <= $urandom; end assign rd = ~wr; assign data = (wr) ? wr_data : 16'hzzzz; initial begin clk = 0; $monitor (); end always #10 clk = ~clk; endinterface // mem_if
Example 5, connecting in tester
module top; mem_if mi(); sram dut (mi.mem_modport); tester tst; initial begin tst = new(mi); fork tst.run; join_none end endmodule // top class tester; // driver logic [3:0] sub_addr; virtual interface mem_if tmi; function new (virtual interface mem_if vmi); tmi = vmi; endfunction // new task run; // generate transaction data tmi.wr = 1'b1; @ (posedge tmi.clk); repeat (100) begin @ (posedge tmi.clk); tmi.wr = $random; tmi.rd = ~tmi.wr; tmi.addr = $random; tmi.wr_data = $urandom($random); end $stop; endtask // run endclass // tester
Example 6, use wrapper_if
module top; import uvm_pkg::*; import my_pkg::*; mem_if mi(); sram dut (mi.mem_modport); // tester tst; // replaced by if_wrapper initial begin: blk dut_if_wrapper if_wrapper = new ("if_wrapper", dut_if_inst1); // path field_name value 0: don't clone set_config_object("*", "dut_if_wrapper", if_wrapper, 0); run_test ("my_test"); end endmodule : top class dut_if_wrapper extends uvm_object; virtual dut_if dut_vi; function new (string s, virtual dut_if if_arg); super.new(s); dut_vi = if_arg; endfunction : new // you can have task run; here endclass : dut_if_wrapper `include "uvm_macros.svh" package my_pkg; import uvm_pkg::*; // Fixed test environment class my_env extends uvm_env; `uvm_component_utils (my_env) virtual dut_if dut_virtual_if_inst; // constructor function new (string s, uvm_component inst_parent); super.new (s, inst_parent); endfunction : new function void build; super.build (); begin uvm_object obj; dut_if_wrapper if_wrapper; get_config_object("dut_if_wrapper", obj, 0); assert( $cast(if_wrapper, obj) ); dut_virtual_if_inst = if_wrapper.dut_vi; end endfunction : build task run; #10 dut_virtual_if_inst.data = 0; #10 dut_virtual_if_inst.data = 1; #10 stop_request(); endtask : run endclass : my_env
Example 7, use uvm_get_port and uvm_put_port in tlm_fifo / tlm_analysis_fifo
class producer extends uvm_agent;
uvm_put_port #(int) phone1;
...
virtual function void build_phase (uvm_phase phase);
super.build_phase(phase);
phone1 = new("phone1", this);
endfunction
virtual task run_phase (uvm_phase phase);
phase.raise_objection(this);
for (int i = 0; i < count; i++) begin : loop
phone1.put(i);
uvm_report_into ("run_phase", $psprintf("...");
end : loop
phase.drop_objection(this);
endtask : run_phase
endclass : producer
class consumer extends uvm_agent;
uvm_get_port #(int) phone2;
...
virtual function void build_phase (uvm_phase phase);
super.build_phase(phase);
phone2 = new("phone2", this);
endfunction
virtual task run_phase (uvm_phase phase);
phase.raise_objection(this);
for (int i = 0; i < count; i++) begin : loop
phone1.put(i);
uvm_report_into ("run_phase", $psprintf("...");
end : loop
phase.drop_objection(this);
endtask : run_phase
endclass : producer
class test_env extends uvm_env;
producer p;
consumer c;
uvm_tlm_fifo #(int) tlmff;
function new () ...
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
p = producer::type_id::create ("p", this);
p = producer::type_id::create ("p", this);
tlmff = new ("tlmff", this);
endfunction : build_phase
virtual function void connect_phase (uvm_phase phase);
super.connect_phase (phase);
p.phone1.connect (tlmff.put_export);
c.phone2.connect (tlmff.get_export);
endfunction : connect_phase
Example 8, using uvm_config_db
module top;
...
dut_if dut_if1 ();
initial
begin: blk
// type of value prefix path
uvm_config_db #(virtual dut_if)::set(null, “uvm_test_top”,
"dut_vi", dut_if1);
// field name, value
run_test("my_test");
end
endmodule: top
class my_test extends uvm_test;
...
my_dut_config dut_config_0;
...
function void build_phase(uvm_phase phase);
dut_config_0 = new();
// type of value prefix path
if(!uvm_config_db #(dut_if)::get( this, “”,
“dut_vi”, dut_config_0.dut_vi))
`uvm_fatal(“MY_TEST”, “No DUT_IF”);
// other DUT configuration settings
uvm_config_db#(my_dut_config)::set(this, “*”, “dut_config”,
dut_config_0);
endfunction
endclass
class my_driver extends uvm_driver;
`uvm_component_utils(my_driver)
virtual dut_if dut_vi;
function new(string name, uvm_component parent); ...
function void build_phase(uvm_phase phase); ...
task run_phase(uvm_phase phase);
phase.raise_objection(this);
#10 dut_vi.data = 0;
#10 dut_vi.data = 1;
#10 phase.drop_objection(this);
endtask: run_phase
endclass
Friday, October 21, 2016
UVM 101.
Packages
- Provide a common name space •
- Can be imported •
- Can contain common objects •
// You can have the followings in a package
// • Common typedefs
// • Common class definitions
// • Shared instances or variables
import uvm_pkg::*;
`include "defines.svh"
`include "macro_defines.svh"
`include "test_plugin.svh"
module top;
initial begin
#10ns;
uvm_top.uvm_report_info ($psprintf("%m"),
"This is an info message");
end
endmodule
Macros
`define info(msg) uvm_top.uvm_report_info($psprintf("%m"), msg);
`define warning(msg) uvm_top.uvm_report_warning($psprintf("%m"), msg);
`define error(msg) uvm_top.uvm_report_error($psprintf("%m"), msg);
`define fatal(msg) uvm_top.uvm_report_fatal($psprintf("%m"), msg);
import uvm_pkg::*;
module top;
initial begin
`info ("My info message goes here");
`warning ("My warning message goes here");
`error ("My error message goes here");
`fatal ("My fatal message goes here");
end
endmodule
`ifdef FPGA
module sythesizable_block;
endmodule // monitor
`else
module beh_model;
endmodule // beh_model;
`endif // !`ifdef FPGA
// Define macro when you compile in dofile
% if (file exists work) {delete -all}
% vlib work
% vlog top.sv +define+FPGA
% vsim -novopt top
% run -all
Classes
class read_op extends memory_op;
constraint read_only_c {mem_op == read;};
endclass // read_op
// • Put each class in individual .svh file
// • Put all .svh files in a package "tb_pkg" using `include
// • Put all files in a file list "vfiles.f" to compile
// • In the top test bench file, import "uvm_pkg" and this "tb_pkg"
UVM package
- uvm_report_object
- uvm_cmdline_processor
- uvm_component
- uvm_agent
- uvm_driver #()
- uvm_env
- uvm_monitor
- uvm_port_component_base
- uvm_root
- uvm_scoreboard
- uvm_sequencer_base
- uvm_test
- uvm_tlm_fifo_base #()
- UVM phases used in uvm_test
- function void build_phase()
- function void connect_phase()
- function void end_of_elaboration_phase()
- function void start_of_simulation_phase()
- function void run_phase()
- function void extract_phase()
- function void check_phase()
- function void report_phase()
- Use "+UVM_TESTNAME=test1" to run different tests
- The sub classes extended rom uvm_test with UVM_TESTNAME plusarg will start the run_test() that is defined in uvm_pkg and the run_test() uses UVM factory pattern to create a test object.
class test1 extends uvm_test;
`uvm_component_util(test1)
function new (string name, uvm_component base);
super.new(name, base);
endfunction : new
task run_phase(uvm_phase phase);
phase.raise_objection(this); // tell UVM this thread started
super.run();
`uvm_info("test1: ", "Starting...", UVM_INFO);
phase.drop_objection(this); // tell UVM this thread finished
endtask
endclass : test1
// in top module
module top;
initial run_test(); // this will create a test object
// and executes its run_phase()
endmodule : top
UVM Structure
- Top
- uvm_test or program in SystemVerilog
- task run();
- uvm_env
- uvm_agent
- driver
- run
- monitor
- $monitoron / $monitoroff
- sync_reset
- semaphore
- semaphore sem = new(1);
- sem.get(1) ... sem.put(1)
- `uvm_raise_objection(this)
/ `uvm_drop_objection(this) - disable <block_name>;
- sequencer
- sequence
- body
- start
- transaction
- build
- run
- uvm_scoreboard or ovm_subscriber
- uvm_agent for coverage
- interface
- DUT
UVM Randomization and Constraints
typedef logic [15:0] addr_type;
typedef logic [7:0] data_type;
typedef enum {read, write, nop} op_type;
class my_op;
rand addr_type addr;
rand data_type data;
rand op_type cmd;
...
endclass : my_op
class read_op extends my_op;
constraint read_only_cmd {my_op == read;};
endclass // read_op
module top;
my_op op;
read_op rdop;
addr_type addr2;
initial begin
op = new();
addr2 = $random;
repeat (2) begin
assert(op.randomize());
// with constraint
assert(op.randomize() with {my_op == read;});
assert(rdop.randomize()); // this will be limited to read only
end
end
endmodule // top
Tuesday, October 11, 2016
UVM/OVM Questions.
If you are preparing for a Verification job interview or if you are trying to master this methodology for your next project, here are some of the questions that you can use to test your skills and measure yourself:
- What are some of the benefits of UVM methodology?
- What are some of the drawbacks of UVM methodology?
- Explain the concept of Transaction Level Modelling?
- What is the difference between an uvm_object and uvm_component class?
- What are TLM ports and TLM Fifos?
- What is an analysis port and analysis fifo and where are they used?
- Explain the protocol handshake between a sequencer and driver ?
- What is the difference between a sequence and sequence item?
- Is it possible to collect responses from DUT back to a sequence and if so how?
- What is the difference between SEQ_ARB_RANDOM and SEQ_ARB_STRICT_RANDOM arbitration mechanism on sequencer?
- What is the difference between grab() and lock() on sequencer?
- What is the difference between a pipelined and non-pipelined driver?
- What is the difference between early randomization and late randomization of sequences?
- Write a sample sequence code that generates a stream of ethernet packets?
- How can you specify weightage for a sequence when started on a sequencer?
- What is the difference between a monitor and a scoreboard in UVM methodology?
- What is meant by factory and what is its importance?
- What is the difference between creating an object using new() and create()?
- What are the difference phases in UVM and what is the order of their execution?
- What are objections and how are they useful?
- How can you implement a simulation timeout mechanism using UVM methodology?
- What is meant by factory override and what are different types of overriding possible with UVM factory?
- What is a virtual sequence and where do we use a virtual sequence?
Answer - What are its benefits? What is uvm_config_db and what is it used for?
- Why should any uvm component be registered with factory?
Subscribe to:
Posts (Atom)