UVM & Advanced Verification – VLSI Company Focus
📌 Question 76: UVM Factory Override Scope
class base_driver extends uvm_driver#(base_transaction);
`uvm_component_utils(base_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class ext_driver extends base_driver;
`uvm_component_utils(ext_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class my_test extends uvm_test;
`uvm_component_utils(my_test)
function void build_phase(uvm_phase phase);
// Type override
base_driver::type_id::set_type_override(ext_driver::get_type());
// Instance override
set_inst_override_by_type("env.agent1.*",
base_driver::get_type(), ext_driver::get_type());
endfunction
endclass
Question: Which agents will use ext_driver?
Answer:
- All agents use ext_driver (type override is global)
- Instance override has no effect (type override takes precedence)
Explanation:
- Type override affects all instances globally
- Applied first, affects entire hierarchy
- Instance override only affects specific paths
- Type override already changed the type, so instance override sees ext_driver
- Order matters:Â Last override wins
- Most specific (instance) should be done after type override
- Common interview trap at Intel, NVIDIA
📌 Question 77: UVM Config DB Get Timing
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
int num_drivers;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(int)::get(this, "", "num_drivers", num_drivers)) begin
`uvm_info("AGENT", "Using default num_drivers = 1", UVM_LOW)
num_drivers = 1;
end
// Create drivers based on num_drivers
endfunction
endclass
class my_test extends uvm_test;
my_agent agent;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
// Set config AFTER creating agent - will it work?
uvm_config_db#(int)::set(this, "agent", "num_drivers", 4);
endfunction
endclass
Question: Will agent get num_drivers = 4?
Answer: NO! Agent gets default value 1
Explanation:
- config_db::set must happen BEFORE component creation
- create() calls build_phase immediately
- Agent’s build_phase runs before the set
- Correct order:
uvm_config_db#(int)::set(this, "agent", "num_drivers", 4);
agent = my_agent::type_id::create("agent", this);
- Common mistake in Qualcomm, Broadcom interviews
- Hierarchy matters:Â Set from parent before creating child
📌 Question 78: Sequence Item Race Condition
class my_sequence extends uvm_sequence#(my_transaction);
`uvm_object_utils(my_sequence)
task body();
my_transaction req;
req = my_transaction::type_id::create("req");
start_item(req);
assert(req.randomize() with {addr < 100;});
finish_item(req);
// Use req again - PROBLEM!
start_item(req);
assert(req.randomize() with {addr >= 100;});
finish_item(req);
endtask
endclass
Question: What’s wrong with reusing req?
Answer: Race condition – req is modified by driver!
Explanation:
- After finish_item(), driver gets req handle
- Driver may modify req (set status, response, etc.)
- Reusing same handle creates race:
- Sequence modifies req
- Driver might still be processing previous req
- Correct approach:
req = my_transaction::type_id::create("req");
start_item(req);
// ...
finish_item(req);
req = my_transaction::type_id::create("req"); // NEW object
start_item(req);
// ...
- Asked at AMD, Marvell
📌 Question 79: Virtual Sequence Hierarchy
class base_vseq extends uvm_sequence#(uvm_sequence_item);
`uvm_object_utils(base_vseq)
my_sequencer seqr1, seqr2;
task body();
// How to get sequencer handles?
// p_sequencer is uvm_sequencer#(uvm_sequence_item)!
endtask
endclass
Question: How to access specific sequencers in virtual sequence?
Answer: Use config_DB or declare typed p_sequencer
Explanation:
Method 1: Config DB
task body();
if (!uvm_config_db#(my_sequencer)::get(null, "", "seqr1", seqr1))
`uvm_fatal("VSEQ", "Cannot get seqr1")
// Now use seqr1
endtask
Method 2: Typed p_sequencer (Better)
class my_virtual_sequencer extends uvm_sequencer#(uvm_sequence_item);
my_sequencer seqr1, seqr2;
`uvm_component_utils(my_virtual_sequencer)
endclass
class base_vseq extends uvm_sequence#(uvm_sequence_item);
`uvm_object_utils(base_vseq)
`uvm_declare_p_sequencer(my_virtual_sequencer)
task body();
// Now p_sequencer is typed!
my_seq seq = my_seq::type_id::create("seq");
seq.start(p_sequencer.seqr1);
endtask
endclass
- Critical for Synopsys, Cadence interviews
📌 Question 80: TLM Analysis Port Fanout
class my_monitor extends uvm_monitor;
uvm_analysis_port#(my_transaction) ap;
task run_phase(uvm_phase phase);
my_transaction tr;
forever begin
// Collect transaction
tr = my_transaction::type_id::create("tr");
collect_transaction(tr);
ap.write(tr); // Broadcast
end
endtask
endclass
class subscriber1 extends uvm_subscriber#(my_transaction);
function void write(my_transaction t);
t.data = 100; // MODIFY transaction!
endfunction
endclass
class subscriber2 extends uvm_subscriber#(my_transaction);
function void write(my_transaction t);
`uvm_info("SUB2", $sformatf("data = %0d", t.data), UVM_LOW)
endfunction
endclass
Question: What does subscriber2 see?
Answer: data = 100 (modified value!)
Explanation:
- Analysis port broadcasts SAME handle to all subscribers
- All subscribers get reference to same object
- subscriber1 modifies shared object
- subscriber2 sees modified value
- Calling order not guaranteed (could see 100 or original)
- Solution:Â Clone transaction before writing
my_transaction tr_clone;
$cast(tr_clone, tr.clone());
ap.write(tr_clone);
- Common bug in Apple, Google verification
📌 Question 81: Sequence Priority and Arbitration
class my_sequencer extends uvm_sequencer#(my_transaction);
`uvm_component_utils(my_sequencer)
endclass
class my_test extends uvm_test;
task run_phase(uvm_phase phase);
phase.raise_objection(this);
fork
begin
seq1.start(seqr, null, 100); // Priority 100
end
begin
seq2.start(seqr, null, 200); // Priority 200
end
begin
seq3.start(seqr, null, 100); // Priority 100
end
join
phase.drop_objection(this);
endtask
endclass
Question: Which sequence gets serviced first?
Answer: seq2 (highest priority 200)
Explanation:
- Sequencer arbitrates by priority
- Higher number = higher priority
- seq2 (200) > seq1,seq3 (100)
- Among equal priorities (seq1, seq3):Â FIFO order
- seq1 started first, so seq1 before seq3
- Execution order: seq2 → seq1 → seq3
- Default priority = 100
- Asked at Texas Instruments, NXP
📌 Question 82: Phase Jump and Objections
class my_test extends uvm_test;
task main_phase(uvm_phase phase);
phase.raise_objection(this);
#100;
phase.drop_objection(this);
endtask
task shutdown_phase(uvm_phase phase);
phase.raise_objection(this);
#50;
phase.drop_objection(this);
endtask
endclass
class my_env extends uvm_env;
task main_phase(uvm_phase phase);
phase.raise_objection(this);
#200; // Takes longer than test!
phase.drop_objection(this);
endtask
endclass
Question: When does main_phase end?
Answer: After 200ns (waits for env to finish)
Explanation:
- Phase ends when ALL objections dropped
- test drops at 100ns
- env still has objection until 200ns
- Phase waits for env to finish
- Hierarchical objection counting
- All components must drop before phase advances
- Common issue at Xilinx, Altera/Intel
📌 Question 83: Callback Execution Order
class driver_cb extends uvm_callback;
virtual task pre_send(my_driver drv, my_transaction tr);
`uvm_info("CB", "Callback executed", UVM_LOW)
endtask
endclass
class my_driver extends uvm_driver#(my_transaction);
`uvm_register_cb(my_driver, driver_cb)
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
`uvm_do_callbacks(my_driver, driver_cb, pre_send(this, req))
drive_transaction(req);
seq_item_port.item_done();
end
endtask
endclass
// Add callbacks in test
driver_cb cb1 = new();
driver_cb cb2 = new();
uvm_callbacks#(my_driver, driver_cb)::add(drv, cb1);
uvm_callbacks#(my_driver, driver_cb)::add(drv, cb2);
Question: Which callback executes first?
Answer: cb1 executes first (FIFO order)
Explanation:
- Callbacks execute in order added
- cb1 added first → executes first
- FIFO queue of callbacks
- Can useÂ
add_by_name for different ordering delete to remove callbacks- Asked at Arm, Samsung
📌 Question 84: Packed vs Unpacked Array Randomization
class my_transaction extends uvm_sequence_item;
rand bit [7:0] packed_arr [4]; // Unpacked array of packed
rand bit unpacked_arr [4][7:0]; // Unpacked only
`uvm_object_utils_begin(my_transaction)
`uvm_field_sarray_int(packed_arr, UVM_DEFAULT)
// unpacked_arr - NO FIELD MACRO!
`uvm_object_utils_end
endclass
Question: What gets randomized?
Answer: Only packed_arr gets randomized properly
Explanation:
- rand keyword works on both
- Field macros only support packed
- packed_arr: Works for copy/compare/print/randomize
- unpacked_arr: Randomizes but no copy/compare/print support
- Limitation:Â Field macros don’t support 2D unpacked
- Workaround:Â Custom do_copy, do_compare
function void do_copy(uvm_object rhs);
my_transaction rhs_;
$cast(rhs_, rhs);
foreach(unpacked_arr[i,j])
unpacked_arr[i][j] = rhs_.unpacked_arr[i][j];
endfunction
- Important for Nvidia, Intel verification
📌 Question 85: UVM Resource DB vs Config DB
class my_test extends uvm_test;
function void build_phase(uvm_phase phase);
// Using config_db
uvm_config_db#(int)::set(this, "*", "timeout", 1000);
// Using resource_db
uvm_resource_db#(int)::set("*", "timeout", 2000);
// Which one wins?
endfunction
endclass
class my_component extends uvm_component;
int timeout;
function void build_phase(uvm_phase phase);
if (!uvm_config_db#(int)::get(this, "", "timeout", timeout))
`uvm_error("COMP", "Cannot get timeout")
endfunction
endclass
Question: What value does component get?
Answer: timeout = 1000 (config_db wins)
Explanation:
- config_db has higher priority than resource_db
- config_db::get searches:
- config_db first
- resource_db second (if not found)
- Here config_db has entry → returns 1000
- Best practice:Â Use config_db consistently
- resource_db is lower level, config_db built on top
- Mixing both can cause confusion
- Asked at Synopsys, Mentor/Siemens
📌 Question 86: Sequence Lock/Unlock
class my_sequence extends uvm_sequence#(my_transaction);
task body();
lock(m_sequencer);
repeat(5) begin
`uvm_do(req)
end
unlock(m_sequencer);
endtask
endclass
// Two instances run in parallel
fork
seq1.start(seqr);
seq2.start(seqr);
join
Question: How do sequences execute?
Answer: seq1 runs 5 transactions, THEN seq2 runs
Explanation:
- lock() grants exclusive access to sequencer
- seq1 locks sequencer
- seq2 waits at lock() call
- seq1 executes all 5 transactions
- seq1 unlocks
- seq2 gets lock and executes
- Serializes access – useful for atomic operations
- grab()Â is similar but with priority
- Important for Qualcomm, Broadcom protocols
📌 Question 87: Field Macro Flags Impact
class my_transaction extends uvm_sequence_item;
rand bit [7:0] addr;
rand bit [31:0] data;
bit [7:0] status; // Not rand
`uvm_object_utils_begin(my_transaction)
`uvm_field_int(addr, UVM_DEFAULT)
`uvm_field_int(data, UVM_DEFAULT | UVM_NOCOMPARE)
`uvm_field_int(status, UVM_DEFAULT | UVM_NOPACK)
`uvm_object_utils_end
endclass
my_transaction tr1, tr2;
tr1.addr = 10; tr1.data = 100; tr1.status = 5;
tr2.addr = 10; tr2.data = 200; tr2.status = 5;
if (tr1.compare(tr2))
$display("Match");
Question: Do they compare as equal?
Answer: YES – Match!
Explanation:
- UVM_NOCOMPARE excludes data from comparison
- compare() checks: addr and status only
- addr: 10 == 10 IGNORED (UVM_NOCOMPARE)
- status: 5 == 5 âś“
- Result:Â Match
- Other flags:
- UVM_NOPRINT – exclude from print
- UVM_NOCOPY – exclude from copy
- UVM_NOPACK – exclude from pack/unpack
- Asked at Apple, Amazon
📌 Question 88: Virtual Interface Assignment Timing
interface my_if(input logic clk);
logic [7:0] data;
logic valid;
endinterface
module top;
logic clk;
my_if if1(clk), if2(clk);
initial begin
uvm_config_db#(virtual my_if)::set(null, "*", "vif", if1);
run_test();
end
endmodule
class my_driver extends uvm_driver#(my_transaction);
virtual my_if vif;
function void build_phase(uvm_phase phase);
if (!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
`uvm_fatal("DRV", "Cannot get vif")
endfunction
function void connect_phase(uvm_phase phase);
// Can we reassign vif here?
uvm_config_db#(virtual my_if)::get(this, "", "vif", vif);
endfunction
endclass
Question: Can vif change between build and connect phase?
Answer: YES – if config_db updated in between!
Explanation:
- Virtual interface is handle/reference
- Can be reassigned anytime
- If another component does:
function void build_phase(uvm_phase phase);
uvm_config_db#(virtual my_if)::set(null, "*", "vif", if2);
endfunction
- Later components see new value
- Last set wins in config_db
- Best practice:Â Set once in top, before run_test()
- Common pitfall at Marvell, Microchip
📌 Question 89: Scoreboard Analysis Export Connection
class my_scoreboard extends uvm_scoreboard;
uvm_analysis_export#(my_transaction) actual_export;
uvm_analysis_export#(my_transaction) expect_export;
`uvm_component_utils(my_scoreboard)
function void build_phase(uvm_phase phase);
actual_export = new("actual_export", this);
expect_export = new("expect_export", this);
endfunction
// How to implement write()?
endclass
Question: How to implement write() for exports?
Answer: Use analysis imp or analysis fifo
Explanation:
Method 1: Use TLM FIFOs
uvm_tlm_analysis_fifo#(my_transaction) actual_fifo, expect_fifo;
function void build_phase(uvm_phase phase);
actual_fifo = new("actual_fifo", this);
expect_fifo = new("expect_fifo", this);
actual_export = new("actual_export", this);
expect_export = new("expect_export", this);
endfunction
function void connect_phase(uvm_phase phase);
actual_export.connect(actual_fifo.analysis_export);
expect_export.connect(expect_fifo.analysis_export);
endfunction
task run_phase(uvm_phase phase);
forever begin
actual_fifo.get(actual_tr);
expect_fifo.get(expect_tr);
compare(actual_tr, expect_tr);
end
endtask
Method 2: Use imp with macros
`uvm_analysis_imp_decl(_actual)
`uvm_analysis_imp_decl(_expect)
uvm_analysis_imp_actual#(my_transaction, my_scoreboard) actual_imp;
uvm_analysis_imp_expect#(my_transaction, my_scoreboard) expect_imp;
function void write_actual(my_transaction t);
// Handle actual transaction
endfunction
function void write_expect(my_transaction t);
// Handle expected transaction
endfunction
- Critical for verification engineer roles
📌 Question 90: Randomization with Inside Operator
class my_transaction extends uvm_sequence_item;
rand bit [7:0] addr;
rand bit [3:0] cmd;
constraint c1 {
addr inside {[0:10], [20:30], 100};
}
constraint c2 {
!(cmd inside {4'h0, 4'hF});
}
endclass
Question: What values can addr and cmd have?
Answer:
- addr: 0-10, 20-30, or exactly 100
- cmd: 1-14 (all except 0 and 15)
Explanation:
inside with ranges: [0:10] means 0,1,2…10- Multiple ranges: union of all ranges
- Single value: exactly that value
!(inside): negation excludes those values- cmd can be: 1,2,3,4,5,6,7,8,9,10,11,12,13,14
- More efficient than individual constraints
- Common at Intel, AMD interviews
📌 Question 91: UVM Report Catcher
class my_catcher extends uvm_report_catcher;
function action_e catch();
if (get_severity() == UVM_ERROR &&
get_id() == "TIMEOUT") begin
set_severity(UVM_WARNING);
return CAUGHT;
end
return THROW;
endfunction
endclass
class my_test extends uvm_test;
function void build_phase(uvm_phase phase);
my_catcher catcher = new();
uvm_report_cb::add(null, catcher); // Global
endfunction
task run_phase(uvm_phase phase);
`uvm_error("TIMEOUT", "Operation timed out")
`uvm_error("CONFIG", "Configuration error")
endtask
endclass
Question: What happens to the errors?
Answer:
- TIMEOUT: Downgraded to WARNING
- CONFIG: Remains ERROR
Explanation:
- Report catcher intercepts messages
- Can modify: severity, verbosity, action
- TIMEOUT error caught → changed to WARNING → CAUGHT
- CONFIG error → no match → THROW (passes through)
- CAUGHT:Â Message handled, don’t propagate
- THROW:Â Pass to next catcher or default handler
- Useful for known issues or debug control
- Asked at Synopsys, Cadence
📌 Question 92: Constraint Solver Iteration Order
class my_packet extends uvm_sequence_item;
rand bit [7:0] len;
rand bit [7:0] data[];
rand bit [7:0] checksum;
constraint c_size {
len inside {[1:10]};
data.size() == len;
}
constraint c_checksum {
checksum == calculate_checksum(data);
}
function bit [7:0] calculate_checksum(bit [7:0] arr[]);
// Sum all data bytes
endfunction
endclass
Question: Will this constraint work?
Answer: NO – Solver cannot call function!
Explanation:
- Constraints must be equations, not function calls
- Solver can’t execute calculate_checksum() during randomization
- Solution: Use post_randomize()
constraint c_size {
len inside {[1:10]};
data.size() == len;
}
function void post_randomize();
checksum = calculate_checksum(data);
endfunction
- Constraints:Â Mathematical relationships only
- Functions:Â Procedural code, not constraint-solvable
- Common mistake at Qualcomm, Broadcom
📌 Question 93: Sequence Response Handling
class my_driver extends uvm_driver#(my_transaction);
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive_bus(req);
// Create response
rsp = my_transaction::type_id::create("rsp");
rsp.set_id_info(req); // Link to request
rsp.status = get_bus_status();
seq_item_port.item_done(rsp);
end
endtask
endclass
class my_sequence extends uvm_sequence#(my_transaction);
task body();
`uvm_do_with(req, {addr == 100;})
// How to get response?
get_response(rsp);
`uvm_info("SEQ", $sformatf("Status = %0d", rsp.status), UVM_LOW)
endtask
endclass
Question: Is get_response() needed?
Answer: YES – to receive driver response!
Explanation:
- `uvm_do macro does NOT get response automatically
- Must explicitly callÂ
get_response(rsp) - Blocking call – waits for driver to send response
- Alternative:Â UseÂ
uvm_do_with_response (custom macro) - Response queue in sequence
- Common bug: Forgetting get_response → hangs!
`uvm_do_with(req, {addr == 100;})
get_response(rsp);
- Or use item_done() without response if not needed
- Asked at Nvidia, ARM
📌 Question 94: Plusargs vs Config DB
module top;
int timeout;
initial begin
// Method 1: Plusargs
if ($value$plusargs("timeout=%0d", timeout))
$display("Got timeout from plusargs: %0d", timeout);
// Method 2: Config DB
uvm_config_db#(int)::set(null, "*", "timeout", timeout);
run_test();
end
endmodule
class my_test extends uvm_test;
int timeout = 1000; // Default
function void build_phase(uvm_phase phase);
void'(uvm_config_db#(int)::get(this, "", "timeout", timeout));
`uvm_info("TEST", $sformatf("Timeout = %0d", timeout), UVM_LOW)
endfunction
endclass
Question: Run with +timeout=5000. What’s the result?
Answer: timeout = 5000
Explanation:
- Plusargs:Â Command-line arguments (+name=value)
- Parsed in initial block before UVM starts
- Value stored in timeout variable
- Config_db::set uses that value
- Test gets 5000 from config_db
- Flow: Plusargs → Variable → Config DB → Component
- Best practice:Â Parse plusargs in top, push to config_db
- Common pattern at all VLSI companies
📌 Question 95: Phase Domain Jumping
class my_test extends uvm_test;
task main_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info("TEST", "In main_phase", UVM_LOW)
phase.drop_objection(this);
endtask
task shutdown_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info("TEST", "In shutdown_phase", UVM_LOW)
// Jump back to reset phase!
phase.jump(uvm_reset_phase::get());
phase.drop_objection(this);
endtask
endclass
Question: What happens after jump?
Answer: Simulation goes back to reset_phase!
Explanation:
- phase.jump()Â restarts from specified phase
- All subsequent phases re-execute
- Useful for restarting DUT mid-simulation
- Dangerous:Â Can create infinite loops
- Must have exit condition
static int jump_count = 0;
if (jump_count < 3) begin
jump_count++;
phase.jump(uvm_reset_phase::get());
end
- Rarely used in practice
- More common in emulation/acceleration environments
- Asked at Cadence, Synopsys for advanced roles
📌 Question 96: Coverage Bin Overflow
bit [2:0] addr;
covergroup cg @(posedge clk);
cp_addr: coverpoint addr {
bins low = {[0:3]};
bins high = {[4:7]};
}
endcovergroup
cg cg_inst = new();
initial begin
addr = 0; @(posedge clk);
addr = 5; @(posedge clk);
addr = 8; @(posedge clk); // Out of range!
addr = 2; @(posedge clk);
end
Question: What happens with addr=8?
Answer: Ignored – out of bit range!
Explanation:
- addr is bit [2:0]: max value = 7
- addr = 8 wraps to 0 (3-bit overflow)
- Coverage sees: 0, 5, 0, 2
- Both bins hit: low{0,2}, high{5}
- No error for overflow in RTL
- Coverage samples actual value (0, not 8)
- Be careful with bit widths!
- Common at Intel, TI interviews
📌 Question 97: Parameterized Transaction
class my_transaction#(int ADDR_WIDTH = 32,
type DATA_TYPE = bit [31:0])
extends uvm_sequence_item;
rand bit [ADDR_WIDTH-1:0] addr;
rand DATA_TYPE data;
`uvm_object_param_utils(my_transaction#(ADDR_WIDTH, DATA_TYPE))
function new(string name = "");
super.new(name);
endfunction
endclass
// Use different specializations
typedef my_transaction#(16, bit [15:0]) narrow_transaction;
typedef my_transaction#(64, bit [63:0]) wide_transaction;
narrow_transaction n_tr;
wide_transaction w_tr;
Question: Can we assign n_tr to w_tr?
Answer: NO – Different types!
Explanation:
- Each specialization creates a new type
- narrow_transaction ≠wide_transaction
- Different addr widths and data types
- No implicit conversion between them
- Factory sees them as completely different types
- Type safety enforced by SystemVerilog
- Must use correct type throughout hierarchy
w_tr = n_tr; // ERROR: Type mismatch
- Important for generic verification IPs
- Asked at verification IP developer roles
📌 Question 98: Multiple TLM Get/Put Ports
class my_driver extends uvm_driver#(my_transaction);
uvm_get_port#(my_transaction) input_port;
uvm_put_port#(my_transaction) output_port;
task run_phase(uvm_phase phase);
my_transaction tr;
forever begin
input_port.get(tr);
process_transaction(tr);
output_port.put(tr);
end
endtask
endclass
class my_env extends uvm_env;
my_driver drv;
uvm_tlm_fifo#(my_transaction) input_fifo, output_fifo;
function void connect_phase(uvm_phase phase);
drv.input_port.connect(input_fifo.get_export);
drv.output_port.connect(output_fifo.put_export);
endfunction
endclass
Question: What if both FIFOs are full/empty?
Answer:
- input_fifo empty:Â get() blocks
- output_fifo full:Â put() blocks
Explanation:
- Blocking TLMÂ – get/put wait until ready
- get() blocks until data available
- put() blocks until space available
- Can cause deadlock if not careful!
- Solution:Â Use try_get/try_put or proper sizing
if (input_port.try_get(tr))
process_transaction(tr);
- Or size FIFOs appropriately
- Common issue at Verification Service Companies
📌 Question 99: Register Model Integration
class my_reg extends uvm_reg;
rand uvm_reg_field status;
rand uvm_reg_field control;
function void build();
status = uvm_reg_field::type_id::create("status");
status.configure(this, 8, 0, "RO", 0, 8'h00, 1, 1, 0);
control = uvm_reg_field::type_id::create("control");
control.configure(this, 8, 8, "RW", 0, 8'hFF, 1, 1, 1);
endfunction
endclass
// In test
my_reg reg_inst;
uvm_status_e status;
bit [7:0] value;
reg_inst.control.write(status, 8'h55);
reg_inst.control.read(status, value);
Question: What is value after read?
Answer: value = 8’h55 (if no errors)
Explanation:
- Register model abstracts register access
- write() updates register and mirror value
- read() reads from DUT (or mirror)
- status field is RO (Read-Only) – can’t write
- control field is RW – can read/write
- Access modes:
- RO: Read Only
- WO: Write Only
- RW: Read Write
- RC: Read Clear
- WC: Write Clear
- W1C: Write 1 to Clear
- Essential for Register Verification roles
- Asked at ARM, Qualcomm
📌 Question 100: Heartbeat Mechanism
class my_env extends uvm_env;
uvm_heartbeat hb;
uvm_event hb_event;
function void build_phase(uvm_phase phase);
hb_event = new("hb_event");
hb = new("hb", this, hb_event);
endfunction
task run_phase(uvm_phase phase);
hb.set_mode(UVM_ALL_ACTIVE);
hb.start(hb_event);
endtask
endclass
class my_driver extends uvm_driver#(my_transaction);
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive_transaction(req);
// Trigger heartbeat every transaction
// How to access hb_event?
seq_item_port.item_done();
end
endtask
endclass
Question: How does driver access hb_event?
Answer: Must get from config_db or event pool!
Explanation:
Method 1: Config DB
class my_env extends uvm_env;
function void build_phase(uvm_phase phase);
hb_event = new("hb_event");
uvm_config_db#(uvm_event)::set(this, "*", "hb_event", hb_event);
endfunction
endclass
class my_driver extends uvm_driver#(my_transaction);
uvm_event hb_event;
function void build_phase(uvm_phase phase);
if (!uvm_config_db#(uvm_event)::get(this, "", "hb_event", hb_event))
`uvm_fatal("DRV", "Cannot get hb_event")
endfunction
task run_phase(uvm_phase phase);
hb_event.trigger();
endtask
endclass
Method 2: Event pool (Better)
uvm_event hb_event = uvm_event_pool::get_global("heartbeat");
hb_event.trigger();
- Heartbeat:Â Watchdog for liveness detection
- Ensures components are active
- Asked at AMD, Marvell for complex testbenches
Summary Statistics – Part 4
Total Questions in Part 4: 25
Grand Total: 100 Questions! 🎉
UVM & Advanced Topics Covered:
- âś… UVM factory overrides (type vs instance)
- âś… Config DB timing and hierarchy
- âś… Sequence item handling and reuse
- âś… Virtual sequences and typed p_sequencer
- âś… TLM analysis ports and fanout
- âś… Sequence arbitration and priority
- âś… Phase objections and jumping
- âś… Callbacks and execution order
- âś… Field macros and flags
- âś… Virtual interface timing
- âś… Scoreboard implementation patterns
- âś… Constraint limitations
- âś… Response handling in sequences
- âś… Plusargs integration
- âś… Coverage edge cases
- âś… Parameterized transactions
- âś… TLM get/put blocking behavior
- âś… Register models
- âś… Heartbeat mechanisms
- âś… Report catchers
🏢 VLSI Company Focus Areas
Intel / AMD / Nvidia (CPU/GPU Verification):
- Factory overrides and polymorphism
- Complex sequence hierarchies
- Register models for control/status
- Coverage-driven verification
- Assertion-based verification
Qualcomm / Broadcom (Communication SoCs):
- Protocol-specific sequences
- Layered sequences and virtual sequences
- TLM-based communication
- Constrained-random verification
- Power-aware verification
ARM / Apple (Processor IP):
- Parameterized VIPs
- Register abstraction layers
- Functional coverage closure
- Temporal assertions
- Low-power verification
Synopsys / Cadence / Mentor (EDA Tools/VIP):
- Generic, reusable components
- UVM best practices
- Factory patterns extensively
- Configurability
- Advanced UVM features
Verification Service Companies:
- Clean coding practices
- Well-structured environments
- Proper phase usage
- TLM connectivity
- Comprehensive coverage
Master-Level UVM Takeaways
- Factory:Â Type overrides are global, instance are specific
- Config DB:Â Set before component creation
- Sequence items:Â Create new object for each transaction
- Virtual sequences:Â Use typed p_sequencer or config_db
- Analysis ports:Â Broadcast same handle – clone if needed
- Priorities:Â Higher number = higher priority (200 > 100)
- Objections:Â Hierarchical – all must drop
- Callbacks:Â FIFO order, can modify behavior
- Field macros:Â Control copy/compare/print/pack
- Resources:Â config_db has priority over resource_db
Interview Success Strategy
For UVM Questions:
- Understand phases – Build before connect, objection management
- Know factory – Type vs instance overrides
- Master config_db – Timing, hierarchy, wildcards
- TLM expertise – Ports, exports, imps, FIFOs
- Sequence control – Lock, grab, priority, responses
- Coverage goals – Functional coverage, assertions
- Register models – Abstraction, access policies
- Debug skills – Report catchers, verbosity, logging
Common Pitfalls to Avoid:
- ❌ Setting config_db after component creation
- ❌ Reusing sequence items without creating new
- ❌ Forgetting get_response() for driver responses
- ❌ Not checking randomize() return value
- ❌ Mixing resource_db and config_db
- ❌ Using procedural code in constraints
- ❌ Forgetting to raise/drop objections
- ❌ Not cloning transactions before analysis broadcast
Part 4 completes our comprehensive collection with 100 expert-level questions covering all aspects tested by top VLSI companies worldwide!