Added the SRAM build space library to the paths that magic
recognizes on startup. Added a custom script to extend the upper
length bound of the special_pfet_pass device, so that the device
found in the dual-port SRAM bit cell layout has a valid model.
Additional minor updates to the ongoing work to revive CACE.
diff --git a/VERSION b/VERSION
index 2b52611..b2768ea 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.399
+1.0.400
diff --git a/runtime/cace_gensim.py b/runtime/cace_gensim.py
index 229db25..8ac5c4e 100755
--- a/runtime/cace_gensim.py
+++ b/runtime/cace_gensim.py
@@ -69,6 +69,7 @@
import faulthandler
from functools import reduce
from spiceunits import spice_unit_convert
+from spiceunits import numeric
# Application path (path where this script is located)
apps_path = os.path.realpath(os.path.dirname(__file__))
@@ -177,9 +178,9 @@
# floating-point numeric sequence generators, to be used with condition generator
def linseq(condition, unit, start, stop, step):
- a = float(start)
- e = float(stop)
- s = float(step)
+ a = numeric(start)
+ e = numeric(stop)
+ s = numeric(step)
while (a < e + s):
if (a > e):
yield (condition, unit, stop)
@@ -188,9 +189,9 @@
a = a + s
def logseq(condition, unit, start, stop, step):
- a = float(start)
- e = float(stop)
- s = float(step)
+ a = numeric(start)
+ e = numeric(stop)
+ s = numeric(step)
while (a < e * s):
if (a > e):
yield (condition, unit, stop)
@@ -312,7 +313,7 @@
if 'target' in prec:
pmax = prec['target']
try:
- maxval = float(spice_unit_convert([simunit, pmax], 'time'))
+ maxval = numeric(spice_unit_convert([simunit, pmax], 'time'))
found = True
except:
pass
@@ -321,7 +322,7 @@
if 'target' in prec:
ptyp = prec['target']
try:
- maxval = float(spice_unit_convert([simunit, ptyp], 'time'))
+ maxval = numeric(spice_unit_convert([simunit, ptyp], 'time'))
found = True
except:
pass
@@ -330,7 +331,7 @@
if 'target' in prec:
pmin = prec['target']
try:
- maxval = float(spice_unit_convert([simunit, pmin], 'time'))
+ maxval = numeric(spice_unit_convert([simunit, pmin], 'time'))
found = True
except:
pass
@@ -343,13 +344,13 @@
condunit = cond['unit']
maxval = 0.0
if 'max' in cond:
- maxval = float(spice_unit_convert([condunit, cond['max']], 'time'))
+ maxval = numeric(spice_unit_convert([condunit, cond['max']], 'time'))
elif 'enum' in cond:
- maxval = float(spice_unit_convert([condunit, cond['enum'][-1]], 'time'))
+ maxval = numeric(spice_unit_convert([condunit, cond['enum'][-1]], 'time'))
elif 'typ' in cond:
- maxval = float(spice_unit_convert([condunit, cond['typ']], 'time'))
+ maxval = numeric(spice_unit_convert([condunit, cond['typ']], 'time'))
elif 'min' in cond:
- maxval = float(spice_unit_convert([condunit, cond['min']], 'time'))
+ maxval = numeric(spice_unit_convert([condunit, cond['min']], 'time'))
if maxval > maxtime:
maxtime = maxval
@@ -599,7 +600,7 @@
sys.stdout.buffer.write(ptext.encode('utf-8'))
else:
units = simrec[1]
- lvals.append(float(simrec[2]))
+ lvals.append(numeric(simrec[2]))
simval.remove(simrec)
# Remove non-unique entries from lvals
@@ -735,7 +736,7 @@
watchend = smatch.start()
ltok = subsline[0:watchend].replace('=', ' = ').split()
ntok = ltok[:-2]
- ntok.append(str(float(ltok[-2]) + float(ltok[-1])))
+ ntok.append(str(numeric(ltok[-2]) + numeric(ltok[-1])))
subsline = ' '.join(ntok).replace(' = ', '=') + line[patmatch.end():]
repl = ''
no_repl_ok = True
@@ -744,7 +745,7 @@
watchend = smatch.start()
ltok = subsline[0:watchend].replace('=', ' = ').split()
ntok = ltok[:-2]
- ntok.append(str(float(ltok[-2]) - float(ltok[-1])))
+ ntok.append(str(numeric(ltok[-2]) - numeric(ltok[-1])))
subsline = ' '.join(ntok).replace(' = ', '=') + line[patmatch.end():]
repl = ''
no_repl_ok = True
@@ -753,7 +754,7 @@
watchend = smatch.start()
ltok = subsline[0:watchend].replace('=', ' = ').split()
ntok = ltok[:-2]
- ntok.append(str(float(ltok[-2]) * float(ltok[-1])))
+ ntok.append(str(numeric(ltok[-2]) * numeric(ltok[-1])))
subsline = ' '.join(ntok).replace(' = ', '=') + line[patmatch.end():]
repl = ''
no_repl_ok = True
@@ -762,7 +763,7 @@
watchend = smatch.start()
ltok = subsline[0:watchend].replace('=', ' = ').split()
ntok = ltok[:-2]
- ntok.append(str(float(ltok[-2]) / float(ltok[-1])))
+ ntok.append(str(numeric(ltok[-2]) / numeric(ltok[-1])))
subsline = ' '.join(ntok).replace(' = ', '=') + line[patmatch.end():]
repl = ''
no_repl_ok = True
@@ -771,7 +772,7 @@
watchend = smatch.start()
ltok = subsline[0:watchend].replace('=', ' = ').split()
ntok = ltok[:-2]
- ntok.append(str(max(float(ltok[-2]), float(ltok[-1]))))
+ ntok.append(str(max(numeric(ltok[-2]), numeric(ltok[-1]))))
subsline = ' '.join(ntok).replace(' = ', '=') + line[patmatch.end():]
repl = ''
no_repl_ok = True
@@ -780,7 +781,7 @@
watchend = smatch.start()
ltok = subsline[0:watchend].replace('=', ' = ').split()
ntok = ltok[:-2]
- ntok.append(str(min(float(ltok[-2]), float(ltok[-1]))))
+ ntok.append(str(min(numeric(ltok[-2]), numeric(ltok[-1]))))
subsline = ' '.join(ntok).replace(' = ', '=') + line[patmatch.end():]
repl = ''
no_repl_ok = True
@@ -790,7 +791,17 @@
watchend = smatch.start()
ltok = subsline[0:watchend].replace('=', ' = ').split()
ntok = ltok[:-1]
- ntok.append(str(-float(ltok[-1])))
+ ntok.append(str(-numeric(ltok[-1])))
+ subsline = ' '.join(ntok).replace(' = ', '=') + line[patmatch.end():]
+ repl = ''
+ no_repl_ok = True
+ # 'INT' also acts on only the previous value in the string.
+ elif condition == 'INT':
+ smatch = varex.search(subsline)
+ watchend = smatch.start()
+ ltok = subsline[0:watchend].replace('=', ' = ').split()
+ ntok = ltok[:-1]
+ ntok.append(str(int(ltok[-1])))
subsline = ' '.join(ntok).replace(' = ', '=') + line[patmatch.end():]
repl = ''
no_repl_ok = True
diff --git a/runtime/spiceunits.py b/runtime/spiceunits.py
index 87d341e..b3b2958 100755
--- a/runtime/spiceunits.py
+++ b/runtime/spiceunits.py
@@ -60,6 +60,18 @@
"": "none"
}
+# Convert string to either integer or float, with priority on integer
+# If argument is not a string, just return the argument.
+
+def numeric(s):
+ if isinstance(s, str):
+ try:
+ return int(s)
+ except ValueError:
+ return float(s)
+ else:
+ return s
+
# Define how to convert SI units to spice values
#
# NOTE: spice_unit_unconvert can act on a tuple of (units, value) where
@@ -79,20 +91,20 @@
# Recursive handling of '/' and multiplicatioon dot in expressions
if '/' in valuet[0]:
parts = valuet[0].split('/', 1)
- result = float(spice_unit_convert([parts[0], valuet[1]], restrict))
- result /= float(spice_unit_convert([parts[1], "1.0"], restrict))
+ result = numeric(spice_unit_convert([parts[0], valuet[1]], restrict))
+ result /= numeric(spice_unit_convert([parts[1], "1.0"], restrict))
return str(result)
if '\u22c5' in valuet[0]: # multiplication dot
parts = valuet[0].split('\u22c5')
- result = float(spice_unit_convert([parts[0], valuet[1]], restrict))
- result *= float(spice_unit_convert([parts[1], "1.0"], restrict))
+ result = numeric(spice_unit_convert([parts[0], valuet[1]], restrict))
+ result *= numeric(spice_unit_convert([parts[1], "1.0"], restrict))
return str(result)
if '\u00b2' in valuet[0]: # squared
part = valuet[0].split('\u00b2')[0]
- result = float(spice_unit_unconvert([part, valuet[1]], restrict))
- result *= float(spice_unit_unconvert([part, "1.0"], restrict))
+ result = numeric(spice_unit_unconvert([part, valuet[1]], restrict))
+ result *= numeric(spice_unit_unconvert([part, "1.0"], restrict))
return str(result)
if valuet[0] == "": # null case, no units
@@ -111,15 +123,15 @@
if re.match('^' + prerec + unitrec + '$', valuet[0]):
if restrict:
if unittypes[unitrec] == restrict.lower():
- newvalue = float(valuet[1]) * prefixtypes[prerec]
+ newvalue = numeric(valuet[1]) * prefixtypes[prerec]
return str(newvalue)
else:
- newvalue = float(valuet[1]) * prefixtypes[prerec]
+ newvalue = numeric(valuet[1]) * prefixtypes[prerec]
return str(newvalue)
# Check for "%", which can apply to anything.
if valuet[0][0] == '%':
- newvalue = float(valuet[1]) * 0.01
+ newvalue = numeric(valuet[1]) * 0.01
return str(newvalue)
if restrict:
diff --git a/sky130/custom/scripts/rename_cells.py b/sky130/custom/scripts/rename_cells.py
index ae8ff89..8bc5cba 100755
--- a/sky130/custom/scripts/rename_cells.py
+++ b/sky130/custom/scripts/rename_cells.py
@@ -69,6 +69,11 @@
fixedline = re.sub('^(.subckt .*)( ad=0 .*)( mf=1)(.*)',
'\g<1> nf=1\g<2>\g<4>', fixedline)
+ # This substitution extends the special_pfet_pass model length limits
+ # to cover the device found in the dual-port SRAM library.
+ fixedline = re.sub('lmin = 0.25e-007 lmax = 0.5e-007',
+ 'lmin = 0.245e-007 lmax = 0.805e-007', fixedline)
+
fixedlines.append(fixedline)
if fixedline != line:
modified = True
diff --git a/sky130/magic/sky130.magicrc b/sky130/magic/sky130.magicrc
index b2cde20..6138b58 100644
--- a/sky130/magic/sky130.magicrc
+++ b/sky130/magic/sky130.magicrc
@@ -70,6 +70,7 @@
addpath ${PDK_ROOT}/TECHNAME/libs.ref/${MAGTYPE}/sky130_osu_sc
addpath ${PDK_ROOT}/TECHNAME/libs.ref/${MAGTYPE}/sky130_osu_sc_t18
addpath ${PDK_ROOT}/TECHNAME/libs.ref/${MAGTYPE}/sky130_ml_xx_hd
+ addpath ${PDK_ROOT}/TECHNAME/libs.ref/${MAGTYPE}/sky130_fd_bd_sram
addpath ${PDK_ROOT}/TECHNAME/libs.ref/${MAGTYPE}/sky130_sram_macros
} else {
addpath ${PDK_ROOT}/TECHNAME/libs.ref/sky130_fd_pr/${MAGTYPE}
@@ -84,6 +85,7 @@
addpath ${PDK_ROOT}/TECHNAME/libs.ref/sky130_osu_sc/${MAGTYPE}
addpath ${PDK_ROOT}/TECHNAME/libs.ref/sky130_osu_sc_t18/${MAGTYPE}
addpath ${PDK_ROOT}/TECHNAME/libs.ref/sky130_ml_xx_hd/${MAGTYPE}
+ addpath ${PDK_ROOT}/TECHNAME/libs.ref/sky130_fd_bd_sram/${MAGTYPE}
addpath ${PDK_ROOT}/TECHNAME/libs.ref/sky130_sram_macros/${MAGTYPE}
}