summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnghelo Carvajal <angheloalf95@gmail.com>2022-07-11 20:13:14 -0400
committerGitHub <noreply@github.com>2022-07-11 20:13:14 -0400
commit54957f8735051610ba97d40467dd008fa1870ca2 (patch)
treecc3f0185e1f5e38aca6d3a62264214058e9cce95
parent45eed680d613642bc3e1591f95902f6d57e0f8e6 (diff)
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 <hensley.derek58@gmail.com> * a * Don't use $FpcCsr Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com> Co-authored-by: Derek Hensley <hensley.derek58@gmail.com>
-rw-r--r--Jenkinsfile6
-rw-r--r--requirements.txt13
-rwxr-xr-xtools/disasm/disasm.py648
-rw-r--r--tools/disasm/mips_isa.py776
4 files changed, 252 insertions, 1191 deletions
diff --git a/Jenkinsfile b/Jenkinsfile
index fb60f0aca..29c3721b2 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 d76027c1c..d410bc853 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 cb634d138..3133f4327 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)
-
- 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
+ insn = rabbitizer.Instruction(raw_insn, vram=vram + i * 4)
+
+ 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 += " "
+
+ disassembled = insn.disassemble(
+ immOverride=getImmOverride(insn), extraLJust=extraLJust
+ )
+ result += f"{comment} {disassembled}\n"
- result += f"/* {i:06X} {vaddr:08X} {raw_insn:08X} */ {mnemonic:12}{op_str}\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 337bbd021..000000000
--- 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)")),
-}