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}
 }