Thursday, July 25, 2024

using ngspice with the skywater pdk.

shout the last goodbye I have a terrible time getting ngspice-43 working with skywater 130. There's some weird stuff in the PDK models, as it definitely is still the "IBM way". Firstly, you need to comment out any includes for any devices that aren't working in the sky130.lib.spice file. For me, it was all of the nfet_05v0_nvt devices.
* .include "../cells/nfet_05v0_nvt/sky130_fd_pr__nfet_05v0_nvt__tt.corner.spice"
The next issue is that "decks" have the devices have .models as a units of 1 meter. If you take a look at the sky130_fd_pr__nfet_01v8.pm3.spice file, you see how the subcircut (subckt) is generated.
.subckt  sky130_fd_pr__nfet_01v8 d g s b
+ 
.param  l = 1 w = 1 ad = 0 as = 0 pd = 0 ps = 0 nrd = 0 nrs = 0 sa = 0 sb = 0 sd = 0 mult = 1 nf = 1.0
msky130_fd_pr__nfet_01v8 d g s b sky130_fd_pr__nfet_01v8__model l = {l} w = {w} ad = {ad} as = {as} pd = {pd} ps = {ps} nrd = {nrd} nrs = {nrs} sa = {sa} sb = {sb} sd = {sd} nf = {nf}
.model sky130_fd_pr__nfet_01v8__model.0 nmos
This means that you need to create a .spiceinit file the same directory where you run the simulation. For me, I did this:
* .spiceinit for use with Skywater PDK and ngspice KLU
set ngbehavior=hsa     ; set compatibility for reading PDK libs
set skywaterpdk        ; skip some checks for faster lib loading
set ng_nomodcheck      ; don't check the model parameters
set num_threads=8      ; CPU processor cores available
option noinit          ; don't print operating point data
option klu             ; select KLU as matrix solver
optran 0 0 0 100p 2n 0 ; don't use dc operating point, but transient op%    
If you've gotten this far, this is how I did the whole thing. You need to install git, ngspice-43 and have some time download the 45GiB that is the skywater PDK.
git clone https://github.com/google/skywater-pdk.git
cd skywater-pdk
git checkout main
git submodule init
git submodule update
In the same directory as the .spiceinit file, I made this inverter.sp file:
* Inverter simulation using SkyWater 130nm PDK
.lib "$HOME/skywater-pdk/libraries/sky130_fd_pr/latest/models/sky130.lib.spice" tt
* Power supply
VDD VDD 0 1.8
* Input voltage source
VIN IN 0 PULSE(0 1.8 0 1n 1n 10n 20n)
* NMOS transistor
X1 OUT IN 0 0 sky130_fd_pr__nfet_01v8 
* PMOS transistor
X2 OUT IN VDD VDD sky130_fd_pr__pfet_01v8 
* Load capacitor
CL OUT 0 1p

.control
* Run transient analysis
tran 0.1n 50n
* plot v(IN) v(OUT)
* Save the results
wrdata inverter_simulation.raw v(IN) v(OUT)
.endc
.end
You will get some interesting warnings. This includes that a "scale" value is set somewhere to make the models based on nanometers, instead of meters. running "ngspice -b inverter.sp" yields:
degs@kazan inverter % ngspice -b inverter.sp
Warning: can't find the initialization file spinit.
Warning: Optran step size potentially too large.

Note: Compatibility modes selected: hs a

Warning: m=xx on .subckt line will override multiplier m hierarchy!


Circuit: * inverter simulation using skywater 130nm pdk

option SCALE: Scale is set to 1e-06 for instance and model parameters
Doing analysis at TEMP = 27.000000 and TNOM = 27.000000

Using KLU as Direct Linear Solver
Note: Transient op started
Note: Transient op finished successfully
 Reference value :  0.00000e+00
No. of Data Rows : 535
Note: Simulation executed from .control section 
At this point, I used Python to read the raw file via "python plot.py inverter_simulation.raw" that is here:
import numpy as np
import matplotlib.pyplot as plt
import argparse

def read_and_plot(filename):
    # Load the data from the raw file
    data = np.loadtxt(filename)

    # Assuming the columns are:
    # Column 1: Time
    # Column 2: VIN
    # Column 3: Time again (redundant)
    # Column 4: VOUT

    time = data[:, 0]  # First column is time
    vin = data[:, 1]   # Second column is VIN
    vout = data[:, 3]  # Fourth column is VOUT

    # Plot the data
    plt.figure()
    plt.plot(time, vin, label='VIN')
    plt.plot(time, vout, label='VOUT')
    plt.xlabel('Time (s)')
    plt.ylabel('Voltage (V)')
    plt.title('Inverter Simulation')
    plt.legend()
    plt.grid(True)
    plt.show()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Plot ngspice simulation data.')
    parser.add_argument('filename', type=str, help='Path to the raw data file')
    args = parser.parse_args()

    read_and_plot(args.filename)
The results are wrong as I buggered up the netlist; however, it is actually functioning. This is a day that I will not get back. The bad graph is:

No comments:

Post a Comment