6 from lxml
import etree
as ET
8 colon
= "39584ac56e6d0976692778b80915f94b61767814a8704982"
18 # the rules.xml names suck
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",
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",
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",
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();
129 for subdir
in ("mmio", "objects", "misc", "strange"):
131 os
.mkdir(outdir
+ "/" + subdir
)
137 address_stripeobjs
= {}
138 objsuper_stripeobjs
= {}
141 class Stripe(object):
143 self
.strange_name
= None
148 class Device(object):
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
)
157 for device
in root
.iterchildren(tag
=ET
.Element
):
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
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()]
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
)
192 stripeobj
= address_stripeobjs
.get(devobj
.offset
)
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
205 stripeobj
.objsuper
= objsuper
206 objsuper_stripeobjs
[objsuper
] = stripeobj
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
):
217 while a
[i
:i
+1] == b
[i
:i
+1]:
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
):
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":
251 if rnn_value_name
in ("TRUE", "ON", "ENABLE", "ENABLED", "YES", "1"):
252 true_value
= rnn_value
253 if rnn_value_name
!= "0":
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])
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():
272 elif common_prefix
is None:
273 common_prefix
= rnn_value_name
275 common_prefix
= common_prefix
[:common_prefix_len(common_prefix
, rnn_value_name
)]
278 us
= common_prefix
.rfind("_")
280 common_prefix
= common_prefix
[:us
+ 1]
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
]
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
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
)
314 stripeobj
.strange_name
= strange_stripeobj_name
316 stripeobj
.end
= 0xffffffff
317 strange_stripeobjs
[strange_stripeobj_name
] = stripeobj
318 stripeobjs
.append(stripeobj
)
322 assert address
>= cand_devobj
.offset
323 assert address
< cand_devobj
.end
324 offset
= address
- cand_devobj
.offset
326 if offset
== 0 and objclasses
:
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:]
335 if rnn_reglike_name
in uninteresting_reglike_names
:
338 rnn_reglike
= ET
.Element("reg32")
340 rnn_reglike
.attrib
["offset"] = hex(offset
)
342 if reglike
.tag
== "array":
344 for field
in reglike
.iterchildren(tag
=ET
.Element
):
345 if field
.tag
== "array-size":
346 size
= int(field
.attrib
["size"], 0)
349 rnn_reglike
.attrib
["length"] = str(max_size
)
350 rnn_reglike
.attrib
["stride"] = str(int(reglike
.attrib
["width"], 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
):
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
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
):
400 if first
is not None:
401 ranges
.append((first
, i
- 1))
404 if first
is not None:
405 ranges
.append((first
, i
- 1))
408 for stripeobj
in stripeobjs
:
409 if not stripeobj
.members
:
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()
423 for offset
, versions
in members
:
424 for version_objclasses
in versions
.values():
425 objclasses
.update(version_objclasses
)
426 objclasses
= list(objclasses
)
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
])
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]
469 stripe
.attrib
["variants"] = objclasses
[0][0] + "-" + objclasses
[-1][0]
471 subchan
.append(stripe
)
472 database
.append(subchan
)
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"
485 mmio
.attrib
["name"] = name
487 mmio
.attrib
["prefix"] = "chipset"
490 stripe
.attrib
["name"] = name
491 stripe
.attrib
["offset"] = hex(stripeobj
.offset
)
492 stripe
.attrib
["stride"] = hex(stripeobj
.end
- stripeobj
.offset
)
494 database
.append(mmio
)
496 if stripeobj
.objsuper
:
497 basename
= stripeobj
.objsuper
.lower()
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
:
509 elif stripeobj
.strange_name
:
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
, ":"))