Added initial conversion from CSV to binned PM3
Signed-off-by: Grzegorz Latosinski <glatosinski@antmicro.com>
diff --git a/convert_pm3_to_csv.py b/convert_pm3_to_csv.py
index 2ff9521..a9889db 100644
--- a/convert_pm3_to_csv.py
+++ b/convert_pm3_to_csv.py
@@ -10,14 +10,15 @@
import sys
from prettytable import PrettyTable
import json
+import clean_spice_files
sourcetodests = defaultdict(list)
RE_SUBCKT = re.compile(r'\.subckt\s+(?P<subcktname>[^ ]+)\s?(?P<nodenames>.*)')
# RE_MODEL = re.compile(r'^[\.]*model\s+(?P<modelname>[^ ]+)\s+(?P<modeltype>[^ ]+)')
-RE_MODEL_END = re.compile(r'^[\s\n]*ends(?P<end>.*)(\n|$)')
-RE_SUBCKT_END = re.compile(r'^.ends')
+# RE_MODEL_END = re.compile(r'^[\s\n]*ends(?P<end>.*)(\n|$)')
+# RE_SUBCKT_END = re.compile(r'^.ends')
RE_GROUP = re.compile(r'[*\s]*?(?P<group>[^*\n]+?)[*\s]*(\n|$)')
RE_MODE_LINE = re.compile(r'(?P<modeid>\d+)\s*:\s*type=\s*(?P<modetype>.*)(\n|$)')
RE_INLINE_SUBCKT_MODEL = re.compile(r'^(?P<subcktname>[^ ]+)\s*\((?P<nodenames>.*)\)\s*(?P<modelname>[^ ]+)\s*(?P<parameters>.*)($|\n)')
@@ -27,26 +28,99 @@
def order_parameters(paramname):
priority = {
'subckt': 0,
- 'nodes': 1,
- 'model': 2,
- 'type': 3,
- 'mode': 4,
- 'modetype': 5,
- 'lmin': 6,
- 'lmax': 7,
- 'wmin': 8,
- 'wmax': 9,
- 'level': 10,
- 'tnom': 11,
- 'version': 12,
- 'tox': 13,
- 'toxm': 14,
+ 'inlinesubckt': 1,
+ 'nodes': 2,
+ 'model': 3,
+ 'type': 4,
+ 'mode': 5,
+ 'modetype': 6,
+ 'lmin': 7,
+ 'lmax': 8,
+ 'wmin': 9,
+ 'wmax': 10,
+ 'level': 11,
+ 'tnom': 12,
+ 'version': 13,
+ 'tox': 14,
+ 'toxm': 15,
}
if paramname in priority:
return (priority[paramname], paramname)
return (1000, paramname)
+def csv_to_pm3(parameters, csventry):
+ # we have following orders
+ # inlinesubckt nodes model type
+ # inlinesubckt nodes model type mode modetype
+ # model type
+ # subckt nodes
+ # subckt nodes model type
+ result = []
+ if parameters[0] == 'model':
+ for entry in csventry:
+ assert 'N/A' not in entry[:2], entry
+ result.append(f'.model {entry[0]} {entry[1]}')
+ for parameter, value in zip(parameters[2:], entry[2:]):
+ if value != 'N/A':
+ result.append(f'+{parameter}= {value}')
+ elif parameters[0] == 'subckt':
+ lastsubckt = None
+ firstsubckt = True
+ for entry in csventry:
+ assert 'N/A' not in entry[:2], entry
+ if lastsubckt != entry[0]:
+ if not firstsubckt:
+ result.append('.ends')
+ firstsubckt = False
+ result.append(f'.subckt {entry[0]} {" ".join(entry[1].split(","))}')
+ lastsubckt = entry[0]
+ startpoint = 2
+ if entry[2] == 'model':
+ assert 'N/A' not in entry[2:4], entry
+ result.append(f'.model {entry[2]} {entry[3]}')
+ startpoint = 4
+ for parameter, value in zip(parameters[startpoint:], entry[startpoint:]):
+ if value != 'N/A':
+ result.append(f'+{parameter}= {value}')
+ if not firstsubckt:
+ result.append('.ends')
+ elif parameters[0] == 'inlinesubckt':
+ lastsubcktdef = None
+ lastmodel = None
+ firstsubcktdef = True
+ firstmodel = True
+ for entry in csventry:
+ assert 'N/A' not in entry[:4], entry
+ if not entry[0].endswith('_dummy') and entry[0] != lastsubcktdef:
+ if not firstsubcktdef:
+ result.append(f'ends {lastsubcktdef}')
+ lastsubcktdef = entry[0]
+ firstsubcktdef = False
+ result.append(f'inline subckt {entry[0]} ({" ".join(entry[1].split(","))})')
+ if 'mode' in set(parameters):
+ if entry[2] != lastmodel:
+ if not firstmodel:
+ result.append('}')
+ firstmodel = False
+ result.append(f'model {entry[2]} {entry[3]} {{')
+ lastmodel = entry[2]
+ result.append(f'{entry[4]}: type={entry[5]}')
+ for parameter, value in zip(parameters[6:], entry[6:]):
+ result.append(f'+{parameter}= {value}')
+ else:
+ result.append(f'{entry[0]} ({" ".join(entry[1].split(","))}) {entry[2]}')
+ for parameter, value in zip(parameters[3:], entry[3:]):
+ if value != 'N/A':
+ result.append(f'+{parameter}= {value}')
+ if not firstmodel:
+ result.append('}')
+ if not firstsubcktdef:
+ result.append(f'ends {lastsubcktdef}')
+ result = clean_spice_files.basic_cleaning(result)
+ result = clean_spice_files.makefixedwidthcolumn(result)
+ return result
+
def pm3_to_csv(lines):
result = []
params = {}
@@ -54,6 +128,7 @@
params['model'] = {}
params['mode'] = {}
scopetype = None
+ leftovers = []
def produce_line():
finparams = {}
finparams.update(params['subckt'])
@@ -66,6 +141,7 @@
try:
if not line.strip():
continue
+ origline = line
line = line.strip()
elements = shlex.split(line, posix=False)
if line.startswith('*'):
@@ -153,14 +229,17 @@
params['model'] = {}
params['mode'] = {}
scopetype = 'subckt'
- params['subckt']['subckt'] = m.group('subcktname')
+ params['subckt']['inlinesubckt'] = m.group('subcktname')
params['subckt']['nodes'] = ','.join(m.group('nodenames').split(' '))
params['model']['model'] = m.group('modelname')
- params['model']['type'] = params['subckt']['subckt']
+ params['model']['type'] = params['subckt']['inlinesubckt']
elements = m.group('parameters').split()
parse_parameters()
else:
- print(colored(line, 'yellow'), file=sys.stderr)
+ if not line.strip().startswith('ends') and not line.strip().startswith('inline subckt'):
+ if scopetype is None or not line.strip() in ['{', '}']:
+ leftovers.append(origline.rstrip())
+ print(colored(line, 'yellow'), file=sys.stderr)
except:
print(colored(line, 'red'), file=sys.stderr)
raise
@@ -182,7 +261,7 @@
row.append('N/A')
csvcontent.append(row)
- return csvcontent
+ return csvcontent, leftovers
if __name__ == '__main__':
parser = argparse.ArgumentParser()
@@ -218,7 +297,7 @@
for line in data.readlines():
lines.append(line)
- result = pm3_to_csv(lines)
+ result, leftovers = pm3_to_csv(lines)
if len(result) > 1:
with open(filename.with_suffix('.csv'), 'w', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=';')
@@ -233,5 +312,13 @@
t.add_row(line)
tablefile.write(str(t))
sourcetodests[str(filename)].append(str(Path(filename).with_suffix('.table')))
+ # print(colored('\n'.join(csv_to_pm3(result[0], result[1:])), 'green'))
+ binnedspice = csv_to_pm3(result[0], result[1:])
+ csv2bsimname = filename.with_suffix(f'.csv2bsim{filename.suffix}')
+ with open(csv2bsimname, 'w') as csv2bsimfile:
+ csv2bsimfile.write('\n'.join(binnedspice))
+ with open(filename.with_suffix(f'.csvwrap{filename.suffix}'), 'w') as csvwrapfile:
+ leftovers.append(f'.include "{csv2bsimname}"')
+ csvwrapfile.write('\n'.join(leftovers))
with open(args.sourcetodests, 'w') as srctodst:
json.dump(sourcetodests, srctodst, indent=2)