Skip to content

Instantly share code, notes, and snippets.

@parasyte
Last active June 20, 2022 11:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save parasyte/f8fa1de4e7070048846a to your computer and use it in GitHub Desktop.
Save parasyte/f8fa1de4e7070048846a to your computer and use it in GitHub Desktop.
NEC VR43xx disassembler (MIPS R4300i; N64)
## MIPS R4300i disassembler
## Specifically: NEC VR43xx
## TODO: Split this file into a generic "mips.py" and specific "vr43xx.py"
## Even better! Split it into MIPS-I, MIPS-II, MIPS-III...
## TODO: New line after "branch and link" instructions
## TODO: Turn addi/addiu/ori into li
## TODO: any instruction with destination $zero = nop (MUST NOT HAVE SIDE-EFFECTS; ll/lld have side-effects)
## TODO: compact multiple instructions. eg. lui/ori -> la, mul/mflo -> mult ...
## TODO: swap operands for mtcz instruction; destination should be on the left! FTM!!
## TODO: Make pseudo-ops configurable (on/off)
def fmt_r(inst):
"""
Instruction format R (Register)
opcode (6) | rs (5) | rt (5) | rd (5) | sh (5) | funct (6)
"""
opcode = (inst >> 26) & 0x0000003F
rs = (inst >> 21) & 0x0000001F
rt = (inst >> 16) & 0x0000001F
rd = (inst >> 11) & 0x0000001F
sh = (inst >> 6) & 0x0000001F
funct = (inst >> 0) & 0x0000003F
return (opcode, rs, rt, rd, sh, funct)
def fmt_i(inst):
"""
Instruction format I (Immediate)
opcode (6) | rs (5) | rt (5) | imm (16)
"""
opcode = (inst >> 26) & 0x0000003F
rs = (inst >> 21) & 0x0000001F
rt = (inst >> 16) & 0x0000001F
imm = (inst >> 0) & 0x0000FFFF
return (opcode, rs, rt, imm)
def fmt_j(inst):
"""
Instruction format J (Jump)
opcode (6) | addr (26)
"""
opcode = (inst >> 26) & 0x0000003F
addr = (inst >> 0) & 0x03FFFFFF
return (opcode, addr)
def sign_ext(imm):
return -(0x10000 - imm) if (imm & 0x8000) else imm
def mask32(imm):
return imm & 0xFFFFFFFF
def branch_target(pc, imm):
return mask32(pc + (sign_ext(imm) << 2))
def jump_target(pc, addr):
return (pc & 0xF0000000) | (addr << 2)
"""
General Purpose Registers LUT
"""
gpr = (
"$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",
)
"""
CoProcessor Registers LUT
"""
cpr = (
## cp0 (System CoProcessor)
(
"Index", "Random", "EntryLo0", "EntryLo1",
"Context", "PageMask", "Wired", None,
"BadVAddr", "Count", "EntryHi", "Compare",
"Status", "Cause", "EPC", "PRId",
"Config", "LLAddr", "WatchLo", "WatchHi",
"XContext", None, None, None,
None, None, "PErr", "CacheErr",
"TagLo", "TagHi", "ErrorEPC", None,
),
## cp1 (FPU)
(
"fpr0", "fpr1", "fpr2", "fpr3", "fpr4", "fpr5", "fpr6", "fpr7",
"fpr8", "fpr9", "fpr10", "fpr11", "fpr12", "fpr13", "fpr14", "fpr15",
"fpr16", "fpr17", "fpr18", "fpr19", "fpr20", "fpr21", "fpr22", "fpr23",
"fpr24", "fpr25", "fpr26", "fpr27", "fpr28", "fpr29", "fpr30", "fpr31",
),
## cp2 (N/A)
)
"""
CoProcessor Control Registers LUT
"""
cpcr = (
## cp1 (FPU)
(
"fcr0", None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, "fcsr",
),
## cp2 (N/A)
)
def dw(inst):
"""
Fall-back decoder function
Returns instruction as a data word
"""
return ".dw 0x{inst:08X}".format(
inst=inst
)
"""
Opcode decoder functions
"""
def o_cp(pc, inst):
(opcode, rs, rt, rd, sh, funct) = fmt_r(inst)
cp = (opcode & 3)
assert cp <= 1
if rs == 8:
(opcode, rs, rt, imm) = fmt_i(inst)
return cp_bc(pc, cp, rs, rt, imm)
if rs & 0x10:
return cp_functs[cp][funct](rs, rt, rd, sh, funct)
return cp_opcodes[rs](cp, rs, rt, rd, sh, funct)
def o_regimm(pc, inst):
(opcode, rs, rt, imm) = fmt_i(inst)
return branches[rt](pc, rs, rt, imm)
def o_special(pc, inst):
(opcode, rs, rt, rd, sh, funct) = fmt_r(inst)
return functs[funct](rs, rt, rd, sh, funct)
def o_addi(pc, inst):
(opcode, rs, rt, imm) = fmt_i(inst)
mnemonics = (
"addi", # 001000, daddi 011000
"addiu", # 001001, daddiu 011001
"slti", # 001010
"sltiu", # 001011
"andi", # 001100
"ori", # 001101
"xori", # 001110
)
if (opcode in ( 0x08, 0x09, 0x0D )) and (imm == 0):
if rt == rs:
return "nop"
return "move {rt:s}, {rs:s}".format(
rt=gpr[rt],
rs=gpr[rs]
)
return "{mnemonic: <6s} {rt:s}, {rs:s}, 0x{imm:04X}".format(
mnemonic=("d" if (opcode & 0x10) else "") + mnemonics[opcode & 7],
rt=gpr[rt],
rs=gpr[rs],
imm=imm
)
def o_b(pc, inst):
(opcode, rs, rt, imm) = fmt_i(inst)
mnemonics = (
"beq", # 000100, beql 010100
"bne", # 000101, bnel 010101
"blez", # 000110, blezl 010110
"bgtz", # 000111, bgtzl 010111
)
target = branch_target(pc, imm)
if (opcode == 4) and (rs == 0) and (rt == 0):
return "b 0x{target:08X}".format(
target=target
)
if (rs == 0 or rt == 0):
return "{mnemonic: <7s} {rs:s}, 0x{target:08X}".format(
mnemonic=mnemonics[opcode & 3] +
("z" if (opcode & 3) < 2 else "") +
("l" if (opcode >> 4) else ""),
rs=gpr[rt if (rs == 0) else rs],
target=target
)
return "{mnemonic: <7s} {rs:s}, {rt:s}, 0x{target:08X}".format(
mnemonic=mnemonics[opcode & 3] + ("l" if (opcode >> 4) else ""),
rs=gpr[rs],
rt=gpr[rt],
target=target,
)
def o_cache(pc, inst):
(opcode, rs, rt, imm) = fmt_i(inst)
assert (rt & 2) == 0
assert (rt >> 2) < 7
assert rt != 0x0C
operations = (
"Index_Invalidate", # 00000
"Index_Write_Back_Invalidate", # 00001
"Index_Load_Tag_I", # 00100
"Index_Load_Tag_D", # 00101
"Index_Store_Tag_I", # 01000
"Index_Store_Tag_D", # 01001
None, # 01100
"Create_Dirty_Exclusive", # 01101
"Hit_Invalidate_I", # 10000
"Hit_Invalidate_D", # 10001
"Fill", # 10100
"Hit_Write_Back_Invalidate", # 10101
"Hit_Write_Back_I", # 11000
"Hit_Write_Back_D", # 11001
)
return "cache {op:s}, 0x{offset:04X}({base:s})".format(
op=operations[(rt >> 1) | (rt & 1)],
offset=imm,
base=gpr[rs]
)
def o_j(pc, inst):
(opcode, addr) = fmt_j(inst)
return "{mnemonic: <3s} 0x{target:08X}".format(
mnemonic="j" + ("al" if (opcode & 1) else ""),
target=jump_target(pc, addr)
)
def o_lui(pc, inst):
(opcode, rs, rt, imm) = fmt_i(inst)
assert rs == 0
return "lui {rt:s}, 0x{imm:04X}".format(
rt=gpr[rt],
imm=imm
)
def o_loadstore(pc, inst):
(opcode, rs, rt, imm) = fmt_i(inst)
mnemonics = (
"lb", # 100000
"lh", # 100001
"lwl", # 100010
"lw", # 100011
"lbu", # 100100
"lhu", # 100101
"lwr", # 100110
"lwu", # 100111
"sb", # 101000
"sh", # 101001
"swl", # 101010
"sw", # 101011
"sdl", # 101100
"sdr", # 101101
"swr", # 101110
)
mnemonics_ll = (
"ll", # 110000
"lld", # 110100
"sc", # 111000
"scd", # 111100
)
if opcode & 0x10:
if opcode & 3:
if opcode & 4:
mnemonic = ("sd" if (opcode & 8) else "ld")
else:
mnemonic = ("ldr" if (opcode & 1) else "ldl")
else:
mnemonic = mnemonics_ll[(opcode >> 2) & 3]
else:
mnemonic = mnemonics[opcode & 0x0F]
return "{mnemonic: <3s} {rt:s}, 0x{offset:04X}({base:s})".format(
mnemonic=mnemonic,
rt=gpr[rt],
offset=imm,
base=gpr[rs]
)
def o_loadstore_cp(pc, inst):
(opcode, rs, rt, imm) = fmt_i(inst)
return "{mnemonic:s} {rt:s}, 0x{offset:04X}({base:s})".format(
mnemonic=("s" if (opcode & 8) else "l") + ("d" if (opcode & 4) else "w") + "c1",
rt=cpr[1][rt],
offset=imm,
base=gpr[rs]
)
"""
Opcodes LUT
Use 'opcode' to look up decoder function
"""
opcodes = (
o_special, # 000000
o_regimm, # 000001
o_j, # 000010, j
o_j, # 000011, jal
o_b, # 000100, beq
o_b, # 000101, bne
o_b, # 000110, blez
o_b, # 000111, bgtz
o_addi, # 001000, addi
o_addi, # 001001, addiu
o_addi, # 001010, slti
o_addi, # 001011, sltiu
o_addi, # 001100, andi
o_addi, # 001101, ori
o_addi, # 001110, xori
o_lui, # 001111
o_cp, # 010000, cp0
o_cp, # 010001, cp1
None, # 010010, cp2 N/A
None, # 010011, cp3 N/A
o_b, # 010100, beql
o_b, # 010101, bnel
o_b, # 010110, blezl
o_b, # 010111, bgtzl
o_addi, # 011000, daddi
o_addi, # 011001, daddiu
o_loadstore, # 011010, ldl
o_loadstore, # 011011, ldr
None, # 011100
None, # 011101
None, # 011110
None, # 011111
o_loadstore, # 100000, lb
o_loadstore, # 100001, lh
o_loadstore, # 100010, lwl
o_loadstore, # 100011, lw
o_loadstore, # 100100, lbu
o_loadstore, # 100101, lhu
o_loadstore, # 100110, lwr
o_loadstore, # 100111, lwu
o_loadstore, # 101000, sb
o_loadstore, # 101001, sh
o_loadstore, # 101010, swl
o_loadstore, # 101011, sw
o_loadstore, # 101100, sdl
o_loadstore, # 101101, sdr
o_loadstore, # 101110, swr
o_cache, # 101111
o_loadstore, # 110000, ll
o_loadstore_cp, # 110001, lwc1
None, # 110010, lwc2 N/A
None, # 110011
o_loadstore, # 110100, lld
o_loadstore_cp, # 110101, ldc1
None, # 110110, ldc2 N/A
o_loadstore, # 110111, ld
o_loadstore, # 111000, sc
o_loadstore_cp, # 111001, swc1
None, # 111010, swc2 N/A
None, # 111011
o_loadstore, # 111100 scd
o_loadstore_cp, # 111101, sdc1
None, # 111110, sdc2 N/A
o_loadstore, # 111111, sd
)
"""
CoProcessor Opcode decoder functions
"""
def cp_bc(pc, cp, rs, rt, imm):
assert rt <= 3
return "{mnemonic: <5s} 0x{target:08X}".format(
mnemonic="bc" + str(cp) + ("t" if (rt & 1) else "f") + ("l" if (rt & 2) else ""),
target=branch_target(pc, imm)
)
def cp_cc(cp, rs, rt, rd, sh, funct):
assert sh == 0
assert funct == 0
assert cp >= 1
assert cpcr[cp - 1][rd] is not None
return "{mnemonic: <5s} {rt:s}, {rd:s}".format(
mnemonic=("ctc" if (rs & 4) else "cfc") + str(cp),
rt=gpr[rt],
rd=cpcr[cp - 1][rd]
)
def cp_mfc(cp, rs, rt, rd, sh, funct):
assert sh == 0
assert funct == 0
assert cpr[cp][rd] is not None
return "{mnemonic: <5s} {rt:s}, {rd:s}".format(
mnemonic=("d" if (rs & 1) else "") + "mfc" + str(cp),
rt=gpr[rt],
rd=cpr[cp][rd]
)
"""
cp_mtc() swaps the register order (opposed to the MIPS spec)
It makes more sense to have this instruction left-handed, like all others.
"""
def cp_mtc(cp, rs, rt, rd, sh, funct):
assert sh == 0
assert funct == 0
assert cpr[cp][rd] is not None
return "{mnemonic: <5s} {rd:s}, {rt:s}".format(
mnemonic=("d" if (rs & 1) else "") + "mtc" + str(cp),
rd=cpr[cp][rd],
rt=gpr[rt]
)
"""
CoProcessor Opcodes LUT
Use 'rs' to lookup secondary decoder function
"""
cp_opcodes = (
cp_mfc, # 00000, mfc
cp_mfc, # 00001, dmfc
cp_cc, # 00010, cfc
None, # 00011
cp_mtc, # 00100, mtc
cp_mtc, # 00101, dmtc
cp_cc, # 00110, ctc
None, # 00111
cp_bc, # 01000
)
"""
CoProcessor 0 Function decoder functions
"""
def cp0(rs, rt, rd, sh, funct):
assert rs == 0x10
assert rt == 0
assert rd == 0
assert sh == 0
mnemonics = {
'1' : "tlbr",
'2' : "tlbwi",
'6' : "tlbwr",
'8' : "tlbp",
'24' : "eret"
}
return mnemonics[str(funct)]
"""
CoProcessor 1 format LUT
"""
cp1_fmt = (
"s", # 10000
"d", # 10001
None, # 10010
None, # 10011
"w", # 10100
"l", # 10101
)
"""
CoProcessor 1 decoder functions
"""
def cp1_add(fmt, ft, fs, fd, funct):
assert fmt in ( 0x10, 0x11 )
mnemonics = (
"add.", # 000000
"sub.", # 000001
"mul.", # 000010
"div.", # 000011
)
return "{mnemonic:s} {fd:s}, {fs:s}, {ft:s}".format(
mnemonic=mnemonics[funct] + cp1_fmt[fmt & 1],
fd=cpr[1][fd],
fs=cpr[1][fs],
ft=cpr[1][ft]
)
def cp1_c(fmt, ft, fs, fd, funct):
assert fmt in ( 0x10, 0x11 )
assert fd == 0
conds = (
"f", # 0000, False
"un", # 0001, Unordered
"eq", # 0010, Equal
"ueq", # 0011, Unordered or Equal
"olt", # 0100, Ordered or Less Than
"ult", # 0101, Unordered or Less Than
"ole", # 0110, Ordered or Less or Equal
"ule", # 0111, Unordered or Less Or Equal
"sf", # 1000, Signaling False
"ngle", # 1001, Not Greater or Less or Equal
"seq", # 1010, Signaling Equal
"ngl", # 1011, Not Greater or Less
"lt", # 1100, Less Than
"nge", # 1101, Not Greater or Equal
"le", # 1110, Less or Equal
"ngt", # 1111, Not Greater Than
)
return "{mnemonic: <8s} {fs:s}, {ft:s}".format(
mnemonic="c." + conds[funct & 0x0F] + "." + cp1_fmt[fmt & 1],
fs=cpr[1][fs],
ft=cpr[1][ft]
)
def cp1_cvt(fmt, ft, fs, fd, funct):
assert fmt in ( 0x10, 0x11, 0x14, 0x15 )
assert ft == 0
mnemonics = (
"round.", # 001000
"trunc.", # 001001
"ceil.", # 001010
"floor.", # 001011
)
if funct & 0x20:
if (funct & 7) >= 2:
assert fmt in ( 0x10, 0x11 )
assert (funct & 7) in ( 0, 1, 4, 5 )
mnemonic = "cvt." + cp1_fmt[funct & 7]
else:
assert fmt in ( 0x10, 0x11 )
mnemonic = mnemonics[funct & 3] + ("w." if (funct & 4) else "l.") + cp1_fmt[fmt & 1]
return "{mnemonic: <9} {fd:s}, {fs:s}".format(
mnemonic=mnemonic,
fd=cpr[1][fd],
fs=cpr[1][fs]
)
def cp1_mov(fmt, ft, fs, fd, funct):
assert fmt in ( 0x10, 0x11 )
assert ft == 0
mnemonics = (
"sqrt.", # 000100
"abs.", # 000101
"mov.", # 000110
"neg.", # 000111
)
return "{mnemonic:s} {fd:s}, {fs:s}".format(
mnemonic=mnemonics[funct & 3] + cp1_fmt[fmt & 1],
fd=cpr[1][fd],
fs=cpr[1][fs]
)
"""
CoProcessor Functions LUT
Use 'funct' to lookup function decoder function
"""
cp_functs = (
## CoProcessor 0
(
None, # 000000
cp0, # 000001, tlbr
cp0, # 000010, tlbwi
None, # 000011
None, # 000100
None, # 000101
cp0, # 000110, tlbwr
None, # 000111
cp0, # 001000, tlbp
None, # 001001
None, # 001010
None, # 001011
None, # 001100
None, # 001101
None, # 001110
None, # 001111
None, # 010000
None, # 010001
None, # 010010
None, # 010011
None, # 010100
None, # 010101
None, # 010110
None, # 010111
cp0, # 011000, eret
),
## CoProcessor 1
(
cp1_add, # 000000, add
cp1_add, # 000001, sub
cp1_add, # 000010, mul
cp1_add, # 000011, div
cp1_mov, # 000100, sqrt
cp1_mov, # 000101, abs
cp1_mov, # 000110, mov
cp1_mov, # 000111, neg
cp1_cvt, # 001000, round.l
cp1_cvt, # 001001, trunc.l
cp1_cvt, # 001010, ceil.l
cp1_cvt, # 001011, floor.l
cp1_cvt, # 001100, round.w
cp1_cvt, # 001101, trunc.w
cp1_cvt, # 001110, ceil.w
cp1_cvt, # 001111, floor.w
None, # 010000
None, # 010001
None, # 010010
None, # 010011
None, # 010100
None, # 010101
None, # 010110
None, # 010111
None, # 011000
None, # 011001
None, # 011010
None, # 011011
None, # 011100
None, # 011101
None, # 011110
None, # 011111
cp1_cvt, # 100000, cvt.s
cp1_cvt, # 100001, cvt.d
None, # 100010
None, # 100011
cp1_cvt, # 100100, cvt.w
cp1_cvt, # 100101, cvt.l
None, # 100110
None, # 100111
None, # 101000
None, # 101001
None, # 101010
None, # 101011
None, # 101100
None, # 101101
None, # 101110
None, # 101111
cp1_c, # 110000, c.f
cp1_c, # 110001, c.un
cp1_c, # 110010, c.eq
cp1_c, # 110011, c.ueq
cp1_c, # 110100, c.olt
cp1_c, # 110101, c.ult
cp1_c, # 110110, c.ole
cp1_c, # 110111, c.ule
cp1_c, # 111000, c.sf
cp1_c, # 111001, c.ngle
cp1_c, # 111010, c.seq
cp1_c, # 111011, c.ngl
cp1_c, # 111100, c.lt
cp1_c, # 111101, c.gne
cp1_c, # 111110, c.le
cp1_c, # 111111, c.ngt
),
)
"""
Special Function decoder functions
"""
def f_add(rs, rt, rd, sh, funct):
assert sh == 0
mnemonics = (
"add", # 100000, dadd 101100
"addu", # 100001, daddu 101101
"sub", # 100010, dsub 101110
"subu", # 100011, dsubu 101111
"and", # 100100
"or", # 100101
"xor", # 100110
"nor", # 100111
)
if (funct in ( 0x20, 0x21, 0x25 )) and ((rt == 0) or (rs == 0)):
if rd == (rs if (rt == 0) else rt):
return "nop"
return "move {rd:s}, {rs:s}".format(
rd=gpr[rd],
rs=gpr[rs if (rt == 0) else rt]
)
if funct & 8:
mnemonic = "d" + mnemonics[funct & 3]
else:
mnemonic = mnemonics[funct & 7]
return "{mnemonic: <5s} {rd:s}, {rs:s}, {rt:s}".format(
mnemonic=mnemonic,
rd=gpr[rd],
rs=gpr[rs],
rt=gpr[rt]
)
def f_jalr(rs, rt, rd, sh, funct):
assert rt == 0
assert sh == 0
if rd == 31:
return "jalr {rs:s}".format(
rs=gpr[rs]
)
return "jalr {rd:s}, {rs:s}".format(
rd=gpr[rd],
rs=gpr[rs]
)
def f_jr(rs, rt, rd, sh, funct):
assert rt == 0
assert rd == 0
assert sh == 0
return "jr {rs:s}".format(
rs=gpr[rs]
)
def f_mfhilo(rs, rt, rd, sh, funct):
assert rs == 0
assert rt == 0
assert sh == 0
return "{mnemonic:s} {rd:s}".format(
mnemonic="mf" + ("lo" if (funct & 2) else "hi"),
rd=gpr[rd]
)
def f_mthilo(rs, rt, rd, sh, funct):
assert rt == 0
assert rd == 0
assert sh == 0
return "{mnemonic:s} {rd:s}".format(
mnemonic="mt" + ("lo" if (funct & 2) else "hi"),
rd=gpr[rs]
)
def f_mult(rs, rt, rd, sh, funct):
assert rd == 0
assert sh == 0
return "{mnemonic: <6s} {rs:s}, {rt:s}".format(
mnemonic=("d" if (funct & 4) else "") + ("div" if (funct & 2) else "mult") + ("u" if (funct & 1) else ""),
rs=gpr[rs],
rt=gpr[rt]
)
def f_sll(rs, rt, rd, sh, funct):
assert rs == 0
if (rt == 0) and (rd == 0) and (sh == 0) and (funct == 0):
return "nop"
mnemonics = (
"sll", # 000000, dsll 111000, dsll32 111100
None, # 000001
"srl", # 000010, dsrl 111010, dsrl32 111110
"sra", # 000011, dsra 111011, dsra32 111111
)
if funct & 4:
sh += 32
return "{mnemonic: <6s} {rd:s}, {rt:s}, {sh:d}".format(
mnemonic=("d" if (funct & 0x10) else "") + mnemonics[funct & 3] + ("32" if (funct & 4) else ""),
rd=gpr[rd],
rt=gpr[rt],
sh=sh
)
def f_sllv(rs, rt, rd, sh, funct):
assert sh == 0
mnemonics = (
"sllv", # 000100, dsllv 010100
None, # 000101
"srlv", # 000110, dsrlv 010110
"srav", # 000111, dsrav 010111
)
if funct & 8:
mnemonic = "slt" + ("u" if (funct & 1) else "")
else:
mnemonic = ("d" if (funct & 0x10) else "") + mnemonics[funct & 3]
return "{mnemonic: <5s} {rd:s}, {rt:s}, {rs:s}".format(
mnemonic=mnemonic,
rd=gpr[rd],
rt=gpr[rt],
rs=gpr[rs]
)
def f_sync(rs, rt, rd, sh, funct):
assert rs == 0
assert rt == 0
assert rd == 0
assert sh == 0
return "sync"
def f_syscall(rs, rt, rd, sh, funct):
return "{mnemonic: <7s} 0x{code:05X}".format(
mnemonic=("break" if (funct & 1) else "syscall"),
code=(rs << 15) | (rt << 10) | (rd << 5) | sh
)
def f_trap(rs, rt, rd, sh, funct):
mnemonics = (
"tgeu", # 110001
"tlt", # 110010
"tltu", # 110011
"teq", # 110100
"tge", # 110101
"tne", # 110110
)
return "{mnemonic: <4s} {rs:s}, {rt:s}, 0x{code:03X}".format(
mnemonic=mnemonics[funct - 1],
rs=gpr[rs],
rt=gpr[rt],
code=(rd << 5) | sh
)
"""
Special Functions LUT
Use 'funct' portion of Format R instruction to look up function decoder function
"""
functs = (
f_sll, # 000000, sll
None, # 000001
f_sll, # 000010, srl
f_sll, # 000011, sra
f_sllv, # 000100, sllv
None, # 000101
f_sllv, # 000110, srlv
f_sllv, # 000111, srav
f_jr, # 001000
f_jalr, # 001001
None, # 001010
None, # 001011
f_syscall, # 001100, syscall
f_syscall, # 001101, break
None, # 001110
f_sync, # 001111
f_mfhilo, # 010000, mfhi
f_mthilo, # 010001, mthi
f_mfhilo, # 010010, mflo
f_mthilo, # 010011, mtlo
f_sllv, # 010100, dsllv
None, # 010101
f_sllv, # 010110, dsrlv
f_sllv, # 010111, dsrav
f_mult, # 011000, mult
f_mult, # 011001, multu
f_mult, # 011010, div
f_mult, # 011011, divu
f_mult, # 011100, dmult
f_mult, # 011101, dmultu
f_mult, # 011110, ddiv
f_mult, # 011111, ddivu
f_add, # 100000, add
f_add, # 100001, addu
f_add, # 100010, sub
f_add, # 100011, subu
f_add, # 100100, and
f_add, # 100101, or
f_add, # 100110, xor
f_add, # 100111, nor
None, # 101000
None, # 101001
f_sllv, # 101010, slt
f_sllv, # 101011, sltu
f_add, # 101100, dadd
f_add, # 101101, daddu
f_add, # 101110, dsub
f_add, # 101111, dsubu
None, # 110000
f_trap, # 110001, tgeu
f_trap, # 110010, tlt
f_trap, # 110011, tltu
f_trap, # 110100, teq
f_trap, # 110101, tge
f_trap, # 110110, tne
None, # 110111
f_sll, # 111000, dsll
None, # 111001
f_sll, # 111010, dsrl
f_sll, # 111011, dsra
f_sll, # 111100, dsll32
None, # 111101
f_sll, # 111110, dsrl32
f_sll, # 111111, dsra32
)
"""
Branch/Trap decoder functions
"""
def b_bz(pc, rs, rt, imm):
if (rt == 0x11) and (rs == 0):
return "bal 0x{target:08X}".format(
target=branch_target(pc, imm)
)
return "{mnemonic: <7s} {rs:s}, 0x{target:08X}".format(
mnemonic="b" + ("gez" if (rt & 1) else "ltz") + ("al" if (rt & 0x10) else "") + ("l" if (rt & 2) else ""),
rs=gpr[rs],
target=branch_target(pc, imm)
)
def b_trap(pc, rs, rt, imm):
mnemonics = (
"tgei", # 01000
"tgeiu", # 01001
"tlti", # 01010
"tltiu", # 01011
"teqi", # 01100
None, # 01101
"tnei", # 01110
)
return "{mnemonic: <5s} {rs:s}, 0x{imm:04X}".format(
mnemonic=mnemonics[rt & 7],
rs=gpr[rs],
imm=imm
)
"""
Branch/Trap LUT
Use 'rt' portion of Format I instruction to look up secondary decoder function
"""
branches = (
b_bz, # 00000, bltz
b_bz, # 00001, bgez
b_bz, # 00010, bltzl
b_bz, # 00011, bgezl
None, # 00100
None, # 00101
None, # 00110
None, # 00111
b_trap, # 01000, tgei
b_trap, # 01001, tgeiu
b_trap, # 01010, tlti
b_trap, # 01011, tltiu
b_trap, # 01100, teqi
None, # 01101
b_trap, # 01110, tnei
None, # 01111
b_bz, # 10000, bltzal
b_bz, # 10001, bgezal
b_bz, # 10010, bltzall
b_bz, # 10011, bgezall
)
if __name__ == "__main__":
import struct
import sys
if len(sys.argv) <= 1:
print("Usage: python {:s} <file> [address]".format(sys.argv[0]))
sys.exit(1)
fp = open(sys.argv[1], mode="rb")
data = fp.read()
fp.close()
data = struct.unpack(">" + ("L" * int(len(data) / 4)), data)
if len(sys.argv) >= 3:
pc = int(sys.argv[2], 16)
else:
pc = 0x80000000
jr = 0
for inst in data:
(opcode, rs, rt, rd, sh, funct) = fmt_r(inst)
## Print address and data
print("{:08X}: {:02X} {:02X} {:02X} {:02X} ".format(
pc,
(inst >> 24) & 0xFF,
(inst >> 16) & 0xFF,
(inst >> 8) & 0xFF,
(inst >> 0) & 0xFF
), end="")
## Print instruction
try:
print(opcodes[opcode](pc + 4, inst))
except:
print(dw(inst))
def is_jr():
return (
(opcode == 0) and
(rt == 0) and
(rd == 0) and
(sh == 0) and
(funct == 8)
)
def is_jalr():
return (
(opcode == 0) and
(rt == 0) and
(sh == 0) and
(funct == 9)
)
def is_eret():
return (
(opcode == 0x10) and
(rs == 0x10) and
(rt == 0) and
(rd == 0) and
(sh == 0) and
(funct == 0x18)
)
## Keep track of jr/jalr instructions
if is_jr() or is_jalr():
jr = pc
## eret instructions do not have a delay slot
if is_eret():
jr = pc - 4
## And print a blank line if the previous instruction was jr/jalr/eret
if (pc - 4) == jr:
print()
pc += 4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment