tools/gen-device-svd: rewrite with ElementTree
xml.etree.ElementTree is much easier to work with. This also fixes a few small bugs in the parser. And as an added bonus, device generation got a lot faster: apprently etree is a lot faster than minidom.
Этот коммит содержится в:
родитель
ee5d562050
коммит
e77a5af5d2
1 изменённых файлов: 49 добавлений и 55 удалений
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from xml.dom import minidom
|
from xml.etree import ElementTree
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import re
|
import re
|
||||||
|
@ -13,11 +13,7 @@ class Device:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def getText(element):
|
def getText(element):
|
||||||
strings = []
|
return ''.join(element.itertext())
|
||||||
for node in element.childNodes:
|
|
||||||
if node.nodeType == node.TEXT_NODE:
|
|
||||||
strings.append(node.data)
|
|
||||||
return ''.join(strings)
|
|
||||||
|
|
||||||
def formatText(text):
|
def formatText(text):
|
||||||
text = re.sub('[ \t\n]+', ' ', text) # Collapse whitespace (like in HTML)
|
text = re.sub('[ \t\n]+', ' ', text) # Collapse whitespace (like in HTML)
|
||||||
|
@ -28,11 +24,11 @@ def formatText(text):
|
||||||
def readSVD(path, sourceURL):
|
def readSVD(path, sourceURL):
|
||||||
# Read ARM SVD files.
|
# Read ARM SVD files.
|
||||||
device = Device()
|
device = Device()
|
||||||
xml = minidom.parse(path)
|
xml = ElementTree.parse(path)
|
||||||
root = xml.getElementsByTagName('device')[0]
|
root = xml.getroot()
|
||||||
deviceName = getText(root.getElementsByTagName('name')[0])
|
deviceName = getText(root.find('name'))
|
||||||
deviceDescription = getText(root.getElementsByTagName('description')[0]).strip()
|
deviceDescription = getText(root.find('description')).strip()
|
||||||
licenseTexts = root.getElementsByTagName('licenseText')
|
licenseTexts = root.findall('licenseText')
|
||||||
if len(licenseTexts) == 0:
|
if len(licenseTexts) == 0:
|
||||||
licenseText = None
|
licenseText = None
|
||||||
elif len(licenseTexts) == 1:
|
elif len(licenseTexts) == 1:
|
||||||
|
@ -46,21 +42,21 @@ def readSVD(path, sourceURL):
|
||||||
|
|
||||||
interrupts = OrderedDict()
|
interrupts = OrderedDict()
|
||||||
|
|
||||||
for periphEl in root.getElementsByTagName('peripherals')[0].getElementsByTagName('peripheral'):
|
for periphEl in root.findall('./peripherals/peripheral'):
|
||||||
name = getText(periphEl.getElementsByTagName('name')[0])
|
name = getText(periphEl.find('name'))
|
||||||
descriptionTags = periphEl.getElementsByTagName('description')
|
descriptionTags = periphEl.findall('description')
|
||||||
description = ''
|
description = ''
|
||||||
if descriptionTags:
|
if descriptionTags:
|
||||||
description = formatText(getText(descriptionTags[0]))
|
description = formatText(getText(descriptionTags[0]))
|
||||||
baseAddress = int(getText(periphEl.getElementsByTagName('baseAddress')[0]), 0)
|
baseAddress = int(getText(periphEl.find('baseAddress')), 0)
|
||||||
groupNameTags = periphEl.getElementsByTagName('groupName')
|
groupNameTags = periphEl.findall('groupName')
|
||||||
groupName = None
|
groupName = None
|
||||||
if groupNameTags:
|
if groupNameTags:
|
||||||
groupName = getText(groupNameTags[0])
|
groupName = getText(groupNameTags[0])
|
||||||
|
|
||||||
if periphEl.hasAttribute('derivedFrom') or groupName in groups:
|
if periphEl.get('derivedFrom') or groupName in groups:
|
||||||
if periphEl.hasAttribute('derivedFrom'):
|
if periphEl.get('derivedFrom'):
|
||||||
derivedFromName = periphEl.getAttribute('derivedFrom')
|
derivedFromName = periphEl.get('derivedFrom')
|
||||||
derivedFrom = peripheralDict[derivedFromName]
|
derivedFrom = peripheralDict[derivedFromName]
|
||||||
else:
|
else:
|
||||||
derivedFrom = groups[groupName]
|
derivedFrom = groups[groupName]
|
||||||
|
@ -87,9 +83,9 @@ def readSVD(path, sourceURL):
|
||||||
if groupName and groupName not in groups:
|
if groupName and groupName not in groups:
|
||||||
groups[groupName] = peripheral
|
groups[groupName] = peripheral
|
||||||
|
|
||||||
for interrupt in periphEl.getElementsByTagName('interrupt'):
|
for interrupt in periphEl.findall('interrupt'):
|
||||||
intrName = getText(interrupt.getElementsByTagName('name')[0])
|
intrName = getText(interrupt.find('name'))
|
||||||
intrIndex = int(getText(interrupt.getElementsByTagName('value')[0]))
|
intrIndex = int(getText(interrupt.find('value')))
|
||||||
if intrName in interrupts:
|
if intrName in interrupts:
|
||||||
if interrupts[intrName]['index'] != intrIndex:
|
if interrupts[intrName]['index'] != intrIndex:
|
||||||
raise ValueError('interrupt with the same name has different indexes: ' + intrName)
|
raise ValueError('interrupt with the same name has different indexes: ' + intrName)
|
||||||
|
@ -101,19 +97,19 @@ def readSVD(path, sourceURL):
|
||||||
'description': description,
|
'description': description,
|
||||||
}
|
}
|
||||||
|
|
||||||
regsEls = periphEl.getElementsByTagName('registers')
|
regsEls = periphEl.findall('registers')
|
||||||
if regsEls:
|
if regsEls:
|
||||||
for el in regsEls[0].childNodes:
|
if len(regsEls) != 1:
|
||||||
if el.nodeName == 'register':
|
raise ValueError('expected just one <registers> in a <peripheral>')
|
||||||
peripheral['registers'].append(parseSVDRegister(groupName or name, el, baseAddress))
|
for register in regsEls[0].findall('register'):
|
||||||
elif el.nodeName == 'cluster':
|
peripheral['registers'].append(parseRegister(groupName or name, register, baseAddress))
|
||||||
if el.getElementsByTagName('dim'):
|
for cluster in regsEls[0].findall('cluster'):
|
||||||
|
if cluster.find('dim') is not None:
|
||||||
continue # TODO
|
continue # TODO
|
||||||
clusterPrefix = getText(el.getElementsByTagName('name')[0]) + '_'
|
clusterPrefix = getText(cluster.find('name')) + '_'
|
||||||
clusterOffset = int(getText(el.getElementsByTagName('addressOffset')[0]), 0)
|
clusterOffset = int(getText(cluster.find('addressOffset')), 0)
|
||||||
for regEl in el.childNodes:
|
for regEl in cluster.findall('register'):
|
||||||
if regEl.nodeName == 'register':
|
peripheral['registers'].append(parseRegister(groupName or name, regEl, baseAddress + clusterOffset, clusterPrefix))
|
||||||
peripheral['registers'].append(parseSVDRegister(groupName or name, regEl, baseAddress + clusterOffset, clusterPrefix))
|
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -133,38 +129,36 @@ def readSVD(path, sourceURL):
|
||||||
|
|
||||||
return device
|
return device
|
||||||
|
|
||||||
def parseSVDRegister(groupName, regEl, baseAddress, namePrefix=''):
|
def parseRegister(groupName, regEl, baseAddress, namePrefix=''):
|
||||||
regName = getText(regEl.getElementsByTagName('name')[0])
|
regName = getText(regEl.find('name'))
|
||||||
regDescription = getText(regEl.getElementsByTagName('description')[0])
|
regDescription = getText(regEl.find('description'))
|
||||||
offsetEls = regEl.getElementsByTagName('offset')
|
offsetEls = regEl.findall('offset')
|
||||||
if not offsetEls:
|
if not offsetEls:
|
||||||
offsetEls = regEl.getElementsByTagName('addressOffset')
|
offsetEls = regEl.findall('addressOffset')
|
||||||
address = baseAddress + int(getText(offsetEls[0]), 0)
|
address = baseAddress + int(getText(offsetEls[0]), 0)
|
||||||
|
|
||||||
dimEls = regEl.getElementsByTagName('dim')
|
dimEls = regEl.findall('dim')
|
||||||
array = None
|
array = None
|
||||||
if dimEls:
|
if dimEls:
|
||||||
array = int(getText(dimEls[0]), 0)
|
array = int(getText(dimEls[0]), 0)
|
||||||
regName = regName.replace('[%s]', '')
|
regName = regName.replace('[%s]', '')
|
||||||
|
|
||||||
fields = []
|
fields = []
|
||||||
fieldsEls = regEl.getElementsByTagName('fields')
|
fieldsEls = regEl.findall('fields')
|
||||||
if fieldsEls:
|
if fieldsEls:
|
||||||
for fieldEl in fieldsEls[0].childNodes:
|
for fieldEl in fieldsEls[0].findall('field'):
|
||||||
if fieldEl.nodeName != 'field':
|
fieldName = getText(fieldEl.find('name'))
|
||||||
continue
|
descrEls = fieldEl.findall('description')
|
||||||
fieldName = getText(fieldEl.getElementsByTagName('name')[0])
|
lsbTags = fieldEl.findall('lsb')
|
||||||
descrEls = fieldEl.getElementsByTagName('description')
|
|
||||||
lsbTags = fieldEl.getElementsByTagName('lsb')
|
|
||||||
if len(lsbTags) == 1:
|
if len(lsbTags) == 1:
|
||||||
lsb = int(getText(lsbTags[0]))
|
lsb = int(getText(lsbTags[0]))
|
||||||
else:
|
else:
|
||||||
lsb = int(getText(fieldEl.getElementsByTagName('bitOffset')[0]))
|
lsb = int(getText(fieldEl.find('bitOffset')))
|
||||||
msbTags = fieldEl.getElementsByTagName('msb')
|
msbTags = fieldEl.findall('msb')
|
||||||
if len(msbTags) == 1:
|
if len(msbTags) == 1:
|
||||||
msb = int(getText(msbTags[0]))
|
msb = int(getText(msbTags[0]))
|
||||||
else:
|
else:
|
||||||
msb = int(getText(fieldEl.getElementsByTagName('bitWidth')[0])) + lsb - 1
|
msb = int(getText(fieldEl.find('bitWidth'))) + lsb - 1
|
||||||
fields.append({
|
fields.append({
|
||||||
'name': '{}_{}{}_{}_Pos'.format(groupName, namePrefix, regName, fieldName),
|
'name': '{}_{}{}_{}_Pos'.format(groupName, namePrefix, regName, fieldName),
|
||||||
'description': 'Position of %s field.' % fieldName,
|
'description': 'Position of %s field.' % fieldName,
|
||||||
|
@ -181,10 +175,10 @@ def parseSVDRegister(groupName, regEl, baseAddress, namePrefix=''):
|
||||||
'description': 'Bit %s.' % fieldName,
|
'description': 'Bit %s.' % fieldName,
|
||||||
'value': 1 << lsb,
|
'value': 1 << lsb,
|
||||||
})
|
})
|
||||||
for enumEl in fieldEl.getElementsByTagName('enumeratedValue'):
|
for enumEl in fieldEl.findall('enumeratedValues/enumeratedValue'):
|
||||||
enumName = getText(enumEl.getElementsByTagName('name')[0])
|
enumName = getText(enumEl.find('name'))
|
||||||
enumDescription = getText(enumEl.getElementsByTagName('description')[0])
|
enumDescription = getText(enumEl.find('description'))
|
||||||
enumValue = int(getText(enumEl.getElementsByTagName('value')[0]), 0)
|
enumValue = int(getText(enumEl.find('value')), 0)
|
||||||
fields.append({
|
fields.append({
|
||||||
'name': '{}_{}{}_{}_{}'.format(groupName, namePrefix, regName, fieldName, enumName),
|
'name': '{}_{}{}_{}_{}'.format(groupName, namePrefix, regName, fieldName, enumName),
|
||||||
'description': enumDescription,
|
'description': enumDescription,
|
||||||
|
@ -265,7 +259,7 @@ const (
|
||||||
out.write('\t{name} {regType}\n'.format(**register, regType=regType))
|
out.write('\t{name} {regType}\n'.format(**register, regType=regType))
|
||||||
|
|
||||||
# next address
|
# next address
|
||||||
if register['array'] is not None and 1:
|
if register['array'] is not None:
|
||||||
address = register['address'] + 4 * register['array']
|
address = register['address'] + 4 * register['array']
|
||||||
else:
|
else:
|
||||||
address = register['address'] + 4
|
address = register['address'] + 4
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче