DEV Community

Alexandre Rusev
Alexandre Rusev

Posted on

Mixed co-simulation with IcarusVerilog and NGSpice using "MixFighter" bridge.

Bridge for Co‑simulation in Icarus Verilog and NGSpice

Author: Cyberflex (based on the real development "MixFighter")

How We Built a Bridge Between Icarus Verilog and NGSpice: Two Different Architecture Implementations, their advantages and drawbacks, and why the ideal solution is not yet achieved

What Are Event‑Driven and Continuous Simulation?

In the world of electronic system simulation, there are two fundamentally different approaches.
Event‑driven simulation is used for digital circuits. Logic elements change their state only at moments when changes occur at their inputs – clock edges, flip‑flop toggles, gate delays. Between these events, nothing happens; the simulator "sleeps" and does not consume resources. This is exactly how Icarus Verilog, Modelsim, VCS, and other digital simulators work. This is fast and efficient because digital signals have only two (or a few discrete) states.

Continuous simulation (or pseudo‑continuous) is used for analog circuits. Current through a transistor, voltage on a capacitor, generator phase – everything changes smoothly according to differential equations. The simulator (SPICE, NGSpice, Spectre) divides time into very small steps, solves systems of equations at each step, and produces results as curves. Accuracy requires the smallest steps, especially during sharp edges or feedback loops. This is slow, but there is no other way to obtain "almost real‑life" analog behavior.

The Problem of Mixed‑Mode Modeling

Sometimes there is a need for co‑simulation of interacting analog and digital systems. Imagine you are developing a SAR ADC. The analog part – comparator, capacitor DAC, input buffer – requires SPICE modeling with microvolt and picosecond accuracy. The digital part – control logic, calibration, interface – is perfectly simulated in Icarus Verilog. How do you make them work together? You can use ready‑made commercial solvers (Cadence, Synopsys), but they are expensive and not always available. Or you can write your own bridge – a VPI module that connects Icarus and NGSpice via shared memory and semaphores. That is exactly what I did.

This can be solved by harnessing two different simulators in the same team, controlling them alternately and exchanging data between them. We took a pair of such standard simulators – Icarus Verilog and NGSpice – and built a controlling bridge. The process gave rise to two implementations: "Classic" – simple, synchronous, where Verilog explicitly requests analog data ("digital oversampling"). "Alternative" – with lookahead and injection of events from SPICE into Verilog.
It would seem that the second is an evolution of the first. But in reality, each has fundamental architectural drawbacks that cannot be fixed with cosmetic patches. In this article, I will analyze both implementations, their compromises, and show why an ideal open‑source solution for mixed‑mode modeling does not yet exist. Spoiler: despite all the drawbacks, the tool is already quite suitable for real tasks – from formal verification of digital blocks in conjunction with analog IP to counting pulses of sigma‑delta ADCs.

Figure 1: GTKWave (digital + analog) and built‑in NGSpice /gnuplot. Merged time scales, same signals.

How the Bridge Works: Common Architecture

Both implementations are based on the same set of technologies: VPI (Verilog Procedural Interface) of Icarus, libngspice.so, pipe semaphores, and a separate NGSpice thread. The workflow (simplified):

Icarus (main thread) NGSpice (thread)

$spice_sync() (or $get_...)
| state.target = t_now
| wait(analog_done)  <----------------+ post(analog_done)
|                                 update real variables
|                                 apply alter (DAC)
|                                 post(digital_done)
| -------------> wait(digital_done)
| return control
| (continues simulation)
Enter fullscreen mode Exit fullscreen mode

The problem is that SPICE produces results only at the moments of its internal time steps. And Verilog operates by events that can occur at any (planned) time.

Important Simplification for Testbench: $spice_sync()

Both implementations include the system task $spice_sync(). Its call (e.g., on each fast clock edge) performs a full exchange cycle: transfers the current digital values to SPICE (via alter), requests fresh analog voltages, and updates real variables in Verilog. There is no need to manually call $get_analog_voltage() for each signal.

always @(posedge clk_fast) begin
    $spice_sync(); // synchronization and update of all exposed variables
    if (tb.Vcmp > vref_th) begin
        // digital reaction on event
    end
end
Enter fullscreen mode Exit fullscreen mode

Thanks to expose_analog_N (config file for co-simulation of specific project), real variables are automatically updated and visible in GTKWave on the same time axis as digital signals.

Modeling Delays and Edges

Often in mixed‑mode circuits, not only static levels are important but also the settling time of the digital signal and the slew rate of the analog edge. In both implementations, this is easily modeled using "wrapper" objects on the Verilog and SPICE sides.

Classic Implementation: Synchronous Polling

Every time Verilog needs fresh analog data, the bridge finds out the current time of Icarus, blocks on a semaphore, SPICE simulates up to that time and returns the values. Pros: simplicity, determinism, predictable performance. Cons (major drawback): analog events that occur between Verilog clock ticks are completely ignored. Example: the comparator switches at 5.2 ns, but the next positive clock edge is at 10.0 ns. Verilog learns about this only at 10 ns, which breaks the feedback logic in SAR ADCs, DC‑DC converters. You have to oversample the data exchange between the two simulators by increasing the frequency of the clk_fast system task. Finding appropriate oversampling rate makes the model to work properly.

Alternative Implementation: Lookahead

The idea: allow SPICE to run ahead for a small interval, monitor analog triggers (thresholds, windows, durations, peaks) and, if something happens, stop and call Verilog earlier. Example of line in configuration file:

analog_event_1 = duration outp above 0.8V for 10ns energy 1e-12
Enter fullscreen mode Exit fullscreen mode

Pros: SPICE can initiate an event, accuracy under ideal conditions, flexibility.
Cons (fundamental): Sentinels are checked only at SPICE steps – an event between steps may be missed. The window length heuristic can fail (too little – late, too much – performance drop). Causality violation for DAC: the alter command will only be executed in the next phase A, after SPICE has already passed the moment of the event. Only one event per window. Non‑determinism due to heuristics.


Figure 2: gwave: viewing analog signals of a Sigma Delta modulator (same vbuck, vbucki, Qbar as in GTKWave)

Comparison Table

            Characteristic                  Classic Alternative
Detection of analog events between          ❌ No          ⚠️ Partial  
clock ticks                                           (with misses)
Injection of events from SPICE into Verilog ❌ Impossible  ✅                                                                  
Performance                                 ✅ Predictable ⚠️ May spike (but maxstep helps)
Determinism                                 ✅ Complete    ⚠️ Depends on heuristics
DAC→Analog causality                        ✅ Correct     ❌ Violated
                                                        during phase B
Support for multiple events                 ❌ No          ❌ Only 
                                                       one per window
Code size (lines)                          ~2000       ~3500                 
Enter fullscreen mode Exit fullscreen mode

Figure 3: JavaElectric EDA: schematics of a mixed‑mode device (Sigma Delta modulator ADC + digital counter) and a fragment of the SPICE netlist describing analog events.
(see https://www.staticfreesoft.com/index.html about JavaElecric project)

Despite Everything: It Works (Mostly)

Neither implementation is perfect, but both have been successfully used in real projects: SAR ADC verification, sigma‑delta modulator modeling, and digital PLL calibration. The code is available on GitHub (search for "MixFighter" or "iverilog-ngspice-bridge"). If you need mixed‑signal simulation today and don't have access to commercial tools, this bridge will get you 80% of the way there – just be aware of the limitations described above.
Following Verilog code count sigma delta modulator pulses (Fig.1, Fig.2 Qbar signal) during specified period and reports resulted value as output.

//// This module count impulses from sigma delta modulator
//// generated during  CNT_CLK periods of functional clock
module DSMCounter(
    input i_clk,
    input i_rst,
    input **i_Qbar**,
    output reg[31:0] **o_cntQbar**,
    output reg o_ready
);
parameter CNT_CLK = 22;
reg [31:0] cnt;
reg [31:0] cntQbar;
reg [31:0] cntTotal;

always @(posedge i_clk) begin
    if(i_rst) begin
        cnt <= 0;
        cntQbar <= 0;
        o_cntQbar <= 0;
        o_ready <= 0;
        cntTotal <= 0;
    end else begin
        o_ready <= 0;
        cntTotal <= cntTotal + 1;
        if(i_Qbar == 1) begin
            cntQbar <= cntQbar + 1;
        end
        if(cnt == CNT_CLK-1) begin
            o_cntQbar <= cntQbar;
            o_ready <= 1;
            cnt <= 0;
            cntQbar <= 0;
        end else begin
            cnt <= cnt + 1;
        end
    end
end
endmodule
Enter fullscreen mode Exit fullscreen mode

Source code available here https://github.com/cyberflex/MixFighter + scripts and example simulation projects.

NGSpice needs to be built with support of libngspice.so (./configure --with-ngshared). Configuration of co-simulatin is set in mixed_bridge.cfg, this file is also available in simulation example projects.

Tags: verilog, spice, opensource, mixed-signal, icarusverilog, ngspice

Original publication: [https://habr.com/ru/articles/1023270/]

Top comments (0)