mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1647 lines
42 KiB
1647 lines
42 KiB
/***********************************************************************
|
|
* Microsoft Puma
|
|
*
|
|
* Microsoft Confidential. Copyright 1994-1996 Microsoft Corporation.
|
|
*
|
|
* Component:
|
|
*
|
|
* File: mipsdis.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "pumap.h"
|
|
|
|
#include "mips.h"
|
|
|
|
#include <ctype.h>
|
|
#include <iomanip.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <strstrea.h>
|
|
|
|
|
|
const TRMT DISMIPS::mptrmtmipstrmt[] =
|
|
{
|
|
trmtUnknown, // trmtmipsUnknown
|
|
trmtFallThrough, // trmtmipsFallThrough
|
|
trmtBraInd, // trmtmipsBraInd
|
|
trmtCallInd, // trmtmipsCallInd
|
|
trmtTrap, // trmtmipsTrap
|
|
trmtTrapCc, // trmtmipsTrapCc
|
|
trmtBraDef, // trmtmipsBraDef
|
|
trmtBraIndDef, // trmtmipsBraIndDef
|
|
trmtBraCcDef, // trmtmipsBraCcDef
|
|
trmtBraCcDef, // trmtmipsBraCcLikely
|
|
trmtCallDef, // trmtmipsCallDef
|
|
trmtCallIndDef, // trmtmipsCallIndDef
|
|
trmtCallCcDef, // trmtmipsCallCcDef
|
|
trmtCallCcDef, // trmtmipsCallCcLikely
|
|
};
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
// Instruction class definitions
|
|
// -----------------------------------------------------------------
|
|
|
|
#define DEFCLS(trmtmips_, opcls1, opcls2, opcls3, opcls4) \
|
|
{ trmtmips ## trmtmips_, { opcls ## opcls1, opcls ## opcls2, opcls ## opcls3, opcls ## opcls4 } }
|
|
|
|
const DISMIPS::CLS DISMIPS::rgcls[] =
|
|
{
|
|
DEFCLS(Unknown, None, None, None, None), // iclsInvalid
|
|
DEFCLS(FallThrough, RegRt, RegRs, Imm, None), // iclsImmediate
|
|
DEFCLS(TrapCc, RegRt, RegRs, Imm, None), // iclsImmTrapCc
|
|
DEFCLS(BraCcDef, RegRt, RegRs, AddrBra, None), // iclsImmBraCc1
|
|
DEFCLS(BraCcLikely, RegRt, RegRs, AddrBra, None), // iclsImmBraCc2
|
|
DEFCLS(BraCcDef, RegRs, AddrBra, None, None), // iclsImmBraCc3
|
|
DEFCLS(BraCcLikely, RegRs, AddrBra, None, None), // iclsImmBraCc4
|
|
DEFCLS(BraCcDef, RegRs, AddrBra, None, None), // iclsImmBraCc5
|
|
DEFCLS(BraCcLikely, RegRs, AddrBra, None, None), // iclsImmBraCc6
|
|
DEFCLS(CallCcDef, RegRs, AddrBra, None, None), // iclsImmCallCc1
|
|
DEFCLS(CallCcLikely, RegRs, AddrBra, None, None), // iclsImmCallCc2
|
|
DEFCLS(FallThrough, ImmRt, Mem, None, None), // iclsImmPerf
|
|
DEFCLS(FallThrough, RegRt, Mem_r, None, None), // iclsImmLoad
|
|
DEFCLS(FallThrough, CprRt, Mem_r, None, None), // iclsImmLoadCp
|
|
DEFCLS(FallThrough, RegRt, Imm, None, None), // iclsImmLui
|
|
DEFCLS(FallThrough, RegRt, Mem_w, None, None), // iclsImmStore
|
|
DEFCLS(FallThrough, RegRt, Mem_w, None, None), // iclsImmSc
|
|
DEFCLS(FallThrough, CprRt, Mem_w, None, None), // iclsImmStoreCp
|
|
DEFCLS(TrapCc, RegRs, Imm, None, None), // iclsImmTrap
|
|
DEFCLS(BraDef, AddrJmp, None, None, None), // iclsJump
|
|
DEFCLS(CallDef, AddrJmp, None, None, None), // iclsJumpJal
|
|
DEFCLS(FallThrough, RegRd, RegRs, RegRt, None), // iclsRegister
|
|
DEFCLS(FallThrough, RegRd, RegRs, Cc1, None), // iclsRegisterCc
|
|
DEFCLS(TrapCc, RegRd, RegRs, RegRt, None), // iclsRegTrapCc
|
|
DEFCLS(Trap, None, None, None, None), // iclsRegBreak
|
|
DEFCLS(CallInd, RegRd, RegRs, None, None), // iclsRegJalr
|
|
DEFCLS(BraIndDef, RegRs, None, None, None), // iclsRegJr
|
|
DEFCLS(FallThrough, RegRd, None, None, None), // iclsRegMfhi
|
|
DEFCLS(FallThrough, RegRd, None, None, None), // iclsRegMflo
|
|
DEFCLS(FallThrough, RegRs, None, None, None), // iclsRegMthi
|
|
DEFCLS(FallThrough, RegRs, None, None, None), // iclsRegMtlo
|
|
DEFCLS(FallThrough, RegRs, RegRt, None, None), // iclsRegMulDiv
|
|
DEFCLS(FallThrough, RegRd, RegRt, ImmRe, None), // iclsRegShift
|
|
DEFCLS(FallThrough, RegRd, RegRt, RegRs, None), // iclsRegShiftVar
|
|
DEFCLS(FallThrough, None, None, None, None), // iclsRegSync
|
|
DEFCLS(Trap, None, None, None, None), // iclsRegSyscall
|
|
DEFCLS(TrapCc, RegRs, RegRt, None, None), // iclsRegTrap
|
|
DEFCLS(BraCcDef, Cc1, AddrBra, None, None), // iclsImmBraCc7
|
|
DEFCLS(BraCcDef, AddrBra, None, None, None), // iclsImmBraCc8
|
|
DEFCLS(FallThrough, RegRt, CprRd, None, None), // iclsRegCfc
|
|
DEFCLS(FallThrough, RegRt, CprRd, None, None), // iclsRegCtc
|
|
DEFCLS(FallThrough, RegRt, CprRd, None, None), // iclsRegMfc
|
|
DEFCLS(FallThrough, RegRt, CprRd, None, None), // iclsRegMtc
|
|
DEFCLS(FallThrough, None, None, None, None), // iclsRegCp0
|
|
DEFCLS(BraInd, None, None, None, None), // iclsRegEret
|
|
DEFCLS(FallThrough, RegFd, RegFs, RegFt, None), // iclsRegFloat1
|
|
DEFCLS(FallThrough, RegFd, RegFs, None, None), // iclsRegFloat2
|
|
DEFCLS(FallThrough, RegFd, RegFs, None, None), // iclsRegFloat3
|
|
DEFCLS(FallThrough, RegFd, RegFs, None, None), // iclsRegFloat4
|
|
DEFCLS(FallThrough, RegFd, RegFs, None, None), // iclsRegFloat5
|
|
DEFCLS(FallThrough, Cc2, RegFs, RegFt, None), // iclsRegFloat6
|
|
DEFCLS(FallThrough, RegFd, RegFs, RegRt, None), // iclsRegFloat7
|
|
DEFCLS(FallThrough, RegFd, RegFs, Cc1, None), // iclsRegFloat8
|
|
DEFCLS(FallThrough, RegFs, RegFt, None, None), // iclsRegFloat9
|
|
DEFCLS(FallThrough, RegFd, RegFr, RegFs, RegFt), // iclsRegFloat10
|
|
DEFCLS(FallThrough, RegRd, Index, None, None), // iclsIndexPref
|
|
DEFCLS(FallThrough, RegFd, Index, None, None), // iclsIndexLoad
|
|
DEFCLS(FallThrough, RegFs, Index, None, None), // iclsIndexStore
|
|
};
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
// Instruction Opcode Definitions
|
|
// -----------------------------------------------------------------
|
|
|
|
// If the mnemonic begins with '!' then there is an embedded asterisk
|
|
// that needs to be replaced with the coprocessor number,
|
|
|
|
// If the mnemonic begins with '@' then the floating point
|
|
// format needs to be appended to the end of the mnemonic.
|
|
|
|
// If the mnemonic begins with '~' then there may be a
|
|
// pseudo-op that should be used.
|
|
|
|
#define DEFOPCD(szMnemonic, icls_) { szMnemonic, icls ## icls_ }
|
|
#define INVOPCD() DEFOPCD(NULL, Invalid)
|
|
|
|
// Main group identified by bits 31-26 of the instruction
|
|
|
|
const DISMIPS::OPCD DISMIPS::rgopcd[] =
|
|
{
|
|
INVOPCD(), // 0x0000 => SPECIAL
|
|
INVOPCD(), // 0x0001 => REGIMM
|
|
DEFOPCD("j", Jump ), // 0x0002
|
|
DEFOPCD("jal", JumpJal ), // 0x0003
|
|
DEFOPCD("~beq", ImmBraCc1 ), // 0x0004
|
|
DEFOPCD("bne", ImmBraCc1 ), // 0x0005
|
|
DEFOPCD("blez", ImmBraCc3 ), // 0x0006
|
|
DEFOPCD("bgtz", ImmBraCc3 ), // 0x0007
|
|
DEFOPCD("addi", ImmTrapCc ), // 0x0008
|
|
DEFOPCD("addiu", Immediate ), // 0x0009
|
|
DEFOPCD("slti", Immediate ), // 0x000A
|
|
DEFOPCD("sltiu", Immediate ), // 0x000B
|
|
DEFOPCD("andi", Immediate ), // 0x000C
|
|
DEFOPCD("ori", Immediate ), // 0x000D
|
|
DEFOPCD("xori", Immediate ), // 0x000E
|
|
DEFOPCD("lui", ImmLui ), // 0x000F
|
|
INVOPCD(), // 0x0010 => COP0
|
|
INVOPCD(), // 0x0011 => COP1
|
|
INVOPCD(), // 0x0012 => COP2
|
|
INVOPCD(), // 0x0013 => COP1X
|
|
DEFOPCD("beql", ImmBraCc2 ), // 0x0014
|
|
DEFOPCD("bnel", ImmBraCc2 ), // 0x0015
|
|
DEFOPCD("blezl", ImmBraCc4 ), // 0x0016
|
|
DEFOPCD("bgtzl", ImmBraCc4 ), // 0x0017
|
|
DEFOPCD("daddi", ImmTrapCc ), // 0x0018
|
|
DEFOPCD("daddiu", Immediate ), // 0x0019
|
|
DEFOPCD("ldl", ImmLoad ), // 0x001A
|
|
DEFOPCD("ldr", ImmLoad ), // 0x001B
|
|
INVOPCD(), // 0x001C (Reserved)
|
|
INVOPCD(), // 0x001D (Reserved)
|
|
INVOPCD(), // 0x001E (Reserved)
|
|
INVOPCD(), // 0x001F (Reserved)
|
|
DEFOPCD("lb", ImmLoad ), // 0x0020
|
|
DEFOPCD("lh", ImmLoad ), // 0x0021
|
|
DEFOPCD("lwl", ImmLoad ), // 0x0022
|
|
DEFOPCD("lw", ImmLoad ), // 0x0023
|
|
DEFOPCD("lbu", ImmLoad ), // 0x0024
|
|
DEFOPCD("lhu", ImmLoad ), // 0x0025
|
|
DEFOPCD("lwr", ImmLoad ), // 0x0026
|
|
DEFOPCD("lwu", ImmLoad ), // 0x0027
|
|
DEFOPCD("sb", ImmStore ), // 0x0028
|
|
DEFOPCD("sh", ImmStore ), // 0x0029
|
|
DEFOPCD("swl", ImmStore ), // 0x002A
|
|
DEFOPCD("sw", ImmStore ), // 0x002B
|
|
DEFOPCD("sdl", ImmStore ), // 0x002C
|
|
DEFOPCD("sdr", ImmStore ), // 0x002D
|
|
DEFOPCD("swr", ImmStore ), // 0x002E
|
|
DEFOPCD("cache", ImmPerf ), // 0x002F
|
|
DEFOPCD("ll", ImmLoad ), // 0x0030
|
|
DEFOPCD("lwc1", ImmLoadCp ), // 0x0031
|
|
DEFOPCD("lwc2", ImmLoadCp ), // 0x0032
|
|
DEFOPCD("pref", ImmPerf ), // 0x0033
|
|
DEFOPCD("lld", ImmLoad ), // 0x0034
|
|
DEFOPCD("ldc1", ImmLoadCp ), // 0x0035
|
|
DEFOPCD("ldc2", ImmLoadCp ), // 0x0036
|
|
DEFOPCD("ld", ImmLoad ), // 0x0037
|
|
DEFOPCD("sc", ImmSc ), // 0x0038
|
|
DEFOPCD("swc1", ImmStoreCp ), // 0x0039
|
|
DEFOPCD("swc2", ImmStoreCp ), // 0x003A
|
|
INVOPCD(), // 0x003B (Reserved)
|
|
DEFOPCD("scd", ImmSc ), // 0x003C
|
|
DEFOPCD("sdc1", ImmStoreCp ), // 0x003D
|
|
DEFOPCD("sdc2", ImmStoreCp ), // 0x003E
|
|
DEFOPCD("sd", ImmStore ), // 0x003F
|
|
};
|
|
|
|
|
|
// SPECIAL group identified by bits 5-0 of the instruction
|
|
|
|
const DISMIPS::OPCD DISMIPS::rgopcdSpecial[] =
|
|
{
|
|
DEFOPCD("~sll", RegShift ), // 0x0000
|
|
DEFOPCD("~movf", RegisterCc ), // 0x0001
|
|
DEFOPCD("srl", RegShift ), // 0x0002
|
|
DEFOPCD("sra", RegShift ), // 0x0003
|
|
DEFOPCD("sllv", RegShiftVar ), // 0x0004
|
|
INVOPCD(), // 0x0005 (Reserved)
|
|
DEFOPCD("srlv", RegShiftVar ), // 0x0006
|
|
DEFOPCD("srav", RegShiftVar ), // 0x0007
|
|
DEFOPCD("jr", RegJr ), // 0x0008
|
|
DEFOPCD("jalr", RegJalr ), // 0x0009
|
|
DEFOPCD("movz", Register ), // 0x000A
|
|
DEFOPCD("movn", Register ), // 0x000B
|
|
DEFOPCD("syscall", RegSyscall ), // 0x000C
|
|
DEFOPCD("break", RegBreak ), // 0x000D
|
|
INVOPCD(), // 0x000E (Reserved)
|
|
DEFOPCD("sync", RegSync ), // 0x000F
|
|
DEFOPCD("mfhi", RegMfhi ), // 0x0010
|
|
DEFOPCD("mthi", RegMthi ), // 0x0011
|
|
DEFOPCD("mflo", RegMflo ), // 0x0012
|
|
DEFOPCD("mtlo", RegMtlo ), // 0x0013
|
|
DEFOPCD("dsllv", RegShiftVar ), // 0x0014
|
|
INVOPCD(), // 0x0015 (Reserved)
|
|
DEFOPCD("dsrlv", RegShiftVar ), // 0x0016
|
|
DEFOPCD("dsrav", RegShiftVar ), // 0x0017
|
|
DEFOPCD("mult", RegMulDiv ), // 0x0018
|
|
DEFOPCD("multu", RegMulDiv ), // 0x0019
|
|
DEFOPCD("div", RegMulDiv ), // 0x001A
|
|
DEFOPCD("divu", RegMulDiv ), // 0x001B
|
|
DEFOPCD("dmult", RegMulDiv ), // 0x001C
|
|
DEFOPCD("dmultu", RegMulDiv ), // 0x001D
|
|
DEFOPCD("ddiv", RegMulDiv ), // 0x001E
|
|
DEFOPCD("ddivu", RegMulDiv ), // 0x001F
|
|
DEFOPCD("add", RegTrapCc ), // 0x0020
|
|
DEFOPCD("addu", Register ), // 0x0021
|
|
DEFOPCD("sub", RegTrapCc ), // 0x0022
|
|
DEFOPCD("subu", Register ), // 0x0023
|
|
DEFOPCD("and", Register ), // 0x0024
|
|
DEFOPCD("or", Register ), // 0x0025
|
|
DEFOPCD("xor", Register ), // 0x0026
|
|
DEFOPCD("nor", Register ), // 0x0027
|
|
INVOPCD(), // 0x0028 (Reserved)
|
|
INVOPCD(), // 0x0029 (Reserved)
|
|
DEFOPCD("slt", Register ), // 0x002A
|
|
DEFOPCD("sltu", Register ), // 0x002B
|
|
DEFOPCD("dadd", RegTrapCc ), // 0x002C
|
|
DEFOPCD("daddu", Register ), // 0x002D
|
|
DEFOPCD("dsub", RegTrapCc ), // 0x002E
|
|
DEFOPCD("dsubu", Register ), // 0x002F
|
|
DEFOPCD("tge", RegTrap ), // 0x0030
|
|
DEFOPCD("tgeu", RegTrap ), // 0x0031
|
|
DEFOPCD("tlt", RegTrap ), // 0x0032
|
|
DEFOPCD("tltu", RegTrap ), // 0x0033
|
|
DEFOPCD("teq", RegTrap ), // 0x0034
|
|
INVOPCD(), // 0x0035 (Reserved)
|
|
DEFOPCD("tne", RegTrap ), // 0x0036
|
|
INVOPCD(), // 0x0037 (Reserved)
|
|
DEFOPCD("dssl", RegShift ), // 0x0038
|
|
INVOPCD(), // 0x0039 (Reserved)
|
|
DEFOPCD("dsrl", RegShift ), // 0x003A
|
|
DEFOPCD("dsra", RegShift ), // 0x003B
|
|
DEFOPCD("dsll32", RegShift ), // 0x003C
|
|
INVOPCD(), // 0x003D (Reserved)
|
|
DEFOPCD("dsrl32", RegShift ), // 0x003E
|
|
DEFOPCD("dsra32", RegShift ), // 0x003F
|
|
};
|
|
|
|
|
|
// REGIMM group identified, by bits 20-16 of the instruction
|
|
|
|
const DISMIPS::OPCD DISMIPS::rgopcdRegimm[] =
|
|
{
|
|
DEFOPCD("bltz", ImmBraCc5 ), // 0x0000
|
|
DEFOPCD("bgez", ImmBraCc5 ), // 0x0001
|
|
DEFOPCD("bltzl", ImmBraCc6 ), // 0x0002
|
|
DEFOPCD("bgezl", ImmBraCc6 ), // 0x0003
|
|
INVOPCD(), // 0x0004
|
|
INVOPCD(), // 0x0005
|
|
INVOPCD(), // 0x0006
|
|
INVOPCD(), // 0x0007
|
|
DEFOPCD("tgei", ImmTrap ), // 0x0008
|
|
DEFOPCD("tgeiu", ImmTrap ), // 0x0009
|
|
DEFOPCD("tlti", ImmTrap ), // 0x000A
|
|
DEFOPCD("tltiu", ImmTrap ), // 0x000B
|
|
DEFOPCD("teqi", ImmTrap ), // 0x000C
|
|
INVOPCD(), // 0x000D
|
|
DEFOPCD("tnei", ImmTrap ), // 0x000E
|
|
INVOPCD(), // 0x000F
|
|
DEFOPCD("bltzal", ImmCallCc1 ), // 0x0010
|
|
DEFOPCD("bgezal", ImmCallCc1 ), // 0x0011
|
|
DEFOPCD("bltzall", ImmCallCc2 ), // 0x0012
|
|
DEFOPCD("bgezall", ImmCallCc2 ), // 0x0013
|
|
INVOPCD(), // 0x0014
|
|
INVOPCD(), // 0x0015
|
|
INVOPCD(), // 0x0016
|
|
INVOPCD(), // 0x0017
|
|
INVOPCD(), // 0x0018
|
|
INVOPCD(), // 0x0019
|
|
INVOPCD(), // 0x001A
|
|
INVOPCD(), // 0x001B
|
|
INVOPCD(), // 0x001C
|
|
INVOPCD(), // 0x001D
|
|
INVOPCD(), // 0x001E
|
|
INVOPCD(), // 0x001F
|
|
};
|
|
|
|
|
|
// COPz groups identified, by bits 25-21 of the instruction
|
|
|
|
const DISMIPS::OPCD DISMIPS::rgopcdCop[] =
|
|
{
|
|
DEFOPCD("!mfc*", RegMfc ), // 0x0000 // UNDONE: MFPC and MFPS
|
|
DEFOPCD("!dmfc*", RegMfc ), // 0x0001
|
|
DEFOPCD("!cfc*", RegCfc ), // 0x0002
|
|
INVOPCD(), // 0x0003
|
|
DEFOPCD("!mtc*", RegMtc ), // 0x0004 // UNDONE: MTPC and MTPS
|
|
DEFOPCD("!dmtc*", RegMtc ), // 0x0005
|
|
DEFOPCD("!ctc*", RegCtc ), // 0x0006
|
|
INVOPCD(), // 0x0007
|
|
INVOPCD(), // 0x0008 => BC
|
|
INVOPCD(), // 0x0009
|
|
INVOPCD(), // 0x000A
|
|
INVOPCD(), // 0x000B
|
|
INVOPCD(), // 0x000C
|
|
INVOPCD(), // 0x000D
|
|
INVOPCD(), // 0x000E
|
|
INVOPCD(), // 0x000F
|
|
};
|
|
|
|
|
|
// BCz groups identified, by bits 20-16 of the instruction
|
|
|
|
const DISMIPS::OPCD DISMIPS::rgopcdBc[] =
|
|
{
|
|
DEFOPCD("~!bc*f", ImmBraCc7 ), // 0x0000
|
|
DEFOPCD("~!bc*t", ImmBraCc7 ), // 0x0001
|
|
DEFOPCD("~!bc*fl", ImmBraCc7 ), // 0x0002
|
|
DEFOPCD("~!bc*tl", ImmBraCc7 ), // 0x0003
|
|
};
|
|
|
|
|
|
// COP1X groups identified, by bits 5-0 of the instruction
|
|
|
|
const DISMIPS::OPCD DISMIPS::rgopcdCop1x[] =
|
|
{
|
|
DEFOPCD("lwxc1", IndexLoad ), // 0x0000
|
|
DEFOPCD("ldxc1", IndexLoad ), // 0x0001
|
|
INVOPCD(), // 0x0002
|
|
INVOPCD(), // 0x0003
|
|
INVOPCD(), // 0x0004
|
|
INVOPCD(), // 0x0005
|
|
INVOPCD(), // 0x0006
|
|
INVOPCD(), // 0x0007
|
|
DEFOPCD("swxc1", IndexStore ), // 0x0008
|
|
DEFOPCD("sdxc1", IndexStore ), // 0x0009
|
|
INVOPCD(), // 0x000A
|
|
INVOPCD(), // 0x000B
|
|
INVOPCD(), // 0x000C
|
|
INVOPCD(), // 0x000D
|
|
INVOPCD(), // 0x000E
|
|
DEFOPCD("prefx", IndexPref ), // 0x000F
|
|
INVOPCD(), // 0x0010
|
|
INVOPCD(), // 0x0011
|
|
INVOPCD(), // 0x0012
|
|
INVOPCD(), // 0x0013
|
|
INVOPCD(), // 0x0014
|
|
INVOPCD(), // 0x0015
|
|
INVOPCD(), // 0x0016
|
|
INVOPCD(), // 0x0017
|
|
INVOPCD(), // 0x0018
|
|
INVOPCD(), // 0x0019
|
|
INVOPCD(), // 0x001A
|
|
INVOPCD(), // 0x001B
|
|
INVOPCD(), // 0x001C
|
|
INVOPCD(), // 0x001D
|
|
INVOPCD(), // 0x001E
|
|
INVOPCD(), // 0x001F
|
|
DEFOPCD("madd.s", RegFloat10 ), // 0x0020
|
|
DEFOPCD("madd.d", RegFloat10 ), // 0x0021
|
|
INVOPCD(), // 0x0022
|
|
INVOPCD(), // 0x0023
|
|
INVOPCD(), // 0x0024
|
|
INVOPCD(), // 0x0025
|
|
INVOPCD(), // 0x0026
|
|
INVOPCD(), // 0x0027
|
|
DEFOPCD("msub.s", RegFloat10 ), // 0x0028
|
|
DEFOPCD("msub.d", RegFloat10 ), // 0x0029
|
|
INVOPCD(), // 0x002A
|
|
INVOPCD(), // 0x002B
|
|
INVOPCD(), // 0x002C
|
|
INVOPCD(), // 0x002D
|
|
INVOPCD(), // 0x002E
|
|
INVOPCD(), // 0x002F
|
|
DEFOPCD("nmadd.s", RegFloat10 ), // 0x0030
|
|
DEFOPCD("nmadd.d", RegFloat10 ), // 0x0031
|
|
INVOPCD(), // 0x0032
|
|
INVOPCD(), // 0x0033
|
|
INVOPCD(), // 0x0034
|
|
INVOPCD(), // 0x0035
|
|
INVOPCD(), // 0x0036
|
|
INVOPCD(), // 0x0037
|
|
DEFOPCD("nmsub.s", RegFloat10 ), // 0x0038
|
|
DEFOPCD("nmsub.d", RegFloat10 ), // 0x0039
|
|
};
|
|
|
|
|
|
// CP0 group identified by, bits 5-0 of the instruction
|
|
|
|
const DISMIPS::OPCD DISMIPS::rgopcdCp0[] =
|
|
{
|
|
INVOPCD(), // 0x0000
|
|
DEFOPCD("tlbr", RegCp0 ), // 0x0001
|
|
DEFOPCD("tlbwi", RegCp0 ), // 0x0002
|
|
INVOPCD(), // 0x0003
|
|
INVOPCD(), // 0x0004
|
|
INVOPCD(), // 0x0005
|
|
DEFOPCD("tlbwi", RegCp0 ), // 0x0006
|
|
INVOPCD(), // 0x0007
|
|
DEFOPCD("tlbp", RegCp0 ), // 0x0008
|
|
INVOPCD(), // 0x0009
|
|
INVOPCD(), // 0x000A
|
|
INVOPCD(), // 0x000B
|
|
INVOPCD(), // 0x000C
|
|
INVOPCD(), // 0x000D
|
|
INVOPCD(), // 0x000E
|
|
INVOPCD(), // 0x000F
|
|
INVOPCD(), // 0x0010
|
|
INVOPCD(), // 0x0011
|
|
INVOPCD(), // 0x0012
|
|
INVOPCD(), // 0x0013
|
|
INVOPCD(), // 0x0014
|
|
INVOPCD(), // 0x0015
|
|
INVOPCD(), // 0x0016
|
|
INVOPCD(), // 0x0017
|
|
DEFOPCD("eret", RegEret ), // 0x0018
|
|
INVOPCD(), // 0x0019
|
|
INVOPCD(), // 0x001A
|
|
INVOPCD(), // 0x001B
|
|
INVOPCD(), // 0x001C
|
|
INVOPCD(), // 0x001D
|
|
INVOPCD(), // 0x001E
|
|
INVOPCD(), // 0x001F
|
|
INVOPCD(), // 0x0020
|
|
INVOPCD(), // 0x0021
|
|
INVOPCD(), // 0x0022
|
|
INVOPCD(), // 0x0023
|
|
INVOPCD(), // 0x0024
|
|
INVOPCD(), // 0x0025
|
|
INVOPCD(), // 0x0026
|
|
INVOPCD(), // 0x0027
|
|
INVOPCD(), // 0x0028
|
|
INVOPCD(), // 0x0029
|
|
INVOPCD(), // 0x002A
|
|
INVOPCD(), // 0x002B
|
|
INVOPCD(), // 0x002C
|
|
INVOPCD(), // 0x002D
|
|
INVOPCD(), // 0x002E
|
|
INVOPCD(), // 0x002F
|
|
INVOPCD(), // 0x0030
|
|
INVOPCD(), // 0x0031
|
|
INVOPCD(), // 0x0032
|
|
INVOPCD(), // 0x0033
|
|
INVOPCD(), // 0x0034
|
|
INVOPCD(), // 0x0035
|
|
INVOPCD(), // 0x0036
|
|
INVOPCD(), // 0x0037
|
|
INVOPCD(), // 0x0038
|
|
INVOPCD(), // 0x0039
|
|
INVOPCD(), // 0x003A
|
|
INVOPCD(), // 0x003B
|
|
INVOPCD(), // 0x003C
|
|
INVOPCD(), // 0x003D
|
|
INVOPCD(), // 0x003E
|
|
INVOPCD(), // 0x003F
|
|
};
|
|
|
|
|
|
// CP1 group identified by, bits 5-0 of the instruction
|
|
|
|
const DISMIPS::OPCD DISMIPS::rgopcdCp1[] =
|
|
{
|
|
DEFOPCD("@add", RegFloat1 ), // 0x0000
|
|
DEFOPCD("@sub", RegFloat1 ), // 0x0001
|
|
DEFOPCD("@mul", RegFloat1 ), // 0x0002
|
|
DEFOPCD("@div", RegFloat1 ), // 0x0003
|
|
DEFOPCD("@sqrt", RegFloat2 ), // 0x0004
|
|
DEFOPCD("@abs", RegFloat2 ), // 0x0005
|
|
DEFOPCD("@mov", RegFloat3 ), // 0x0006
|
|
DEFOPCD("@neg", RegFloat2 ), // 0x0007
|
|
DEFOPCD("@round.l", RegFloat2 ), // 0x0008
|
|
DEFOPCD("@trunc.l", RegFloat2 ), // 0x0009
|
|
DEFOPCD("@ceil.l", RegFloat2 ), // 0x000A
|
|
DEFOPCD("@floor.l", RegFloat2 ), // 0x000B
|
|
DEFOPCD("@round.w", RegFloat2 ), // 0x000C
|
|
DEFOPCD("@trunc.w", RegFloat2 ), // 0x000D
|
|
DEFOPCD("@ceil.w", RegFloat2 ), // 0x000E
|
|
DEFOPCD("@floor.w", RegFloat2 ), // 0x000F
|
|
INVOPCD(), // 0x0010
|
|
DEFOPCD("~@movf", RegFloat8 ), // 0x0011
|
|
DEFOPCD("@movz", RegFloat7 ), // 0x0012
|
|
DEFOPCD("@movn", RegFloat7 ), // 0x0013
|
|
INVOPCD(), // 0x0014
|
|
DEFOPCD("@recip", RegFloat2 ), // 0x0015
|
|
DEFOPCD("@rsqrt", RegFloat2 ), // 0x0016
|
|
INVOPCD(), // 0x0017
|
|
INVOPCD(), // 0x0018
|
|
INVOPCD(), // 0x0019
|
|
INVOPCD(), // 0x001A
|
|
INVOPCD(), // 0x001B
|
|
INVOPCD(), // 0x001C
|
|
INVOPCD(), // 0x001D
|
|
INVOPCD(), // 0x001E
|
|
INVOPCD(), // 0x001F
|
|
DEFOPCD("@cvt.s", RegFloat4 ), // 0x0020
|
|
DEFOPCD("@cvt.d", RegFloat5 ), // 0x0021
|
|
INVOPCD(), // 0x0022
|
|
INVOPCD(), // 0x0023
|
|
DEFOPCD("@cvt.w", RegFloat2 ), // 0x0024
|
|
DEFOPCD("@cvt.l", RegFloat2 ), // 0x0025
|
|
INVOPCD(), // 0x0026
|
|
INVOPCD(), // 0x0027
|
|
INVOPCD(), // 0x0028
|
|
INVOPCD(), // 0x0029
|
|
INVOPCD(), // 0x002A
|
|
INVOPCD(), // 0x002B
|
|
INVOPCD(), // 0x002C
|
|
INVOPCD(), // 0x002D
|
|
INVOPCD(), // 0x002E
|
|
INVOPCD(), // 0x002F
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0030
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0031
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0032
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0033
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0034
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0035
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0036
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0037
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0038
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x0039
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x003A
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x003B
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x003C
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x003D
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x003E
|
|
DEFOPCD("[email protected]", RegFloat6 ), // 0x003F
|
|
};
|
|
|
|
|
|
const char DISMIPS::rgszFormat[5][4] =
|
|
{
|
|
".s", // 0
|
|
".d", // 1
|
|
"***", // 2
|
|
"***", // 3
|
|
".w", // 4
|
|
};
|
|
|
|
|
|
const char * const DISMIPS::rgszGpr[32] =
|
|
{
|
|
"zero", // $0
|
|
"at", // $1
|
|
"v0", // $2
|
|
"v1", // $3
|
|
"a0", // $4
|
|
"a1", // $5
|
|
"a2", // $6
|
|
"a3", // $7
|
|
"t0", // $8
|
|
"t1", // $9
|
|
"t2", // $10
|
|
"t3", // $11
|
|
"t4", // $12
|
|
"t5", // $13
|
|
"t6", // $14
|
|
"t7", // $15
|
|
"s0", // $16
|
|
"s1", // $17
|
|
"s2", // $18
|
|
"s3", // $19
|
|
"s4", // $20
|
|
"s5", // $21
|
|
"s6", // $22
|
|
"s7", // $23
|
|
"t8", // $24
|
|
"t9", // $25
|
|
"k0", // $26
|
|
"k1", // $27
|
|
"gp", // $28
|
|
"sp", // $29
|
|
"s8", // $30
|
|
"ra", // $31
|
|
};
|
|
|
|
|
|
const DISMIPS::OPCD DISMIPS::opcdB =
|
|
DEFOPCD("b", ImmBraCc8 );
|
|
|
|
const DISMIPS::OPCD DISMIPS::opcdNop =
|
|
DEFOPCD("nop", RegSync );
|
|
|
|
|
|
DISMIPS::DISMIPS(ARCHT archt) : DIS(archt)
|
|
{
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
// Public Methods
|
|
// -----------------------------------------------------------------
|
|
|
|
ADDR DISMIPS::AddrAddress() const
|
|
{
|
|
// UNDONE
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
|
|
ADDR DISMIPS::AddrJumpTable() const
|
|
{
|
|
return(addrNil);
|
|
}
|
|
|
|
|
|
ADDR DISMIPS::AddrOperand(size_t ioperand) const
|
|
{
|
|
if (m_pfndwgetreg == 0)
|
|
{
|
|
return(addrNil);
|
|
}
|
|
|
|
if (ioperand == 0)
|
|
{
|
|
// Implicit operand if any
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
if (!FValidOperand(ioperand))
|
|
{
|
|
return(addrNil);
|
|
}
|
|
|
|
ICLS icls = (ICLS) m_popcd->icls;
|
|
Assert(icls != iclsInvalid);
|
|
|
|
ADDR addr = addrNil;
|
|
|
|
OPCLS opcls = (OPCLS) rgcls[icls].rgopcls[ioperand-1];
|
|
|
|
switch (opcls)
|
|
{
|
|
DWORD dwDisp;
|
|
|
|
case opclsMem : // Memory reference
|
|
case opclsMem_w : // Memory read
|
|
case opclsMem_r : // Memory write
|
|
if (m_mipsiw.u_format.Rs != 0)
|
|
{
|
|
addr = (ADDR) (*m_pfndwgetreg)(this, (int) m_mipsiw.u_format.Rs);
|
|
}
|
|
|
|
dwDisp = m_mipsiw.u_format.Uimmediate;
|
|
|
|
if ((dwDisp & 0x8000) != 0)
|
|
{
|
|
dwDisp |= 0xFFFF0000;
|
|
}
|
|
|
|
addr += dwDisp;
|
|
break;
|
|
}
|
|
|
|
return(addr);
|
|
}
|
|
|
|
|
|
ADDR DISMIPS::AddrTarget() const
|
|
{
|
|
ICLS icls = (ICLS) m_popcd->icls;
|
|
Assert(icls != iclsInvalid);
|
|
|
|
ADDR addrTarget;
|
|
|
|
switch (icls)
|
|
{
|
|
DWORD dwDisp;
|
|
|
|
case iclsImmBraCc1 :
|
|
case iclsImmBraCc2 :
|
|
case iclsImmBraCc3 :
|
|
case iclsImmBraCc4 :
|
|
case iclsImmBraCc5 :
|
|
case iclsImmBraCc6 :
|
|
case iclsImmBraCc7 :
|
|
case iclsImmCallCc1 :
|
|
case iclsImmCallCc2 :
|
|
dwDisp = m_mipsiw.u_format.Uimmediate;
|
|
if ((dwDisp & 0x8000) != 0)
|
|
{
|
|
dwDisp |= 0xFFFF0000; // Sign Extend
|
|
}
|
|
|
|
addrTarget = m_addr + sizeof(MIPSIW) + (dwDisp << 2);
|
|
break;
|
|
|
|
case iclsJump :
|
|
case iclsJumpJal :
|
|
addrTarget = (m_addr & 0xF0000000) | (m_mipsiw.j_format.Target << 2);
|
|
break;
|
|
|
|
default :
|
|
addrTarget = addrNil;
|
|
}
|
|
|
|
return(addrTarget);
|
|
}
|
|
|
|
|
|
size_t DISMIPS::Cb() const
|
|
{
|
|
return(sizeof(MIPSIW));
|
|
}
|
|
|
|
|
|
size_t DISMIPS::CbDisassemble(ADDR addr, const BYTE *pb, size_t cbMax)
|
|
{
|
|
m_addr = addr;
|
|
|
|
if ((addr & 3) != 0)
|
|
{
|
|
// Instruction address not aligned
|
|
|
|
m_popcd = NULL;
|
|
return(0);
|
|
}
|
|
|
|
if (cbMax < sizeof(MIPSIW))
|
|
{
|
|
// Buffer not large enough for single instruction
|
|
|
|
m_popcd = NULL;
|
|
return(0);
|
|
}
|
|
|
|
m_mipsiw = *(MIPSIW UNALIGNED *) pb;
|
|
|
|
m_popcd = PopcdDecode(m_mipsiw);
|
|
|
|
if (m_popcd == NULL)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
return(sizeof(MIPSIW));
|
|
}
|
|
|
|
|
|
size_t DISMIPS::CbGenerateLoadAddress(BYTE *, size_t, size_t *) const
|
|
{
|
|
// UNDONE
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
size_t DISMIPS::CbJumpEntry() const
|
|
{
|
|
return(sizeof(DWORD));
|
|
}
|
|
|
|
|
|
size_t DISMIPS::CbMemoryReference() const
|
|
{
|
|
// UNDONE: Should we just use an array index by Opcode - 0x20?
|
|
|
|
size_t cb;
|
|
|
|
switch (m_mipsiw.j_format.Opcode)
|
|
{
|
|
case 0x0020 : // lb
|
|
case 0x0024 : // lbu
|
|
case 0x0028 : // sb
|
|
cb = 1;
|
|
break;
|
|
|
|
case 0x0021 : // lh
|
|
case 0x0025 : // lhu
|
|
case 0x0029 : // sh
|
|
cb = 2;
|
|
break;
|
|
|
|
case 0x0023 : // lw
|
|
case 0x0027 : // lwu
|
|
case 0x002B : // sw
|
|
case 0x0030 : // ll
|
|
case 0x0031 : // lwc1
|
|
case 0x0032 : // lwc2
|
|
case 0x0038 : // sc
|
|
case 0x0039 : // swc1
|
|
case 0x003A : // swc2
|
|
cb = 4;
|
|
break;
|
|
|
|
case 0x0034 : // lld
|
|
case 0x0035 : // ldc1
|
|
case 0x0036 : // ldc2
|
|
case 0x0037 : // ld
|
|
case 0x003C : // scd
|
|
case 0x003D : // sdc1
|
|
case 0x003E : // sdc2
|
|
case 0x003F : // sd
|
|
cb = 8;
|
|
break;
|
|
|
|
default :
|
|
cb = 0;
|
|
};
|
|
|
|
return(cb);
|
|
}
|
|
|
|
|
|
size_t DISMIPS::CchFormatAddr(ADDR addr, char *sz, size_t cchMax) const
|
|
{
|
|
if (cchMax > INT_MAX)
|
|
{
|
|
cchMax = INT_MAX;
|
|
}
|
|
|
|
ostrstream ostr(sz, (int) cchMax);
|
|
|
|
FormatAddr(ostr, addr);
|
|
|
|
ostr << ends;
|
|
|
|
if (ostr.fail())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
return((size_t) ostr.pcount());
|
|
}
|
|
|
|
|
|
size_t DISMIPS::CchFormatBytes(char *sz, size_t cchMax) const
|
|
{
|
|
if (cchMax <= 8)
|
|
{
|
|
// Caller's buffer is too small
|
|
|
|
return(0);
|
|
}
|
|
|
|
size_t cch = (size_t) sprintf(sz, "%08X", m_mipsiw.dw);
|
|
|
|
Assert(cch == 8);
|
|
|
|
return(8);
|
|
}
|
|
|
|
|
|
size_t DISMIPS::CchFormatBytesMax() const
|
|
{
|
|
return(8);
|
|
}
|
|
|
|
|
|
size_t DISMIPS::CchFormatInstr(char *sz, size_t cchMax) const
|
|
{
|
|
if (cchMax > INT_MAX)
|
|
{
|
|
cchMax = INT_MAX;
|
|
}
|
|
|
|
ostrstream ostr(sz, (int) cchMax);
|
|
|
|
FormatInstr(ostr);
|
|
|
|
ostr << ends;
|
|
|
|
if (ostr.fail())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
return((size_t) ostr.pcount());
|
|
}
|
|
|
|
|
|
size_t DISMIPS::Coperand() const
|
|
{
|
|
ICLS icls = (ICLS) m_popcd->icls;
|
|
Assert(icls != iclsInvalid);
|
|
|
|
for (size_t coperand = 4; coperand > 0; coperand--)
|
|
{
|
|
if (rgcls[icls].rgopcls[coperand-1] != opclsNone)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(coperand);
|
|
}
|
|
|
|
|
|
void DISMIPS::FormatAddr(ostream& ostr, ADDR addr) const
|
|
{
|
|
long lFlags = ostr.setf(ios::uppercase);
|
|
char chFill = ostr.fill('0');
|
|
|
|
ostr << hex << setw(8) << addr;
|
|
|
|
ostr.fill(chFill);
|
|
ostr.flags(lFlags);
|
|
}
|
|
|
|
|
|
void DISMIPS::FormatInstr(ostream& ostr) const
|
|
{
|
|
long lFlags = ostr.setf(ios::uppercase);
|
|
char chFill = ostr.fill('0');
|
|
|
|
ICLS icls = (ICLS) m_popcd->icls;
|
|
Assert(icls != iclsInvalid);
|
|
|
|
const char *szMnemonic = m_popcd->szMnemonic;
|
|
|
|
// If the mnemonic begins with '~' then there
|
|
// may be a pseudo-op that should be used.
|
|
|
|
char szPseudo[32];
|
|
|
|
if (szMnemonic[0] == '~')
|
|
{
|
|
OPCD opcd;
|
|
|
|
opcd.szMnemonic = szPseudo;
|
|
|
|
const OPCD *popcd = PopcdPseudoOp(&opcd, szPseudo);
|
|
|
|
if (popcd != NULL)
|
|
{
|
|
icls = (ICLS) popcd->icls;
|
|
Assert(icls != iclsInvalid);
|
|
|
|
szMnemonic = popcd->szMnemonic;
|
|
}
|
|
|
|
else
|
|
{
|
|
szMnemonic++;
|
|
}
|
|
}
|
|
|
|
// If the mnemonic begins with '!' then there is an embedded asterisk
|
|
// that needs to be replaced with the coprocessor number,
|
|
|
|
char szMnemonicT[32];
|
|
|
|
if (szMnemonic[0] == '!')
|
|
{
|
|
szMnemonic = strcpy(szMnemonicT, szMnemonic + 1);
|
|
|
|
// Replace '*' in mnemonic with coprocessor number
|
|
|
|
Assert(strchr(szMnemonic, '*') != NULL);
|
|
|
|
*strchr(szMnemonic, '*') = (char) ('0' + m_mipsiw.j_format.Opcode - 0x10);
|
|
}
|
|
|
|
// If the mnemonic begins with '@' then the floating point
|
|
// format needs to be appended to the end of the mnemonic.
|
|
|
|
const char *szFormat;
|
|
|
|
if (szMnemonic[0] == '@')
|
|
{
|
|
szMnemonic++;
|
|
|
|
szFormat = rgszFormat[m_mipsiw.c_format.Format];
|
|
}
|
|
|
|
else
|
|
{
|
|
szFormat = "";
|
|
}
|
|
|
|
ostr << szMnemonic << szFormat;
|
|
|
|
for (size_t ioperand = 0; ioperand < 4; ioperand++)
|
|
{
|
|
OPCLS opcls = (OPCLS) rgcls[icls].rgopcls[ioperand];
|
|
|
|
if (opcls == opclsNone)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (ioperand == 0)
|
|
{
|
|
// Pad opcode field to 12 characters
|
|
|
|
size_t cch = strlen(szMnemonic) + strlen(szFormat);
|
|
|
|
do
|
|
{
|
|
ostr << ' ';
|
|
}
|
|
while (++cch < 12);
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << ',';
|
|
}
|
|
|
|
FormatOperand(ostr, opcls);
|
|
}
|
|
|
|
ostr.fill(chFill);
|
|
ostr.flags(lFlags);
|
|
}
|
|
|
|
|
|
DIS::MEMREFT DISMIPS::Memreft() const
|
|
{
|
|
ICLS icls = (ICLS) m_popcd->icls;
|
|
Assert(icls != iclsInvalid);
|
|
|
|
MEMREFT memreft;
|
|
|
|
switch ((OPCLS) rgcls[icls].rgopcls[1])
|
|
{
|
|
case opclsMem_w :
|
|
// UNDONE: Should SC return memreftOther?
|
|
|
|
memreft = memreftWrite;
|
|
break;
|
|
|
|
case opclsMem_r :
|
|
memreft = memreftRead;
|
|
break;
|
|
|
|
default :
|
|
memreft = memreftNone;
|
|
break;
|
|
}
|
|
|
|
return(memreft);
|
|
}
|
|
|
|
|
|
TRMT DISMIPS::Trmt() const
|
|
{
|
|
TRMTMIPS trmtmips = Trmtmips();
|
|
|
|
return(mptrmtmipstrmt[trmtmips]);
|
|
}
|
|
|
|
|
|
TRMTA DISMIPS::Trmta() const
|
|
{
|
|
TRMTMIPS trmtmips = Trmtmips();
|
|
|
|
return((TRMTA) trmtmips);
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
// Private Methods
|
|
// -----------------------------------------------------------------
|
|
|
|
void DISMIPS::FormatHex(ostream& ostr, DWORD dw) const
|
|
{
|
|
if (dw <= 9)
|
|
{
|
|
ostr << dw;
|
|
return;
|
|
}
|
|
|
|
ostr << "0x" << hex << dw;
|
|
}
|
|
|
|
|
|
void DISMIPS::FormatOperand(ostream& ostr, OPCLS opcls) const
|
|
{
|
|
size_t cch;
|
|
char szSymbol[1024];
|
|
DWORD dwDisp;
|
|
|
|
switch (opcls)
|
|
{
|
|
case opclsNone : // No operand
|
|
AssertSz(false, "Unexpected Mips operand class");
|
|
break;
|
|
|
|
case opclsRegRs : // General purpose register Rs
|
|
ostr << rgszGpr[m_mipsiw.r_format.Rs];
|
|
break;
|
|
|
|
case opclsRegRt : // General purpose register Rt
|
|
ostr << rgszGpr[m_mipsiw.r_format.Rt];
|
|
break;
|
|
|
|
case opclsRegRd : // General purpose register Rd
|
|
ostr << rgszGpr[m_mipsiw.r_format.Rd];
|
|
break;
|
|
|
|
case opclsImmRt : // Immediate value of Rt
|
|
FormatHex(ostr, m_mipsiw.r_format.Rt);
|
|
break;
|
|
|
|
case opclsImmRe : // Immediate value of Re
|
|
FormatHex(ostr, m_mipsiw.r_format.Re);
|
|
break;
|
|
|
|
case opclsImm : // Immediate value
|
|
if (m_pfncchfixup != 0)
|
|
{
|
|
cch = (*m_pfncchfixup)(this, m_addr, sizeof(WORD), szSymbol, sizeof(szSymbol), &dwDisp);
|
|
|
|
if (cch != 0)
|
|
{
|
|
ostr << szSymbol;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
ostr << '+';
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
FormatHex(ostr, m_mipsiw.u_format.Uimmediate);
|
|
break;
|
|
|
|
case opclsIndex :
|
|
ostr << rgszGpr[m_mipsiw.r_format.Rt];
|
|
ostr << '(' << rgszGpr[m_mipsiw.u_format.Rs] << ')';
|
|
break;
|
|
|
|
case opclsMem : // Memory reference
|
|
case opclsMem_w : // Memory read
|
|
case opclsMem_r : // Memory write
|
|
if (m_pfncchfixup != 0)
|
|
{
|
|
cch = (*m_pfncchfixup)(this, m_addr, sizeof(WORD), szSymbol, sizeof(szSymbol), &dwDisp);
|
|
|
|
if (cch != 0)
|
|
{
|
|
ostr << szSymbol;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
ostr << '+';
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
|
|
if (m_mipsiw.u_format.Rs != 0)
|
|
{
|
|
ostr << '(' << rgszGpr[m_mipsiw.u_format.Rs] << ')';
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwDisp = m_mipsiw.u_format.Uimmediate;
|
|
|
|
if ((dwDisp & 0x8000) != 0)
|
|
{
|
|
dwDisp |= 0xFFFF0000;
|
|
}
|
|
|
|
FormatRegRel(ostr, (REG) m_mipsiw.u_format.Rs, dwDisp);
|
|
break;
|
|
|
|
case opclsCc1 : // Floating point condition code
|
|
ostr << "$fcc" << (unsigned) (m_mipsiw.r_format.Rt >> 2);
|
|
break;
|
|
|
|
case opclsCc2 : // Floating point condition code
|
|
ostr << "$fcc" << (unsigned) (m_mipsiw.c_format.Fd >> 2);
|
|
break;
|
|
|
|
case opclsAddrBra : // Branch instruction target
|
|
case opclsAddrJmp : // Jump instruction target
|
|
if (m_pfncchaddr != 0)
|
|
{
|
|
cch = (*m_pfncchaddr)(this, AddrTarget(), szSymbol, sizeof(szSymbol), &dwDisp);
|
|
|
|
if (cch != 0)
|
|
{
|
|
ostr << szSymbol;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
ostr << '+';
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
ostr << hex << setw(8) << AddrTarget();
|
|
break;
|
|
|
|
case opclsCprRt : // Coprocessor general register Rt
|
|
ostr << '$' << (unsigned) m_mipsiw.r_format.Rt;
|
|
break;
|
|
|
|
case opclsCprRd : // Coprocessor general register Rd
|
|
ostr << '$' << (unsigned) m_mipsiw.r_format.Rd;
|
|
break;
|
|
|
|
case opclsRegFr : // Floating point general register Fr
|
|
ostr << "$f" << (unsigned) m_mipsiw.r_format.Rs;
|
|
break;
|
|
|
|
case opclsRegFs : // Floating point general register Fs
|
|
ostr << "$f" << (unsigned) m_mipsiw.c_format.Fs;
|
|
break;
|
|
|
|
case opclsRegFt : // Floating point general register Ft
|
|
ostr << "$f" << (unsigned) m_mipsiw.c_format.Ft;
|
|
break;
|
|
|
|
case opclsRegFd : // Floating point general register Fd
|
|
ostr << "$f" << (unsigned) m_mipsiw.c_format.Fd;
|
|
break;
|
|
|
|
default :
|
|
AssertSz(false, "Unexpected Mips operand class");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void DISMIPS::FormatRegRel(ostream& ostr, REG reg, DWORD dwDisp) const
|
|
{
|
|
if ((m_pfncchregrel != 0) && (reg != regZero))
|
|
{
|
|
char sz[1024];
|
|
|
|
size_t cch = (*m_pfncchregrel)(this, (int) reg, dwDisp, sz, sizeof(sz), &dwDisp);
|
|
|
|
if (cch != 0)
|
|
{
|
|
ostr << sz;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
ostr << '+';
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
FormatHex(ostr, (WORD) dwDisp);
|
|
|
|
if (reg != regZero)
|
|
{
|
|
ostr << '(' << rgszGpr[reg] << ')';
|
|
}
|
|
}
|
|
|
|
|
|
bool DISMIPS::FValidOperand(size_t ioperand) const
|
|
{
|
|
if (ioperand == 0)
|
|
{
|
|
// Implicit operand if any
|
|
|
|
return(true);
|
|
}
|
|
|
|
if (ioperand > 4)
|
|
{
|
|
return(false);
|
|
}
|
|
|
|
ICLS icls = (ICLS) m_popcd->icls;
|
|
Assert(icls != iclsInvalid);
|
|
|
|
OPCLS opcls = (OPCLS) rgcls[icls].rgopcls[ioperand-1];
|
|
|
|
return(opcls != opclsNone);
|
|
}
|
|
|
|
|
|
const DISMIPS::OPCD *DISMIPS::PopcdDecode(MIPSIW mipsiw)
|
|
{
|
|
const OPCD *popcd = rgopcd + mipsiw.j_format.Opcode;
|
|
|
|
if ((ICLS) popcd->icls == iclsInvalid)
|
|
{
|
|
switch (mipsiw.j_format.Opcode)
|
|
{
|
|
case 0x00 : // SPECIAL group
|
|
popcd = rgopcdSpecial + mipsiw.r_format.Function;
|
|
break;
|
|
|
|
case 0x01 : // REGIMM group
|
|
popcd = rgopcdRegimm + mipsiw.u_format.Rt;
|
|
break;
|
|
|
|
case 0x10 : // COP0 group
|
|
case 0x11 : // COP1 group
|
|
case 0x12 : // COP2 group
|
|
if (mipsiw.c_format.Fill1 == 0)
|
|
{
|
|
// This is in the common region for all coprocessors
|
|
|
|
if (mipsiw.c_format.Format == 0x08)
|
|
{
|
|
// BC group
|
|
|
|
popcd = rgopcdBc + (mipsiw.u_format.Rt & 3);
|
|
}
|
|
|
|
else
|
|
{
|
|
popcd = rgopcdCop + mipsiw.c_format.Format;
|
|
}
|
|
}
|
|
|
|
else if ((mipsiw.c_format.Opcode & 3) == 0)
|
|
{
|
|
// Coprocessor 0
|
|
|
|
popcd = rgopcdCp0 + mipsiw.c_format.Function;
|
|
}
|
|
|
|
else if ((mipsiw.c_format.Opcode & 3) == 1)
|
|
{
|
|
// Coprocessor 1 - Floating point
|
|
|
|
popcd = rgopcdCp1 + mipsiw.c_format.Function;
|
|
}
|
|
|
|
else
|
|
{
|
|
// There are no coprocessor 2 or 3 instructions
|
|
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case 0x13 : // COP1X group
|
|
popcd = rgopcdCop1x + mipsiw.r_format.Function;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
ICLS icls = (ICLS) popcd->icls;
|
|
|
|
switch (icls)
|
|
{
|
|
case iclsInvalid :
|
|
return(NULL);
|
|
|
|
case iclsImmBraCc3 :
|
|
case iclsImmBraCc4 :
|
|
if (mipsiw.u_format.Rt != 0)
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegister :
|
|
case iclsRegTrapCc :
|
|
case iclsRegShiftVar :
|
|
if (mipsiw.r_format.Re != 0)
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegJalr :
|
|
if ((mipsiw.r_format.Rt != 0) ||
|
|
(mipsiw.r_format.Re != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegJr :
|
|
case iclsRegMthi :
|
|
case iclsRegMtlo :
|
|
if ((mipsiw.r_format.Rd != 0) ||
|
|
(mipsiw.r_format.Rt != 0) ||
|
|
(mipsiw.r_format.Re != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegMfhi :
|
|
case iclsRegMflo :
|
|
if ((mipsiw.r_format.Rs != 0) ||
|
|
(mipsiw.r_format.Rt != 0) ||
|
|
(mipsiw.r_format.Re != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegMulDiv :
|
|
if ((mipsiw.r_format.Rd != 0) ||
|
|
(mipsiw.r_format.Re != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegShift :
|
|
if (mipsiw.u_format.Rs != 0)
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegSync :
|
|
case iclsRegSyscall :
|
|
if ((mipsiw.r_format.Rs != 0) ||
|
|
(mipsiw.r_format.Rt != 0) ||
|
|
(mipsiw.r_format.Rd != 0) ||
|
|
(mipsiw.r_format.Re != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegCtc :
|
|
case iclsRegMfc :
|
|
case iclsRegMtc :
|
|
if ((mipsiw.r_format.Re != 0) ||
|
|
(mipsiw.r_format.Function != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegCp0 :
|
|
case iclsRegEret :
|
|
if ((mipsiw.f_format.Format != 0) ||
|
|
(mipsiw.f_format.Rt != 0) ||
|
|
(mipsiw.f_format.Rd != 0) ||
|
|
(mipsiw.f_format.Re != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegFloat1 :
|
|
if ((mipsiw.c_format.Format != 0) &&
|
|
(mipsiw.c_format.Format != 1))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegFloat2 :
|
|
if (((mipsiw.c_format.Format != 0) &&
|
|
(mipsiw.c_format.Format != 1)) ||
|
|
(mipsiw.c_format.Ft != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegFloat3 :
|
|
if (((mipsiw.c_format.Format != 0) &&
|
|
(mipsiw.c_format.Format != 1)) ||
|
|
(mipsiw.c_format.Ft != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegFloat4 :
|
|
if (((mipsiw.c_format.Format != 1) &&
|
|
(mipsiw.c_format.Format != 4) &&
|
|
(mipsiw.c_format.Format != 5)) ||
|
|
(mipsiw.c_format.Ft != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegFloat5 :
|
|
if (((mipsiw.c_format.Format != 0) &&
|
|
(mipsiw.c_format.Format != 4) &&
|
|
(mipsiw.c_format.Format != 5)) ||
|
|
(mipsiw.c_format.Ft != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegFloat6 :
|
|
if (((mipsiw.c_format.Format != 0) &&
|
|
(mipsiw.c_format.Format != 1)) ||
|
|
((mipsiw.c_format.Fd & 0x3) != 0))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
|
|
case iclsRegFloat7 :
|
|
// UNDONE:
|
|
break;
|
|
|
|
case iclsRegFloat8 :
|
|
if (mipsiw.c_format.Ft & 2)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
// UNDONE:
|
|
break;
|
|
|
|
case iclsRegFloat10 :
|
|
if (((mipsiw.r_format.Function & 0x07) != 0) &&
|
|
((mipsiw.r_format.Function & 0x07) != 1))
|
|
{
|
|
return(NULL);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return(popcd);
|
|
}
|
|
|
|
|
|
const DISMIPS::OPCD *DISMIPS::PopcdPseudoOp(OPCD *popcd, char *szMnemonic) const
|
|
{
|
|
// Check for pseudo-instructions
|
|
|
|
if (m_mipsiw.dw == 0x00000000)
|
|
{
|
|
// This is a NOP instruction
|
|
|
|
return(&opcdNop);
|
|
}
|
|
|
|
if ((m_mipsiw.dw & 0xFFFF0000) == 0x10000000)
|
|
{
|
|
// This is a B (unconditional branch) instruction
|
|
|
|
return(&opcdB);
|
|
}
|
|
|
|
if (m_popcd->icls == iclsImmBraCc7)
|
|
{
|
|
if ((m_mipsiw.r_format.Rt >> 2) == 0)
|
|
{
|
|
popcd->szMnemonic = m_popcd->szMnemonic + 1;
|
|
popcd->icls = iclsImmBraCc8;
|
|
|
|
return(popcd);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
if (m_popcd->icls == iclsRegFloat6)
|
|
{
|
|
if ((m_mipsiw.c_format.Fd >> 2) == 0)
|
|
{
|
|
popcd->szMnemonic = m_popcd->szMnemonic + 1;
|
|
popcd->icls = iclsRegFloat9;
|
|
|
|
return(popcd);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
if (m_popcd->icls == iclsRegFloat8)
|
|
{
|
|
if (m_mipsiw.c_format.Ft & 1)
|
|
{
|
|
strcpy(szMnemonic, "@movt");
|
|
|
|
popcd->icls = iclsRegFloat8;
|
|
|
|
return(popcd);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
if (m_popcd->icls == iclsRegisterCc)
|
|
{
|
|
if (m_mipsiw.r_format.Rt & 1)
|
|
{
|
|
strcpy(szMnemonic, "movt");
|
|
|
|
popcd->icls = iclsRegisterCc;
|
|
|
|
return(popcd);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
TRMTMIPS DISMIPS::Trmtmips() const
|
|
{
|
|
ICLS icls = (ICLS) m_popcd->icls;
|
|
Assert(icls != iclsInvalid);
|
|
|
|
TRMTMIPS trmtmips = (TRMTMIPS) rgcls[icls].trmtmips;
|
|
|
|
if (((m_mipsiw.u_format.Opcode == 0x04) ||
|
|
(m_mipsiw.u_format.Opcode == 0x14)) &&
|
|
(m_mipsiw.u_format.Rs == m_mipsiw.u_format.Rt))
|
|
{
|
|
// This is really an unconditional branch
|
|
|
|
trmtmips = trmtmipsBraDef;
|
|
}
|
|
|
|
return(trmtmips);
|
|
}
|