Last active
July 16, 2017 09:47
-
-
Save dsvensson/f0f411a2de84c9a10fe07fcb976553aa to your computer and use it in GitHub Desktop.
generate register stuff from Atmel Studio XML files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.