moving scripts into separate repo
This commit is contained in:
commit
0f50dcaab0
179
hspice2xyce
Executable file
179
hspice2xyce
Executable file
@ -0,0 +1,179 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
class StackElem:
|
||||
def __init__(self, parent):
|
||||
self.parent = parent
|
||||
self.methods = set()
|
||||
|
||||
def emitOperation(number, command, operation, stack):
|
||||
if command in [".prot", ".protect", ".unprot", ".unprotect"]:
|
||||
return # Xyce does not support these commands
|
||||
elif command == ".option":
|
||||
operation = fixOption(number, operation, stack)
|
||||
else:
|
||||
operation = fixParams(number, operation, stack)
|
||||
|
||||
if len(operation) > 0:
|
||||
print("\n".join(operation))
|
||||
|
||||
def emitFunction(name, args, definition):
|
||||
print(".func " + name + args + " {" + definition + "}")
|
||||
|
||||
# s/^include/* include/g
|
||||
|
||||
def fixParams(number, operation, stack):
|
||||
result = []
|
||||
index = []
|
||||
|
||||
for i, line in enumerate(operation):
|
||||
if len(line) == 0 or line[0] == "*":
|
||||
result.append(line)
|
||||
continue
|
||||
|
||||
result.append("")
|
||||
line = line.replace("$", ";")
|
||||
|
||||
for param in re.finditer(r'([^ \t=+\(\)]+|\'[^\']*\'|[\(\)])(?:[ \t]*(\([^\)]*\))?[ \t]*=[ \t]*(\'[^\']*\'|[^ \t]+))?', line):
|
||||
name = param.group(1)
|
||||
args = param.group(2)
|
||||
definition = param.group(3)
|
||||
|
||||
# dev/gauss is an unsupported parameter in xyce
|
||||
if name == "dev/gauss":
|
||||
continue
|
||||
elif name in ["vt", "Vt", "vT", "VT"]:
|
||||
name = "local_" + name
|
||||
|
||||
if definition:
|
||||
if ":" in definition:
|
||||
definition = definition.replace(":", " :")
|
||||
if definition[0] != "'":
|
||||
definition = "'" + definition + "'"
|
||||
|
||||
# Convert .param functions to .func commands
|
||||
if args and len(args) > 0:
|
||||
found = False
|
||||
for elem in stack:
|
||||
if name in elem.methods:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
emitFunction(name, args, definition[1:-1] if definition[0] == "'" else definition)
|
||||
stack[-1].methods.add(name)
|
||||
# TODO(edward.bingham) other parameter fixes
|
||||
elif definition and len(definition) > 0:
|
||||
result[-1] += " " + name + "=" + definition
|
||||
elif name and len(name) > 0:
|
||||
if len(result[-1]) > 0:
|
||||
result[-1] += " "
|
||||
result[-1] += name
|
||||
|
||||
if len(result[-1]) == 0:
|
||||
result.pop()
|
||||
else:
|
||||
index.append(len(result)-1)
|
||||
|
||||
if len(index) == 1 and result[index[0]] == ".param":
|
||||
del result[index[0]]
|
||||
|
||||
for i in index[1:]:
|
||||
result[i] = "+ " + result[i]
|
||||
|
||||
return result
|
||||
|
||||
def fixOption(number, operation, stack):
|
||||
result = []
|
||||
for i, line in enumerate(operation):
|
||||
if len(line) == 0 or line[0] == "*":
|
||||
result.append(line)
|
||||
continue
|
||||
|
||||
for param in re.finditer(r'([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(\'[^\']*\'|[^ \t]*)', line):
|
||||
name = param.group(1)
|
||||
definition = param.group(2)
|
||||
if name in ["tmiflag", "modmonte", "tmipath", "etmiUsrInput"]:
|
||||
# these options load the TSMC Model Interface (TMI) which isn't supported in Xyce
|
||||
# TMI is generally used for modelling of silicon, transistor, and wire aging
|
||||
continue
|
||||
# TODO(edward.bingham) scale and geoshrink ultimately need to be
|
||||
# combined, which means keeping track of the values of each in a given
|
||||
# scope and generating options that combine those values as needed
|
||||
if name == "scale":
|
||||
result.append(".options parser " + name + "=" + definition)
|
||||
elif name == "geoshrink":
|
||||
result.append(".options parser scale=" + definition)
|
||||
else:
|
||||
# options need to be actively handled individually, all options between hspice and xyce are different
|
||||
print("line " + str(number) + ": unhandled option '" + line + "'", file=sys.stderr)
|
||||
continue
|
||||
|
||||
return result
|
||||
|
||||
def hspice2Xyce(path):
|
||||
stack = [StackElem("")]
|
||||
operation = []
|
||||
command = ""
|
||||
|
||||
devices = "bcdefghijklmopqrstuvwxyz"
|
||||
commands = "."
|
||||
continuations = "+"
|
||||
|
||||
with open(path, 'r') as fptr:
|
||||
for number, line in enumerate(fptr):
|
||||
line = line.strip()
|
||||
# extraneous include statements
|
||||
if line.lower().startswith("include"):
|
||||
line = "* " + line
|
||||
|
||||
if len(line) == 0 or line[0] == '*' or line[0] == '#':
|
||||
pass
|
||||
else:
|
||||
if line[0].lower() in continuations:
|
||||
pass
|
||||
elif line[0].lower() in commands or line[0].lower() in devices:
|
||||
# print and clear stored multiline command
|
||||
emitOperation(number, command, operation, stack)
|
||||
operation = []
|
||||
|
||||
command = re.split("[ \t]+", line)[0].lower().strip()
|
||||
if line[0].lower() in commands:
|
||||
if command in [".data", ".subckt", ".if", ".control"]:
|
||||
stack.append(StackElem(command))
|
||||
elif command == ".lib":
|
||||
args = re.split("[ \t]+", line)
|
||||
if len(args) <= 2:
|
||||
stack.append(StackElem(command))
|
||||
elif command.startswith(".end"):
|
||||
if command == ".endl" and stack[-1].parent == ".lib":
|
||||
stack.pop()
|
||||
elif command == ".ends" and stack[-1].parent == ".subckt":
|
||||
stack.pop()
|
||||
elif command == ".enddata" and stack[-1].parent == ".data":
|
||||
stack.pop()
|
||||
elif command == ".endif" and stack[-1].parent == ".if":
|
||||
stack.pop()
|
||||
elif command == ".endc" and stack[-1].parent == ".control":
|
||||
stack.pop()
|
||||
elif command == ".end" and stack[-1].parent == "":
|
||||
stack.pop()
|
||||
else:
|
||||
print("line " + str(number) + ": stack parse error '" + command + "' disagrees with '" + stack[-1].parent + "'", file=sys.stderr)
|
||||
return
|
||||
else:
|
||||
print("line " + str(number) + ": unrecognized command '" + line + "'", file=sys.stderr)
|
||||
return
|
||||
|
||||
operation.append(line)
|
||||
|
||||
emitOperation(-1, command, operation, stack)
|
||||
operation = []
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
hspice2Xyce(sys.argv[1])
|
||||
else:
|
||||
print("$ hspice2xyce path")
|
||||
print("Converts an HSPICE netlist to a Xyce netlist and emits result to stdout.")
|
41
shortenspice.py
Executable file
41
shortenspice.py
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import re
|
||||
import datetime
|
||||
import os
|
||||
|
||||
ckts = dict()
|
||||
ids = dict()
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
print("shortenspice.py <file>")
|
||||
print("Prints the spice file, removing the template parameters from each subcircuit in favor of a unique id. This is useful for shortening subcircuit names for HSIM.")
|
||||
else:
|
||||
with open(sys.argv[1], 'r') as fptr:
|
||||
for line in fptr:
|
||||
line = line.split()
|
||||
if line and line[0] == '.subckt':
|
||||
ms = re.finditer(r'[a-zA-Z]', line[1])
|
||||
if ms:
|
||||
m = None
|
||||
for m in ms:
|
||||
pass
|
||||
idx = m.span()[-1]
|
||||
if idx < len(line[1]):
|
||||
name = line[1][0:idx]
|
||||
if name in ids:
|
||||
ids[name] += 1
|
||||
else:
|
||||
ids[name] = 0
|
||||
name += '_' + str(ids[name])
|
||||
ckts[line[1]] = name
|
||||
line[1] = name
|
||||
elif line and line[0].startswith("x"):
|
||||
i = 0
|
||||
while i < len(line) and '=' in line[-1-i]:
|
||||
i += 1
|
||||
if i < len(line):
|
||||
if line[-1-i] in ckts:
|
||||
line[-1-i] = ckts[line[-1-i]]
|
||||
print(' '.join(line))
|
Loading…
Reference in New Issue
Block a user