Table of Contents

Porting/Converting Spice to Verilog(-AMS)

Verilog-AMS has been designed to coexist with Spice, and to replace it as needed (among other things). Citing from Annex E of the language reference manual, Analog simulation has long been performed with SPICE and SPICE-like simulators. As such, there is a huge legacy of SPICE netlists. These are supposed to retain its use when upgrading a SPICE simulator. On the other hand, Annex E provides a list of “SPICE primitives” that facilitate the rewrite of basic SPICE netlists.

(See Using Verilog circuits in a SPICE-only simulator for a solution of the inverse problem.)

SPICE Subsystem

Gnucap and Verilog-AMS offer mechanisms to include device models and circuits written for SPICE. The idea is to facilitate the transition from SPICE, motivated elsewhere. In theory, the approach corresponds to the “extern C” construct in C++, which has been widely successful. The limitations are as follows.

- SPICE dialects are mutually incompatible, there is a need to pick one at least as a starting point. Supporting all of them is likely infeasible.

- Verilog-AMS does not mandate a specific SPICE dialect for use in a Verilog-AMS environment. As a consequence, no two SPICE subsystems in two distinct Simulators will be compatible. This defies the purpose of standardisation.

- A full transition to Verilog-AMS can be neccessary to enable an endless list of features missing in SPICE and its derivatives. If those are needed, even a manual rewrite can be more practical and less time consuming than inventing and implementing workarounds.

Gnucap offers a SPICE subsystem subject to these issues.z

Netlist translation

A SPICE netlist is composed of a list of device instances. What we need to do is find a substitute for each such instance. We use lower case letters only for consistency and to aid recognition after the translation.

Basic simple case

In some cases, devices can be substituted following Annex E.

SPICE Verilog-AMS
R1 a b 1k resistor #(.r(1k)) r1(.p(a), .n(b));
V1 a B sin 1 1k 1 vsine #(.ampl(1.), .freq(1k), .offset(1)) v1(.p(a), .n(b));
C1 a b 1u ic=1. capacitor #(.c(1u), .ic(1.) C1 (.p(a), .n(b));

Note that in SPICE the type is implicit, often encoded in the label. We need to find the correct type, and simply keep the label. The port and parameter assignments depend on the SPICE dialect used in the legacy netlist. A translation to Verilog will hence make a guess and assign names accordingly. Both a wrong guess, or an error in the SPICE netlist will be easy to spot after the translation.

 vsine #(.freq(1.), .ampl(1k), .offset(1)) V1(.p(a), .n(b));

It remains to check if additional parameters in a desired SPICE device instance, such as ic in a capacitor, actually match the behaviour described in table E1.

Behavioural modelling

SPICE provides modelling features between netlisting and device modelling. These need special treatment. For example a vccs like

G1 a b c d dc {p} tran {p*tanh(V(c,d))}

To represent “G1” in a Verilog-AMS system, we need a substitute similar to

parameter real p;
analog begin
  if($analysis("dc")) begin
     V(a,b) <+ p;
  end else if($analysis("tran")) begin
     V(a,b) <+ p*tanh(V(c,d));
  end   
end

Such a substitute needs a module context to work, and a compiler.

Specific cases

TODO

".model" instances

The .model statement refers to model code often hardwired in the simulator. A “model instance” defines a device prototype that somehow relates to that model code. For example

.MODEL MYNPN NPN BF=80 IS=1E-18 RB=100 VAF=50 CJE=3PF CJC=2PF CJS=2PF TF=0.3NS TR=6NS

Refers to an “npn” device “model” provided by the simulator and declares a “MYNPN” type, which might have instances in the netlist looking similar to

Q1 a b c mynpn w=1u l=2u

Translating such devices highly depends on the SPICE implementation, and may be represented by a line similar to

mynpn #(.w(1u), .l(2u)) Q1 (.c(a), .b(b), .e(c));

Generic instances

Without context, an instance translation will be impossible to guess. Consider for example

?1 a b c d e,

which may translate to either

c #(d, e) ?1(a, b);

or

d #(e) ?1(a,b,c);

".subckt" instances

Most implementations use X to indicate a subcircuit aka module instance. If the SPICE dialect used named parameters, a generic translation seems possible.

X1 a b c d e='{17.}' F=42

may translate to

d #(.e(17), .f(42) X1(a, b, c);

with considerable success rate. Due to case insensitivity, upper case letters must be replaced by lower case.

prototype declarations

".subckt"

In SPICE, the .subckt directive declares a new prototype and translates to a module declaration. The devices in it need to be replaced according to the section above. For example, the declaration

.subckt a b rc
  .parameter r=1k
  .parameter c=1u
  R1 a b r
  C1 b 0 c
.ends

translates to

module rc(a, b);
  electrical a, b, \0 ;
  inout a, b;
  parameter real r=1k;
  parameter real c=1u;
  ground \0 ;
  resistor #(.r(r)) R1(.p(a), .n(b));
  capacitor #(.c(c)) C1(.p(b), .n(\0 ));
endmodule.

The discipline binding will be required in analog blocks making use of branches (not shown). Nodes in a SPICE subckt are usually of the “electrical” type, and better choices are possible, but must be left to the user. Similarly, it is safe yet possibly suboptimal to declare ports as “inout”. It is harder to automate better guesses based on the SPICE input only. Note that “0” is not a valid identifier in Verilog, and needs escaping. The node named “0” is no longer tied to ground implicitly and needs special attention. Other SPICE specific rules may apply depending on the dialect and context.

".model" declaration

In Gnucap, a .model declaration may refer directly to the model originally intended by a SPICE netlist author. A line like

.MODEL mynpn NPN BF=80 IS=1E-18

refers to a Spice implementation. If this implementation is available, the statement will define a type mynpn for instanciation in a Verilog context, such as

module example();
  mynpn #(.w(1.)) m1(a, b, c, d);
  [..]
endmodule.

In some cases a wrapper may be useful to encapsulate the .model declaration, for example if customised port or parameter names are required.

.subckt mynpn a b c
  .parameter w=1u
  .parameter l=1u
  .model mynpn_ npn bf=80 is=1E-18
  q1 a b c mynpn_ w=1u l=2u
.ends

If there is no intent or need to use Spice models, the .model statement can be replaced by a paramset. This requires some background knowlege about the Spice model parameters, as these have to be stated explicitly.

paramset mynpn npn;
  .parameter real w=1u; // instance parameters
  .parameter l=1u;      // all user defined.
  .w=w; .l=l;           // mirror implicit assignment from SPICE.
  .bf=80; .is=1e-18;    // "model parameters" become ordinary parameter assignments
endparamset,

Also, “npn” should refer to the desired device prototype, implemented in Verilog.

Binning

Spice may support binning for device models. Given two model statements

.model mymos.1 nmos wmin=1 wmax=2 more=42
.model mymos.2 nmos wmin=2 wmax=3 more=17

a device instance of type “mynpn” will pick the suitable model based on 'w' and infer the value of the other parameters (here: more) accordingly.

M1 d g s b mymos w=1.5
M2 d g s b mymos w=2.5

M1 will have more=42, and M2 will end up with more=17.

In Gnucap, binned models behave like ordinary models, and “bin names” from spice are ignored, so the devices may be instanticated as if there was no binning suffix.

module example_bin();
  mynmos #(.w(1.5)) M1(d, g, s, b);
  mynmos #(.w(2.5)) M2(d, g, s, b);
endmodule;
  

Similar to shown above without binning, this may be expressed in Verilog using the paramset construct referring to a wrapper similar to the one shown above.

.subckt mymos_wrap d gate s b
  .parameter w=1u
  .parameter l=1u
  .parameter more=0
  .model mm nmos w=w, l=l
  m1 d gate s b mm w=w l=l more=more
.ends
paramset mymos mymos_wrap
  parameter real w=0 from [1.:2.];
  .more=42;
  .w=w;
endparamset
paramset mymos mymos_wrap
  parameter real w=0 from [2.:3.];
  .more=17;
  .w=w;
endparamset

With these, M1 and M2 translate to

mymos #(.w(1.5)) M1(d,g,s,b);
mymos #(.w(2.5)) M2(.d(d),.gate(g),.s(s),.b(b));

as expected, optionally with port names inferred from mymos_wrap. Note that these paramsets are self contained and reusable specifically when moving on from Spice “model + instance” .subckt wrappers to behavioural models implemented as Verilog “module”.

Type nesting

Verilog-AMS does not explicitly require support for nested types, and they are not mentioned in the paramset specification. Moreover module and paramset declarations are supposedly at top level. There is little gain from nested types in terms of expressivity, and possibly this choice was made to just improve compatibility between implementations. However, System-Verilog supports nested types, and it would be totally natural to have them. Perhaps System-Verilog-AMS will consolidate the drift.

Global Options

Spice simulators provide a global set of “options” that interfere with circuit behaviour and affect models. Examples are temperature, scale, method, gmin, tolerances etc. Verilog-AMS offers a place for some of these options. Gnucap implements some of it, and adds features that are still missing in the standards.

Gnucap supports Spice options through the .option command. These may be accessed from Verilog code through the $simparam function, according to the standard. For example, $simparam(“scale”, 1.) evaluates to the value managed by the .option command. Note that this is only available in behavioural models right now (early '26).

Most options are candidates for “hierarchical system parameters” (HSP). HSPs are additional device parameters with a name starting with a dollar ($) character. Such parameters may not be declared, but assigned and used in a module. Unrecognised HSPs are allowed for forward and backwards compatiblilty, like attributes. Example

  module bad();
     parameter real $mfactor = 1.; // not allowed
  endmodule;
  module good();
     parameter real m = $mfactor; // OK
  endmodule;
  module test();
     good #(.$mfactor(17.)) g1(); // OK
     good #(.$somethingelse(42.)) g2(); // allowed (in Gnucap)
  endmodule

Gnucap implements “inofficial” HSPs $temperature, $dtemp, $method (early '26) following real demand. The option scale may be covered by a $scale HSP in principle. We do not wish to encourage the use of a scaling mechanism at this point, as it normally causes problems, invites funny ideas and leads to broken promises. SI units are a good choice for physical parameters.

Algorithmic Peculiarities

In Spice, commands and devices sometimes accept curious arguments and parameters. Often there is no need for them, once their interaction and purpose is understood.

One example is the ic parameter that supposedly sets “initial contitions” and the uic that instructs a transient simulation command to “use” initial conditions (as opposed to compute them). Both are implemented in Gnucap for backwards compatibility and to mirror Spice. Do not use them.

The ic parameter may be assigned to (say) a capacitor instance, setting an initial charge. A nonzero value puts the device into a non-converged state, as the potential across the terminals is initially zero. In theory, a computed operating point could depend on the value specified here (if there are multiple operating points). It normally does not work like this.

The purpose of uic is to circumvent non-convergence in initial dc. There are some circuits where nonconvergence is the correct result. The uic flag just sets some values and has no basis in reality. It mostly fills in zeros, where no ic has been set explicitly, assuming convergence.

In Verilog-AMS, it is possible to model initial conditions in a physically meaningful way. Behavioural models support “initial” and “analog initial” statements to initialise variables before a simulation starts. In an analog block the call $analysis(“ic”) tests, if the simulator is solving for an operating point (iteratively). If it does not converge, there may be something wrong with the model. The uic flag will not fix it.