10.4.1. SPICE OPUS simulator interface

This demo shows how to use the SPICE OPUS simulator interface. Let us first take a look at the files in the folder.

File demo/evaluation/01-simulator-spiceopus/cmos180n.lib defines two MOSFET models: nmosmod is a NMOS model and pmosmod is a PMOS model. A total of 5 variants of these two models are defined in the sections of the library file:

  • tm - a typical mean model

  • wp - worst power model

  • ws - worst speed model

  • wo - worst one model

  • wz - worst zero model

  • wcd - Monte Carlo model for worst case and worst case distance analysis

File demo/evaluation/01-simulator-spiceopus/mosmm.inc defines the wrappers around nmosmod and pmosmod.

* Mismatch model of NMOS and PMOS, Spice Opus
*   w, l, m    ... MOS parameters
*   vtmm, u0mm ... normalized mismatch (+1 means +1 sigma)

.subckt submodn drain gate source bulk param: w l m=1 vtmm=0 u0mm=0
.param sqrtarea=sqrt(w*l*m)
.param vvt=vtmm*(5e-3*1e-6/sqrtarea/sqrt(2))
.param vu0r=u0mm*(1.04e-2*1e-6/sqrtarea/sqrt(2))
vgmm (gate gate_int) dc={vvt}
m0 (drain gate_int source bulk) nmosmod w={w*(1+vu0r)} l={l} m={m} ad={w*0.18u} as={w*0.18u} pd={2*(w+0.18u)} ps={2*(w+0.18u)} nrs={0.18u/w} nrd={0.18u/w}
.ends

.subckt submodp drain gate source bulk param: w l m=1 vtmm=0 u0mm=0
.param sqrtarea=sqrt(w*l*m)
.param vvt=vtmm*(5.49e-3*1e-6/sqrtarea/sqrt(2))
.param vu0r=u0mm*(0.99e-2*1e-6/sqrtarea/sqrt(2))
vgmm (gate gate_int) dc={vvt}
m0 (drain gate_int source bulk) pmosmod w={w*(1+vu0r)} l={l} m={m} ad={w*0.18u} as={w*0.18u} pd={2*(w+0.18u)} ps={2*(w+0.18u)} nrs={0.18u/w} nrd={0.18u/w}
.ends

Every wrapper is a parameterized subcircuit. Parameters w, l, and m specify the channel dimensions and the device multiplier. Parameters vtmm and u0mm specify the normalized mismatch in terms of normal distribution’s standard deviation (+1 corresponds to sigma and -1 to -sigma). The typical mean model is obtained by setting vtmm and u0mm to 0.

The circuit is described in file demo/evaluation/01-simulator-spiceopus/opamp.cir.

* Simple opamp, 0.18u, 1.8V, SpiceOpus

* Any include or lib that is set from PyOPUS (specified in problem definition) 
* must not be specified here. 

* Any parameter that is set from PyOPUS (specified in problem definition) 
* must not be specified here. 

* Include files - fixed
.include 'mosmm.inc'

* Operating conditions - fixed
.param lev1=0
.param lev2=0.5
.param tstart=1e-9
.param tr=1e-9
.param tf=1e-9
.param pw=500e-9
.param ibias=1.000000000000e-004 
.param rfb=1e6
.param rin=1e6

* Design parameters - fixed
.param out_w=4.800592541419e-005
.param out_l=3.750131780858e-007
.param load_w=3.486243671853e-005
.param load_l=2.572996921261e-006
.param dif_w=7.728734451428e-006
.param dif_l=1.082371380389e-006
.param c_out=8.211596855053e-012
.param r_out=1.968986740568e+001

* inp inn out vdd vss bias slp slpx
.subckt amp 3 4 5 1 2 7 11 12
xmp1 9 10 1 1  submodp w={load_w} l={load_l} m=2
xmp2 10 10 1 1 submodp w={load_w} l={load_l} m=2
xmp1s 9 12 1 1 submodp w=1u        l=0.5u
xmp3 5 9 1 1   submodp w={out_w}   l={out_l}   m=16
xmn2 9 3 8 2   submodn w={dif_w}   l={dif_l} 
xmn3 10 4 8 2  submodn w={dif_w}   l={dif_l} 
xmn1s 7 11 2 2 submodn w=1u        l=0.5u
xmn1b 7 7 2 2  submodn w={mirr_w}  l={mirr_l}  m=2
xmn1 8 7 2 2   submodn w={mirr_w}  l={mirr_l}  m=2
xmn4 5 7 2 2   submodn w={mirr_w}  l={mirr_l}  m=16
cout 5a 9 c={c_out}
rout 5 5a r={r_out}
.ends

* Test topology
x1 (inp inn out vdd 0 bias 0 vdd) amp
vdd (vdd 0) dc={vdd}
ibias (vdd bias) dc={ibias}
rfb (out inn) r={rfb}
rin (in inn) r={rin}
vcom (inp 0) dc={vdd/2}
vin (in inp) dc=0 acmag=1 pulse=({lev1} {lev2} {tstart} {tr} {tf} {pw})
rload (out 0) r=100k
cload (out 0) c=0.5p

* This file is included in the main simulator input file. 
* Do not add .end - it is added by PyOPUS to the main input file. 

The file follows the standard SPICE OPUS netlist syntax, except for the missing .end statement which is added later by PyOPUS.

_images/tutorial.evaluation.01-simulator-spiceopus-opamp.png

The schematic of the opamp subcircuit.

_images/tutorial.evaluation.01-simulator-spiceopus-opamptb.png

The testbench circuit surrounding the opamp.

The following Python script constructs 5 OP analyses (jobs) and passes them to the simulator interface. The vdd and the temperature parameter are specified in the job descriptions. The simulator interface optimizes the order of evaluation in such manner that the number of simulator calls is minimized. During this process the jobs are grouped in job groups. The job groups are printed.

The two circuit parameters (mirr_w and mirr_l) are not specified in the netlist. They are passed to the simulator interface. Finally, every job groups is run and the results are collected. For every job some of the results are printed.

In the end all intermediate files generated by the simulator interface and the simulator are deleted.

File: demo/evaluation/01-simulator-spiceopus/runme.py

# Test SpiceOpus simulator interface

from pyopus.simulator import simulatorClass

if __name__=='__main__':
	# Job list for simulator
	jobList=[
		{	# First job - op analysis
			'name': 'dcop', 
			'definitions': [
				{ 'file': 'cmos180n.lib', 'section': 'tm' }, 
				{ 'file': 'opamp.cir' }
			], 
			'params': {
				'vdd': 1.8, 
				'temperature': 25
			}, 
			'options': {
				'method': 'trap'
			}, 
			'saves': [
			], 
			'command': 'op()'
		},
		{	# Second job - op analysis with different temperature
			'name': 'dcop100', 
			'definitions': [
				{ 'file': 'cmos180n.lib', 'section': 'tm' }, 
				{ 'file': 'opamp.cir' }
			], 
			'params': {
				'vdd': 1.6, 
				'temperature': 100
			}, 
			'options': {
				'method': 'trap'
			}, 
			'saves': [
			], 
			'command': 'op()'
		},
		{	# Third job - op analysis with different supply voltage
			'name': 'dcopv33', 
			'definitions': [
				{ 'file': 'cmos180n.lib', 'section': 'tm' }, 
				{ 'file': 'opamp.cir' }
			], 
			'params': {
				'vdd': 2.0, 
				'temperature': 25
			}, 
			'options': {
				'method': 'trap'
			}, 
			'saves': [
			], 
			'command': 'op()'
		},
		{	# Fourth job - op analysis with different library
			'name': 'dcopff', 
			'definitions': [
				{ 'file': 'cmos180n.lib', 'section': 'ws' }, 
				{ 'file': 'opamp.cir' }
			], 
			'params': {
				'vdd': 2.0, 
				'temperature': 25
			}, 
			'options': {
				'method': 'trap'
			}, 
			'saves': [
			], 
			'command': 'op()'
		}, 
		{	# Fifth job - op analysis with different library
			'name': 'dcopff100', 
			'definitions': [
				{ 'file': 'cmos180n.lib', 'section': 'ws' }, 
				{ 'file': 'opamp.cir' }
			], 
			'params': {
				'vdd': 2.0, 
				'temperature': 100
			}, 
			'options': {
				'method': 'trap'
			}, 
			'saves': [
			], 
			'command': 'op()'
		}
	]

	# Input parameters
	inParams={
		'mirr_w': 7.46e-005, 
		'mirr_l': 5.63e-007
	}

	# Create simulator
	sim=simulatorClass("SpiceOpus")(debug=10)

	# Set job list and optimize it
	sim.setJobList(jobList)

	# Print optimized job groups 
	ngroups=sim.jobGroupCount()
	print("\nJob Groups:")
	for i in range(ngroups):
		group=sim.jobGroup(i)
		gstr=''
		for j in group:
			gstr+=" %d (%s), " % (j, jobList[j]['name'])
		print("  %d: %s" % (i, gstr))

	print("")
	# Set input parameters
	sim.setInputParameters(inParams)
	
	# Go through all job groups, write file, run it and collect results
	for i in range(ngroups):
		# Run jobs in job group. 
		(jobIndices, status)=sim.runJobGroup(i)
		
		print("")
		for j in jobIndices:
			# Job name
			jobName=jobList[j]['name']
			# Load results
			res=sim.readResults(j, status)
			# Print results
			if res is not None:
				print("Job %d (%s): Vout=%e" % (j, jobName, res.v("out")))
			else:
				print("Job %d (%s): no results" % (j, jobName))
		print("")

	sim.cleanup()