#!/usr/bin/python # -*- coding: utf-8 -*- import itertools import re from xml.etree import ElementTree class RadeonReg(object): def __init__(self, unit, name, count, access, addr, stride, desc): self.unit = unit self.name = name self.desc = desc self.count = count self.access = access self.addr = addr self.fields = [] self.stride = stride def __eq__(self, other): if (not isinstance(other, RadeonReg)): return False if self.unit != other.unit or \ self.name != other.name or \ self.desc != other.desc or \ self.count != other.count or \ self.access != other.access or \ self.addr != other.addr or \ self.stride != other.stride or \ len(self.fields) != len(other.fields): return False for i in xrange(len(self.fields)): if self.fields[i] != other.fields[i]: return False return True def __ne__(self, other): return not self == other class RadeonField(object): def __init__(self, name, low, high, desc): self.name = name self.desc = desc self.low = low if low <= high else high self.high = high if high >= low else low self.enum = None def __eq__(self, other): if (not isinstance(other, RadeonField)): return False if self.name == other.name and \ self.desc == other.desc and \ self.low == other.low and \ self.high == other.high and \ self.enum == other.enum: return True return False def __ne__(self, other): return not self == other class RadeonEnum(object): def __init__(self): self.entries = set() self.refs = 0 def __eq__(self, other): return self.entries == other.entries def __ne__(self, other): return not self == other enums = [] def AddEnum(e): for i in xrange(len(enums)): if e == enums[i]: enums[i].refs += 1 return i enums.append(e) enums[-1].refs += 1 return len(enums)-1 enum_regex = re.compile('(\d\d?)( - |: |=)((?:(?!\d\d?(?: - |: |=)).)*)', re.DOTALL) enum_desc = re.compile('(\d\d?( - |: |=)|POSSIBLE VALUES:)') enum_ename = re.compile('([A-Za-z0-9_]*)') reserved_regex = re.compile('[Rr][Ee][Ss][Ee][Rr][Vv][Ee][Dd]') def ExtractEnum(s): dl = s.split('\n') d = '' for line in dl: if enum_desc.match(line): break d += ' ' + line d = StripSpaces(d) enum = RadeonEnum() m = enum_regex.findall(s) for entry in m: val = int(entry[0]) desc = StripSpaces(entry[2].replace('\n', ' ')) if reserved_regex.search(desc): continue name = StripUnders(enum_ename.match(desc.replace(' ', '_')).group(1).upper()) enum.entries.add((val, name, desc)) if not enum.entries: enum = None return (d, enum) subs = [re.compile('^.+ 2008 Advanced Micro Devices, Inc.$'), re.compile('^Proprietary *[0-9]*$'), re.compile('^. *Revision [0-9\.]* *[A-Za-z]* [0-9]{1,2}, [0-9]*$'), re.compile('^.$'), re.compile('^ *$'), re.compile('\n'), re.compile('^[0-9]+.[0-9]+ .* Registers.*$'), re.compile('^\(Access: [RW]\)')] stupid_linebreaks = re.compile('-\n0x') def ReadPDFDump(filename): pdffile = open(filename, 'r') pdflines = pdffile.readlines() pdffile.close() formatted = '' for line in pdflines: for regex in subs: line = regex.sub('', line) if line: formatted += line + '\n' formatted = stupid_linebreaks.sub('-0x', formatted); return formatted + '\n' spaces = re.compile(' +') spaces_end = re.compile('(^ | $)', re.MULTILINE) def StripSpaces(s): return spaces_end.sub('', spaces.sub(' ', s)) uscores = re.compile('_+') uscores_end = re.compile('(^_|_$)', re.MULTILINE) def StripUnders(s): return uscores_end.sub('', uscores.sub('_', s)) reg_regex = re.compile( '([A-Za-z0-9_]{1,4}):([A-Za-z0-9_]+)(\[([0-9]+)-([0-9]+)\]?|)([A-Za-z0-9_]*).*\[([RW\/]+)\].*[^,]? ?MMReg:0x([0-9A-Fa-f]{1,6})(-0x([0-9A-Fa-f]{1,6})|).*' '(\nDESCRIPTION: (.*(\n.*)*?))?' '\nField Name +.*? +Description.*\n' '([^ยท]*\n)+' ) field_regex = re.compile( '([A-Za-z0-9_]+) +([0-9]{1,2})(:([0-9]{1,2})|) +(0x[0-9A-Fa-f]+|[Nn]one) +(.*(\n +.*)*)' ) def FormatPDFDump(pdf): regs = [] m = reg_regex.findall(pdf) for reg in m: unit = reg[0] name = StripUnders(reg[1] + '_' + reg[5]) addr = [ int(reg[7], 16), int(reg[9], 16) if reg[9] != '' else int(reg[7], 16) ] access = reg[6].lower().replace('/', '') count = (int(reg[4]) - int(reg[3]) + 1) if reg[3] != '' and reg[4] != '' else 1 stride = ((addr[1] - addr[0]) / (count - 1)) if count > 1 else 4 desc = StripSpaces(reg[11].replace('\n', ' ')) regs.append(RadeonReg(unit, name, count, access, addr[0], stride, desc)) creg = regs[-1] f = field_regex.findall(reg[13]) for field in f: fname = field[0] fbits = [ int(field[1]), int(field[3]) if field[3] != '' else int(field[1]) ] fdesc = StripSpaces(field[5]) creg.fields.append(RadeonField(fname, fbits[1], fbits[0], "")) cfield = creg.fields[-1] e = ExtractEnum(fdesc) cfield.desc = e[0] if e[1]: cfield.enum = AddEnum(e[1]) if len(creg.fields) > 0: if creg.fields[0].low == 0 and creg.fields[0].high == 31: creg.fields = [] return regs def RegInArray(r1, regs): for r2 in regs: if r1 == r2: return True return False def CompareRegs(regs1, regs2): regs_both = [] for (r1r, r2r) in itertools.product(regs1, regs2): if r1r == r2r: regs_both.append(r1r) for bf in regs_both[-1].fields: if bf.enum != None: enums[bf.enum].refs -= 1 regs_a = [reg for reg in regs1 if not RegInArray(reg, regs_both)] regs_b = [reg for reg in regs2 if not RegInArray(reg, regs_both)] return [regs_both, regs_a, regs_b] def CreateEnumChildren(root, enum): for (value, name, description) in sorted(enum.entries): if not name: continue value_tag = ElementTree.SubElement(root, "value") value_tag.attrib["name"] = name value_tag.attrib["value"] = str(value) ElementTree.SubElement(value_tag, "doc").text = description def CreateEnumElement(root, enum, index): if not enum.entries: return enum_tag = ElementTree.Element("enum") enum_tag.attrib["name"] = "ENUM%d" % index CreateEnumChildren(enum_tag, enum) if enum_tag: root.append(enum_tag) def CreateXML(handle, regs, variants): comment = ElementTree.Comment( """ This file was automatically generated from radeonreg.py. I strongly suggest running "tidy -i -m -xml 'name_of_file.xml'" on this file before attempting to read it. ~ C. """) preamble = ElementTree.PI("xml", "version=\"1.0\" encoding=\"UTF-8\"") database_attrs = { "xmlns": "http://nouveau.freedesktop.org/", "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation": "rules-ng.xsd", } database = ElementTree.Element("database", database_attrs) domain = ElementTree.SubElement(database, "domain", name="R300") for i, enum in enumerate(enums): if enum.refs > 1: CreateEnumElement(database, enum, i) for (group, name, prepend) in regs: group_tag = ElementTree.SubElement(database, "group", name=name) # "prepend" isn't (yet) recognized by the schema #group_tag.attrib["prepend"] = "%s_" % prepend for reg in group: if reg.count > 1: stripe = ElementTree.SubElement(group_tag, "stripe") stripe.attrib["offset"] = "0x%04X" % reg.addr stripe.attrib["stride"] = "0x%04X" % reg.stride stripe.attrib["length"] = str(reg.count) reg32 = ElementTree.SubElement(stripe, "reg32", name=reg.name, access=reg.access, offset="0x0") else: reg32 = ElementTree.SubElement(group_tag, "reg32", name=reg.name, access=reg.access) reg32.attrib["offset"] = "0x%04X" % reg.addr if reg.desc: ElementTree.SubElement(reg32, "doc").text = reg.desc for field in reg.fields: bitfield = ElementTree.SubElement(reg32, "bitfield", name=field.name, high=str(field.high), low=str(field.low)) ElementTree.SubElement(reg32, "doc").text = field.desc if field.enum: if enums[field.enum].refs == 1: CreateEnumChildren(bitfield, enums[field.enum]) else: use_enum = ElementTree.SubElement(bitfield, "use-enum") use_enum.attrib["ref"] = "ENUM%d" % field.enum for (name, groups) in variants: variant = ElementTree.SubElement(database, "variant", id=name) for group in groups: ElementTree.SubElement(variant, "use-group", ref=group) ElementTree.ElementTree(preamble).write(handle) ElementTree.ElementTree(comment).write(handle) ElementTree.ElementTree(database).write(handle) r300regs = FormatPDFDump(ReadPDFDump('R3xx_3D_Registers.txt')) r500regs = FormatPDFDump(ReadPDFDump('R5xx_Acceleration_v1.3.txt')) finalregs = CompareRegs(r300regs, r500regs) regs_both = finalregs[0] regs_r300 = finalregs[1] regs_r500 = finalregs[2] xmlfile = open("r300reg.xml", "w") CreateXML(xmlfile, [ [regs_both, 'rX00_regs', 'R300'], [regs_r300, 'r300_regs', 'R300'], [regs_r500, 'r500_regs', 'R500'] ], [ ['r300', ['rX00_regs', 'r300_regs']], ['r500', ['rX00_regs', 'r500_regs']] ] ) xmlfile.close()