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.
Этот коммит содержится в:
Ayke van Laethem 2018-09-30 12:48:03 +02:00
родитель ee5d562050
коммит e77a5af5d2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED

Просмотреть файл

@ -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