import csv import sys from functools import partial from pprint import pprint from generate import renderer def as_dict(header, row0): row = [s.strip() for s in row0] return dict(zip(header, row)) def read_input(filename): with open(filename) as f: reader = csv.reader(f, delimiter=",", quotechar='"') header, *rows = reader rows = [ as_dict(header, row) for row in rows if "".join(map(str, row)).strip() ] return rows def size_p(size): return size in {1, 2, 4} def size_to_type(size): if size == 1: return "reg8 " elif size == 2: return "reg16" elif size == 4: return "reg32" else: raise NotImplemented(size) def new_writer(): first_address = 0 next_address = 0 last_block = None size_total = 0 reserved_num = 0 stack = [] def terminate(): nonlocal last_block nonlocal stack if last_block is not None: yield "};" for address, name in stack: yield f"static_assert((offsetof (struct {last_block.lower()}_reg, {name})) == {hex(address - first_address)});" yield "" stack = [] def process_row(row): nonlocal first_address nonlocal next_address nonlocal last_block nonlocal reserved_num nonlocal size_total nonlocal stack block = row["block"] _offset = int(row["offset"], 16) if "offset" in row else 0 _address = int(row["address"], 16) assert _offset <= 0xff assert _address <= 0xffff offset_address = (_offset << 16) address = offset_address | (_address << 0) size = int(row["size"], 10) name = row["name"] description = row["description"] if block != last_block: yield from terminate() first_address = offset_address next_address = offset_address size_total = 0 reserved_num = 0 yield f"struct {block.lower()}_reg {{" assert address >= next_address, row if address > next_address: padding = address - next_address type = size_to_type(1) yield f"{type} _pad{reserved_num}[{padding}];" reserved_num += 1 size_total += padding def field(): if size_p(size): assert address % size == 0 type = size_to_type(size) return f"{type} {name};" else: type = size_to_type(4) return f"{type} {name}[{size // 4}];" yield field().ljust(27) + f"/* {description} */" stack.append((address, name)) next_address = address + size last_block = block size_total += size def process(rows): for row in rows: yield from process_row(row) yield from terminate() return process def blocks(rows): stack = [] last_block = None for row in rows: block = row["block"] if last_block != block: offset = int(row["offset"], 16) stack.append((block, offset)) last_block = block yield "struct sh7091_reg {" last_offset = 0 last_block = None reserved_num = 0 for block, offset in stack: if offset != last_offset: assert last_block is not None type = size_to_type(1) raw_pad = (offset - last_offset) << 16 yield f"{type} _pad{reserved_num}[{hex(raw_pad)} - (sizeof (struct {last_block.lower()}_reg))];" reserved_num += 1 yield f"struct {block.lower()}_reg {block};" last_offset = offset last_block = block yield "};" for block, offset in stack: yield f"static_assert((offsetof (struct sh7091_reg, {block})) == {hex(offset << 16)});" yield "" yield 'extern struct sh7091_reg sh7091 __asm("sh7091");' def headers(): yield "#include " yield "#include " yield "" yield '#include "type.hpp"' yield "" if __name__ == "__main__": input_file = sys.argv[1] rows = read_input(input_file) process = new_writer() render, out = renderer() render(headers()) render(process(rows)) render(blocks(rows)) sys.stdout.write(out.getvalue())