vc4: Introduce XML-based packet header generation like Intel's.
[mesa.git] / src / broadcom / cle / gen_pack_header.py
1 #encoding=utf-8
2
3 # Copyright (C) 2016 Intel Corporation
4 # Copyright (C) 2016 Broadcom
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a
7 # copy of this software and associated documentation files (the "Software"),
8 # to deal in the Software without restriction, including without limitation
9 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 # and/or sell copies of the Software, and to permit persons to whom the
11 # Software is furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice (including the next
14 # paragraph) shall be included in all copies or substantial portions of the
15 # Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24
25 from __future__ import (
26 absolute_import, division, print_function, unicode_literals
27 )
28 import xml.parsers.expat
29 import re
30 import sys
31 import copy
32
33 license = """/* Generated code, see packets.xml and gen_packet_header.py */
34 """
35
36 pack_header = """%(license)s
37
38 /* Packets, enums and structures for %(platform)s.
39 *
40 * This file has been generated, do not hand edit.
41 */
42
43 #ifndef %(guard)s
44 #define %(guard)s
45
46 #include "v3d_packet_helpers.h"
47
48 """
49
50 def to_alphanum(name):
51 substitutions = {
52 ' ': '_',
53 '/': '_',
54 '[': '',
55 ']': '',
56 '(': '',
57 ')': '',
58 '-': '_',
59 ':': '',
60 '.': '',
61 ',': '',
62 '=': '',
63 '>': '',
64 '#': '',
65 'α': 'alpha',
66 '&': '',
67 '*': '',
68 '"': '',
69 '+': '',
70 '\'': '',
71 }
72
73 for i, j in substitutions.items():
74 name = name.replace(i, j)
75
76 return name
77
78 def safe_name(name):
79 name = to_alphanum(name)
80 if not name[0].isalpha():
81 name = '_' + name
82
83 return name
84
85 def num_from_str(num_str):
86 if num_str.lower().startswith('0x'):
87 return int(num_str, base=16)
88 else:
89 assert(not num_str.startswith('0') and 'octals numbers not allowed')
90 return int(num_str)
91
92 class Field(object):
93 ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")
94 sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")
95
96 def __init__(self, parser, attrs):
97 self.parser = parser
98 if "name" in attrs:
99 self.name = safe_name(attrs["name"]).lower()
100
101 if str(attrs["start"]).endswith("b"):
102 self.start = int(attrs["start"][:-1]) * 8
103 else:
104 self.start = int(attrs["start"])
105 # packet <field> entries in XML start from the bit after the
106 # opcode, so shift everything up by 8 since we'll also have a
107 # Field for the opcode.
108 if not parser.struct:
109 self.start += 8
110
111 self.end = self.start + int(attrs["size"]) - 1
112 self.type = attrs["type"]
113
114 if "prefix" in attrs:
115 self.prefix = safe_name(attrs["prefix"]).upper()
116 else:
117 self.prefix = None
118
119 if "default" in attrs:
120 self.default = int(attrs["default"])
121 else:
122 self.default = None
123
124 ufixed_match = Field.ufixed_pattern.match(self.type)
125 if ufixed_match:
126 self.type = 'ufixed'
127 self.fractional_size = int(ufixed_match.group(2))
128
129 sfixed_match = Field.sfixed_pattern.match(self.type)
130 if sfixed_match:
131 self.type = 'sfixed'
132 self.fractional_size = int(sfixed_match.group(2))
133
134 def emit_template_struct(self, dim):
135 if self.type == 'address':
136 type = '__gen_address_type'
137 elif self.type == 'bool':
138 type = 'bool'
139 elif self.type == 'float':
140 type = 'float'
141 elif self.type == 'ufixed':
142 type = 'float'
143 elif self.type == 'sfixed':
144 type = 'float'
145 elif self.type == 'uint' and self.end - self.start > 32:
146 type = 'uint64_t'
147 elif self.type == 'offset':
148 type = 'uint64_t'
149 elif self.type == 'int':
150 type = 'int32_t'
151 elif self.type == 'uint':
152 type = 'uint32_t'
153 elif self.type in self.parser.structs:
154 type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))
155 elif self.type == 'mbo':
156 return
157 else:
158 print("#error unhandled type: %s" % self.type)
159
160 print(" %-36s %s%s;" % (type, self.name, dim))
161
162 if len(self.values) > 0 and self.default == None:
163 if self.prefix:
164 prefix = self.prefix + "_"
165 else:
166 prefix = ""
167
168 for value in self.values:
169 print("#define %-40s %d" % ((prefix + value.name).replace("__", "_"),
170 value.value))
171
172 def overlaps(self, field):
173 return self != field and max(self.start, field.start) <= min(self.end, field.end)
174
175
176 class Group(object):
177 def __init__(self, parser, parent, start, count):
178 self.parser = parser
179 self.parent = parent
180 self.start = start
181 self.count = count
182 self.size = 0
183 self.fields = []
184
185 def emit_template_struct(self, dim):
186 if self.count == 0:
187 print(" /* variable length fields follow */")
188 else:
189 if self.count > 1:
190 dim = "%s[%d]" % (dim, self.count)
191
192 for field in self.fields:
193 field.emit_template_struct(dim)
194
195 class Byte:
196 def __init__(self):
197 self.size = 8
198 self.fields = []
199 self.address = None
200
201 def collect_bytes(self, bytes):
202 for field in self.fields:
203 first_byte = field.start // 8
204 last_byte = field.end // 8
205
206 for b in xrange(first_byte, last_byte + 1):
207 if not b in bytes:
208 bytes[b] = self.Byte()
209
210 bytes[b].fields.append(field)
211
212 if field.type == "address":
213 # assert bytes[index].address == None
214 bytes[b].address = field
215
216 def emit_pack_function(self, start):
217 # Determine number of bytes in this group.
218 self.length = max(field.end // 8 for field in self.fields) + 1
219
220 bytes = {}
221 self.collect_bytes(bytes)
222
223 relocs_emitted = set()
224 memcpy_fields = set()
225
226 for index in range(self.length):
227 # Handle MBZ bytes
228 if not index in bytes:
229 print(" cl[%2d] = 0;" % index)
230 continue
231 byte = bytes[index]
232
233 # Call out to the driver to note our relocations. Inside of the
234 # packet we only store offsets within the BOs, and we store the
235 # handle to the packet outside. Unlike Intel genxml, we don't
236 # need to have the other bits that will be stored together with
237 # the address during the reloc process, so there's no need for the
238 # complicated combine_address() function.
239 if byte.address and byte.address not in relocs_emitted:
240 print(" __gen_emit_reloc(data, &values->%s);" % byte.address.name)
241 relocs_emitted.add(byte.address)
242
243 # Special case: floats can't have any other fields packed into
244 # them (since they'd change the meaning of the float), and the
245 # per-byte bitshifting math below bloats the pack code for floats,
246 # so just copy them directly here. Also handle 16/32-bit
247 # uints/ints with no merged fields.
248 if len(byte.fields) == 1:
249 field = byte.fields[0]
250 if field.type in ["float", "uint", "int"] and field.start % 8 == 0 and field.end - field.start == 31:
251 if field in memcpy_fields:
252 continue
253
254 if not any(field.overlaps(scan_field) for scan_field in self.fields):
255 assert(field.start == index * 8)
256 print("")
257 print(" memcpy(&cl[%d], &values->%s, sizeof(values->%s));" %
258 (index, field.name, field.name))
259 memcpy_fields.add(field)
260 continue
261
262 byte_start = index * 8
263
264 v = None
265 prefix = " cl[%2d] =" % index
266
267 field_index = 0
268 for field in byte.fields:
269 if field.type != "mbo":
270 name = field.name
271
272 start = field.start
273 end = field.end
274 field_byte_start = (field.start // 8) * 8
275 start -= field_byte_start
276 end -= field_byte_start
277
278 if field.type == "mbo":
279 s = "__gen_mbo(%d, %d)" % \
280 (start, end)
281 elif field.type == "address":
282 s = "__gen_address_offset(&values->%s)" % byte.address.name
283 elif field.type == "uint":
284 s = "__gen_uint(values->%s, %d, %d)" % \
285 (name, start, end)
286 elif field.type == "int":
287 s = "__gen_sint(values->%s, %d, %d)" % \
288 (name, start, end)
289 elif field.type == "bool":
290 s = "__gen_uint(values->%s, %d, %d)" % \
291 (name, start, end)
292 elif field.type == "float":
293 s = "#error %s float value mixed in with other fields" % name
294 elif field.type == "offset":
295 s = "__gen_offset(values->%s, %d, %d)" % \
296 (name, start, end)
297 elif field.type == 'ufixed':
298 s = "__gen_ufixed(values->%s, %d, %d, %d)" % \
299 (name, start, end, field.fractional_size)
300 elif field.type == 'sfixed':
301 s = "__gen_sfixed(values->%s, %d, %d, %d)" % \
302 (name, start, end, field.fractional_size)
303 elif field.type in self.parser.structs:
304 s = "__gen_uint(v%d_%d, %d, %d)" % \
305 (index, field_index, start, end)
306 field_index = field_index + 1
307 else:
308 print("/* unhandled field %s, type %s */\n" % (name, field.type))
309 s = None
310
311 if not s == None:
312 if byte_start - field_byte_start != 0:
313 s = "%s >> %d" % (s, byte_start - field_byte_start)
314
315 if field == byte.fields[-1]:
316 print("%s %s;" % (prefix, s))
317 else:
318 print("%s %s |" % (prefix, s))
319 prefix = " "
320
321 print("")
322 continue
323
324 def emit_unpack_function(self, start):
325 for field in self.fields:
326 if field.type != "mbo":
327 convert = None
328
329 if field.type == "address":
330 convert = "__gen_unpack_address"
331 elif field.type == "uint":
332 convert = "__gen_unpack_uint"
333 elif field.type == "int":
334 convert = "__gen_unpack_sint"
335 elif field.type == "bool":
336 convert = "__gen_unpack_uint"
337 elif field.type == "float":
338 convert = "__gen_unpack_float"
339 elif field.type == "offset":
340 convert = "__gen_unpack_offset"
341 elif field.type == 'ufixed':
342 convert = "__gen_unpack_ufixed"
343 elif field.type == 'sfixed':
344 convert = "__gen_unpack_sfixed"
345 else:
346 print("/* unhandled field %s, type %s */\n" % (name, field.type))
347 s = None
348
349 print(" values->%s = %s(cl, %s, %s);" % \
350 (field.name, convert, \
351 start + field.start, start + field.end))
352
353
354 class Value(object):
355 def __init__(self, attrs):
356 self.name = safe_name(attrs["name"]).upper()
357 self.value = int(attrs["value"])
358
359 class Parser(object):
360 def __init__(self):
361 self.parser = xml.parsers.expat.ParserCreate()
362 self.parser.StartElementHandler = self.start_element
363 self.parser.EndElementHandler = self.end_element
364
365 self.packet = None
366 self.struct = None
367 self.structs = {}
368 self.registers = {}
369
370 def gen_prefix(self, name):
371 if name[0] == "_":
372 return 'V3D%s%s' % (self.ver, name)
373 else:
374 return 'V3D%s_%s' % (self.ver, name)
375
376 def gen_guard(self):
377 return self.gen_prefix("PACK_H")
378
379 def start_element(self, name, attrs):
380 if name == "vcxml":
381 self.platform = "V3D {}".format(attrs["ver"])
382 self.ver = attrs["ver"].replace('.', '')
383 print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})
384 elif name in ("packet", "struct", "register"):
385 default_field = None
386
387 object_name = self.gen_prefix(safe_name(attrs["name"].upper()))
388 if name == "packet":
389 self.packet = object_name
390
391 # Add a fixed Field for the opcode. We only make <field>s in
392 # the XML for the fields listed in the spec, and all of those
393 # start from bit 0 after of the opcode.
394 default_field = {
395 "name" : "opcode",
396 "default" : attrs["code"],
397 "type" : "uint",
398 "start" : -8,
399 "size" : 8,
400 }
401 elif name == "struct":
402 self.struct = object_name
403 self.structs[attrs["name"]] = 1
404 elif name == "register":
405 self.register = object_name
406 self.reg_num = num_from_str(attrs["num"])
407 self.registers[attrs["name"]] = 1
408
409 self.group = Group(self, None, 0, 1)
410 if default_field:
411 field = Field(self, default_field)
412 field.values = []
413 self.group.fields.append(field)
414
415 elif name == "field":
416 self.group.fields.append(Field(self, attrs))
417 self.values = []
418 elif name == "enum":
419 self.values = []
420 self.enum = safe_name(attrs["name"])
421 if "prefix" in attrs:
422 self.prefix = safe_name(attrs["prefix"])
423 else:
424 self.prefix= None
425 elif name == "value":
426 self.values.append(Value(attrs))
427
428 def end_element(self, name):
429 if name == "packet":
430 self.emit_packet()
431 self.packet = None
432 self.group = None
433 elif name == "struct":
434 self.emit_struct()
435 self.struct = None
436 self.group = None
437 elif name == "register":
438 self.emit_register()
439 self.register = None
440 self.reg_num = None
441 self.group = None
442 elif name == "field":
443 self.group.fields[-1].values = self.values
444 elif name == "enum":
445 self.emit_enum()
446 self.enum = None
447 elif name == "vcxml":
448 print('#endif /* %s */' % self.gen_guard())
449
450 def emit_template_struct(self, name, group):
451 print("struct %s {" % name)
452 group.emit_template_struct("")
453 print("};\n")
454
455 def emit_pack_function(self, name, group):
456 print("static inline void\n%s_pack(__gen_user_data *data, uint8_t * restrict cl,\n%sconst struct %s * restrict values)\n{" %
457 (name, ' ' * (len(name) + 6), name))
458
459 group.emit_pack_function(0)
460
461 print("}\n")
462
463 print('#define %-33s %6d' %
464 (name + "_length", self.group.length))
465
466 def emit_unpack_function(self, name, group):
467 print("#ifdef __gen_unpack_address")
468 print("static inline void")
469 print("%s_unpack(const uint8_t * restrict cl,\n%sstruct %s * restrict values)\n{" %
470 (name, ' ' * (len(name) + 8), name))
471
472 group.emit_unpack_function(0)
473
474 print("}\n#endif\n")
475
476 def emit_packet(self):
477 name = self.packet
478
479 assert(self.group.fields[0].name == "opcode")
480 print('#define %-33s %6d' %
481 (name + "_opcode", self.group.fields[0].default))
482
483 default_fields = []
484 for field in self.group.fields:
485 if not type(field) is Field:
486 continue
487 if field.default == None:
488 continue
489 default_fields.append(" .%-35s = %6d" % (field.name, field.default))
490
491 if default_fields:
492 print('#define %-40s\\' % (name + '_header'))
493 print(", \\\n".join(default_fields))
494 print('')
495
496 self.emit_template_struct(self.packet, self.group)
497 self.emit_pack_function(self.packet, self.group)
498 self.emit_unpack_function(self.packet, self.group)
499
500 print('')
501
502 def emit_register(self):
503 name = self.register
504 if not self.reg_num == None:
505 print('#define %-33s 0x%04x' %
506 (self.gen_prefix(name + "_num"), self.reg_num))
507
508 self.emit_template_struct(self.register, self.group)
509 self.emit_pack_function(self.register, self.group)
510 self.emit_unpack_function(self.register, self.group)
511
512 def emit_struct(self):
513 name = self.struct
514 # Emit an empty header define so that we can use the CL pack functions
515 # with structs.
516 print('#define ' + name + '_header')
517
518 self.emit_template_struct(self.struct, self.group)
519 self.emit_pack_function(self.struct, self.group)
520 self.emit_unpack_function(self.struct, self.group)
521
522 print('')
523
524 def emit_enum(self):
525 print('/* enum %s */' % self.gen_prefix(self.enum))
526 for value in self.values:
527 if self.prefix:
528 name = self.prefix + "_" + value.name
529 else:
530 name = value.name
531 print('#define %-36s %6d' % (name.upper(), value.value))
532 print('')
533
534 def parse(self, filename):
535 file = open(filename, "rb")
536 self.parser.ParseFile(file)
537 file.close()
538
539 if len(sys.argv) < 2:
540 print("No input xml file specified")
541 sys.exit(1)
542
543 input_file = sys.argv[1]
544
545 p = Parser()
546 p.parse(input_file)