From 35cd0e07ca994b056a93f8439febc417fead7bc6 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 12 Oct 2025 01:01:51 -0500 Subject: [PATCH] regs: add us_disassemble --- regs/parse_bits.py | 21 +++- .../{us_cmn_inst_bits.txt => us_cmn_inst.txt} | 0 regs/us_disassemble.py | 116 ++++++++++++++++++ 3 files changed, 133 insertions(+), 4 deletions(-) rename regs/{us_cmn_inst_bits.txt => us_cmn_inst.txt} (100%) create mode 100644 regs/us_disassemble.py diff --git a/regs/parse_bits.py b/regs/parse_bits.py index 9743ffb..720b1c3 100644 --- a/regs/parse_bits.py +++ b/regs/parse_bits.py @@ -3,6 +3,7 @@ from typing import Union import re from dataclasses import dataclass from pprint import pprint +from collections import OrderedDict def split_line_fields(line): fields = [0, 17, 24, 32] @@ -87,11 +88,22 @@ def aggregate(fields): yield description ix += 1 + def parse_possible_value_num(s): + num, description = s.split(' - ') + num = int(num, 10) + if ": " in description: + name, description = description.split(": ") + else: + name = None + return num, (name, description) + while ix < len(fields): field_name, bits, default, description = fields[ix] description_lines = [description] description_lines.extend(parse_description_lines()) - possible_values = list(parse_possible_values()) + possible_values = OrderedDict( + map(parse_possible_value_num, parse_possible_values()) + ) assert default.startswith('0x'), default yield Descriptor( @@ -105,6 +117,7 @@ def aggregate(fields): ix += 1 next_nonempty() -l = list(parse_file_fields(sys.argv[1])) -for descriptor in aggregate(l): - pprint(descriptor, width=200) +if __name__ == "__main__": + l = list(parse_file_fields(sys.argv[1])) + for descriptor in aggregate(l): + pprint(descriptor, width=200) diff --git a/regs/us_cmn_inst_bits.txt b/regs/us_cmn_inst.txt similarity index 100% rename from regs/us_cmn_inst_bits.txt rename to regs/us_cmn_inst.txt diff --git a/regs/us_disassemble.py b/regs/us_disassemble.py new file mode 100644 index 0000000..f8c4a0b --- /dev/null +++ b/regs/us_disassemble.py @@ -0,0 +1,116 @@ +import parse_bits +from pprint import pprint +from collections import OrderedDict + +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(): + for register in register_names: + filename = 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"] + +code = [ + 0x00078005, + 0x08020080, + 0x08020080, + 0x1c9b04d8, + 0x1c810003, + 0x00000005, +] + +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}") + max_length = max(map(len, US_CMN_INST.keys())) + 1 + + def inner(register_name_list): + for i, register_name in enumerate(register_name_list): + value = code[ix + i] + register = registers[register_name] + print(" ", f"{value:08x}", register_name) + for d in register.values(): + field_pv_name = get_field_pv_name(value, d) + print(" ", d.field_name.ljust(max_length), field_pv_name) + + 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 + +disassemble(code, 0)