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