Added support for bipolar transistor types (using the pwell or
nwell base layer as the transistor ID type) and bipolar transistor
extraction.
diff --git a/VERSION b/VERSION
index 15245f3..e8eb7f1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.32
+1.0.33
diff --git a/common/spectre_to_spice.py b/common/spectre_to_spice.py
index fdbfe31..6d137d5 100755
--- a/common/spectre_to_spice.py
+++ b/common/spectre_to_spice.py
@@ -104,14 +104,17 @@
rmatch = rtok.match(rest)
if rmatch:
expch = rmatch.group(1)[0]
- if (expch.isalpha() or expch == '$') and not needmore:
+ if expch == '$':
+ break
+ elif expch.isalpha() and not needmore:
break
else:
needmore = False
value += rmatch.group(1)
rest = rmatch.group(2)
- expch = rmatch.group(1).strip()
- if expch in '+-*/(){}^~!':
+ if any((c in '+-*/({^~!') for c in rmatch.group(1)[-1]):
+ needmore = True
+ if rest != '' and any((c in '+-*/(){}^~!') for c in rest[0]):
needmore = True
else:
break
@@ -121,7 +124,14 @@
elif value.strip().startswith("'"):
fmtline.append(value)
else:
- fmtline.append('{' + value + '}')
+ # It is not possible to know if a spectre expression continues
+ # on another line without some kind of look-ahead, but check
+ # if the parameter ends in an operator.
+ lastc = value.strip()[-1]
+ if any((c in '*+-/,(') for c in lastc):
+ fmtline.append('{' + value)
+ else:
+ fmtline.append('{' + value + '}')
# These parameter sub-expressions are related to monte carlo
# simulation and are incompatible with ngspice. So put them
@@ -141,15 +151,39 @@
# assumes that the parameter is always passed, and therefore must
# be part of the .subckt line. A parameter without a value is not
# legal SPICE, so supply a default value of 1.
+
pmatch = parm5rex.match(rest)
if pmatch:
- fmtline.append(pmatch.group(1) + '=1')
- ispassed = True
- rest = pmatch.group(2)
+ # NOTE: Something that is not a parameters name should be
+ # extended from the previous line. Note that this parsing
+ # is not rigorous and is possible to break. . .
+ if any((c in '+-*/(){}^~!') for c in pmatch.group(1).strip()):
+ fmtline.append(rest)
+ if not any((c in '*+-/,(') for c in rest.strip()[-1]):
+ fmtline.append('}')
+ rest = ''
+ else:
+ fmtline.append(pmatch.group(1) + '=1')
+ ispassed = True
+ rest = pmatch.group(2)
else:
break
- return ' '.join(fmtline), ispassed
+ finalline = ' '.join(fmtline)
+
+ # ngspice does not understand round(), so replace it with the equivalent
+ # floor() expression.
+
+ finalline = re.sub('round\(', 'floor(0.5+', finalline)
+
+ # use of "no" and "yes" as parameter values is not allowed in ngspice.
+
+ finalline = re.sub('sw_et[ \t]*=[ \t]*{no}', 'sw_et=0', finalline)
+ finalline = re.sub('sw_et[ \t]*=[ \t]*{yes}', 'sw_et=1', finalline)
+ finalline = re.sub('isnoisy[ \t]*=[ \t]*{no}', 'isnoisy=0', finalline)
+ finalline = re.sub('isnoisy[ \t]*=[ \t]*{yes}', 'isnoisy=1', finalline)
+
+ return finalline, ispassed
def get_param_names(line):
# Find parameter names in a ".param" line and return a list of them.
@@ -357,7 +391,7 @@
# Continue to "if inmodel == 1" block below
else:
fmtline, ispassed = parse_param_line(mmatch.group(3), True, False, True, ispassed)
- if isspectre and (modtype == 'resistor'):
+ if isspectre and (modtype == 'resistor' or modtype == 'r2'):
modtype = 'r'
modellines.append('.model ' + modname + ' ' + modtype + ' ' + fmtline)
if fmtline != '':
@@ -533,7 +567,7 @@
cmatch = cdlrex.match(line)
if not cmatch:
- if not isspectre:
+ if not isspectre or 'capacitor' in line or 'resistor' in line:
cmatch = stddevrex.match(line)
if cmatch:
@@ -548,12 +582,6 @@
elif devmodel == 'resistor':
devtype = 'r'
devmodel = ''
- elif devmodel == 'resbody':
- # This is specific to the SkyWater models; handling it
- # in a generic way would be difficult, as it would be
- # necessary to find the model and discover that the
- # model is a resistor and not a subcircuit.
- devtype = 'r'
elif devtype.lower() == 'n' or devtype.lower() == 'p':
# May be specific to SkyWater models, or is it a spectreism?
# NOTE: There is a check, below, to revisit this assignment
@@ -651,6 +679,13 @@
# Copy line as-is
spicelines.append(line)
+ # If any model lines remain at end, append them before output
+ if modellines != []:
+ for line in modellines:
+ spicelines.append(line)
+ modellines = []
+ inmodel = False
+
# Output the result to out_file.
with open(out_file, 'w') as ofile:
for line in spicelines:
diff --git a/sky130/magic/sky130.tech b/sky130/magic/sky130.tech
index 193b56f..4b5ef0e 100644
--- a/sky130/magic/sky130.tech
+++ b/sky130/magic/sky130.tech
@@ -64,6 +64,9 @@
# sky130_fd_pr__diode_pw2nd_lvt ndiodelvt low Vt n+ diff diode
# sky130_fd_pr__diode_pd2nw_lvt pdiodelvt low Vt p+ diff diode
# sky130_fd_pr__diode_pd2nw_hvt pdiodehvt high Vt p+ diff diode
+# sky130_fd_pr__npn_05v0 pbase NPN in deep nwell
+# sky130_fd_pr__npn_11v0 mvpbase thick oxide gated NPN
+# sky130_fd_pr__pnp_05v0 nbase PNP
# xcmimc1 mimcap MiM cap 1st plate
# xcmimc2 mimcap2 MiM cap 2nd plate
# mrdn rdn n+ diff resistor
@@ -104,10 +107,6 @@
# nhvnativeesd ESD native nFET
# phvesd ESD thickox pFET
# fnpass flash nFET device
-# npnpar1x* parasitic NPN
-# npn_1x1_2p0_hv thickox gated parasitic NPN
-# pnppar parasitic PNP
-# pnppar5x parasitic PNP
# xesd_ndiode_h_*** ESD n+ diode
# xesd_pdiode_h_*** ESD p+ diode
# reslocsub local substrate island indicator
@@ -162,6 +161,9 @@
-well pwell,pw
-well rpw,rpwell
-well obswell
+ -well pbase,npn
+ -well mvpbase,mvnpn
+ -well nbase,pnp
# Transistors
active nmos,ntransistor,nfet
@@ -373,7 +375,7 @@
aliases
allwellplane nwell
- allnwell nwell,obswell
+ allnwell nwell,obswell,pnp
allnfets nfet,npass,npd,scnfet,mvnfet,mvnnfet,nfetlvt,nsonos
allpfets pfet,ppu,scpfet,mvpfet,pfethvt,pfetlvt,pfetmvt
@@ -477,6 +479,10 @@
nsc ndiff_in_nwell metal1 contact_X'es
psc pdiff_in_pwell metal1 contact_X'es
+ pnp nwell ntransistor_stripes
+ npn pwell ptransistor_stripes
+ mvnpn pwell hvpdiff_mask
+
pfetlvt ptransistor ptransistor_stripes implant1
pfetmvt ptransistor ptransistor_stripes implant3
pfethvt ptransistor ptransistor_stripes implant2
@@ -656,8 +662,8 @@
#-----------------------------------------------------
connect
- *nwell,*nsd,*mvnsd,dnwell *nwell,*nsd,*mvnsd,dnwell
- pwell,*psd,*mvpsd pwell,*psd,*mvpsd
+ *nwell,*nsd,*mvnsd,dnwell,pnp *nwell,*nsd,*mvnsd,dnwell,pnp
+ pwell,*psd,*mvpsd,npn pwell,*psd,*mvpsd,npn
*li,coreli *li,coreli
*m1,m1fill *m1,m1fill
*m2,m2fill *m2,m2fill
@@ -724,7 +730,7 @@
# DNWELL
#----------------------------------------------------------------
- layer DNWELL dnwell
+ layer DNWELL dnwell,pnp
calma 64 18
layer PWRES rpw
@@ -879,6 +885,22 @@
calma 81 4
#----------------------------------------------------------------
+# NPNID and PNPID apply to bipolar transistors
+#----------------------------------------------------------------
+
+ layer NPNID
+ bloat-all npn,mvnpn dnwell
+ calma 82 20
+
+ templayer pnparea pnp
+ grow 400
+
+ layer PNPID
+ bloat-all pnparea *psd
+ or pnparea
+ calma 82 44
+
+#----------------------------------------------------------------
# RPM
#----------------------------------------------------------------
@@ -1910,8 +1932,6 @@
#endif
ignore NPC
ignore SEALID
- ignore NPNID
- ignore PNPID
ignore CAPID
ignore LDNTM
ignore HVNTM
@@ -1919,6 +1939,13 @@
ignore LOWTAPDENSITY
layer nwell NWELL,WELLTXT,WELLPIN
+ and-not PNPID
+ labels NWELL
+ labels WELLTXT text
+ labels WELLPIN port
+
+ layer pnp NWELL,WELLTXT,WELLPIN
+ and PNPID
labels NWELL
labels WELLTXT text
labels WELLPIN port
@@ -1930,6 +1957,10 @@
layer dnwell DNWELL
labels DNWELL
+ layer npn DNWELL
+ and-not NWELL
+ and NPNID
+
layer rpw PWRES
and DNWELL
labels PWRES
@@ -3246,7 +3277,7 @@
# Bipolar NPN mark
calma NPNID 82 20
# Bipolar PNP mark
- calma PNPID 82 20
+ calma PNPID 82 44
# Capacitor ID
calma CAPID 82 64
# Core area ID mark
@@ -3357,8 +3388,6 @@
calma FILLOBSM3 107 24
calma FILLOBSM4 112 4
-end
-
#-----------------------------------------------------------------------
style vendorimport
@@ -3377,8 +3406,6 @@
#endif
ignore NPC
ignore SEALID
- ignore NPNID
- ignore PNPID
ignore CAPID
ignore LDNTM
ignore HVNTM
@@ -3386,6 +3413,13 @@
ignore LOWTAPDENSITY
layer nwell NWELL,WELLTXT,WELLPIN
+ and-not PNPID
+ labels NWELL
+ labels WELLTXT port
+ labels WELLPIN port
+
+ layer pnp NWELL,WELLTXT,WELLPIN
+ and PNPID
labels NWELL
labels WELLTXT port
labels WELLPIN port
@@ -3397,6 +3431,10 @@
layer dnwell DNWELL
labels DNWELL
+ layer npn DNWELL
+ and-not NWELL
+ and NPNID
+
layer rpw PWRES
and DNWELL
labels PWRES
@@ -4713,7 +4751,7 @@
# Bipolar NPN mark
calma NPNID 82 20
# Bipolar PNP mark
- calma PNPID 82 20
+ calma PNPID 82 44
# Capacitor ID
calma CAPID 82 64
# Core area ID mark
@@ -5870,6 +5908,9 @@
device msubcircuit sky130_fd_pr__nfet_05v0_nvt mvnnfet \
*mvndiff,mvndiffres *mvndiff,mvndiffres pwell,space/w error l=l w=w
+ device msubcircuit sky130_fd_pr__npn_05v0 npn dnwell *ndiff space/w error a1=area
+ device msubcircuit sky130_fd_pr__pnp_05v0 pnp pwell,space/w *pdiff a1=area
+
device rsubcircuit short rmp \
*poly space/w,pwell,nwell error l=l w=w
device rsubcircuit short rli1 \
@@ -5928,27 +5969,27 @@
*mvpdiff nwell error l=l w=w
device subcircuit sky130-fd_pr__diode_pd2nw *pdiode \
- nwell a=a p=p
+ nwell a=area
device msubcircuit sky130_fd_pr__diode_pw2nd *ndiode \
- pwell,space/w a=a p=p
+ pwell,space/w a=area
device subcircuit pdiode_h *mvpdiode \
- nwell a=a p=p
+ nwell a=area
device msubcircuit ndiode_h *mvndiode \
- pwell,space/w a=a p=p
+ pwell,space/w a=area
# These are parasitic devices
device msubcircuit sky130_fd_pr__diode_pw2nd_lvt *ndiodelvt \
- pwell,space/w a=a p=p
+ pwell,space/w a=area
device subcircuit sky130_fd_pr__diode_pd2nw_lvt *pdiodelvt \
- nwell a=a p=p
+ nwell a=area
device subcircuit sky130_fd_pr_diode_pd2nw_hvt *pdiodehvt \
- nwell a=a p=p
+ nwell a=area
device msubcircuit sky130_fd_pr__diode_pw2nd_nvt *nndiode \
- pwell,space/w a=a p=p
+ pwell,space/w a=area
#ifdef MIM
- device subcircuit xcmimc1 *mimcap m3 nwell,pwell,space/w error a=a p=p s=subs
- device subcircuit xcmimc2 *mimcap2 m4,mimcc/m4 nwell,pwell,space/w error a=a p=p s=subs
+ device subcircuit xcmimc1 *mimcap m3 nwell,pwell,space/w error a=area s=subs
+ device subcircuit xcmimc2 *mimcap2 m4,mimcc/m4 nwell,pwell,space/w error a=area s=subs
#endif (MIM)
variants (orig)
@@ -6001,20 +6042,22 @@
device resistor mrdp_hv mvpdiffres *mvpdiff
device resistor xpwres rpw pwell
- device pdiode pdiode *pdiode nwell a=a p=p
- device ndiode ndiode *ndiode pwell,space/w a=a p=p
- device pdiode pdiode_h *mvpdiode nwell a=a p=p
- device ndiode ndiode_h *mvndiode pwell,space/w a=a p=p
+ device pdiode pdiode *pdiode nwell a=area
+ device ndiode ndiode *ndiode pwell,space/w a=area
+ device pdiode pdiode_h *mvpdiode nwell a=area
+ device ndiode ndiode_h *mvndiode pwell,space/w a=area
# These are parasitic devices
- device ndiode ndiode_lvt *ndiodelvt pwell,space/w a=a p=p
- device pdiode pdiode_lvt *pdiodelvt nwell a=a p=p
- device pdiode pdiode_hvt *pdiodehvt nwell a=a p=p
- device ndiode ndiode_native *nndiode pwell,space/w a=a p=p
+ device ndiode ndiode_lvt *ndiodelvt pwell,space/w a=area
+ device pdiode pdiode_lvt *pdiodelvt nwell a=area
+ device pdiode pdiode_hvt *pdiodehvt nwell a=area
+ device ndiode ndiode_native *nndiode pwell,space/w a=area
- device subcircuit pdiode_h *mvpdiode nwell a=a p=p
- device msubcircuit ndiode_h *mvndiode pwell,space/w a=a p=p
+ device bjt sky130_fd_pr__npn_05v0 npn dnwell *ndiff space/w error a1=area
+ device bjt sky130_fd_pr__pnp_05v0 pnp pwell,space/w *pdiff a1=area
+ device subcircuit pdiode_h *mvpdiode nwell a=area
+ device msubcircuit ndiode_h *mvndiode pwell,space/w a=area
#ifdef MIM
device capacitor xcmimc1 *mimcap *m3 1