Merge pull request #218 from saper/build-fixes
[envytools.git] / rnn / rules2rnn
blob8641e463cd89a57a9778dd4e48a5d9e1e121758b
1 #!/usr/bin/env python
2 import subprocess
3 import sys
4 import os
5 import bisect
6 from lxml import etree as ET
8 colon = "39584ac56e6d0976692778b80915f94b61767814a8704982"
10 def hexa(v):
11 if v <= 9:
12 return str(v)
13 else:
14 return hex(v)
17 # from renouveau.xml
18 # the rules.xml names suck
19 known_objclasses = {
20 0x0001 : "NV01_ROOT",
21 0x0002 : "NV01_CONTEXT_DMA",
22 0x0003 : "NV01_DEVICE",
23 0x0004 : "NV01_TIMER",
24 0x0012 : "NV01_CONTEXT_BETA1",
25 0x0017 : "NV01_CONTEXT_COLOR_KEY",
26 0x0057 : "NV04_CONTEXT_COLOR_KEY",
27 0x0018 : "NV01_CONTEXT_PATTERN",
28 0x0019 : "NV01_CONTEXT_CLIP_RECTANGLE",
29 0x001c : "NV01_RENDER_SOLID_LINE",
30 0x005c : "NV04_RENDER_SOLID_LINE",
31 0x001d : "NV01_RENDER_SOLID_TRIANGLE",
32 0x005d : "NV04_RENDER_SOLID_TRIANGLE",
33 0x001e : "NV01_RENDER_SOLID_RECTANGLE",
34 0x005e : "NV04_RENDER_SOLID_RECTANGLE",
35 0x001f : "NV01_IMAGE_BLIT",
36 0x005f : "NV04_IMAGE_BLIT",
37 0x009f : "NV12_IMAGE_BLIT",
38 0x0021 : "NV01_IMAGE_FROM_CPU",
39 0x0061 : "NV04_IMAGE_FROM_CPU",
40 0x0065 : "NV05_IMAGE_FROM_CPU",
41 0x008a : "NV10_IMAGE_FROM_CPU",
42 0x038a : "NV30_IMAGE_FROM_CPU",
43 0x308a : "NV40_IMAGE_FROM_CPU",
44 0x0030 : "NV01_NULL",
45 0x0036 : "NV03_STRETCHED_IMAGE_FROM_CPU",
46 0x0076 : "NV04_STRETCHED_IMAGE_FROM_CPU",
47 0x0066 : "NV05_STRETCHED_IMAGE_FROM_CPU",
48 0x0366 : "NV30_STRETCHED_IMAGE_FROM_CPU",
49 0x3066 : "NV40_STRETCHED_IMAGE_FROM_CPU",
50 0x0037 : "NV03_SCALED_IMAGE_FROM_MEMORY",
51 0x0077 : "NV04_SCALED_IMAGE_FROM_MEMORY",
52 0x0063 : "NV05_SCALED_IMAGE_FROM_MEMORY",
53 0x0089 : "NV10_SCALED_IMAGE_FROM_MEMORY",
54 0x0389 : "NV30_SCALED_IMAGE_FROM_MEMORY",
55 0x3089 : "NV40_SCALED_IMAGE_FROM_MEMORY",
56 0x0038 : "NV04_DVD_SUBPICTURE",
57 0x0088 : "NV10_DVD_SUBPICTURE",
58 0x0039 : "NV04_MEMORY_TO_MEMORY_FORMAT",
59 0x5039 : "NV50_MEMORY_TO_MEMORY_FORMAT",
60 0x003d : "NV01_MEMORY_LOCAL_BANKED",
61 # 0x003e : "NV01_MAPPING_SYSTEM",
62 0x003f : "NV03_MEMORY_LOCAL_CURSOR",
63 0x0040 : "NV01_MEMORY_LOCAL_LINEAR",
64 0x0041 : "NV01_MAPPING_LOCAL",
65 0x0042 : "NV04_CONTEXT_SURFACES_2D",
66 0x0062 : "NV10_CONTEXT_SURFACES_2D",
67 0x0362 : "NV30_CONTEXT_SURFACES_2D",
68 0x3062 : "NV40_CONTEXT_SURFACES_2D",
69 0x0043 : "NV03_CONTEXT_ROP",
70 0x0044 : "NV04_IMAGE_PATTERN",
71 0x0046 : "NV03_VIDEO_LUT_CURSOR_DAC",
72 0x0048 : "NV03_TEXTURED_TRIANGLE",
73 0x004a : "NV04_GDI_RECTANGLE_TEXT",
74 0x004b : "NV03_GDI_RECTANGLE_TEXT",
75 0x0052 : "NV04_SWIZZLED_SURFACE",
76 0x009e : "NV20_SWIZZLED_SURFACE",
77 0x039e : "NV30_SWIZZLED_SURFACE",
78 0x309e : "NV40_SWIZZLED_SURFACE",
79 0x0053 : "NV04_CONTEXT_SURFACES_3D",
80 0x0093 : "NV10_CONTEXT_SURFACES_3D",
81 0x0054 : "NV04_TEXTURED_TRIANGLE",
82 0x0094 : "NV10_TEXTURED_TRIANGLE",
83 0x0055 : "NV04_MULTITEX_TRIANGLE",
84 0x0095 : "NV10_MULTITEX_TRIANGLE",
85 0x0056 : "NV10TCL",
86 0x0096 : "NV11TCL",
87 0x0099 : "NV17TCL",
88 0x0058 : "NV03_CONTEXT_SURFACES_2D",
89 0x005a : "NV03_CONTEXT_SURFACES_3D",
90 0x0060 : "NV04_INDEXED_IMAGE_FROM_CPU",
91 0x0064 : "NV05_INDEXED_IMAGE_FROM_CPU",
92 0x006a : "NV03_CHANNEL_PIO",
93 0x006b : "NV03_CHANNEL_DMA",
94 0x0072 : "NV04_BETA_SOLID",
95 0x007b : "NV10_TEXTURE_FROM_CPU",
96 0x037b : "NV30_TEXTURE_FROM_CPU",
97 0x307b : "NV40_TEXTURE_FROM_CPU",
98 0x007c : "NV10_VIDEO_DISPLAY",
99 0x0097 : "NV20TCL",
100 0x0597 : "NV25TCL",
101 0x0397 : "NV30TCL",
102 0x0497 : "NV35TCL",
103 0x0697 : "NV34TCL",
104 0x4097 : "NV40TCL",
105 0x4497 : "NV44TCL",
106 0x502d : "NV50_2D",
107 0x5097 : "NV50TCL",
108 0x8297 : "NV84TCL",
109 0x8397 : "NVA0TCL",
110 0x8597 : "NVA8TCL",
111 0x50c0 : "NV50_COMPUTE",
112 0x0010 : "NV_IMAGE_STENCIL",
113 0x0011 : "NV_IMAGE_BLEND_AND",
114 0x0013 : "NV_IMAGE_ROP_AND",
115 0x0015 : "NV_IMAGE_COLOR_KEY",
116 0x0064 : "NV01_IMAGE_SRCCOPY_AND",
117 0x0065 : "NV03_IMAGE_SRCCOPY",
118 0x0066 : "NV04_IMAGE_SRCCOPY_PREMULT",
119 0x0067 : "NV04_IMAGE_BLEND_PREMULT",
122 tree = ET.parse("rules.xml")
123 root = tree.getroot();
124 outdir = "rules"
125 try:
126 os.mkdir(outdir)
127 except:
128 pass
129 for subdir in ("mmio", "objects", "misc", "strange"):
130 try:
131 os.mkdir(outdir + "/" + subdir)
132 except:
133 pass
135 devobjs = []
137 address_stripeobjs = {}
138 objsuper_stripeobjs = {}
139 stripeobjs = []
141 class Stripe(object):
142 def __init__(self):
143 self.strange_name = None
144 self.objsuper = None
145 self.names = set()
146 self.members = {}
148 class Device(object):
149 pass
151 addendum = '<rule-database><device name="NV_PRMIO" start="0x00007100" end="0x0000710f" /><device name="NV_PCRTC" start="0x00600000" end="0x00600fff" /></rule-database>'
152 addendum_root = ET.fromstring(addendum)
153 for device in addendum_root.iterchildren(tag=ET.Element):
154 addendum_root.remove(device)
155 root.append(device)
157 for device in root.iterchildren(tag=ET.Element):
158 devobj = Device()
159 devobj.device = device
160 devobj.name = device.attrib["name"]
161 devobj.offset = int(device.attrib["start"], 0)
162 devobj.end = int(device.attrib["end"], 0) + 1
164 objclasses = {}
166 for reglike in device.iterchildren(tag=ET.Element):
167 if reglike.tag == "field-value":
168 if "name" in reglike.attrib and "value" in reglike.attrib:
169 objclasses[int(reglike.attrib["value"], 0)] = reglike.attrib["name"]
171 for objclass in objclasses:
172 if objclass in known_objclasses:
173 objclasses[objclass] = known_objclasses[objclass]
175 objclasses = [(name, num) for num, name in objclasses.items()]
176 objclasses.sort()
178 if not objclasses:
179 if devobj.name == "NV_UTOMEM":
180 objclasses = [("NV_IMAGE_TO_MEMORY", None)]
182 devobj.objclasses = objclasses
184 devobjs.append(devobj)
186 if devobj.objclasses:
187 objsuper = devobj.objclasses[0][0]
188 us = objsuper.find("_")
189 objsuper = objsuper[us + 1:]
190 stripeobj = objsuper_stripeobjs.get(objsuper)
191 else:
192 stripeobj = address_stripeobjs.get(devobj.offset)
194 if not stripeobj:
195 stripeobj = Stripe()
196 stripeobj.offset = devobj.offset
197 stripeobj.end = devobj.end
198 stripeobjs.append(stripeobj)
200 # don't merge stuff at offset 0, since they usually aren't in the MMIO domain
201 if not devobj.objclasses:
202 if devobj.offset != 0:
203 address_stripeobjs[devobj.offset] = stripeobj
204 else:
205 stripeobj.objsuper = objsuper
206 objsuper_stripeobjs[objsuper] = stripeobj
207 else:
208 if devobj.end > stripeobj.end:
209 stripeobj.end = devobj.end
210 stripeobj.names.add(devobj.name)
211 devobj.stripeobj = stripeobj
213 strange_stripeobjs = {}
215 def common_prefix_len(a, b):
216 i = 0
217 while a[i:i+1] == b[i:i+1]:
218 i += 1
219 return i
221 field_name_to_type_map = {"HANDLE" : "object", "STYLE" : "notify_style"}
222 uninteresting_field_names = ["VAL", "VALUE", "PARAMETER", "ADDRESS", "RESERVED", "DATA", "BLAH", "COUNT", "CNT", "ARGUMENT", "BITMAP", "OFFSET", "FIELD", "MODE", "LE"]
223 uninteresting_field_names += field_name_to_type_map.keys()
224 uninteresting_field_names = frozenset(uninteresting_field_names)
226 uninteresting_reglike_names = frozenset(["NOP", "NOTIFY", "SET_NOTIFY", "CTX_SWITCH"])
228 def process_values(field, rnn_field):
229 true_value = None
230 false_value = None
231 common_prefix = None
233 rnn_values = []
234 strong_bool = False
236 for field_value in field.iterchildren(tag=ET.Element):
237 if field_value.tag == "field-value":
238 field_value_name = field_value.attrib["name"]
239 rnn_value_name = field_value_name
240 if rnn_value_name.startswith(field_name + "_"):
241 rnn_value_name = field_value_name[len(field_name)+1:]
242 rnn_value = ET.Element("value")
243 rnn_value.attrib["name"] = rnn_value_name
244 rnn_value.attrib["value"] = hexa(int(field_value.attrib["value"], 0))
245 rnn_values.append(rnn_value)
246 rnn_field.append(rnn_value)
247 if rnn_value_name in ("FALSE", "OFF", "DISABLE", "DISABLED", "NO", "0"):
248 false_value = rnn_value
249 if rnn_value_name != "0":
250 strong_bool = True
251 if rnn_value_name in ("TRUE", "ON", "ENABLE", "ENABLED", "YES", "1"):
252 true_value = rnn_value
253 if rnn_value_name != "0":
254 strong_bool = True
256 # avoid reglikes with just "0 = 0"
257 if len(rnn_values) == 1 and rnn_values[0].attrib["name"] == "0" and rnn_values[0].attrib["value"] == "0":
258 rnn_field.remove(rnn_values[0])
259 rnn_values = []
260 elif len(rnn_values) and len(rnn_values) == ((1 if true_value is not None else 0) + (1 if false_value is not None else 0)):
261 if false_value is not None:
262 rnn_field.remove(false_value)
263 if true_value is not None:
264 rnn_field.remove(true_value)
265 rnn_field.attrib["type"] = "boolean"
267 if len(rnn_values) > 1 and rnn_field.attrib["name"] not in ("NOTIFY",):
268 for rnn_value in rnn_values:
269 rnn_value_name = rnn_value.attrib["name"]
270 if rnn_value_name == "INVALID" or rnn_value_name[0:1].isdigit():
271 pass
272 elif common_prefix is None:
273 common_prefix = rnn_value_name
274 else:
275 common_prefix = common_prefix[:common_prefix_len(common_prefix, rnn_value_name)]
277 if common_prefix:
278 us = common_prefix.rfind("_")
279 if us >= 0:
280 common_prefix = common_prefix[:us + 1]
281 if common_prefix:
282 for rnn_value in rnn_values:
283 if rnn_value.attrib["name"].startswith(common_prefix):
284 rnn_value.attrib["name"] = rnn_value.attrib["name"][len(common_prefix):]
285 rnn_field.attrib["name"] += "_" + common_prefix.rstrip("_")
287 #print ET.tostring(tree)
288 for devobj in devobjs:
289 for reglike in devobj.device.iterchildren(tag=ET.Element):
290 if reglike.tag == "register" or reglike.tag == "array":
291 address = int(reglike.attrib["address"], 0)
293 reglike_name = reglike.attrib["name"]
294 cand_devobjs = [(-common_prefix_len(cand_devobj.name, reglike_name), cand_devobj) for cand_devobj in devobjs if address >= cand_devobj.offset and address < cand_devobj.end]
295 cand_devobjs.sort()
296 cand_devobj = cand_devobjs[0][1]
297 stripeobj = cand_devobj.stripeobj
298 # if stripeobj.offset == 0:
300 if reglike_name.startswith(cand_devobj.name + "_"):
301 stripeobj = cand_devobj.stripeobj
302 if devobj.objclasses:
303 assert cand_devobj.objclasses
304 if cand_devobj.objclasses:
305 assert devobj.objclasses
306 objclasses = devobj.objclasses
307 else:
308 us = reglike_name.find("_")
309 us = reglike_name.find("_", us + 1)
310 strange_stripeobj_name = reglike_name[:us]
311 stripeobj = strange_stripeobjs.get(strange_stripeobj_name)
312 if not stripeobj:
313 stripeobj = Stripe()
314 stripeobj.strange_name = strange_stripeobj_name
315 stripeobj.offset = 0
316 stripeobj.end = 0xffffffff
317 strange_stripeobjs[strange_stripeobj_name] = stripeobj
318 stripeobjs.append(stripeobj)
320 objclasses = []
322 assert address >= cand_devobj.offset
323 assert address < cand_devobj.end
324 offset = address - cand_devobj.offset
326 if offset == 0 and objclasses:
327 continue
329 rnn_reglike_name = reglike_name
330 for device_name in stripeobj.names:
331 if rnn_reglike_name.startswith(device_name + "_"):
332 rnn_reglike_name = rnn_reglike_name[len(device_name) + 1:]
333 break
335 if rnn_reglike_name in uninteresting_reglike_names:
336 continue
338 rnn_reglike = ET.Element("reg32")
340 rnn_reglike.attrib["offset"] = hex(offset)
342 if reglike.tag == "array":
343 max_size = 0
344 for field in reglike.iterchildren(tag=ET.Element):
345 if field.tag == "array-size":
346 size = int(field.attrib["size"], 0)
347 if size > max_size:
348 max_size = size
349 rnn_reglike.attrib["length"] = str(max_size)
350 rnn_reglike.attrib["stride"] = str(int(reglike.attrib["width"], 0))
352 num_bitfields = 0
353 full_field_name = None
354 for field in reglike.iterchildren(tag=ET.Element):
355 if field.tag == "field":
356 i = 0 # for "i" variables in the low-bit and high-bit attributes
357 low = eval(field.attrib["low-bit"])
358 high = eval(field.attrib["high-bit"])
359 field_name = field.attrib["name"]
360 rnn_field_name = field_name
361 if rnn_field_name.startswith(reglike_name + "_"):
362 rnn_field_name = rnn_field_name[len(reglike_name)+1:]
364 if low == 0 and high == 31:
365 if rnn_field_name not in uninteresting_field_names and not rnn_field_name.startswith("NV_"):
366 full_field_name = rnn_field_name
367 if rnn_field_name in field_name_to_type_map:
368 rnn_reglike.attrib["type"] = field_name_to_type_map[rnn_field_name]
369 bitfield = rnn_reglike
370 for elem in field.iterchildren(tag=ET.Element):
371 field.remove(elem)
372 reglike.append(elem)
373 else:
374 bitfield = ET.Element("bitfield")
375 rnn_reglike.append(bitfield)
376 bitfield.attrib["low"] = str(low)
377 bitfield.attrib["high"] = str(high)
378 bitfield.attrib["name"] = rnn_field_name
379 num_bitfields += 1
380 process_values(field, bitfield)
382 if full_field_name is not None and num_bitfields == 0:
383 rnn_reglike_name += "_" + full_field_name
384 rnn_reglike.attrib["name"] = rnn_reglike_name
385 process_values(reglike, rnn_reglike)
387 stripeobj.members.setdefault(offset, {}).setdefault(ET.tostring(rnn_reglike), []).extend(objclasses)
389 # TODO: maybe the Python stdlib provides this function?
390 def extract_ranges(univ, cur):
391 cur = frozenset(cur)
392 i = 0
393 first = None
394 ranges = []
395 for item in univ:
396 if item in cur:
397 if first is None:
398 first = i
399 else:
400 if first is not None:
401 ranges.append((first, i - 1))
402 first = None
403 i += 1
404 if first is not None:
405 ranges.append((first, i - 1))
406 return ranges
408 for stripeobj in stripeobjs:
409 if not stripeobj.members:
410 continue
412 stripe = ET.Element("stripe")
414 database = ET.Element("database")
415 database.attrib["xmlns"] = "http://nouveau.freedesktop.org/"
416 database.attrib["xmlns" + colon + "xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
417 database.attrib["xsi" + colon + "schemaLocation"] = "http://nouveau.freedesktop.org/ rules-ng.xsd"
419 members = stripeobj.members.items()
420 members.sort()
422 objclasses = set()
423 for offset, versions in members:
424 for version_objclasses in versions.values():
425 objclasses.update(version_objclasses)
426 objclasses = list(objclasses)
427 objclasses.sort()
429 objclass_numbers = set([num for num, name in objclasses])
430 # assert no objclass has conflicting names
431 # could actually handle this, but it's not necessary
432 assert len(objclasses) == len(objclass_numbers)
434 for offset, versions in members:
435 versions_sorted = [(version_objclasses, xml) for xml, version_objclasses in versions.items()]
436 versions_sorted.sort()
437 for version_objclasses, xml in versions_sorted:
438 elem = ET.fromstring(xml)
440 if version_objclasses and set(objclasses) != set(version_objclasses):
441 ranges = extract_ranges(objclasses, version_objclasses)
442 elem.attrib["variants"] = " ".join([(objclasses[a][0] if a == b else objclasses[a][0] + "-" + objclasses[b][0]) for a, b in ranges])
443 stripe.append(elem)
445 if stripeobj.objsuper:
446 objenum = ET.Element("enum")
447 objenum.attrib["bare"] = "yes"
448 objenum.attrib["name"] = "obj-class"
450 for objname, objclass in objclasses:
451 objvalue = ET.Element("value")
452 if objclass is not None:
453 objvalue.attrib["value"] = hex(objclass)
454 objvalue.attrib["name"] = objname
455 objenum.append(objvalue)
457 database.append(objenum)
459 subchan = ET.Element("domain")
460 subchan.attrib["name"] = "NV01_SUBCHAN"
461 subchan.attrib["bare"] = "yes"
462 subchan.attrib["size"] = "0x2000"
464 stripe.attrib["prefix"] = "obj-class"
465 #stripe.attrib["varset"] = "obj-class"
466 if len(objclasses) == 1:
467 stripe.attrib["variants"] = objclasses[0][0]
468 else:
469 stripe.attrib["variants"] = objclasses[0][0] + "-" + objclasses[-1][0]
471 subchan.append(stripe)
472 database.append(subchan)
473 else:
474 name = None
475 if stripeobj.names:
476 assert len(stripeobj.names) == 1
477 name = list(stripeobj.names)[0]
479 mmio = ET.Element("domain")
480 if stripeobj.offset != 0 or name == "NV_PMC":
481 mmio.attrib["name"] = "NV_MMIO"
482 mmio.attrib["bare"] = "yes"
483 is_mmio = True
484 elif name:
485 mmio.attrib["name"] = name
486 is_mmio = False
487 mmio.attrib["prefix"] = "chipset"
489 if is_mmio and name:
490 stripe.attrib["name"] = name
491 stripe.attrib["offset"] = hex(stripeobj.offset)
492 stripe.attrib["stride"] = hex(stripeobj.end - stripeobj.offset)
493 mmio.append(stripe)
494 database.append(mmio)
496 if stripeobj.objsuper:
497 basename = stripeobj.objsuper.lower()
498 else:
499 basename = name
500 if stripeobj.strange_name:
501 basename = stripeobj.strange_name
503 if basename.startswith("NV_"):
504 basename = basename[3:]
505 basename = basename.lower()
507 if stripeobj.objsuper:
508 subdir = "objects"
509 elif stripeobj.strange_name:
510 subdir = "strange"
511 elif is_mmio:
512 subdir = "mmio"
513 else:
514 subdir = "misc"
515 filename = outdir + "/" + subdir + "/" + basename
517 outfile = open(filename, "w")
518 xml2text = subprocess.Popen("./xml2text", stdin = subprocess.PIPE, stdout = outfile)
519 xml2text.communicate(ET.tostring(database).replace(colon, ":"))
520 xml2text.wait()
521 outfile.close()