Modified the spectre_to_spice.py script to remove a specific use of "m" in expressions, which might be incorrect to begin with.
diff --git a/common/spectre_to_spice.py b/common/spectre_to_spice.py index fdbfe31..8b22a6d 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,45 @@ # 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) + + # Use of "m" in parameters is forbidden. Specifically look for "{N*m}". + # e.g., replace "mult = {2*m}" with "mult = 2". Note that this usage + # is most likely an error in the source. + + finalline = re.sub('\{([0-9]+)\*[mM]\}', r'\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 +397,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 +573,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 +588,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 +685,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: