blob: 94d079b377b66602311b0636ccc957f09738ede1 [file] [log] [blame]
#!/usr/bin/env python3
#------------------------------------------------------------------------------
#
# run_spice_tests.py --
#
# Run all ngspice tests, assuming an input file "devices.txt" containing,
# with one entry per line:
#
# <device_name> <device_type> <expected_value>
#
# where <device_type> is one of: mosfet, bipolar, capacitor, resistor, or diode.
#
#------------------------------------------------------------------------------
import re
import os
import sys
import subprocess
import multiprocessing
from plot_mosfet_iv import make_mosfet_iv_plot
from plot_bipolar_iv import make_bipolar_iv_plot
from plot_bipolar_beta import make_bipolar_beta_plot
from plot_diode_iv import make_diode_iv_plot
__dir__ = os.path.dirname(os.path.abspath(__file__))
def make_testdir(outdir):
testdir = os.path.join(outdir, 'tests')
if not os.path.exists(testdir):
os.makedirs(testdir)
return testdir
def getmake(outdir):
testdir = make_testdir(outdir)
testrunner = os.path.join(testdir, 'Makefile')
# FIXME: Write out a Makefile
with open(testrunner, 'w') as ofile:
# FIXME: run ngspice
# FIXME: run the check_XXXX.py script on the ngspice output
# FIXME: run the plot_XXX.py script on the ngspice output
#------------------------------------------------------------------------------
# Read ".spice.in" file, replace DEVICENAME string with the device name,
# PDKVERSION with the version (v0.20.1), and CORNER with the simulation
# corner (tt), and write out as ".spice" file in "results" directory.
#------------------------------------------------------------------------------
def genspice(outdir, scriptname, devicename, version, corner):
print('Generating simulation netlist for device ' + devicename)
scripttype = scriptname.split('_', 1)[1]
scriptpath = os.path.join(__dir__, scriptname+'.in')
with open(scriptpath, 'r') as ifile:
spicelines = ifile.read().splitlines()
outlines = ['* '+devicename+' Spice Simulation Test']
for line in spicelines:
newline = line.replace('DEVICENAME', devicename)
newline = newline.replace('PDKVERSION', version)
newline = newline.replace('CORNER', corner)
outlines.append(newline)
testdir = make_testdir(outdir)
testfile = os.path.join(testdir, devicename + '_' + scripttype)
with open(testfile, 'w') as ofile:
for line in outlines:
print(line, file=ofile)
return testfile
#------------------------------------------------------------------------------
# Run a spice simulation (or two) for the device specified in 'line' (obtained
# from the list of devices and expected values).
#------------------------------------------------------------------------------
def do_for_device(outdir, devicename, version, corner):
if 'ind' in devicename:
# Inductors not handled (yet)!
pass
elif 'cap_mim_' in devicename:
devicetype = 'mimcap'
elif 'cap_vpp_' in devicename:
devicetype = 'capacitor'
elif 'esd_rf_diode' in devicename:
devicetype = 'diode_dev'
elif 'diode_' in devicename:
devicetype = 'diode'
elif 'nfet_' in devicename:
devicetype = 'nfet'
elif 'pfet_' in devicename:
devicetype = 'pfet'
elif 'pnp_' in devicename:
devicetype = 'pnp'
elif 'npn_' in devicename:
devicetype = 'npn'
elif 'res_' in devicename:
devicetype = 'resistor'
else:
print('Unknown device type for device name ' + devicename + '. Cannot simulate.')
return -1
print('Diagnostic: Determined device ' + devicename + ' to be type ' + devicetype)
if devicetype in ('nfet', 'pfet'):
genspice(outdir, devicetype + '_iv.spice', devicename, version, corner)
genspice(outdir, devicetype + '_vth.spice', devicename, version, corner)
genmake(
outdir,
{
devicetype + '_iv.spice' : 'plot_mostfet_iv',
devicetype + '_vth.spice': '',
},
)
elif devicetype in ('npn', 'pnp'):
genspice(outdir, devicetype + '_iv.spice', devicename, version, corner)
genspice(outdir, devicetype + '_beta.spice', devicename, version, corner)
genmake(
outdir,
{
devicetype + '_iv.spice' : 'plot_bipolar_iv',
devicetype + '_beta.spice': 'plot_bipolar_beta',
},
)
elif devicetype == 'mimcap':
genspice(outdir, 'cap_mim_value.spice', devicename, version, corner)
genmake(
outdir,
{
'cap_mim_value.spice': None,
},
)
elif devicetype == 'capacitor':
genspice(outdir, 'cap_vpp_value.spice', devicename, version, corner)
genmake(
outdir,
{
'cap_vpp_value.spice': None,
},
)
elif devicetype == 'resistor':
genspice(outdir, 'res_value.spice', devicename, version, corner)
genmake(
outdir,
{
'res_value.spice': None,
},
)
elif devicetype in ('diode', 'diode_dev'):
genspice(outdir, devicetype + '_vth.spice', devicename, version, corner)
genmake(
outdir,
{
devicetype + '_iv.spice': 'plot_diode_iv',
},
)
#------------------------------------------------------------------------------
# Main script starts here (no arguments, at least for now)
#------------------------------------------------------------------------------
def main(d):
# To do: Loop through version and corner. For now, fixed.
version = 'v0.20.1'
corner = 'tt'
device = os.path.basename(d)
dp = os.path.abspath(d)
if not os.path.isdir(dp):
print("Skipping:", dp)
return 0
do_for_device(dp,device,version,corner)
return 0
for c in sorted(os.listdir(dp)):
if not os.path.isdir(c):
print("Skipping:", c)
continue
cp = os.path.join(dp, c)
if __name__ == "__main__":
for a in sys.argv[1:]:
r = main(a)
if r != 0:
sys.exit(r)
sys.exit(0)