← Design Verification Interviews
Interview Question · Concept
One C Model, Two Agents
The Question
The interviewer asks
Your C reference model keeps its state in a static global. It worked with one agent; with two agent instances the predictions are wrong for both. Why, and how do you fix it?
You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
A static global is one variable for the whole simulation, so both agents' calls update the same state. Give each instance its own state. A C model_new() returns a pointer, SystemVerilog stores it in a chandle, and every call passes it back. Add reset and free entry points too, so a mid-test reset and the end of test leave nothing stale behind.
Columns are calls in order. The AXI side expects 7 after its second packet and reads 5: the APB reset wiped its count as well.
- Allocate
Two calls to
model_newgive two structs with separate totals. The testbench keeps the two addresses inaandb. - Add through each handle
A receives 3 and then 4, B receives 2. Each call lands on the struct its handle names, so A reports 7 and B reports 2.
Follow the calls, values and waits
- call model_add(a, 3): model_add / reset / delete → Model A
- return total 7: Model A → model_add / reset / delete
- call model_add(b, 2): model_add / reset / delete → Model B
- return total 2: Model B → model_add / reset / delete
- Reset A
Reset clears A's total and keeps the struct where it is. B still holds 2, and the handles still point where they did.
Follow the calls, values and waits
- call model_reset(a): model_add / reset / delete → Model A
- Delete A
Delete returns the struct's memory. The variable
astill holds the old address, so the testbench sets it tonullat once.Follow the calls, values and waits
- call model_delete(a): model_add / reset / delete → Model A
Read the diagram as text
- chandle a: an address SystemVerilog never reads
- chandle b: a second address
- model_add / reset / delete: the handle comes first
- Model A: int total
- Model B: int total
- chandle a → Model A: points at
- chandle b → Model B: points at
- model_add / reset / delete → Model A: reads or writes
- model_add / reset / delete → Model B: reads or writes
A global would be the single struct in the middle, shared by every caller. A handle per instance keeps the two totals apart.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Mid-Level)
A good mid-level answer points at the static global as the cause. It proposes a handle for each instance, with create, reset and free calls.
What Interviewers Listen For (Senior)
A good senior answer says who owns the model's memory across resets and at the end of the test. It explains how verification shares one architecture model without copying and changing its code.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyWhat IfBreak ItCompareScale It
- One C Model, Two Agents
-
WhyWhy a Chandle and Not an IntegerL2 Mid-Level
Why store the C pointer in a
chandlerather than in alongint?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
A
chandlealways has the size of a pointer on the machine that runs the simulation. The language only lets you assign it, compare it with null and pass it to C. That stops SystemVerilog code from doing arithmetic on it or inventing values. Alongintwould work by accident on a 64-bit host and offer none of those guarantees.Self-Check
Tick each key point you covered in your answer.
Misconception
"You can read the struct fields through the
chandlein SystemVerilog."It is opaque: only C code can dereference it, through accessor functions you import.
Source IEEE 1800-2017 §6.14
-
CompareImporting C vs Exporting SystemVerilogL2 Mid-Level
Compare an import and an export. When would the C model need an export?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
An import lets SystemVerilog call C; an export lets C call a SystemVerilog function or task. The model needs an export when it must call into the testbench. For example, it can report a mismatch through the testbench's error counter, or read a configuration value. C may call an export only from inside a
contextimport call.Self-Check
Tick each key point you covered in your answer.
Misconception
"C can call an exported function from any thread at any time."
Exports may be called only while a context import is executing, so the simulator knows the scope and the time.
Source IEEE 1800-2017 §35.5.3 (context tasks and functions)
-
What IfTime Inside an Exported TaskL2 Mid-LevelL3 Senior
What if the C model needs to wait for ten clock cycles in the middle of its work?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
C itself cannot consume simulation time. Make the import a
contexttask, and have C call an exported SystemVerilog task such aswait_cycles(10), which may contain@(posedge clk). The calling SystemVerilog thread blocks until the exported task returns, while the rest of the simulation runs on.Out to C, Back into the Same InstanceArrows are calls. The request travels from the testbench into C and back into SystemVerilog; each return travels the same arrow backwards. Illustrative sequenceCallValueReturnWaiting- Call out
Instance
u0calls the import. The simulator notes which scope made the call.Follow the calls, values and waits
- call c_visit(3): u0.visit(3) → c_visit(3)
- Ask for the scope
svGetScopereturns the calling instance,tb.u0. Withoutcontexton the import, C has no such answer. - Call back in
C calls the export. It runs in
tb.u0, so it updates that instance'saccepted, on the same thread, right now.Follow the calls, values and waits
- call sv_accept(3): c_visit(3) → sv_accept(3)
- data 3: sv_accept(3) → u0.accepted
- Return twice
The export returns 3 to C, and C returns 3 to the testbench. No simulation time has passed.
Follow the calls, values and waits
- return 3: sv_accept(3) → c_visit(3)
- return 3: c_visit(3) → u0.visit(3)
Read the diagram as text
- u0.visit(3): a call from instance u0
- c_visit(3): context import
- svGetScope(): answers: tb.u0
- sv_accept(3): exported function
- u0.accepted: 0, then 3
- u0.visit(3) → c_visit(3): import call
- c_visit(3) → svGetScope(): which instance?
- c_visit(3) → sv_accept(3): export call
- sv_accept(3) → u0.accepted: accepted += 3
One thread, one chain of calls. The C function is in the middle of it, and the testbench waits for it to return.
Self-Check
Tick each key point you covered in your answer.
Misconception
"Call
usleep()in C to let ten cycles pass."That pauses the simulator process on the wall clock while simulation time stands still. Lesson D1.7 measured
time=0after such a sleep.Source Lesson D1.7 review claims (a sleep in C left the simulation at time 0 on Verilator 5.052)
- Call out
-
What IfA Python Model Behind DPIL2 Mid-LevelL3 Senior
Asked if the model is written in Python
What if the reference model is written in Python? How does it reach the testbench?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The standard defines DPI only between SystemVerilog and C. So a small C bridge starts the Python interpreter, calls the model and converts arguments and results. The bridge must catch every Python exception and turn it into a status code, because nothing may unwind into the simulator. Pass a whole packet per call, not one byte, because each call into Python is much slower than a C call.
Self-Check
Tick each key point you covered in your answer.
Misconception
"Let the Python exception propagate; the simulator will report it."
The standard gives imported routines no way to raise into SystemVerilog, so an exception crossing the boundary has undefined behaviour. The bridge must handle it.
Source IEEE 1800-2017 §35.5.1 (semantic constraints on imported routines)
-
Scale ItIntegrating an Architecture Model at Subsystem LevelL3 Senior
The architecture team owns a C++ model of the whole subsystem. How do you use it as the scoreboard's reference without forking it?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Wrap it behind a thin, versioned DPI layer owned by verification: transaction in, predicted transactions out, one handle per instance, plus reset. Feed it from monitors, never drivers, so it predicts from what the DUT actually received. Agree on where the model is untimed, such as ordering between independent streams, and compare there by key rather than by cycle.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Senior)
A good senior answer separates the shared model from the wrapper that verification owns. It says exactly where the comparison must allow differences in order.
Wrong Altitude
Copies the model into the verification repository and patches it to match the RTL.
The model then stops being independent: it quietly learns the RTL's bugs, and the architecture fixes never arrive.
-
Break ItCopying an Object That Holds a ChandleL2 Mid-Level
Asked if the model object is copied
What if a model class holds a
chandle, and someone copies the object withnew thisor acopy()method?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The copy gets the same address, so both objects drive one C model. An update through either is seen by both. If the copy needs its own state, call a C clone function that allocates a new struct. Then decide which object deletes which model.
Self-Check
Tick each key point you covered in your answer.
Misconception
"The copied object now has its own C model."
A shallow copy copies field values, and a chandle's value is an address. The twin adds 100 through the copy and the original shows 105.
Run It
A model object with a C accumulator, copied after adding 5.
RUNVerilator + C/C++ over DPI · simulator serviceExpected:a=105 b=105FAIL: the copy shares one C model, because copying a chandle copies only the addressSee the Fix
module tb; import "DPI-C" function chandle acc_new(); import "DPI-C" function chandle acc_clone(input chandle h); import "DPI-C" function int acc_add(input chandle h, input int v); class model; chandle h; function new(); h = acc_new(); endfunction function model copy(); model c = new this; // a shallow copy of every field c.h = acc_clone(h); // the fix: the copy gets its own C state return c; endfunction endclass model a = new, b; initial begin void'(acc_add(a.h, 5)); b = a.copy(); void'(acc_add(b.h, 100)); $display("a=%0d b=%0d", acc_add(a.h, 0), acc_add(b.h, 0)); if (acc_add(a.h, 0) != 5) $display("FAIL: the copy shares one C model, because copying a chandle copies only the address"); else $display("PASS: each object owns its own C state"); $finish; end endmodulePrints:
a=5 b=105PASS: each object owns its own C state -
CompareWhy a Chandle and Not an IntegerL2 Mid-Level
Why store the C pointer in a
chandlerather than in alongint?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
A
chandlealways has the size of a pointer on the machine that runs the simulation. The language only lets you assign it, compare it with null and pass it to C. That stops SystemVerilog code from doing arithmetic on it or inventing values. Alongintwould work by accident on a 64-bit host and offer none of those guarantees.Self-Check
Tick each key point you covered in your answer.
Misconception
"You can read the struct fields through the
chandlein SystemVerilog."It is opaque: only C code can dereference it, through accessor functions you import.
Source IEEE 1800-2017 §6.14
What People Get Wrong
Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.
Misconception
"Each SystemVerilog object that calls the model gets its own copy of the C code's state."
C knows nothing about the calling object. The twin's two models share one counter until each holds its own handle.
Run It
Two port_model objects call a C accumulator that keeps a static total.
a=7 b=7 FAIL: the static C counter is one variable shared by every model instanceSee the Fix
module tb;
import "DPI-C" function chandle acc_new();
import "DPI-C" function void acc_add(input chandle h, input int v);
import "DPI-C" function int acc_total(input chandle h);
class port_model;
chandle h; // the fix: each model owns its C state
function new(); h = acc_new(); endfunction
function void add(int v); acc_add(h, v); endfunction
function int total(); return acc_total(h); endfunction
endclass
port_model a = new, b = new;
initial begin
a.add(3); b.add(4);
$display("a=%0d b=%0d", a.total(), b.total());
if (a.total() == 3 && b.total() == 4) $display("PASS: each model owns its state behind its own chandle");
else $display("FAIL: the static C counter is one variable shared by every model instance");
$finish;
end
endmodule
Prints: a=3 b=4 PASS: each model owns its state behind its own chandle
Misconception
"Declare the model functions pure so the simulator knows they are safe."
A model with state is the opposite of pure. The simulator may then drop or reuse calls, and the model misses updates.
Source IEEE 1800-2017 §35.5.2 (pure functions)
Missed Corner
Resets the SystemVerilog agent on a mid-test reset, but not the C model.
The model still holds transactions from before the reset and predicts responses the DUT has correctly discarded.
Source Lesson D1.6 example (a reset entry point restores the model's state)
Wrong Altitude
"Rewrite the model in SystemVerilog and avoid DPI."
That throws away the architecture team's checked model and creates a second model that must always match the first. The fix is a handle per instance, not a rewrite.