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