import sys import parse_bits from collections import OrderedDict from os import path register_names = [ "US_CMN_INST", "US_ALU_RGB_ADDR", "US_ALU_ALPHA_ADDR", "US_ALU_RGB_INST", "US_ALU_ALPHA_INST", "US_ALU_RGBA_INST", "US_TEX_INST", "US_TEX_ADDR", "US_TEX_ADDR_DXDY", "US_FC_INST", "US_FC_ADDR", ] alu_output = [ "US_CMN_INST", "US_ALU_RGB_ADDR", "US_ALU_ALPHA_ADDR", "US_ALU_RGB_INST", "US_ALU_ALPHA_INST", "US_ALU_RGBA_INST", ] tex = [ "US_CMN_INST", "US_TEX_INST", "US_TEX_ADDR", "US_TEX_ADDR_DXDY", 0, 0, ] fc = [ "US_CMN_INST", 0, "US_FC_INST", "US_FC_ADDR", 0, 0, ] def parse_registers(): base = path.dirname(__file__) for register in register_names: filename = path.join(base, "bits", register.lower() + ".txt") l = list(parse_bits.parse_file_fields(filename)) yield register, OrderedDict( (d.field_name, d) for d in parse_bits.aggregate(l) ) registers = dict(parse_registers()) US_CMN_INST = registers["US_CMN_INST"] def get_field(n, descriptor): if type(descriptor.bits) is int: return (n >> descriptor.bits) & 1 else: high, low = descriptor.bits assert high > low mask_length = (high - low) + 1 mask = (1 << mask_length) - 1 return (n >> low) & mask def get_possible_value(value, descriptor): if not descriptor.possible_values: return value name, description = descriptor.possible_values[value] if name is not None: return name else: if len(description) < 20: return description else: return value def get_field_pv_name(value, descriptor): return get_possible_value(get_field(value, descriptor), descriptor) def disassemble(code, ix): us_cmn_inst = code[ix + 0] print(f"{ix:04x}") def inner2(i, register_name): max_length = max(map(len, registers[register_name])) + 1 value = code[ix + i] yield f"{register_name}" yield f" [{value:08x}]" if register_name == 0: assert value == 0 return register = registers[register_name] for d in register.values(): field_pv_name = get_field_pv_name(value, d) yield ' '.join([d.field_name.ljust(max_length), f"{field_pv_name}"]) def inner(register_name_list): columns = [] for i, register_name in enumerate(register_name_list): columns.append(list(inner2(i, register_name))) column_widths = [35, 26, 24, 24, 27, 22] column_height = max(len(column) for column in columns) assert len(columns) == 6 def get_row(column, rix, cix): if rix < len(column): value = column[rix] else: value = '' return value.ljust(column_widths[cix]) + '| ' for rix in range(column_height): row = ''.join([ get_row(column, rix, cix) for cix, column in enumerate(columns) ]) print(" ", row) inst_type = get_field_pv_name(us_cmn_inst, US_CMN_INST["TYPE"]) if inst_type in {"US_INST_TYPE_OUT", "US_INST_TYPE_ALU"}: inner(alu_output) elif inst_type == "US_INST_TYPE_FC": inner(fc) elif inst_type == "US_INST_TYPE_TEX": inner(tex) else: assert False, inst_type def parse_hex(s): assert s.startswith('0x') return int(s.removeprefix('0x'), 16) if __name__ == "__main__": filename = sys.argv[1] with open(filename) as f: buf = f.read() code = [parse_hex(c.strip()) for c in buf.split(',') if c.strip()] for i in range(len(code) // 6): disassemble(code, i * 6)