99 lines
3.1 KiB
Python
99 lines
3.1 KiB
Python
from typing import Optional, Dict
|
|
import re
|
|
import sys
|
|
|
|
def parse_table_entries(fields, pattern, lines):
|
|
"""Parse aligned table entries"""
|
|
prev: Optional[Dict] = None
|
|
entries = []
|
|
def flush():
|
|
nonlocal prev
|
|
if prev is not None:
|
|
entries.append(prev['data'])
|
|
prev = None
|
|
for line in lines:
|
|
if len(line.strip()) == 0:
|
|
flush()
|
|
continue
|
|
|
|
match = pattern.search(line.strip())
|
|
if match is not None:
|
|
flush()
|
|
starts = [match.span(v)[0] for v in fields] + [len(line)]
|
|
prev = {
|
|
'data': {v: match.group(v) for v in fields},
|
|
'starts': starts
|
|
}
|
|
elif prev is not None:
|
|
for i, field in enumerate(fields):
|
|
v = line[prev['starts'][i]:prev['starts'][i + 1]].strip()
|
|
if len(v) == 0:
|
|
continue
|
|
if prev['data'][field][-1] not in ['-', '_']:
|
|
v = ' ' + v
|
|
prev['data'][field] += v
|
|
|
|
flush()
|
|
return entries
|
|
|
|
|
|
def parse_registers(lines):
|
|
"""Parse register entry from `pdftotext -layout output` from TRM table"""
|
|
fields = ['id', 'address', 'size', 'type', 'reset_value', 'description']
|
|
|
|
ENTRY_PATTERN = re.compile(r'^'
|
|
r'(?P<id>\w+)\s+'
|
|
r'(?P<address>0x[0-9A-F]+)\s+'
|
|
r'(?P<size>\d+)\s+'
|
|
r'(?P<type>\w+)\s+'
|
|
r'(?P<reset_value>0x[0-9A-F]+)\s+'
|
|
r'(?P<description>.+)$')
|
|
return parse_table_entries(fields, ENTRY_PATTERN, lines)
|
|
|
|
def emit_rust(base_addr, ending_addr, registers):
|
|
current_addr = base_addr
|
|
reserved_id = 0
|
|
code = []
|
|
for reg in registers:
|
|
addr = int(reg['address'], 16)
|
|
if addr > ending_addr:
|
|
break
|
|
if addr < base_addr:
|
|
continue
|
|
padding = addr - current_addr
|
|
if padding > 0:
|
|
if padding % 4 == 0:
|
|
code.append(f'unused{reserved_id}: [RO<u32>; {padding // 4}],')
|
|
else:
|
|
code.append(f'unused{reserved_id}: [RO<u8>; {padding}],')
|
|
reserved_id += 1
|
|
access = ''
|
|
unknown = False
|
|
if reg['type'] == 'ro':
|
|
access = 'RO'
|
|
elif reg['type'] == 'wo':
|
|
access = 'WO'
|
|
elif reg['type'] in ['rw', 'mixed']:
|
|
access = 'RW'
|
|
else:
|
|
access = reg['type']
|
|
unknown = True
|
|
size = int(reg['size'])
|
|
if size not in [8, 16, 32]:
|
|
unknown = True
|
|
current_addr += padding + size // 8
|
|
line = f"pub {reg['id'].lower()}: {access}<u{size}>,"
|
|
if unknown:
|
|
line = '// FIXME: ' + line
|
|
code.append(f"/// {reg['description']}")
|
|
code.append(line)
|
|
return code
|
|
|
|
if len(sys.argv) != 3:
|
|
print("Pipe pdftotext to stdin, and give starting and ending address"
|
|
"(inclusive) for the registers")
|
|
exit()
|
|
|
|
for line in emit_rust(int(sys.argv[1], 0), int(sys.argv[2], 0), parse_registers(sys.stdin)):
|
|
print(line)
|