WinUAE/disasm.cpp
2023-12-13 21:28:29 +02:00

2566 lines
64 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"
int disasm_flags = DISASM_FLAG_LC_MNEMO | DISASM_FLAG_LC_REG | DISASM_FLAG_LC_SIZE | DISASM_FLAG_LC_HEX |
DISASM_FLAG_CC | DISASM_FLAG_EA | DISASM_FLAG_VAL | DISASM_FLAG_WORDS | DISASM_FLAG_ABSSHORTLONG;
int disasm_min_words = 5;
int disasm_max_words = 16;
TCHAR disasm_hexprefix[3] = { '$', 0 };
static TCHAR disasm_areg, disasm_dreg, disasm_byte, disasm_word, disasm_long;
static TCHAR disasm_pcreg[3], disasm_fpreg[3];
static bool absshort_long = false;
void disasm_init(void)
{
_tcscpy(disasm_pcreg, _T("PC"));
_tcscpy(disasm_fpreg, _T("FP"));
if (disasm_flags & DISASM_FLAG_LC_REG) {
_tcscpy(disasm_pcreg, _T("pc"));
_tcscpy(disasm_fpreg, _T("fp"));
}
disasm_areg = (disasm_flags & DISASM_FLAG_LC_REG) ? 'a' : 'A';
disasm_dreg = (disasm_flags & DISASM_FLAG_LC_REG) ? 'd' : 'D';
disasm_byte = (disasm_flags & DISASM_FLAG_LC_REG) ? 'b' : 'B';
disasm_word = (disasm_flags & DISASM_FLAG_LC_REG) ? 'w' : 'W';
disasm_long = (disasm_flags & DISASM_FLAG_LC_REG) ? 'l' : 'L';
absshort_long = (disasm_flags & DISASM_FLAG_ABSSHORTLONG) != 0;
}
static void disasm_lc_mnemo(TCHAR *s)
{
if (!(disasm_flags & DISASM_FLAG_LC_MNEMO) && !(disasm_flags & DISASM_FLAG_LC_SIZE)) {
return;
}
if ((disasm_flags & DISASM_FLAG_LC_MNEMO) && (disasm_flags & DISASM_FLAG_LC_SIZE)) {
to_lower(s, -1);
return;
}
TCHAR *s2 = _tcschr(s, '.');
if (s2) {
if (disasm_flags & DISASM_FLAG_LC_SIZE) {
to_lower(s2, -1);
}
if (disasm_flags & DISASM_FLAG_LC_MNEMO) {
s2[0] = 0;
to_lower(s, -1);
s2[0] = '.';
}
} else {
if (disasm_flags & DISASM_FLAG_LC_MNEMO) {
to_lower(s, -1);
return;
}
}
}
static const TCHAR *disasm_lc_size(const TCHAR *s)
{
static TCHAR tmp[32];
if (disasm_flags & DISASM_FLAG_LC_SIZE) {
_tcscpy(tmp, s);
to_lower(tmp, -1);
return tmp;
}
return s;
}
static const TCHAR *disasm_lc_reg(const TCHAR *s)
{
static TCHAR tmp[32];
if (disasm_flags & DISASM_FLAG_LC_REG) {
_tcscpy(tmp, s);
to_lower(tmp, -1);
return tmp;
}
return s;
}
static const TCHAR *disasm_lc_hex2(const TCHAR *s, bool noprefix)
{
static TCHAR tmp[32];
bool copied = false;
if (disasm_flags & DISASM_FLAG_LC_HEX) {
const TCHAR *s2 = _tcschr(s, 'X');
if (s2) {
_tcscpy(tmp, s);
copied = true;
tmp[s2 - s] = 'x';
for (;;) {
s2 = _tcschr(tmp, 'X');
if (!s2) {
break;
}
tmp[s2 - tmp] = 'x';
}
}
}
if (!noprefix) {
if (disasm_hexprefix[0] != '$' || disasm_hexprefix[1] != 0 || s[0] != '$') {
if (!copied) {
_tcscpy(tmp, s);
copied = true;
}
const TCHAR *s2 = _tcschr(tmp, '%');
if (s2) {
int len = uaetcslen(disasm_hexprefix);
if (s2 > tmp && s2[-1] == '$') {
len--;
s2--;
}
if (len < 0) {
memmove(tmp + (s2 - tmp), tmp + (s2 - tmp) - len, (uaetcslen(tmp + (s2 - tmp) - len) + 1) * sizeof(TCHAR));
} else {
if (len > 0) {
memmove(tmp + (s2 - tmp) + len, s2, (uaetcslen(s2) + 1) * sizeof(TCHAR));
}
memcpy(tmp + (s2 - tmp), disasm_hexprefix, uaetcslen(disasm_hexprefix) * sizeof(TCHAR));
}
}
return tmp;
}
}
if (copied) {
return tmp;
}
return s;
}
static const TCHAR *disasm_lc_hex(const TCHAR *s)
{
return disasm_lc_hex2(s, false);
}
static const TCHAR *disasm_lc_nhex(const TCHAR *s)
{
return disasm_lc_hex2(s, true);
}
struct cpum2c m2cregs[] = {
{ 0, 31, _T("SFC") },
{ 1, 31, _T("DFC") },
{ 2, 30, _T("CACR") },
{ 3, 24, _T("TC") },
{ 4, 24, _T("ITT0") },
{ 5, 24, _T("ITT1") },
{ 6, 24, _T("DTT0") },
{ 7, 24, _T("DTT1") },
{ 8, 16, _T("BUSC") },
{ 0x800, 31, _T("USP") },
{ 0x801, 31, _T("VBR") },
{ 0x802, 6, _T("CAAR") },
{ 0x803, 15, _T("MSP") },
{ 0x804, 31, _T("ISP") },
{ 0x805, 8, _T("MMUS") },
{ 0x806, 12, _T("URP") },
{ 0x807, 12, _T("SRP") },
{ 0x808, 16, _T("PCR") },
{ -1, 0, NULL }
};
const TCHAR *fpsizes[] = {
_T("L"),
_T("S"),
_T("X"),
_T("P"),
_T("W"),
_T("D"),
_T("B"),
_T("P")
};
static const wordsizes 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];
#ifndef CPU_TESTER
#if UAE
if (addr >= 0xe90000 && addr < 0xf00000)
goto skip;
if (addr >= 0xdff000 && addr < 0xe00000)
goto skip;
#endif
#endif
if (!(disasm_flags & (DISASM_FLAG_VAL_FORCE | DISASM_FLAG_VAL))) {
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, bool pcrel)
{
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);
}
int m = 1 << ((dp >> 9) & 3);
mult[0] = 0;
if (currprefs.cpu_model >= 68020) {
dispreg <<= (dp >> 9) & 3; // SCALE
}
if (buffer)
buffer[0] = 0;
if ((dp & 0x100) && currprefs.cpu_model >= 68020) {
TCHAR dr[20];
uae_s32 outer = 0, disp = 0;
// Full format extension (68020+)
if (m > 1 && buffer) {
_stprintf(mult, _T("*%d"), m);
}
if (dp & 0x80) { // BS (base register suppress)
base = 0;
if (buffer)
name = NULL;
}
if (buffer)
_stprintf(dr, _T("%c%d.%c"), dp & 0x8000 ? disasm_areg : disasm_dreg, (int)r, dp & 0x800 ? disasm_long : disasm_word);
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, disasm_lc_hex(_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, disasm_lc_hex(_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, disasm_lc_hex(_T("$%04X,")), (uae_s16)outer);
p += _tcslen(p);
}
pc += 2;
} else if ((dp & 0x03) == 0x03) {
outer = get_ilong_debug(pc);
if (buffer) {
_stprintf(p, disasm_lc_hex(_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) {
if (disasm_flags & (DISASM_FLAG_VAL_FORCE | DISASM_FLAG_VAL)) {
_stprintf(p, disasm_lc_hex(_T(" == $%08X")), addr);
p += _tcslen(p);
}
}
} else {
// Brief format extension
TCHAR regstr[20];
uae_s8 disp8 = dp & 0xFF;
if (m > 1 && buffer) {
if (currprefs.cpu_model < 68020) {
_stprintf(mult, _T("[*%d]"), m);
} else {
_stprintf(mult, _T("*%d"), m);
}
}
regstr[0] = 0;
_stprintf(regstr, _T(",%c%d.%c"), dp & 0x8000 ? disasm_areg : disasm_dreg, (int)r, dp & 0x800 ? disasm_long : disasm_word);
addr = base + (uae_s32)((uae_s8)disp8) + dispreg;
if (buffer) {
if (pcrel) {
if (disasm_flags & (DISASM_FLAG_VAL_FORCE | DISASM_FLAG_VAL)) {
_stprintf(buffer, _T("(%s%s%s,$%02x=$%08x) == $%08x"), name, regstr, mult, (uae_u8)disp8, (*pcp) += disp8, addr);
} else {
_stprintf(buffer, _T("(%s%s%s,$%02x=$%08x)"), name, regstr, mult, (uae_u8)disp8, (*pcp) += disp8);
}
} else {
if (disasm_flags & (DISASM_FLAG_VAL_FORCE | DISASM_FLAG_VAL)) {
_stprintf(buffer, _T("(%s%s%s,$%02x) == $%08x"), name, regstr, mult, (uae_u8)disp8, addr);
} else {
_stprintf(buffer, _T("(%s%s%s,$%02x)"), name, regstr, mult, (uae_u8)disp8);
}
}
if (((dp & 0x0100) || m != 1) && currprefs.cpu_model < 68020) {
_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 *actualea, int safemode)
{
uaecptr addr = pc;
uae_s16 disp16;
uae_s32 offset = 0;
TCHAR buffer[80];
if (actualea)
*actualea = 1;
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("%c%d"), disasm_dreg, reg);
if (actualea)
*actualea = 0;
break;
case Areg:
_stprintf(buffer, _T("%c%d"), disasm_areg, reg);
if (actualea)
*actualea = 0;
break;
case Aind:
_stprintf(buffer, _T("(%c%d)"), disasm_areg, reg);
addr = regs.regs[reg + 8];
if (disasm_flags & DISASM_FLAG_VAL_FORCE) {
_stprintf(buffer + _tcslen(buffer), disasm_lc_hex(_T(" == $%08X")), addr);
}
showea_val(buffer, opcode, addr, size);
break;
case Aipi:
_stprintf(buffer, _T("(%c%d)+"), disasm_areg, reg);
addr = regs.regs[reg + 8];
if (disasm_flags & DISASM_FLAG_VAL_FORCE) {
_stprintf(buffer + _tcslen(buffer), disasm_lc_hex(_T(" == $%08X")), addr);
}
showea_val(buffer, opcode, addr, size);
break;
case Apdi:
_stprintf(buffer, _T("-(%c%d)"), disasm_areg, reg);
addr = regs.regs[reg + 8] - datasizes[size];
if (disasm_flags & DISASM_FLAG_VAL_FORCE) {
_stprintf(buffer + _tcslen(buffer), disasm_lc_hex(_T(" == $%08X")), addr);
}
showea_val(buffer, opcode, addr, size);
break;
case Ad16:
{
TCHAR offtxt[32];
disp16 = get_iword_debug (pc); pc += 2;
if (disp16 < 0)
_stprintf (offtxt, disasm_lc_hex(_T("-$%04X")), -disp16);
else
_stprintf (offtxt, disasm_lc_hex(_T("$%04X")), disp16);
addr = m68k_areg (regs, reg) + disp16;
_stprintf(buffer, _T("(%c%d,%s)"), disasm_areg, reg, offtxt);
if (disasm_flags & (DISASM_FLAG_VAL_FORCE | DISASM_FLAG_VAL)) {
_stprintf(buffer + _tcslen(buffer), disasm_lc_hex(_T(" == $%08X")), addr);
}
showea_val(buffer, opcode, addr, size);
}
break;
case Ad8r:
{
TCHAR name[10];
_stprintf(name, _T("%c%d"), disasm_areg, reg);
addr = ShowEA_disp(&pc, m68k_areg(regs, reg), buffer, name, false);
showea_val(buffer, opcode, addr, size);
}
break;
case PC16:
disp16 = get_iword_debug (pc); pc += 2;
addr += (uae_s16)disp16;
_stprintf(buffer, _T("(%s"), disasm_pcreg);
_stprintf(buffer + _tcslen(buffer), disasm_lc_hex(_T(",$%04X)")), disp16 & 0xffff);
if (disasm_flags & (DISASM_FLAG_VAL_FORCE | DISASM_FLAG_VAL)) {
_stprintf(buffer + _tcslen(buffer), disasm_lc_hex(_T(" == $%08X")), addr);
}
showea_val(buffer, opcode, addr, size);
break;
case PC8r:
{
addr = ShowEA_disp(&pc, addr, buffer, disasm_pcreg, true);
showea_val(buffer, opcode, addr, size);
}
break;
case absw:
{
addr = (uae_s32)(uae_s16)get_iword_debug (pc);
uae_s16 saddr = (uae_s16)addr;
if (absshort_long) {
_stprintf(buffer, disasm_lc_hex(_T("$%08X.%c")), addr, disasm_word);
} else if (saddr < 0) {
_stprintf(buffer, disasm_lc_hex(_T("-$%04X.%c")), -saddr, disasm_word);
} else {
_stprintf(buffer, disasm_lc_hex(_T("$%04X.%c")), saddr, disasm_word);
}
pc += 2;
showea_val(buffer, opcode, addr, size);
}
break;
case absl:
addr = get_ilong_debug (pc);
_stprintf (buffer, disasm_lc_hex(_T("$%08X")), addr);
pc += 4;
showea_val(buffer, opcode, addr, size);
break;
case imm:
if (actualea)
*actualea = 0;
switch (size){
case sz_byte:
_stprintf (buffer, disasm_lc_hex(_T("#$%02X")), (get_iword_debug (pc) & 0xff));
pc += 2;
break;
case sz_word:
_stprintf (buffer, disasm_lc_hex(_T("#$%04X")), (get_iword_debug (pc) & 0xffff));
pc += 2;
break;
case sz_long:
_stprintf(buffer, disasm_lc_hex(_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, disasm_lc_hex(_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, disasm_lc_hex(_T("#$%02X")), (uae_u32)(offset & 0xff));
addr = pc + 2 + offset;
if ((opcode & 0xf000) == 0x6000) {
showea_val(buffer, opcode, addr, 1);
}
pc += 2;
if (actualea)
*actualea = 0;
break;
case imm1:
offset = (uae_s32)(uae_s16)get_iword_debug (pc);
buffer[0] = 0;
_stprintf (buffer, disasm_lc_hex(_T("#$%04X")), (uae_u32)(offset & 0xffff));
addr = pc + offset;
if ((opcode & 0xf000) == 0x6000) {
showea_val(buffer, opcode, addr, 2);
}
pc += 2;
if (actualea)
*actualea = 0;
break;
case imm2:
offset = (uae_s32)get_ilong_debug (pc);
_stprintf (buffer, disasm_lc_hex(_T("#$%08X")), (uae_u32)offset);
addr = pc + offset;
if ((opcode & 0xf000) == 0x6000) {
showea_val(buffer, opcode, addr, 4);
}
pc += 4;
if (actualea)
*actualea = 0;
break;
case immi:
offset = (uae_s32)(uae_s8)(reg & 0xff);
_stprintf (buffer, disasm_lc_hex(_T("#$%02X")), (uae_u8)offset);
addr = pc + offset;
if (actualea)
*actualea = 0;
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,
_T("FSMOVE"), // 0x40
_T("FSSQRT"),
NULL,
NULL,
_T("FDMOVE"),
_T("FDSQRT"),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL, // 0x50
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
_T("FSABS"),
NULL,
_T("FSNEG"),
NULL,
_T("FDABS"),
NULL,
_T("FDNEG"),
NULL,
_T("FSDIV"), // 0x60
NULL,
_T("FSADD"),
_T("FSMUL"),
_T("FDDIV"),
NULL,
_T("FDADD"),
_T("FDMUL"),
_T("FSSUB"),
NULL,
NULL,
NULL,
_T("FDSUB"),
NULL,
NULL,
NULL,
NULL, // 0x70
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
_T("ILLG") // 0x80
};
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("FPCR"),
_T("FPSR"),
_T("FPIAR")
};
static void addmovemreg(TCHAR *out, int *prevreg, int *lastreg, int *first, int reg, int fpmode)
{
TCHAR s[10];
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))) {
_tcscpy(s, movemregs[*lastreg]);
if (disasm_flags & DISASM_FLAG_LC_REG) {
to_lower(s, -1);
}
_stprintf (p, _T("%s%s"), (*first) ? _T("") : _T("/"), s);
p = p + _tcslen (p);
if (*lastreg != *prevreg) {
_tcscpy(s, movemregs[*prevreg]);
if (disasm_flags & DISASM_FLAG_LC_REG) {
to_lower(s, -1);
}
if ((*lastreg) + 2 == reg) {
_stprintf(p, _T("/%s"), s);
} else if ((*lastreg) != (*prevreg)) {
_stprintf(p, _T("-%s"), s);
}
}
*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)
{
int size = dp->size;
if (dp->unsized) {
_tcscat(instrname, _T(" "));
return;
}
int m = dp->mnemo;
if (dp->suse && dp->smode == immi &&
(m == i_MOVE || m == i_ADD || m == i_ADDA || m == i_SUB || m == i_SUBA)) {
_tcscat(instrname, disasm_lc_size(_T("Q")));
if (m == i_MOVE)
size = -1;
}
// EXT.B -> EXTB.L
if (m == i_EXT && dp->size == sz_byte) {
_tcscat(instrname, disasm_lc_size(_T("B")));
size = sz_long;
}
switch (size)
{
case sz_byte:
_tcscat(instrname, disasm_lc_size(_T(".B ")));
break;
case sz_word:
_tcscat(instrname, disasm_lc_size(_T(".W ")));
break;
case sz_long:
_tcscat(instrname, disasm_lc_size(_T(".L ")));
break;
default:
_tcscat(instrname, disasm_lc_size(_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] == '$') {
s++;
}
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;
}
}
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 {
if (s[1] == '$')
startptr = s + 2;
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 {
if (s[1] == '$')
startptr = s + 2;
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 (uaetcslen(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, uaetcslen(line));
p = line;
while (*p && *p != ' ')
p++;
if (*p == ' ') {
*p = 0;
_tcscpy(parms, p + 1);
my_trim(parms);
}
_tcscpy(ins, line);
if (uaetcslen(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;
struct mnemolookup *lookup;
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 = uaetcslen(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') {
TCHAR insa[256];
_tcscpy(insa, ins);
_tcscat(insa, _T("A"));
for (lookup = lookuptab; lookup->name; lookup++) {
if (!_tcscmp(insa, lookup->name)) {
_tcscpy(ins, insa);
break;
}
}
}
}
bool fp = ins[0] == 'F';
int tsize = size;
if (ins[uaetcslen(ins) - 1] == 'Q' && uaetcslen(ins) > 3 && !fp) {
quick = 1;
ins[uaetcslen(ins) - 1] = 0;
if (inssize < 0)
tsize = 2;
}
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 unsized = 0;
for (int round = 0; round < 9; round++) {
if (!found && round == 8)
return 0;
if (round == 3) {
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);
if (disasm_flags & (DISASM_FLAG_VAL_FORCE | DISASM_FLAG_VAL)) {
_stprintf(p, disasm_lc_hex(_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("%c%d"), disasm_dreg, extra & 7);
return true;
case 0x0000:
if (extra & 1) {
_tcscpy(out, disasm_lc_reg(_T("DFC")));
} else {
_tcscpy(out, disasm_lc_reg(_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 *actualea, 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(" "));
disasm_lc_mnemo(instrname);
if (!rw) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, actualea, safemode);
_tcscat(instrname, _T(","));
}
_tcscat(instrname, disasm_lc_reg(r));
if (rw) {
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, actualea, 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;
if (!mmu_op30_helper_get_fc(extra, fc))
break;
_stprintf(instrname, _T("PLOAD%c"), mode == 0 ? 'W' : 'R');
disasm_lc_mnemo(instrname);
_stprintf(instrname + _tcslen(instrname), _T(" %s,"), fc);
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, actualea, safemode);
break;
case 0x04: // PFLUSHA
if (fc_bits)
break;
_tcscpy(instrname, _T("PFLUSHA"));
disasm_lc_mnemo(instrname);
break;
case 0x10: // FC
if (!mmu_op30_helper_get_fc(extra, fc))
break;
_tcscpy(instrname, _T("PFLUSH"));
disasm_lc_mnemo(instrname);
_stprintf(instrname + _tcslen(instrname), _T(" %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;
_tcscpy(instrname, _T("PFLUSH"));
disasm_lc_mnemo(instrname);
_stprintf(instrname + _tcslen(instrname), _T(" %s,%d"), fc, fc_mask);
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, actualea, 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"), rw ? 'R' : 'W');
disasm_lc_mnemo(instrname);
_stprintf(instrname + _tcslen(instrname), _T(" %s,"), fc);
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr2, actualea, safemode);
_stprintf(instrname + _tcslen(instrname), _T(",#%d"), level);
if (a)
_stprintf(instrname + _tcslen(instrname), _T(",%c%d"), disasm_areg, areg);
break;
}
default:
disasm_lc_mnemo(instrname);
break;
}
return pc;
}
static uae_u16 get_disasm_word(uaecptr pc, uae_u16 *bufpc, int bufpcsizep, int offset)
{
offset /= 2;
if (bufpc) {
if (bufpcsizep > offset) {
return bufpc[offset];
}
return 0;
} else {
return get_word_debug(pc + offset * 2);
}
}
static void add_disasm_word(uaecptr *pcp, uae_u16 **bufpcp, int *bufpcsizep, int add)
{
if (*bufpcp) {
*bufpcp += add;
*bufpcsizep -= add;
} else {
*pcp += add;
}
}
uae_u32 m68k_disasm_2(TCHAR *buf, int bufsize, uaecptr pc, uae_u16 *bufpc, int bufpcsize, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, uaecptr lastpc, int safemode)
{
uae_u32 seaddr2;
uae_u32 deaddr2;
int actualea_src = 0;
int actualea_dst = 0;
if (!table68k)
return 0;
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;
int illegal = 0;
int segid, lastsegid;
TCHAR *symbolpos;
bool skip = false;
seaddr2 = deaddr2 = 0xffffffff;
oldpc = pc;
opcode = get_disasm_word(pc, bufpc, bufpcsize, 0);
extra = get_disasm_word(pc, bufpc, bufpcsize, 2);
if (cpufunctbl[opcode] == op_illg_1 || cpufunctbl[opcode] == op_unimpl_1) {
m68kpc_illg = pc + 2;
illegal = 1;
}
dp = table68k + opcode;
if (dp->mnemo == i_ILLG) {
illegal = 0;
opcode = 0x4AFC;
dp = table68k + opcode;
}
for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
;
lastsegid = -1;
bool exact = false;
segid = 0;
if (!bufpc) {
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, disasm_lc_nhex(_T("%08X ")), pc);
if (segid) {
buf = buf_out(buf, &bufsize, _T("%s "), segout);
}
add_disasm_word(&pc, &bufpc, &bufpcsize, 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) {
if (lookup->mnemo == i_FBcc) {
_tcscpy(ccpt, fpccnames[opcode & 0x1f]);
} else {
_tcscpy(ccpt, fpccnames[extra & 0x1f]);
}
} else {
_tcscpy(ccpt, ccnames[dp->cc]);
if (dp->mnemo == i_Bcc && dp->cc == 0) {
_tcscpy(ccpt, _T("RA")); // BT -> BRA
}
}
}
disasm_lc_mnemo(instrname);
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 ? disasm_areg : disasm_dreg, 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);
}
int lvl = (currprefs.cpu_model - 68000) / 10;
if (lvl == 6)
lvl = 5;
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
if (lvl < 1 || !(m2cregs[j].flags & (1 << (lvl - 1))))
illegal = -1;
} else if (lookup->mnemo == i_CHK2) {
TCHAR *p;
if (!(extra & 0x0800)) {
instrname[1] = 'M';
instrname[2] = 'P';
disasm_lc_mnemo(instrname);
}
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
p = instrname + _tcslen(instrname);
_stprintf(p, _T(",%c%d"), (extra & 0x8000) ? disasm_areg : disasm_dreg, (extra >> 12) & 7);
} else if (lookup->mnemo == i_CAS) {
TCHAR *p = instrname + _tcslen(instrname);
_stprintf(p, _T("%c%d,%c%d,"), disasm_dreg, extra & 7, disasm_dreg, (extra >> 6) & 7);
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, &actualea_dst, safemode);
} else if (lookup->mnemo == i_CAS2) {
TCHAR *p = instrname + _tcslen(instrname);
uae_u16 extra2 = get_word_debug(pc + 2);
_stprintf(p, _T("%c%d:%c%d,%c%d,%c%d,(%c%d):(%c%d)"),
disasm_dreg, extra & 7, disasm_dreg, extra2 & 7, disasm_dreg, (extra >> 6) & 7, disasm_dreg, (extra2 >> 6) & 7,
(extra & 0x8000) ? disasm_areg : disasm_dreg, (extra >> 12) & 7,
(extra2 & 0x8000) ? disasm_areg : disasm_dreg, (extra2 >> 12) & 7);
add_disasm_word(&pc, &bufpc, &bufpcsize, 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, &actualea_src, safemode);
_tcscat(instrname, dp->size == sz_byte ? disasm_lc_reg(_T(",CCR")) : disasm_lc_reg(_T(",SR")));
} else if (lookup->mnemo == i_MVR2USP) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
_tcscat(instrname, disasm_lc_reg(_T(",USP")));
} else if (lookup->mnemo == i_MVUSP2R) {
_tcscat(instrname, disasm_lc_reg(_T("USP,")));
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
} else if (lookup->mnemo == i_MV2SR) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
_tcscat(instrname, dp->size == sz_byte ? disasm_lc_reg(_T(",CCR")) : disasm_lc_reg(_T(",SR")));
} else if (lookup->mnemo == i_MVSR2) {
_tcscat(instrname, dp->size == sz_byte ? disasm_lc_reg(_T("CCR,")) : disasm_lc_reg(_T("SR,")));
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
} else if (lookup->mnemo == i_MVMEL) {
uae_u16 mask = extra;
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
pc = ShowEA (NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
movemout (instrname, mask, dp->dmode, 0, true);
} else if (lookup->mnemo == i_MVMLE) {
uae_u16 mask = extra;
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
if (movemout(instrname, mask, dp->dmode, 0, false))
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, &actualea_dst, safemode);
} else if (lookup->mnemo == i_DIVL || lookup->mnemo == i_MULL) {
TCHAR *p;
extra = get_disasm_word(pc, bufpc, bufpcsize, 0);
add_disasm_word(&pc, &bufpc, &bufpcsize, 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[8] = 0;
instrname[7] = ' ';
instrname[6] = instrname[5];
instrname[5] = instrname[4];
instrname[4] = 'L';
}
disasm_lc_mnemo(instrname);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
p = instrname + _tcslen(instrname);
if (extra & 0x0400)
_stprintf(p, _T(",%c%d:%c%d"), disasm_dreg, extra & 7, disasm_dreg, (extra >> 12) & 7);
else
_stprintf(p, _T(",%c%d"), disasm_dreg, (extra >> 12) & 7);
} else if (lookup->mnemo == i_MOVES) {
TCHAR *p;
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
if (!(extra & 0x0800)) {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, &actualea_dst, safemode);
p = instrname + _tcslen(instrname);
_stprintf(p, _T(",%c%d"), (extra & 0x8000) ? disasm_areg : disasm_dreg, (extra >> 12) & 7);
} else {
p = instrname + _tcslen(instrname);
_stprintf(p, _T("%c%d,"), (extra & 0x8000) ? disasm_areg : disasm_dreg, (extra >> 12) & 7);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, &actualea_src, 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;
add_disasm_word(&pc, &bufpc, &bufpcsize, 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("%c%d,"), disasm_dreg, reg);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
_tcscat(instrname, _T(" {"));
p = instrname + _tcslen(instrname);
if (extra & 0x0800)
_stprintf(p, _T("%c%d"), disasm_dreg, (extra >> 6) & 7);
else
_stprintf(p, _T("%d"), (extra >> 6) & 31);
_tcscat(instrname, _T(":"));
p = instrname + _tcslen(instrname);
if (extra & 0x0020)
_stprintf(p, _T("%c%d"), disasm_dreg, 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(",%c%d"), disasm_dreg, 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, disasm_lc_reg(_T("BC")));
else if (opcode & 0x80)
_tcscat(instrname, disasm_lc_reg(_T("IC")));
else if (opcode & 0x40)
_tcscat(instrname, disasm_lc_reg(_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(",(%c%d)"), disasm_areg, opcode & 7);
}
} else if (lookup->mnemo == i_MOVE16) {
TCHAR *p = instrname + _tcslen(instrname);
if (opcode & 0x20) {
_stprintf(p, _T("(%c%d)+,(%c%d)+"), disasm_areg, opcode & 7, disasm_areg, (extra >> 12) & 7);
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
} else {
uae_u32 addr = get_long_debug(pc);
int ay = opcode & 7;
pc += 4;
switch ((opcode >> 3) & 3)
{
case 0:
_stprintf(p, _T("(%c%d)+,$%08x"), disasm_areg, ay, addr);
break;
case 1:
_stprintf(p, _T("$%08x,(%c%d)+"), addr, disasm_areg, ay);
break;
case 2:
_stprintf(p, _T("(%c%d),$%08x"), disasm_areg, ay, addr);
break;
case 3:
_stprintf(p, _T("$%08x,(%c%d)"), addr, disasm_areg, 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, &actualea_src, safemode);
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, &actualea_dst, safemode);
extra = get_word_debug(pc);
_stprintf(instrname + _tcslen(instrname), disasm_lc_hex(_T(",#$%04X")), extra);
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
} else if (lookup->mnemo == i_LPSTOP) {
if (extra == 0x01c0) {
uae_u16 extra2 = get_word_debug(pc + 2);
_tcscpy(instrname, _T("LPSTOP"));
disasm_lc_mnemo(instrname);
_stprintf(instrname + _tcslen(instrname), disasm_lc_hex(_T(" #$%04X")), extra2);
add_disasm_word(&pc, &bufpc, &bufpcsize, 4);
} else {
_tcscpy(instrname, _T("ILLG"));
disasm_lc_mnemo(instrname);
_stprintf(instrname + _tcslen(instrname), disasm_lc_hex(_T(" #$%04X")), extra);
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
}
} else if (lookup->mnemo == i_CALLM) {
TCHAR *p = instrname + _tcslen(instrname);
_stprintf(p, _T("#%d,"), extra & 255);
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
} else if (lookup->mnemo == i_FDBcc) {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, 0, imm1, sz_word, instrname, &deaddr2, &actualea_dst, safemode);
} else if (lookup->mnemo == i_FTRAPcc) {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, &actualea_src, safemode);
int mode = opcode & 7;
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
if (mode == 2) {
pc = ShowEA(NULL, pc, opcode, 0, imm1, sz_word, instrname, NULL, NULL, safemode);
} else if (mode == 3) {
pc = ShowEA(NULL, pc, opcode, 0, imm2, sz_long, instrname, NULL, NULL, safemode);
}
} else if (lookup->mnemo == i_FPP) {
TCHAR *p;
int ins = extra & 0x7f;
int size = (extra >> 10) & 7;
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
if ((extra & 0xfc00) == 0x5c00) { // FMOVECR (=i_FPP with source specifier = 7)
fpdata fp;
fpu_get_constant(&fp, extra & 0x7f);
_tcscpy(instrname, _T("FMOVECR.X"));
disasm_lc_mnemo(instrname);
_stprintf(instrname + _tcslen(instrname), _T(" #0x%02x [%s],%s%d"), extra & 0x7f, fpp_print(&fp, 0), disasm_fpreg, (extra >> 7) & 7);
} else if ((extra & 0x8000) == 0x8000) { // FMOVEM or FMOVE control register
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 "));
disasm_lc_mnemo(instrname);
} else {
mode = 0;
regmask = (extra >> 10) & 7; // FMOVEM or FMOVE control
fpmode = 2;
_tcscpy(instrname, _T("FMOVEM.L "));
if (regmask == 1 || regmask == 2 || regmask == 4)
_tcscpy(instrname, _T("FMOVE.L "));
disasm_lc_mnemo(instrname);
int msk = regmask & 2;
if (regmask & 1) {
msk |= 4;
}
if (regmask & 4) {
msk |= 1;
}
regmask = msk;
}
p = instrname + _tcslen(instrname);
if (dr) {
if (mode & 1)
_stprintf(p, _T("%c%d"), disasm_dreg, dreg);
else
movemout(p, regmask, dp->dmode, fpmode, false);
_tcscat(instrname, _T(","));
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, &actualea_dst, safemode);
} else {
if ((opcode & 0x3f) == 0x3c && !(extra & 0x2000)) {
// FMOVEM #xxx,control registers (strange one, can have up to 3 long word immediates)
bool entry = false;
if (!(extra & (0x400 | 0x800 | 0x1000)))
extra |= 0x400;
for (int i = 0; i < 3; i++) {
if (extra & (0x1000 >> i)) {
if (entry)
_tcscat(p, _T("/"));
entry = true;
p = instrname + _tcslen(instrname);
_stprintf(p, disasm_lc_hex(_T("#$%08X")), get_ilong_debug(pc));
add_disasm_word(&pc, &bufpc, &bufpcsize, 4);
}
}
} else {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, &actualea_dst, safemode);
}
p = instrname + _tcslen(instrname);
if (mode & 1)
_stprintf(p, _T(",%c%d"), disasm_dreg, dreg);
else
movemout(p, regmask, dp->dmode, fpmode, true);
}
} else {
if (fpuopcodes[ins]) {
_tcscpy(instrname, fpuopcodes[ins]);
} else {
_stprintf(instrname, _T("%s?%02X"), disasm_lc_reg(_T("F")), ins);
}
disasm_lc_mnemo(instrname);
if ((extra & (0x8000 | 0x4000 | 0x2000)) == (0x4000 | 0x2000)) { // FMOVE to memory/data register
int kfactor = extra & 0x7f;
_tcscpy(instrname, _T("FMOVE."));
_tcscat(instrname, fpsizes[size]);
disasm_lc_mnemo(instrname);
_tcscat(instrname, _T(" "));
p = instrname + _tcslen(instrname);
_stprintf(p, _T("%s%d,"), disasm_fpreg, (extra >> 7) & 7);
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &deaddr2, &actualea_dst, safemode);
p = instrname + _tcslen(instrname);
if (size == 7) {
_stprintf(p, _T(" {%c%d}"), disasm_dreg, (kfactor >> 4));
} else if (kfactor) {
if (kfactor & 0x40)
kfactor |= ~0x3f;
_stprintf(p, _T(" {%d}"), kfactor);
}
} else if ((extra & (0x8000 | 0x2000)) == 0) {
if (extra & 0x4000) { // source is EA
_tcscat(instrname, _T("."));
_tcscat(instrname, disasm_lc_size(fpsizes[size]));
_tcscat(instrname, _T(" "));
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &seaddr2, &actualea_src, safemode);
} else { // source is FPx
p = instrname + _tcslen(instrname);
_tcscat(p, disasm_lc_reg(_T(".X")));
p = instrname + _tcslen(instrname);
_stprintf(p, _T(" %s%d"), disasm_fpreg, (extra >> 10) & 7);
}
p = instrname + _tcslen(instrname);
if (ins >= 0x30 && ins < 0x38) { // FSINCOS
p = instrname + _tcslen(instrname);
_stprintf(p, _T(",%s%d"), disasm_fpreg, extra & 7);
p = instrname + _tcslen(instrname);
_stprintf(p, _T(",%s%d"), disasm_fpreg, (extra >> 7) & 7);
} else {
if ((extra & 0x4000) || (((extra >> 7) & 7) != ((extra >> 10) & 7))) {
_stprintf(p, _T(",%s%d"), disasm_fpreg, (extra >> 7) & 7);
}
}
}
if (ins >= 0x40 && currprefs.fpu_model >= 68881 && fpuopcodes[ins]) {
_tcscat(instrname, _T(" (68040+)"));
}
}
} else if (lookup->mnemo == i_MMUOP030) {
pc = disasm_mmu030(pc, opcode, extra, dp, instrname, &seaddr2, &actualea_src, safemode);
} else if ((opcode & 0xf000) == 0xa000) {
_tcscpy(instrname, _T("A-LINE"));
disasm_lc_mnemo(instrname);
} else {
if (lookup->mnemo == i_FBcc && (opcode & 0x1f) == 0 && extra == 0) {
_tcscpy(instrname, _T("FNOP"));
disasm_lc_mnemo(instrname);
add_disasm_word(&pc, &bufpc, &bufpcsize, 2);
} else {
if (dp->suse) {
pc = ShowEA(NULL, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, &actualea_src, 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, &actualea_dst, safemode);
}
if (lookup->mnemo == i_RTS || lookup->mnemo == i_RTD || lookup->mnemo == i_RTR || lookup->mnemo == i_RTE) {
uaecptr a = regs.regs[15];
TCHAR eas[100];
eas[0] = 0;
if (lookup->mnemo == i_RTE || lookup->mnemo == i_RTR) {
a += 2;
}
if (disasm_flags & DISASM_FLAG_EA) {
_stprintf(eas, disasm_lc_hex(_T(" == $%08X")), get_ilong_debug(a));
}
_tcscat(instrname, eas);
}
}
}
if (disasm_flags & DISASM_FLAG_WORDS) {
for (i = 0; i < (pc - oldpc) / 2 && i < disasm_max_words; i++) {
buf = buf_out(buf, &bufsize, disasm_lc_nhex(_T("%04X ")), get_word_debug(oldpc + i * 2));
}
while (i++ < disasm_min_words) {
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 != 0xffffffff ? deaddr2 : seaddr2;
if (deaddr)
*deaddr = pc;
if ((opcode & 0xf000) == 0xf000) {
if (currprefs.fpu_model) {
if (disasm_flags & DISASM_FLAG_EA) {
buf = buf_out(buf, &bufsize, disasm_lc_hex(_T(" == $%08X")), addr2);
}
if (disasm_flags & DISASM_FLAG_CC) {
if (fpp_cond(dp->cc)) {
buf = buf_out(buf, &bufsize, _T(" (T)"));
} else {
buf = buf_out(buf, &bufsize, _T(" (F)"));
}
}
}
} else {
if (dp->mnemo == i_Bcc || dp->mnemo == i_DBcc) {
if (disasm_flags & DISASM_FLAG_EA) {
buf = buf_out(buf, &bufsize, disasm_lc_hex(_T(" == $%08X")), addr2);
}
if (disasm_flags & DISASM_FLAG_CC) {
if (cctrue(dp->cc)) {
buf = buf_out(buf, &bufsize, _T(" (T)"));
} else {
buf = buf_out(buf, &bufsize, _T(" (F)"));
}
}
} else {
if (disasm_flags & DISASM_FLAG_CC) {
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;
if (disasm_flags & DISASM_FLAG_EA) {
buf = buf_out(buf, &bufsize, disasm_lc_hex(_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 > uaetcslen(segout)) {
memmove(symbolpos + uaetcslen(segout), symbolpos, (uaetcslen(symbolpos) + 1) * sizeof(TCHAR));
memcpy(symbolpos, segout, uaetcslen(segout) * sizeof(TCHAR));
bufsize -= uaetcslen(segout);
buf += uaetcslen(segout);
symbolpos += uaetcslen(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 > 0)
pc = m68kpc_illg;
}
if (nextpc)
*nextpc = pc;
if (seaddr)
*seaddr = seaddr2;
if (deaddr)
*deaddr = deaddr2;
return (actualea_src ? 1 : 0) | (actualea_dst ? 2 : 0);
}
/*************************************************************
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, 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, 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;
}