Skip to content

Repository files navigation

SpiceBind

Tests Documentation PyPI License

Run SPICE circuits as blocks inside your existing Verilog simulation.

SpiceBind embeds ngspice into a VPI-capable HDL simulator. Replace only the blocks that need circuit-level simulation. RTL, testbench, cocotb, and the digital verification flow stay in the HDL simulator.

It is useful for mixed-signal simulation in general, and especially when the digital part is large.

SpiceBind is an early project. It is tested with Icarus Verilog, Verilator, and ngspice. The plugin uses VPI, so it is not tied to those two HDL simulators, but others have not been qualified.

SPI ADC mixed-signal simulation in Surfer

The spi_adc example above crosses the HDL/SPICE boundary in both directions. vin is passed from HDL into ngspice, the ADC code is calculated by the SPICE model, and HDL logic shifts the result out over SPI.

What it does

  • RTL, testbenches, cocotb, and digital simulation stay in the HDL simulator you already use. You do not have to move the design into a mixed-signal environment.
  • The plugin uses standard VPI, so it can attach to open-source or commercial HDL simulators. It is tested with Icarus Verilog and Verilator. Other VPI-capable simulators still need qualification. You can change the simulator without changing the RTL, testbench, or how SpiceBind maps instances.
  • Selected HDL instances can be backed by transistor-level or analog SPICE models. The rest of the design stays RTL.
  • HDL events stay in lock-step with ngspice adaptive timesteps, including events that fall inside an analog step.

Why HDL-first?

A mixed-signal design is often mostly RTL with a few analog blocks. Putting the whole system under SPICE can mean rewriting the testbench and how the digital part is simulated.

Architecture

%%{init: {
  'theme': 'base',
  'themeVariables': {
    'lineColor': '#22808f',
    'textColor': '#1c3d42',
    'fontSize': '14px'
  }
}}%%

flowchart LR

    TB["Testbench / cocotb\n{test.v} / {test.py}"]:::tb

    subgraph DUT["Design Under Test\n          {dut.v}"]
        direction LR

        ADC["ADC (stub)\n{adc.v}"]:::hdl
        FE["Sensor (stub)\n{sensor.v}"]:::hdl

        DD["\n\nDigital Design\n{core.v}\n\n\n"]:::hdl

        DD <--> ADC
        DD <--> FE
    end

    SB["SpiceBind<br/>time synchronization<br/>D/A + A/D"]:::bridge

    subgraph NG["ngspice"]
        direction LR
        ADCSP["ADC (SPICE)\n{adc.cir}"]:::analog
        FESP["Sensor (SPICE)\n{sensor.cir}"]:::analog
    end

    TB <--> DUT
    DUT <-->|VPI| SB
    SB <-->|libngspice| NG

    %% Custom Class Definitions based on SVG Palette
    classDef hdl fill:#eef7f8,stroke:#22808f,stroke-width:2.5px,color:#1c3d42,font-weight:bold;
    classDef analog fill:#fff5eb,stroke:#d9772b,stroke-width:2.5px,color:#b8540a,font-weight:bold;
    classDef bridge fill:#e07a2d,stroke:#e07a2d,color:#ffffff,stroke-width:2px,font-weight:bold;
    classDef tb fill:#fcfbb4,stroke:#d1ce00,stroke-width:2.5px,color:#1c3d42,font-weight:bold;

    %% Subgraph Styles
    style DUT fill:#ffffff,stroke:#22808f,stroke-width:2.5px,color:#22808f
    style NG fill:#ffffff,stroke:#d9772b,stroke-width:2.5px,color:#d9772b
    style DD fill:#ffffff,stroke:#22808f,stroke-width:2.5px,color:#22808f
Loading

The HDL side sees a normal module instance. The module body can be empty. SpiceBind finds the selected instance through VPI and connects its ports to sources and nodes in the SPICE circuit.

Digital-to-analog values go to ngspice through external voltage sources. Analog results are read back and driven onto the corresponding HDL outputs.

The two simulators have independent event and timestep mechanisms, so exchanging values is not enough. SpiceBind also keeps simulation time in lock-step. VPI callbacks detect HDL events, ngspice callbacks report analog progress, and a time barrier stops either engine from running ahead. If an HDL event lands inside an ngspice step, ngspice repeats that step at the event time.

See the timing synchronization documentation.

Quick start

Requirements

  • C++17 compiler (needed to build the VPI plugin)
  • ngspice shared library and development headers
  • Verilog VPI compatible simulator (tested with Icarus Verilog and Verilator 5)
  • Python 3.10+

On Debian/Ubuntu:

sudo apt install build-essential cmake iverilog ngspice libngspice0-dev python3-venv

Icarus Verilog from that package set is enough to run the examples. Verilator needs a recent 5.x build with --timing and --vpi (CI compiles it from git; distro packages are often too old).

Install the released package:

pip install spicebind

If ngspice is not on PATH, point CMake at its install prefix (include/ and lib/):

NGSPICE_ROOT=/path/to/ngspice pip install spicebind

Run the SPI ADC example (Icarus Verilog by default; SIM=verilator selects Verilator):

python examples/spi_adc/test_spi_adc.py
SIM=verilator python examples/spi_adc/test_spi_adc.py

For development:

git clone https://github.com/themperek/spicebind.git
cd spicebind
pip install -e ".[dev]"

Standalone VPI build (no Python package):

cmake -S . -B build  # optional: -DNGSPICE_ROOT=/path/to/ngspice
cmake --build build
cmake --build build --target debug  # Optional: debug VPI

Binding an HDL instance to SPICE

The HDL contains a module with the interface that the rest of the design expects:

module adc_core(
    input  real      vin,
    output     [7:0] code,
    input             range0,
    input             range1
);
    // implemented in SPICE
endmodule

The corresponding SPICE netlist provides external sources for HDL inputs and nodes for HDL outputs:

Vvin    vin    0 0 external
Vrange0 range0 0 0 external
Vrange1 range1 0 0 external

* Analog implementation
Xadc vin ref vcc code[7] code[6] code[5] code[4] code[3] code[2] code[1] code[0] adc_ideal_8bit

.tran 1ns 100us
.end

At runtime, select the netlist and HDL instance:

export SPICE_NETLIST=examples/spi_adc/spi_adc.cir
export HDL_INSTANCE=spi_adc.adc_inst
export VCC=3.3

The VPI module can then be loaded by the HDL simulator.

Icarus Verilog:

vvp -M "$(spicebind-vpi-path)" -m spicebind_vpi simulation.vvp

Verilator (--vpi --timing); pass the plugin as a plusarg:

./Vtop +verilator+vpi+"$(spicebind-vpi-path)/spicebind_vpi.vpi"

The examples use the cocotb runner or small shell scripts to set this up automatically. $SIM selects the HDL simulator (icarus default, or verilator). The full suite is nox -s test (see CONTRIBUTING.md).

Runtime configuration

Variable Meaning
SPICE_NETLIST Path to the ngspice netlist
HDL_INSTANCE HDL instance path, or a comma-separated list of instance paths
VCC Voltage used for digital-to-analog conversion. Default: 1.0
SPICE_DUMP_RAW Write ngspice transient data to dump.raw at shutdown

Examples

Example What it shows
examples/adc 8-bit ADC with Verilog and cocotb testbenches
examples/adder_mos Four-bit CMOS adder derived from the ngspice MOS adder example
examples/spi_adc HDL SPI interface connected to an ADC implemented in SPICE
examples/serv_dco_calibration SERV firmware calibrates a transistor-level DCO through SpiceBind

How this differs from other open-source flows

There are several ways to combine HDL and SPICE. They differ mainly in which simulator owns the top level and how the digital part is executed.

Approach Top-level environment Digital execution Analog engine What it does
SpiceBind HDL simulator Normal HDL simulation ngspice shared library Selected HDL instances are replaced by SPICE while the HDL flow stays in place
ngspice d_cosim ngspice / XSPICE HDL compiled with Verilator, Icarus Verilog, or GHDL and loaded as an XSPICE model ngspice SPICE-first flow with HDL blocks inside the ngspice netlist
Yosys to XSPICE ngspice / XSPICE Synthesizable RTL mapped to XSPICE gates and storage elements ngspice One simulator at runtime, but the RTL is reduced to synthesized logic
cocotbext-ams cocotb / Python Normal HDL simulator through cocotb ngspice or Xyce Python coordinates the HDL and analog simulators

A SPICE-first flow fits when the analog netlist is already the top level. Synthesizing RTL into XSPICE avoids synchronizing two simulators at runtime. SpiceBind is for the other case: a digital simulation already exists and only selected blocks need SPICE.

Commercial Verilog-AMS and real-number-modeling flows are not compared here.

Current scope

SpiceBind currently focuses on:

  • ngspice as the analog engine
  • Verilog through VPI
  • Icarus Verilog and Verilator as the tested HDL simulators
  • binding selected HDL instances to SPICE
  • event and timestep synchronization between HDL and ngspice
  • cocotb compatibility, without requiring cocotb

The VPI plugin is not tied to those two HDL simulators, but others have not been tested.

Documentation

Tutorials, configuration, API notes, and timing:

https://themperek.github.io/spicebind/

Talks

OrConf 2026: SpiceBind: Bringing SPICE into RTL Verification. Slides (PDF).

Contributing

Bug reports, examples, and pull requests are welcome. Use the GitHub issue tracker for bugs, questions, and feature proposals.

License

SpiceBind is distributed under the BSD 3-Clause License. See LICENSE.

Development note

SpiceBind is developed with assistance from generative AI tools. All generated or modified code is reviewed, tested, and maintained like any other contribution.

About

HDL-first mixed-signal co-simulation: embed ngspice circuits in Verilog through VPI

Resources

Contributing

Stars

60 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages