← Design Verification Interviews

Interview Question · Concept

Making a C Model Wait for the Design

L2 Mid-LevelL3 Seniordpitiming

The Question

The interviewer asks

Your C model must wait until the DUT raises ready before it sends the next item. How do you do that with DPI, and what are the rules?

Reveal the Model Answer

C itself cannot let simulation time pass. The simple way is to let SystemVerilog wait for ready, then call C, which stays untimed. The standard also allows a context import task whose C calls an exported task that waits. That thread then sleeps inside the export while the rest of the simulation runs. Verilator 5.052 rejects timing controls in exported tasks, so there you must use the first way.

A context task import waiting inside an exported task (standard semantics)
012345clkreadycalling threadin Cin exportin Cdoneother threadswaitrunwaitrunC calls sv_wait_readyexport returns

Drawn from IEEE 1800-2017 §35.8, not run: Verilator 5.052 rejects the timed export.

The standard pattern. The exported task holds the wait; C checks its result for a disable.
// SystemVerilog side
import "DPI-C" context task c_run_model();     // must be a context task
export "DPI-C" task sv_wait_ready;              // an exported task may wait
task sv_wait_ready();
  @(posedge clk iff ready);
endtask

// C side: the task's int result reports a disable (IEEE 1800-2017 §35.9)
extern "C" int c_run_model() {
  if (sv_wait_ready()) { svAckDisabledState(); return 1; }   // the thread was killed
  /* ... send the next item ... */
  return 0;
}

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Mid-Level)

Puts the wait in SystemVerilog first, and knows both sides must be tasks when C waits.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfBreak ItCompare

  1. Making a C Model Wait for the Design
  2. WhyWhy Both Sides Must Be TasksL2 Mid-Level

    Why must both the import and the export be tasks when C needs to wait?

    Reveal the Model Answer

    The wait itself, such as @(posedge clk), can only live in a task, because functions may not contain timing controls. A function cannot call a task. So the chain from SystemVerilog through C and back must be task, task, task. The import must also be context, because it calls an export.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Make the export a function with a #10 inside."

    Functions may not contain delays or event controls in SystemVerilog. The compiler rejects it before DPI is involved.

    Source IEEE 1800-2017 §13.4

  3. What IfA Thread Killed While C WaitsL3 Senior

    Asked if they mention a timeout or disable fork

    What if the test runs disable fork on the thread while C is waiting inside the exported task?

    Reveal the Model Answer

    The exported task returns 1 to C instead of 0, which means the thread was disabled. C must stop at once, free what it holds and call svAckDisabledState. Then the C task returns 1 to the simulator. C must not call any more exports in that state.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "C never sees the disable; the thread just stops."

    The C frames are still on the stack and must unwind. The non-zero return is how the simulator tells C to clean up and leave.

    Source IEEE 1800-2017 §35.9

  4. Break ItIgnoring the Disable ResultL3 Senior

    Break it: the C code ignores the result of sv_wait_ready() and goes on to send the next item. What goes wrong?

    Reveal the Model Answer

    C carries on as if the wait finished. It may call more exports for a thread that no longer exists, which the standard does not allow. Buffers it allocated for the item are never freed. The test can end with the model one item ahead of the testbench.

    Self-Check

    Tick each key point you covered in your answer.

    Spec Misquote

    "Return 0 anyway; the simulator does not check."

    A disabled call chain must report the disable with a return of 1 after the acknowledgement. Returning 0 breaks that protocol.

    Source IEEE 1800-2017 §35.9 (disable protocol)

  5. CompareTimed C Models Compared with Untimed OnesL3 Senior

    Compare a C model that waits through exported tasks with an untimed model that SystemVerilog calls once per transaction.

    Reveal the Model Answer

    An untimed model is a pure prediction step. It is portable, easy to test alone, and the testbench decides when to call it. A timed model owns its own sequence, which suits legacy C test programs. But it needs context task imports, careful disable handling and reentrant C code. Choose the untimed model unless existing C already drives the flow.

    Self-Check

    Tick each key point you covered in your answer.

    What Interviewers Listen For (Senior)

    Prefers the untimed model and names reentrancy and portability as the costs of the timed one.

    Buzzword Without Mechanism

    "A timed model is more accurate, so it is always better."

    Accuracy comes from the algorithm, not from where the wait sits. Timing in the model also ties it to the bench and to tool support.

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"C can poll ready through an exported function until it rises."

No simulation time passes while C runs. So the value C reads can never change during that call. The twin polls a million times and sees 0 every time.

Run It

C polls ready through an export. The design raises it at t=20.

RUNVerilator + C/C++ over DPI · simulator service
Edit the code, then run it
Expected: t=1 polls=-1 FAIL: ready never rose inside the C call, because no simulation time passes there
See the Fix
`timescale 1ns/1ps
module tb;
  bit ready = 0;
  initial #20 ready = 1;          // the DUT becomes ready at t=20
  import "DPI-C" context function int c_send_when_ready(input int max_polls);
  export "DPI-C" function sv_ready;
  function int sv_ready(); return ready; endfunction
  int polls;
  initial begin
    #1;
    // The fix: SystemVerilog waits for ready; C only does the work.
    wait (ready);
    polls = c_send_when_ready(1000000);
    $display("t=%0d polls=%0d", $time, polls);
    if (polls < 0) $display("FAIL: ready never rose inside the C call, because no simulation time passes there");
    else $display("PASS: SystemVerilog waited for ready, then C saw it on the first poll");
    $finish;
  end
endmodule

Prints: t=20 polls=0 PASS: SystemVerilog waited for ready, then C saw it on the first poll

Tool as Truth

"Our simulator rejects a wait in an exported task, so DPI cannot do this."

The standard allows exported tasks to consume time. Verilator 5.052 reports it as unsupported, which is a tool limit, not a language rule.

Source IEEE 1800-2017 §35.8 (exported tasks); ASIC Point engine notes (Verilator 5.052 DPI probe, 2026-11-08: "Unsupported: Timing controls inside DPI-exported tasks")

Spec Misquote

"A context import function may call the exported task."

A function can never call a task, and that rule holds across DPI too. Only an imported task may call an exported task.

Source IEEE 1800-2017 §13.4

Learn It, Then Prove It