Skip to content

Instantly share code, notes, and snippets.

@dsvensson
Last active July 16, 2017 09:47
Show Gist options
  • Save dsvensson/f0f411a2de84c9a10fe07fcb976553aa to your computer and use it in GitHub Desktop.
Save dsvensson/f0f411a2de84c9a10fe07fcb976553aa to your computer and use it in GitHub Desktop.
generate register stuff from Atmel Studio XML files
import xml.etree.ElementTree as ET
import argparse
import math
def bits(n):
while n:
b = n & (~n+1)
yield int(round(math.log(b, 2)))
n ^= b
def gen_bitfields(name, mask):
fields = [None] * 8
for bit in bits(mask):
fields[7 - bit] = '{}{}'.format(name, bit)
return tuple(fields)
def get_bitfields(node):
fields = [None] * 8
reg_name = node.attrib['name']
bitfields = node.findall('bitfield')
for bitfield in bitfields:
bit_name = bitfield.attrib['name']
mask = int(bitfield.attrib['mask'], 16)
if len(bitfields) == 1 and mask == 0xff and bit_name != reg_name and reg_name.startswith(bit_name):
name = reg_name
else:
name = bit_name
for i, bit in enumerate(bits(mask)):
if bin(mask).count('1') > 1:
fields[7 - bit] = '{}{}'.format(name, i)
else:
fields[7 - bit] = name
return tuple(fields)
def get_registers(node):
for group in node.findall('.//register-group'):
for register in group.findall('register'):
name = register.attrib['name']
offset = int(register.attrib['offset'], 16)
if 'mask' in register.attrib:
# If mask defined, there are no named bitfields
mask = int(register.attrib['mask'], 16)
if mask > 0xff:
# Split between high and low registers
yield (offset + 1, name + 'H', gen_bitfields(name + 'H', mask & 0xff00))
yield (offset, name + 'L', gen_bitfields(name + 'L', mask & 0xff))
else:
yield (offset, name, gen_bitfields(name, mask))
else:
yield (offset, name, get_bitfields(register))
def gen_aliases(node):
for group in node.findall('.//register-group'):
for register in group.findall('register'):
if 'mask' in register.attrib:
if int(register.attrib['mask'], 16) > 0xff:
yield register.attrib['name']
if __name__ == '__main__':
# Datasheets can be found at https://github.com/avrxml/AS6-Devices-XML
parser = argparse.ArgumentParser()
parser.add_argument('datasheet', help='Atmel XML Register Datasheet.')
args = parser.parse_args()
root = ET.parse(args.datasheet).getroot()
lookup = {}
for offset, next_name, next_bitfields in get_registers(root):
prev = lookup.get(offset)
if prev is None:
lookup[offset] = (offset, next_name, next_bitfields)
else:
_, prev_name, prev_bitfields = prev
bitfields = [a or b for a,b in zip(prev_bitfields, next_bitfields)]
next_is_set = sum(x is not None for x in next_bitfields)
prev_is_set = sum(x is not None for x in prev_bitfields)
lookup[offset] = (offset, prev_name if prev_is_set > next_is_set else next_name, bitfields)
registers = []
for offset, name, bitfields in lookup.values():
fields = ''.join('{:11}'.format((f or '-') + ',') for f in bitfields).rstrip(', ')
registers.append('register!(0x{:02X}, {:9} [{:87}]);'.format(offset, name + ',', fields))
wide_registers = []
for register in gen_aliases(root):
wide_registers.append('pub const {:7} *mut u16 = {:7} as *mut u16;'.format(register+':', register+'L'))
print('\n'.join(sorted(registers, reverse=True)))
print('\n')
print('\n'.join(sorted(wide_registers)))
@dsvensson
Copy link
Author

Filter out duplicates, and prefix register bits with register in cases where the XML really should have said that... still a few cases where the bits have duplicate names, specifically the WGM* bits in for example TCCR{1..}{A..} registers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment