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; {padding // 4}],') else: code.append(f'unused{reserved_id}: [RO; {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}," 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('------------')