Back to blog Verification

Automating Testbenches While Keeping the Test Strategy in Your Hands

Automating Testbenches While Keeping the Test Strategy in Your Hands

Automated testbench generation gets the scaffolding right, but can miss the failure the design actually contains. The dangerous result is a testbench that appears complete, compiles cleanly, runs without warnings, and reports every test passed without applying meaningful stimulus. Teams burned by this outcome trust generated testbenches less than handwritten ones, removing much of automation's value.

The usual cause is generation from RTL structure rather than the specification. Suppose the spec requires "gain greater than 15 dB across the 2.35 to 2.5 GHz band." If the generator sees only module ports, it may apply default stimulus at one frequency and compare output power with an invented threshold. Such a test passes but conveys nothing.

Spec-Driven and Structure-Driven Testbench Generation

Choosing between spec-driven and structure-driven generation is central to any testbench automation system. Structure-driven generation reads the DUT port list and clock declarations, then creates stimulus and monitors from port types. It drives inputs, samples outputs, and checks for output changes after input changes. The result is syntactically valid and can catch gross functional faults, such as no output or an output stuck at zero, but it cannot establish spec compliance.

With spec-driven generation, the specification enters the generator alongside the RTL. It must be available in an interpretable form, either as structured parameters on the module declaration or within the natural-language description used to create the RTL. Given "NF less than 2.5 dB, gain greater than 15 dB, input return loss better than -10 dB at 2.4 GHz," the generator can check every condition using the right thresholds and input stimulus range.

Skycore feeds the spec description to both the RTL and testbench generators. The shared description places spec parameters in the RTL as module parameters and in the testbench as assertion thresholds. Changing the gain spec updates both in one regeneration step.

Contents of a Useful RF Testbench

An LNA behavioral block needs at least four test cases for a minimum viable testbench:

  • Measure gain at center frequency, nominal input power, nominal PVT. Tests the core spec.
  • Measure noise figure at center frequency. Drive thermal noise power into the block and measure SNR degradation through it.
  • Measure input return loss over the frequency band. Sweep input frequency and calculate reflected-to-incident power ratio.
  • Compression check: raise input power to and beyond P1dB, then verify gain compression of 1 dB at the specified P1dB input power.

These four cases map directly to an LNA's four primary spec requirements. Each uses a spec-derived pass/fail threshold and a distinct stimulus setup. Passing all four supplies evidence that the behavioral block meets its spec. That is a useful testbench: either result provides information.

// Gain test task -- checks gain at center frequency vs spec threshold
task automatic check_gain_nom;
  real pin_test_dbm;
  real pout_meas_dbm;
  real gain_meas_db;
  begin
    pin_test_dbm = -30.0;    // Small-signal input (well below P1dB)
    // Drive DUT at center frequency, nominal PVT
    @(posedge clk);
    pin_dbm  = pin_test_dbm;
    freq_ghz = DUT.F_CENTER_GHZ;
    temp_c   = DUT.TEMP_NOM_C;
    vdd_v    = DUT.VDD_NOM_V;
    #10; // Allow combinational propagation
    pout_meas_dbm = pout_dbm;
    gain_meas_db  = pout_meas_dbm - pin_test_dbm;
    if (gain_meas_db >= DUT.GAIN_NOM_DB) begin
      $display("PASS: gain_nom -- measured %.2f dB >= spec %.2f dB",
               gain_meas_db, DUT.GAIN_NOM_DB);
    end else begin
      $display("FAIL: gain_nom -- measured %.2f dB < spec %.2f dB",
               gain_meas_db, DUT.GAIN_NOM_DB);
      test_fail_count = test_fail_count + 1;
    end
  end
endtask

Where Automation Saves Time: Testbench Boilerplate

Testbench automation should target the structural scaffolding repeated around every test: module instantiation, clock generation, reset sequence, simulation time control, result logging, and the final summary report. This structure stays the same across block testbenches, so hand-writing it adds no engineering value. It is transcription.

A medium-complexity RF block testbench contains roughly 200 to 400 boilerplate lines for every 100 lines of actual test logic. Skycore produces that boilerplate in seconds. The substantive output is the spec-derived test logic. The generated file has a better signal-to-noise ratio than a manual testbench copied from another project.

Corner Cases and Automation's Boundaries

Spec-based automated generation cannot cover every case an experienced verification engineer might write. It handles tests directly derivable from stated requirements. Failures caused by undocumented block interactions, supply-noise coupling absent from the single-block spec, or digital control interface timing conditions omitted from the spec remain outside automation's scope without human input.

That boundary is appropriate, not an automation failure. Automation handles spec-derived tests completely and correctly; the verification engineer adds tests for interactions and edge cases the spec misses. Together, they are faster than starting from scratch and more reliable than automation alone.

Do not use automation instead of documenting requirements. Vague parameters such as "gain should be reasonable" or "NF should be low" give the generator no threshold to test. Automated testbench generation therefore demands that the actual requirements be written down first. Teams using this process say it exposes spec ambiguity earlier in the design cycle, apart from the time saved writing tests.

Adding Generated Testbenches to an Existing EDA Flow

Skycore produces standalone SystemVerilog testbench files for Questa and VCS, plus UVM test class stubs for teams with a UVM environment. The UVM option supplies a test class and sequence class that fit an existing environment without building a complete UVM agent from scratch. The sequence applies stimulus; the test configures coverage and invokes it. The remaining UVM infrastructure, including scoreboard, checker, and coverage collector, is a marked extension point with comments defining each component's task.

Without UVM, teams can use the standalone testbench as a self-contained simulation. It includes a simulation control script for Questa and VCS command-line flows, plus an output parser that extracts pass/fail results and formats them for a CI pipeline or shared simulation log viewer.