mirror of https://github.com/YosysHQ/yosys.git
287 lines
9.1 KiB
Python
287 lines
9.1 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
# Based on Xilinx cells_xtra.py; modified for Radiant's structure
|
||
|
|
||
|
from argparse import ArgumentParser
|
||
|
from io import StringIO
|
||
|
from enum import Enum, auto
|
||
|
import os.path
|
||
|
import sys
|
||
|
import re
|
||
|
|
||
|
|
||
|
class Cell:
|
||
|
def __init__(self, name, keep=False, port_attrs={}):
|
||
|
self.name = name
|
||
|
self.keep = keep
|
||
|
self.port_attrs = port_attrs
|
||
|
self.found = False
|
||
|
|
||
|
class State(Enum):
|
||
|
OUTSIDE = auto()
|
||
|
IN_MODULE = auto()
|
||
|
IN_OTHER_MODULE = auto()
|
||
|
IN_FUNCTION = auto()
|
||
|
IN_TASK = auto()
|
||
|
|
||
|
devices = [
|
||
|
("lifcl", [
|
||
|
Cell("ACC54"),
|
||
|
Cell("ADC"),
|
||
|
Cell("ALUREG"),
|
||
|
Cell("BB_ADC", keep=True),
|
||
|
Cell("BB_CDR", keep=True),
|
||
|
Cell("BB_I3C_A", keep=True),
|
||
|
Cell("BFD1P3KX"),
|
||
|
Cell("BFD1P3LX"),
|
||
|
Cell("BNKREF18", keep=True),
|
||
|
Cell("CONFIG_LMMI", keep=True),
|
||
|
Cell("DCC"),
|
||
|
Cell("DCS"),
|
||
|
Cell("DDRDLL"),
|
||
|
Cell("DELAYA"),
|
||
|
Cell("DELAYB"),
|
||
|
Cell("DIFFIO18", keep=True),
|
||
|
Cell("DLLDEL"),
|
||
|
Cell("DP16K_MODE"),
|
||
|
Cell("DP16K"),
|
||
|
Cell("DPHY", keep=True),
|
||
|
Cell("DPSC512K"),
|
||
|
Cell("DQSBUF"),
|
||
|
Cell("EBR_CORE"),
|
||
|
Cell("EBR"),
|
||
|
Cell("ECLKDIV"),
|
||
|
Cell("ECLKSYNC"),
|
||
|
Cell("FBMUX"),
|
||
|
Cell("FIFO16K_MODE"),
|
||
|
Cell("FIFO16K"),
|
||
|
Cell("GSR"),
|
||
|
Cell("HSE"),
|
||
|
Cell("I2CFIFO"),
|
||
|
Cell("IDDR71"),
|
||
|
Cell("IDDRX1"),
|
||
|
Cell("IDDRX2DQ"),
|
||
|
Cell("IDDRX2"),
|
||
|
Cell("IDDRX4DQ"),
|
||
|
Cell("IDDRX4"),
|
||
|
Cell("IDDRX5"),
|
||
|
Cell("IFD1P3BX"),
|
||
|
Cell("IFD1P3DX"),
|
||
|
Cell("IFD1P3IX"),
|
||
|
Cell("IFD1P3JX"),
|
||
|
Cell("JTAG", keep=True),
|
||
|
Cell("LRAM"),
|
||
|
Cell("M18X36"),
|
||
|
Cell("MIPI"),
|
||
|
Cell("MULT18"),
|
||
|
Cell("MULT18X18"),
|
||
|
Cell("MULT18X36"),
|
||
|
Cell("MULT36"),
|
||
|
Cell("MULT36X36"),
|
||
|
Cell("MULT9"),
|
||
|
Cell("MULT9X9"),
|
||
|
Cell("MULTADDSUB18X18"),
|
||
|
Cell("MULTADDSUB18X18WIDE"),
|
||
|
Cell("MULTADDSUB18X36"),
|
||
|
Cell("MULTADDSUB36X36"),
|
||
|
Cell("MULTADDSUB9X9WIDE"),
|
||
|
Cell("MULTIBOOT", keep=True),
|
||
|
Cell("MULTPREADD18X18"),
|
||
|
Cell("MULTPREADD9X9"),
|
||
|
Cell("ODDR71"),
|
||
|
Cell("ODDRX1"),
|
||
|
Cell("ODDRX2DQS"),
|
||
|
Cell("ODDRX2DQ"),
|
||
|
Cell("ODDRX2"),
|
||
|
Cell("ODDRX4DQS"),
|
||
|
Cell("ODDRX4DQ"),
|
||
|
Cell("ODDRX4"),
|
||
|
Cell("ODDRX5"),
|
||
|
Cell("OFD1P3BX"),
|
||
|
Cell("OFD1P3DX"),
|
||
|
Cell("OFD1P3IX"),
|
||
|
Cell("OFD1P3JX"),
|
||
|
Cell("OSC"),
|
||
|
Cell("OSCA"),
|
||
|
Cell("OSHX2"),
|
||
|
Cell("OSHX4"),
|
||
|
Cell("PCIE"),
|
||
|
Cell("PCLKDIV"),
|
||
|
Cell("PCLKDIVSP"),
|
||
|
Cell("PDP16K_MODE"),
|
||
|
Cell("PDP16K"),
|
||
|
Cell("PDPSC16K_MODE"),
|
||
|
Cell("PDPSC16K"),
|
||
|
Cell("PDPSC512K"),
|
||
|
Cell("PLL"),
|
||
|
Cell("PREADD9"),
|
||
|
Cell("PUR", keep=True),
|
||
|
Cell("REFMUX"),
|
||
|
Cell("REG18"),
|
||
|
Cell("SEDC", keep=True),
|
||
|
Cell("SEIO18"),
|
||
|
Cell("SEIO33"),
|
||
|
Cell("SGMIICDR"),
|
||
|
Cell("SP16K_MODE"),
|
||
|
Cell("SP16K"),
|
||
|
Cell("SP512K"),
|
||
|
Cell("TSALLA"),
|
||
|
Cell("TSHX2DQS"),
|
||
|
Cell("TSHX2DQ"),
|
||
|
Cell("TSHX4DQS"),
|
||
|
Cell("TSHX4DQ"),
|
||
|
Cell("WDT", keep=True),
|
||
|
|
||
|
Cell("ACC54_CORE"),
|
||
|
Cell("ADC_CORE"),
|
||
|
Cell("ALUREG_CORE"),
|
||
|
Cell("BNKREF18_CORE"),
|
||
|
Cell("BNKREF33_CORE"),
|
||
|
Cell("DIFFIO18_CORE"),
|
||
|
Cell("CONFIG_CLKRST_CORE", keep=True),
|
||
|
Cell("CONFIG_HSE_CORE", keep=True),
|
||
|
Cell("CONFIG_IP_CORE", keep=True),
|
||
|
Cell("CONFIG_JTAG_CORE", keep=True),
|
||
|
Cell("CONFIG_LMMI_CORE", keep=True),
|
||
|
Cell("CONFIG_MULTIBOOT_CORE", keep=True),
|
||
|
Cell("CONFIG_SEDC_CORE", keep=True),
|
||
|
Cell("CONFIG_WDT_CORE", keep=True),
|
||
|
Cell("DDRDLL_CORE"),
|
||
|
Cell("DLLDEL_CORE"),
|
||
|
Cell("DPHY_CORE"),
|
||
|
Cell("DQSBUF_CORE"),
|
||
|
Cell("ECLKDIV_CORE"),
|
||
|
Cell("ECLKSYNC_CORE"),
|
||
|
Cell("FBMUX_CORE"),
|
||
|
Cell("GSR_CORE"),
|
||
|
Cell("I2CFIFO_CORE"),
|
||
|
Cell("LRAM_CORE"),
|
||
|
Cell("MULT18_CORE"),
|
||
|
Cell("MULT18X36_CORE"),
|
||
|
Cell("MULT36_CORE"),
|
||
|
Cell("MULT9_CORE"),
|
||
|
Cell("OSC_CORE"),
|
||
|
Cell("PCIE_CORE"),
|
||
|
Cell("PLL_CORE"),
|
||
|
Cell("PREADD9_CORE"),
|
||
|
Cell("REFMUX_CORE"),
|
||
|
Cell("REG18_CORE"),
|
||
|
Cell("SEIO18_CORE"),
|
||
|
Cell("SEIO33_CORE"),
|
||
|
Cell("SGMIICDR_CORE"),
|
||
|
])
|
||
|
]
|
||
|
|
||
|
def xtract_cells_decl(device, cells, dirs, outf):
|
||
|
fname = os.path.join(dir, device + '.v')
|
||
|
with open(fname) as f:
|
||
|
state = State.OUTSIDE
|
||
|
# Probably the most horrible Verilog "parser" ever written.
|
||
|
cell = None
|
||
|
for l in f:
|
||
|
l, _, comment = l.partition('//')
|
||
|
l = l.strip()
|
||
|
if l.startswith("module "):
|
||
|
cell_name = l[7:l.find('(')].strip()
|
||
|
cell = None
|
||
|
module_ports = []
|
||
|
iopad_pin = set()
|
||
|
if state != State.OUTSIDE:
|
||
|
print('Nested modules in {}.'.format(fname))
|
||
|
sys.exit(1)
|
||
|
for c in cells:
|
||
|
if c.name != cell_name:
|
||
|
continue
|
||
|
cell = c
|
||
|
state = State.IN_MODULE
|
||
|
if cell.keep:
|
||
|
outf.write('(* keep *)\n')
|
||
|
outf.write('module {} (...);\n'.format(cell.name))
|
||
|
cell.found = True
|
||
|
|
||
|
m = re.search(r'synthesis .*black_box_pad_pin="([^"]*)"', comment)
|
||
|
if m:
|
||
|
iopad_pin = set(m.group(1).split(","))
|
||
|
|
||
|
if cell is None:
|
||
|
state = State.IN_OTHER_MODULE
|
||
|
elif l.startswith('task '):
|
||
|
if state == State.IN_MODULE:
|
||
|
state = State.IN_TASK
|
||
|
elif l.startswith('function '):
|
||
|
if state == State.IN_MODULE:
|
||
|
state = State.IN_FUNCTION
|
||
|
elif l == 'endtask':
|
||
|
if state == State.IN_TASK:
|
||
|
state = State.IN_MODULE
|
||
|
elif l == 'endfunction':
|
||
|
if state == State.IN_FUNCTION:
|
||
|
state = State.IN_MODULE
|
||
|
elif l == 'endmodule':
|
||
|
if state == State.IN_MODULE:
|
||
|
for kind, rng, port in module_ports:
|
||
|
for attr in cell.port_attrs.get(port, []):
|
||
|
outf.write(' (* {} *)\n'.format(attr))
|
||
|
if port in iopad_pin:
|
||
|
outf.write(' (* iopad_external_pin *)\n')
|
||
|
if rng is None:
|
||
|
outf.write(' {} {};\n'.format(kind, port))
|
||
|
else:
|
||
|
outf.write(' {} {} {};\n'.format(kind, rng, port))
|
||
|
outf.write(l + '\n')
|
||
|
outf.write('\n')
|
||
|
elif state != State.IN_OTHER_MODULE:
|
||
|
print('endmodule in weird place in {}.'.format(cell.name, fname))
|
||
|
sys.exit(1)
|
||
|
state = State.OUTSIDE
|
||
|
elif l.startswith(('input ', 'output ', 'inout ')) and state == State.IN_MODULE:
|
||
|
if l.endswith((';', ',')):
|
||
|
l = l[:-1]
|
||
|
if ';' in l:
|
||
|
print('Weird port line in {} [{}].'.format(fname, l))
|
||
|
sys.exit(1)
|
||
|
kind, _, ports = l.partition(' ')
|
||
|
for port in ports.split(','):
|
||
|
port = port.strip()
|
||
|
if port.startswith('['):
|
||
|
rng, port = port.split()
|
||
|
else:
|
||
|
rng = None
|
||
|
module_ports.append((kind, rng, port))
|
||
|
elif l.startswith('parameter ') and state == State.IN_MODULE:
|
||
|
if l.endswith((';', ',')):
|
||
|
l = l[:-1]
|
||
|
while ' ' in l:
|
||
|
l = l.replace(' ', ' ')
|
||
|
if ';' in l:
|
||
|
print('Weird parameter line in {} [{}].'.format(fname, l))
|
||
|
sys.exit(1)
|
||
|
outf.write(' {};\n'.format(l))
|
||
|
|
||
|
if state != State.OUTSIDE:
|
||
|
print('endmodule not found in {}.'.format(fname))
|
||
|
sys.exit(1)
|
||
|
for cell in cells:
|
||
|
if not cell.found:
|
||
|
print('cell {} not found in {}.'.format(cell.name, fname))
|
||
|
if __name__ == '__main__':
|
||
|
parser = ArgumentParser(description='Extract Lattice blackbox cell definitions from Radiant.')
|
||
|
parser.add_argument('radiant_dir', nargs='?', default='/opt/lscc/radiant/2.0/')
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
dirs = [
|
||
|
os.path.join(args.radiant_dir, 'cae_library/synthesis/verilog/'),
|
||
|
]
|
||
|
for dir in dirs:
|
||
|
if not os.path.isdir(dir):
|
||
|
print('{} is not a directory'.format(dir))
|
||
|
|
||
|
out = StringIO()
|
||
|
for device, cells in devices:
|
||
|
xtract_cells_decl(device, cells, dirs, out)
|
||
|
|
||
|
with open('cells_xtra.v', 'w') as f:
|
||
|
f.write('// Created by cells_xtra.py from Lattice models\n')
|
||
|
f.write('\n')
|
||
|
f.write(out.getvalue())
|