broadcom/genxml: Stop manually scrubbing 'α' -> "alpha"
[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 v3d_packet_v21.xml, v3d_packet_v33.xml and gen_pack_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 "cle/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 '&': '',
66 '*': '',
67 '"': '',
68 '+': '',
69 '\'': '',
70 }
71
72 for i, j in substitutions.items():
73 name = name.replace(i, j)
74
75 return name
76
77 def safe_name(name):
78 name = to_alphanum(name)
79 if not name[0].isalpha():
80 name = '_' + name
81
82 return name
83
84 def prefixed_upper_name(prefix, name):
85 if prefix:
86 name = prefix + "_" + name
87 return safe_name(name).upper()
88
89 def num_from_str(num_str):
90 if num_str.lower().startswith('0x'):
91 return int(num_str, base=16)
92 else:
93 assert(not num_str.startswith('0') and 'octals numbers not allowed')
94 return int(num_str)
95
96 class Field(object):
97 ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")
98 sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")
99
100 def __init__(self, parser, attrs):
101 self.parser = parser
102 if "name" in attrs:
103 self.name = safe_name(attrs["name"]).lower()
104
105 if str(attrs["start"]).endswith("b"):
106 self.start = int(attrs["start"][:-1]) * 8
107 else:
108 self.start = int(attrs["start"])
109 # packet <field> entries in XML start from the bit after the
110 # opcode, so shift everything up by 8 since we'll also have a
111 # Field for the opcode.
112 if not parser.struct:
113 self.start += 8
114
115 self.end = self.start + int(attrs["size"]) - 1
116 self.type = attrs["type"]
117
118 if self.type == 'bool' and self.start != self.end:
119 print("#error Field {} has bool type but more than one bit of size".format(self.name));
120
121 if "prefix" in attrs:
122 self.prefix = safe_name(attrs["prefix"]).upper()
123 else:
124 self.prefix = None
125
126 if "default" in attrs:
127 self.default = int(attrs["default"])
128 else:
129 self.default = None
130
131 if "minus_one" in attrs:
132 assert(attrs["minus_one"] == "true")
133 self.minus_one = True
134 else:
135 self.minus_one = False
136
137 ufixed_match = Field.ufixed_pattern.match(self.type)
138 if ufixed_match:
139 self.type = 'ufixed'
140 self.fractional_size = int(ufixed_match.group(2))
141
142 sfixed_match = Field.sfixed_pattern.match(self.type)
143 if sfixed_match:
144 self.type = 'sfixed'
145 self.fractional_size = int(sfixed_match.group(2))
146
147 def emit_template_struct(self, dim):
148 if self.type == 'address':
149 type = '__gen_address_type'
150 elif self.type == 'bool':
151 type = 'bool'
152 elif self.type == 'float':
153 type = 'float'
154 elif self.type == 'f187':
155 type = 'float'
156 elif self.type == 'ufixed':
157 type = 'float'
158 elif self.type == 'sfixed':
159 type = 'float'
160 elif self.type == 'uint' and self.end - self.start > 32:
161 type = 'uint64_t'
162 elif self.type == 'offset':
163 type = 'uint64_t'
164 elif self.type == 'int':
165 type = 'int32_t'
166 elif self.type == 'uint':
167 type = 'uint32_t'
168 elif self.type in self.parser.structs:
169 type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))
170 elif self.type in self.parser.enums:
171 type = 'enum ' + self.parser.gen_prefix(safe_name(self.type))
172 elif self.type == 'mbo':
173 return
174 else:
175 print("#error unhandled type: %s" % self.type)
176 type = "uint32_t"
177
178 print(" %-36s %s%s;" % (type, self.name, dim))
179
180 for value in self.values:
181 name = prefixed_upper_name(self.prefix, value.name)
182 print("#define %-40s %d" % (name, value.value))
183
184 def overlaps(self, field):
185 return self != field and max(self.start, field.start) <= min(self.end, field.end)
186
187
188 class Group(object):
189 def __init__(self, parser, parent, start, count):
190 self.parser = parser
191 self.parent = parent
192 self.start = start
193 self.count = count
194 self.size = 0
195 self.fields = []
196 self.min_ver = 0
197 self.max_ver = 0
198
199 def emit_template_struct(self, dim):
200 if self.count == 0:
201 print(" /* variable length fields follow */")
202 else:
203 if self.count > 1:
204 dim = "%s[%d]" % (dim, self.count)
205
206 for field in self.fields:
207 field.emit_template_struct(dim)
208
209 class Byte:
210 def __init__(self):
211 self.size = 8
212 self.fields = []
213 self.address = None
214
215 def collect_bytes(self, bytes):
216 for field in self.fields:
217 first_byte = field.start // 8
218 last_byte = field.end // 8
219
220 for b in range(first_byte, last_byte + 1):
221 if not b in bytes:
222 bytes[b] = self.Byte()
223
224 bytes[b].fields.append(field)
225
226 if field.type == "address":
227 # assert bytes[index].address == None
228 bytes[b].address = field
229
230 def emit_pack_function(self, start):
231 # Determine number of bytes in this group.
232 self.length = max(field.end // 8 for field in self.fields) + 1
233
234 bytes = {}
235 self.collect_bytes(bytes)
236
237 relocs_emitted = set()
238 memcpy_fields = set()
239
240 for field in self.fields:
241 if field.minus_one:
242 print(" assert(values->%s >= 1);" % field.name)
243
244 for index in range(self.length):
245 # Handle MBZ bytes
246 if not index in bytes:
247 print(" cl[%2d] = 0;" % index)
248 continue
249 byte = bytes[index]
250
251 # Call out to the driver to note our relocations. Inside of the
252 # packet we only store offsets within the BOs, and we store the
253 # handle to the packet outside. Unlike Intel genxml, we don't
254 # need to have the other bits that will be stored together with
255 # the address during the reloc process, so there's no need for the
256 # complicated combine_address() function.
257 if byte.address and byte.address not in relocs_emitted:
258 print(" __gen_emit_reloc(data, &values->%s);" % byte.address.name)
259 relocs_emitted.add(byte.address)
260
261 # Special case: floats can't have any other fields packed into
262 # them (since they'd change the meaning of the float), and the
263 # per-byte bitshifting math below bloats the pack code for floats,
264 # so just copy them directly here. Also handle 16/32-bit
265 # uints/ints with no merged fields.
266 if len(byte.fields) == 1:
267 field = byte.fields[0]
268 if field.type in ["float", "uint", "int"] and field.start % 8 == 0 and field.end - field.start == 31 and not field.minus_one:
269 if field in memcpy_fields:
270 continue
271
272 if not any(field.overlaps(scan_field) for scan_field in self.fields):
273 assert(field.start == index * 8)
274 print("")
275 print(" memcpy(&cl[%d], &values->%s, sizeof(values->%s));" %
276 (index, field.name, field.name))
277 memcpy_fields.add(field)
278 continue
279
280 byte_start = index * 8
281
282 v = None
283 prefix = " cl[%2d] =" % index
284
285 field_index = 0
286 for field in byte.fields:
287 if field.type != "mbo":
288 name = field.name
289
290 start = field.start
291 end = field.end
292 field_byte_start = (field.start // 8) * 8
293 start -= field_byte_start
294 end -= field_byte_start
295 extra_shift = 0
296
297 value = "values->%s" % name
298 if field.minus_one:
299 value = "%s - 1" % value
300
301 if field.type == "mbo":
302 s = "__gen_mbo(%d, %d)" % \
303 (start, end)
304 elif field.type == "address":
305 extra_shift = (31 - (end - start)) // 8 * 8
306 s = "__gen_address_offset(&values->%s)" % byte.address.name
307 elif field.type == "uint":
308 s = "__gen_uint(%s, %d, %d)" % \
309 (value, start, end)
310 elif field.type in self.parser.enums:
311 s = "__gen_uint(%s, %d, %d)" % \
312 (value, start, end)
313 elif field.type == "int":
314 s = "__gen_sint(%s, %d, %d)" % \
315 (value, start, end)
316 elif field.type == "bool":
317 s = "__gen_uint(%s, %d, %d)" % \
318 (value, start, end)
319 elif field.type == "float":
320 s = "#error %s float value mixed in with other fields" % name
321 elif field.type == "f187":
322 s = "__gen_uint(fui(%s) >> 16, %d, %d)" % \
323 (value, start, end)
324 elif field.type == "offset":
325 s = "__gen_offset(%s, %d, %d)" % \
326 (value, start, end)
327 elif field.type == 'ufixed':
328 s = "__gen_ufixed(%s, %d, %d, %d)" % \
329 (value, start, end, field.fractional_size)
330 elif field.type == 'sfixed':
331 s = "__gen_sfixed(%s, %d, %d, %d)" % \
332 (value, start, end, field.fractional_size)
333 elif field.type in self.parser.structs:
334 s = "__gen_uint(v%d_%d, %d, %d)" % \
335 (index, field_index, start, end)
336 field_index = field_index + 1
337 else:
338 print("/* unhandled field %s, type %s */\n" % (name, field.type))
339 s = None
340
341 if not s == None:
342 shift = byte_start - field_byte_start + extra_shift
343 if shift:
344 s = "%s >> %d" % (s, shift)
345
346 if field == byte.fields[-1]:
347 print("%s %s;" % (prefix, s))
348 else:
349 print("%s %s |" % (prefix, s))
350 prefix = " "
351
352 print("")
353 continue
354
355 def emit_unpack_function(self, start):
356 for field in self.fields:
357 if field.type != "mbo":
358 convert = None
359
360 args = []
361 args.append('cl')
362 args.append(str(start + field.start))
363 args.append(str(start + field.end))
364
365 if field.type == "address":
366 convert = "__gen_unpack_address"
367 elif field.type == "uint":
368 convert = "__gen_unpack_uint"
369 elif field.type in self.parser.enums:
370 convert = "__gen_unpack_uint"
371 elif field.type == "int":
372 convert = "__gen_unpack_sint"
373 elif field.type == "bool":
374 convert = "__gen_unpack_uint"
375 elif field.type == "float":
376 convert = "__gen_unpack_float"
377 elif field.type == "f187":
378 convert = "__gen_unpack_f187"
379 elif field.type == "offset":
380 convert = "__gen_unpack_offset"
381 elif field.type == 'ufixed':
382 args.append(str(field.fractional_size))
383 convert = "__gen_unpack_ufixed"
384 elif field.type == 'sfixed':
385 args.append(str(field.fractional_size))
386 convert = "__gen_unpack_sfixed"
387 else:
388 print("/* unhandled field %s, type %s */\n" % (field.name, field.type))
389 s = None
390
391 plusone = ""
392 if field.minus_one:
393 plusone = " + 1"
394 print(" values->%s = %s(%s)%s;" % \
395 (field.name, convert, ', '.join(args), plusone))
396
397 class Value(object):
398 def __init__(self, attrs):
399 self.name = attrs["name"]
400 self.value = int(attrs["value"])
401
402 class Parser(object):
403 def __init__(self, ver):
404 self.parser = xml.parsers.expat.ParserCreate()
405 self.parser.StartElementHandler = self.start_element
406 self.parser.EndElementHandler = self.end_element
407
408 self.packet = None
409 self.struct = None
410 self.structs = {}
411 # Set of enum names we've seen.
412 self.enums = set()
413 self.registers = {}
414 self.ver = ver
415
416 def gen_prefix(self, name):
417 if name[0] == "_":
418 return 'V3D%s%s' % (self.ver, name)
419 else:
420 return 'V3D%s_%s' % (self.ver, name)
421
422 def gen_guard(self):
423 return self.gen_prefix("PACK_H")
424
425 def attrs_version_valid(self, attrs):
426 if "min_ver" in attrs and self.ver < attrs["min_ver"]:
427 return False
428
429 if "max_ver" in attrs and self.ver > attrs["max_ver"]:
430 return False
431
432 return True
433
434 def group_enabled(self):
435 if self.group.min_ver != 0 and self.ver < self.group.min_ver:
436 return False
437
438 if self.group.max_ver != 0 and self.ver > self.group.max_ver:
439 return False
440
441 return True
442
443 def start_element(self, name, attrs):
444 if name == "vcxml":
445 self.platform = "V3D {}.{}".format(self.ver[0], self.ver[1])
446 print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})
447 elif name in ("packet", "struct", "register"):
448 default_field = None
449
450 object_name = self.gen_prefix(safe_name(attrs["name"].upper()))
451 if name == "packet":
452 self.packet = object_name
453
454 # Add a fixed Field for the opcode. We only make <field>s in
455 # the XML for the fields listed in the spec, and all of those
456 # start from bit 0 after of the opcode.
457 default_field = {
458 "name" : "opcode",
459 "default" : attrs["code"],
460 "type" : "uint",
461 "start" : -8,
462 "size" : 8,
463 }
464 elif name == "struct":
465 self.struct = object_name
466 self.structs[attrs["name"]] = 1
467 elif name == "register":
468 self.register = object_name
469 self.reg_num = num_from_str(attrs["num"])
470 self.registers[attrs["name"]] = 1
471
472 self.group = Group(self, None, 0, 1)
473 if default_field:
474 field = Field(self, default_field)
475 field.values = []
476 self.group.fields.append(field)
477
478 if "min_ver" in attrs:
479 self.group.min_ver = attrs["min_ver"]
480 if "max_ver" in attrs:
481 self.group.max_ver = attrs["max_ver"]
482
483 elif name == "field":
484 self.group.fields.append(Field(self, attrs))
485 self.values = []
486 elif name == "enum":
487 self.values = []
488 self.enum = safe_name(attrs["name"])
489 self.enums.add(attrs["name"])
490 self.enum_enabled = self.attrs_version_valid(attrs)
491 if "prefix" in attrs:
492 self.prefix = attrs["prefix"]
493 else:
494 self.prefix= None
495 elif name == "value":
496 if self.attrs_version_valid(attrs):
497 self.values.append(Value(attrs))
498
499 def end_element(self, name):
500 if name == "packet":
501 self.emit_packet()
502 self.packet = None
503 self.group = None
504 elif name == "struct":
505 self.emit_struct()
506 self.struct = None
507 self.group = None
508 elif name == "register":
509 self.emit_register()
510 self.register = None
511 self.reg_num = None
512 self.group = None
513 elif name == "field":
514 self.group.fields[-1].values = self.values
515 elif name == "enum":
516 if self.enum_enabled:
517 self.emit_enum()
518 self.enum = None
519 elif name == "vcxml":
520 print('#endif /* %s */' % self.gen_guard())
521
522 def emit_template_struct(self, name, group):
523 print("struct %s {" % name)
524 group.emit_template_struct("")
525 print("};\n")
526
527 def emit_pack_function(self, name, group):
528 print("static inline void\n%s_pack(__gen_user_data *data, uint8_t * restrict cl,\n%sconst struct %s * restrict values)\n{" %
529 (name, ' ' * (len(name) + 6), name))
530
531 group.emit_pack_function(0)
532
533 print("}\n")
534
535 print('#define %-33s %6d' %
536 (name + "_length", self.group.length))
537
538 def emit_unpack_function(self, name, group):
539 print("#ifdef __gen_unpack_address")
540 print("static inline void")
541 print("%s_unpack(const uint8_t * restrict cl,\n%sstruct %s * restrict values)\n{" %
542 (name, ' ' * (len(name) + 8), name))
543
544 group.emit_unpack_function(0)
545
546 print("}\n#endif\n")
547
548 def emit_header(self, name):
549 default_fields = []
550 for field in self.group.fields:
551 if not type(field) is Field:
552 continue
553 if field.default == None:
554 continue
555 default_fields.append(" .%-35s = %6d" % (field.name, field.default))
556
557 print('#define %-40s\\' % (name + '_header'))
558 print(", \\\n".join(default_fields))
559 print('')
560
561 def emit_packet(self):
562 if not self.group_enabled():
563 return
564
565 name = self.packet
566
567 assert(self.group.fields[0].name == "opcode")
568 print('#define %-33s %6d' %
569 (name + "_opcode", self.group.fields[0].default))
570
571 self.emit_header(name)
572 self.emit_template_struct(self.packet, self.group)
573 self.emit_pack_function(self.packet, self.group)
574 self.emit_unpack_function(self.packet, self.group)
575
576 print('')
577
578 def emit_register(self):
579 if not self.group_enabled():
580 return
581
582 name = self.register
583 if not self.reg_num == None:
584 print('#define %-33s 0x%04x' %
585 (self.gen_prefix(name + "_num"), self.reg_num))
586
587 self.emit_template_struct(self.register, self.group)
588 self.emit_pack_function(self.register, self.group)
589 self.emit_unpack_function(self.register, self.group)
590
591 def emit_struct(self):
592 if not self.group_enabled():
593 return
594
595 name = self.struct
596
597 self.emit_header(name)
598 self.emit_template_struct(self.struct, self.group)
599 self.emit_pack_function(self.struct, self.group)
600 self.emit_unpack_function(self.struct, self.group)
601
602 print('')
603
604 def emit_enum(self):
605 print('enum %s {' % self.gen_prefix(self.enum))
606 for value in self.values:
607 name = value.name
608 if self.prefix:
609 name = self.prefix + "_" + name
610 name = safe_name(name).upper()
611 print(' % -36s = %6d,' % (name, value.value))
612 print('};\n')
613
614 def parse(self, filename):
615 file = open(filename, "rb")
616 self.parser.ParseFile(file)
617 file.close()
618
619 if len(sys.argv) < 2:
620 print("No input xml file specified")
621 sys.exit(1)
622
623 input_file = sys.argv[1]
624
625 p = Parser(sys.argv[2])
626 p.parse(input_file)