dd4e300ae0c98ebfcf6905a97fff5eb24bda0f99
[yosys.git] / techlibs / xilinx / cells_xtra.py
1 #!/usr/bin/env python3
2
3 from argparse import ArgumentParser
4 from io import StringIO
5 from enum import Enum, auto
6 import os.path
7 import sys
8
9
10 class Cell:
11 def __init__(self, name, keep=False, port_attrs={}):
12 self.name = name
13 self.keep = keep
14 self.port_attrs = port_attrs
15
16
17 CELLS = [
18 # Design elements types listed in Xilinx UG953
19 Cell('BSCANE2', keep=True),
20 # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}),
21 Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}),
22 Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}),
23 #Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}),
24 Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}),
25 Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}),
26 Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}),
27 Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}),
28 #Cell('BUFHCE', port_attrs={'O': ['clkbuf_driver']}),
29 Cell('BUFIO', port_attrs={'O': ['clkbuf_driver']}),
30 Cell('BUFMR', port_attrs={'O': ['clkbuf_driver']}),
31 Cell('BUFMRCE', port_attrs={'O': ['clkbuf_driver']}),
32 Cell('BUFR', port_attrs={'O': ['clkbuf_driver']}),
33 Cell('CAPTUREE2', keep=True),
34 # Cell('CARRY4'),
35 Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}),
36 Cell('DCIRESET', keep=True),
37 Cell('DNA_PORT'),
38 Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}),
39 Cell('EFUSE_USR'),
40 # Cell('FDCE'),
41 # Cell('FDPE'),
42 # Cell('FDRE'),
43 # Cell('FDSE'),
44 Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
45 Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
46 Cell('FRAME_ECCE2'),
47 Cell('GTHE2_CHANNEL'),
48 Cell('GTHE2_COMMON'),
49 Cell('GTPE2_CHANNEL'),
50 Cell('GTPE2_COMMON'),
51 Cell('GTXE2_CHANNEL'),
52 Cell('GTXE2_COMMON'),
53 # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}),
54 Cell('IBUF_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin']}),
55 Cell('IBUF_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin']}),
56 Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
57 Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
58 Cell('IBUFDS_DIFF_OUT_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
59 Cell('IBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
60 Cell('IBUFDS_GTE2', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
61 Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
62 Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
63 Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}),
64 Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
65 Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}),
66 Cell('ICAPE2', keep=True),
67 Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}),
68 Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}),
69 Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}),
70 Cell('IDELAYE2', port_attrs={'C': ['clkbuf_sink']}),
71 Cell('IN_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
72 Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}),
73 Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}),
74 Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}),
75 Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}),
76 Cell('IOBUFDS_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
77 Cell('IOBUFDS_DIFF_OUT', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
78 Cell('IOBUFDS_DIFF_OUT_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
79 Cell('IOBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}),
80 Cell('ISERDESE2', port_attrs={
81 'CLK': ['clkbuf_sink'],
82 'CLKB': ['clkbuf_sink'],
83 'OCLK': ['clkbuf_sink'],
84 'OCLKB': ['clkbuf_sink'],
85 'CLKDIV': ['clkbuf_sink'],
86 'CLKDIVP': ['clkbuf_sink'],
87 }),
88 Cell('KEEPER'),
89 Cell('LDCE'),
90 Cell('LDPE'),
91 # Cell('LUT1'),
92 # Cell('LUT2'),
93 # Cell('LUT3'),
94 # Cell('LUT4'),
95 # Cell('LUT5'),
96 # Cell('LUT6'),
97 #Cell('LUT6_2'),
98 Cell('MMCME2_ADV'),
99 Cell('MMCME2_BASE'),
100 # Cell('MUXF7'),
101 # Cell('MUXF8'),
102 # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}),
103 Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
104 Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}),
105 Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}),
106 Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}),
107 Cell('ODELAYE2', port_attrs={'C': ['clkbuf_sink']}),
108 Cell('OSERDESE2', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}),
109 Cell('OUT_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
110 Cell('PHASER_IN'),
111 Cell('PHASER_IN_PHY'),
112 Cell('PHASER_OUT'),
113 Cell('PHASER_OUT_PHY'),
114 Cell('PHASER_REF'),
115 Cell('PHY_CONTROL'),
116 Cell('PLLE2_ADV'),
117 Cell('PLLE2_BASE'),
118 Cell('PS7', keep=True),
119 Cell('PULLDOWN'),
120 Cell('PULLUP'),
121 #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
122 Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
123 Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
124 Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}),
125 #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
126 Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
127 Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}),
128 Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}),
129 Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}),
130 #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}),
131 Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}),
132 Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}),
133 Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}),
134 # Cell('RAMB18E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}),
135 # Cell('RAMB36E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}),
136 Cell('ROM128X1'),
137 Cell('ROM256X1'),
138 Cell('ROM32X1'),
139 Cell('ROM64X1'),
140 #Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}),
141 #Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}),
142 Cell('STARTUPE2', keep=True),
143 Cell('USR_ACCESSE2'),
144 Cell('XADC'),
145 ]
146
147 class State(Enum):
148 OUTSIDE = auto()
149 IN_MODULE = auto()
150 IN_OTHER_MODULE = auto()
151 IN_FUNCTION = auto()
152 IN_TASK = auto()
153
154 def xtract_cell_decl(cell, dirs, outf):
155 for dir in dirs:
156 fname = os.path.join(dir, cell.name + '.v')
157 try:
158 with open(fname) as f:
159 state = State.OUTSIDE
160 found = False
161 # Probably the most horrible Verilog "parser" ever written.
162 for l in f:
163 l = l.partition('//')[0]
164 l = l.strip()
165 if l == 'module {}'.format(cell.name) or l.startswith('module {} '.format(cell.name)):
166 if found:
167 print('Multiple modules in {}.'.format(fname))
168 sys.exit(1)
169 elif state != State.OUTSIDE:
170 print('Nested modules in {}.'.format(fname))
171 sys.exit(1)
172 found = True
173 state = State.IN_MODULE
174 if cell.keep:
175 outf.write('(* keep *)\n')
176 outf.write('module {} (...);\n'.format(cell.name))
177 elif l.startswith('module '):
178 if state != State.OUTSIDE:
179 print('Nested modules in {}.'.format(fname))
180 sys.exit(1)
181 state = State.IN_OTHER_MODULE
182 elif l.startswith('task '):
183 if state == State.IN_MODULE:
184 state = State.IN_TASK
185 elif l.startswith('function '):
186 if state == State.IN_MODULE:
187 state = State.IN_FUNCTION
188 elif l == 'endtask':
189 if state == State.IN_TASK:
190 state = State.IN_MODULE
191 elif l == 'endfunction':
192 if state == State.IN_FUNCTION:
193 state = State.IN_MODULE
194 elif l == 'endmodule':
195 if state == State.IN_MODULE:
196 outf.write(l + '\n')
197 outf.write('\n')
198 elif state != State.IN_OTHER_MODULE:
199 print('endmodule in weird place in {}.'.format(cell.name, fname))
200 sys.exit(1)
201 state = State.OUTSIDE
202 elif l.startswith(('input ', 'output ', 'inout ')) and state == State.IN_MODULE:
203 if l.endswith((';', ',')):
204 l = l[:-1]
205 if ';' in l:
206 print('Weird port line in {} [{}].'.format(fname, l))
207 sys.exit(1)
208 kind, _, ports = l.partition(' ')
209 for port in ports.split(','):
210 port = port.strip()
211 for attr in cell.port_attrs.get(port, []):
212 outf.write(' (* {} *)\n'.format(attr))
213 outf.write(' {} {};\n'.format(kind, port))
214 elif l.startswith('parameter ') and state == State.IN_MODULE:
215 if 'UNPLACED' in l:
216 continue
217 if l.endswith((';', ',')):
218 l = l[:-1]
219 while ' ' in l:
220 l = l.replace(' ', ' ')
221 if ';' in l:
222 print('Weird parameter line in {} [{}].'.format(fname, l))
223 sys.exit(1)
224 outf.write(' {};\n'.format(l))
225 if state != State.OUTSIDE:
226 print('endmodule not found in {}.'.format(fname))
227 sys.exit(1)
228 if not found:
229 print('Cannot find module {} in {}.'.format(cell.name, fname))
230 sys.exit(1)
231 return
232 except FileNotFoundError:
233 continue
234 print('Cannot find {}.'.format(cell.name))
235 sys.exit(1)
236
237 if __name__ == '__main__':
238 parser = ArgumentParser(description='Extract Xilinx blackbox cell definitions from Vivado.')
239 parser.add_argument('vivado_dir', nargs='?', default='/opt/Xilinx/Vivado/2018.1')
240 args = parser.parse_args()
241
242 dirs = [
243 os.path.join(args.vivado_dir, 'data/verilog/src/xeclib'),
244 os.path.join(args.vivado_dir, 'data/verilog/src/retarget'),
245 ]
246 for dir in dirs:
247 if not os.path.isdir(dir):
248 print('{} is not a directory'.format(dir))
249
250 out = StringIO()
251 for cell in CELLS:
252 xtract_cell_decl(cell, dirs, out)
253
254 with open('cells_xtra.v', 'w') as f:
255 f.write('// Created by cells_xtra.py from Xilinx models\n')
256 f.write('\n')
257 f.write(out.getvalue())