mirror of
https://github.com/dborth/vbagx.git
synced 2024-12-27 11:11:50 +01:00
743 lines
21 KiB
C++
743 lines
21 KiB
C++
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
|
// Copyright (C) 1999-2003 Forgotten
|
|
// Copyright (C) 2005 Forgotten and the VBA development team
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2, or(at your option)
|
|
// any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software Foundation,
|
|
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
/************************************************************************/
|
|
/* Arm/Thumb command set disassembler */
|
|
/************************************************************************/
|
|
#include <stdio.h>
|
|
|
|
#include "System.h"
|
|
#include "Port.h"
|
|
#include "agb/GBA.h"
|
|
#include "armdis.h"
|
|
#include "elf.h"
|
|
|
|
struct Opcodes {
|
|
u32 mask;
|
|
u32 cval;
|
|
const char *mnemonic;
|
|
};
|
|
|
|
#define debuggerReadMemory(addr) \
|
|
READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
|
|
|
|
#define debuggerReadHalfWord(addr) \
|
|
READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
|
|
|
|
#define debuggerReadByte(addr) \
|
|
map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
|
|
|
|
const char hdig[] = "0123456789abcdef";
|
|
|
|
const char *decVals[16] = {
|
|
"0","1","2","3","4","5","6","7","8",
|
|
"9","10","11","12","13","14","15"
|
|
};
|
|
|
|
const char *regs[16] = {
|
|
"r0","r1","r2","r3","r4","r5","r6","r7",
|
|
"r8","r9","r10","r11","r12","sp","lr","pc"
|
|
};
|
|
|
|
const char *conditions[16] = {
|
|
"eq","ne","cs","cc","mi","pl","vs","vc",
|
|
"hi","ls","ge","lt","gt","le","","nv"
|
|
};
|
|
|
|
const char *shifts[5] = {
|
|
"lsl","lsr","asr","ror","rrx"
|
|
};
|
|
|
|
const char *armMultLoadStore[12] = {
|
|
// non-stack
|
|
"da","ia","db","ib",
|
|
// stack store
|
|
"ed","ea","fd","fa",
|
|
// stack load
|
|
"fa","fd","ea","ed"
|
|
};
|
|
|
|
const Opcodes thumbOpcodes[] = {
|
|
// Format 1
|
|
{0xf800, 0x0000, "lsl %r0, %r3, %o"},
|
|
{0xf800, 0x0800, "lsr %r0, %r3, %o"},
|
|
{0xf800, 0x1000, "asr %r0, %r3, %o"},
|
|
// Format 2
|
|
{0xfe00, 0x1800, "add %r0, %r3, %r6"},
|
|
{0xfe00, 0x1a00, "sub %r0, %r3, %r6"},
|
|
{0xfe00, 0x1c00, "add %r0, %r3, %i"},
|
|
{0xfe00, 0x1e00, "sub %r0, %r3, %i"},
|
|
// Format 3
|
|
{0xf800, 0x2000, "mov %r8, %O"},
|
|
{0xf800, 0x2800, "cmp %r8, %O"},
|
|
{0xf800, 0x3000, "add %r8, %O"},
|
|
{0xf800, 0x3800, "sub %r8, %O"},
|
|
// Format 4
|
|
{0xffc0, 0x4000, "and %r0, %r3"},
|
|
{0xffc0, 0x4040, "eor %r0, %r3"},
|
|
{0xffc0, 0x4080, "lsl %r0, %r3"},
|
|
{0xffc0, 0x40c0, "lsr %r0, %r3"},
|
|
{0xffc0, 0x4100, "asr %r0, %r3"},
|
|
{0xffc0, 0x4140, "adc %r0, %r3"},
|
|
{0xffc0, 0x4180, "sbc %r0, %r3"},
|
|
{0xffc0, 0x41c0, "ror %r0, %r3"},
|
|
{0xffc0, 0x4200, "tst %r0, %r3"},
|
|
{0xffc0, 0x4240, "neg %r0, %r3"},
|
|
{0xffc0, 0x4280, "cmp %r0, %r3"},
|
|
{0xffc0, 0x42c0, "cmn %r0, %r3"},
|
|
{0xffc0, 0x4300, "orr %r0, %r3"},
|
|
{0xffc0, 0x4340, "mul %r0, %r3"},
|
|
{0xffc0, 0x4380, "bic %r0, %r3"},
|
|
{0xffc0, 0x43c0, "mvn %r0, %r3"},
|
|
// Format 5
|
|
{0xff80, 0x4700, "bx %h36"},
|
|
{0xfcc0, 0x4400, "[ ??? ]"},
|
|
{0xff00, 0x4400, "add %h07, %h36"},
|
|
{0xff00, 0x4500, "cmp %h07, %h36"},
|
|
{0xff00, 0x4600, "mov %h07, %h36"},
|
|
// Format 6
|
|
{0xf800, 0x4800, "ldr %r8, [%I] (=%J)"},
|
|
// Format 7
|
|
{0xfa00, 0x5000, "str%b %r0, [%r3, %r6]"},
|
|
{0xfa00, 0x5800, "ldr%b %r0, [%r3, %r6]"},
|
|
// Format 8
|
|
{0xfe00, 0x5200, "strh %r0, [%r3, %r6]"},
|
|
{0xfe00, 0x5600, "ldsb %r0, [%r3, %r6]"},
|
|
{0xfe00, 0x5a00, "ldrh %r0, [%r3, %r6]"},
|
|
{0xfe00, 0x5e00, "ldsh %r0, [%r3, %r6]"},
|
|
// Format 9
|
|
{0xe800, 0x6000, "str%B %r0, [%r3, %p]"},
|
|
{0xe800, 0x6800, "ldr%B %r0, [%r3, %p]"},
|
|
// Format 10
|
|
{0xf800, 0x8000, "strh %r0, [%r3, %e]"},
|
|
{0xf800, 0x8800, "ldrh %r0, [%r3, %e]"},
|
|
// Format 11
|
|
{0xf800, 0x9000, "str %r8, [sp, %w]"},
|
|
{0xf800, 0x9800, "ldr %r8, [sp, %w]"},
|
|
// Format 12
|
|
{0xf800, 0xa000, "add %r8, pc, %w (=%K)"},
|
|
{0xf800, 0xa800, "add %r8, sp, %w"},
|
|
// Format 13
|
|
{0xff00, 0xb000, "add sp, %s"},
|
|
// Format 14
|
|
{0xffff, 0xb500, "push {lr}"},
|
|
{0xff00, 0xb400, "push {%l}"},
|
|
{0xff00, 0xb500, "push {%l,lr}"},
|
|
{0xffff, 0xbd00, "pop {pc}"},
|
|
{0xff00, 0xbd00, "pop {%l,pc}"},
|
|
{0xff00, 0xbc00, "pop {%l}"},
|
|
// Format 15
|
|
{0xf800, 0xc000, "stmia %r8!, {%l}"},
|
|
{0xf800, 0xc800, "ldmia %r8!, {%l}"},
|
|
// Format 17
|
|
{0xff00, 0xdf00, "swi %m"},
|
|
// Format 16
|
|
{0xf000, 0xd000, "b%c %W"},
|
|
// Format 18
|
|
{0xf800, 0xe000, "b %a"},
|
|
// Format 19
|
|
{0xf800, 0xf000, "bl %A"},
|
|
{0xf800, 0xf800, "blh %Z"},
|
|
{0xff00, 0xbe00, "bkpt %O"},
|
|
// Unknown
|
|
{0x0000, 0x0000, "[ ??? ]"}
|
|
};
|
|
|
|
const Opcodes armOpcodes[] = {
|
|
// Undefined
|
|
{0x0e000010, 0x06000010, "[ undefined ]"},
|
|
// Branch instructions
|
|
{0x0ff000f0, 0x01200010, "bx%c %r0"},
|
|
{0x0f000000, 0x0a000000, "b%c %o"},
|
|
{0x0f000000, 0x0b000000, "bl%c %o"},
|
|
{0x0f000000, 0x0f000000, "swi%c %q"},
|
|
// PSR transfer
|
|
{0x0fbf0fff, 0x010f0000, "mrs%c %r3, %p"},
|
|
{0x0db0f000, 0x0120f000, "msr%c %p, %i"},
|
|
// Multiply instructions
|
|
{0x0fe000f0, 0x00000090, "mul%c%s %r4, %r0, %r2"},
|
|
{0x0fe000f0, 0x00200090, "mla%c%s %r4, %r0, %r2, %r3"},
|
|
{0x0fa000f0, 0x00800090, "%umull%c%s %r3, %r4, %r0, %r2"},
|
|
{0x0fa000f0, 0x00a00090, "%umlal%c%s %r3, %r4, %r0, %r2"},
|
|
// Load/Store instructions
|
|
{0x0fb00ff0, 0x01000090, "swp%c%b %r3, %r0, [%r4]"},
|
|
{0x0fb000f0, 0x01000090, "[ ??? ]"},
|
|
{0x0c100000, 0x04000000, "str%c%b%t %r3, %a"},
|
|
{0x0c100000, 0x04100000, "ldr%c%b%t %r3, %a"},
|
|
{0x0e100090, 0x00000090, "str%c%h %r3, %a"},
|
|
{0x0e100090, 0x00100090, "ldr%c%h %r3, %a"},
|
|
{0x0e100000, 0x08000000, "stm%c%m %r4%l"},
|
|
{0x0e100000, 0x08100000, "ldm%c%m %r4%l"},
|
|
// Data processing
|
|
{0x0de00000, 0x00000000, "and%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x00200000, "eor%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x00400000, "sub%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x00600000, "rsb%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x00800000, "add%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x00a00000, "adc%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x00c00000, "sbc%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x00e00000, "rsc%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x01000000, "tst%c%s %r4, %i"},
|
|
{0x0de00000, 0x01200000, "teq%c%s %r4, %i"},
|
|
{0x0de00000, 0x01400000, "cmp%c%s %r4, %i"},
|
|
{0x0de00000, 0x01600000, "cmn%c%s %r4, %i"},
|
|
{0x0de00000, 0x01800000, "orr%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x01a00000, "mov%c%s %r3, %i"},
|
|
{0x0de00000, 0x01c00000, "bic%c%s %r3, %r4, %i"},
|
|
{0x0de00000, 0x01e00000, "mvn%c%s %r3, %i"},
|
|
// Coprocessor operations
|
|
{0x0f000010, 0x0e000000, "cdp%c %P, %N, %r3, %R4, %R0%V"},
|
|
{0x0e100000, 0x0c000000, "stc%c%L %P, %r3, %A"},
|
|
{0x0f100010, 0x0e000010, "mcr%c %P, %N, %r3, %R4, %R0%V"},
|
|
{0x0f100010, 0x0e100010, "mrc%c %P, %N, %r3, %R4, %R0%V"},
|
|
// Unknown
|
|
{0x00000000, 0x00000000, "[ ??? ]"}
|
|
};
|
|
|
|
char* addStr(char *dest, const char *src){
|
|
while (*src){
|
|
*dest++ = *src++;
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
char* addHex(char *dest, int siz, u32 val){
|
|
if (siz==0){
|
|
siz = 28;
|
|
while ( (((val>>siz)&15)==0) && (siz>=4) )
|
|
siz -= 4;
|
|
siz += 4;
|
|
}
|
|
while (siz>0){
|
|
siz -= 4;
|
|
*dest++ = hdig[(val>>siz)&15];
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
int disArm(u32 offset, char *dest, int flags){
|
|
u32 opcode = debuggerReadMemory(offset);
|
|
|
|
const Opcodes *sp = armOpcodes;
|
|
while( sp->cval != (opcode & sp->mask) )
|
|
sp++;
|
|
|
|
if (flags&DIS_VIEW_ADDRESS){
|
|
dest = addHex(dest, 32, offset);
|
|
*dest++ = ' ';
|
|
}
|
|
if (flags&DIS_VIEW_CODE){
|
|
dest = addHex(dest, 32, opcode);
|
|
*dest++ = ' ';
|
|
}
|
|
|
|
const char *src = sp->mnemonic;
|
|
while (*src){
|
|
if (*src!='%')
|
|
*dest++ = *src++;
|
|
else{
|
|
src++;
|
|
switch (*src){
|
|
case 'c':
|
|
dest = addStr(dest, conditions[opcode>>28]);
|
|
break;
|
|
case 'r':
|
|
dest = addStr(dest, regs[(opcode>>((*(++src)-'0')*4))&15]);
|
|
break;
|
|
case 'o':
|
|
{
|
|
*dest++ = '$';
|
|
int off = opcode&0xffffff;
|
|
if (off&0x800000)
|
|
off |= 0xff000000;
|
|
off <<= 2;
|
|
dest = addHex(dest, 32, offset+8+off);
|
|
}
|
|
break;
|
|
case 'i':
|
|
if (opcode&(1<<25)){
|
|
dest = addStr(dest, "#0x");
|
|
int imm = opcode&0xff;
|
|
int rot = (opcode&0xf00)>>7;
|
|
int val = (imm<<(32-rot))|(imm>>rot);
|
|
dest = addHex(dest, 0, val);
|
|
} else{
|
|
dest = addStr(dest, regs[opcode&0x0f]);
|
|
int shi = (opcode>>5)&3;
|
|
int sdw = (opcode>>7)&0x1f;
|
|
if ((sdw==0)&&(shi==3))
|
|
shi = 4;
|
|
if ( (sdw) || (opcode&0x10) || (shi)) {
|
|
dest = addStr(dest, ", ");
|
|
dest = addStr(dest, shifts[shi]);
|
|
if (opcode&0x10){
|
|
*dest++ = ' ';
|
|
dest = addStr(dest, regs[(opcode>>8)&15]);
|
|
} else {
|
|
if (sdw==0 && ( (shi==1) || (shi==2) ))
|
|
sdw = 32;
|
|
if(shi != 4) {
|
|
dest = addStr(dest, " #0x");
|
|
dest = addHex(dest, 8, sdw);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 'p':
|
|
if (opcode&(1<<22))
|
|
dest = addStr(dest, "spsr");
|
|
else
|
|
dest = addStr(dest, "cpsr");
|
|
if(opcode & 0x00F00000) {
|
|
*dest++ = '_';
|
|
if(opcode & 0x00080000)
|
|
*dest++ = 'f';
|
|
if(opcode & 0x00040000)
|
|
*dest++ = 's';
|
|
if(opcode & 0x00020000)
|
|
*dest++ = 'x';
|
|
if(opcode & 0x00010000)
|
|
*dest++ = 'c';
|
|
}
|
|
break;
|
|
case 's':
|
|
if (opcode&(1<<20))
|
|
*dest++ = 's';
|
|
break;
|
|
case 'S':
|
|
if (opcode&(1<<22))
|
|
*dest++ = 's';
|
|
break;
|
|
case 'u':
|
|
if (opcode&(1<<22))
|
|
*dest++ = 's';
|
|
else
|
|
*dest++ = 'u';
|
|
break;
|
|
case 'b':
|
|
if (opcode&(1<<22))
|
|
*dest++ = 'b';
|
|
break;
|
|
case 'a':
|
|
if ((opcode&0x076f0000)==0x004f0000){
|
|
*dest++ = '[';
|
|
*dest++ = '$';
|
|
int adr = offset+8;
|
|
int add = (opcode&15)|((opcode>>8)&0xf0);
|
|
if (opcode&(1<<23))
|
|
adr += add;
|
|
else
|
|
adr -= add;
|
|
dest = addHex(dest, 32, adr);
|
|
*dest++ = ']';
|
|
dest = addStr(dest, " (=");
|
|
*dest++ = '$';
|
|
dest = addHex(dest ,32, debuggerReadMemory(adr));
|
|
*dest++=')';
|
|
}
|
|
if ((opcode&0x072f0000)==0x050f0000){
|
|
*dest++ = '[';
|
|
*dest++ = '$';
|
|
int adr = offset+8;
|
|
if (opcode&(1<<23))
|
|
adr += opcode&0xfff;
|
|
else
|
|
adr -= opcode&0xfff;
|
|
dest = addHex(dest, 32, adr);
|
|
*dest++ = ']';
|
|
dest = addStr(dest, " (=");
|
|
*dest++ = '$';
|
|
dest = addHex(dest ,32, debuggerReadMemory(adr));
|
|
*dest++=')';
|
|
} else {
|
|
int reg = (opcode>>16)&15;
|
|
*dest++ = '[';
|
|
dest = addStr(dest, regs[reg]);
|
|
if (!(opcode&(1<<24)))
|
|
*dest++ = ']';
|
|
if ( ((opcode&(1<<25))&&(opcode&(1<<26))) || (!(opcode&(1<<22))&&!(opcode&(1<<26))) ){
|
|
dest = addStr(dest, ", ");
|
|
if (!(opcode&(1<<23)))
|
|
*dest++ = '-';
|
|
dest = addStr(dest, regs[opcode&0x0f]);
|
|
int shi = (opcode>>5)&3;
|
|
if (opcode&(1<<26)){
|
|
if ( ((opcode>>7)&0x1f) || (opcode&0x10) || (shi==1) || (shi==2)){
|
|
dest = addStr(dest, ", ");
|
|
dest = addStr(dest, shifts[shi]);
|
|
if (opcode&0x10){
|
|
*dest++ = ' ';
|
|
dest = addStr(dest, regs[(opcode>>8)&15]);
|
|
} else {
|
|
int sdw = (opcode>>7)&0x1f;
|
|
if (sdw==0 && ( (shi==1) || (shi==2) ))
|
|
sdw = 32;
|
|
dest = addStr(dest, " #0x");
|
|
dest = addHex(dest, 8, sdw);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
int off;
|
|
if (opcode&(1<<26))
|
|
off = opcode&0xfff;
|
|
else
|
|
off = (opcode&15)|((opcode>>4)&0xf0);
|
|
if (off){
|
|
dest = addStr(dest, ", ");
|
|
if (!(opcode&(1<<23)))
|
|
*dest++ = '-';
|
|
dest = addStr(dest, "#0x");
|
|
dest = addHex(dest, 0, off);
|
|
}
|
|
}
|
|
if (opcode&(1<<24)){
|
|
*dest++ = ']';
|
|
if (opcode&(1<<21))
|
|
*dest++ = '!';
|
|
}
|
|
}
|
|
break;
|
|
case 't':
|
|
if ((opcode&0x01200000)==0x01200000)
|
|
*dest++ = 't';
|
|
break;
|
|
case 'h':
|
|
if (opcode&(1<<6))
|
|
*dest++ = 's';
|
|
if (opcode&(1<<5))
|
|
*dest++ = 'h';
|
|
else
|
|
*dest++ = 'b';
|
|
break;
|
|
case 'm':
|
|
if (((opcode>>16)&15)==13) {
|
|
if(opcode & 0x00100000)
|
|
dest = addStr(dest, armMultLoadStore[8+((opcode>>23)&3)]);
|
|
else
|
|
dest = addStr(dest, armMultLoadStore[4+((opcode>>23)&3)]);
|
|
} else
|
|
dest = addStr(dest, armMultLoadStore[(opcode>>23)&3]);
|
|
break;
|
|
case 'l':
|
|
if (opcode&(1<<21))
|
|
*dest++ = '!';
|
|
dest = addStr(dest, ", {");
|
|
{
|
|
int rlst = opcode&0xffff;
|
|
int msk = 0;
|
|
int not_first = 0;
|
|
while (msk<16){
|
|
if (rlst&(1<<msk)){
|
|
int fr = msk;
|
|
while (rlst&(1<<msk))
|
|
msk++;
|
|
int to = msk-1;
|
|
if (not_first)
|
|
//dest = addStr(dest, ", ");
|
|
*dest++ = ',';
|
|
dest = addStr(dest, regs[fr]);
|
|
if (fr!=to){
|
|
if (fr==to-1)
|
|
//dest = addStr(", ");
|
|
*dest++ = ',';
|
|
else
|
|
*dest++ = '-';
|
|
dest = addStr(dest, regs[to]);
|
|
}
|
|
not_first = 1;
|
|
} else
|
|
msk++;
|
|
}
|
|
*dest++ = '}';
|
|
if (opcode&(1<<22))
|
|
*dest++ = '^';
|
|
}
|
|
break;
|
|
case 'q':
|
|
*dest++ = '$';
|
|
dest = addHex(dest, 24, opcode&0xffffff);
|
|
break;
|
|
case 'P':
|
|
*dest++ = 'p';
|
|
dest = addStr(dest, decVals[(opcode>>8)&15]);
|
|
break;
|
|
case 'N':
|
|
if (opcode&0x10)
|
|
dest = addStr(dest, decVals[(opcode>>21)&7]);
|
|
else
|
|
dest = addStr(dest, decVals[(opcode>>20)&15]);
|
|
break;
|
|
case 'R':
|
|
{
|
|
src++;
|
|
int reg = 4*(*src-'0');
|
|
*dest++ = 'c';
|
|
dest = addStr(dest, decVals[(opcode>>reg)&15]);
|
|
}
|
|
break;
|
|
case 'V':
|
|
{
|
|
int val = (opcode>>5)&7;
|
|
if (val){
|
|
dest = addStr(dest, ", ");
|
|
dest = addStr(dest, decVals[val]);
|
|
}
|
|
}
|
|
break;
|
|
case 'L':
|
|
if (opcode&(1<<22))
|
|
*dest++ = 'l';
|
|
break;
|
|
case 'A':
|
|
if ((opcode&0x012f0000)==0x010f0000){
|
|
int adr = offset+8;
|
|
int add = (opcode&0xff)<<2;
|
|
if (opcode&(1<<23))
|
|
adr += add;
|
|
else
|
|
adr -= add;
|
|
*dest++ = '$';
|
|
addHex(dest, 32, adr);
|
|
} else {
|
|
*dest++ = '[';
|
|
dest = addStr(dest, regs[(opcode>>16)&15]);
|
|
if (!(opcode&(1<<24)))
|
|
*dest++ = ']';
|
|
int off = (opcode&0xff)<<2;
|
|
if (off){
|
|
dest = addStr(dest, ", ");
|
|
if (!(opcode&(1<<23)))
|
|
*dest++ = '-';
|
|
dest = addStr(dest, "#0x");
|
|
dest = addHex(dest, 0, off);
|
|
}
|
|
if (opcode&(1<<24)){
|
|
*dest++ = ']';
|
|
if (opcode&(1<<21))
|
|
*dest++ = '!';
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
src++;
|
|
}
|
|
}
|
|
*dest++ = 0;
|
|
|
|
return 4;
|
|
}
|
|
|
|
int disThumb(u32 offset, char *dest, int flags){
|
|
u32 opcode = debuggerReadHalfWord(offset);
|
|
|
|
const Opcodes *sp = thumbOpcodes;
|
|
int ret = 2;
|
|
while( sp->cval != (opcode & sp->mask) )
|
|
sp++;
|
|
|
|
if (flags&DIS_VIEW_ADDRESS){
|
|
dest = addHex(dest, 32, offset);
|
|
*dest++ = ' ';
|
|
}
|
|
if (flags&DIS_VIEW_CODE){
|
|
dest = addHex(dest, 16, opcode);
|
|
*dest++ = ' ';
|
|
}
|
|
|
|
const char *src = sp->mnemonic;
|
|
while (*src){
|
|
if (*src!='%')
|
|
*dest++ = *src++;
|
|
else {
|
|
src++;
|
|
switch (*src){
|
|
case 'r':
|
|
src++;
|
|
dest = addStr(dest, regs[(opcode>>(*src-'0'))&7]);
|
|
break;
|
|
case 'o':
|
|
dest = addStr(dest, "#0x");
|
|
{
|
|
int val = (opcode>>6)&0x1f;
|
|
dest = addHex(dest, 8, val);
|
|
}
|
|
break;
|
|
case 'p':
|
|
dest = addStr(dest, "#0x");
|
|
{
|
|
int val = (opcode>>6)&0x1f;
|
|
if (!(opcode&(1<<12)))
|
|
val <<= 2;
|
|
dest = addHex(dest, 0, val);
|
|
}
|
|
break;
|
|
case 'e':
|
|
dest = addStr(dest, "#0x");
|
|
dest = addHex(dest, 0, ((opcode>>6)&0x1f)<<1);
|
|
break;
|
|
case 'i':
|
|
dest = addStr(dest, "#0x");
|
|
dest = addHex(dest, 0, (opcode>>6)&7);
|
|
break;
|
|
case 'h':
|
|
{
|
|
src++;
|
|
int reg = (opcode>>(*src-'0'))&7;
|
|
src++;
|
|
if (opcode&(1<<(*src-'0')))
|
|
reg += 8;
|
|
dest = addStr(dest, regs[reg]);
|
|
}
|
|
break;
|
|
case 'O':
|
|
dest = addStr(dest, "#0x");
|
|
dest = addHex(dest, 0, (opcode&0xff));
|
|
break;
|
|
case 'I':
|
|
*dest++ = '$';
|
|
dest = addHex(dest, 32, (offset&0xfffffffc)+4+((opcode&0xff)<<2));
|
|
break;
|
|
case 'J':
|
|
{
|
|
u32 value = debuggerReadMemory((offset&0xfffffffc)+4+
|
|
((opcode & 0xff)<<2));
|
|
*dest++ = '$';
|
|
dest = addHex(dest, 32, value);
|
|
const char *s = elfGetAddressSymbol(value);
|
|
if(*s) {
|
|
*dest++ = ' ';
|
|
dest = addStr(dest, s);
|
|
}
|
|
}
|
|
break;
|
|
case 'K':
|
|
{
|
|
u32 value = (offset&0xfffffffc)+4+((opcode & 0xff)<<2);
|
|
*dest++ = '$';
|
|
dest = addHex(dest, 32, value);
|
|
const char *s = elfGetAddressSymbol(value);
|
|
if(*s) {
|
|
*dest++ = ' ';
|
|
dest = addStr(dest, s);
|
|
}
|
|
}
|
|
break;
|
|
case 'b':
|
|
if (opcode&(1<<10))
|
|
*dest++ = 'b';
|
|
break;
|
|
case 'B':
|
|
if (opcode&(1<<12))
|
|
*dest++ = 'b';
|
|
break;
|
|
case 'w':
|
|
dest = addStr(dest, "#0x");
|
|
dest = addHex(dest, 0, (opcode&0xff)<<2);
|
|
break;
|
|
case 'W':
|
|
*dest++ = '$';
|
|
{
|
|
int add = opcode&0xff;
|
|
if (add&0x80)
|
|
add |= 0xffffff00;
|
|
dest = addHex(dest, 32, (offset&0xfffffffe)+4+(add<<1));
|
|
}
|
|
break;
|
|
case 'c':
|
|
dest = addStr(dest, conditions[(opcode>>8)&15]);
|
|
break;
|
|
case 's':
|
|
if (opcode&(1<<7))
|
|
*dest++ = '-';
|
|
dest = addStr(dest, "#0x");
|
|
dest = addHex(dest, 0, (opcode&0x7f)<<2);
|
|
break;
|
|
case 'l':
|
|
{
|
|
int rlst = opcode&0xff;
|
|
int msk = 0;
|
|
int not_first = 0;
|
|
while (msk<8){
|
|
if (rlst&(1<<msk)){
|
|
int fr = msk;
|
|
while (rlst&(1<<msk))
|
|
msk++;
|
|
int to = msk-1;
|
|
if (not_first)
|
|
*dest++ = ',';
|
|
dest = addStr(dest, regs[fr]);
|
|
if (fr!=to){
|
|
if (fr==to-1)
|
|
*dest++ = ',';
|
|
else
|
|
*dest++ = '-';
|
|
dest = addStr(dest, regs[to]);
|
|
}
|
|
not_first = 1;
|
|
} else
|
|
msk++;
|
|
}
|
|
}
|
|
break;
|
|
case 'm':
|
|
*dest++ = '$';
|
|
dest = addHex(dest, 8, opcode&0xff);
|
|
break;
|
|
case 'Z':
|
|
*dest++ = '$';
|
|
dest = addHex(dest, 16, (opcode&0x7ff)<<1);
|
|
break;
|
|
case 'a':
|
|
*dest++ = '$';
|
|
{
|
|
int add = opcode&0x07ff;
|
|
if (add&0x400)
|
|
add |= 0xfffff800;
|
|
add <<= 1;
|
|
dest = addHex(dest, 32, offset+4+add);
|
|
}
|
|
break;
|
|
case 'A':
|
|
{
|
|
int nopcode = debuggerReadHalfWord(offset+2);
|
|
int add = opcode&0x7ff;
|
|
if (add&0x400)
|
|
add |= 0xfff800;
|
|
add = (add<<12)|((nopcode&0x7ff)<<1);
|
|
*dest++ = '$';
|
|
dest = addHex(dest,32, offset+4+add);
|
|
const char *s = elfGetAddressSymbol(offset+4+add);
|
|
if(*s) {
|
|
*dest++ = ' ';
|
|
*dest++ = '(';
|
|
dest = addStr(dest, s);
|
|
*dest++ = ')';
|
|
}
|
|
ret = 4;
|
|
}
|
|
break;
|
|
}
|
|
src++;
|
|
}
|
|
}
|
|
*dest++ = 0;
|
|
return ret;
|
|
}
|