blob: 7675c3eeb71d71a12f218b60ae153a1202a3fa95 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright 2020 The SkyWater PDK Authors.
#
# Use of this source code is governed by the Apache 2.0
# license that can be found in the LICENSE file or at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
import json
import os
import pprint
import re
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
*/
"""
from skywater_pdk.utils import OrderedEnum
class PortGroup(OrderedEnum):
DATA_IN_CHAR = 10 # A, A1, D, etc
DATA_IN_WORD = 11 # IN
DATA_OUT_CHAR = 20 # X, Y, Q
DATA_OUT_WORD = 21 # OUT
DATA_IO_CHAR = 30 # Inout?
DATA_IO_WORD = 31 # Inout?
DATA_CONTROL = 40 # SET / RESET / etc
SCAN_CHAIN = 44 # SCD, SCE, etc
CLOCK = 50 # Clock
CLOCK_CONTROL = 51 # Clock enable
POWER_CONTROL = 78 # SLEEP
POWER_OTHER = 79 # KAPWR
POWER_POSITIVE = 80 # VPWR
POWER_NEGATIVE = 81 # VGND
@property
def type(self):
pg = self
if pg in (self.DATA_IN_CHAR, self.DATA_IN_WORD,
self.DATA_OUT_CHAR, self.DATA_OUT_WORD,
self.DATA_IO_CHAR, self.DATA_IO_WORD,):
return 'data'
if pg in (self.DATA_CONTROL,):
return 'control'
if pg in (self.CLOCK, self.CLOCK_CONTROL,):
return 'clocks'
if pg in (self.SCAN_CHAIN,):
return 'scanchain'
if pg in (self.POWER_CONTROL, self.POWER_OTHER,
self.POWER_POSITIVE, self.POWER_NEGATIVE,):
return 'power'
assert False, self
@property
def desc(self):
pg = self
if pg in (self.DATA_IN_CHAR, self.DATA_IN_WORD,
self.DATA_OUT_CHAR, self.DATA_OUT_WORD,
self.DATA_IO_CHAR, self.DATA_IO_WORD,):
return 'Data Signals'
if pg in (self.DATA_CONTROL,):
return 'Control Signals'
if pg in (self.SCAN_CHAIN,):
return 'Scan Chain'
if pg in (self.CLOCK, self.CLOCK_CONTROL,):
return 'Clocking'
if pg in (self.POWER_CONTROL, self.POWER_OTHER,
self.POWER_POSITIVE, self.POWER_NEGATIVE,):
return 'Power'
assert False, self
@classmethod
def classify(cls, name, modname=None):
"""
Data Input Signals
++++++++++++++++++
>>> PortGroup.classify('A')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('A1')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('A1_N')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('A_N')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('B')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('B1')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('B1_N')
<PortGroup.DATA_IN_CHAR: 10>
>>> 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')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('IN')
<PortGroup.DATA_IN_WORD: 11>
>>> PortGroup.classify('D')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('D_N')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('P0')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('N1')
<PortGroup.DATA_IN_CHAR: 10>
>>> PortGroup.classify('CI')
<PortGroup.DATA_IN_WORD: 11>
>>> PortGroup.classify('CIN')
<PortGroup.DATA_IN_WORD: 11>
SCD
Scan Chain Data
>>> PortGroup.classify('SCD')
<PortGroup.SCAN_CHAIN: 44>
SCE
Scan Chain Enable
>>> PortGroup.classify('SCE')
<PortGroup.SCAN_CHAIN: 44>
Data Output Signals
+++++++++++++++++++
>>> PortGroup.classify('X')
<PortGroup.DATA_OUT_CHAR: 20>
>>> PortGroup.classify('X_N')
<PortGroup.DATA_OUT_CHAR: 20>
>>> PortGroup.classify('Y')
<PortGroup.DATA_OUT_CHAR: 20>
>>> PortGroup.classify('Y_N')
<PortGroup.DATA_OUT_CHAR: 20>
>>> PortGroup.classify('Z')
<PortGroup.DATA_OUT_CHAR: 20>
>>> PortGroup.classify('Z_N')
<PortGroup.DATA_OUT_CHAR: 20>
>>> PortGroup.classify('Q')
<PortGroup.DATA_OUT_CHAR: 20>
>>> PortGroup.classify('OUT')
<PortGroup.DATA_OUT_WORD: 21>
>>> PortGroup.classify('HI')
<PortGroup.DATA_OUT_WORD: 21>
>>> PortGroup.classify('LO')
<PortGroup.DATA_OUT_WORD: 21>
>>> PortGroup.classify('COUT')
<PortGroup.DATA_OUT_WORD: 21>
>>> PortGroup.classify('SUM')
<PortGroup.DATA_OUT_WORD: 21>
Data Control Signals
++++++++++++++++++++
>>> PortGroup.classify('SET')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('SET_N')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('SET_B')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('S')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('S_N')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('S_B')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('R')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('R_N')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('R_B')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('RESET')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('RESET_N')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('RESET_B')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('RESET')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('RESET_N')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('RESET_B')
<PortGroup.DATA_CONTROL: 40>
Data Enable
>>> PortGroup.classify('DE')
<PortGroup.DATA_CONTROL: 40>
Tristate Enable
>>> PortGroup.classify('TE_B')
<PortGroup.DATA_CONTROL: 40>
Select lines on muxes
>>> PortGroup.classify('S0')
<PortGroup.DATA_CONTROL: 40>
>>> PortGroup.classify('S4')
<PortGroup.DATA_CONTROL: 40>
Clock Signals
+++++++++++++
#>>> PortGroup.classify('C')
#<PortGroup.CLOCK: 50>
#>>> PortGroup.classify('CN')
#<PortGroup.CLOCK: 50>
#>>> PortGroup.classify('C_N')
#<PortGroup.CLOCK: 50>
>>> PortGroup.classify('CLK')
<PortGroup.CLOCK: 50>
>>> PortGroup.classify('GCLK')
<PortGroup.CLOCK: 50>
>>> PortGroup.classify('CLK_N')
<PortGroup.CLOCK: 50>
>>> PortGroup.classify('G')
<PortGroup.CLOCK: 50>
>>> PortGroup.classify('GN')
<PortGroup.CLOCK: 50>
>>> PortGroup.classify('G_N')
<PortGroup.CLOCK: 50>
>>> PortGroup.classify('GATE')
<PortGroup.CLOCK: 50>
>>> PortGroup.classify('GATE_N')
<PortGroup.CLOCK: 50>
Clock Control Signals
+++++++++++++++++++++
>>> PortGroup.classify('CLK_EN')
<PortGroup.CLOCK_CONTROL: 51>
>>> PortGroup.classify('CE')
<PortGroup.CLOCK_CONTROL: 51>
>>> PortGroup.classify('CEN')
<PortGroup.CLOCK_CONTROL: 51>
>>> PortGroup.classify('GATE_EN')
<PortGroup.CLOCK_CONTROL: 51>
>>> PortGroup.classify('GEN')
<PortGroup.CLOCK_CONTROL: 51>
>>> PortGroup.classify('GE')
<PortGroup.CLOCK_CONTROL: 51>
Positive Power Supplies
+++++++++++++++++++++++
>>> PortGroup.classify('VPWR')
<PortGroup.POWER_POSITIVE: 80>
>>> PortGroup.classify('VPB')
<PortGroup.POWER_POSITIVE: 80>
Negative Power Supplies
+++++++++++++++++++++++
>>> PortGroup.classify('VGND')
<PortGroup.POWER_NEGATIVE: 81>
>>> PortGroup.classify('VNB')
<PortGroup.POWER_NEGATIVE: 81>
>>> PortGroup.classify('DEST')
<PortGroup.POWER_OTHER: 79>
Power Control Signals
+++++++++++++++++++++
>>> PortGroup.classify('SLEEP')
<PortGroup.POWER_CONTROL: 78>
>>> PortGroup.classify('SLEEP_B')
<PortGroup.POWER_CONTROL: 78>
>>> PortGroup.classify('SLEEP_N')
<PortGroup.POWER_CONTROL: 78>
Other Power Suppliers
+++++++++++++++++++++
>>> PortGroup.classify('KAPWR')
<PortGroup.POWER_OTHER: 79>
>>> PortGroup.classify('KAGND')
<PortGroup.POWER_OTHER: 79>
>>> PortGroup.classify('DIODE')
<PortGroup.POWER_OTHER: 79>
>>> PortGroup.classify('LOWLVPWRA')
<PortGroup.POWER_OTHER: 79>
"""
# Override for csw module
if modname and 'csw' in modname:
if name == 'VPB':
return cls.POWER_POSITIVE
elif name == 'VNB':
return cls.POWER_NEGATIVE
elif name in ('S', 'D', 'GN', 'GP'):
return cls.POWER_OTHER
name = name.upper()
if re.search('^[A-FJKPN][0-9]?(_[NB])?$', name):
return cls.DATA_IN_CHAR
if re.search('^[XYZQ][0-9]?(_[NB])?$', name):
return cls.DATA_OUT_CHAR
if re.search('^IN[0-9]?_?', name):
return cls.DATA_IN_WORD
if re.search('^CI[0-9]?_?', name):
return cls.DATA_IN_WORD
if re.search('^CIN[0-9]?_?', name):
return cls.DATA_IN_WORD
if re.search('^OUT[0-9]?_?', name):
return cls.DATA_OUT_WORD
if re.search('^COUT[0-9]?_?', name):
return cls.DATA_OUT_WORD
if re.search('^SUM[0-9]?_?', name):
return cls.DATA_OUT_WORD
if name in ('HI', 'LO'):
return cls.DATA_OUT_WORD
if re.search('^S[0-9]+$', name):
return cls.DATA_CONTROL
if re.search('^((SET)|(RESET)|[SR])(_[NB])?$', name):
return cls.DATA_CONTROL
if re.search('^((T)|(TE))(_[NB])?$', name):
return cls.DATA_CONTROL
if re.search('^(DE)(_[NB])?$', name):
return cls.DATA_CONTROL
if re.search('^((CLK)|(GCLK)|(GATE))_EN$', name):
return cls.CLOCK_CONTROL
if re.search('^[CG]EN$', name):
return cls.CLOCK_CONTROL
if re.search('^[CG]E$', name):
return cls.CLOCK_CONTROL
if re.search('^((CLK)|(GCLK)|(GATE))$', name):
return cls.CLOCK
if re.search('^((CLK)|(GCLK)|(GATE))_N$', name):
return cls.CLOCK
if re.search('^[G]_?N?$', name):
return cls.CLOCK
if re.search('^SLEEP(_[NB])?$', name):
return cls.POWER_CONTROL
if re.search('^VPWR', name):
return cls.POWER_POSITIVE
if re.search('^VPB$', name):
return cls.POWER_POSITIVE
if re.search('^VGND', name):
return cls.POWER_NEGATIVE
if re.search('^VNB$', name):
return cls.POWER_NEGATIVE
if name.startswith('DEST'):
return cls.POWER_OTHER
if 'DIODE' in name:
return cls.POWER_OTHER
if 'PWR' in name:
return cls.POWER_OTHER
if 'GND' in name:
return cls.POWER_OTHER
if 'SHORT' in name:
return cls.POWER_OTHER
if 'MET' in name:
return cls.POWER_OTHER
if re.search('^[M][0-1]$', name):
return cls.POWER_OTHER
if 'SRC' == name:
return cls.DATA_IN_WORD
if 'DST' == name:
return cls.DATA_OUT_WORD
if 'NETA' == name:
return cls.DATA_IN_WORD
if 'NETB' == name:
return cls.DATA_OUT_WORD
if name.startswith('SC'):
return cls.SCAN_CHAIN
if name.startswith('ASYNC'):
return cls.SCAN_CHAIN
def write_verilog(define_data, outfile, drive=None):
with open(outfile, 'w') as f:
f.write(copyright_header)
f.write('\n')
f.write(include_header.format(define_data['fullname']))
f.write('\n')
if not drive:
return
drive_name, drive_value = drive
if not 'ports' in define_data:
return
module_signal_defports = []
module_signal_ports = []
for pname, ptype in define_data['ports']['signal']:
module_signal_defports.append("{} {}, ".format(ptype, pname))
module_signal_ports.append(pname)
module_signal_defports = "".join(module_signal_defports)
assert module_signal_defports.endswith(", "), module_signal_defports
module_signal_defports = module_signal_defports[:-2]
module_signal_ports = ", ".join(module_signal_ports)
module_power_defports = []
module_power_ports = []
for pname, ptype in define_data['ports']['power']:
module_power_defports.append(", {} {}".format('input', pname))
module_power_ports.append(", {}".format(pname))
module_power_defports = "".join(module_power_defports)
module_power_ports = "".join(module_power_ports)
library_name = "{} {}".format(
define_data['library']['name'].upper(), define_data['library']['type'])
f.write(module_header.format(
module_base_name = define_data['fullname'],
cell_name = define_data['name'],
library_name = library_name,
drive_name = drive_name,
drive_value = drive_value,
description = define_data.get('description', ''),
module_signal_defports = module_signal_defports,
module_signal_ports = module_signal_ports,
module_power_defports = module_power_defports,
module_power_ports = module_power_ports,
))
def echo_file(fname):
with open(fname) as f:
sys.stdout.write('\n')
sys.stdout.write('File: ')
sys.stdout.write(fname)
sys.stdout.write('\n')
sys.stdout.write('------\n')
sys.stdout.write(f.read())
sys.stdout.write('------\n')
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):
if not f.endswith('.gds'):
continue
f = f.split('.', 1)[0]
libname, modname = f.split('__', 1)
drive = modname.replace(basename, '')
if not drive:
continue
assert drive.startswith('_'), drive
drives.append(drive[1:])
return drives
def wrap(s):
return "\n".join(textwrap.wrap(s, initial_indent=' * ', subsequent_indent=' * '))
warning = """\
WARNING: This file is autogenerated, do not modify directly!
"""
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')
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('`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']} (")
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 write_verilog_ports(f, ports):
maxlen = {}
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']:
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):
outpath = os.path.join(cellpath, f"{define_data['library']}__{define_data['name']}.blackbox.v")
assert not os.path.exists(outpath), outpath
print("Creating", outpath)
with open(outpath, "w+") as f:
write_verilog_header(
f,
"Verilog stub definition (black box without power pins).",
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):
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,
"Verilog stub definition (black box with power pins).",
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):
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(
f,
"Verilog stub (without power pins) for graphical symbol definition generation.",
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):
outpath = os.path.join(cellpath, f"{define_data['library']}__{define_data['name']}.pp.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', 'power'])
with open(outpath, "w+") as f:
write_verilog_header(
f,
"Verilog stub (with power pins) for graphical symbol definition generation.",
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):
print()
print(cellpath)
define_json = os.path.join(cellpath, 'definition.json')
if not os.path.exists(define_json):
print("No definition.json in", cellpath)
return
assert os.path.exists(define_json), define_json
define_data = json.load(open(define_json))
write_blackbox(cellpath, define_data)
write_blackbox_pp(cellpath, define_data)
write_symbol(cellpath, define_data)
write_symbol_pp(cellpath, define_data)
for d in drive_strengths(define_data['name'], cellpath):
write_drive_wrapper(d, cellpath, define_data)
return
def main(args):
for a in args:
process(a)
if __name__ == "__main__":
import doctest
fails, _ = doctest.testmod()
if fails>0:
sys.exit()
sys.exit(main(sys.argv[1:]))