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