Generate symbols.
diff --git a/scripts/python-skywater-pdk/generate_metadata_json.py b/scripts/python-skywater-pdk/generate_metadata_json.py
index e02bfa1..5154e04 100755
--- a/scripts/python-skywater-pdk/generate_metadata_json.py
+++ b/scripts/python-skywater-pdk/generate_metadata_json.py
@@ -76,6 +76,10 @@
re.compile('macro_sync'),
re.compile('lsbuflv2hv_simple'),
re.compile('_lp'),
+ re.compile('icecap'),
+ re.compile('inv_p'),
+ re.compile('nor_p'),
+ re.compile('nor2_p'),
]
def should_ignore(f, x=IGNORE):
diff --git a/scripts/python-skywater-pdk/generate_symbols.sh b/scripts/python-skywater-pdk/generate_symbols.sh
new file mode 100755
index 0000000..9b45617
--- /dev/null
+++ b/scripts/python-skywater-pdk/generate_symbols.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+if [ ! -d $1/skywater-pdk/ ]; then
+ echo "Need a directory to the skywater-pdk"
+ exit 1
+fi
+
+find $1/skywater-pdk/ -name *.blackbox.v -delete
+find $1/skywater-pdk/ -name *.symbol.v -delete
+
+./generate_verilog_blackbox.py $1/skywater-pdk/libraries/*/*/cells/*
+
+exit 0
+
+for LIB in $1/skywater-pdk/libraries/*; do
+ LIBNAME=$(basename $LIB)
+
+ find $LIB -name \*.symbol.svg -delete
+ find $LIB -name \*.symbol.v -print \
+ | parallel -v symbolator --libname $LIBNAME --title -t --input \{\} \
+ ; RETCODE=$?
+ if [ $RETCODE -ne 0 ]; then
+ echo "FAILURE on $LIB"
+ exit
+ fi
+done
diff --git a/scripts/python-skywater-pdk/generate_verilog_blackbox.py b/scripts/python-skywater-pdk/generate_verilog_blackbox.py
index 82d7257..05c7882 100755
--- a/scripts/python-skywater-pdk/generate_verilog_blackbox.py
+++ b/scripts/python-skywater-pdk/generate_verilog_blackbox.py
@@ -17,23 +17,27 @@
import sys
import textwrap
+from collections import defaultdict
+
copyright_header = """\
-// Copyright 2020 The SkyWater PDK Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright 2020 The SkyWater PDK Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
"""
from skywater_pdk.utils import OrderedEnum
@@ -70,7 +74,7 @@
if pg in (self.DATA_CONTROL,):
return 'control'
if pg in (self.CLOCK, self.CLOCK_CONTROL,):
- return 'clocking'
+ return 'clocks'
if pg in (self.SCAN_CHAIN,):
return 'scanchain'
if pg in (self.POWER_CONTROL, self.POWER_OTHER,
@@ -122,6 +126,15 @@
>>> PortGroup.classify('B_N')
<PortGroup.DATA_IN_CHAR: 10>
+ >>> PortGroup.classify('C')
+ <PortGroup.DATA_IN_CHAR: 10>
+ >>> PortGroup.classify('C1')
+ <PortGroup.DATA_IN_CHAR: 10>
+ >>> PortGroup.classify('C1_N')
+ <PortGroup.DATA_IN_CHAR: 10>
+ >>> PortGroup.classify('C_N')
+ <PortGroup.DATA_IN_CHAR: 10>
+
>>> PortGroup.classify('J')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('K')
@@ -245,14 +258,14 @@
Clock Signals
+++++++++++++
- >>> PortGroup.classify('C')
- <PortGroup.CLOCK: 50>
+ #>>> PortGroup.classify('C')
+ #<PortGroup.CLOCK: 50>
- >>> PortGroup.classify('CN')
- <PortGroup.CLOCK: 50>
+ #>>> PortGroup.classify('CN')
+ #<PortGroup.CLOCK: 50>
- >>> PortGroup.classify('C_N')
- <PortGroup.CLOCK: 50>
+ #>>> PortGroup.classify('C_N')
+ #<PortGroup.CLOCK: 50>
>>> PortGroup.classify('CLK')
<PortGroup.CLOCK: 50>
@@ -360,8 +373,7 @@
name = name.upper()
if re.search('^[A-FJKPN][0-9]?(_[NB])?$', name):
- if name not in ('C', 'C_N'):
- return cls.DATA_IN_CHAR
+ return cls.DATA_IN_CHAR
if re.search('^[XYZQ][0-9]?(_[NB])?$', name):
return cls.DATA_OUT_CHAR
@@ -403,7 +415,7 @@
return cls.CLOCK
if re.search('^((CLK)|(GCLK)|(GATE))_N$', name):
return cls.CLOCK
- if re.search('^[CG]_?N?$', name):
+ if re.search('^[G]_?N?$', name):
return cls.CLOCK
if re.search('^SLEEP(_[NB])?$', name):
@@ -527,16 +539,97 @@
return "\n".join(textwrap.wrap(s, initial_indent=' * ', subsequent_indent=' * '))
+warning = """\
+WARNING: This file is autogenerated, do not modify directly!
+"""
-def write_verilog_header(f, define_data):
+
+def write_verilog_header(desc, f, define_data):
f.write(copyright_header)
f.write('\n')
f.write(f"/**\n")
f.write(wrap(f"{define_data['name']}: {define_data['description']}"))
f.write('\n')
+ f.write(f" *\n")
+ f.write(wrap(desc))
+ f.write('\n')
+ f.write(f" *\n")
+ f.write(wrap(warning))
+ f.write('\n')
f.write(f" */\n")
+ f.write('\n')
f.write('(* blackbox *)\n')
- f.write(f"module {define_data['library']}__{define_data['name']} (\n")
+ f.write(f"module {define_data['library']}__{define_data['name']} (")
+
+
+def write_verilog_parameters(f, define_data):
+ maxlen = {}
+ maxlen['pname'] = max([0]+[len(p[0]) for p in define_data['parameters']])
+ maxlen['ptype'] = max([0]+[len(p[1]) for p in define_data['parameters']])
+ if maxlen['pname']:
+ f.write('\n // Parameters\n')
+ for pname, ptype in define_data['parameters']:
+ pname = pname.ljust(maxlen['pname'])
+ if maxlen['ptype']:
+ ptype = ptype.ljust(maxlen['ptype'])+ ' '
+ else:
+ ptype = ''
+ f.write(f' parameter {ptype}{pname};\n')
+
+
+def write_verilog_supplies(f, define_data):
+ maxlen = {}
+ maxlen['pname'] = max([0]+[len(p[1]) for p in define_data['ports'] if p[0] == 'power'])
+ maxlen['ptype'] = max([0]+[len(p[3]) for p in define_data['ports'] if p[0] == 'power'])
+ if maxlen['pname']:
+ f.write('\n // Voltage supply signals\n')
+ for pclass, pname, pdir, ptype in define_data['ports']:
+ if pclass != 'power':
+ continue
+ assert ptype, (pclass, pname, pdir, ptype)
+
+ pname = pname.ljust(maxlen['pname'])
+ ptype = ptype.ljust(maxlen['ptype'])
+
+ f.write(f' {ptype} {pname};\n')
+ 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': [],
+ }
+ maxlen = {}
+ maxlen['power'] = defaultdict(lambda: 0)
+ maxlen['signal'] = defaultdict(lambda: 0)
+ 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
def write_blackbox(cellpath, define_data):
@@ -544,14 +637,123 @@
assert not os.path.exists(outpath), outpath
print("Creating", outpath)
with open(outpath, "w+") as f:
- write_verilog_header(f, define_data)
+ write_verilog_header(
+ "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")
+
+ write_verilog_parameters(f, define_data)
+ write_verilog_supplies(f, define_data)
+ f.write('endmodule\n')
+
+
+def write_blackbox_pp(cellpath, define_data):
+ outpath = os.path.join(cellpath, f"{define_data['library']}__{define_data['name']}.pp.blackbox.v")
+ assert not os.path.exists(outpath), outpath
+ print("Creating", outpath)
+ with open(outpath, "w+") as f:
+ write_verilog_header(
+ "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")
+ write_verilog_parameters(f, define_data)
+ f.write('endmodule\n')
+
+
+def group_ports_for_symbol(define_data, only):
+ ports = []
+ for pclass, pname, pdir, ptype in define_data['ports']:
+ if pclass not in only:
+ continue
+ pg = PortGroup.classify(pname, define_data['name'])
+ ports.append((pg, pclass, pname, pdir, ptype))
+
+ ports.sort()
+
+ pports = [None,]
+ while len(ports) > 0:
+ if pports[-1] and pports[-1][0].type != ports[0][0].type:
+ pports.append(None)
+ pports.append(ports.pop(0))
+
+ if len(pports) == 1:
+ return []
+
+ return pports
+
+
+def write_symbol(cellpath, define_data):
+ outpath = os.path.join(cellpath, f"{define_data['library']}__{define_data['name']}.symbol.v")
+ assert not os.path.exists(outpath), outpath
+ print("Creating", outpath)
+
+ # Group the ports to make a nice symbol
+ pports = group_ports_for_symbol(define_data, ['signal'])
+
+ with open(outpath, "w+") as f:
+ write_verilog_header(
+ "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 pclass, pname, pdir, ptype in define_data['ports']:
+ 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
@@ -567,122 +769,42 @@
else:
ptype = ''
- f.write(f" {pdir}{ptype}{pname},\n")
- f.seek(f.tell()-2)
- f.write("\n);\n")
-
- maxlen['pname'] = max([0]+[len(p[0]) for p in define_data['parameters']])
- maxlen['ptype'] = max([0]+[len(p[1]) for p in define_data['parameters']])
- if maxlen['pname']:
- f.write('\n // Parameters\n')
- for pname, ptype in define_data['parameters']:
- pname = pname.ljust(maxlen['pname'])
- if maxlen['ptype']:
- ptype = ptype.ljust(maxlen['ptype'])+ ' '
- else:
- ptype = ''
- f.write(f' parameter {ptype}{pname};\n')
-
- maxlen['pname'] = max([0]+[len(p[1]) for p in define_data['ports'] if p[0] == 'power'])
- maxlen['ptype'] = max([0]+[len(p[3]) for p in define_data['ports'] if p[0] == 'power'])
- if maxlen['pname']:
- f.write('\n // Voltage supply signals\n')
- for pclass, pname, pdir, ptype in define_data['ports']:
- if pclass != 'power':
- continue
- assert ptype, (pclass, pname, pdir, ptype)
-
- pname = pname.ljust(maxlen['pname'])
- ptype = ptype.ljust(maxlen['ptype'])
-
- f.write(f' {ptype} {pname};\n')
-
- f.write('endmodule\n')
-
-
-def write_blackbox_pp(cellpath, define_data):
- outpath = os.path.join(cellpath, f"{define_data['library']}__{define_data['name']}.pp.blackbox.v")
- assert not os.path.exists(outpath), outpath
- print("Creating", outpath)
- with open(outpath, "w+") as f:
- write_verilog_header(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" {pdir}{ptype}{pname},\n")
- f.seek(f.tell()-2)
- f.write("\n);\n")
-
- maxlen['pname'] = max([0]+[len(p[0]) for p in define_data['parameters']])
- maxlen['ptype'] = max([0]+[len(p[1]) for p in define_data['parameters']])
- if maxlen['pname']:
- f.write('\n // Parameters\n')
- for pname, ptype in define_data['parameters']:
- pname = pname.ljust(maxlen['pname'])
- if maxlen['ptype']:
- ptype = ptype.ljust(maxlen['ptype'])+ ' '
- else:
- ptype = ''
- f.write(f' parameter {ptype}{pname};\n')
+ f.write(f"\n {pdir}{ptype}{pname},")
+ if pports:
+ f.seek(f.tell()-1)
+ f.write("\n")
+ f.write(");\n")
+ write_verilog_parameters(f, define_data)
+ write_verilog_supplies(f, define_data)
f.write('endmodule\n')
def write_symbol_pp(cellpath, define_data):
outpath = os.path.join(cellpath, f"{define_data['library']}__{define_data['name']}.pp.symbol.v")
assert not os.path.exists(outpath), outpath
-
- ports = []
- for pclass, pname, pdir, ptype in define_data['ports']:
- pg = PortGroup.classify(pname, define_data['name'])
- ports.append((pg, pclass, pname, pdir, ptype))
-
- ports.sort()
-
- pports = [None,]
- while len(ports) > 0:
- if pports[-1] and pports[-1][0].type != ports[0][0].type:
- pports.append(None)
- pports.append(ports.pop(0))
-
- for i, p in enumerate(pports):
- if not p:
- np = pports[i+1]
- print('//# {{'+np[0].type+'|'+np[0].desc+'}}')
- continue
- print(p)
-
- return
-
-
print("Creating", outpath)
+
+ # Group the ports to make a nice symbol
+ pports = group_ports_for_symbol(define_data, ['signal', 'power'])
+
with open(outpath, "w+") as f:
- write_verilog_header(f, define_data)
+ write_verilog_header(
+ "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 pclass, pname, pdir, ptype in define_data['ports']:
+ 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 = ''
@@ -698,25 +820,17 @@
else:
ptype = ''
- f.write(f" {pdir}{ptype}{pname},\n")
- f.seek(f.tell()-2)
- f.write("\n);\n")
-
- maxlen['pname'] = max([0]+[len(p[0]) for p in define_data['parameters']])
- maxlen['ptype'] = max([0]+[len(p[1]) for p in define_data['parameters']])
- if maxlen['pname']:
- f.write('\n // Parameters\n')
- for pname, ptype in define_data['parameters']:
- pname = pname.ljust(maxlen['pname'])
- if maxlen['ptype']:
- ptype = ptype.ljust(maxlen['ptype'])+ ' '
- else:
- ptype = ''
- f.write(f' parameter {ptype}{pname};\n')
+ f.write(f"\n {pdir}{ptype}{pname},")
+ if pports:
+ f.seek(f.tell()-1)
+ f.write("\n")
+ f.write(");\n")
+ write_verilog_parameters(f, define_data)
f.write('endmodule\n')
+
def process(cellpath):
print()
print(cellpath)
@@ -726,17 +840,14 @@
return
assert os.path.exists(define_json), define_json
define_data = json.load(open(define_json))
- pprint.pprint(define_data)
write_blackbox(cellpath, define_data)
write_blackbox_pp(cellpath, define_data)
+ write_symbol(cellpath, define_data)
write_symbol_pp(cellpath, define_data)
pprint.pprint(drive_strengths(define_data['name'], cellpath))
- for pclass, pname, pdir, ptype in define_data['ports']:
- print(pname, PortGroup.classify(pname, define_data['name']))
-
return
drives = define_data.get('drives', [])
for d in drives: