mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			286 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			286 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())
 |