WinUAE/disasm.cpp

2108 lines
50 KiB
C++

#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "debug.h"
#include "memory.h"
#include "newcpu.h"
#include "fpp.h"
#include "debugmem.h"
#include "disasm.h"
struct cpum2c m2cregs[] = {
{ 0, _T("SFC") },
{ 1, _T("DFC") },
{ 2, _T("CACR") },
{ 3, _T("TC") },
{ 4, _T("ITT0") },
{ 5, _T("ITT1") },
{ 6, _T("DTT0") },
{ 7, _T("DTT1") },
{ 8, _T("BUSC") },
{ 0x800, _T("USP") },
{ 0x801, _T("VBR") },
{ 0x802, _T("CAAR") },
{ 0x803, _T("MSP") },
{ 0x804, _T("ISP") },
{ 0x805, _T("MMUS") },
{ 0x806, _T("URP") },
{ 0x807, _T("SRP") },
{ 0x808, _T("PCR") },
{ -1, NULL }
};
const TCHAR *fpsizes[] = {
_T("L"),
_T("S"),
_T("X"),
_T("P"),
_T("W"),
_T("D"),
_T("B"),
_T("P")
};
static const int fpsizeconv[] = {
sz_long,
sz_single,
sz_extended,
sz_packed,
sz_word,
sz_double,
sz_byte,
sz_packed
};
static const int datasizes[] = {
1,
2,
4,
4,
8,
12,
12
};
static void showea_val(TCHAR *buffer, uae_u16 opcode, uaecptr addr, int size)
{
struct mnemolookup *lookup;
struct instr *table = &table68k[opcode];
if (addr >= 0xe90000 && addr < 0xf00000)
goto skip;
if (addr >= 0xdff000 && addr < 0xe00000)
goto skip;
for (lookup = lookuptab; lookup->mnemo != table->mnemo; lookup++)
;
if (!(lookup->flags & 1))
goto skip;
buffer += _tcslen(buffer);
if (debug_safe_addr(addr, datasizes[size])) {
bool cached = false;
switch (size)
{
case sz_byte:
{
uae_u8 v = get_byte_cache_debug(addr, &cached);
uae_u8 v2 = v;
if (cached)
v2 = get_byte_debug(addr);
if (v != v2) {
_stprintf(buffer, _T(" [%02x:%02x]"), v, v2);
} else {
_stprintf(buffer, _T(" [%s%02x]"), cached ? _T("*") : _T(""), v);
}
}
break;
case sz_word:
{
uae_u16 v = get_word_cache_debug(addr, &cached);
uae_u16 v2 = v;
if (cached)
v2 = get_word_debug(addr);
if (v != v2) {
_stprintf(buffer, _T(" [%04x:%04x]"), v, v2);
} else {
_stprintf(buffer, _T(" [%s%04x]"), cached ? _T("*") : _T(""), v);
}
}
break;
case sz_long:
{
uae_u32 v = get_long_cache_debug(addr, &cached);
uae_u32 v2 = v;
if (cached)
v2 = get_long_debug(addr);
if (v != v2) {
_stprintf(buffer, _T(" [%08x:%08x]"), v, v2);
} else {
_stprintf(buffer, _T(" [%s%08x]"), cached ? _T("*") : _T(""), v);
}
}
break;
case sz_single:
{
fpdata fp;
fpp_to_single(&fp, get_long_debug(addr));
_stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
}
break;
case sz_double:
{
fpdata fp;
fpp_to_double(&fp, get_long_debug(addr), get_long_debug(addr + 4));
_stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
}
break;
case sz_extended:
{
fpdata fp;
fpp_to_exten(&fp, get_long_debug(addr), get_long_debug(addr + 4), get_long_debug(addr + 8));
_stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
break;
}
case sz_packed:
_stprintf(buffer, _T("[%08x%08x%08x]"), get_long_debug(addr), get_long_debug(addr + 4), get_long_debug(addr + 8));
break;
}
}
skip:
for (int i = 0; i < size; i++) {
TCHAR name[256];
if (debugmem_get_symbol(addr + i, name, sizeof(name) / sizeof(TCHAR))) {
_stprintf(buffer + _tcslen(buffer), _T(" %s"), name);
}
}
}
uaecptr ShowEA_disp(uaecptr *pcp, uaecptr base, TCHAR *buffer, const TCHAR *name)
{
uaecptr addr;
uae_u16 dp;
int r;
uae_u32 dispreg;
uaecptr pc = *pcp;
TCHAR mult[20];
TCHAR *p = NULL;
dp = get_iword_debug(pc);
pc += 2;
r = (dp & 0x7000) >> 12; // REGISTER
dispreg = dp & 0x8000 ? m68k_areg(regs, r) : m68k_dreg(regs, r);
if (!(dp & 0x800)) { // W/L
dispreg = (uae_s32)(uae_s16)(dispreg);
}
if (currprefs.cpu_model >= 68020) {
dispreg <<= (dp >> 9) & 3; // SCALE
}
int m = 1 << ((dp >> 9) & 3);
mult[0] = 0;
if (m > 1 && buffer) {
_stprintf(mult, _T("*%d"), m);
}
if (buffer)
buffer[0] = 0;
if ((dp & 0x100) && currprefs.cpu_model >= 68020) {
TCHAR dr[20];
// Full format extension (68020+)
uae_s32 outer = 0, disp = 0;
if (dp & 0x80) { // BS (base register suppress)
base = 0;
if (buffer)
name = NULL;
}
if (buffer)
_stprintf(dr, _T("%c%d.%c"), dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W');
if (dp & 0x40) { // IS (index suppress)
dispreg = 0;
dr[0] = 0;
}
if (buffer) {
_tcscpy(buffer, _T("("));
p = buffer + _tcslen(buffer);
if (dp & 3) {
// indirect
_stprintf(p, _T("["));
p += _tcslen(p);
} else {
// (an,dn,word/long)
if (name) {
_stprintf(p, _T("%s,"), name);
p += _tcslen(p);
}
if (dr[0]) {
_stprintf(p, _T("%s%s,"), dr, mult);
p += _tcslen(p);
}
}
}
if ((dp & 0x30) == 0x20) { // BD SIZE = 2 (WORD)
disp = (uae_s32)(uae_s16)get_iword_debug(pc);
if (buffer) {
_stprintf(p, _T("$%04x,"), (uae_s16)disp);
p += _tcslen(p);
}
pc += 2;
base += disp;
} else if ((dp & 0x30) == 0x30) { // BD SIZE = 3 (LONG)
disp = get_ilong_debug(pc);
if (buffer) {
_stprintf(p, _T("$%08x,"), disp);
p += _tcslen(p);
}
pc += 4;
base += disp;
}
if ((dp & 3) && buffer) {
if (name) {
_stprintf(p, _T("%s,"), name);
p += _tcslen(p);
}
if (!(dp & 0x04)) {
if (dr[0]) {
_stprintf(p, _T("%s%s,"), dr, mult);
p += _tcslen(p);
}
}
if (p[-1] == ',')
p--;
_stprintf(p, _T("],"));
p += _tcslen(p);
if ((dp & 0x04)) {
if (dr[0]) {
_stprintf(p, _T("%s%s,"), dr, mult);
p += _tcslen(p);
}
}
}
if ((dp & 0x03) == 0x02) {
outer = (uae_s32)(uae_s16)get_iword_debug(pc);
if (buffer) {
_stprintf(p, _T("$%04x,"), (uae_s16)outer);
p += _tcslen(p);
}
pc += 2;
} else if ((dp & 0x03) == 0x03) {
outer = get_ilong_debug(pc);
if (buffer) {
_stprintf(p, _T("$%08x,"), outer);
p += _tcslen(p);
}
pc += 4;
}
if (buffer) {
if (p[-1] == ',')
p--;
_stprintf(p, _T(")"));
p += _tcslen(p);
}
if ((dp & 0x4) == 0)
base += dispreg;
if (dp & 0x3)
base = get_long_debug(base);
if (dp & 0x4)
base += dispreg;
addr = base + outer;
if (buffer) {
_stprintf(p, _T(" == $%08x"), addr);
p += _tcslen(p);
}
} else {
// Brief format extension
TCHAR regstr[20];
uae_s8 disp8 = dp & 0xFF;
regstr[0] = 0;
_stprintf(regstr, _T(",%c%d.%c"), dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W');
addr = base + (uae_s32)((uae_s8)disp8) + dispreg;
if (buffer) {
_stprintf(buffer, _T("(%s%s%s,$%02x) == $%08x"), name, regstr, mult, (uae_u8)disp8, addr);
if (dp & 0x100) {
_tcscat(buffer, _T(" (68020+)"));
}
}
}
*pcp = pc;
return addr;
}
uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode, wordsizes size, TCHAR *buf, uae_u32 *eaddr, int safemode)
{
uaecptr addr = pc;
uae_s16 disp16;
uae_s32 offset = 0;
TCHAR buffer[80];
if ((opcode & 0xf0ff) == 0x60ff && currprefs.cpu_model < 68020) {
// bcc.l is bcc.s if 68000/68010
mode = immi;
}
buffer[0] = 0;
switch (mode){
case Dreg:
_stprintf (buffer, _T("D%d"), reg);
break;
case Areg:
_stprintf (buffer, _T("A%d"), reg);
break;
case Aind:
_stprintf (buffer, _T("(A%d)"), reg);
addr = regs.regs[reg + 8];
showea_val(buffer, opcode, addr, size);
break;
case Aipi:
_stprintf (buffer, _T("(A%d)+"), reg);
addr = regs.regs[reg + 8];
showea_val(buffer, opcode, addr, size);
break;
case Apdi:
_stprintf (buffer, _T("-(A%d)"), reg);
addr = regs.regs[reg + 8];
showea_val(buffer, opcode, addr - datasizes[size], size);
break;
case Ad16:
{
TCHAR offtxt[8];
disp16 = get_iword_debug (pc); pc += 2;
if (disp16 < 0)
_stprintf (offtxt, _T("-$%04x"), -disp16);
else
_stprintf (offtxt, _T("$%04x"), disp16);
addr = m68k_areg (regs, reg) + disp16;
_stprintf (buffer, _T("(A%d,%s) == $%08x"), reg, offtxt, addr);
showea_val(buffer, opcode, addr, size);
}
break;
case Ad8r:
{
TCHAR name[10];
_stprintf(name, _T("A%d"), reg);
addr = ShowEA_disp(&pc, m68k_areg(regs, reg), buffer, name);
showea_val(buffer, opcode, addr, size);
}
break;
case PC16:
disp16 = get_iword_debug (pc); pc += 2;
addr += (uae_s16)disp16;
_stprintf (buffer, _T("(PC,$%04x) == $%08x"), disp16 & 0xffff, addr);
showea_val(buffer, opcode, addr, size);
break;
case PC8r:
{
addr = ShowEA_disp(&pc, addr, buffer, _T("PC"));
showea_val(buffer, opcode, addr, size);
}
break;
case absw:
addr = (uae_s32)(uae_s16)get_iword_debug (pc);
_stprintf (buffer, _T("$%04x"), (uae_u16)addr);
pc += 2;
showea_val(buffer, opcode, addr, size);
break;
case absl:
addr = get_ilong_debug (pc);
_stprintf (buffer, _T("$%08x"), addr);
pc += 4;
showea_val(buffer, opcode, addr, size);
break;
case imm:
switch (size){
case sz_byte:
_stprintf (buffer, _T("#$%02x"), (get_iword_debug (pc) & 0xff));
pc += 2;
break;
case sz_word:
_stprintf (buffer, _T("#$%04x"), (get_iword_debug (pc) & 0xffff));
pc += 2;
break;
case sz_long:
_stprintf(buffer, _T("#$%08x"), (get_ilong_debug(pc)));
pc += 4;
break;
case sz_single:
{
fpdata fp;
fpp_to_single(&fp, get_ilong_debug(pc));
_stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
pc += 4;
}
break;
case sz_double:
{
fpdata fp;
fpp_to_double(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4));
_stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
pc += 8;
}
break;
case sz_extended:
{
fpdata fp;
fpp_to_exten(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
_stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
pc += 12;
break;
}
case sz_packed:
_stprintf(buffer, _T("#$%08x%08x%08x"), get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
pc += 12;
break;
default:
break;
}
break;
case imm0:
offset = (uae_s32)(uae_s8)get_iword_debug (pc);
_stprintf (buffer, _T("#$%02x"), (uae_u32)(offset & 0xff));
addr = pc + 2 + offset;
if ((opcode & 0xf000) == 0x6000) {
showea_val(buffer, opcode, addr, 1);
}
pc += 2;
break;
case imm1:
offset = (uae_s32)(uae_s16)get_iword_debug (pc);
buffer[0] = 0;
_stprintf (buffer, _T("#$%04x"), (uae_u32)(offset & 0xffff));
addr = pc + offset;
if ((opcode & 0xf000) == 0x6000) {
showea_val(buffer, opcode, addr, 2);
}
pc += 2;
break;
case imm2:
offset = (uae_s32)get_ilong_debug (pc);
_stprintf (buffer, _T("#$%08x"), (uae_u32)offset);
addr = pc + offset;
if ((opcode & 0xf000) == 0x6000) {
showea_val(buffer, opcode, addr, 4);
}
pc += 4;
break;
case immi:
offset = (uae_s32)(uae_s8)(reg & 0xff);
_stprintf (buffer, _T("#$%02x"), (uae_u8)offset);
addr = pc + offset;
break;
default:
break;
}
if (buf == NULL)
f_out (f, _T("%s"), buffer);
else
_tcscat (buf, buffer);
if (eaddr)
*eaddr = addr;
return pc;
}
static const TCHAR *ccnames[] =
{
_T("T "),_T("F "),_T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"),
_T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE")
};
static const TCHAR *fpccnames[] =
{
_T("F"),
_T("EQ"),
_T("OGT"),
_T("OGE"),
_T("OLT"),
_T("OLE"),
_T("OGL"),
_T("OR"),
_T("UN"),
_T("UEQ"),
_T("UGT"),
_T("UGE"),
_T("ULT"),
_T("ULE"),
_T("NE"),
_T("T"),
_T("SF"),
_T("SEQ"),
_T("GT"),
_T("GE"),
_T("LT"),
_T("LE"),
_T("GL"),
_T("GLE"),
_T("NGLE"),
_T("NGL"),
_T("NLE"),
_T("NLT"),
_T("NGE"),
_T("NGT"),
_T("SNE"),
_T("ST")
};
const TCHAR *fpuopcodes[] =
{
_T("FMOVE"),
_T("FINT"),
_T("FSINH"),
_T("FINTRZ"),
_T("FSQRT"),
NULL,
_T("FLOGNP1"),
NULL,
_T("FETOXM1"),
_T("FTANH"),
_T("FATAN"),
NULL,
_T("FASIN"),
_T("FATANH"),
_T("FSIN"),
_T("FTAN"),
_T("FETOX"), // 0x10
_T("FTWOTOX"),
_T("FTENTOX"),
NULL,
_T("FLOGN"),
_T("FLOG10"),
_T("FLOG2"),
NULL,
_T("FABS"),
_T("FCOSH"),
_T("FNEG"),
NULL,
_T("FACOS"),
_T("FCOS"),
_T("FGETEXP"),
_T("FGETMAN"),
_T("FDIV"), // 0x20
_T("FMOD"),
_T("FADD"),
_T("FMUL"),
_T("FSGLDIV"),
_T("FREM"),
_T("FSCALE"),
_T("FSGLMUL"),
_T("FSUB"),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
_T("FSINCOS"), // 0x30
_T("FSINCOS"),
_T("FSINCOS"),
_T("FSINCOS"),
_T("FSINCOS"),
_T("FSINCOS"),
_T("FSINCOS"),
_T("FSINCOS"),
_T("FCMP"),
NULL,
_T("FTST"),
NULL,
NULL,
NULL,
NULL,
NULL
};
static const TCHAR *movemregs[] =
{
_T("D0"),
_T("D1"),
_T("D2"),
_T("D3"),
_T("D4"),
_T("D5"),
_T("D6"),
_T("D7"),
_T("A0"),
_T("A1"),
_T("A2"),
_T("A3"),
_T("A4"),
_T("A5"),
_T("A6"),
_T("A7"),
_T("FP0"),
_T("FP1"),
_T("FP2"),
_T("FP3"),
_T("FP4"),
_T("FP5"),
_T("FP6"),
_T("FP7"),
_T("FPIAR"),
_T("FPSR"),
_T("FPCR")
};
static void addmovemreg (TCHAR *out, int *prevreg, int *lastreg, int *first, int reg, int fpmode)
{
TCHAR *p = out + _tcslen (out);
if (*prevreg < 0) {
*prevreg = reg;
*lastreg = reg;
return;
}
if (reg < 0 || fpmode == 2 || (*prevreg) + 1 != reg || (reg & 8) != ((*prevreg & 8))) {
_stprintf (p, _T("%s%s"), (*first) ? _T("") : _T("/"), movemregs[*lastreg]);
p = p + _tcslen (p);
if (*lastreg != *prevreg) {
if ((*lastreg) + 2 == reg) {
_stprintf(p, _T("/%s"), movemregs[*prevreg]);
} else if ((*lastreg) != (*prevreg)) {
_stprintf(p, _T("-%s"), movemregs[*prevreg]);
}
}
*lastreg = reg;
*first = 0;
}
*prevreg = reg;
}
static bool movemout (TCHAR *out, uae_u16 mask, int mode, int fpmode, bool dst)
{
unsigned int dmask, amask;
int prevreg = -1, lastreg = -1, first = 1;
if (mode == Apdi && !fpmode) {
uae_u8 dmask2;
uae_u8 amask2;
amask2 = mask & 0xff;
dmask2 = (mask >> 8) & 0xff;
dmask = 0;
amask = 0;
for (int i = 0; i < 8; i++) {
if (dmask2 & (1 << i))
dmask |= 1 << (7 - i);
if (amask2 & (1 << i))
amask |= 1 << (7 - i);
}
} else {
dmask = mask & 0xff;
amask = (mask >> 8) & 0xff;
if (fpmode == 1 && mode != Apdi) {
uae_u8 dmask2 = dmask;
dmask = 0;
for (int i = 0; i < 8; i++) {
if (dmask2 & (1 << i))
dmask |= 1 << (7 - i);
}
}
}
bool dataout = dmask != 0 || amask != 0;
if (dst && dataout)
_tcscat(out, _T(","));
if (fpmode) {
while (dmask) { addmovemreg(out, &prevreg, &lastreg, &first, movem_index1[dmask] + (fpmode == 2 ? 24 : 16), fpmode); dmask = movem_next[dmask]; }
} else {
while (dmask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[dmask], fpmode); dmask = movem_next[dmask]; }
while (amask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[amask] + 8, fpmode); amask = movem_next[amask]; }
}
addmovemreg(out, &prevreg, &lastreg, &first, -1, fpmode);
return dataout;
}
static void disasm_size (TCHAR *instrname, struct instr *dp)
{
if (dp->unsized) {
_tcscat(instrname, _T(" "));
return;
}
switch (dp->size)
{
case sz_byte:
_tcscat (instrname, _T(".B "));
break;
case sz_word:
_tcscat (instrname, _T(".W "));
break;
case sz_long:
_tcscat (instrname, _T(".L "));
break;
default:
_tcscat (instrname, _T(" "));
break;
}
}
static void asm_add_extensions(uae_u16 *data, int *dcntp, int mode, uae_u32 v, int extcnt, uae_u16 *ext, uaecptr pc, int size)
{
int dcnt = *dcntp;
if (mode < 0)
return;
if (mode == Ad16) {
data[dcnt++] = v;
}
if (mode == PC16) {
data[dcnt++] = v - (pc + 2);
}
if (mode == Ad8r || mode == PC8r) {
for (int i = 0; i < extcnt; i++) {
data[dcnt++] = ext[i];
}
}
if (mode == absw) {
data[dcnt++] = (uae_u16)v;
}
if (mode == absl) {
data[dcnt++] = (uae_u16)(v >> 16);
data[dcnt++] = (uae_u16)v;
}
if ((mode == imm && size == 0) || mode == imm0) {
data[dcnt++] = (uae_u8)v;
}
if ((mode == imm && size == 1) || mode == imm1) {
data[dcnt++] = (uae_u16)v;
}
if ((mode == imm && size == 2) || mode == imm2) {
data[dcnt++] = (uae_u16)(v >> 16);
data[dcnt++] = (uae_u16)v;
}
*dcntp = dcnt;
}
static int asm_isdreg(const TCHAR *s)
{
if (s[0] == 'D' && s[1] >= '0' && s[1] <= '7')
return s[1] - '0';
return -1;
}
static int asm_isareg(const TCHAR *s)
{
if (s[0] == 'A' && s[1] >= '0' && s[1] <= '7')
return s[1] - '0';
if (s[0] == 'S' && s[1] == 'P')
return 7;
return -1;
}
static int asm_ispc(const TCHAR *s)
{
if (s[0] == 'P' && s[1] == 'C')
return 1;
return 0;
}
static uae_u32 asmgetval(const TCHAR *s)
{
TCHAR *endptr;
if (s[0] == '-')
return _tcstol(s, &endptr, 16);
return _tcstoul(s, &endptr, 16);
}
static int asm_parse_mode020(TCHAR *s, uae_u8 *reg, uae_u32 *v, int *extcnt, uae_u16 *ext)
{
return -1;
}
static int asm_parse_mode(TCHAR *s, uae_u8 *reg, uae_u32 *v, int *extcnt, uae_u16 *ext)
{
TCHAR *ss = s;
*reg = -1;
*v = 0;
*ext = 0;
*extcnt = 0;
if (s[0] == 0)
return -1;
// Dn
if (asm_isdreg(s) >= 0 && s[2] == 0) {
*reg = asm_isdreg(s);
return Dreg;
}
// An
if (asm_isareg(s) >= 0 && s[2] == 0) {
*reg = asm_isareg(s);
return Areg;
}
// (An) and (An)+
if (s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')') {
*reg = asm_isareg(s + 1);
if (s[4] == '+' && s[5] == 0)
return Aipi;
if (s[4] == 0)
return Aind;
return -1;
}
// -(An)
if (s[0] == '-' && s[1] == '(' && asm_isareg(s + 2) >= 0 && s[4] == ')' && s[5] == 0) {
*reg = asm_isareg(s + 2);
return Apdi;
}
// Immediate
if (s[0] == '#') {
if (s[1] == '!') {
*v = _tstol(s + 2);
} else {
*v = asmgetval(s + 1);
}
return imm;
}
// Value
if (s[0] == '!') {
*v = _tstol(s + 1);
} else {
*v = asmgetval(s);
}
int dots = 0;
int fullext = 0;
for (int i = 0; i < _tcslen(s); i++) {
if (s[i] == ',') {
dots++;
} else if (s[i] == '[') {
if (fullext > 0)
fullext = -1;
else
fullext = 1;
} else if (s[i] == ']') {
if (fullext != 1)
fullext = -1;
else
fullext = 2;
fullext++;
}
}
if (fullext < 0 || fullext == 1)
return -1;
if (fullext == 2) {
return asm_parse_mode020(s, reg, v, extcnt, ext);
}
while (*s != 0) {
// d16(An)
if (dots == 0 && s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')' && s[4] == 0) {
*reg = asm_isareg(s + 1);
return Ad16;
}
// d16(PC)
if (dots == 0 && s[0] == '(' && asm_ispc(s + 1) && s[3] == ')' && s[4] == 0) {
*reg = 2;
return PC16;
}
// (d16,An) / (d16,PC)
if (dots == 1 && s[0] == '(' && !asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
TCHAR *startptr, *endptr;
if (s[1] == '!') {
startptr = s + 2;
*v = _tcstol(startptr, &endptr, 10);
} else {
startptr = s + 1;
*v = _tcstol(startptr, &endptr, 16);
}
if (endptr == startptr || endptr[0] != ',')
return -1;
if (asm_ispc(endptr + 1) && endptr[3] == ')') {
*reg = 2;
return PC16;
}
if (asm_isareg(endptr + 1) >= 0 && endptr[3] == ')') {
*reg = asm_isareg(endptr + 1);
return Ad16;
}
return -1;
}
// Ad8r PC8r
if (s[0] == '(') {
TCHAR *s2 = s;
if (!asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
if (dots != 2)
return -1;
TCHAR *startptr, *endptr;
if (s[1] == '!') {
startptr = s + 2;
*v = _tcstol(startptr, &endptr, 10);
} else {
startptr = s + 1;
*v = _tcstol(startptr, &endptr, 16);
}
if (endptr == startptr || endptr[0] != ',')
return -1;
s2 = endptr + 1;
} else if (((asm_isareg(s + 1) >= 0 || asm_ispc(s + 1)) && s[3] == ',') || (asm_isdreg(s + 4) >= 0 || asm_isareg(s + 4) >= 0)) {
if (dots != 1)
return -1;
s2 = s + 1;
} else {
return -1;
}
uae_u8 reg2;
bool ispc = asm_ispc(s2);
if (ispc) {
*reg = 3;
} else {
*reg = asm_isareg(s2);
}
*extcnt = 1;
s2 += 2;
if (*s2 != ',')
return -1;
s2++;
if (asm_isdreg(s2) >= 0) {
reg2 = asm_isdreg(s2);
} else {
reg2 = asm_isareg(s2);
*ext |= 1 << 15;
}
s2 += 2;
*ext |= reg2 << 12;
*ext |= (*v) & 0xff;
if (s2[0] == '.' && s2[1] == 'W') {
s2 += 2;
} else if (s2[0] == '.' && s2[1] == 'L') {
*ext |= 1 << 11;
s2 += 2;
}
if (s2[0] == '*') {
TCHAR scale = s2[1];
if (scale == '2')
*ext |= 1 << 9;
else if (scale == '4')
*ext |= 2 << 9;
else if (scale == '8')
*ext |= 3 << 9;
else
return -1;
s2 += 2;
}
if (s2[0] == ')' && s2[1] == 0) {
return ispc ? PC8r : Ad8r;
}
return -1;
}
s++;
}
// abs.w
if (s - ss > 2 && s[-2] == '.' && s[-1] == 'W') {
*reg = 0;
return absw;
}
// abs.l
*reg = 1;
return absl;
}
static TCHAR *asm_parse_parm(TCHAR *parm, TCHAR *out)
{
TCHAR *p = parm;
bool quote = false;
for (;;) {
if (*p == '(') {
quote = true;
}
if (*p == ')') {
if (!quote)
return NULL;
quote = false;
}
if ((*p == ',' || *p == 0) && !quote) {
TCHAR c = *p;
p[0] = 0;
_tcscpy(out, parm);
my_trim(out);
if (c)
p++;
return p;
}
p++;
}
}
static bool m68k_asm_parse_movec(TCHAR *s, TCHAR *d)
{
for (int i = 0; m2cregs[i].regname; i++) {
if (!_tcscmp(s, m2cregs[i].regname)) {
uae_u16 v = m2cregs[i].regno;
if (asm_isareg(d) >= 0)
v |= 0x8000 | (asm_isareg(d) << 12);
else if (asm_isdreg(d) >= 0)
v |= (asm_isdreg(d) << 12);
else
return false;
_stprintf(s, _T("#%X"), v);
return true;
}
}
return false;
}
static bool m68k_asm_parse_movem(TCHAR *s, int dir)
{
TCHAR *d = s;
uae_u16 regmask = 0;
uae_u16 mask = dir ? 0x8000 : 0x0001;
bool ret = false;
while(*s) {
int dreg = asm_isdreg(s);
int areg = asm_isareg(s);
if (dreg < 0 && areg < 0)
break;
int reg = dreg >= 0 ? dreg : areg + 8;
regmask |= dir ? (mask >> reg) : (mask << reg);
s += 2;
if (*s == 0) {
ret = true;
break;
} else if (*s == '/') {
s++;
continue;
} else if (*s == '-') {
s++;
int dreg2 = asm_isdreg(s);
int areg2 = asm_isareg(s);
if (dreg2 < 0 && areg2 < 0)
break;
int reg2 = dreg2 >= 0 ? dreg2 : areg2 + 8;
if (reg2 < reg)
break;
while (reg2 >= reg) {
regmask |= dir ? (mask >> reg) : (mask << reg);
reg++;
}
s += 2;
if (*s == 0) {
ret = true;
break;
}
} else {
break;
}
}
if (ret)
_stprintf(d, _T("#%X"), regmask);
return ret;
}
int m68k_asm(TCHAR *sline, uae_u16 *out, uaecptr pc)
{
TCHAR *p;
const TCHAR *cp1;
TCHAR ins[256], parms[256];
TCHAR line[256];
TCHAR srcea[256], dstea[256];
uae_u16 data[16], sexts[8], dexts[8];
int sextcnt, dextcnt;
int dcnt = 0;
int cc = -1;
int quick = 0;
bool immrelpc = false;
if (_tcslen(sline) > 100)
return -1;
srcea[0] = dstea[0] = 0;
parms[0] = 0;
// strip all white space except first space
p = line;
bool firstsp = true;
for (int i = 0; sline[i]; i++) {
TCHAR c = sline[i];
if (c == 32 && firstsp) {
firstsp = false;
*p++ = 32;
}
if (c <= 32)
continue;
*p++ = c;
}
*p = 0;
to_upper(line, _tcslen(line));
p = line;
while (*p && *p != ' ')
p++;
if (*p == ' ') {
*p = 0;
_tcscpy(parms, p + 1);
my_trim(parms);
}
_tcscpy(ins, line);
if (_tcslen(ins) == 0)
return 0;
int size = 1;
int inssize = -1;
cp1 = _tcschr(line, '.');
if (cp1) {
size = cp1[1];
if (size == 'W')
size = 1;
else if (size == 'L')
size = 2;
else if (size == 'B')
size = 0;
else
return 0;
inssize = size;
line[cp1 - line] = 0;
_tcscpy(ins, line);
}
TCHAR *parmp = parms;
parmp = asm_parse_parm(parmp, srcea);
if (!parmp)
return 0;
if (srcea[0]) {
parmp = asm_parse_parm(parmp, dstea);
if (!parmp)
return 0;
}
int smode = -1;
int dmode = -1;
uae_u8 sreg = -1;
uae_u8 dreg = -1;
uae_u32 sval = 0;
uae_u32 dval = 0;
int ssize = -1;
int dsize = -1;
dmode = asm_parse_mode(dstea, &dreg, &dval, &dextcnt, dexts);
// Common alias
if (!_tcscmp(ins, _T("BRA"))) {
_tcscpy(ins, _T("BT"));
} else if (!_tcscmp(ins, _T("BSR"))) {
immrelpc = true;
} else if (!_tcscmp(ins, _T("MOVEM"))) {
if (dmode >= Aind && _tcschr(dstea, '-') == NULL && _tcschr(dstea, '/') == NULL) {
_tcscpy(ins, _T("MVMLE"));
if (!m68k_asm_parse_movem(srcea, dmode == Apdi))
return -1;
} else {
TCHAR tmp[256];
_tcscpy(ins, _T("MVMEL"));
_tcscpy(tmp, srcea);
_tcscpy(srcea, dstea);
_tcscpy(dstea, tmp);
if (!m68k_asm_parse_movem(srcea, 0))
return -1;
dmode = asm_parse_mode(dstea, &dreg, &dval, &dextcnt, dexts);
}
} else if (!_tcscmp(ins, _T("MOVEC"))) {
if (dmode == Dreg || dmode == Areg) {
_tcscpy(ins, _T("MOVEC2"));
if (!m68k_asm_parse_movec(srcea, dstea))
return -1;
} else {
TCHAR tmp[256];
_tcscpy(ins, _T("MOVE2C"));
_tcscpy(tmp, srcea);
_tcscpy(srcea, dstea);
dstea[0] = 0;
if (!m68k_asm_parse_movec(srcea, tmp))
return -1;
}
dmode = -1;
}
if (dmode == Areg) {
int l = _tcslen(ins);
if (l <= 2)
return -1;
TCHAR last = ins[l- 1];
if (last == 'Q') {
last = ins[l - 2];
if (last != 'A') {
ins[l - 1] = 'A';
ins[l] = 'Q';
ins[l + 1] = 0;
}
} else if (last != 'A') {
_tcscat(ins, _T("A"));
}
}
bool fp = ins[0] == 'F';
if (ins[_tcslen(ins) - 1] == 'Q' && _tcslen(ins) > 3 && !fp) {
quick = 1;
ins[_tcslen(ins) - 1] = 0;
}
struct mnemolookup *lookup;
for (lookup = lookuptab; lookup->name; lookup++) {
if (!_tcscmp(ins, lookup->name))
break;
}
if (!lookup->name) {
// Check cc variants
for (lookup = lookuptab; lookup->name; lookup++) {
const TCHAR *ccp = _tcsstr(lookup->name, _T("cc"));
if (ccp) {
TCHAR tmp[256];
for (int i = 0; i < (fp ? 32 : 16); i++) {
const TCHAR *ccname = fp ? fpccnames[i] : ccnames[i];
_tcscpy(tmp, lookup->name);
_tcscpy(tmp + (ccp - lookup->name), ccname);
if (tmp[_tcslen(tmp) - 1] == ' ')
tmp[_tcslen(tmp) - 1] = 0;
if (!_tcscmp(tmp, ins)) {
_tcscpy(ins, lookup->name);
cc = i;
if (lookup->mnemo == i_DBcc || lookup->mnemo == i_Bcc) {
// Bcc.B uses same encoding mode as MOVEQ
immrelpc = true;
}
if (size == 0) {
quick = 2;
}
break;
}
}
}
if (cc >= 0)
break;
}
}
if (!lookup->name)
return 0;
int mnemo = lookup->mnemo;
int found = 0;
int sizemask = 0;
int tsize = size;
int unsized = 0;
for (int round = 0; round < 9; round++) {
if (!found && round == 8)
return 0;
if (round == 3) {
// Q is always LONG sized
if (quick == 1) {
tsize = 2;
}
bool isimm = srcea[0] == '#';
if (immrelpc && !isimm) {
TCHAR tmp[256];
_tcscpy(tmp, srcea);
srcea[0] = '#';
_tcscpy(srcea + 1, tmp);
}
smode = asm_parse_mode(srcea, &sreg, &sval, &sextcnt, sexts);
if (immrelpc && !isimm) {
sval = sval - (pc + 2);
}
if (quick) {
smode = immi;
sreg = sval & 0xff;
}
}
if (round == 1) {
if (!quick && (sizemask == 1 || sizemask == 2 || sizemask == 4)) {
tsize = 0;
if (sizemask == 2)
tsize = 1;
else if (sizemask == 4)
tsize = 2;
} else {
continue;
}
}
if (round == 2 && !found) {
unsized = 1;
}
if (round == 4 && smode == imm) {
smode = imm0;
} else if (round == 5 && smode == imm0) {
smode = imm1;
} else if (round == 6 && smode == imm1) {
smode = imm2;
} else if (round == 7 && smode == imm2) {
smode = immi;
sreg = sval & 0xff;
} else if (round == 4) {
round += 5 - 1;
}
for (int opcode = 0; opcode < 65536; opcode++) {
struct instr *table = &table68k[opcode];
if (table->mnemo != mnemo)
continue;
if (cc >= 0 && table->cc != cc)
continue;
#if 0
if (round == 0) {
console_out_f(_T("%s OP=%04x S=%d SR=%d SM=%d SU=%d SP=%d DR=%d DM=%d DU=%d DP=%d SDU=%d\n"), lookup->name, opcode, table->size,
table->sreg, table->smode, table->suse, table->spos,
table->dreg, table->dmode, table->duse, table->dpos,
table->sduse);
}
#endif
if (table->duse && !(table->dmode == dmode || (dmode >= imm && dmode <= imm2 && table->dmode >= imm && table->dmode <= imm2)))
continue;
if (round == 0) {
sizemask |= 1 << table->size;
}
if (unsized > 0 && !table->unsized) {
continue;
}
found++;
if (round >= 3) {
if (
((table->size == tsize || table->unsized)) &&
((!table->suse && smode < 0) || (table->suse && table->smode == smode)) &&
((!table->duse && dmode < 0) || (table->duse && (table->dmode == dmode || (dmode == imm && (table->dmode >= imm && table->dmode <= imm2))))) &&
((table->sreg == sreg || (table->smode >= absw && table->smode != immi))) &&
((table->dreg == dreg || table->dmode >= absw))
)
{
if (inssize >= 0 && tsize != inssize)
continue;
data[dcnt++] = opcode;
asm_add_extensions(data, &dcnt, smode, sval, sextcnt, sexts, pc, tsize);
if (smode >= 0)
asm_add_extensions(data, &dcnt, dmode, dval, dextcnt, dexts, pc, tsize);
for (int i = 0; i < dcnt; i++) {
out[i] = data[i];
}
return dcnt;
}
}
}
}
return 0;
}
static void resolve_if_jmp(TCHAR *s, uae_u32 addr)
{
uae_u16 opcode = get_word_debug(addr);
if (opcode == 0x4ef9) { // JMP x.l
TCHAR *p = s + _tcslen(s);
uae_u32 addr2 = get_long_debug(addr + 2);
_stprintf(p, _T(" == $%08x "), addr2);
showea_val(p + _tcslen(p), opcode, addr2, 4);
TCHAR txt[256];
bool ext;
if (debugmem_get_segment(addr2, NULL, &ext, NULL, txt)) {
if (ext) {
_tcscat(p, _T(" "));
_tcscat(p, txt);
}
}
}
}
static bool mmu_op30_helper_get_fc(uae_u16 extra, TCHAR *out)
{
switch (extra & 0x0018) {
case 0x0010:
_stprintf(out, _T("#%d"), extra & 7);
return true;
case 0x0008:
_stprintf(out, _T("D%d"), extra & 7);
return true;
case 0x0000:
if (extra & 1) {
_tcscpy(out, _T("DFC"));
} else {
_tcscpy(out, _T("SFC"));
}
return true;
default:
return false;
}
}
static bool mmu_op30_invea(uae_u32 opcode)
{
int eamode = (opcode >> 3) & 7;
int rreg = opcode & 7;
// Dn, An, (An)+, -(An), immediate and PC-relative not allowed
if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || (eamode == 7 && rreg > 1))
return true;
return false;
}
static uaecptr disasm_mmu030(uaecptr pc, uae_u16 opcode, uae_u16 extra, struct instr *dp, TCHAR *instrname, uae_u32 *seaddr2, int safemode)
{
int type = extra >> 13;
_tcscpy(instrname, _T("F-LINE (MMU 68030)"));
pc += 2;
switch (type)
{
case 0:
case 2:
case 3:
{
// PMOVE
int preg = (extra >> 10) & 31;
int rw = (extra >> 9) & 1;
int fd = (extra >> 8) & 1;
int unused = (extra & 0xff);
const TCHAR *r = NULL;
if (mmu_op30_invea(opcode))
break;
if (unused)
break;
if (rw && fd)
break;
switch (preg)
{
case 0x10:
r = _T("TC");
break;
case 0x12:
r = _T("SRP");
break;
case 0x13:
r = _T("CRP");
break;
case 0x18:
r = _T("MMUSR");
break;
case 0x02:
r = _T("TT0");
break;
case 0x03:
r = _T("TT1");
break;
}
if (!r)
break;
_tcscpy(instrname, _T("PMOVE"));
if (fd)
_tcscat(instrname, _T("FD"));
_tcscat(instrname, _T(" "));
if (!rw) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, safemode);
_tcscat(instrname, _T(","));
}
_tcscat(instrname, r);
if (rw) {
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, safemode);
}
break;
}
case 1:
{
// PLOAD/PFLUSH
uae_u16 mode = (extra >> 8) & 31;
int unused = (extra & (0x100 | 0x80 | 0x40 | 0x20));
uae_u16 fc_mask = (extra & 0x00E0) >> 5;
uae_u16 fc_bits = extra & 0x7f;
TCHAR fc[10];
if (unused)
break;
switch (mode) {
case 0x00: // PLOAD W
case 0x02: // PLOAD R
if (mmu_op30_invea(opcode))
break;
_stprintf(instrname, _T("PLOAD%c %s,"), mode == 0 ? 'W' : 'R', fc);
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, safemode);
break;
case 0x04: // PFLUSHA
if (fc_bits)
break;
_tcscpy(instrname, _T("PFLUSHA"));
break;
case 0x10: // FC
if (!mmu_op30_helper_get_fc(extra, fc))
break;
_stprintf(instrname, _T("PFLUSH %s,%d"), fc, fc_mask);
break;
case 0x18: // FC + EA
if (mmu_op30_invea(opcode))
break;
if (!mmu_op30_helper_get_fc(extra, fc))
break;
_stprintf(instrname, _T("PFLUSH %s,%d"), fc, fc_mask);
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, safemode);
break;
}
break;
}
case 4:
{
// PTEST
int level = (extra & 0x1C00) >> 10;
int rw = (extra >> 9) & 1;
int a = (extra >> 8) & 1;
int areg = (extra & 0xE0) >> 5;
TCHAR fc[10];
if (mmu_op30_invea(opcode))
break;
if (!mmu_op30_helper_get_fc(extra, fc))
break;
if (!level && a)
break;
_stprintf(instrname, _T("PTEST%c %s,"), rw ? 'R' : 'W', fc);
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, safemode);
_stprintf(instrname + _tcslen(instrname), _T(",#%d"), level);
if (a)
_stprintf(instrname + _tcslen(instrname), _T(",A%d"), areg);
break;
}
}
return pc;
}
void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, uaecptr lastpc, int safemode)
{
uae_u32 seaddr2;
uae_u32 deaddr2;
if (!table68k)
return;
while (cnt-- > 0) {
TCHAR instrname[256], *ccpt;
TCHAR segout[256], segname[256];
int i;
uae_u32 opcode;
uae_u16 extra;
struct mnemolookup *lookup;
struct instr *dp;
uaecptr oldpc;
uaecptr m68kpc_illg = 0;
bool illegal = false;
int segid, lastsegid;
TCHAR *symbolpos;
seaddr2 = deaddr2 = 0;
oldpc = pc;
opcode = get_word_debug (pc);
extra = get_word_debug (pc + 2);
if (cpufunctbl[opcode] == op_illg_1 || cpufunctbl[opcode] == op_unimpl_1) {
m68kpc_illg = pc + 2;
illegal = TRUE;
}
dp = table68k + opcode;
if (dp->mnemo == i_ILLG) {
illegal = FALSE;
opcode = 0x4AFC;
dp = table68k + opcode;
}
for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
;
lastsegid = -1;
bool exact = false;
if (lastpc != 0xffffffff) {
lastsegid = debugmem_get_segment(lastpc, NULL, NULL, NULL, NULL);
}
segid = debugmem_get_segment(pc, &exact, NULL, segout, segname);
if (segid && (lastsegid != -1 || exact) && (segid != lastsegid || pc == lastpc || exact)) {
buf = buf_out(buf, &bufsize, _T("%s\n"), segname);
}
symbolpos = buf;
buf = buf_out (buf, &bufsize, _T("%08X "), pc);
if (segid) {
buf = buf_out(buf, &bufsize, _T("%s "), segout);
}
pc += 2;
if (lookup->friendlyname)
_tcscpy (instrname, lookup->friendlyname);
else
_tcscpy (instrname, lookup->name);
ccpt = _tcsstr (instrname, _T("cc"));
if (ccpt != 0) {
if ((opcode & 0xf000) == 0xf000)
_tcscpy (ccpt, fpccnames[extra & 0x1f]);
else
_tcsncpy (ccpt, ccnames[dp->cc], 2);
}
disasm_size (instrname, dp);
if (lookup->mnemo == i_MOVEC2 || lookup->mnemo == i_MOVE2C) {
uae_u16 imm = extra;
uae_u16 creg = imm & 0x0fff;
uae_u16 r = imm >> 12;
TCHAR regs[16];
const TCHAR *cname = _T("?");
int j;
for (j = 0; m2cregs[j].regname; j++) {
if (m2cregs[j].regno == creg)
break;
}
_stprintf(regs, _T("%c%d"), r >= 8 ? 'A' : 'D', r >= 8 ? r - 8 : r);
if (m2cregs[j].regname)
cname = m2cregs[j].regname;
if (lookup->mnemo == i_MOVE2C) {
_tcscat(instrname, regs);
_tcscat(instrname, _T(","));
_tcscat(instrname, cname);
} else {
_tcscat(instrname, cname);
_tcscat(instrname, _T(","));
_tcscat(instrname, regs);
}
pc += 2;
} else if (lookup->mnemo == i_CHK2) {
TCHAR *p;
if (!(extra & 0x0800)) {
instrname[1] = 'M';
instrname[2] = 'P';
}
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
extra = get_word_debug(pc);
pc += 2;
p = instrname + _tcslen(instrname);
_stprintf(p, (extra & 0x8000) ? _T(",A%d") : _T(",D%d"), (extra >> 12) & 7);
} else if (lookup->mnemo == i_CAS) {
TCHAR *p = instrname + _tcslen(instrname);
_stprintf(p, _T("D%d,D%d,"), extra & 7, (extra >> 6) & 7);
pc += 2;
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
} else if (lookup->mnemo == i_CAS2) {
TCHAR *p = instrname + _tcslen(instrname);
uae_u16 extra2 = get_word_debug(pc + 2);
_stprintf(p, _T("D%d:D%d,D%d,D%d,(%c%d):(%c%d)"),
extra & 7, extra2 & 7, (extra >> 6) & 7, (extra2 >> 6) & 7,
(extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7,
(extra2 & 0x8000) ? 'A' : 'D', (extra2 >> 12) & 7);
pc += 4;
} else if (lookup->mnemo == i_ORSR || lookup->mnemo == i_ANDSR || lookup->mnemo == i_EORSR) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
_tcscat(instrname, dp->size == sz_byte ? _T(",CCR") : _T(",SR"));
} else if (lookup->mnemo == i_MVR2USP) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
_tcscat(instrname, _T(",USP"));
} else if (lookup->mnemo == i_MVUSP2R) {
_tcscat(instrname, _T("USP,"));
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
} else if (lookup->mnemo == i_MV2SR) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
_tcscat(instrname, dp->size == sz_byte ? _T(",CCR") : _T(",SR"));
} else if (lookup->mnemo == i_MVSR2) {
_tcscat(instrname, dp->size == sz_byte ? _T("CCR,") : _T("SR,"));
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
} else if (lookup->mnemo == i_MVMEL) {
uae_u16 mask = extra;
pc += 2;
pc = ShowEA (NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
movemout (instrname, mask, dp->dmode, 0, true);
} else if (lookup->mnemo == i_MVMLE) {
uae_u16 mask = extra;
pc += 2;
if (movemout(instrname, mask, dp->dmode, 0, false))
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
} else if (lookup->mnemo == i_DIVL || lookup->mnemo == i_MULL) {
TCHAR *p;
extra = get_word_debug(pc);
pc += 2;
if (extra & 0x0800) // signed/unsigned
instrname[3] = 'S';
else
instrname[3] = 'U';
if (lookup->mnemo == i_DIVL && !(extra & 0x0400)) {
// DIVSL.L/DIVUL.L
instrname[7] = 0;
instrname[6] = instrname[5];
instrname[5] = instrname[4];
instrname[4] = 'L';
}
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
p = instrname + _tcslen(instrname);
if (extra & 0x0400)
_stprintf(p, _T(",D%d:D%d"), extra & 7, (extra >> 12) & 7);
else
_stprintf(p, _T(",D%d"), (extra >> 12) & 7);
} else if (lookup->mnemo == i_MOVES) {
TCHAR *p;
pc += 2;
if (!(extra & 0x0800)) {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
p = instrname + _tcslen(instrname);
_stprintf(p, _T(",%c%d"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
} else {
p = instrname + _tcslen(instrname);
_stprintf(p, _T("%c%d,"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
}
} else if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU ||
lookup->mnemo == i_BFCHG || lookup->mnemo == i_BFCLR ||
lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS ||
lookup->mnemo == i_BFSET || lookup->mnemo == i_BFTST) {
TCHAR *p;
int reg = -1;
pc += 2;
p = instrname + _tcslen(instrname);
if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU || lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS)
reg = (extra >> 12) & 7;
if (lookup->mnemo == i_BFINS)
_stprintf(p, _T("D%d,"), reg);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
_tcscat(instrname, _T(" {"));
p = instrname + _tcslen(instrname);
if (extra & 0x0800)
_stprintf(p, _T("D%d"), (extra >> 6) & 7);
else
_stprintf(p, _T("%d"), (extra >> 6) & 31);
_tcscat(instrname, _T(":"));
p = instrname + _tcslen(instrname);
if (extra & 0x0020)
_stprintf(p, _T("D%d"), extra & 7);
else
_stprintf(p, _T("%d"), extra & 31);
_tcscat(instrname, _T("}"));
p = instrname + _tcslen(instrname);
if (lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU)
_stprintf(p, _T(",D%d"), reg);
} else if (lookup->mnemo == i_CPUSHA || lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP ||
lookup->mnemo == i_CINVA || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
if ((opcode & 0xc0) == 0xc0)
_tcscat(instrname, _T("BC"));
else if (opcode & 0x80)
_tcscat(instrname, _T("IC"));
else if (opcode & 0x40)
_tcscat(instrname, _T("DC"));
else
_tcscat(instrname, _T("?"));
if (lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
TCHAR *p = instrname + _tcslen(instrname);
_stprintf(p, _T(",(A%d)"), opcode & 7);
}
} else if (lookup->mnemo == i_MOVE16) {
TCHAR *p = instrname + _tcslen(instrname);
if (opcode & 0x20) {
_stprintf(p, _T("(A%d)+,(A%d)+"), opcode & 7, (extra >> 12) & 7);
pc += 2;
} else {
uae_u32 addr = get_long_debug(pc);
int ay = opcode & 7;
pc += 4;
switch ((opcode >> 3) & 3)
{
case 0:
_stprintf(p, _T("(A%d)+,$%08x"), ay, addr);
break;
case 1:
_stprintf(p, _T("$%08x,(A%d)+"), addr, ay);
break;
case 2:
_stprintf(p, _T("(A%d),$%08x"), ay, addr);
break;
case 3:
_stprintf(p, _T("$%08x,(A%d)"), addr, ay);
break;
}
}
} else if (lookup->mnemo == i_PACK || lookup->mnemo == i_UNPK) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, safemode);
extra = get_word_debug(pc);
_stprintf(instrname + _tcslen(instrname), _T(",#$%04x"), extra);
pc += 2;
} else if (lookup->mnemo == i_LPSTOP) {
if (extra == 0x01c0) {
uae_u16 extra2 = get_word_debug(pc + 2);
_stprintf(instrname, _T("LPSTOP #$%04x"), extra2);
pc += 4;
} else {
_stprintf(instrname, _T("ILLG #$%04x"), extra);
pc += 2;
}
} else if (lookup->mnemo == i_FDBcc) {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
pc += 2;
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, 0, imm1, sz_word, instrname, &deaddr2, safemode);
} else if (lookup->mnemo == i_FTRAPcc) {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
int mode = opcode & 7;
pc += 2;
if (mode == 2) {
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, 0, imm1, sz_word, instrname, NULL, safemode);
} else if (mode == 3) {
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, 0, imm1, sz_long, instrname, NULL, safemode);
}
} else if (lookup->mnemo == i_FPP) {
TCHAR *p;
int ins = extra & 0x3f;
int size = (extra >> 10) & 7;
pc += 2;
if ((extra & 0xfc00) == 0x5c00) { // FMOVECR (=i_FPP with source specifier = 7)
fpdata fp;
fpu_get_constant(&fp, extra);
_stprintf(instrname, _T("FMOVECR.X #0x%02x [%s],FP%d"), extra & 0x7f, fpp_print(&fp, 0), (extra >> 7) & 7);
} else if ((extra & 0x8000) == 0x8000) { // FMOVEM
int dr = (extra >> 13) & 1;
int mode;
int dreg = (extra >> 4) & 7;
int regmask, fpmode;
if (extra & 0x4000) {
mode = (extra >> 11) & 3;
regmask = extra & 0xff; // FMOVEM FPx
fpmode = 1;
_tcscpy(instrname, _T("FMOVEM.X "));
} else {
mode = 0;
regmask = (extra >> 10) & 7; // FMOVEM control
fpmode = 2;
_tcscpy(instrname, _T("FMOVEM.L "));
if (regmask == 1 || regmask == 2 || regmask == 4)
_tcscpy(instrname, _T("FMOVE.L "));
}
p = instrname + _tcslen(instrname);
if (dr) {
if (mode & 1)
_stprintf(p, _T("D%d"), dreg);
else
movemout(p, regmask, dp->dmode, fpmode, false);
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
} else {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
p = instrname + _tcslen(instrname);
if (mode & 1)
_stprintf(p, _T(",D%d"), dreg);
else
movemout(p, regmask, dp->dmode, fpmode, true);
}
} else {
if (fpuopcodes[ins])
_tcscpy(instrname, fpuopcodes[ins]);
else
_tcscpy(instrname, _T("F?"));
if ((extra & 0xe000) == 0x6000) { // FMOVE to memory
int kfactor = extra & 0x7f;
_tcscpy(instrname, _T("FMOVE."));
_tcscat(instrname, fpsizes[size]);
_tcscat(instrname, _T(" "));
p = instrname + _tcslen(instrname);
_stprintf(p, _T("FP%d,"), (extra >> 7) & 7);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &deaddr2, safemode);
p = instrname + _tcslen(instrname);
if (size == 7) {
_stprintf(p, _T(" {D%d}"), (kfactor >> 4));
} else if (kfactor) {
if (kfactor & 0x40)
kfactor |= ~0x3f;
_stprintf(p, _T(" {%d}"), kfactor);
}
} else {
if (extra & 0x4000) { // source is EA
_tcscat(instrname, _T("."));
_tcscat(instrname, fpsizes[size]);
_tcscat(instrname, _T(" "));
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &seaddr2, safemode);
} else { // source is FPx
p = instrname + _tcslen(instrname);
_stprintf(p, _T(".X FP%d"), (extra >> 10) & 7);
}
p = instrname + _tcslen(instrname);
if ((extra & 0x4000) || (((extra >> 7) & 7) != ((extra >> 10) & 7)))
_stprintf(p, _T(",FP%d"), (extra >> 7) & 7);
if (ins >= 0x30 && ins < 0x38) { // FSINCOS
p = instrname + _tcslen(instrname);
_stprintf(p, _T(",FP%d"), extra & 7);
}
}
}
} else if (lookup->mnemo == i_MMUOP030) {
pc = disasm_mmu030(pc, opcode, extra, dp, instrname, &seaddr2, safemode);
} else if ((opcode & 0xf000) == 0xa000) {
_tcscpy(instrname, _T("A-LINE"));
} else {
if (dp->suse) {
pc = ShowEA (NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
// JSR x(a6) / JMP x(a6)
if (opcode == 0x4ea8 + 6 || opcode == 0x4ee8 + 6) {
TCHAR sname[256];
if (debugger_get_library_symbol(m68k_areg(regs, 6), 0xffff0000 | extra, sname)) {
TCHAR *p = instrname + _tcslen(instrname);
_stprintf(p, _T(" %s"), sname);
resolve_if_jmp(instrname, m68k_areg(regs, 6) + (uae_s16)extra);
}
}
// show target address if JSR x(pc) + JMP xxxx combination
if (opcode == 0x4eba && seaddr2 && instrname[0]) { // JSR x(pc)
resolve_if_jmp(instrname, seaddr2);
}
}
if (dp->suse && dp->duse)
_tcscat (instrname, _T(","));
if (dp->duse) {
pc = ShowEA (NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, safemode);
}
}
for (i = 0; i < (pc - oldpc) / 2; i++) {
buf = buf_out (buf, &bufsize, _T("%04x "), get_word_debug (oldpc + i * 2));
}
while (i++ < 5)
buf = buf_out (buf, &bufsize, _T(" "));
if (illegal)
buf = buf_out (buf, &bufsize, _T("[ "));
buf = buf_out (buf, &bufsize, instrname);
if (illegal)
buf = buf_out (buf, &bufsize, _T(" ]"));
if (ccpt != 0) {
uaecptr addr2 = deaddr2 ? deaddr2 : seaddr2;
if (deaddr)
*deaddr = pc;
if ((opcode & 0xf000) == 0xf000) {
if (fpp_cond(dp->cc)) {
buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2);
} else {
buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2);
}
} else {
if (dp->mnemo == i_Bcc || dp->mnemo == i_DBcc) {
if (cctrue(dp->cc)) {
buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2);
} else {
buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2);
}
} else {
if (cctrue(dp->cc)) {
buf = buf_out(buf, &bufsize, _T(" (T)"));
} else {
buf = buf_out(buf, &bufsize, _T(" (F)"));
}
}
}
} else if ((opcode & 0xff00) == 0x6100) { /* BSR */
if (deaddr)
*deaddr = pc;
buf = buf_out (buf, &bufsize, _T(" == $%08x"), seaddr2);
}
buf = buf_out (buf, &bufsize, _T("\n"));
for (uaecptr segpc = oldpc; segpc < pc; segpc++) {
TCHAR segout[256];
if (debugmem_get_symbol(segpc, segout, sizeof(segout) / sizeof(TCHAR))) {
_tcscat(segout, _T(":\n"));
if (bufsize > _tcslen(segout)) {
memmove(symbolpos + _tcslen(segout), symbolpos, (_tcslen(symbolpos) + 1) * sizeof(TCHAR));
memcpy(symbolpos, segout, _tcslen(segout) * sizeof(TCHAR));
bufsize -= _tcslen(segout);
buf += _tcslen(segout);
symbolpos += _tcslen(segout);
}
}
}
int srcline = -1;
for (uaecptr segpc = oldpc; segpc < pc; segpc++) {
TCHAR sourceout[256];
int line = debugmem_get_sourceline(segpc, sourceout, sizeof(sourceout) / sizeof(TCHAR));
if (line < 0)
break;
if (srcline != line) {
if (srcline < 0)
buf = buf_out(buf, &bufsize, _T("\n"));
buf = buf_out(buf, &bufsize, sourceout);
srcline = line;
}
}
if (srcline >= 0) {
buf = buf_out(buf, &bufsize, _T("\n"));
}
if (illegal)
pc = m68kpc_illg;
}
if (nextpc)
*nextpc = pc;
if (seaddr)
*seaddr = seaddr2;
if (deaddr)
*deaddr = deaddr2;
}
/*************************************************************
Disasm the m68kcode at the given address into instrname
and instrcode
*************************************************************/
void sm68k_disasm (TCHAR *instrname, TCHAR *instrcode, uaecptr addr, uaecptr *nextpc, uaecptr lastpc)
{
TCHAR *ccpt;
uae_u32 opcode;
struct mnemolookup *lookup;
struct instr *dp;
uaecptr pc, oldpc;
pc = oldpc = addr;
opcode = get_word_debug (pc);
if (cpufunctbl[opcode] == op_illg_1) {
opcode = 0x4AFC;
}
dp = table68k + opcode;
for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++);
pc += 2;
_tcscpy (instrname, lookup->name);
ccpt = _tcsstr (instrname, _T("cc"));
if (ccpt != 0) {
_tcsncpy (ccpt, ccnames[dp->cc], 2);
}
switch (dp->size){
case sz_byte: _tcscat (instrname, _T(".B ")); break;
case sz_word: _tcscat (instrname, _T(".W ")); break;
case sz_long: _tcscat (instrname, _T(".L ")); break;
default: _tcscat (instrname, _T(" ")); break;
}
if (dp->suse) {
pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, NULL, 0);
}
if (dp->suse && dp->duse)
_tcscat (instrname, _T(","));
if (dp->duse) {
pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, NULL, 0);
}
if (instrcode)
{
int i;
for (i = 0; i < (pc - oldpc) / 2; i++)
{
_stprintf (instrcode, _T("%04x "), get_iword_debug (oldpc + i * 2));
instrcode += _tcslen (instrcode);
}
}
if (nextpc)
*nextpc = pc;
}