/* Code HIGHLY ripped off^W^W inspired from PCSX. */ enum registers { Rzr, Rat, Rv0, Rv1, Ra0, Ra1, Ra2, Ra3, Rt0, Rt1, Rt2, Rt3, Rt4, Rt5, Rt6, Rt7, Rs0, Rs1, Rs2, Rs3, Rs4, Rs5, Rs6, Rs7, Rt8, Rt9, Rk0, Rk1, Rgp, Rsp, Rfp, Rra, Rhi, Rlo, }; char * GPRregisters[] = { "0", "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", "hi", "lo", }; char * CP0registers[] = { "Index" , "Random" , "EntryLo0", "EntryLo1", "Context" , "PageMask" , "Wired" , "*Check me*", "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID" , "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "XContext", "*RES*" , "*RES*" , "*RES*" , "*RES*" , "*RES* " , "PErr" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "*RES*" }; typedef void (*TdisR3000AF)(TDis *, Uint32 code, Uint32 pc); // These macros are used to assemble the disassembler functions #define MakeDisF(fn, b) \ static void fn(TDis * d, Uint32 code, Uint32 pc) { \ d->pc = pc; \ b; \ } #define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register #define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register #define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register #define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register #define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register #define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register // The signed immediate part of the instruction register #define _sIm_ (code & 0x8000 ? - (((~code) & 0x7FFF) + 1) : ( code & 0x7FFF)) #define _Target_ (0x80000000 + ((code & 0x03ffffff) * 4)) #define _Branch_ (pc + 4 + ((short)_Im_ * 4)) #define _OfB_ _Im_, _nRs_ #define dName(n) { d->Name(n); } #define dGPR(i) { d->PushGPReg(i); } #define dCP0(i) { d->PushCPReg(i); } #define dImm() { d->PushImm(_Im_); } #define dTarget() { d->PushTarget(_Target_); } #define dSa() { d->PushSa(_Sa_); } #define dOfB() { \ d->PushOfB(_Rs_, _Im_, width); \ } #define dOffset() { \ d->PushOffset(_Branch_); \ } #define dFull(full) { \ d->PushFull(full); \ d->Comment("MaybeRefTo..."); \ } #define sep #define dInvalid() { \ d->Invalid(); \ } #define dSuspect() { \ d->Suspect(); \ } #define Invalidate(reg) { \ if (!reg) \ dSuspect(); \ } #define SetReg(reg, val) { \ if (!reg) \ dSuspect(); \ } #define MarkFunction(target) { \ d->add_function(target); \ } #define Branch(branch) { \ d->add_branch(branch); \ } #define Jump(target) { \ d->add_jump(target); \ } #define Stop(target) { \ d->SetTag(target, STOP, true); \ } /********************************************************* * Arithmetic with immediate operand * * Format: OP rt, rs, immediate * *********************************************************/ MakeDisF(disADDI, dName("addi"); dGPR(_Rt_); sep; if (_Rt_ != _Rs_) { dGPR(_Rs_); sep; } dImm(); if (isInvalid(_Rs_)) { Invalidate(_Rt_); } else { SetRegS(_Rt_, GetRegS(_Rs_) + _sIm_); } d->Comment("Add immediate"); ) MakeDisF(disADDIU, if (!_Rs_) { dName("li"); dGPR(_Rt_); sep; dImm(); SetRegS(_Rt_, _sIm_); d->Comment("Load immediate"); } else { dName("addiu"); dGPR(_Rt_); sep; if (_Rt_ != _Rs_) { dGPR(_Rs_); sep; } dImm(); if (isInvalid(_Rs_) { Invalidate(_Rt_); } else { SetRegS(_Rt_, GetRegS(_Rs_) + _sIm_); } d->Comment("Add immediate"); } ) MakeDisF(disANDI, dName("andi"); dGPR(_Rt_); sep; if (_Rt_ != _Rs_) { dGPR(_Rs_); sep; } dImm(); if (isInvalid(_Rs_) { Invalidate(_Rt_); } else { SetReg(_Rt_, GetReg(_Rs_) & _Im_); } d->Comment("And immediate"); ) MakeDisF(disORI, if (!_Rs_) { dName("liu"); dGPR(_Rt_); sep; dImm(); SetReg(_Rt_, _Im_); d->Comment("Load immediate without sign extension"); } else { dName("ori"); dGPR(_Rt_); sep; if (_Rt_ != _Rs_) { dGPR(_Rs_); sep; } dImm(); if (isInvalid(_Rs_)) { Invalidate(_Rt_); } else { SetReg(_Rt_, GetReg(_Rs_) | _Im_); } d->Comment("Or immediate"); } ) MakeDisF(disSLTI, dName("slti"); dGPR(_Rt_); sep; if (_Rt_ != _Rs_) { dGPR(_Rs_); sep; } dImm(); if (isInvalid(_Rs_)) { Invalidate(_Rt_); } else { SetReg(_Rt_, GetRegS(_Rs_) < _sIm_ ? 1 : 0); } d->Comment(registers[_Rt_] + String(" = ") + registers[_Rs_] + " < immediate ? 1 : 0 (signed)"); ) MakeDisF(disSLTIU, dName("sltiu"); dGPR(_Rt_); sep; if (_Rt_ != _Rs_) { dGPR(_Rs_); sep; } dImm(); if (isInvalid(_Rs_)) { Invalidate(_Rt_); } else { SetReg(_Rt_, GetReg(_Rs_) < _Im_ ? 1 : 0); } d->Comment(registers[_Rt_] + String(" = ") + registers[_Rs_] + " < immediate ? 1 : 0 (unsigned)"); ) MakeDisF(disXORI, dName("xori"); dGPR(_Rt_); sep; if (_Rt_ != _Rs_) { dGPR(_Rs_); sep; } dImm(); if (isInvalid(_Rs_)) { Invalidate(_Rt_); } else { SetReg(_Rt_, GetReg(_Rs_) ^ _Im_); } d->Comment("XOr immediate"); ) /********************************************************* * Register arithmetic * * Format: OP rd, rs, rt * *********************************************************/ MakeDisF(disADD, dName("add"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetRegS(_Rd_, GetRegS(_Rs_) + GetRegS(_Rt_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " + " + registers[_Rt_]); ) MakeDisF(disADDU, if (!_Rt_) { dName("move"); dGPR(_Rd_); sep; dGPR(_Rs_); if (_Rs_) { if (isInvalid(_Rs_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, _Rs_); } } else { SetReg(_Rd_, 0); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_]); } else { dName("addu"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetRegS(_Rd_, GetRegS(_Rs_) + GetRegS(_Rt_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " + " + registers[_Rt_]); } ) MakeDisF(disAND, dName("and"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(_Rs_) & GetReg(_Rt_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " & " + registers[_Rt_]); ) MakeDisF(disNOR, dName("nor"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, ~(GetReg(_Rs_) | GetReg(_Rt_))); } d->Comment(String(registers[_Rd_]) + " = ~(" + registers[_Rs_] + " | " + registers[_Rt_] + ")"); ) MakeDisF(disOR, dName("or"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(_Rs_) | GetReg(_Rt_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " | " + registers[_Rt_]); ) MakeDisF(disSLT, dName("slt"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetRegS(_Rs_) < GetRegS(_Rt_) ? 1 : 0); } d->Comment(registers[_Rd_] + String(" = ") + registers[_Rs_] + " < " + registers[_Rt_] + " ? 1 : 0 (signed)"); ) MakeDisF(disSLTU, dName("sltu"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(_Rs_) < GetReg(_Rt_) ? 1 : 0); } d->Comment(registers[_Rd_] + String(" = ") + registers[_Rs_] + " < " + registers[_Rt_] + " ? 1 : 0 (unsigned)"); ) MakeDisF(disSUB, dName("sub"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetRegS(_Rd_, GetRegS(_Rs_) - GetRegS(_Rt_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " - " + registers[_Rt_]); ) MakeDisF(disSUBU, dName("subu"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetRegS(_Rd_, GetRegS(_Rs_) - GetRegS(_Rt_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " - " + registers[_Rt_]); ) MakeDisF(disXOR, dName("xor"); dGPR(_Rd_); sep; if (_Rd_ != _Rs_) { dGPR(_Rs_); sep; } dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(_Rs_) ^ GetReg(_Rt_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rs_] + " ^ " + registers[_Rt_]); ) /********************************************************* * Register arithmetic & Register trap logic * * Format: OP rs, rt * *********************************************************/ MakeDisF(disDIV, dName("div"); dGPR(_Rs_); sep; dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(Rhi); Invalidate(Rlo); } else { int32 lo, hi, rs, rt; rs = GetRegS(_Rs_); rt = GetRegS(_Rt_); lo = rs / rt; hi = rs % rt; SetRegS(Rlo, lo); SetRegS(Rhi, hi); } String c1 = String(registers[_Rs_]) + " / " + registers[_Rt_]; String c2 = String(registers[_Rs_]) + " %% " + registers[_Rt_]; d->Comment("lo = " + c1 + "; hi = " + c2); ) MakeDisF(disDIVU, dName("divu"); dGPR(_Rs_); sep; dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(Rhi); Invalidate(Rlo); } else { Uint32 lo, hi, rs, rt; rs = GetReg(_Rs_); rt = GetReg(_Rt_); lo = rs / rt; hi = rs % rt; SetReg(Rlo, lo); SetReg(Rhi, hi); } String c1 = String(registers[_Rs_]) + " / " + registers[_Rt_]; String c2 = String(registers[_Rs_]) + " %% " + registers[_Rt_]; d->Comment("lo = " + c1 + "; hi = " + c2); ) MakeDisF(disMULT, dName("mult"); dGPR(_Rs_); sep; dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(Rhi); Invalidate(Rlo); } else { int64 res; Uint32 lo, hi; res = ((int64) GetRegS(_Rs_)) * ((int64) GetRegS(_Rt_)); lo = (Uint32) (((Uint64) res) & 0xffffffffUL); hi = (Uint32) (((Uint64) res >> 32) & 0xffffffffUL); SetReg(Rlo, lo); SetReg(Rhi, hi); } d->Comment(String("hilo = ") + registers[_Rs_] + " * " + registers[_Rt_]); ) MakeDisF(disMULTU, dName("multu"); dGPR(_Rs_); sep; dGPR(_Rt_); if (isInvalid(_Rs_) || isInvalid(_Rt_)) { Invalidate(Rhi); Invalidate(Rlo); } else { Uint64 res; Uint32 lo, hi; res = ((Uint64) GetReg(_Rs_)) * ((Uint64) GetReg(_Rt_)); lo = (Uint32) (res & 0xffffffffUL); hi = (Uint32) ((res >> 32) & 0xffffffffUL); SetReg(Rlo, lo); SetReg(Rhi, hi); } d->Comment(String("hilo = ") + registers[_Rs_] + " * " + registers[_Rt_]); ) /********************************************************* * Register branch logic * * Format: OP rs, offset * *********************************************************/ MakeDisF(disBGEZ, dName("bgez"); dGPR(_Rs_); sep; dOffset(); Branch(_Branch_); d->Comment("Branch if " + String(registers[_Rs_]) + " >= 0"); ) MakeDisF(disBGEZAL, if (_Rs_) { dName("bgezal"); dGPR(_Rs_); sep; dOffset(); Call(_Branch_); d->Comment("Branch and link if " + String(registers[_Rs_]) + " >= 0"); } else { dName("bal"); dOffset(); Call(_Branch_); d->Comment("Branch and link"); } ) MakeDisF(disBGTZ, dName("bgtz"); dGPR(_Rs_); sep; dOffset(); Branch(_Branch_); d->Comment("Branch if " + String(registers[_Rs_]) + " > 0"); ) MakeDisF(disBLEZ, dName("blez"); dGPR(_Rs_); sep; dOffset(); Branch(_Branch_); d->Comment("Branch if " + String(registers[_Rs_]) + " <= 0"); ) MakeDisF(disBLTZ, dName("bltz"); dGPR(_Rs_); sep; dOffset(); Branch(_Branch_); d->Comment("Branch if " + String(registers[_Rs_]) + " < 0"); ) MakeDisF(disBLTZAL, dName("bltzal"); dGPR(_Rs_); sep; dOffset(); Call(_Branch_); d->Comment("Branch and link if " + String(registers[_Rs_]) + " < 0"); ) /********************************************************* * Shift arithmetic with constant shift * * Format: OP rd, rt, sa * *********************************************************/ MakeDisF(disSLL, if ((!_Rd_) && (!_Rt_)) { dName("nop"); if (code) { dSuspect(); } } else { dName("sll"); dGPR(_Rd_); sep; if (_Rd_ != _Rt_) { dGPR(_Rt_); sep; } dSa(); if (isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(_Rt_) << _Sa_); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " << immediate"); } ) MakeDisF(disSRA, dName("sra"); dGPR(_Rd_); sep; if (_Rd_ != _Rt_) { dGPR(_Rt_); sep; } dSa(); if (isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetRegS(_Rd_, GetRegS(_Rt_) << _Sa_); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " >> immediate (arithmetic)"); ) MakeDisF(disSRL, dName("srl"); dGPR(_Rd_); sep; if (_Rd_ != _Rt_) { dGPR(_Rt_); sep; } dSa(); if (isInvalid(_Rt_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(_Rt_) << _Sa_); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " >> immediate (logical)"); ) /********************************************************* * Shift arithmetic with variant register shift * * Format: OP rd, rt, rs * *********************************************************/ MakeDisF(disSLLV, dName("sllv"); dGPR(_Rd_); sep; if (_Rd_ != _Rt_) { dGPR(_Rt_); sep; } dGPR(_Rs_); if (isInvalid(_Rt_) || isInvalid(_Rs_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(_Rt_) << GetReg(_Rs_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " << " + registers[_Rs_]); ) MakeDisF(disSRAV, dName("srav"); dGPR(_Rd_); sep; if (_Rd_ != _Rt_) { dGPR(_Rt_); sep; } dGPR(_Rs_); if (isInvalid(_Rt_) || isInvalid(_Rs_)) { Invalidate(_Rd_); } else { SetRegS(_Rd_, GetRegS(_Rt_) >> GetReg(_Rs_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " >> " + registers[_Rs_] + " (arithmetic)"); ) MakeDisF(disSRLV, dName("srlv"); dGPR(_Rd_); sep; if (_Rd_ != _Rt_) { dGPR(_Rt_); sep; } dGPR(_Rs_); if (isInvalid(_Rt_) || isInvalid(_Rs_)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(_Rt_) >> GetReg(_Rs_)); } d->Comment(String(registers[_Rd_]) + " = " + registers[_Rt_] + " >> " + registers[_Rs_] + " (logical)"); ) /********************************************************* * Load higher 16 bits of the first word in GPR with imm * * Format: OP rt, immediate * *********************************************************/ MakeDisF(disLUI, dName("lui"); dGPR(_Rt_); sep; dImm(); SetReg(_Rt_, _Imm_ << 16) d->Comment("Load upper immediate"); ) /********************************************************* * Move from HI/LO to GPR * * Format: OP rd * *********************************************************/ MakeDisF(disMFHI, dName("mfhi"); dGPR(_Rd_); if (isInvalid(Rhi)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(Rhi)); } d->Comment(String(registers[_Rd_]) + " = hi"); ) MakeDisF(disMFLO, dName("mflo"); dGPR(_Rd_); if (isInvalid(Rlo)) { Invalidate(_Rd_); } else { SetReg(_Rd_, GetReg(Rlo)); } d->Comment(String(registers[_Rd_]) + " = lo"); ) /********************************************************* * Move from GPR to HI/LO * * Format: OP rd * *********************************************************/ MakeDisF(disMTHI, dName("mthi"); dGPR(_Rd_); if (isInvalid(_Rd_)) { Invalidate(Rhi); } else { SetReg(Rhi, GetReg(_Rd_)); } d->Comment("hi = " + String(registers[_Rd_])); ) MakeDisF(disMTLO, dName("mtlo"); dGPR(_Rd_); if (isInvalid(_Rd_)) { Invalidate(Rlo); } else { SetReg(Rlo, GetReg(_Rd_)); } d->Comment("lo = " + String(registers[_Rd_])); ) /********************************************************* * Special purpose instructions * * Format: OP * *********************************************************/ MakeDisF(disBREAK, dName("break"); Stop(pc + 4); d->Comment("Stops the machine"); ) MakeDisF(disRFE, dName("rfe")) MakeDisF(disSYSCALL, int syscall; dName("syscall"); syscall = code & 0xfffff; Syscall(syscall); d->Comment(String("Syscall number ") + syscall); ) MakeDisF(disHLE, dName("hle")) MakeDisF(disRTPS, dName("rtps")) MakeDisF(disOP, dName("op")) MakeDisF(disNCLIP, dName("nclip")) MakeDisF(disDPCS, dName("dpcs")) MakeDisF(disINTPL, dName("intpl")) MakeDisF(disMVMVA, dName("mvmva")) MakeDisF(disNCDS, dName("ncds")) MakeDisF(disCDP, dName("cdp")) MakeDisF(disNCDT, dName("ncdt")) MakeDisF(disNCCS, dName("nccs")) MakeDisF(disCC, dName("cc")) MakeDisF(disNCS, dName("ncs")) MakeDisF(disNCT, dName("nct")) MakeDisF(disSQR, dName("sqr")) MakeDisF(disDCPL, dName("dcpl")) MakeDisF(disDPCT, dName("dpct")) MakeDisF(disAVSZ3, dName("avsz3")) MakeDisF(disAVSZ4, dName("avsz4")) MakeDisF(disRTPT, dName("rtpt")) MakeDisF(disGPF, dName("gpf")) MakeDisF(disGPL, dName("gpl")) MakeDisF(disNCCT, dName("ncct")) MakeDisF(disMFC2, dName("mfc2"); dGPR(_Rt_); Invalidate(_Rt_); ) MakeDisF(disCFC2, dName("cfc2"); dGPR(_Rt_); Invalidate(_Rt_); ) MakeDisF(disMTC2, dName("mtc2"); dGPR(_Rt_);) MakeDisF(disCTC2, dName("ctc2"); dGPR(_Rt_);) /********************************************************* * Register branch logic * * Format: OP rs, rt, offset * *********************************************************/ MakeDisF(disBEQ, if ((!_Rt_) && (!_Rs_)) { dName("b"); dOffset(); Branch(_Branch_); Stop(pc + 8); d->Comment("Branch always"); } if (!_Rt_) { dName("bez"); dGPR(_Rs_); sep; dOffset(); Branch(_Branch_); d->Comment(String("Branch if ") + registers[_Rs_] + " == 0"); } else { dName("beq"); dGPR(_Rs_); sep; dGPR(_Rt_); sep; dOffset(); Branch(_Branch_); d->Comment(String("Branch if ") + registers[_Rs_] + " == " + registers[_Rt_]); } ) MakeDisF(disBNE, if (!_Rt_) { dName("bnz"); dGPR(_Rs_); sep; dOffset(); Branch(_Branch_); d->Comment(String("Branch if ") + registers[_Rs_] + " != 0"); } else { dName("bne"); dGPR(_Rs_); sep; dGPR(_Rt_); sep; dOffset(); Branch(_Branch_); d->Comment(String("Branch if ") + registers[_Rs_] + " != " + registers[_Rt_]); } ) /********************************************************* * Jump to target * * Format: OP target * *********************************************************/ MakeDisF(disJ, dName("j"); dTarget(); Jump(_Target_); Stop(pc + 8); d->Comment("Jump always"); ) MakeDisF(disJAL, dName("jal"); dTarget(); Invalidate(Rra); MarkFunction(_Target_); d->Comment("Jump and link (function call)"); ) /********************************************************* * Register jump * * Format: OP rs, rd * *********************************************************/ MakeDisF(disJR, dName("jr"); dGPR(_Rs_); Stop(pc + 8); d->Comment("Jump register"); ) MakeDisF(disJALR, dName("jalr"); dGPR(_Rs_); if ((_Rd_) != Rra) { sep; dGPR(_Rd_); } Invalidate(_Rd_); d->Comment("Jump and link register (function call)"); ) /********************************************************* * Load and store for GPR * * Format: OP rt, offset(base) * *********************************************************/ MakeDisF(disLB, int width = 8; dName("lb"); dGPR(_Rt_); sep; dOfB(); Invalidate(_Rt_); d->Comment("Load signed byte"); ) MakeDisF(disLBU, int width = 8; dName("lbu"); dGPR(_Rt_); sep; dOfB(); Invalidate(_Rt_); d->Comment("Load unsigned byte"); ) MakeDisF(disLH, int width = 16; dName("lh"); dGPR(_Rt_); sep; dOfB(); Invalidate(_Rt_); d->Comment("Load signed half"); ) MakeDisF(disLHU, int width = 16; dName("lhu"); dGPR(_Rt_); sep; dOfB(); Invalidate(_Rt_); d->Comment("Load unsigned half"); ) MakeDisF(disLW, int width = 32; dName("lw"); dGPR(_Rt_); sep; dOfB(); Invalidate(_Rt_); d->Comment("Load word"); ) MakeDisF(disLWL, int width = 32; dName("lwl"); dGPR(_Rt_); sep; dOfB(); Invalidate(_Rt_); d->Comment("Load word left"); ) MakeDisF(disLWR, int width = 32; dName("lwr"); dGPR(_Rt_); sep; dOfB(); Invalidate(_Rt_); d->Comment("Load word right"); ) MakeDisF(disLWC2, int width = 32; dName("lwc2"); dCP0(_Rt_); sep; dOfB(); ) MakeDisF(disSB, int width = 8; dName("sb"); dGPR(_Rt_); sep; dOfB(); d->Comment("Store byte"); ) MakeDisF(disSH, int width = 16; dName("sh"); dGPR(_Rt_); sep; dOfB(); d->Comment("Store half"); ) MakeDisF(disSW, int width = 32; dName("sw"); dGPR(_Rt_); sep; dOfB(); d->Comment("Store word"); ) MakeDisF(disSWL, int width = 32; dName("swl"); dGPR(_Rt_); sep; dOfB(); d->Comment("Store word left"); ) MakeDisF(disSWR, int width = 32; dName("swr"); dGPR(_Rt_); sep; dOfB(); d->Comment("Store word right"); ) MakeDisF(disSWC2, int width = 32; dName("swc2"); dGPR(_Rt_); sep; dOfB(); ) /********************************************************* * Moves between GPR and COPx * * Format: OP rt, fs * *********************************************************/ MakeDisF(disMFC0, dName("mfc0"); dGPR(_Rt_); sep; dCP0(_Rd_); Invalidate(_Rt_);) MakeDisF(disMTC0, dName("mtc0"); dCP0(_Rd_); sep; dGPR(_Rt_);) MakeDisF(disCFC0, dName("cfc0"); dGPR(_Rt_); sep; dCP0(_Rd_); Invalidate(_Rt_);) MakeDisF(disCTC0, dName("ctc0"); dCP0(_Rd_); sep; dGPR(_Rt_);) /********************************************************* * Unknow instruction (would generate an exception) * * Format: ? * *********************************************************/ MakeDisF(disNULL, dName("*** Bad OP ***"); dInvalid(); ) TdisR3000AF disR3000A_SPECIAL[] = { // Subset of disSPECIAL disSLL , disNULL , disSRL , disSRA , disSLLV , disNULL , disSRLV , disSRAV , disJR , disJALR , disNULL, disNULL, disSYSCALL, disBREAK , disNULL , disNULL , disMFHI, disMTHI , disMFLO, disMTLO, disNULL , disNULL , disNULL , disNULL , disMULT, disMULTU, disDIV , disDIVU, disNULL , disNULL , disNULL , disNULL , disADD , disADDU , disSUB , disSUBU, disAND , disOR , disXOR , disNOR , disNULL, disNULL , disSLT , disSLTU, disNULL , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL ,}; MakeDisF(disSPECIAL, disR3000A_SPECIAL[_Funct_](d, code, pc)) TdisR3000AF disR3000A_BCOND[] = { // Subset of disBCOND disBLTZ , disBGEZ , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disBLTZAL, disBGEZAL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL,}; MakeDisF(disBCOND, disR3000A_BCOND[_Rt_](d, code, pc)) TdisR3000AF disR3000A_COP0[] = { // Subset of disCOP0 disMFC0, disNULL, disCFC0, disNULL, disMTC0, disNULL, disCTC0, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disRFE , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL,}; MakeDisF(disCOP0, disR3000A_COP0[_Rs_](d, code, pc)) TdisR3000AF disR3000A_BASIC[] = { // Subset of disBASIC (based on rs) disMFC2, disNULL, disCFC2, disNULL, disMTC2, disNULL, disCTC2, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL,}; MakeDisF(disBASIC, disR3000A_BASIC[_Rs_](d, code, pc)) TdisR3000AF disR3000A_COP2[] = { // Subset of disR3000F_COP2 (based on funct) disBASIC, disRTPS , disNULL , disNULL , disNULL, disNULL , disNCLIP, disNULL, disNULL , disNULL , disNULL , disNULL , disOP , disNULL , disNULL , disNULL, disDPCS , disINTPL, disMVMVA, disNCDS , disCDP , disNULL , disNCDT , disNULL, disNULL , disNULL , disNULL , disNCCS , disCC , disNULL , disNCS , disNULL, disNCT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, disSQR , disDCPL , disDPCT , disNULL , disNULL, disAVSZ3, disAVSZ4, disNULL, disRTPT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, disNULL , disNULL , disNULL , disNULL , disNULL, disGPF , disGPL , disNCCT,}; MakeDisF(disCOP2, disR3000A_COP2[_Funct_](d, code, pc)) TdisR3000AF disR3000A[] = { disSPECIAL , disBCOND , disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , disADDI , disADDIU , disSLTI , disSLTIU, disANDI, disORI , disXORI , disLUI , disCOP0 , disNULL , disCOP2 , disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL , disNULL , disNULL , disNULL, disNULL, disNULL , disNULL , disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disNULL , disSB , disSH , disSWL , disSW , disNULL, disNULL, disSWR , disNULL , disNULL , disNULL , disLWC2 , disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL , disSWC2 , disHLE , disNULL, disNULL, disNULL , disNULL ,}; //MakeDisFg(disR3000AF, disR3000A[code >> 26](code, pc)) void decode(TDis * d, Uint32 pc) { Uint32 code = d->getmem()->Read32(pc); disR3000A[code >> 26](d, code, pc); }