machxo2: Tristate is active-low.
[yosys.git] / techlibs / nexus / cells_xtra.py
1 #!/usr/bin/env python3
2
3 # Based on Xilinx cells_xtra.py; modified for Radiant's structure
4
5 from argparse import ArgumentParser
6 from io import StringIO
7 from enum import Enum, auto
8 import os.path
9 import sys
10 import re
11
12
13 class Cell:
14 def __init__(self, name, keep=False, port_attrs={}):
15 self.name = name
16 self.keep = keep
17 self.port_attrs = port_attrs
18 self.found = False
19
20 class State(Enum):
21 OUTSIDE = auto()
22 IN_MODULE = auto()
23 IN_OTHER_MODULE = auto()
24 IN_FUNCTION = auto()
25 IN_TASK = auto()
26
27 devices = [
28 ("lifcl", [
29 Cell("ACC54"),
30 Cell("ADC"),
31 Cell("ALUREG"),
32 Cell("BB_ADC", keep=True),
33 Cell("BB_CDR", keep=True),
34 Cell("BB_I3C_A", keep=True),
35 Cell("BFD1P3KX"),
36 Cell("BFD1P3LX"),
37 Cell("BNKREF18", keep=True),
38 Cell("CONFIG_LMMI", keep=True),
39 Cell("DCC"),
40 Cell("DCS"),
41 Cell("DDRDLL"),
42 Cell("DELAYA"),
43 Cell("DELAYB"),
44 Cell("DIFFIO18", keep=True),
45 Cell("DLLDEL"),
46 Cell("DP16K_MODE"),
47 Cell("DP16K"),
48 Cell("DPHY", keep=True),
49 Cell("DPSC512K"),
50 Cell("DQSBUF"),
51 Cell("EBR_CORE"),
52 Cell("EBR"),
53 Cell("ECLKDIV"),
54 Cell("ECLKSYNC"),
55 Cell("FBMUX"),
56 Cell("FIFO16K_MODE"),
57 Cell("FIFO16K"),
58 Cell("GSR"),
59 Cell("HSE"),
60 Cell("I2CFIFO"),
61 Cell("IDDR71"),
62 Cell("IDDRX1"),
63 Cell("IDDRX2DQ"),
64 Cell("IDDRX2"),
65 Cell("IDDRX4DQ"),
66 Cell("IDDRX4"),
67 Cell("IDDRX5"),
68 Cell("IFD1P3BX"),
69 Cell("IFD1P3DX"),
70 Cell("IFD1P3IX"),
71 Cell("IFD1P3JX"),
72 Cell("JTAG", keep=True),
73 Cell("LRAM"),
74 Cell("M18X36"),
75 Cell("MIPI"),
76 Cell("MULT18"),
77 # Cell("MULT18X18"),
78 # Cell("MULT18X36"),
79 Cell("MULT36"),
80 # Cell("MULT36X36"),
81 Cell("MULT9"),
82 # Cell("MULT9X9"),
83 # Cell("MULTADDSUB18X18"),
84 Cell("MULTADDSUB18X18WIDE"),
85 # Cell("MULTADDSUB18X36"),
86 # Cell("MULTADDSUB36X36"),
87 Cell("MULTADDSUB9X9WIDE"),
88 Cell("MULTIBOOT", keep=True),
89 # Cell("MULTPREADD18X18"),
90 # Cell("MULTPREADD9X9"),
91 Cell("ODDR71"),
92 Cell("ODDRX1"),
93 Cell("ODDRX2DQS"),
94 Cell("ODDRX2DQ"),
95 Cell("ODDRX2"),
96 Cell("ODDRX4DQS"),
97 Cell("ODDRX4DQ"),
98 Cell("ODDRX4"),
99 Cell("ODDRX5"),
100 Cell("OFD1P3BX"),
101 Cell("OFD1P3DX"),
102 Cell("OFD1P3IX"),
103 Cell("OFD1P3JX"),
104 Cell("OSC"),
105 Cell("OSCA"),
106 Cell("OSHX2"),
107 Cell("OSHX4"),
108 Cell("PCIE"),
109 Cell("PCLKDIV"),
110 Cell("PCLKDIVSP"),
111 Cell("PDP16K_MODE"),
112 Cell("PDP16K"),
113 Cell("PDPSC16K_MODE"),
114 Cell("PDPSC16K"),
115 Cell("PDPSC512K"),
116 Cell("PLL"),
117 Cell("PREADD9"),
118 Cell("PUR", keep=True),
119 Cell("REFMUX"),
120 Cell("REG18"),
121 Cell("SEDC", keep=True),
122 Cell("SEIO18"),
123 Cell("SEIO33"),
124 Cell("SGMIICDR"),
125 Cell("SP16K_MODE"),
126 Cell("SP16K"),
127 Cell("SP512K"),
128 Cell("TSALLA"),
129 Cell("TSHX2DQS"),
130 Cell("TSHX2DQ"),
131 Cell("TSHX4DQS"),
132 Cell("TSHX4DQ"),
133 Cell("WDT", keep=True),
134
135 Cell("ACC54_CORE"),
136 Cell("ADC_CORE"),
137 Cell("ALUREG_CORE"),
138 Cell("BNKREF18_CORE"),
139 Cell("BNKREF33_CORE"),
140 Cell("DIFFIO18_CORE"),
141 Cell("CONFIG_CLKRST_CORE", keep=True),
142 Cell("CONFIG_HSE_CORE", keep=True),
143 Cell("CONFIG_IP_CORE", keep=True),
144 Cell("CONFIG_JTAG_CORE", keep=True),
145 Cell("CONFIG_LMMI_CORE", keep=True),
146 Cell("CONFIG_MULTIBOOT_CORE", keep=True),
147 Cell("CONFIG_SEDC_CORE", keep=True),
148 Cell("CONFIG_WDT_CORE", keep=True),
149 Cell("DDRDLL_CORE"),
150 Cell("DLLDEL_CORE"),
151 Cell("DPHY_CORE"),
152 Cell("DQSBUF_CORE"),
153 Cell("ECLKDIV_CORE"),
154 Cell("ECLKSYNC_CORE"),
155 Cell("FBMUX_CORE"),
156 Cell("GSR_CORE"),
157 Cell("I2CFIFO_CORE"),
158 Cell("LRAM_CORE"),
159 Cell("MULT18_CORE"),
160 Cell("MULT18X36_CORE"),
161 Cell("MULT36_CORE"),
162 Cell("MULT9_CORE"),
163 Cell("OSC_CORE"),
164 Cell("PCIE_CORE"),
165 Cell("PLL_CORE"),
166 Cell("PREADD9_CORE"),
167 Cell("REFMUX_CORE"),
168 Cell("REG18_CORE"),
169 Cell("SEIO18_CORE"),
170 Cell("SEIO33_CORE"),
171 Cell("SGMIICDR_CORE"),
172 ])
173 ]
174
175 def xtract_cells_decl(device, cells, dirs, outf):
176 fname = os.path.join(dir, device + '.v')
177 with open(fname) as f:
178 state = State.OUTSIDE
179 # Probably the most horrible Verilog "parser" ever written.
180 cell = None
181 for l in f:
182 l, _, comment = l.partition('//')
183 l = l.strip()
184 if l.startswith("module "):
185 cell_name = l[7:l.find('(')].strip()
186 cell = None
187 module_ports = []
188 iopad_pin = set()
189 if state != State.OUTSIDE:
190 print('Nested modules in {}.'.format(fname))
191 sys.exit(1)
192 for c in cells:
193 if c.name != cell_name:
194 continue
195 cell = c
196 state = State.IN_MODULE
197 if cell.keep:
198 outf.write('(* keep *)\n')
199 outf.write('module {} (...);\n'.format(cell.name))
200 cell.found = True
201
202 m = re.search(r'synthesis .*black_box_pad_pin="([^"]*)"', comment)
203 if m:
204 iopad_pin = set(m.group(1).split(","))
205
206 if cell is None:
207 state = State.IN_OTHER_MODULE
208 elif l.startswith('task '):
209 if state == State.IN_MODULE:
210 state = State.IN_TASK
211 elif l.startswith('function '):
212 if state == State.IN_MODULE:
213 state = State.IN_FUNCTION
214 elif l == 'endtask':
215 if state == State.IN_TASK:
216 state = State.IN_MODULE
217 elif l == 'endfunction':
218 if state == State.IN_FUNCTION:
219 state = State.IN_MODULE
220 elif l == 'endmodule':
221 if state == State.IN_MODULE:
222 for kind, rng, port in module_ports:
223 for attr in cell.port_attrs.get(port, []):
224 outf.write(' (* {} *)\n'.format(attr))
225 if port in iopad_pin:
226 outf.write(' (* iopad_external_pin *)\n')
227 if rng is None:
228 outf.write(' {} {};\n'.format(kind, port))
229 else:
230 outf.write(' {} {} {};\n'.format(kind, rng, port))
231 outf.write(l + '\n')
232 outf.write('\n')
233 elif state != State.IN_OTHER_MODULE:
234 print('endmodule in weird place in {}.'.format(cell.name, fname))
235 sys.exit(1)
236 state = State.OUTSIDE
237 elif l.startswith(('input ', 'output ', 'inout ')) and state == State.IN_MODULE:
238 if l.endswith((';', ',')):
239 l = l[:-1]
240 if ';' in l:
241 print('Weird port line in {} [{}].'.format(fname, l))
242 sys.exit(1)
243 kind, _, ports = l.partition(' ')
244 for port in ports.split(','):
245 port = port.strip()
246 if port.startswith('['):
247 rng, port = port.split()
248 else:
249 rng = None
250 module_ports.append((kind, rng, port))
251 elif l.startswith('parameter ') and state == State.IN_MODULE:
252 if l.endswith((';', ',')):
253 l = l[:-1]
254 while ' ' in l:
255 l = l.replace(' ', ' ')
256 if ';' in l:
257 print('Weird parameter line in {} [{}].'.format(fname, l))
258 sys.exit(1)
259 outf.write(' {};\n'.format(l))
260
261 if state != State.OUTSIDE:
262 print('endmodule not found in {}.'.format(fname))
263 sys.exit(1)
264 for cell in cells:
265 if not cell.found:
266 print('cell {} not found in {}.'.format(cell.name, fname))
267 if __name__ == '__main__':
268 parser = ArgumentParser(description='Extract Lattice blackbox cell definitions from Radiant.')
269 parser.add_argument('radiant_dir', nargs='?', default='/opt/lscc/radiant/2.0/')
270 args = parser.parse_args()
271
272 dirs = [
273 os.path.join(args.radiant_dir, 'cae_library/synthesis/verilog/'),
274 ]
275 for dir in dirs:
276 if not os.path.isdir(dir):
277 print('{} is not a directory'.format(dir))
278
279 out = StringIO()
280 for device, cells in devices:
281 xtract_cells_decl(device, cells, dirs, out)
282
283 with open('cells_xtra.v', 'w') as f:
284 f.write('// Created by cells_xtra.py from Lattice models\n')
285 f.write('\n')
286 f.write(out.getvalue())