diff options
Diffstat (limited to 'techlibs/nexus/cells_xtra.py')
-rw-r--r-- | techlibs/nexus/cells_xtra.py | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/techlibs/nexus/cells_xtra.py b/techlibs/nexus/cells_xtra.py new file mode 100644 index 000000000..dc462c29a --- /dev/null +++ b/techlibs/nexus/cells_xtra.py @@ -0,0 +1,286 @@ +#!/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()) |