Also generate strength wrappers.
diff --git a/scripts/python-skywater-pdk/generate_symbols.sh b/scripts/python-skywater-pdk/generate_symbols.sh
index 9b45617..a063313 100755
--- a/scripts/python-skywater-pdk/generate_symbols.sh
+++ b/scripts/python-skywater-pdk/generate_symbols.sh
@@ -5,12 +5,13 @@
exit 1
fi
-find $1/skywater-pdk/ -name *.blackbox.v -delete
-find $1/skywater-pdk/ -name *.symbol.v -delete
+find $1/skywater-pdk/ -name *.v -delete
./generate_verilog_blackbox.py $1/skywater-pdk/libraries/*/*/cells/*
-exit 0
+(cd $1/ ; git diff --no-renames --name-only --diff-filter=D -z | xargs -0 git checkout --)
+
+exit
for LIB in $1/skywater-pdk/libraries/*; do
LIBNAME=$(basename $LIB)
diff --git a/scripts/python-skywater-pdk/generate_verilog_blackbox.py b/scripts/python-skywater-pdk/generate_verilog_blackbox.py
index 05c7882..7675c3e 100755
--- a/scripts/python-skywater-pdk/generate_verilog_blackbox.py
+++ b/scripts/python-skywater-pdk/generate_verilog_blackbox.py
@@ -521,6 +521,19 @@
sys.stdout.flush()
+
+def seek_backwards(f):
+ start_pos = f.tell()
+ current_pos = f.tell()-1
+ while True:
+ f.seek(current_pos)
+ d = f.read(1)
+ if d not in '\n ,':
+ break
+ current_pos -= 1
+ f.seek(current_pos+1)
+
+
def drive_strengths(basename, cellpath):
drives = []
for f in os.listdir(cellpath):
@@ -532,7 +545,8 @@
drive = modname.replace(basename, '')
if not drive:
continue
- drives.append(drive)
+ assert drive.startswith('_'), drive
+ drives.append(drive[1:])
return drives
def wrap(s):
@@ -544,9 +558,19 @@
"""
-def write_verilog_header(desc, f, define_data):
+def file_guard(fname):
+ fname = re.sub('[^A-Za-z_0-9]', '_', fname)
+ return fname.upper()
+
+
+def write_verilog_header(f, desc, define_data):
+ assert f.name, f
+ guard = file_guard(os.path.basename(f.name))
f.write(copyright_header)
f.write('\n')
+ f.write(f'`ifndef {guard}\n')
+ f.write(f'`define {guard}\n')
+ f.write('\n')
f.write(f"/**\n")
f.write(wrap(f"{define_data['name']}: {define_data['description']}"))
f.write('\n')
@@ -558,6 +582,20 @@
f.write('\n')
f.write(f" */\n")
f.write('\n')
+ f.write('`timescale 1ns / 1ps\n')
+ f.write('\n')
+
+
+def write_verilog_footer(f):
+ assert f.name, f
+ guard = file_guard(os.path.basename(f.name))
+ f.write('\n')
+ f.write(f'`endif // {guard}\n')
+ f.close()
+
+
+
+def write_module_header(f, define_data):
f.write('(* blackbox *)\n')
f.write(f"module {define_data['library']}__{define_data['name']} (")
@@ -595,41 +633,84 @@
f.write('\n')
-# def maxlen(ports, groups, filter=None):
-# if filter is None:
-# filter = {}
-# maxl = {}
-# for g in groups:
-# maxl[g] = 0
-# for p in ports:
-# if not p:
-# continue
-# for i, g in enumerate(groups):
-# if g is None:
-# continue
-# if g in filter:
-# if p[0] not in filter[g]:
-# continue
-# if not p[i]:
-# continue
-# maxl[g] = max(maxl[g], len(p[i]))
-# return maxl
-
-
-def ports_by_class(define_data):
- ports = {
- 'power': [],
- 'signal': [],
- }
+def write_verilog_ports(f, ports):
maxlen = {}
- maxlen['power'] = defaultdict(lambda: 0)
- maxlen['signal'] = defaultdict(lambda: 0)
+ maxlen['pname'] = max([0]+[len(p[1]) for p in ports])
+ maxlen['pdir'] = max([0]+[len(p[2]) for p in ports])
+ maxlen['ptype'] = max([0]+[len(p[3]) for p in ports if p[0] != 'power'])
+
+ for pclass, pname, pdir, ptype in ports:
+ pname = pname.ljust(maxlen['pname'])
+
+ if maxlen['pdir']:
+ pdir = pdir.ljust(maxlen['pdir'])+' '
+ else:
+ pdir = ''
+
+ if maxlen['ptype']:
+ ptype = ptype.ljust(maxlen['ptype'])+ ' '
+ else:
+ ptype = ''
+
+ f.write(f"\n {pdir}{ptype}{pname},")
+ seek_backwards(f)
+ if ports:
+ f.write("\n")
+ f.write(");\n")
+
+
+def write_verilog_symbol_ports(f, pports):
+ maxlen = {}
+ maxlen['pname'] = max([0]+[len(p[2]) for p in pports if p])
+ maxlen['pdir'] = max([0]+[len(p[3]) for p in pports if p])
+ maxlen['ptype'] = max([0]+[len(p[4]) for p in pports if p and p[1] != 'power'])
+
+ for i, p in enumerate(pports):
+ if not p:
+ np = pports[i+1]
+ if i > 0:
+ f.write('\n')
+ f.write('\n //# {{'+np[0].type+'|'+np[0].desc+'}}')
+ continue
+ pg, pclass, pname, pdir, ptype = p
+ if pclass == 'power':
+ ptype = ''
+
+ pname = pname.ljust(maxlen['pname'])
+
+ if maxlen['pdir']:
+ pdir = pdir.ljust(maxlen['pdir'])+' '
+ else:
+ pdir = ''
+
+ if maxlen['ptype']:
+ ptype = ptype.ljust(maxlen['ptype'])+ ' '
+ else:
+ ptype = ''
+
+ f.write(f"\n {pdir}{ptype}{pname},")
+ seek_backwards(f)
+ if pports:
+ f.write("\n")
+ f.write(");\n")
+
+
+def nonpp_ports(define_data):
+ ports = []
for pclass, pname, pdir, ptype in define_data['ports']:
- ports[pclass].append((pclass, pname, pdir, ptype))
- maxlen[pclass]['pname'] = max(maxlen[pclass]['pname'], len(pname))
- maxlen[pclass]['pdir'] = max(maxlen[pclass]['pdir'], len(pdir))
- maxlen[pclass]['ptype'] = max(maxlen[pclass]['ptype'], len(ptype))
- return ports, maxlen
+ if pclass != 'signal':
+ continue
+ ports.append((pclass, pname, pdir, ptype))
+ return ports
+
+
+def pp_ports(define_data):
+ ports = []
+ for pclass, pname, pdir, ptype in define_data['ports']:
+ if pclass == 'power':
+ ptype = ''
+ ports.append((pclass, pname, pdir, ptype))
+ return ports
def write_blackbox(cellpath, define_data):
@@ -638,33 +719,15 @@
print("Creating", outpath)
with open(outpath, "w+") as f:
write_verilog_header(
+ f,
"Verilog stub definition (black box without power pins).",
- f, define_data)
-
- ports, maxlen = ports_by_class(define_data)
- maxlen = maxlen['signal']
- for pclass, pname, pdir, ptype in ports['signal']:
- pname = pname.ljust(maxlen['pname'])
-
- if maxlen['pdir']:
- pdir = pdir.ljust(maxlen['pdir'])+' '
- else:
- pdir = ''
-
- if maxlen['ptype']:
- ptype = ptype.ljust(maxlen['ptype'])+ ' '
- else:
- ptype = ''
-
- f.write(f"\n {pdir}{ptype}{pname},")
- if ports['signal']:
- f.seek(f.tell()-1)
- f.write("\n")
- f.write(");\n")
-
+ define_data)
+ write_module_header(f, define_data)
+ write_verilog_ports(f, nonpp_ports(define_data))
write_verilog_parameters(f, define_data)
write_verilog_supplies(f, define_data)
f.write('endmodule\n')
+ write_verilog_footer(f)
def write_blackbox_pp(cellpath, define_data):
@@ -673,37 +736,14 @@
print("Creating", outpath)
with open(outpath, "w+") as f:
write_verilog_header(
+ f,
"Verilog stub definition (black box with power pins).",
- f, define_data)
-
- maxlen = {}
- maxlen['pname'] = max([0]+[len(p[1]) for p in define_data['ports']])
- maxlen['pdir'] = max([0]+[len(p[2]) for p in define_data['ports']])
- maxlen['ptype'] = max([0]+[len(p[3]) for p in define_data['ports'] if p[0] == 'signal'])
-
- for pclass, pname, pdir, ptype in define_data['ports']:
- if pclass == 'power':
- ptype = ''
-
- pname = pname.ljust(maxlen['pname'])
-
- if maxlen['pdir']:
- pdir = pdir.ljust(maxlen['pdir'])+' '
- else:
- pdir = ''
-
- if maxlen['ptype']:
- ptype = ptype.ljust(maxlen['ptype'])+ ' '
- else:
- ptype = ''
-
- f.write(f"\n {pdir}{ptype}{pname},")
- if define_data['ports']:
- f.seek(f.tell()-1)
- f.write("\n")
- f.write(");\n")
+ define_data)
+ write_module_header(f, define_data)
+ write_verilog_ports(f, pp_ports(define_data))
write_verilog_parameters(f, define_data)
f.write('endmodule\n')
+ write_verilog_footer(f)
def group_ports_for_symbol(define_data, only):
@@ -738,45 +778,15 @@
with open(outpath, "w+") as f:
write_verilog_header(
+ f,
"Verilog stub (without power pins) for graphical symbol definition generation.",
- f, define_data)
-
- maxlen = {}
- maxlen['pname'] = max([0]+[len(p[1]) for p in define_data['ports'] if p[0] == 'signal'])
- maxlen['pdir'] = max([0]+[len(p[2]) for p in define_data['ports'] if p[0] == 'signal'])
- maxlen['ptype'] = max([0]+[len(p[3]) for p in define_data['ports'] if p[0] == 'signal'])
-
- for i, p in enumerate(pports):
- if not p:
- np = pports[i+1]
- if i > 0:
- f.write('\n')
- f.write('\n //# {{'+np[0].type+'|'+np[0].desc+'}}')
- continue
- pg, pclass, pname, pdir, ptype = p
- if pclass != 'signal':
- continue
-
- pname = pname.ljust(maxlen['pname'])
-
- if maxlen['pdir']:
- pdir = pdir.ljust(maxlen['pdir'])+' '
- else:
- pdir = ''
-
- if maxlen['ptype']:
- ptype = ptype.ljust(maxlen['ptype'])+ ' '
- else:
- ptype = ''
-
- f.write(f"\n {pdir}{ptype}{pname},")
- if pports:
- f.seek(f.tell()-1)
- f.write("\n")
- f.write(");\n")
+ define_data)
+ write_module_header(f, define_data)
+ write_verilog_symbol_ports(f, pports)
write_verilog_parameters(f, define_data)
write_verilog_supplies(f, define_data)
f.write('endmodule\n')
+ write_verilog_footer(f)
def write_symbol_pp(cellpath, define_data):
@@ -789,46 +799,74 @@
with open(outpath, "w+") as f:
write_verilog_header(
+ f,
"Verilog stub (with power pins) for graphical symbol definition generation.",
- f, define_data)
-
- maxlen = {}
- maxlen['pname'] = max([0]+[len(p[1]) for p in define_data['ports']])
- maxlen['pdir'] = max([0]+[len(p[2]) for p in define_data['ports']])
- maxlen['ptype'] = max([0]+[len(p[3]) for p in define_data['ports'] if p[0] == 'signal'])
-
- for i, p in enumerate(pports):
- if not p:
- np = pports[i+1]
- if i > 0:
- f.write('\n')
- f.write('\n //# {{'+np[0].type+'|'+np[0].desc+'}}')
- continue
- pg, pclass, pname, pdir, ptype = p
- if pclass == 'power':
- ptype = ''
-
- pname = pname.ljust(maxlen['pname'])
-
- if maxlen['pdir']:
- pdir = pdir.ljust(maxlen['pdir'])+' '
- else:
- pdir = ''
-
- if maxlen['ptype']:
- ptype = ptype.ljust(maxlen['ptype'])+ ' '
- else:
- ptype = ''
-
- f.write(f"\n {pdir}{ptype}{pname},")
- if pports:
- f.seek(f.tell()-1)
- f.write("\n")
- f.write(");\n")
+ define_data)
+ write_module_header(f, define_data)
+ write_verilog_symbol_ports(f, pports)
write_verilog_parameters(f, define_data)
f.write('endmodule\n')
+ write_verilog_footer(f)
+def write_verilog_wrapper(f, extra, supplies, ports, define_data):
+ f.write('\n')
+ f.write('`celldefine\n')
+ f.write(f"module {define_data['library']}__{define_data['name']}{extra} (")
+ write_verilog_ports(f, pp_ports(define_data))
+ write_verilog_parameters(f, define_data)
+ if supplies:
+ write_verilog_supplies(f, define_data)
+
+ param_str = ''
+ if define_data['parameters']:
+ param_str += '#('
+ param_str += " ".join('.{0}({0})'.format(p[0]) for p in define_data['parameters'])
+ param_str += ') '
+
+ ports_str = ''
+ if ports:
+ ports_str += ",\n ".join('.{0}({0})'.format(p[1]) for p in ports);
+
+ f.write(f" {define_data['library']}__{define_data['name']} cell ")
+ f.write(param_str)
+ f.write('(\n ')
+ f.write(ports_str)
+ seek_backwards(f)
+ if ports:
+ f.write("\n );\n")
+ else:
+ f.write(");\n")
+ f.write('\n')
+ f.write('endmodule\n')
+ f.write('`endcelldefine\n')
+ f.write('\n')
+
+
+def write_drive_wrapper(drive, cellpath, define_data):
+ outpath = os.path.join(cellpath, f"{define_data['library']}__{define_data['name']}_{drive}.v")
+ basefile = f"{define_data['library']}__{define_data['name']}"
+ assert not os.path.exists(outpath), outpath
+ print("Creating", outpath)
+
+ with open(outpath, "w+") as f:
+ write_verilog_header(
+ f,
+ f"Verilog wrapper for {define_data['name']} drive {drive}.",
+ define_data)
+ f.write(f'`include "{basefile}.v"\n')
+ f.write('\n')
+ f.write('`ifdef USE_POWER_PINS\n')
+ f.write('/*********************************************************/\n')
+ write_verilog_wrapper(f, '_'+drive, False, pp_ports(define_data), define_data)
+ f.write('/*********************************************************/\n')
+ f.write('`else // If not USE_POWER_PINS\n')
+ f.write('/*********************************************************/\n')
+ write_verilog_wrapper(f, '_'+drive, True, nonpp_ports(define_data), define_data)
+ f.write('/*********************************************************/\n')
+ f.write('`endif // USE_POWER_PINS\n')
+ write_verilog_footer(f)
+
def process(cellpath):
@@ -846,35 +884,11 @@
write_symbol(cellpath, define_data)
write_symbol_pp(cellpath, define_data)
- pprint.pprint(drive_strengths(define_data['name'], cellpath))
+
+ for d in drive_strengths(define_data['name'], cellpath):
+ write_drive_wrapper(d, cellpath, define_data)
return
- drives = define_data.get('drives', [])
- for d in drives:
- assert len(d) == 1, d
- drive_name = list(d.keys())[0]
- drive_value = list(d.values())[0]
- if drive_name == 'units':
- pass
- elif drive_name == 'lp_variant':
- if drive_value == 0:
- drive_value = 'lp'
- else:
- drive_value = 'lp'+str(drive_value+1)
- elif drive_name == "minimum":
- assert drive_value is None
- drive_value = "m"
- else:
- raise TypeError("Unknown drive:"+repr(d))
-
- dvfile = os.path.join(cellpath, "{}_{}.v".format(define_data['fullname'], drive_value))
- write_verilog(define_data, dvfile, list(d.items())[0])
- echo_file(dvfile)
-
- if not drives:
- outfile = os.path.join(cellpath, "{}.v".format(define_data['fullname']))
- write_verilog(define_data, outfile)
- echo_file(outfile)
def main(args):