160 lines
4.4 KiB
Python
160 lines
4.4 KiB
Python
import re
|
|
import sys
|
|
|
|
def parse_table_entries(fields):
|
|
"""Parse aligned table entries"""
|
|
pattern = r'\s+'.join([f"(?P<{v[:v.find(':')]}>{v[v.find(':') + 1:].strip()})"
|
|
for v in fields])
|
|
pattern = re.compile(pattern)
|
|
fields = [v[:v.find(':')] for v in fields]
|
|
prev = None
|
|
entries = []
|
|
def flush():
|
|
nonlocal prev
|
|
if prev is not None:
|
|
entries.append(prev['data'])
|
|
prev = None
|
|
|
|
while True:
|
|
line = yield
|
|
if line == None:
|
|
break
|
|
if len(line.strip()) == 0:
|
|
flush()
|
|
continue
|
|
match = pattern.fullmatch(line.strip())
|
|
if match is not None:
|
|
flush()
|
|
starts = [match.span(v)[0] for v in fields]
|
|
prev = {
|
|
'data': {v: [match.group(v)] for v in fields},
|
|
'starts': starts
|
|
}
|
|
elif prev is not None:
|
|
for i, field in enumerate(fields):
|
|
if i + 1 == len(fields):
|
|
v = line[prev['starts'][i]:].strip()
|
|
else:
|
|
v = line[prev['starts'][i]:prev['starts'][i + 1]].strip()
|
|
if len(v) == 0:
|
|
continue
|
|
prev['data'][field].append(v)
|
|
flush()
|
|
return entries
|
|
|
|
# def parse_register_list(lines):
|
|
# """Parse register entry from `pdftotext -layout output` from TRM table"""
|
|
# fields = [
|
|
# r'id: \w+',
|
|
# r'address: 0x[0-9A-F]+',
|
|
# r'size: \d+',
|
|
# r'type: \w+',
|
|
# r'reset_value: 0x[0-9A-F]+',
|
|
# r'description: .+'
|
|
# ]
|
|
# return parse_table_entries(fields, lines)
|
|
|
|
def parse_register_fields():
|
|
fields = [
|
|
r'name: \w+',
|
|
r'bits: \d+(:\d+)?',
|
|
r'type: \w+',
|
|
r'reset: 0x[0-9A-F]+',
|
|
r'description: .+'
|
|
]
|
|
it = parse_table_entries(fields)
|
|
next(it)
|
|
return it
|
|
|
|
def end_iterator(it):
|
|
try:
|
|
it.send(None)
|
|
except StopIteration as e:
|
|
return e.value
|
|
|
|
def parse_registers():
|
|
def inner():
|
|
pattern = re.compile(r'Name\s+(\w+)')
|
|
state = 0
|
|
name = ''
|
|
it = None
|
|
results = {}
|
|
while True:
|
|
line = yield
|
|
if line == None:
|
|
break
|
|
line = line.strip()
|
|
m = pattern.fullmatch(line)
|
|
if m is not None:
|
|
if it is not None:
|
|
results[name] = end_iterator(it)
|
|
name = m.group(1)
|
|
it = parse_register_fields()
|
|
else:
|
|
if it is not None:
|
|
it.send(line)
|
|
if it is not None:
|
|
results[name] = end_iterator(it)
|
|
return results
|
|
it = inner()
|
|
next(it)
|
|
return it
|
|
|
|
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_register_list(sys.stdin)):
|
|
# print(line)
|
|
|
|
parser = parse_registers()
|
|
for line in sys.stdin:
|
|
parser.send(line)
|
|
for k, v in end_iterator(parser).items():
|
|
print(k)
|
|
for entry in v:
|
|
print(entry)
|
|
print('------------')
|