Skip to content

Netlisting, schematic capture, cell libraries

Inverter

Here is the fixed code after a lot of (slow) trial & errors. The unit after the width or length of the transistor must not be added or it will fail.

 CMOS Inverter Simulation

* Include the Sky130 device models
.lib "/foss/pdks/sky130A/libs.tech/ngspice/sky130.lib.spice" tt

* Power supply: 1.8V
Vdd vdd gnd 1.8

* Input: pulse from 0V to 1.8V
* PULSE(initial final delay rise fall width period)
Vin in gnd PULSE(0 1.8 1n 100p 100p 2n 4n)

* PMOS transistor (W=1u, L=150n)
* Format: Mname drain gate source body model W=... L=...
Xp out in vdd vdd sky130_fd_pr__pfet_01v8 W=1 L=0.150

* NMOS transistor (W=0.5u, L=150n)
Xn out in gnd gnd sky130_fd_pr__nfet_01v8 W=0.5 L=0.150

* Output load capacitor (typical gate load)
Cload out gnd 10f

* Simulation: transient analysis, 10ps step, 20ns duration
.tran 100n 20n

* Save node voltages for plotting
.save v(in) v(out)

* Control block for ngspice
.control
run
plot v(in) v(out)
meas tran tpd_hl TRIG v(in) VAL=0.9 RISE=1 TARG v(out) VAL=0.9 FALL=1
meas tran tpd_lh TRIG v(in) VAL=0.9 FALL=1 TARG v(out) VAL=0.9 RISE=1
.endc
.end

It produces this output :

Circuit: * multi-corner simulation

Doing analysis at TEMP = 27.000000 and TNOM = 27.000000

Using SPARSE 1.3 as Direct Linear Solver

Initial Transient Solution
--------------------------

Node                                   Voltage
----                                   -------
vdd                                        1.8
in                                           0
out                                        1.8
vin#branch                                   0
vdd#branch                        -1.91736e-12

 Reference value :  0.00000e+00
No. of Data Rows : 175
tpd_hl              =  6.396259e-11 targ=  1.113963e-09 trig=  1.050000e-09
tpd_lh              =  7.878344e-11 targ=  3.228783e-09 trig=  3.150000e-09

Changing the corner automatically in the script with the given solution does not work, but changing it manually (or with sed) does work. Result with ff corner :

Node                                   Voltage
----                                   -------
vdd                                        1.8
in                                           0
out                                        1.8
vin#branch                                   0
vdd#branch                        -5.12086e-12

 Reference value :  0.00000e+00
No. of Data Rows : 180
tpd_hl              =  5.226728e-11 targ=  1.102267e-09 trig=  1.050000e-09
tpd_lh              =  6.293676e-11 targ=  3.212937e-09 trig=  3.150000e-09

And with ss corner :

Node                                   Voltage
----                                   -------
vdd                                        1.8
in                                           0
out                                        1.8
vin#branch                                   0
vdd#branch                        -1.81147e-12

 Reference value :  0.00000e+00
No. of Data Rows : 174
tpd_hl              =  8.296079e-11 targ=  1.132961e-09 trig=  1.050000e-09
tpd_lh              =  1.054676e-10 targ=  3.255468e-09 trig=  3.150000e-09

I don’t know how to interpret the vdd#branch values…

NAND Gate

Now that we know how to instantiate nmos and pmos, it’s easy to make a NAND gate:

* NAND gate SKY130

.lib "/foss/pdks/sky130A/libs.tech/ngspice/sky130.lib.spice" ss

* Power supply: 1.8V
Vdd vdd gnd 1.8

* AND pull-up network -- two pmos in parallel
Xp1 nOUT A vdd vdd sky130_fd_pr__pfet_01v8 W=1 L=0.150
Xp2 nOUT B vdd vdd sky130_fd_pr__pfet_01v8 W=1 L=0.150

* Pull-down network -- two nmos in series
Xn1 nOUT A npd gnd sky130_fd_pr__nfet_01v8 W=0.5 L=0.150
Xn2 npd B gnd gnd sky130_fd_pr__nfet_01v8 W=0.5 L=0.150

* Input voltage source, ramps up to VDD then back down
vin1 A 0 PWL(0 0 2mS 0 2.001mS 1.8V 3mS 1.8V 3.001mS 0) 
vin2 B 0 PWL(0 0 1mS 0 1.001mS 1.8V 2.5mS 1.8V 2.5001mS 0) 

.control 
* transient simulation using vin sweep
  tran 100n 4m 

* plot vout against vin 
  plot v(A) v(B) v(nOUT)
  meas tran tpd_hl TRIG v(A) VAL=0.9 RISE=1 TARG v(nOUT) VAL=0.9 FALL=1
  meas tran tpd_lh TRIG v(A) VAL=0.9 FALL=1 TARG v(nOUT) VAL=0.9 RISE=1
  meas tran tpd_hl TRIG v(B) VAL=0.9 RISE=1 TARG v(nOUT) VAL=0.9 FALL=1
  meas tran tpd_lh TRIG v(B) VAL=0.9 FALL=1 TARG v(nOUT) VAL=0.9 RISE=1
.endc

Here’s the result :

Initial Transient Solution
--------------------------

Node                                   Voltage
----                                   -------
vdd                                        1.8
nout                                       1.8
a                                            0
b                                            0
npd                                0.000556357
vin2#branch                                  0
vin1#branch                                  0
vdd#branch                        -1.81143e-12

 Reference value :  3.82545e-03
No. of Data Rows : 40032
tpd_hl              =  3.994612e-10 targ=  2.000500e-03 trig=  2.000500e-03
tpd_lh              =  -5.004500e-04 targ=  2.500050e-03 trig=  3.000500e-03
tpd_hl              =  1.000000e-03 targ=  2.000500e-03 trig=  1.000500e-03
tpd_lh              =  6.679659e-12 targ=  2.500050e-03 trig=  2.500050e-03

Modified script to read any .spice file :

#!/bin/bash
# run_corners.sh - Simulate at all process corners
if [ -z "$1" ]
then
        echo "Error : spice file as argument needed"
        exit -1
fi

echo "Treating file : $1"
base=`basename $1 .spice` # Works only with .spice names

for corner in tt ff ss sf fs; do
    echo "=== Simulating corner: $corner ==="
    sed -E "s/(\.lib.*\.spice\").*/\1 $corner/" \
        $1 > ${base}_${corner}.spice
    ngspice -b ${base}_${corner}.spice > results_${corner}.log 2>&1
    grep "tpd" results_${corner}.log
done

Maximum delay from high to low is 1e-03 which seems very slow if it’s in seconds. Max delay from low to high is -5e-04… I forgot to add a capacitive load to the output.

/foss/designs > ./run_corners.sh nand_sky130.spice 
Treating file : nand_sky130.spice
=== Simulating corner: tt ===
tpd_hl              =  -2.784143e-09 targ=  2.000497e-03 trig=  2.000500e-03
tpd_lh              =  -5.004500e-04 targ=  2.500050e-03 trig=  3.000500e-03
tpd_hl              =  9.999972e-04 targ=  2.000497e-03 trig=  1.000500e-03
tpd_lh              =  -2.744393e-11 targ=  2.500050e-03 trig=  2.500050e-03
=== Simulating corner: ff ===
tpd_hl              =  -1.367037e-08 targ=  2.000486e-03 trig=  2.000500e-03
tpd_lh              =  -5.004501e-04 targ=  2.500050e-03 trig=  3.000500e-03
tpd_hl              =  9.999863e-04 targ=  2.000486e-03 trig=  1.000500e-03
tpd_lh              =  -1.116948e-10 targ=  2.500050e-03 trig=  2.500050e-03
=== Simulating corner: ss ===
tpd_hl              =  3.994612e-10 targ=  2.000500e-03 trig=  2.000500e-03
tpd_lh              =  -5.004500e-04 targ=  2.500050e-03 trig=  3.000500e-03
tpd_hl              =  1.000000e-03 targ=  2.000500e-03 trig=  1.000500e-03
tpd_lh              =  6.679659e-12 targ=  2.500050e-03 trig=  2.500050e-03
=== Simulating corner: sf ===
tpd_hl              =  -1.027323e-07 targ=  2.000397e-03 trig=  2.000500e-03
tpd_lh              =  -5.004498e-04 targ=  2.500050e-03 trig=  3.000500e-03
tpd_hl              =  9.998973e-04 targ=  2.000397e-03 trig=  1.000500e-03
tpd_lh              =  2.451179e-10 targ=  2.500050e-03 trig=  2.500050e-03
=== Simulating corner: fs ===
tpd_hl              =  1.008480e-07 targ=  2.000601e-03 trig=  2.000500e-03
tpd_lh              =  -5.004509e-04 targ=  2.500049e-03 trig=  3.000500e-03
tpd_hl              =  1.000101e-03 targ=  2.000601e-03 trig=  1.000500e-03
tpd_lh              =  -8.731326e-10 targ=  2.500049e-03 trig=  2.500050e-03