From 54957f8735051610ba97d40467dd008fa1870ca2 Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Mon, 11 Jul 2022 20:13:14 -0400 Subject: [PATCH] Yet another disasm.py speedup (#918) * starting point * add rabbitizer stuff, but commented out * kinda works now, except for symbols * trying to fix using symbols for disassembly * more fixes * fix branches and some format changes * make disasm.py runnable again :sweat_smile: * fix double words * hopefully fix jumptables * fix delay slot spacing on entry.s * Fix delay slot shenanigans * minor format update * re enable multithreading * add rabbitizer to requirements.txt and cleanup the file * cleanup * more cleanup * more cleanups * getImmOverride * black * hopefully final cleanup * diff.py requirements * Install python dependencies on jenkinsfile * --no-cache * Remove `--no-cache --upgrade` * branch_likely_delay_slot_save Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com> * review Co-authored-by: Derek Hensley * a * Don't use $FpcCsr Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com> Co-authored-by: Derek Hensley --- Jenkinsfile | 6 + requirements.txt | 13 +- tools/disasm/disasm.py | 646 ++++++++++++-------------------- tools/disasm/mips_isa.py | 776 --------------------------------------- 4 files changed, 251 insertions(+), 1190 deletions(-) delete mode 100644 tools/disasm/mips_isa.py diff --git a/Jenkinsfile b/Jenkinsfile index fb60f0acad..29c3721b27 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -20,6 +20,12 @@ pipeline { sh 'bash -c "tools/reloc_spec_check.sh"' } } + stage('Install Python dependencies') { + steps { + echo 'Installing Python dependencies' + sh 'python3 -m pip install -r requirements.txt' + } + } stage('Copy ROM') { steps { echo 'Setting up ROM...' diff --git a/requirements.txt b/requirements.txt index d76027c1c8..d410bc8531 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,12 @@ +# Setup libyaz0>=0.5 -pyelftools>=0.26 colorama>=0.4.3 -ansiwrap>=0.8.4 -attrs>=18.2.0 + +# disasm +rabbitizer>=1.0.0,<2.0.0 + +# diff watchdog>=0.10.2 -GitPython>=3.1.14 +argcomplete +python-Levenshtein +cxxfilt diff --git a/tools/disasm/disasm.py b/tools/disasm/disasm.py index cb634d1385..3133f4327c 100755 --- a/tools/disasm/disasm.py +++ b/tools/disasm/disasm.py @@ -1,15 +1,17 @@ #!/usr/bin/env python3 +from __future__ import annotations + import argparse, ast, math, os, re, struct import bisect import multiprocessing from pathlib import Path -import mips_isa +import rabbitizer # Consider implementing gpr naming too, but already uses abi names by default fpr_name_options = { - "numeric": mips_isa.numeric_fpr_names, - "o32": mips_isa.o32_fpr_names, + "numeric", + "o32", } parser = argparse.ArgumentParser() @@ -32,12 +34,15 @@ parser.add_argument( required=False, help="Optional list of files to diassemble separated by a space. This is a whitelist, all files will be skipped besides the ones listed here if used.", ) -parser.add_argument("--reg-names", choices=fpr_name_options.keys(), help="How to name registers in the output") +parser.add_argument( + "--reg-names", choices=fpr_name_options, help="How to name registers in the output" +) args = parser.parse_args() jobs = args.jobs -mips_isa.mips_fpr_names = fpr_name_options.get(args.reg_names, mips_isa.mips_fpr_names) +rabbitizer.config.regNames_fprAbiNames = rabbitizer.Abi.fromStr(args.reg_names) +rabbitizer.config.regNames_userFpcCsr = False ASM_OUT = "asm/" @@ -131,76 +136,6 @@ def discard_decomped_files(files_spec, include_files): return new_spec -MIPS_BRANCH_LIKELY_INSNS = [ - mips_isa.MIPS_INS_BEQL, - mips_isa.MIPS_INS_BGEZALL, - mips_isa.MIPS_INS_BGEZL, - mips_isa.MIPS_INS_BGTZL, - mips_isa.MIPS_INS_BLEZL, - mips_isa.MIPS_INS_BLTZALL, - mips_isa.MIPS_INS_BLTZL, - mips_isa.MIPS_INS_BNEL, - mips_isa.MIPS_INS_BC1TL, - mips_isa.MIPS_INS_BC1FL, -] - -MIPS_BRANCH_INSNS = [ - *MIPS_BRANCH_LIKELY_INSNS, - mips_isa.MIPS_INS_BEQ, - mips_isa.MIPS_INS_BGEZ, - mips_isa.MIPS_INS_BGEZAL, - mips_isa.MIPS_INS_BGTZ, - mips_isa.MIPS_INS_BNE, - mips_isa.MIPS_INS_BLTZ, - mips_isa.MIPS_INS_BLTZAL, - mips_isa.MIPS_INS_BLEZ, - mips_isa.MIPS_INS_BC1T, - mips_isa.MIPS_INS_BC1F, - mips_isa.MIPS_INS_BEQZ, - mips_isa.MIPS_INS_BNEZ, - mips_isa.MIPS_INS_B, -] - -MIPS_JUMP_INSNS = [mips_isa.MIPS_INS_JAL, mips_isa.MIPS_INS_JALR, mips_isa.MIPS_INS_J, mips_isa.MIPS_INS_JR] - -MIPS_FP_LOAD_INSNS = [mips_isa.MIPS_INS_LWC1, mips_isa.MIPS_INS_LDC1] - -MIPS_FP_STORE_INSNS = [mips_isa.MIPS_INS_SWC1, mips_isa.MIPS_INS_SDC1] - -MIPS_FP_LOAD_STORE_INSNS = [*MIPS_FP_LOAD_INSNS, *MIPS_FP_STORE_INSNS] - -MIPS_STORE_INSNS = [ - mips_isa.MIPS_INS_SB, - mips_isa.MIPS_INS_SH, - mips_isa.MIPS_INS_SW, - mips_isa.MIPS_INS_SWL, - mips_isa.MIPS_INS_SWR, - mips_isa.MIPS_INS_SD, - mips_isa.MIPS_INS_SDL, - mips_isa.MIPS_INS_SDR, - mips_isa.MIPS_INS_SC, - mips_isa.MIPS_INS_SCD, - *MIPS_FP_STORE_INSNS, -] - -MIPS_LOAD_STORE_INSNS = [ - mips_isa.MIPS_INS_LB, - mips_isa.MIPS_INS_LBU, - mips_isa.MIPS_INS_LH, - mips_isa.MIPS_INS_LHU, - mips_isa.MIPS_INS_LW, - mips_isa.MIPS_INS_LWL, - mips_isa.MIPS_INS_LWR, - mips_isa.MIPS_INS_LWU, - mips_isa.MIPS_INS_LD, - mips_isa.MIPS_INS_LDL, - mips_isa.MIPS_INS_LDR, - mips_isa.MIPS_INS_LL, - mips_isa.MIPS_INS_LLD, - *MIPS_STORE_INSNS, - *MIPS_FP_LOAD_STORE_INSNS, -] - VRAM_BASE = { "code": {"data": 0x801AAAB0, "rodata": 0x801DBDF0, "bss": 0x801E3FA0}, "boot": {"data": 0x800969C0, "rodata": 0x80098190, "bss": 0x80099500}, @@ -573,6 +508,18 @@ def update_symbols_from_dict(symbols_dict): put_text(file[0], file[1]) +def validateLuiImm(imm_value: int, insn: rabbitizer.Instruction) -> bool: + if ((imm_value >> 0x8) & 0xF) != 0 and imm_value < 0x1000: + return True + if imm_value >= 0x8000 and imm_value < 0x80D0: + return True + if imm_value >= 0xA400 and imm_value < 0xA480: + return True + if imm_value < 0x0400 and insn.uniqueId == rabbitizer.InstrId.cpu_addiu: + return True + return False + + def find_symbols_in_text(section, rodata_section, data_regions): data, rodata = section[4], rodata_section[4] if rodata_section else None vram, vram_rodata = section[0], rodata_section[0] if rodata_section else None @@ -582,6 +529,7 @@ def find_symbols_in_text(section, rodata_section, data_regions): print(f"Finding symbols from .text in {info['name']}") + rodata_words = [] if rodata is not None: rodata_words = as_word_list(rodata) @@ -623,20 +571,20 @@ def find_symbols_in_text(section, rodata_section, data_regions): # that means no code path produces a valid symbol at he convergent code, unless the convergent code provides all the # new registers. - # assert insn.value_forname(insn.fields[0]) is not None - # print(f"insn: {insn.mnemonic}, rt: {insn.rt}, first: {insn.value_forname(insn.fields[0])}") - # assert insn.id not in [MIPS_INS_ORI, mips_isa.MIPS_INS_ADDIU, *MIPS_LOAD_STORE_INSNS] or insn.rt == insn.value_forname(insn.fields[0]) - - if ( - delay_slot - and delayed_insn is not None - and delayed_insn.id in MIPS_BRANCH_LIKELY_INSNS - ): - clobber_later.update( - {delayed_insn.offset: insn.value_forname(insn.fields[0])} - ) + if delay_slot and delayed_insn is not None and delayed_insn.isBranchLikely(): + if insn.modifiesRd(): + clobber_later.update( + {delayed_insn.getBranchOffset() + delayed_insn.vram: insn.rd} + ) + elif insn.modifiesRt(): + clobber_later.update( + {delayed_insn.getBranchOffset() + delayed_insn.vram: insn.rt} + ) else: - lui_tracker.pop(insn.value_forname(insn.fields[0]), None) + if insn.modifiesRd(): + lui_tracker.pop(insn.rd, None) + elif insn.modifiesRt(): + lui_tracker.pop(insn.rt, None) for region in data_regions: assert region[1] != 0 @@ -644,28 +592,32 @@ def find_symbols_in_text(section, rodata_section, data_regions): if region[1] % 0x10 == 0: put_symbol(symbols_dict, "files", region[1]) - insns = [] + insns: list[rabbitizer.Instruction] = [] for i, raw_insn in enumerate(raw_insns, 0): - insn = mips_isa.decode_insn(raw_insn, vram + i * 4) + insn = rabbitizer.Instruction(raw_insn, vram=vram + i * 4) - if insn.id == mips_isa.MIPS_INS_JR and insn.rs != mips_isa.MIPS_REG_RA: - # It's hard to find when two jump tables next to each other end, so do a naive first pass - # to try and find as many jump tables as possible. - # Luckily IDO has a very homogeneous output for jump tables for which it is very unlikely - # that other instructions will break up: - # lui $at, %hi(jtbl) - # addu $at, $at, $reg - # lw $reg, %lo(jtbl)($at) - # jr $reg + if insn.isJrNotRa() and len(insns) > 3: + """ + It's hard to find when two jump tables next to each other end, so do a naive first pass + to try and find as many jump tables as possible. + Luckily IDO has a very homogeneous output for jump tables for which it is very unlikely + that other instructions will break up: + lui $at, %hi(jtbl) + addu $at, $at, $reg + lw $reg, %lo(jtbl)($at) + jr $reg + """ insn_m1 = insns[-1] insn_m2 = insns[-2] insn_m3 = insns[-3] if ( - insn_m1.id == mips_isa.MIPS_INS_LW - and insn_m2.id == mips_isa.MIPS_INS_ADDU - and insn_m3.id == mips_isa.MIPS_INS_LUI + insn_m1.uniqueId == rabbitizer.InstrId.cpu_lw + and insn_m2.uniqueId == rabbitizer.InstrId.cpu_addu + and insn_m3.uniqueId == rabbitizer.InstrId.cpu_lui ): - prospective_jtbls.add((insn_m3.imm << 0x10) + insn_m1.imm) + prospective_jtbls.add( + (insn_m3.getImmediate() << 0x10) + insn_m1.getProcessedImmediate() + ) insns.append(insn) if relocs is not None: @@ -684,40 +636,39 @@ def find_symbols_in_text(section, rodata_section, data_regions): Relocated jump targets give us functions in this section """ assert ( - insn.id == mips_isa.MIPS_INS_JAL - ), f"R_MIPS_26 applied to {insn.mnemonic} when it should be JAL" - put_symbol(symbols_dict, "functions", insn.target) + insn.uniqueId == rabbitizer.InstrId.cpu_jal + ), f"R_MIPS_26 applied to {insn.getOpcodeName()} when it should be JAL" + put_symbol(symbols_dict, "functions", insn.getInstrIndexAsVram()) elif reloc[1] == 5: # R_MIPS_HI16 """ Relocated %hi gives us %hi values to match with associated %lo """ assert ( - insn.id == mips_isa.MIPS_INS_LUI - ), f"R_MIPS_HI16 applied to {insn.mnemonic} when it should be LUI" - prev_hi = insn.imm + insn.canBeHi() + ), f"R_MIPS_HI16 applied to {insn.getOpcodeName()} when it should be LUI" + prev_hi = insn.getImmediate() hi_vram = vram + reloc[2] elif reloc[1] == 6: # R_MIPS_LO16 """ Relocated %lo + a %hi to match with gives us relocated symbols in data sections """ assert ( - insn.id == mips_isa.MIPS_INS_ADDIU or insn.id in MIPS_LOAD_STORE_INSNS - ), f"R_MIPS_HI16 applied to {insn.mnemonic} when it should be ADDIU or a load/store" - symbol_value = (prev_hi << 0x10) + insn.imm + insn.canBeLo() + ), f"R_MIPS_HI16 applied to {insn.getOpcodeName()} when it should be ADDIU or a load/store" + assert prev_hi is not None + symbol_value = (prev_hi << 0x10) + insn.getProcessedImmediate() put_symbols(symbols_dict, "symbols", {hi_vram: symbol_value}) put_symbols(symbols_dict, "symbols", {vram + reloc[2]: symbol_value}) else: assert False, "Invalid relocation type encountered" result_files = [] - results = [asm_header(".text")] + results: list[str | dict] = [asm_header(".text")] raw_insns = as_word_list(data) cur_file = "" cur_vaddr = 0 - segment_dirname = ("" if info["type"] != "overlay" else "overlays/") + info["name"] - delayed_insn = None delay_slot = False @@ -730,14 +681,13 @@ def find_symbols_in_text(section, rodata_section, data_regions): if vaddr in range(region[0], region[1], 4): in_data = True break + if not insn.isValid(): + in_data = True if in_data: results.append( { - "vaddr": vaddr, - "insn": {"id": insn.id}, - "addr": f"/* {i*4:06X} {vaddr:08X} {raw_insns[i]:08X} */ ", - "mnem": "", - "op": [f" .word 0x{raw_insns[i]:08X}"], + "insn": insn, + "comment": f"/* {i*4:06X} {vaddr:08X} {raw_insns[i]:08X} */", "data": True, } ) @@ -764,19 +714,21 @@ def find_symbols_in_text(section, rodata_section, data_regions): if cl is not None: lui_tracker.pop(cl, None) - if insn.id in MIPS_BRANCH_INSNS: - func_branch_labels.add(insn.offset) + branch_likely_delay_slot_save = None + + if insn.isBranch(): + func_branch_labels.add(insn.getBranchOffset() + insn.vram) delayed_insn = insn - elif insn.id == mips_isa.MIPS_INS_ERET: + elif insn.uniqueId == rabbitizer.InstrId.cpu_eret: put_symbol(symbols_dict, "functions", vaddr + 4) - elif insn.id in MIPS_JUMP_INSNS: - if insn.id == mips_isa.MIPS_INS_JAL: + elif insn.isJump(): + if insn.uniqueId == rabbitizer.InstrId.cpu_jal: # mark function at target - put_symbol(symbols_dict, "functions", insn.target) - elif insn.id == mips_isa.MIPS_INS_J: + put_symbol(symbols_dict, "functions", insn.getInstrIndexAsVram()) + elif insn.uniqueId == rabbitizer.InstrId.cpu_j: # mark label at target - func_branch_labels.add(insn.target) - elif insn.id == mips_isa.MIPS_INS_JR: + func_branch_labels.add(insn.getInstrIndexAsVram()) + elif insn.uniqueId == rabbitizer.InstrId.cpu_jr: # check if anything branches past it in either branch or jtbl labels if vaddr >= max(func_branch_labels, default=0) and vaddr >= max( func_jtbl_labels, default=0 @@ -802,7 +754,7 @@ def find_symbols_in_text(section, rodata_section, data_regions): symbols_dict, "functions", vaddr + 8 + n_padding * 4 ) delayed_insn = insn - elif insn.id == mips_isa.MIPS_INS_LUI: + elif insn.canBeHi(): """ Process LUI instruction @@ -813,45 +765,47 @@ def find_symbols_in_text(section, rodata_section, data_regions): if ( delay_slot and delayed_insn is not None - and delayed_insn.id in MIPS_BRANCH_LIKELY_INSNS + and delayed_insn.isBranchLikely() ): # for branch likelies, the current tracker does not update but the lui is saved to be tracked at the branch target - save_tracker(delayed_insn.offset, {insn.rt: (vaddr, insn.imm)}) + branch_likely_delay_slot_save = {insn.rt: (vaddr, insn.getProcessedImmediate())} else: - lui_tracker.update({insn.rt: (vaddr, insn.imm)}) - elif insn.id == mips_isa.MIPS_INS_ADDIU or insn.id in MIPS_LOAD_STORE_INSNS: + lui_tracker.update({insn.rt: (vaddr, insn.getProcessedImmediate())}) + elif insn.uniqueId == rabbitizer.InstrId.cpu_ori: + # try match with tracked lui and mark constant + hi_vram, imm_value = lui_tracker.get(insn.rs, (None, None)) + if hi_vram is not None and imm_value is not None: # found match + lo_vram = vaddr + const_value = (imm_value << 0x10) | insn.getProcessedImmediate() + put_symbols(symbols_dict, "constants", {hi_vram: const_value}) + put_symbols(symbols_dict, "constants", {lo_vram: const_value}) + # clear lui tracking state if register is clobbered by the ori instruction itself + # insn.rt == insn.rs or + if insn.rt in lui_tracker.keys(): + clobber_conditionally(insn) + elif insn.canBeLo(): # try match with tracked lui and mark symbol - hi_vram, imm_value = lui_tracker.get( - insn.rs if insn.id == mips_isa.MIPS_INS_ADDIU else insn.base, (None, None) - ) + hi_vram, imm_value = lui_tracker.get(insn.rs, (None, None)) # if a match was found, validate and record the symbol, TODO improve validation - if hi_vram != None and ( - (((imm_value >> 0x8) & 0xF) != 0 and imm_value < 0x1000) - or (imm_value >= 0x8000 and imm_value < 0x80D0) - or (imm_value >= 0xA400 and imm_value < 0xA480) - or (imm_value < 0x0400 and insn.id == mips_isa.MIPS_INS_ADDIU) + if ( + hi_vram is not None + and imm_value is not None + and validateLuiImm(imm_value, insn) ): lo_vram = vaddr - symbol_value = (imm_value << 0x10) + insn.imm + symbol_value = (imm_value << 0x10) + insn.getProcessedImmediate() put_symbols(symbols_dict, "symbols", {hi_vram: symbol_value}) put_symbols(symbols_dict, "symbols", {lo_vram: symbol_value}) - if insn.id == mips_isa.MIPS_INS_LW: + if insn.uniqueId == rabbitizer.InstrId.cpu_lw: # try find jr within the same block cur_idx = i lookahead_insn = insns[cur_idx] # TODO fix vaddr here # still in same block unless one of these instructions are found - while lookahead_insn.id not in [ - *MIPS_BRANCH_INSNS, - mips_isa.MIPS_INS_JAL, - mips_isa.MIPS_INS_JALR, - mips_isa.MIPS_INS_J, - ]: - if lookahead_insn.id == mips_isa.MIPS_INS_JR: - if lookahead_insn.rs == ( - insn.ft - if insn.id in MIPS_FP_LOAD_STORE_INSNS - else insn.rt - ): + while lookahead_insn.isJrNotRa() or not ( + lookahead_insn.isBranch() or lookahead_insn.isJump() + ): + if lookahead_insn.uniqueId == rabbitizer.InstrId.cpu_jr: + if lookahead_insn.rs == insn.rt: # read the jtbl and add targets to func_jtbl_labels assert ( rodata is not None @@ -881,104 +835,52 @@ def find_symbols_in_text(section, rodata_section, data_regions): put_symbol(symbols_dict, "jtbls", symbol_value) # found a jr that matches, no need to keep searching break - elif ( - insn.ft if insn.id in MIPS_FP_LOAD_STORE_INSNS else insn.rt - ) in [ - lookahead_insn.value_forname(field) - for field in lookahead_insn.fields[1:] - ]: - # register clobbered, no need to keep searching - break cur_idx += 1 # found end before finding jr insn, not a jtbl if cur_idx >= len(raw_insns): break lookahead_insn = insns[cur_idx] # TODO fix vaddr here - elif insn.id == mips_isa.MIPS_INS_LD: # doubleword loads + elif insn.uniqueId == rabbitizer.InstrId.cpu_ld: # doubleword loads put_symbol(symbols_dict, "dwords", symbol_value) - elif insn.id in [mips_isa.MIPS_INS_LWC1, mips_isa.MIPS_INS_SWC1]: # float load/stores - # add float - put_symbol(symbols_dict, "floats", symbol_value) - elif insn.id in [mips_isa.MIPS_INS_LDC1, mips_isa.MIPS_INS_SDC1]: # double load/stores - # add double - put_symbol(symbols_dict, "doubles", symbol_value) - elif ( - insn.id == mips_isa.MIPS_INS_ADDIU and vaddr % 4 == 0 - ): # strings seem to only ever be 4-byte aligned - # add possible string - put_symbol(symbols_dict, "prospective_strings", symbol_value) + elif insn.doesDereference() and insn.isFloat(): + if insn.isDouble(): # double load/stores + # add double + put_symbol(symbols_dict, "doubles", symbol_value) + else: # float load/stores + # add float + put_symbol(symbols_dict, "floats", symbol_value) + elif not insn.doesDereference() and not insn.isUnsigned(): + if vaddr % 4 == 0: # strings seem to only ever be 4-byte aligned + # add possible string + put_symbol(symbols_dict, "prospective_strings", symbol_value) # clear lui tracking state if register is clobbered by the addiu/load instruction itself - # insn.rt == (insn.rs if insn.id == mips_isa.MIPS_INS_ADDIU else insn.base) and - if insn.id not in MIPS_STORE_INSNS and insn.id not in MIPS_FP_LOAD_INSNS: - clobber_conditionally(insn) - elif insn.id == mips_isa.MIPS_INS_ORI: - # try match with tracked lui and mark constant - hi_vram, imm_value = lui_tracker.get(insn.rs, (None, None)) - if hi_vram != None: # found match - lo_vram = vaddr - const_value = (imm_value << 0x10) | insn.imm - put_symbols(symbols_dict, "constants", {hi_vram: const_value}) - put_symbols(symbols_dict, "constants", {lo_vram: const_value}) - # clear lui tracking state if register is clobbered by the ori instruction itself - # insn.rt == insn.rs or - if insn.rt in lui_tracker.keys(): + if not insn.doesStore() and not (insn.doesLoad() and insn.isFloat()): clobber_conditionally(insn) else: # clear lui tracking if register is clobbered by something unrelated if ( - insn.id == mips_isa.MIPS_INS_ADDU + insn.uniqueId == rabbitizer.InstrId.cpu_addu and insn.rs in lui_tracker.keys() - and (insn.rd == insn.rs) + and insn.rd == insn.rs ): - # array accesses optimisation: - # lui reg, %hi(symbol) - # addu reg, reg, idx - # lw reg, %lo(symbol)(reg) - # instead of clobbering, keep it if the second operand is also the first - # if the output is not currently tracked it will behave as intended anyway + """ + array accesses optimisation: + lui reg, %hi(symbol) + addu reg, reg, idx + lw reg, %lo(symbol)(reg) + instead of clobbering, keep it if the second operand is also the first + if the output is not currently tracked it will behave as intended anyway + """ pass # insns listed either write to fprs/cop0 or don't write to any - elif insn.id not in [ - mips_isa.MIPS_INS_MTC0, - mips_isa.MIPS_INS_MTC1, - mips_isa.MIPS_INS_DMTC1, - mips_isa.MIPS_INS_MULT, - mips_isa.MIPS_INS_MULTU, - mips_isa.MIPS_INS_DMULT, - mips_isa.MIPS_INS_DMULTU, - mips_isa.MIPS_INS_DIV, - mips_isa.MIPS_INS_DIVU, - mips_isa.MIPS_INS_DDIV, - mips_isa.MIPS_INS_DDIVU, - mips_isa.MIPS_INS_MTHI, - mips_isa.MIPS_INS_MTLO, - mips_isa.MIPS_INS_CTC1, - mips_isa.MIPS_INS_NOP, - mips_isa.MIPS_INS_BREAK, - mips_isa.MIPS_INS_TLBP, - mips_isa.MIPS_INS_TLBR, - mips_isa.MIPS_INS_TLBWI, - mips_isa.MIPS_INS_MOV_S, - mips_isa.MIPS_INS_MOV_D, - mips_isa.MIPS_INS_C_LT_S, - mips_isa.MIPS_INS_C_LT_D, - mips_isa.MIPS_INS_DIV_S, - mips_isa.MIPS_INS_MUL_S, - mips_isa.MIPS_INS_TRUNC_W_S, - mips_isa.MIPS_INS_CVT_S_W, - mips_isa.MIPS_INS_SUB_S, - mips_isa.MIPS_INS_ADD_S, - ]: + else: clobber_conditionally(insn) ############# Start text disassembly ########## # Symbols aren't avaialble here yet, so placeholders are added # in each instruction, to be looked up later - mnemonic = f" {insn.mnemonic}" if delay_slot else insn.mnemonic - op_str = insn.op_str - instr = {"id": insn.id} - if vaddr in full_file_list[info["name"]]: + if info["name"] in full_file_list and vaddr in full_file_list[info["name"]]: if cur_file != "": if cur_vaddr in info["syms"]: result_files.append([cur_file, results]) @@ -988,51 +890,10 @@ def find_symbols_in_text(section, rodata_section, data_regions): if cur_file == "": cur_file = f"{info['name']}_{vaddr:08X}" - if insn.id in MIPS_BRANCH_INSNS: - op_str_parts = [] - for field in insn.fields: - if field == "offset": - op_str_parts.append(f".L{insn.offset:08X}") - else: - op_str_parts.append(insn.format_field(field)) - op_str = [", ".join(op_str_parts)] - - elif insn.id in MIPS_JUMP_INSNS: - op_str = [] - op_str_parts = [] - for field in insn.fields: - if field == "target": - op_str_parts.append([insn.target, False, True]) - else: - op_str_parts.append(insn.format_field(field)) - for x, part in enumerate(op_str_parts): - if x + 1 < len(op_str_parts): - part += ", " - op_str.append(part) - - elif insn.id == mips_isa.MIPS_INS_LUI: - op_str = [op_str] - instr["rt"] = insn.rt - - elif insn.id == mips_isa.MIPS_INS_ADDIU or insn.id in MIPS_LOAD_STORE_INSNS: - op_str = [op_str] - instr["rt"] = insn.rt - instr["rs"] = insn.rs - instr["ft"] = insn.ft - instr["base"] = insn.base - - elif insn.id == mips_isa.MIPS_INS_ORI: - op_str = [op_str] - instr["rt"] = insn.rt - instr["rs"] = insn.rs - results.append( { - "vaddr": vaddr, - "insn": instr, - "addr": f"/* {i*4:06X} {vaddr:08X} {raw_insns[i]:08X} */ ", - "mnem": mnemonic, - "op": op_str, + "insn": insn, + "comment": f"/* {i*4:06X} {vaddr:08X} {raw_insns[i]:08X} */", "data": False, } ) @@ -1041,22 +902,30 @@ def find_symbols_in_text(section, rodata_section, data_regions): if delay_slot and delayed_insn is not None: if ( - delayed_insn.id == mips_isa.MIPS_INS_JAL - or delayed_insn.id == mips_isa.MIPS_INS_JALR - or (delayed_insn.id == mips_isa.MIPS_INS_JR and delayed_insn.rs == mips_isa.MIPS_REG_RA) + delayed_insn.uniqueId == rabbitizer.InstrId.cpu_jal + or delayed_insn.uniqueId == rabbitizer.InstrId.cpu_jalr + or delayed_insn.isJrRa() ): # destroy lui tracking state lui_tracker.clear() - elif delayed_insn.id == mips_isa.MIPS_INS_JR and vaddr == next_jtbl_jr + 4: + elif ( + delayed_insn.uniqueId == rabbitizer.InstrId.cpu_jr + and vaddr == next_jtbl_jr + 4 + ): # save lui tracking state for each jtbl label for label in individual_jtbl_labels[next_jtbl_jr]: save_tracker(label, lui_tracker.copy()) next_jtbl_jr = 0 - else: + elif delayed_insn.isBranch(): # save lui tracking state - save_tracker(delayed_insn.offset, lui_tracker.copy()) + save_tracker( + delayed_insn.getBranchOffset() + delayed_insn.vram, + lui_tracker.copy(), + ) + if branch_likely_delay_slot_save is not None: + save_tracker(delayed_insn.getBranchOffset() + delayed_insn.vram, branch_likely_delay_slot_save) # destroy current lui tracking state for unconditional branches - if delayed_insn.id == mips_isa.MIPS_INS_B: + if delayed_insn.isUnconditionalBranch(): lui_tracker.clear() delayed_insn = None @@ -1221,7 +1090,7 @@ def find_symbols_in_rodata(section): return symbols_dict -def asm_header(section_name): +def asm_header(section_name: str): return f""".include "macro.inc" # assembler directives @@ -1235,6 +1104,43 @@ def asm_header(section_name): """ +def getImmOverride(insn: rabbitizer.Instruction) -> str | None: + if insn.isBranch(): + return f".L{insn.getBranchOffset() + insn.vram:08X}" + elif insn.isJump(): + return proper_name(insn.getInstrIndexAsVram(), in_data=False, is_symbol=True) + + elif insn.uniqueId == rabbitizer.InstrId.cpu_ori: + constant_value = constants.get(insn.vram, None) + if constant_value is not None: + return f"(0x{constant_value:08X} & 0xFFFF)" + + elif insn.canBeHi(): + symbol_value = symbols.get(insn.vram, None) + if symbol_value is not None: + return f"%hi({proper_name(symbol_value)})" + constant_value = constants.get(insn.vram, None) + if constant_value is not None: + return f"(0x{constant_value:08X} >> 16)" + + elif insn.canBeLo(): + symbol_value = symbols.get(insn.vram, None) + if symbol_value is not None: + return f"%lo({proper_name(symbol_value)})" + return None + + +def getLabelForVaddr(vaddr: int, in_data: bool = False) -> str: + label = "" + if vaddr in functions: + label += f"\nglabel {proper_name(vaddr, in_data=in_data)}\n" + if vaddr in jtbl_labels: + label += f"glabel L{vaddr:08X}\n" + if vaddr in branch_labels: + label += f".L{vaddr:08X}:\n" + return label + + def fixup_text_symbols(data, vram, data_regions, info): segment_dirname = "" if info["type"] != "overlay" else "overlays/" if info["type"] in ("boot", "code"): @@ -1251,73 +1157,34 @@ def fixup_text_symbols(data, vram, data_regions, info): # We didn't have full symbols available during initial disassembly, # so here we loop over each instruction, and do symbol lookups, add labels etc - for i, entry in enumerate(file): - vaddr = entry["vaddr"] - - if vaddr in functions: - text.append(f"\nglabel {proper_name(vaddr, in_data=entry['data'])}\n") - if vaddr in jtbl_labels: - text.append(f"glabel L{vaddr:08X}\n") - if vaddr in branch_labels: - text.append(f".L{vaddr:08X}:\n") - - line = entry["addr"] - if not entry["data"]: - line += f"{entry['mnem']:12}" - + delay_slot = False + disasm_as_data = False + for entry in file: insn = entry["insn"] - if insn["id"] in MIPS_JUMP_INSNS: - for op_part in entry["op"]: - if type(op_part) == list: - line += proper_name( - op_part[0], in_data=op_part[1], is_symbol=op_part[2] - ) - else: - line += op_part + in_data = entry["data"] + comment = entry["comment"] - elif insn["id"] == mips_isa.MIPS_INS_LUI: - symbol_value = symbols.get(vaddr, None) - if symbol_value is not None: - line += ( - f"{ mips_isa.mips_gpr_names[insn['rt']]}, %hi({proper_name(symbol_value)})" - ) - else: - constant_value = constants.get(vaddr, None) - if constant_value is not None: - line += ( - f"{ mips_isa.mips_gpr_names[insn['rt']]}, (0x{constant_value:08X} >> 16)" - ) - else: - line += entry["op"][0] + text.append(getLabelForVaddr(insn.vram, in_data)) + if insn.vram in functions: + # new function, needs to check this again + disasm_as_data = False - elif insn["id"] == mips_isa.MIPS_INS_ADDIU or insn["id"] in MIPS_LOAD_STORE_INSNS: - symbol_value = symbols.get(vaddr, None) - if symbol_value is not None: - if insn["id"] == mips_isa.MIPS_INS_ADDIU: - line += f"{ mips_isa.mips_gpr_names[insn['rt']]}, { mips_isa.mips_gpr_names[insn['rs']]}, %lo({proper_name(symbol_value)})" - else: - line += f"{mips_isa.mips_fpr_names[insn['ft']] if insn['id'] in MIPS_FP_LOAD_STORE_INSNS else mips_isa.mips_gpr_names[insn['rt']]}, %lo({proper_name(symbol_value)})({ mips_isa.mips_gpr_names[insn['base']]})" - else: - line += entry["op"][0] + if in_data or disasm_as_data: + disasm_as_data = True + text.append(f"{comment} .word 0x{insn.getRaw():08X}\n") + continue - elif insn["id"] == mips_isa.MIPS_INS_ORI: - constant_value = constants.get(vaddr, None) - if constant_value is not None: - line += f"{ mips_isa.mips_gpr_names[insn['rt']]}, { mips_isa.mips_gpr_names[insn['rs']]}, (0x{constant_value:08X} & 0xFFFF)" - else: - line += entry["op"][0] + extraLJust = 0 + if delay_slot: + extraLJust = -1 + comment += " " - else: - for part in entry["op"]: - if type(part) == list: - line += ( - f"{proper_name(part[0], in_data=part[1], is_symbol=part[2])}" - ) - else: - line += part + disassembled = insn.disassemble( + immOverride=getImmOverride(insn), extraLJust=extraLJust + ) + text.append(f"{comment} {disassembled}\n") - line += "\n" - text.append(line) + delay_slot = insn.hasDelaySlot() with open(f"{ASM_OUT}/{segment_dirname}/{info['name']}.text.s", "w") as outfile: outfile.write("".join(text)) @@ -1333,15 +1200,12 @@ def disassemble_text(data, vram, data_regions, info): segment_dirname = ("" if info["type"] != "overlay" else "overlays/") + info["name"] os.makedirs(f"{ASM_OUT}/{segment_dirname}/", exist_ok=True) - delayed_insn = None delay_slot = False for i, raw_insn in enumerate(raw_insns, 0): i *= 4 vaddr = vram + i - insn = mips_isa.decode_insn(raw_insns[i // 4], vaddr) - mnemonic = insn.mnemonic - op_str = insn.op_str + insn = rabbitizer.Instruction(raw_insns[i // 4], vram=vaddr) if vaddr in full_file_list[info["name"]]: if cur_file != "": @@ -1372,63 +1236,20 @@ def disassemble_text(data, vram, data_regions, info): ) continue - # LABELS - if vaddr in functions: - result += f"\nglabel {proper_name(vaddr)}\n" - if vaddr in jtbl_labels: - result += f"glabel L{vaddr:08X}\n" - if vaddr in branch_labels: - result += f".L{vaddr:08X}:\n" - - # INSTRUCTIONS FORMATTING/CORRECTING - if insn.id in MIPS_BRANCH_INSNS: - op_str_parts = [] - for field in insn.fields: - if field == "offset": - op_str_parts.append(f".L{insn.offset:08X}") - else: - op_str_parts.append(insn.format_field(field)) - op_str = ", ".join(op_str_parts) - delayed_insn = insn - elif insn.id in MIPS_JUMP_INSNS: - op_str_parts = [] - for field in insn.fields: - if field == "target": - op_str_parts.append(proper_name(insn.target, is_symbol=True)) - else: - op_str_parts.append(insn.format_field(field)) - op_str = ", ".join(op_str_parts) - delayed_insn = insn - elif insn.id == mips_isa.MIPS_INS_LUI: - symbol_value = symbols.get(vaddr, None) - if symbol_value is not None: - op_str = f"{ mips_isa.mips_gpr_names[insn.rt]}, %hi({proper_name(symbol_value)})" - else: - constant_value = constants.get(vaddr, None) - if constant_value is not None: - op_str = ( - f"{ mips_isa.mips_gpr_names[insn.rt]}, (0x{constant_value:08X} >> 16)" - ) - elif insn.id == mips_isa.MIPS_INS_ADDIU or insn.id in MIPS_LOAD_STORE_INSNS: - symbol_value = symbols.get(vaddr, None) - if symbol_value is not None: - if insn.id == mips_isa.MIPS_INS_ADDIU: - op_str = f"{ mips_isa.mips_gpr_names[insn.rt]}, { mips_isa.mips_gpr_names[insn.rs]}, %lo({proper_name(symbol_value)})" - else: - op_str = f"{mips_isa.mips_fpr_names[insn.ft] if insn.id in MIPS_FP_LOAD_STORE_INSNS else mips_isa.mips_gpr_names[insn.rt]}, %lo({proper_name(symbol_value)})({ mips_isa.mips_gpr_names[insn.base]})" - elif insn.id == mips_isa.MIPS_INS_ORI: - constant_value = constants.get(vaddr, None) - if constant_value is not None: - op_str = f"{ mips_isa.mips_gpr_names[insn.rt]}, { mips_isa.mips_gpr_names[insn.rs]}, (0x{constant_value:08X} & 0xFFFF)" + result += getLabelForVaddr(vaddr) + comment = f"/* {i:06X} {vaddr:08X} {raw_insn:08X} */" + extraLJust = 0 if delay_slot: - mnemonic = " " + mnemonic - delayed_insn = None - delay_slot = False - if delayed_insn is not None: - delay_slot = True + extraLJust = -1 + comment += " " - result += f"/* {i:06X} {vaddr:08X} {raw_insn:08X} */ {mnemonic:12}{op_str}\n" + disassembled = insn.disassemble( + immOverride=getImmOverride(insn), extraLJust=extraLJust + ) + result += f"{comment} {disassembled}\n" + + delay_slot = insn.hasDelaySlot() with open(f"{ASM_OUT}/{segment_dirname}/{cur_file}.text.s", "w") as outfile: outfile.write(result) @@ -1703,12 +1524,16 @@ def disassemble_rodata(data, vram, end, info): if symbol in strings: string_data = data[data_offset : data_offset + data_size] - string_data = string_data[: string_data.index(0)] - # ensure strings don't have a null char midway through - assert all( - [b != 0 for b in string_data[:-1]] - ), f"{symbol:08X} , {data_size:X} , {string_data}" - r += f"/* {data_base:06X} {symbol:08X} */ {try_decode_string(string_data, force_ascii=force_ascii_str)}\n{STR_INDENT}.balign 4\n" + if 0 in string_data: + string_data = string_data[: string_data.index(0)] + # ensure strings don't have a null char midway through + assert all( + [b != 0 for b in string_data[:-1]] + ), f"{symbol:08X} , {data_size:X} , {string_data}" + r += f"/* {data_base:06X} {symbol:08X} */ {try_decode_string(string_data, force_ascii=force_ascii_str)}\n{STR_INDENT}.balign 4\n" + else: + # Not null-terminanted. Can't be a string + strings.remove(symbol) elif symbol % 8 == 0 and data_size % 8 == 0 and symbol in doubles: r += ( "\n".join( @@ -2392,9 +2217,10 @@ for section in all_sections: rodata_section = None pool.apply_async( find_symbols_in_text, - args=(section, rodata_section if rodata_section else None, data_regions), + args=(section, rodata_section, data_regions), callback=update_symbols_from_dict, ) + elif section[2] == "data": pool.apply_async( find_symbols_in_data, args=(section), callback=update_symbols_from_dict diff --git a/tools/disasm/mips_isa.py b/tools/disasm/mips_isa.py deleted file mode 100644 index 337bbd021f..0000000000 --- a/tools/disasm/mips_isa.py +++ /dev/null @@ -1,776 +0,0 @@ -# Register IDs -MIPS_REG_R0 = MIPS_REG_F0 = 0 -MIPS_REG_AT = MIPS_REG_F1 = 1 -MIPS_REG_V0 = MIPS_REG_F2 = 2 -MIPS_REG_V1 = MIPS_REG_F3 = 3 -MIPS_REG_A0 = MIPS_REG_F4 = 4 -MIPS_REG_A1 = MIPS_REG_F5 = 5 -MIPS_REG_A2 = MIPS_REG_F6 = 6 -MIPS_REG_A3 = MIPS_REG_F7 = 7 -MIPS_REG_T0 = MIPS_REG_F8 = 8 -MIPS_REG_T1 = MIPS_REG_F9 = 9 -MIPS_REG_T2 = MIPS_REG_F10 = 10 -MIPS_REG_T3 = MIPS_REG_F11 = 11 -MIPS_REG_T4 = MIPS_REG_F12 = 12 -MIPS_REG_T5 = MIPS_REG_F13 = 13 -MIPS_REG_T6 = MIPS_REG_F14 = 14 -MIPS_REG_T7 = MIPS_REG_F15 = 15 -MIPS_REG_S0 = MIPS_REG_F16 = 16 -MIPS_REG_S1 = MIPS_REG_F17 = 17 -MIPS_REG_S2 = MIPS_REG_F18 = 18 -MIPS_REG_S3 = MIPS_REG_F19 = 19 -MIPS_REG_S4 = MIPS_REG_F20 = 20 -MIPS_REG_S5 = MIPS_REG_F21 = 21 -MIPS_REG_S6 = MIPS_REG_F22 = 22 -MIPS_REG_S7 = MIPS_REG_F23 = 23 -MIPS_REG_T8 = MIPS_REG_F24 = 24 -MIPS_REG_T9 = MIPS_REG_F25 = 25 -MIPS_REG_K0 = MIPS_REG_F26 = 26 -MIPS_REG_K1 = MIPS_REG_F27 = 27 -MIPS_REG_GP = MIPS_REG_F28 = 28 -MIPS_REG_SP = MIPS_REG_F29 = 29 -MIPS_REG_FP = MIPS_REG_F30 = 30 -MIPS_REG_RA = MIPS_REG_F31 = 31 - -# Instruction Unique IDs -MIPS_INS_SLL = 0 -MIPS_INS_SRL = 1 -MIPS_INS_SRA = 2 -MIPS_INS_SLLV = 3 -MIPS_INS_SRLV = 4 -MIPS_INS_SRAV = 5 -MIPS_INS_JR = 6 -MIPS_INS_JALR = 7 -MIPS_INS_SYSCALL = 8 -MIPS_INS_BREAK = 9 -MIPS_INS_SYNC = 10 -MIPS_INS_MFHI = 11 -MIPS_INS_MTHI = 12 -MIPS_INS_MFLO = 13 -MIPS_INS_MTLO = 14 -MIPS_INS_DSLLV = 15 -MIPS_INS_DSRLV = 16 -MIPS_INS_DSRAV = 17 -MIPS_INS_MULT = 18 -MIPS_INS_MULTU = 19 -MIPS_INS_DIV = 20 -MIPS_INS_DIVU = 21 -MIPS_INS_DMULT = 22 -MIPS_INS_DMULTU = 23 -MIPS_INS_DDIV = 24 -MIPS_INS_DDIVU = 25 -MIPS_INS_ADD = 26 -MIPS_INS_ADDU = 27 -MIPS_INS_SUB = 28 -MIPS_INS_SUBU = 29 -MIPS_INS_AND = 30 -MIPS_INS_OR = 31 -MIPS_INS_XOR = 32 -MIPS_INS_NOR = 33 -MIPS_INS_SLT = 34 -MIPS_INS_SLTU = 35 -MIPS_INS_DADD = 36 -MIPS_INS_DADDU = 37 -MIPS_INS_DSUB = 38 -MIPS_INS_DSUBU = 39 -MIPS_INS_TGE = 40 -MIPS_INS_TGEU = 41 -MIPS_INS_TLT = 42 -MIPS_INS_TLTU = 43 -MIPS_INS_TEQ = 44 -MIPS_INS_TNE = 45 -MIPS_INS_DSLL = 46 -MIPS_INS_DSRL = 47 -MIPS_INS_DSRA = 48 -MIPS_INS_DSLL32 = 49 -MIPS_INS_DSRL32 = 50 -MIPS_INS_DSRA32 = 51 -MIPS_INS_BLTZ = 52 -MIPS_INS_BGEZ = 53 -MIPS_INS_BLTZL = 54 -MIPS_INS_BGEZL = 55 -MIPS_INS_TGEI = 56 -MIPS_INS_TGEIU = 57 -MIPS_INS_TLTI = 58 -MIPS_INS_TLTIU = 59 -MIPS_INS_TEQI = 60 -MIPS_INS_TNEI = 61 -MIPS_INS_BLTZAL = 62 -MIPS_INS_BGEZAL = 63 -MIPS_INS_BLTZALL = 64 -MIPS_INS_BGEZALL = 65 -MIPS_INS_J = 66 -MIPS_INS_JAL = 67 -MIPS_INS_BEQ = 68 -MIPS_INS_BNE = 69 -MIPS_INS_BLEZ = 70 -MIPS_INS_BGTZ = 71 -MIPS_INS_ADDI = 72 -MIPS_INS_ADDIU = 73 -MIPS_INS_SLTI = 74 -MIPS_INS_SLTIU = 75 -MIPS_INS_ANDI = 76 -MIPS_INS_ORI = 77 -MIPS_INS_XORI = 78 -MIPS_INS_LUI = 79 -MIPS_INS_MFC0 = 80 -MIPS_INS_MTC0 = 81 -MIPS_INS_TLBR = 82 -MIPS_INS_TLBWI = 83 -MIPS_INS_TLBWR = 84 -MIPS_INS_TLBP = 85 -MIPS_INS_ERET = 86 -MIPS_INS_MFC1 = 87 -MIPS_INS_DMFC1 = 88 -MIPS_INS_CFC1 = 89 -MIPS_INS_MTC1 = 90 -MIPS_INS_DMTC1 = 91 -MIPS_INS_CTC1 = 92 -MIPS_INS_BC1F = 93 -MIPS_INS_BC1T = 94 -MIPS_INS_BC1FL = 95 -MIPS_INS_BC1TL = 96 -MIPS_INS_ADD_S = 97 -MIPS_INS_SUB_S = 98 -MIPS_INS_MUL_S = 99 -MIPS_INS_DIV_S = 100 -MIPS_INS_SQRT_S = 101 -MIPS_INS_ABS_S = 102 -MIPS_INS_MOV_S = 103 -MIPS_INS_NEG_S = 104 -MIPS_INS_ROUND_L_S = 105 -MIPS_INS_TRUNC_L_S = 106 -MIPS_INS_CEIL_L_S = 107 -MIPS_INS_FLOOR_L_S = 108 -MIPS_INS_ROUND_W_S = 109 -MIPS_INS_TRUNC_W_S = 110 -MIPS_INS_CEIL_W_S = 111 -MIPS_INS_FLOOR_W_S = 112 -MIPS_INS_CVT_D_S = 113 -MIPS_INS_CVT_W_S = 114 -MIPS_INS_CVT_L_S = 115 -MIPS_INS_C_F_S = 116 -MIPS_INS_C_UN_S = 117 -MIPS_INS_C_EQ_S = 118 -MIPS_INS_C_UEQ_S = 119 -MIPS_INS_C_OLT_S = 120 -MIPS_INS_C_ULT_S = 121 -MIPS_INS_C_OLE_S = 122 -MIPS_INS_C_ULE_S = 123 -MIPS_INS_C_SF_S = 124 -MIPS_INS_C_NGLE_S = 125 -MIPS_INS_C_SEQ_S = 126 -MIPS_INS_C_NGL_S = 127 -MIPS_INS_C_LT_S = 128 -MIPS_INS_C_NGE_S = 129 -MIPS_INS_C_LE_S = 130 -MIPS_INS_C_NGT_S = 131 -MIPS_INS_ADD_D = 132 -MIPS_INS_SUB_D = 133 -MIPS_INS_MUL_D = 134 -MIPS_INS_DIV_D = 135 -MIPS_INS_SQRT_D = 136 -MIPS_INS_ABS_D = 137 -MIPS_INS_MOV_D = 138 -MIPS_INS_NEG_D = 139 -MIPS_INS_ROUND_L_D = 140 -MIPS_INS_TRUNC_L_D = 141 -MIPS_INS_CEIL_L_D = 142 -MIPS_INS_FLOOR_L_D = 143 -MIPS_INS_ROUND_W_D = 144 -MIPS_INS_TRUNC_W_D = 145 -MIPS_INS_CEIL_W_D = 146 -MIPS_INS_FLOOR_W_D = 147 -MIPS_INS_CVT_S_D = 148 -MIPS_INS_CVT_W_D = 149 -MIPS_INS_CVT_L_D = 150 -MIPS_INS_C_F_D = 151 -MIPS_INS_C_UN_D = 152 -MIPS_INS_C_EQ_D = 153 -MIPS_INS_C_UEQ_D = 154 -MIPS_INS_C_OLT_D = 155 -MIPS_INS_C_ULT_D = 156 -MIPS_INS_C_OLE_D = 157 -MIPS_INS_C_ULE_D = 158 -MIPS_INS_C_SF_D = 159 -MIPS_INS_C_NGLE_D = 160 -MIPS_INS_C_SEQ_D = 161 -MIPS_INS_C_NGL_D = 162 -MIPS_INS_C_LT_D = 163 -MIPS_INS_C_NGE_D = 164 -MIPS_INS_C_LE_D = 165 -MIPS_INS_C_NGT_D = 166 -MIPS_INS_CVT_S_W = 167 -MIPS_INS_CVT_D_W = 168 -MIPS_INS_CVT_S_L = 169 -MIPS_INS_CVT_D_L = 170 -MIPS_INS_BEQL = 171 -MIPS_INS_BNEL = 172 -MIPS_INS_BLEZL = 173 -MIPS_INS_BGTZL = 174 -MIPS_INS_DADDI = 175 -MIPS_INS_DADDIU = 176 -MIPS_INS_LDL = 177 -MIPS_INS_LDR = 178 -MIPS_INS_LB = 179 -MIPS_INS_LH = 180 -MIPS_INS_LWL = 181 -MIPS_INS_LW = 182 -MIPS_INS_LBU = 183 -MIPS_INS_LHU = 184 -MIPS_INS_LWR = 185 -MIPS_INS_LWU = 186 -MIPS_INS_SB = 187 -MIPS_INS_SH = 188 -MIPS_INS_SWL = 189 -MIPS_INS_SW = 190 -MIPS_INS_SDL = 191 -MIPS_INS_SDR = 192 -MIPS_INS_SWR = 193 -MIPS_INS_CACHE = 194 -MIPS_INS_LL = 195 -MIPS_INS_LWC1 = 196 -MIPS_INS_LLD = 197 -MIPS_INS_LDC1 = 198 -#MIPS_INS_INVALID = 199 -MIPS_INS_LD = 200 -MIPS_INS_SC = 201 -MIPS_INS_SWC1 = 202 -MIPS_INS_SCD = 203 -MIPS_INS_SDC1 = 204 -MIPS_INS_SD = 206 - -# Pseudo-Instruction Unique IDs -MIPS_INS_BEQZ = 207 -MIPS_INS_BNEZ = 208 -MIPS_INS_B = 209 -MIPS_INS_NOP = 210 -MIPS_INS_MOVE = 211 -MIPS_INS_NEGU = 212 -MIPS_INS_NOT = 213 - -# Invalid Instruction Unique ID -MIPS_INS_INVALID = -1 - -# Op IDs -# MIPS_OP_RS = 0 -# MIPS_OP_RT = 0 -# MIPS_OP_RD = 0 -# MIPS_OP_IMM = 0 - -# Register Names - -mips_gpr_names = [ - "$zero", - "$at", - "$v0", "$v1", - "$a0", "$a1", "$a2", "$a3", - "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", - "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", - "$t8", "$t9", - "$k0", "$k1", - "$gp", - "$sp", - "$fp", - "$ra", -] - -mips_cop0_names = [ - "Index" , "Random" , "EntryLo0" , "EntryLo1" , - "Context" , "PageMask" , "Wired" , "Reserved07", - "BadVaddr" , "Count" , "EntryHi" , "Compare" , - "Status" , "Cause" , "EPC" , "PRevID" , - "Config" , "LLAddr" , "WatchLo" , "WatchHi" , - "XContext" , "Reserved21", "Reserved22", "Reserved23", - "Reserved24", "Reserved25", "PErr" , "CacheErr" , - "TagLo" , "TagHi" , "ErrorEPC" , "Reserved31", -] - -numeric_fpr_names = [ - "$f0", "$f1", "$f2", "$f3", - "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", - "$f12", "$f13", "$f14", "$f15", - "$f16", "$f17", "$f18", "$f19", - "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", - "$31", # Floating-point control/status register -] - -o32_fpr_names = [ - "$fv0", "$fv0f", "$fv1", "$fv1f", - "$ft0", "$ft0f", "$ft1", "$ft1f", "$ft2", "$ft2f", "$ft3", "$ft3f", - "$fa0", "$fa0f", "$fa1", "$fa1f", - "$ft4", "$ft4f", "$ft5", "$ft5f", - "$fs0", "$fs0f", "$fs1", "$fs1f", "$fs2", "$fs2f", "$fs3", "$fs3f", "$fs4", "$fs4f", "$fs5", - "$31", # Floating-point control/status register -] - -mips_fpr_names = numeric_fpr_names - -# Instruction field fetching - -def sign_extend_16(value): - return (value & 0x7FFF) - (value & 0x8000) - -def mask_shift(v, s, w): - return (v >> s) & ((1 << w) - 1) - -mips_get_field = lambda raw,vaddr : mask_shift(raw, 26, 6) -mips_get_special = lambda raw,vaddr : mask_shift(raw, 0, 6) -mips_get_cop0 = lambda raw,vaddr : mask_shift(raw, 21, 5) -mips_get_cop1 = lambda raw,vaddr : mask_shift(raw, 21, 5) -mips_get_regimm = lambda raw,vaddr : mask_shift(raw, 16, 5) -mips_get_tlb = lambda raw,vaddr : mask_shift(raw, 0, 5) -mips_get_function = lambda raw,vaddr : mask_shift(raw, 0, 6) - -mips_get_cond = lambda raw,vaddr : mask_shift(raw, 0, 4) -mips_get_fc = lambda raw,vaddr : mask_shift(raw, 2, 2) -mips_get_fd = lambda raw,vaddr : mask_shift(raw, 6, 5) -mips_get_fs = lambda raw,vaddr : mask_shift(raw, 11, 5) -mips_get_ft = lambda raw,vaddr : mask_shift(raw, 16, 5) -mips_get_fmt = lambda raw,vaddr : mask_shift(raw, 21, 5) -mips_get_ndtf = lambda raw,vaddr : mask_shift(raw, 16, 2) - -mips_get_target = lambda raw,vaddr : (0x80000000 | (mask_shift(raw, 0, 26) << 2)) -mips_get_offset = lambda raw,vaddr : vaddr + 4 + sign_extend_16(mask_shift(raw, 0, 16)) * 4 -mips_get_imm = lambda raw,vaddr : mask_shift(raw, 0, 16) - -mips_get_base = lambda raw,vaddr : mask_shift(raw, 21, 5) - -mips_get_cd = lambda raw,vaddr : mask_shift(raw, 11, 5) - -mips_get_code = lambda raw,vaddr : (mask_shift(raw, 6, 20) << 6) >> 16 -mips_get_op = lambda raw,vaddr : mask_shift(raw, 16, 5) - -mips_get_sa = lambda raw,vaddr : mask_shift(raw, 6, 5) - -mips_get_rd = lambda raw,vaddr : mask_shift(raw, 11, 5) -mips_get_rs = lambda raw,vaddr : mask_shift(raw, 21, 5) -mips_get_rt = lambda raw,vaddr : mask_shift(raw, 16, 5) - -# Formatting - -class MipsInsn: - - def __init__(self, raw, vaddr, values): - self.raw = raw - self.vaddr = vaddr - - if values is None: - values = MIPS_INS_INVALID, f"/* Invalid Instruction: 0x{raw:08X} */", () - - self.id, self.mnemonic, self.fields = values - - self.code = self.sa = self.op = self.cd = self.rd = self.rs = self.rt = self.fd = self.fs = self.ft = self.imm = self.offset = self.base = self.target = None - - for field in self.fields: - self.value_forname(field) - - self.op_str = self.format_insn() - - if self.id == MIPS_INS_SLL and self.rd == MIPS_REG_R0 and self.rt == MIPS_REG_R0 and self.sa == 0: - self.id = MIPS_INS_NOP - self.mnemonic = "nop" - self.fields = () - elif self.id == MIPS_INS_BEQ and self.rs == MIPS_REG_R0 and self.rt == MIPS_REG_R0: - self.id = MIPS_INS_B - self.mnemonic = "b" - self.fields = ("offset",) - elif self.id == MIPS_INS_OR and self.rt == MIPS_REG_R0: - self.id = MIPS_INS_MOVE - self.mnemonic = "move" - self.fields = ("rd","rs") - elif self.id == MIPS_INS_BEQ and self.rt == MIPS_REG_R0: - self.id = MIPS_INS_BEQZ - self.mnemonic = "beqz" - self.fields = ("rs","offset") - elif self.id == MIPS_INS_BNE and self.rt == MIPS_REG_R0: - self.id = MIPS_INS_BNEZ - self.mnemonic = "bnez" - self.fields = ("rs","offset") - elif self.id == MIPS_INS_SUBU and self.rs == MIPS_REG_R0: - self.id = MIPS_INS_NEGU - self.mnemonic = "negu" - self.fields = ("rd","rt") - elif self.id == MIPS_INS_NOR and self.rt == MIPS_REG_R0: - self.id = MIPS_INS_NOT - self.mnemonic = "not" - self.fields = ("rd","rs") - - self.op_str = self.format_insn() - - def value_forname(self, name): - field_setters = { - 'code' : self.set_code, - 'sa' : self.set_sa, - 'op' : self.set_op, - 'cd' : self.set_cd, - 'rd' : self.set_rd, - 'rs' : self.set_rs, - 'rt' : self.set_rt, - 'fd' : self.set_fd, - 'fs' : self.set_fs, - 'ft' : self.set_ft, - 'imm' : self.set_imm, - 'offset' : self.set_offset, - 'base' : self.set_base, - 'offset(base)' : self.set_offset_base, - 'target' : self.set_target, - } - - return field_setters[name]() - - def format_field(self, field): - def format_hex(v, signed, zeros, no_zero): - if abs(v) < 10: - if v == 0 and no_zero: - return "" - return f"{v}" - elif not signed: - return f"0x{v:{f'0{zeros}' if zeros > 0 else ''}x}" - else: - return f"{v:#x}" - - format_handlers = { - 'code' : (lambda insn : f'{insn.code}' if insn.code != 0 else ''), - 'cd' : (lambda insn : mips_cop0_names[insn.cd]), - 'rd' : (lambda insn : mips_gpr_names[insn.rd]), - 'rs' : (lambda insn : mips_gpr_names[insn.rs]), - 'rt' : (lambda insn : mips_gpr_names[insn.rt]), - 'fd' : (lambda insn : mips_fpr_names[insn.fd]), - 'fs' : (lambda insn : mips_fpr_names[insn.fs]), - 'ft' : (lambda insn : mips_fpr_names[insn.ft]), - 'sa' : (lambda insn : format_hex(insn.sa, True, 0, False)), - 'op' : (lambda insn : format_hex(insn.op, False, 0, False)), - 'imm' : (lambda insn : format_hex(insn.imm, True, 0, False)), - 'offset(base)' : (lambda insn : f'{format_hex(insn.imm, True, 0, True)}({mips_gpr_names[insn.base]})'), - 'offset' : (lambda insn : f'{format_hex(insn.offset, True, 0, False)}'), - 'target' : (lambda insn : f'{format_hex(insn.target, False, 0, False)}') - } - - return format_handlers[field](self) - - def format_insn(self): - return ", ".join([self.format_field(field) for field in self.fields]) - - def __str__(self): - return f"{self.mnemonic:12}{self.op_str}" - - def set_code(self): - self.code = mips_get_code(self.raw, self.vaddr) - return self.code - - def set_sa(self): - self.sa = mips_get_sa(self.raw, self.vaddr) - return self.sa - - def set_op(self): - self.op = mips_get_op(self.raw, self.vaddr) - return self.op - - def set_cd(self): - self.cd = mips_get_cd(self.raw, self.vaddr) - return self.cd - - def set_rd(self): - self.rd = mips_get_rd(self.raw, self.vaddr) - return self.rd - - def set_rs(self): - self.rs = mips_get_rs(self.raw, self.vaddr) - return self.rs - - def set_rt(self): - self.rt = mips_get_rt(self.raw, self.vaddr) - return self.rt - - def set_fd(self): - self.fd = mips_get_fd(self.raw, self.vaddr) - return self.fd - - def set_fs(self): - self.fs = mips_get_fs(self.raw, self.vaddr) - return self.fs - - def set_ft(self): - self.ft = mips_get_ft(self.raw, self.vaddr) - return self.ft - - def set_imm(self): - do_sign_extend = [ MIPS_INS_ADDIU, MIPS_INS_SLTI, MIPS_INS_ADDI, MIPS_INS_DADDIU, - MIPS_INS_LB, MIPS_INS_LBU, - MIPS_INS_LH, MIPS_INS_LHU, - MIPS_INS_LW, MIPS_INS_LWL, MIPS_INS_LWR, MIPS_INS_LWU, - MIPS_INS_LWC1, - MIPS_INS_LD, MIPS_INS_LDL, MIPS_INS_LDR, - MIPS_INS_LDC1, - MIPS_INS_LL, MIPS_INS_LLD, - MIPS_INS_SB, - MIPS_INS_SH, - MIPS_INS_SW, MIPS_INS_SWL, MIPS_INS_SWR, - MIPS_INS_SWC1, - MIPS_INS_SD, MIPS_INS_SDL, MIPS_INS_SDR, - MIPS_INS_SDC1, - MIPS_INS_SC, MIPS_INS_SCD, - ] - - self.imm = mips_get_imm(self.raw, self.vaddr) - if self.id in do_sign_extend: # sign extended immediates - self.imm = sign_extend_16(self.imm) - return self.imm - - def set_offset(self): - self.offset = mips_get_offset(self.raw, self.vaddr) - return self.offset - - def set_base(self): - self.base = mips_get_base(self.raw, self.vaddr) - return self.base - - def set_offset_base(self): - self.set_imm() - self.set_base() - return self.imm, self.base - - def set_target(self): - self.target = mips_get_target(self.raw, self.vaddr) - return self.target - -def fetch_insn(raw, vaddr, insn_set, func): - insn = insn_set.get(func(raw, vaddr), None) # default none for invalid instruction encoding - - if insn is not None and type(insn[1]) == dict: # extra decoding required - insn = fetch_insn(raw, vaddr, insn[1], insn[0]) - return insn - -def decode_insn(raw, vaddr): - return MipsInsn(raw, vaddr, fetch_insn(raw, vaddr, mips_insns, mips_get_field)) - -mips_insns = { - 0b000000: (mips_get_special, { - 0b000000: (MIPS_INS_SLL, "sll", ("rd","rt","sa")), - 0b000010: (MIPS_INS_SRL, "srl", ("rd","rt","sa")), - 0b000011: (MIPS_INS_SRA, "sra", ("rd","rt","sa")), - 0b000100: (MIPS_INS_SLLV, "sllv", ("rd","rt","rs")), - 0b000110: (MIPS_INS_SRLV, "srlv", ("rd","rt","rs")), - 0b000111: (MIPS_INS_SRAV, "srav", ("rd","rt","rs")), - 0b001000: (MIPS_INS_JR, "jr", ("rs", )), - 0b001001: (MIPS_INS_JALR, "jalr", ("rs", )), # technically also rd but it's always $ra - 0b001100: (MIPS_INS_SYSCALL, "syscall", ( )), - 0b001101: (MIPS_INS_BREAK, "break", ("code", )), - 0b001111: (MIPS_INS_SYNC, "sync", ( )), - 0b010000: (MIPS_INS_MFHI, "mfhi", ("rd", )), - 0b010001: (MIPS_INS_MTHI, "mthi", ("rs", )), - 0b010010: (MIPS_INS_MFLO, "mflo", ("rd", )), - 0b010011: (MIPS_INS_MTLO, "mtlo", ("rs", )), - 0b010100: (MIPS_INS_DSLLV, "dsllv", ("rd","rt","rs")), - 0b010110: (MIPS_INS_DSRLV, "dsrlv", ("rd","rt","rs")), - 0b010111: (MIPS_INS_DSRAV, "dsrav", ("rd","rt","rs")), - 0b011000: (MIPS_INS_MULT, "mult", ("rs","rt" )), - 0b011001: (MIPS_INS_MULTU, "multu", ("rs","rt" )), - 0b011010: (MIPS_INS_DIV, "div", ("rd","rs","rt")), # for some reason gas hates div instructions - 0b011011: (MIPS_INS_DIVU, "divu", ("rd","rs","rt")), # with the correct number of operands - 0b011100: (MIPS_INS_DMULT, "dmult", ("rs","rt" )), - 0b011101: (MIPS_INS_DMULTU, "dmultu", ("rs","rt" )), - 0b011110: (MIPS_INS_DDIV, "ddiv", ("rd","rs","rt")), - 0b011111: (MIPS_INS_DDIVU, "ddivu", ("rd","rs","rt")), - 0b100000: (MIPS_INS_ADD, "add", ("rd","rs","rt")), - 0b100001: (MIPS_INS_ADDU, "addu", ("rd","rs","rt")), - 0b100010: (MIPS_INS_SUB, "sub", ("rd","rs","rt")), - 0b100011: (MIPS_INS_SUBU, "subu", ("rd","rs","rt")), - 0b100100: (MIPS_INS_AND, "and", ("rd","rs","rt")), - 0b100101: (MIPS_INS_OR, "or", ("rd","rs","rt")), - 0b100110: (MIPS_INS_XOR, "xor", ("rd","rs","rt")), - 0b100111: (MIPS_INS_NOR, "nor", ("rd","rs","rt")), - 0b101010: (MIPS_INS_SLT, "slt", ("rd","rs","rt")), - 0b101011: (MIPS_INS_SLTU, "sltu", ("rd","rs","rt")), - 0b101100: (MIPS_INS_DADD, "dadd", ("rd","rs","rt")), - 0b101101: (MIPS_INS_DADDU, "daddu", ("rd","rs","rt")), - 0b101110: (MIPS_INS_DSUB, "dsub", ("rd","rs","rt")), - 0b101111: (MIPS_INS_DSUBU, "dsubu", ("rd","rs","rt")), - 0b110000: (MIPS_INS_TGE, "tge", ("rs","rt" )), - 0b110001: (MIPS_INS_TGEU, "tgeu", ("rs","rt" )), - 0b110010: (MIPS_INS_TLT, "tlt", ("rs","rt" )), - 0b110011: (MIPS_INS_TLTU, "tltu", ("rs","rt" )), - 0b110100: (MIPS_INS_TEQ, "teq", ("rs","rt" )), - 0b110110: (MIPS_INS_TNE, "tne", ("rs","rt" )), - 0b111000: (MIPS_INS_DSLL, "dsll", ("rd","rt","sa")), - 0b111010: (MIPS_INS_DSRL, "dsrl", ("rd","rt","sa")), - 0b111011: (MIPS_INS_DSRA, "dsra", ("rd","rt","sa")), - 0b111100: (MIPS_INS_DSLL32, "dsll32", ("rd","rt","sa")), - 0b111110: (MIPS_INS_DSRL32, "dsrl32", ("rd","rt","sa")), - 0b111111: (MIPS_INS_DSRA32, "dsra32", ("rd","rt","sa")), - }), - 0b000001: (mips_get_regimm, { - 0b00000: (MIPS_INS_BLTZ, "bltz", ("rs","offset")), - 0b00001: (MIPS_INS_BGEZ, "bgez", ("rs","offset")), - 0b00010: (MIPS_INS_BLTZL, "bltzl", ("rs","offset")), - 0b00011: (MIPS_INS_BGEZL, "bgezl", ("rs","offset")), - 0b01000: (MIPS_INS_TGEI, "tgei", ("rs","imm" )), - 0b01001: (MIPS_INS_TGEIU, "tgeiu", ("rs","imm" )), - 0b01010: (MIPS_INS_TLTI, "tlti", ("rs","imm" )), - 0b01011: (MIPS_INS_TLTIU, "tltiu", ("rs","imm" )), - 0b01100: (MIPS_INS_TEQI, "teqi", ("rs","imm" )), - 0b01110: (MIPS_INS_TNEI, "tnei", ("rs","imm" )), - 0b10000: (MIPS_INS_BLTZAL, "bltzal", ("rs","offset")), - 0b10001: (MIPS_INS_BGEZAL, "bgezal", ("rs","offset")), - 0b10010: (MIPS_INS_BLTZALL, "bltzall", ("rs","offset")), - 0b10011: (MIPS_INS_BGEZALL, "bgezall", ("rs","offset")), - }), - 0b000010: (MIPS_INS_J, "j", ("target", )), - 0b000011: (MIPS_INS_JAL, "jal", ("target", )), - 0b000100: (MIPS_INS_BEQ, "beq", ("rs","rt","offset")), - 0b000101: (MIPS_INS_BNE, "bne", ("rs","rt","offset")), - 0b000110: (MIPS_INS_BLEZ, "blez", ("rs","offset" )), - 0b000111: (MIPS_INS_BGTZ, "bgtz", ("rs","offset" )), - 0b001000: (MIPS_INS_ADDI, "addi", ("rt","rs","imm" )), - 0b001001: (MIPS_INS_ADDIU, "addiu", ("rt","rs","imm" )), - 0b001010: (MIPS_INS_SLTI, "slti", ("rt","rs","imm" )), - 0b001011: (MIPS_INS_SLTIU, "sltiu", ("rt","rs","imm" )), - 0b001100: (MIPS_INS_ANDI, "andi", ("rt","rs","imm" )), - 0b001101: (MIPS_INS_ORI, "ori", ("rt","rs","imm" )), - 0b001110: (MIPS_INS_XORI, "xori", ("rt","rs","imm" )), - 0b001111: (MIPS_INS_LUI, "lui", ("rt","imm" )), - 0b010000: (mips_get_cop0, { - 0b00000: (MIPS_INS_MFC0, "mfc0", ("rt","cd")), - 0b00100: (MIPS_INS_MTC0, "mtc0", ("rt","cd")), - 0b10000: (mips_get_tlb, { - 0b000001: (MIPS_INS_TLBR, "tlbr", ()), - 0b000010: (MIPS_INS_TLBWI, "tlbwi", ()), - 0b000110: (MIPS_INS_TLBWR, "tlbwr", ()), - 0b001000: (MIPS_INS_TLBP, "tlbp", ()), - 0b011000: (MIPS_INS_ERET, "eret", ()), - }), - }), - 0b010001: (mips_get_cop1, { - 0b00000: (MIPS_INS_MFC1, "mfc1", ("rt","fs")), - 0b00001: (MIPS_INS_DMFC1, "dmfc1", ("rt","fs")), - 0b00010: (MIPS_INS_CFC1, "cfc1", ("rt","fs")), - 0b00100: (MIPS_INS_MTC1, "mtc1", ("rt","fs")), - 0b00101: (MIPS_INS_DMTC1, "dmtc1", ("rt","fs")), - 0b00110: (MIPS_INS_CTC1, "ctc1", ("rt","fs")), - 0b01000: (mips_get_ndtf, { - 0b00: (MIPS_INS_BC1F, "bc1f", ("offset",)), - 0b01: (MIPS_INS_BC1T, "bc1t", ("offset",)), - 0b10: (MIPS_INS_BC1FL, "bc1fl", ("offset",)), - 0b11: (MIPS_INS_BC1TL, "bc1tl", ("offset",)), - }), - 0b010000: (mips_get_function, { - 0b000000: (MIPS_INS_ADD_S, "add.s", ("fd","fs","ft")), - 0b000001: (MIPS_INS_SUB_S, "sub.s", ("fd","fs","ft")), - 0b000010: (MIPS_INS_MUL_S, "mul.s", ("fd","fs","ft")), - 0b000011: (MIPS_INS_DIV_S, "div.s", ("fd","fs","ft")), - 0b000100: (MIPS_INS_SQRT_S, "sqrt.s", ("fd","fs" )), - 0b000101: (MIPS_INS_ABS_S, "abs.s", ("fd","fs" )), - 0b000110: (MIPS_INS_MOV_S, "mov.s", ("fd","fs" )), - 0b000111: (MIPS_INS_NEG_S, "neg.s", ("fd","fs" )), - 0b001000: (MIPS_INS_ROUND_L_S, "round.l.s", ("fd","fs" )), - 0b001001: (MIPS_INS_TRUNC_L_S, "trunc.l.s", ("fd","fs" )), - 0b001010: (MIPS_INS_CEIL_L_S, "ceil.l.s", ("fd","fs" )), - 0b001011: (MIPS_INS_FLOOR_L_S, "floor.l.s", ("fd","fs" )), - 0b001100: (MIPS_INS_ROUND_W_S, "round.w.s", ("fd","fs" )), - 0b001101: (MIPS_INS_TRUNC_W_S, "trunc.w.s", ("fd","fs" )), - 0b001110: (MIPS_INS_CEIL_W_S, "ceil.w.s", ("fd","fs" )), - 0b001111: (MIPS_INS_FLOOR_W_S, "floor.w.s", ("fd","fs" )), - 0b100001: (MIPS_INS_CVT_D_S, "cvt.d.s", ("fd","fs" )), - 0b100100: (MIPS_INS_CVT_W_S, "cvt.w.s", ("fd","fs" )), - 0b100101: (MIPS_INS_CVT_L_S, "cvt.l.s", ("fd","fs" )), - 0b110000: (MIPS_INS_C_F_S, "c.f.s", ("fs","ft" )), - 0b110001: (MIPS_INS_C_UN_S, "c.un.s", ("fs","ft" )), - 0b110010: (MIPS_INS_C_EQ_S, "c.eq.s", ("fs","ft" )), - 0b110011: (MIPS_INS_C_UEQ_S, "c.ueq.s", ("fs","ft" )), - 0b110100: (MIPS_INS_C_OLT_S, "c.olt.s", ("fs","ft" )), - 0b110101: (MIPS_INS_C_ULT_S, "c.ult.s", ("fs","ft" )), - 0b110110: (MIPS_INS_C_OLE_S, "c.ole.s", ("fs","ft" )), - 0b110111: (MIPS_INS_C_ULE_S, "c.ule.s", ("fs","ft" )), - 0b111000: (MIPS_INS_C_SF_S, "c.sf.s", ("fs","ft" )), - 0b111001: (MIPS_INS_C_NGLE_S, "c.ngle.s", ("fs","ft" )), - 0b111010: (MIPS_INS_C_SEQ_S, "c.seq.s", ("fs","ft" )), - 0b111011: (MIPS_INS_C_NGL_S, "c.ngl.s", ("fs","ft" )), - 0b111100: (MIPS_INS_C_LT_S, "c.lt.s", ("fs","ft" )), - 0b111101: (MIPS_INS_C_NGE_S, "c.nge.s", ("fs","ft" )), - 0b111110: (MIPS_INS_C_LE_S, "c.le.s", ("fs","ft" )), - 0b111111: (MIPS_INS_C_NGT_S, "c.ngt.s", ("fs","ft" )), - }), - 0b010001: (mips_get_function, { - 0b000000: (MIPS_INS_ADD_D, "add.d", ("fd","fs","ft")), - 0b000001: (MIPS_INS_SUB_D, "sub.d", ("fd","fs","ft")), - 0b000010: (MIPS_INS_MUL_D, "mul.d", ("fd","fs","ft")), - 0b000011: (MIPS_INS_DIV_D, "div.d", ("fd","fs","ft")), - 0b000100: (MIPS_INS_SQRT_D, "sqrt.d", ("fd","fs" )), - 0b000101: (MIPS_INS_ABS_D, "abs.d", ("fd","fs" )), - 0b000110: (MIPS_INS_MOV_D, "mov.d", ("fd","fs" )), - 0b000111: (MIPS_INS_NEG_D, "neg.d", ("fd","fs" )), - 0b001000: (MIPS_INS_ROUND_L_D, "round.l.d", ("fd","fs" )), - 0b001001: (MIPS_INS_TRUNC_L_D, "trunc.l.d", ("fd","fs" )), - 0b001010: (MIPS_INS_CEIL_L_D, "ceil.l.d", ("fd","fs" )), - 0b001011: (MIPS_INS_FLOOR_L_D, "floor.l.d", ("fd","fs" )), - 0b001100: (MIPS_INS_ROUND_W_D, "round.w.d", ("fd","fs" )), - 0b001101: (MIPS_INS_TRUNC_W_D, "trunc.w.d", ("fd","fs" )), - 0b001110: (MIPS_INS_CEIL_W_D, "ceil.w.d", ("fd","fs" )), - 0b001111: (MIPS_INS_FLOOR_W_D, "floor.w.d", ("fd","fs" )), - 0b100000: (MIPS_INS_CVT_S_D, "cvt.s.d", ("fd","fs" )), - 0b100100: (MIPS_INS_CVT_W_D, "cvt.w.d", ("fd","fs" )), - 0b100101: (MIPS_INS_CVT_L_D, "cvt.l.d", ("fd","fs" )), - 0b110000: (MIPS_INS_C_F_D, "c.f.d", ("fs","ft" )), - 0b110001: (MIPS_INS_C_UN_D, "c.un.d", ("fs","ft" )), - 0b110010: (MIPS_INS_C_EQ_D, "c.eq.d", ("fs","ft" )), - 0b110011: (MIPS_INS_C_UEQ_D, "c.ueq.d", ("fs","ft" )), - 0b110100: (MIPS_INS_C_OLT_D, "c.olt.d", ("fs","ft" )), - 0b110101: (MIPS_INS_C_ULT_D, "c.ult.d", ("fs","ft" )), - 0b110110: (MIPS_INS_C_OLE_D, "c.ole.d", ("fs","ft" )), - 0b110111: (MIPS_INS_C_ULE_D, "c.ule.d", ("fs","ft" )), - 0b111000: (MIPS_INS_C_SF_D, "c.sf.d", ("fs","ft" )), - 0b111001: (MIPS_INS_C_NGLE_D, "c.ngle.d", ("fs","ft" )), - 0b111010: (MIPS_INS_C_SEQ_D, "c.seq.d", ("fs","ft" )), - 0b111011: (MIPS_INS_C_NGL_D, "c.ngl.d", ("fs","ft" )), - 0b111100: (MIPS_INS_C_LT_D, "c.lt.d", ("fs","ft" )), - 0b111101: (MIPS_INS_C_NGE_D, "c.nge.d", ("fs","ft" )), - 0b111110: (MIPS_INS_C_LE_D, "c.le.d", ("fs","ft" )), - 0b111111: (MIPS_INS_C_NGT_D, "c.ngt.d", ("fs","ft" )), - }), - 0b010100: (mips_get_function, { - 0b100000: (MIPS_INS_CVT_S_W, "cvt.s.w", ("fd","fs")), - 0b100001: (MIPS_INS_CVT_D_W, "cvt.d.w", ("fd","fs")), - }), - 0b010101: (mips_get_function, { - 0b100000: (MIPS_INS_CVT_S_L, "cvt.s.l", ("fd","fs")), - 0b100001: (MIPS_INS_CVT_D_L, "cvt.d.l", ("fd","fs")), - }), - }), - 0b010100: (MIPS_INS_BEQL, "beql", ("rs","rt","offset" )), - 0b010101: (MIPS_INS_BNEL, "bnel", ("rs","rt","offset" )), - 0b010110: (MIPS_INS_BLEZL, "blezl", ("rs","offset" )), - 0b010111: (MIPS_INS_BGTZL, "bgtzl", ("rs","offset" )), - 0b011000: (MIPS_INS_DADDI, "daddi", ("rt","rs","imm" )), - 0b011001: (MIPS_INS_DADDIU, "daddiu", ("rt","rs","imm" )), - 0b011010: (MIPS_INS_LDL, "ldl", ("rt","offset(base)")), - 0b011011: (MIPS_INS_LDR, "ldr", ("rt","offset(base)")), - 0b100000: (MIPS_INS_LB, "lb", ("rt","offset(base)")), - 0b100001: (MIPS_INS_LH, "lh", ("rt","offset(base)")), - 0b100010: (MIPS_INS_LWL, "lwl", ("rt","offset(base)")), - 0b100011: (MIPS_INS_LW, "lw", ("rt","offset(base)")), - 0b100100: (MIPS_INS_LBU, "lbu", ("rt","offset(base)")), - 0b100101: (MIPS_INS_LHU, "lhu", ("rt","offset(base)")), - 0b100110: (MIPS_INS_LWR, "lwr", ("rt","offset(base)")), - 0b100111: (MIPS_INS_LWU, "lwu", ("rt","offset(base)")), - 0b101000: (MIPS_INS_SB, "sb", ("rt","offset(base)")), - 0b101001: (MIPS_INS_SH, "sh", ("rt","offset(base)")), - 0b101010: (MIPS_INS_SWL, "swl", ("rt","offset(base)")), - 0b101011: (MIPS_INS_SW, "sw", ("rt","offset(base)")), - 0b101100: (MIPS_INS_SDL, "sdl", ("rt","offset(base)")), - 0b101101: (MIPS_INS_SDR, "sdr", ("rt","offset(base)")), - 0b101110: (MIPS_INS_SWR, "swr", ("rt","offset(base)")), - 0b101111: (MIPS_INS_CACHE, "cache", ("op","offset(base)")), - 0b110000: (MIPS_INS_LL, "ll", ("rt","offset(base)")), - 0b110001: (MIPS_INS_LWC1, "lwc1", ("ft","offset(base)")), - 0b110100: (MIPS_INS_LLD, "lld", ("rt","offset(base)")), - 0b110101: (MIPS_INS_LDC1, "ldc1", ("ft","offset(base)")), - # ldc2 - 0b110111: (MIPS_INS_LD, "ld", ("rt","offset(base)")), - 0b111000: (MIPS_INS_SC, "sc", ("rt","offset(base)")), - 0b111001: (MIPS_INS_SWC1, "swc1", ("ft","offset(base)")), - 0b111100: (MIPS_INS_SCD, "scd", ("rt","offset(base)")), - 0b111101: (MIPS_INS_SDC1, "sdc1", ("ft","offset(base)")), - # sdc2 - 0b111111: (MIPS_INS_SD, "sd", ("rt","offset(base)")), -}