Removed the "minenclosedarea" patch for the HD and HDLL libraries and moved the fix to the "fix_techlefA|B.py" scripts. This avoids the use of patch files and avoids having to re-do the patch files to deal with the change in the technology LEF files to cover process corners. Also: made some enhancements to the spectre_to_spice.py script stemming from conversion of the SkyWater continuous models.
diff --git a/VERSION b/VERSION index 2bae0e1..ca94b4b 100644 --- a/VERSION +++ b/VERSION
@@ -1 +1 @@ -1.0.297 +1.0.298
diff --git a/common/spectre_to_spice.py b/common/spectre_to_spice.py index 4243a1a..38cd2ec 100755 --- a/common/spectre_to_spice.py +++ b/common/spectre_to_spice.py
@@ -27,7 +27,7 @@ # If inside a subcircuit, remove the keyword "parameters". If outside, # change it to ".param" -def parse_param_line(line, inparam, insub, iscall, ispassed): +def parse_param_line(line, inparam, insub, iscall, ispassed, linenum): # Regexp patterns parm1rex = re.compile('[ \t]*parameters[ \t]*(.*)') @@ -69,16 +69,15 @@ return '', ispassed while rest != '': - if iscall: - # It is hard to believe that this is legal even in spectre. - # Parameter expression given with no braces or quotes around - # the expression. Fix the expression by removing the spaces - # around '*'. - rest = re.sub('[ \t]*\*[ \t]*', '*', rest) + # It is hard to believe that this is legal even in spectre. + # Parameter expression given with no braces or quotes around + # the expression. Fix the expression by removing the spaces + # around '*'. + rest = re.sub('[ \t]*([\*\+\-])[ \t]*', '\g<1>', rest) pmatch = parm4rex.match(rest) if pmatch: - if ispassed: + if ispassed and not iscall: # End of passed parameters. Break line and generate ".param" ispassed = False fmtline.append('\n.param ') @@ -97,14 +96,14 @@ # Watch for spaces in expressions (have they no rules??!) # as indicated by something after a space not being an - # alphabetical character (parameter name) or '$' (comment) + # alphabetical character (parameter name) or ';' (comment) needmore = False while rest != '': rmatch = rtok.match(rest) if rmatch: expch = rmatch.group(1)[0] - if expch == '$': + if expch == ';' or expch == '$': break elif expch.isalpha() and not needmore: break @@ -141,10 +140,10 @@ if rest != '': nmatch = parm4rex.match(rest) if not nmatch: - if rest.lstrip().startswith('$ '): + if rest.lstrip().startswith('; '): fmtline.append(rest) elif rest.strip() != '': - fmtline.append(' $ ' + rest.replace(' ', '').replace('\t', '')) + fmtline.append(' ; ' + rest.replace(' ', '').replace('\t', '')) rest = '' else: # Match to a CDL subckt parameter that does not have an '=' and so @@ -211,6 +210,40 @@ break return paramnames +# Dump any saved model lines to a list. Check for "type =" syntax in a +# binned model + +def addmodel(modellines, linenum): + typerex = re.compile('([ \t]*type[ \t]*=[ \t]*)([^ \t]+)[ \t]*', re.IGNORECASE) + + # 'ZYXW' was left as a placeholder for the device type + if len(modellines) > 0: + typename = None + for j in range(len(modellines) - 1, -1, -1): + line = modellines[j] + pmatch = typerex.search(line) + if pmatch: + typename = pmatch.group(2).strip('{}').strip() + newline = typerex.sub(' ', line) + modellines[j] = newline + line = newline + + if 'ZYXW' in line: + if typename: + if typename == 'n': + newtype = 'nmos' + elif typename == 'p': + newtype = 'pmos' + else: + newtype = typename + modellines[j] = re.sub('ZYXW', newtype, line) + typename = None + else: + print('Error: No type name for model at line ' + str(linenum)) + modellines[j] = re.sub('ZYXW', 'unknown', line) + + return modellines + # Run the spectre-to-ngspice conversion def convert_file(in_file, out_file): @@ -223,13 +256,13 @@ endsubrex = re.compile('[ \t]*ends[ \t]+(.+)') endonlysubrex = re.compile('[ \t]*ends[ \t]*') modelrex = re.compile('[ \t]*model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+\{(.*)') - cdlmodelrex = re.compile('[ \t]*model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+(.*)') - binrex = re.compile('[ \t]*([0-9]+):[ \t]+type[ \t]*=[ \t]*(.*)') + cdlmodelrex = re.compile('[ \t]*model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*(.*)') + binrex = re.compile('[ \t]*([0-9]+):[ \t]*(.*)') shincrex = re.compile('\.inc[ \t]+') isexprrex = re.compile('[^0-9a-zA-Z_]') paramrex = re.compile('\.param[ \t]+(.*)') - stdsubrex = re.compile('\.subckt[ \t]+([^ \t]+)[ \t]+(.*)') + stdsubrex = re.compile('\.?subckt[ \t]+([^ \t]+)[ \t]+(.*)') stdmodelrex = re.compile('\.model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*(.*)') stdendsubrex = re.compile('\.ends[ \t]+(.+)') stdendonlysubrex = re.compile('\.ends[ \t]*') @@ -242,7 +275,6 @@ stddev2rex = re.compile('[ \t]*([cr])([^ \t]+)[ \t]+([^ \t]+[ \t]+[^ \t]+)[ \t]+([^ \t\'{]+[\'{][^\'}]+[\'}])[ \t]*(.*)', re.IGNORECASE) stddev3rex = re.compile('[ \t]*([npcrdlmqx])([^ \t]+)[ \t]+(.*)', re.IGNORECASE) - with open(in_file, 'r') as ifile: try: speclines = ifile.read().splitlines() @@ -266,8 +298,12 @@ subnames = [] modname = '' modtype = '' + othermodnames = [] + othermodtypes = [] + linenum = 0 for line in speclines: + linenum = linenum + 1 # Item 1a. C++-style // comments get replaced with * comment character if line.strip().startswith('//'): @@ -280,13 +316,13 @@ spicelines.append(line.strip().replace('//', '*', 1)) continue - # Item 1b. In-line C++-style // comments get replaced with $ comment character + # Item 1b. In-line C++-style // comments get replaced with ; comment character elif ' //' in line: - line = line.replace(' //', ' $ ', 1) + line = line.replace(' //', ' ; ', 1) elif '//' in line: - line = line.replace('//', ' $ ', 1) + line = line.replace('//', ' ; ', 1) elif '\t//' in line: - line = line.replace('\t//', '\t$ ', 1) + line = line.replace('\t//', '\t; ', 1) # Item 2. Handle SPICE-style comment lines if line.strip().startswith('*'): @@ -338,7 +374,7 @@ if contline: if inparam: # Continue handling parameters - fmtline, ispassed = parse_param_line(line, inparam, insub, False, ispassed) + fmtline, ispassed = parse_param_line(line, inparam, insub, False, ispassed, linenum) if fmtline != '': if modellines != []: modellines.append(fmtline) @@ -362,7 +398,7 @@ # If inside a subcircuit, remove "parameters". If outside, # change it to ".param" - fmtline, ispassed = parse_param_line(line, inparam, insub, False, ispassed) + fmtline, ispassed = parse_param_line(line, inparam, insub, False, ispassed, linenum) if fmtline != '': inparam = True spicelines.append(fmtline) @@ -388,6 +424,9 @@ mmatch = stdmodelrex.match(line) if mmatch: + if modname: + othermodnames.append(modname) + othermodtypes.append(modtype) modname = mmatch.group(1) modtype = mmatch.group(2) @@ -396,9 +435,13 @@ inmodel = 1 # Continue to "if inmodel == 1" block below else: - fmtline, ispassed = parse_param_line(mmatch.group(3), True, False, True, ispassed) + fmtline, ispassed = parse_param_line(mmatch.group(3), True, False, True, ispassed, linenum) if isspectre and (modtype == 'resistor' or modtype == 'r2'): modtype = 'r' + if isspectre and (modtype == 'bsim4'): + # "bsim4"---cast to special string so that it can be later + # converted to "nmos" or "pmos" based on the "type" parameter + modtype = 'ZYXW' modellines.append('.model ' + modname + ' ' + modtype + ' ' + fmtline) if fmtline != '': inparam = True @@ -415,10 +458,9 @@ imatch = cdlsubrex.match(line) if not imatch: - if not isspectre: - # Check for standard SPICE format .subckt lines - imatch = stdsubrex.match(line) - + # Check for standard SPICE format .subckt lines + # or CDL format subckt line without parentheses + imatch = stdsubrex.match(line) if imatch: # If a model block is pending, then dump it if modellines != []: @@ -432,16 +474,15 @@ subname = imatch.group(1) subnames.append(subname) if isspectre: - devrex = re.compile(subname + '[ \t]*\(([^)]*)\)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE) + devrex = re.compile('[ \t]*' + subname + '[ \t]*\(([^)]*)\)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE) else: - devrex = re.compile(subname + '[ \t]*([^ \t]+)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE) + devrex = re.compile('[ \t]*' + subname + '[ \t]*([^ \t]+)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE) # If there is no close-parenthesis then we should expect it on # a continuation line inpinlist = True if ')' not in line else False # Remove parentheses groups from subcircuit arguments spicelines.append('.subckt ' + ' ' + subname + ' ' + imatch.group(2)) continue - else: # Things to parse when inside of an "inline subckt" block @@ -476,29 +517,58 @@ print('Error: "ends" name does not match "subckt" name!') print('"ends" name = ' + endname) print('"subckt" name = ' + subname) - if len(calllines) > 0: - line = calllines[0] - if modtype.startswith('bsim'): - line = 'M' + line - elif modtype.startswith('nmos'): - line = 'M' + line - elif modtype.startswith('pmos'): - line = 'M' + line - elif modtype.startswith('res'): - line = 'R' + line - elif modtype.startswith('cap'): - line = 'C' + line - elif modtype.startswith('pnp'): - line = 'Q' + line - elif modtype.startswith('npn'): - line = 'Q' + line - elif modtype.startswith('d'): - line = 'D' + line - spicelines.append(line) + if modname: + othermodnames.append(modname) + othermodtypes.append(modtype) - for line in calllines[1:]: - spicelines.append(line) - calllines = [] + for line in calllines: + modified = False + for j in range(len(othermodnames)): + if othermodnames[j] in line: + modtype = othermodtypes[j] + if modtype.startswith('bsim'): + line = 'M' + line + modified = True + elif modtype.startswith('nmos'): + line = 'M' + line + modified = True + elif modtype.startswith('pmos'): + line = 'M' + line + modified = True + elif modtype.startswith('res'): + line = 'R' + line + modified = True + elif modtype.startswith('cap'): + line = 'C' + line + modified = True + elif modtype.startswith('pnp'): + line = 'Q' + line + modified = True + elif modtype.startswith('npn'): + line = 'Q' + line + modified = True + elif modtype.startswith('d'): + line = 'D' + line + modified = True + elif modtype.startswith('ZYXW'): + line = 'M' + line + modified = True + else: + print('Error: No prefix at line ' + str(linenum)) + print(' Model type is ' + modtype) + if modified: + break + if not modified: + # Also check for "standard" models, e.g. "resistor" + pnames = line.split() + if 'resistor' in pnames[1:]: + pnames.remove('resistor') + line = 'R' + ' '.join(pnames) + elif 'capacitor' in pnames[1:]: + pnames.remove('capacitor') + line = 'C' + ' '.join(pnames) + spicelines.append(line) + calllines = [] # Last check: Do any model types confict with the way they # are called within the subcircuit? Spectre makes it very @@ -529,16 +599,18 @@ # Now add any in-circuit models spicelines.append('') - for line in modellines: - spicelines.append(line) + spicelines.extend(addmodel(modellines, linenum)) modellines = [] # Complete the subcircuit definition spicelines.append('.ends ' + subname) - insub = False inmodel = False subname = '' + modname = '' + modtype = '' + othermodnames = [] + othermodtypes = [] paramnames = [] continue @@ -551,7 +623,7 @@ # Check for devices R and C. dmatch = caprex.match(line) if dmatch: - fmtline, ispassed = parse_param_line(dmatch.group(3), True, insub, True, ispassed) + fmtline, ispassed = parse_param_line(dmatch.group(3), True, insub, True, ispassed, linenum) if fmtline != '': inparam = True spicelines.append('c' + dmatch.group(1) + ' ' + dmatch.group(2) + ' ' + fmtline) @@ -562,7 +634,7 @@ dmatch = resrex.match(line) if dmatch: - fmtline, ispassed = parse_param_line(dmatch.group(3), True, insub, True, ispassed) + fmtline, ispassed = parse_param_line(dmatch.group(3), True, insub, True, ispassed, linenum) if fmtline != '': inparam = True spicelines.append('r' + dmatch.group(1) + ' ' + dmatch.group(2) + ' ' + fmtline) @@ -598,7 +670,7 @@ # it must be enclosed in single quotes. Otherwise, if the named # device model is a subcircuit, then the devtype must be "x". - elif devtype.lower() == 'c' or devtype.lower() == 'r': + elif devtype.lower() == 'c' or devtype.lower() == 'r' or devtype.lower() == 'd': if devmodel in subnames: devtype = 'x' + devtype else: @@ -622,7 +694,7 @@ if devmodel.strip("'") == devmodel: devmodel = "'" + devmodel + "'" - fmtline, ispassed = parse_param_line(cmatch.group(5), True, insub, True, ispassed) + fmtline, ispassed = parse_param_line(cmatch.group(5), True, insub, True, ispassed, linenum) if fmtline != '': inparam = True spicelines.append(devtype + cmatch.group(2) + ' ' + cmatch.group(3) + ' ' + devmodel + ' ' + fmtline) @@ -640,12 +712,13 @@ dmatch = devrex.match(line) if dmatch: - fmtline, ispassed = parse_param_line(dmatch.group(3), True, insub, True, ispassed) + fmtline, ispassed = parse_param_line(dmatch.group(3), True, insub, True, ispassed, linenum) if fmtline != '': inparam = True calllines.append(subname + ' ' + dmatch.group(1) + ' ' + dmatch.group(2) + ' ' + fmtline) continue else: + inparam = True calllines.append(subname + ' ' + dmatch.group(1) + ' ' + dmatch.group(2) + ' ' + dmatch.group(3)) continue @@ -659,39 +732,65 @@ if bmatch: bin = bmatch.group(1) - type = bmatch.group(2) - - if type == 'n': - convtype = 'nmos' - elif type == 'p': - convtype = 'pmos' - else: - convtype = type + rest = bmatch.group(2) # If there is a binned model then it replaces any original # model line that was saved. if modellines[-1].startswith('.model'): modellines = modellines[0:-1] modellines.append('') - modellines.append('.model ' + modname + '.' + bin + ' ' + convtype) - continue + modellines.append('.model ' + modname + '.' + bin + ' ZYXW') - else: - fmtline, ispassed = parse_param_line(line, True, True, False, ispassed) - if fmtline != '': - modellines.append(fmtline) + if rest != '': + # Somehow model numbers are allowed to break syntax and + # not start a new line with a continuation character. + if rest[0] == '+': + line = rest + else: + line = '+' + rest + else: continue + fmtline, ispassed = parse_param_line(line, True, True, False, ispassed, linenum) + if fmtline != '': + modellines.append(fmtline) + continue + # 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) + spicelines.extend(addmodel(modellines, linenum)) modellines = [] inmodel = False + # Catching the spectre use of "m" is difficult, so do a 2nd pass + # on "spicelines" to catch which subcircuits use "*m" expressions, + # then for those subcircuits, add "mult=1" to the subcircuit + # parameters. (NOTE: Need a more generic regular expression here) + + sqrtrex = re.compile('.*(sqrt\([ \t]*[^ \t]+[ \t]*\*[ \t]*)m[ \t]*\)', re.IGNORECASE) + sqsubrex = re.compile('(sqrt\([ \t]*[^ \t]+[ \t]*\*[ \t]*)m[ \t]*\)', re.IGNORECASE) + subrex = re.compile('\.subckt[ \t]+([^ \t\(]+)[ \t]*') + needmult = [] + for j in range(len(spicelines)): + line = spicelines[j] + smatch = subrex.match(line) + if smatch: + cursub = smatch.group(1) + smatch = sqrtrex.match(line) + if smatch: + spicelines[j] = sqsubrex.sub('\g<1>mult)', line) + needmult.append(cursub) + + # Now add "mult=1" parameter to any subcircuit in the "needmult" list + for j in range(len(spicelines)): + line = spicelines[j] + smatch = subrex.match(line) + if smatch: + spicelines[j] = line + ' mult=1' + # Output the result to out_file. with open(out_file, 'w') as ofile: for line in spicelines:
diff --git a/sky130/Makefile.in b/sky130/Makefile.in index 6715ffa..07ca4c4 100644 --- a/sky130/Makefile.in +++ b/sky130/Makefile.in
@@ -1275,9 +1275,6 @@ # the libraries ${RM} ${STAGING_PATH}/${SKY130$*}/libs.ref/${HD_VERILOG}/*.*.v # Apply extra PDK patches until they get fixed properly in the source - ${PATCH} -p1 -f -d ${STAGING_PATH}/${SKY130$*}/libs.ref/${HD_TECHLEF} \ - < custom/patches/hd_minenclosed.squeaky.patch \ - 2>&1 | tee -a ${SKY130$*}_make.log || true ${PATCH} -p1 -f -d ${STAGING_PATH}/${SKY130$*}/libs.ref/${HD_VERILOG} \ < custom/patches/hd_wire_syntax.patch \ 2>&1 | tee -a ${SKY130$*}_make.log || true @@ -1315,10 +1312,6 @@ # Remove the base verilog files which have already been included into # the libraries ${RM} ${STAGING_PATH}/${SKY130$*}/libs.ref/${HDLL_VERILOG}/*.*.v - # Apply extra PDK patches until they get fixed properly in the source - ${PATCH} -p1 -f -d ${STAGING_PATH}/${SKY130$*}/libs.ref/${HDLL_TECHLEF} \ - < custom/patches/hdll_minenclosed.squeaky.patch \ - 2>&1 | tee -a ${SKY130$*}_make.log || true digital-hvl-%: # Install custom additions to standard cell libraries
diff --git a/sky130/custom/patches/hd_minenclosed.squeaky.patch b/sky130/custom/patches/hd_minenclosed.squeaky.patch deleted file mode 100644 index 64376e7..0000000 --- a/sky130/custom/patches/hd_minenclosed.squeaky.patch +++ /dev/null
@@ -1,20 +0,0 @@ -diff --git a/sky130_fd_sc_hd.tlef b/sky130_fd_sc_hd.tlef -index 1c913ba..815b750 100644 ---- a/sky130_fd_sc_hd.tlef -+++ b/sky130_fd_sc_hd.tlef -@@ -107,6 +107,7 @@ LAYER met1 - WIDTH 3 0.28 ; - AREA 0.083 ; # Met1 6 - THICKNESS 0.35 ; -+ MINENCLOSEDAREA 0.14 ; - - ANTENNAMODEL OXIDE1 ; - ANTENNADIFFSIDEAREARATIO PWL ( ( 0 400 ) ( 0.0125 400 ) ( 0.0225 2609 ) ( 22.5 11600 ) ) ; -@@ -149,6 +150,7 @@ LAYER met2 - WIDTH 3 0.28 ; - AREA 0.0676 ; # Met2 6 - THICKNESS 0.35 ; -+ MINENCLOSEDAREA 0.14 ; - - EDGECAPACITANCE 37.759E-6 ; - CAPACITANCE CPERSQDIST 16.9423E-6 ;
diff --git a/sky130/custom/patches/hdll_minenclosed.squeaky.patch b/sky130/custom/patches/hdll_minenclosed.squeaky.patch deleted file mode 100644 index 5d8dba5..0000000 --- a/sky130/custom/patches/hdll_minenclosed.squeaky.patch +++ /dev/null
@@ -1,21 +0,0 @@ -diff --git a/sky130_fd_sc_hdll.tlef b/sky130_fd_sc_hdll.tlef -index 1c913ba..815b750 100644 ---- a/sky130_fd_sc_hdll.tlef -+++ b/sky130_fd_sc_hdll.tlef -@@ -107,6 +107,7 @@ LAYER met1 - WIDTH 3 0.28 ; - AREA 0.083 ; # Met1 6 - THICKNESS 0.35 ; -+ MINENCLOSEDAREA 0.14 ; - - ANTENNAMODEL OXIDE1 ; - ANTENNADIFFSIDEAREARATIO PWL ( ( 0 400 ) ( 0.0125 400 ) ( 0.0225 2609 ) ( 22.5 11600 ) ) ; -@@ -149,6 +150,7 @@ LAYER met2 - WIDTH 3 0.28 ; - AREA 0.0676 ; # Met2 6 - THICKNESS 0.35 ; -+ MINENCLOSEDAREA 0.14 ; - - EDGECAPACITANCE 37.759E-6 ; - CAPACITANCE CPERSQDIST 16.9423E-6 ; -
diff --git a/sky130/custom/scripts/fix_techlefA.py b/sky130/custom/scripts/fix_techlefA.py index fa992d9..6c61f54 100755 --- a/sky130/custom/scripts/fix_techlefA.py +++ b/sky130/custom/scripts/fix_techlefA.py
@@ -45,9 +45,19 @@ resrex = re.compile('[ \t]*ENCLOSURE ABOVE') layerrex = re.compile('[ \t]*LAYER ([^ \t\n]+)') resrex2 = re.compile('[ \t]*RESISTANCE RPERSQ 12.2 ;') + thickrex = re.compile('[ \t]*THICKNESS') + emptyrex = re.compile('^[ \t]*$') curlayer = None + thickness_seen = False for line in llines: + if thickness_seen: + thickness_seen = False + if curlayer and (curlayer == 'met1' or curlayer == 'met2'): + ematch = emptyrex.match(line) + if ematch: + fixedlines.append(' MINENCLOSEDAREA 0.14 ;') + rmatch = resrex2.match(line) if rmatch: fixedlines.append(' RESISTANCE RPERSQ 12.8 ;') @@ -72,6 +82,10 @@ if lmatch: curlayer = lmatch.group(1) + tmatch = thickrex.match(line) + if tmatch: + thickness_seen = True + # Write output if outname == None: for i in fixedlines:
diff --git a/sky130/custom/scripts/fix_techlefB.py b/sky130/custom/scripts/fix_techlefB.py index 731851d..f34b51b 100755 --- a/sky130/custom/scripts/fix_techlefB.py +++ b/sky130/custom/scripts/fix_techlefB.py
@@ -62,9 +62,18 @@ resrex = re.compile('[ \t]*ENCLOSURE ABOVE') layerrex = re.compile('[ \t]*LAYER ([^ \t\n]+)') resrex2 = re.compile('[ \t]*RESISTANCE RPERSQ 12.2 ;') + thickrex = re.compile('[ \t]*THICKNESS') + emptyrex = re.compile('^[ \t]*$') curlayer = None + thickness_seen = False for line in llines: + if thickness_seen: + thickness_seen = False + if curlayer and (curlayer == 'met1' or curlayer == 'met2'): + ematch = emptyrex.match(line) + if ematch: + fixedlines.append(' MINENCLOSEDAREA 0.14 ;') # Check for the MANUFACTURINGGRID statement in the file, and # add the USEMINSPACING statement after it.
diff --git a/sky130/custom/scripts/mismatch_params.py b/sky130/custom/scripts/mismatch_params.py index 0053542..c9388cc 100755 --- a/sky130/custom/scripts/mismatch_params.py +++ b/sky130/custom/scripts/mismatch_params.py
@@ -36,7 +36,7 @@ mismatch_params = [] -mmrex = re.compile('^\*[ \t]*mismatch[ \t]+\{') +mmrex = re.compile('^\*[ \t]*mismatch[ \t]*\{') endrex = re.compile('^\*[ \t]*\}') filelist = [] @@ -72,10 +72,32 @@ tokens = line.split() if 'vary' in tokens: if ('dist=gauss' in tokens) or ('gauss' in tokens): + gtype = 'A' mismatch_param = tokens[2] - std_dev = float(tokens[-1].split('=')[-1]) - replacement = '{}*AGAUSS(0,{!s},1)'.format(mm_switch_param, std_dev) + for token in tokens[3:]: + gparam = token.split('=') + if len(gparam) == 2: + if gparam[0] == 'std': + std_dev = float(gparam[1]) + elif gparam[0] == 'percent' and gparam[1] == 'yes': + gtype = '' + + if gtype == '': + # Convert percentage to a fraction + std_dev = std_dev / 100 + repltext = '{}*' + gtype + 'GAUSS(0,{!s},1)' + replacement = repltext.format(mm_switch_param, std_dev) mismatch_params.append((mismatch_param, replacement)) + elif ('dist=lnorm' in tokens) or ('lnorm' in tokens): + mismatch_param = tokens[2] + for token in tokens[3:]: + gparam = token.split('=') + if len(gparam) == 2: + if gparam[0] == 'std': + std_dev = float(gparam[1]) + replacement = '{}*EXP(AGAUSS(0,{!s},1))'.format(mm_switch_param, std_dev) + mismatch_params.append((mismatch_param, replacement)) + infile.close()
diff --git a/sky130/custom/scripts/pdk_update.sh b/sky130/custom/scripts/pdk_update.sh index 47910b2..c6bb970 100755 --- a/sky130/custom/scripts/pdk_update.sh +++ b/sky130/custom/scripts/pdk_update.sh
@@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # pdk_update.sh -- # @@ -8,8 +8,8 @@ # Usage: pdk_update.sh <directory> # -if [ ! test -d $1 ] ; then - echo "Project does not exist in $pdir ; Cannot update." +if [ ! -d $1 ] ; then + echo "Project does not exist in $1 ; Cannot update." exit 0 fi
diff --git a/sky130/custom/scripts/process_params.py b/sky130/custom/scripts/process_params.py index c27840a..9cfc122 100755 --- a/sky130/custom/scripts/process_params.py +++ b/sky130/custom/scripts/process_params.py
@@ -37,7 +37,7 @@ process_params = [] parmrex = re.compile('^\.param[ \t]+') -prrex = re.compile('^\*[ \t]*process[ \t]+\{') +prrex = re.compile('^\*[ \t]*process[ \t]*\{') endrex = re.compile('^\*[ \t]*\}') filelist = [] @@ -73,10 +73,31 @@ tokens = line.split() if 'vary' in tokens: if ('dist=gauss' in tokens) or ('gauss' in tokens): + gtype = 'A' process_param = tokens[2] - std_dev = float(tokens[-1].split('=')[-1]) - replacement = ' + {}*AGAUSS(0,{!s},1)'.format(pr_switch_param, std_dev) + for token in tokens[3:]: + gparam = token.split('=') + if len(gparam) == 2: + if gparam[0] == 'std': + std_dev = float(gparam[1]) + elif gparam[0] == 'percent' and gparam[1] == 'yes': + gtype = '' + if gtype == '': + # Convert percentage to a fraction + std_dev = std_dev / 100 + repltext = ' + {}*' + gtype + 'GAUSS(0,{!s},1)' + replacement = repltext.format(pr_switch_param, std_dev) process_params.append((process_param, replacement)) + elif ('dist=lnorm' in tokens) or ('lnorm' in tokens): + process_param = tokens[2] + for token in tokens[3:]: + gparam = token.split('=') + if len(gparam) == 2: + if gparam[0] == 'std': + std_dev = float(gparam[1]) + replacement = ' + {}*EXP(AGAUSS(0,{!s},1))'.format(pr_switch_param, std_dev) + process_params.append((process_param, replacement)) + infile.close()
diff --git a/sky130/qflow/sky130.sh b/sky130/qflow/sky130.sh index 31a1fc9..effc569 100644 --- a/sky130/qflow/sky130.sh +++ b/sky130/qflow/sky130.sh
@@ -32,9 +32,9 @@ #ifdef METAL5 #ifdef EF_FORMAT -set techleffile=STAGING_PATH/TECHNAME/libs.ref/techLEF/LIBRARY/LIBRARY.tlef +set techleffile=STAGING_PATH/TECHNAME/libs.ref/techLEF/LIBRARY/LIBRARY__nom.tlef #else (!EF_FORMAT) -set techleffile=STAGING_PATH/TECHNAME/libs.ref/LIBRARY/techlef/LIBRARY.tlef +set techleffile=STAGING_PATH/TECHNAME/libs.ref/LIBRARY/techlef/LIBRARY__nom.tlef #endif (!EF_FORMAT) #else # NOTE: There is no technology LEF file for the 3-metal stack!