www.pudn.com > ncdzsrc.rar > i68k.c
/***************************************************************************
i68k.c
MC68000 簡易インタプリタ (調整中)
以下の命令は未サポート
MOVEP (to Dn) MOVEP (from Dn)
PEA LINK UNLK
CHK TRAP TRAPV
ABCD NBCD SBCD
RTR
特権命令全て
(サポートしている命令でも実装していないオペレーションあり)
元々デバッガ用に作成した、処理内容を画面に出力する関数だった為、
サイクル数等は一切考慮していません。速度もそれなりに遅いです。
***************************************************************************/
#include "neogeocd.h"
#define VERBOSE 0
#if VERBOSE
#define LOG(x) { if (i68k_verbose) { logerror x; } }
#else
#define LOG(x)
#endif
/****************************************************************************
マクロ
***************************************************************************/
#define An 0 // address register
#define Dn 1 // data register
#define AI 2 // address register indirect
#define PI 3 // postincrement
#define PI7 4 // postincrement (A7)
#define PD 5 // predecrement
#define PD7 6 // predecrement (A7)
#define IX 7 // indirect + index
#define IM 8 // immidiate
#define AA 9 // absolute addressing
#define MM 10 // movem register list
#define CCR 11 // condition code register
#define SR 12 // status register
#define NA -1 // N/A
#define SIZE_B 1
#define SIZE_W 2
#define SIZE_L 4
#define NOTFOUND 0
#define SET1 1
#define SET2 2
#define TEST 3
#define INVALID 4
#define OTHER 5
#define OPCODE(x) (strcmp(opcode, x) == 0)
#define MAKE_INT_8(A) (INT8)((A) & 0xff)
#define MAKE_INT_16(A) (INT16)((A) & 0xffff)
#define MAKE_INT_32(A) (INT32)((A) & 0xffffffff)
#define HI (C == 0 && Z == 0)
#define LS (C != 0 || Z != 0)
#define CC (C == 0)
#define CS (C != 0)
#define NE (Z == 0)
#define EQ (Z != 0)
#define VC (V == 0)
#define VS (V != 0)
#define PL (N == 0)
#define MI (N != 0)
#define GE ((N == 0) == (V == 0))
#define LT ((N == 0) != (V == 0))
#define GT (Z == 0 && (N == 0) == (V == 0))
#define LE (Z != 0 || (N == 0) != (V == 0))
#define read8(addr) m68000_read_memory_8(addr)
#define read16(addr) m68000_read_memory_16(addr)
#define read32(addr) m68000_read_memory_32(addr)
#define write8(addr, data) m68000_write_memory_8(addr, data)
#define write16(addr, data) m68000_write_memory_16(addr, data)
#define write32(addr, data) m68000_write_memory_32(addr, data)
/****************************************************************************
プロトタイプ
***************************************************************************/
int m68k_disassemble(char *str_buff, int pc);
/****************************************************************************
ローカル変数
***************************************************************************/
int i68k_verbose = 0;
static UINT32 value1, value2, addr1, addr2;
static UINT32 a[8], d[8];
static UINT16 sr;
static int X, N, Z, V, C;
/***************************************************************************
文字列解析
***************************************************************************/
/*--------------------------------------------------------
buf1の文字列からデータの種類を判別し、計算しやすい
形に変換してbuf2に格納する
引 数: char *buf1 元の文字列
char *buf2 変換した文字列の格納先
UINT32 pc 現在のPC(OPCODE含む)
戻り値: 文字列の種類
アドレスレジスタ及びデータレジスタはbuf[0]に
レジスタ番号が数値で入ります
-------------------------------------------------------*/
static int check_type(char *buf1, char *buf2, UINT32 pc)
{
int i, j;
memset(buf2, 0, 256);
switch (buf1[0])
{
case '[':
// movem - 表記を変更してあります
for (i = 1; buf1[i] != ']'; i++)
buf2[i - 1] = buf1[i];
return MM;
case 'A':
// アドレスレジスタ
buf2[0] = buf1[1] - '0';
return An;
case 'D': // データレジスタ
buf2[0] = buf1[1] - '0';
return Dn;
case 'C': // CCR
buf2[0] = 0;
return SR;
case 'S': // ステータスレジスタ
buf2[0] = 0;
return SR;
case '#': // イミディエイト
i = 1;
j = 0;
while (1)
{
if (buf1[i] == '\0'
|| buf1[i] == ','
|| buf1[i] == '.')
{
break;
}
else
if ((buf1[i] == '-')
|| (buf1[i] >= '0' && buf1[i] <= '9')
|| (buf1[i] >= 'a' && buf1[i] <= 'f'))
{
buf2[j++] = buf1[i];
}
i++;
}
return IM;
case '$': // アドレス直接指定
strcpy(buf2, &buf1[1]);
*strchr(buf2, '.') = '\0';
return AA;
case '-': // プレデクリメント
buf2[0] = buf1[2];
buf2[1] = buf1[3];
return (buf1[3] == '7') ? PD7 : PD;
case '(':
if (buf1[1] == 'A' && buf1[3] == ')')
{
buf2[0] = buf1[1];
buf2[1] = buf1[2];
if (buf1[4] == '+')
{
// ポストインクリメント
return (buf1[2] == '7') ? PI7 : PI;
}
else
{
// アドレスレジスタ間接参照
return AI;
}
}
i = 1;
j = 0;
while (1)
{
if (buf1[i] == ')')
break;
else if (buf1[i] == ',')
{
buf2[j++] = ',';
}
else
if (buf1[i] == 'P')
{
char tmp[16];
// PCは数値に変換しておく
sprintf(tmp, "%x", pc + 2);
strcat(buf2, tmp);
i++;
j += strlen(tmp);
}
else
if ((buf1[i] == 'A')
|| (buf1[i] == 'D')
|| (buf1[i] == '-')
|| (buf1[i] >= '0' && buf1[i] <= '9')
|| (buf1[i] >= 'a' && buf1[i] <= 'f'))
{
buf2[j++] = buf1[i];
}
i++;
}
return IX;
default:
return NA;
}
}
/***************************************************************************
レジスタ操作
***************************************************************************/
/*--------------------------------------------------------
データレジスタの値を取得
引 数: int n レジスタ番号
int size サイズ (バイト)
戻り値: レジスタのの値
-------------------------------------------------------*/
static UINT32 get_d(int n, int size)
{
switch (size)
{
case SIZE_B: return d[n] & 0xff;
case SIZE_W: return d[n] & 0xffff;
}
return d[n];
}
/*--------------------------------------------------------
データレジスタの値を設定
引 数: int n レジスタ番号
UINT32 value 設定する値
int size サイズ (バイト)
戻り値: なし
-------------------------------------------------------*/
static void set_d(int n, UINT32 value, int size)
{
switch (size)
{
case SIZE_B:
d[n] &= 0xffffff00;
d[n] |= value & 0xff;
return;
case SIZE_W:
d[n] &= 0xffff0000;
d[n] |= value & 0xffff;
return;
}
d[n] = value;
}
/*--------------------------------------------------------
アドレスレジスタの値を取得
引 数: int n レジスタ番号
int size サイズ (バイト)
戻り値: レジスタのの値
※現状常にLONGの値を返します
-------------------------------------------------------*/
static UINT32 get_a(int n)
{
return a[n];
}
/*--------------------------------------------------------
アドレスレジスタの値を設定
引 数: int n レジスタ番号
UINT32 value 設定する値
int size サイズ (バイト)
戻り値: なし
※現状常にLONGの値を設定します
-------------------------------------------------------*/
static void set_a(int n, UINT32 value)
{
a[n] = value;
}
/***************************************************************************
イミディエイト値操作
***************************************************************************/
/*--------------------------------------------------------
即値の文字列を数値に変換して取得
引 数: char *buf 文字列のバッファ
int size サイズ (バイト)
戻り値: 値
-------------------------------------------------------*/
static UINT32 get_imm(char *buf, int size)
{
int value;
if (buf[0] == '-')
{
sscanf(&buf[1], "%x", &value);
value = 0 - value;
}
else
{
sscanf(buf, "%x", &value);
}
switch (size)
{
case SIZE_B: return value & 0xff;
case SIZE_W: return value & 0xffff;
}
return value;
}
/***************************************************************************
エフェクティブアドレス操作
***************************************************************************/
/*--------------------------------------------------------
アドレスの文字列を数値に変換して取得
引 数: char *buf 文字列のバッファ
int size サイズ (バイト)
戻り値: アドレスの値
-------------------------------------------------------*/
static int get_ea(char *buf, int *a, int *d, int type, int size)
{
int n, res = 0;
char *p;
switch (type)
{
case AI:
n = buf[1] - '0';
res = a[n];
break;
case PD:
case PD7:
n = buf[1] - '0';
a[n] -= size;
res = a[n];
break;
case PI:
case PI7:
n = buf[1] - '0';
res = a[n];
a[n] += size;
break;
case AA:
sscanf(buf, "%x", &res);
break;
case IX:
p = strtok(buf, ",\n\0");
while (p)
{
if ((p[0] == '-') || (p[0] >= '0' && p[0] <= '9') || (p[0] >= 'a' && p[0] <= 'f'))
{
int value;
if (p[0] == '-')
{
sscanf(&p[1], "%x", &value);
value = 0 - value;
}
else
{
sscanf(p, "%x", &value);
}
res += value;
}
else if (p[0] == 'A')
{
n = p[1] - '0';
res += a[n];
}
else if (p[0] == 'D')
{
n = p[1] - '0';
res += MAKE_INT_16(d[n]);
}
p = strtok(NULL, ",\n\0");
}
break;
}
return res;
}
/*--------------------------------------------------------
アドレスのデータを取得
引 数: int addr アドレス
int size サイズ (バイト)
戻り値: アドレスの値
-------------------------------------------------------*/
static UINT32 read_ea(int addr, int size)
{
switch (size)
{
case SIZE_B: return read8(addr);
case SIZE_W: return read16(addr);
}
return read32(addr);
}
/*--------------------------------------------------------
アドレスのデータを設定
引 数: int addr アドレス
UINT32 value 設定する値
int size サイズ (バイト)
戻り値: なし
-------------------------------------------------------*/
static void write_ea(int addr, UINT32 value, int size)
{
switch (size)
{
case SIZE_B: write8(addr, value & 0xff); return;
case SIZE_W: write16(addr, value & 0xffff); return;
}
write32(addr, value);
}
/***************************************************************************
オペレーション & フラグセット
***************************************************************************/
/*--------------------------------------------------------
ネガティブフラグ取得
引 数: UINT32 result オペレーションの結果の値
int size サイズ (バイト)
戻り値: Nフラグの値
-------------------------------------------------------*/
static int NFLAG(UINT32 result, int size)
{
switch (size)
{
case SIZE_B: return (result & 0x80) != 0;
case SIZE_W: return (result & 0x8000) != 0;
}
return (result & 0x80000000) != 0;
}
/*--------------------------------------------------------
ゼロフラグ取得
引 数: UINT32 result オペレーションの結果の値
int size サイズ (バイト)
戻り値: Zフラグの値
-------------------------------------------------------*/
static int ZFLAG(UINT32 result, int size)
{
switch (size)
{
case SIZE_B: return (result & 0xff) == 0;
case SIZE_W: return (result & 0xffff) == 0;
}
return (result & 0xffffffff) == 0;
}
/*--------------------------------------------------------
ADDを実行し、演算結果を返す
引 数: UINT32 s ソース
UINT32 d デスティネーション
int size サイズ (バイト)
戻り値: 演算結果
※同時にフラグも設定します
-------------------------------------------------------*/
#define VFLAG_ADD(s, d, r) ((s ^ r) & (d ^ r))
static UINT32 op_add(UINT32 s, UINT32 d, int size)
{
UINT32 result;
switch (size)
{
case SIZE_B:
s &= 0x000000ff;
d &= 0x000000ff;
break;
case SIZE_W:
s &= 0x0000ffff;
d &= 0x0000ffff;
break;
}
result = d + s;
switch (size)
{
case SIZE_B:
C = result;
V = VFLAG_ADD(s, d, result);
result &= 0x000000ff;
break;
case SIZE_W:
C = result >> 8;
V = VFLAG_ADD(s, d, result) >> 8;
result &= 0x0000ffff;
break;
case SIZE_L:
C = ((s & d & 1) + (s >> 1) + (d >> 1)) >> 23;
V = VFLAG_ADD(s, d, result) >> 24;
break;
}
C = (C & 0x100) != 0;
V = (V & 0x80) != 0;
N = NFLAG(result, size);
Z = ZFLAG(result, size);
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x + %02x (=%02x) -> ", d, s, result)); break;
case SIZE_W: LOG(("%04x + %04x (=%04x) -> ", d, s, result)); break;
case SIZE_L: LOG(("%08x + %08x (=%08x) -> ", d, s, result)); break;
}
#endif
return result;
}
/*--------------------------------------------------------
SUBを実行し、演算結果を返す
引 数: UINT32 s ソース
UINT32 d デスティネーション
int size サイズ (バイト)
戻り値: 演算結果
※同時にフラグも設定します
-------------------------------------------------------*/
#define VFLAG_SUB(s, d, r) ((s ^ d) & (r ^ d))
static UINT32 op_sub(UINT32 s, UINT32 d, int size)
{
UINT32 result;
switch (size)
{
case SIZE_B:
s &= 0x000000ff;
d &= 0x000000ff;
break;
case SIZE_W:
s &= 0x0000ffff;
d &= 0x0000ffff;
break;
}
result = d - s;
switch (size)
{
case SIZE_B:
C = result;
V = VFLAG_SUB(s, d, result);
result &= 0x000000ff;
break;
case SIZE_W:
C = result >> 8;
V = VFLAG_SUB(s, d, result) >> 8;
result &= 0x0000ffff;
break;
case SIZE_L:
C = ((s & result & 1) + (s >> 1) + (result >> 1)) >> 23;
V = VFLAG_SUB(s, d, result) >> 24;
break;
}
C = (C & 0x100) != 0;
V = (V & 0x80) != 0;
N = NFLAG(result, size);
Z = ZFLAG(result, size);
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x - %02x (=%02x) -> ", d, s, result)); break;
case SIZE_W: LOG(("%04x - %04x (=%04x) -> ", d, s, result)); break;
case SIZE_L: LOG(("%08x - %08x (=%08x) -> ", d, s, result)); break;
}
#endif
return result;
}
/*--------------------------------------------------------
ANDを実行し、演算結果を返す
引 数: UINT32 s ソース
UINT32 d デスティネーション
int size サイズ (バイト)
戻り値: 演算結果
※同時にフラグも設定します
-------------------------------------------------------*/
static UINT32 op_and(UINT32 s, UINT32 d, int size)
{
UINT32 result;
switch (size)
{
case SIZE_B:
s &= 0x000000ff;
d &= 0x000000ff;
break;
case SIZE_W:
s &= 0x0000ffff;
d &= 0x0000ffff;
break;
}
result = d & s;
switch (size)
{
case SIZE_B:
result &= 0x000000ff;
break;
case SIZE_W:
result &= 0x0000ffff;
break;
}
C = 0;
V = 0;
N = NFLAG(result, size);
Z = ZFLAG(result, size);
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x & %02x (=%02x) -> ", d, s, result)); break;
case SIZE_W: LOG(("%04x & %04x (=%04x) -> ", d, s, result)); break;
case SIZE_L: LOG(("%08x & %08x (=%08x) -> ", d, s, result)); break;
}
#endif
return result;
}
/*--------------------------------------------------------
EORを実行し、演算結果を返す
引 数: UINT32 s ソース
UINT32 d デスティネーション
int size サイズ (バイト)
戻り値: 演算結果
※同時にフラグも設定します
-------------------------------------------------------*/
static UINT32 op_eor(UINT32 s, UINT32 d, int size)
{
UINT32 result;
switch (size)
{
case SIZE_B:
s &= 0x000000ff;
d &= 0x000000ff;
break;
case SIZE_W:
s &= 0x0000ffff;
d &= 0x0000ffff;
break;
}
result = d ^ s;
switch (size)
{
case SIZE_B:
result &= 0x000000ff;
break;
case SIZE_W:
result &= 0x0000ffff;
break;
}
C = 0;
V = 0;
N = NFLAG(result, size);
Z = ZFLAG(result, size);
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x ^ %02x (=%02x) -> ", d, s, result)); break;
case SIZE_W: LOG(("%04x ^ %04x (=%04x) -> ", d, s, result)); break;
case SIZE_L: LOG(("%08x ^ %08x (=%08x) -> ", d, s, result)); break;
}
#endif
return result;
}
/*--------------------------------------------------------
ORを実行し、演算結果を返す
引 数: UINT32 s ソース
UINT32 d デスティネーション
int size サイズ (バイト)
戻り値: 演算結果
※同時にフラグも設定します
-------------------------------------------------------*/
static UINT32 op_or(UINT32 s, UINT32 d, int size)
{
UINT32 result;
switch (size)
{
case SIZE_B:
s &= 0x000000ff;
d &= 0x000000ff;
break;
case SIZE_W:
s &= 0x0000ffff;
d &= 0x0000ffff;
break;
}
result = d | s;
switch (size)
{
case SIZE_B:
result &= 0x000000ff;
break;
case SIZE_W:
result &= 0x0000ffff;
break;
}
C = 0;
V = 0;
N = NFLAG(result, size);
Z = ZFLAG(result, size);
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x | %02x (=%02x) -> ", d, s, result)); break;
case SIZE_W: LOG(("%04x | %04x (=%04x) -> ", d, s, result)); break;
case SIZE_L: LOG(("%08x | %08x (=%08x) -> ", d, s, result)); break;
}
#endif
return result;
}
/***************************************************************************
文字列から値を取得
***************************************************************************/
/*--------------------------------------------------------
値1(ソースまたはデスティネーションのみの場合)
引 数: char *buf 文字列のバッファ
int type check_type()で取得した値
int size サイズ (バイト)
戻り値: なし
※value1に値を、EAの場合はaddr1にアドレスを設定します
-------------------------------------------------------*/
INLINE void get_value1(char *buf, int type, int size)
{
switch (type)
{
case NA:
LOG(("(error) "));
break;
case CCR:
value1 = ((X << 4) | (N << 3) | (Z << 2) | (V << 1) | C);
break;
case SR:
value1 = (SR & 0xffe1) | ((X << 4) | (N << 3) | (Z << 2) | (V << 1) | C);
break;
case An:
value1 = a[(int)buf[0]];
break;
case Dn:
value1 = get_d(buf[0], size);
break;
case IM:
value1 = get_imm(buf, size);
break;
default:
addr1 = get_ea(buf, a, d, type, size);
value1 = read_ea(addr1, size);
break;
}
}
/*--------------------------------------------------------
値2 (デスティネーション)
引 数: char *buf 文字列のバッファ
int type check_type()で取得した値
int size サイズ (バイト)
戻り値: なし
※value2に値を、EAの場合はaddr2にアドレスを設定します
-------------------------------------------------------*/
INLINE void get_value2(char *buf, int type, int size)
{
switch (type)
{
case NA:
LOG(("(error) "));
break;
case CCR:
value1 = ((X << 4) | (N << 3) | (Z << 2) | (V << 1) | C);
break;
case SR:
value1 = (SR & 0xffe1) | ((X << 4) | (N << 3) | (Z << 2) | (V << 1) | C);
break;
case An:
value2 = a[(int)buf[0]];
break;
case Dn:
value2 = get_d(buf[0], size);
break;
case IM:
value2 = get_imm(buf, size);
break;
default:
addr2 = get_ea(buf, a, d, type, size);
value2 = read_ea(addr2, size);
break;
}
}
/***************************************************************************
インタプリタコア
***************************************************************************/
/*--------------------------------------------------------
MC68000 簡易インタプリタ
引 数: UINT32 start_pc 開始PC
UINT32 break_point ブレークポイント
戻り値: なし
※ブレークポイントが'0'の場合は、開始PCと同じレベルの
処理が終了した時点で停止します
-------------------------------------------------------*/
void m68000_interpreter(UINT32 start_pc, UINT32 break_point)
{
UINT32 pc, nest_pc[256];
int type1, type2, size;
char buf[256], src[256], dst[256];
char *opcode, *p, *tmp1, *tmp2;
UINT32 mask, msb, nest_count, result;
int i, n1, n2, opcode_len, op;
pc = start_pc;
nest_count= 0;
for (i = 0; i < 8; i++)
{
a[i] = m68000_get_reg(M68K_A0 + i);
d[i] = m68000_get_reg(M68K_D0 + i);
}
sr = m68000_get_reg(M68K_SR);
C = sr & (1 << 0);
V = sr & (1 << 1);
Z = sr & (1 << 2);
N = sr & (1 << 3);
X = sr & (1 << 4);
// NEOGEO CD用
a[5] = 0x108000;
a[7] -= 4 * 8 * 2; // スタックを破壊しないように念の為
result = 0;
n1 = 0;
n2 = 0;
LOG(("\n-- start --\n"));
while (pc != break_point)
{
opcode_len = m68k_disassemble(buf, pc);
if ((p = strchr(buf, ';')) != NULL) *p = '\0'; // コメント削除
LOG(("%06x: %-32s", pc, buf));
opcode = strtok(buf, " \n");
tmp1 = strtok(NULL, " \n");
tmp2 = strtok(NULL, " \n");
if (tmp1 != NULL)
type1 = check_type(tmp1, src, pc);
else
type1 = NA;
if (tmp2 != NULL)
type2 = check_type(tmp2, dst, pc);
else
type2 = NA;
if ((p = strchr(buf, '.')) != NULL)
{
switch (*(p + 1))
{
case 'b':
size = SIZE_B;
mask = 0x000000ff;
msb = 0x00000080;
break;
case 'w':
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
break;
default:
size = SIZE_L;
mask = 0xffffffff;
msb = 0x80000000;
break;
}
*p = '\0';
}
else
{
size = SIZE_L;
mask = 0xffffffff;
msb = 0x80000000;
}
if (type2 == An && size == SIZE_B)
{
LOG(("%s\tbyte size oparation (illegal).\n"));
pc += opcode_len;
continue;
}
LOG(("%s\t", opcode));
if (type1 == An || type1 == Dn) n1 = src[0];
if (type2 == An || type2 == Dn) n2 = dst[0];
// 実行
op = NOTFOUND;
switch (opcode[0])
{
case 'a':
if (OPCODE("add") || OPCODE("addi"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
result = op_add(value1, value2, size);
X = C;
op = SET2;
}
else if (OPCODE("adda"))
{
get_value1(src, type1, size);
get_value2(dst, type2, SIZE_L);
if (size == SIZE_W && type1 != An)
value1 = MAKE_INT_16(value1);
result = value2 + value1;
LOG(("%06x + %08x (=%06x) -> ", value2, value1, result));
op = SET2;
}
else if (OPCODE("addq"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
if (type2 == An)
{
if (size == SIZE_W && type1 != An)
value1 = MAKE_INT_16(value1);
result = value2 + value1;
LOG(("%06x + %08x (=%06x) -> ", value2, value1, result));
}
else
{
result = op_add(value1, value2, size);
X = C;
}
op = SET2;
}
else if (OPCODE("addx"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
result = op_add(value1 + X, value2, size);
X = C;
op = SET2;
}
else if (OPCODE("and") || OPCODE("andi"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
result = op_and(value1, value2, size);
op = SET2;
}
else if (OPCODE("asl"))
{
UINT32 msb_bit1, msb_bit2;
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
}
else
{
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
value1 = 1;
get_value2(src, type1, size);
}
result = value2;
if (value1 == 0)
{
C = 0;
}
else
{
msb_bit1 = result & msb;
X = C = (result & (msb >> (value1 - 1))) != 0;
msb_bit2 = msb_bit1;
for (i = 0; i < value1; i++)
{
result = (result << 1) & mask;
V = (msb_bit2 != (result & msb));
msb_bit2 = result & msb;
}
result = (result & ~msb) | msb_bit1;
}
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x << %d (=%02x) -> ", value2, value1, result)); break;
case SIZE_W: LOG(("%04x << %d (=%04x) -> ", value2, value1, result)); break;
case SIZE_L: LOG(("%08x << %d (=%08x) -> ", value2, value1, result)); break;
}
#endif
Z = ZFLAG(result, size);
N = NFLAG(result, size);
op = SET2;
}
else if (OPCODE("asr"))
{
UINT32 msb_bit1, msb_bit2;
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
}
else
{
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
value1 = 1;
get_value2(src, type1, size);
}
result = value2;
if (value1 == 0)
{
C = 0;
}
else
{
msb_bit1 = result & msb;
X = C = (result & (1 << (value1 - 1))) != 0;
msb_bit2 = msb_bit1;
for (i = 0; i < value1; i++)
{
result = (result >> 1) & mask;
V = (msb_bit2 != (result & msb));
msb_bit2 = result & msb;
}
result = (result & ~msb) | msb_bit1;
}
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x >> %d (=%02x) -> ", value2, value1, result)); break;
case SIZE_W: LOG(("%04x >> %d (=%04x) -> ", value2, value1, result)); break;
case SIZE_L: LOG(("%08x >> %d (=%08x) -> ", value2, value1, result)); break;
}
#endif
Z = ZFLAG(result, size);
N = NFLAG(result, size);
op = SET2;
}
break;
case 'b':
if (OPCODE("bchg") || OPCODE("bclr") || OPCODE("bset") || OPCODE("btst"))
{
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
value1 %= 32;
Z = (value2 & (1 << value1)) == 0;
LOG(("%08x & bit%d -> Z (= %d)", value2, value1, Z));
}
else
{
size = SIZE_B;
mask = 0x000000ff;
msb = 0x00000080;
get_value1(src, type1, size);
get_value2(dst, type2, size);
value1 %= 8;
Z = (value2 & (1 << value1)) == 0;
LOG(("%02x & bit%d -> Z (= %d)", value2, value1, Z));
}
if (opcode[2] != 's')
{
switch (opcode[2])
{
case 'h': // bchg
result = value2 ^ (value2 & (1 << value1));
break;
case 'l': // bclr
result = value2 & ~(value2 & (1 << value1));
break;
case 'e': // bset
result = value2 | (value2 & (1 << value1));
break;
}
LOG((", %08x -> ", result));
op = SET2;
}
else
{
LOG(("\n"));
op = OTHER; // TEST
}
}
else if (OPCODE("bsr"))
{
nest_pc[nest_count++] = pc + opcode_len;
pc = (pc + 2) + MAKE_INT_16(get_imm(src, SIZE_W));
LOG(("(branch to sub routine %06x)\n\n", pc));
continue;
}
else if (OPCODE("bra") || OPCODE("bf"))
{
pc = (pc + 2) + MAKE_INT_16(get_imm(src, SIZE_W));
LOG(("(branch to %06x)\n", pc));
continue;
}
else if (OPCODE("bcc") || OPCODE("bcs") || OPCODE("beq") || OPCODE("bge") ||
OPCODE("bgt") || OPCODE("bhi") || OPCODE("ble") || OPCODE("bls") ||
OPCODE("blt") || OPCODE("bmi") || OPCODE("bne") || OPCODE("bpl") ||
OPCODE("bvc") || OPCODE("bvs") || OPCODE("bt"))
{
switch (opcode[1])
{
case 'e': result = EQ; break;
case 'h': result = HI; break;
case 'm': result = MI; break;
case 'n': result = NE; break;
case 'p': result = PL; break;
case 't': result = 1; break;
case 'c': result = (opcode[2] == 'c') ? CC : CS; break;
case 'g': result = (opcode[2] == 'e') ? GE : GT; break;
case 'v': result = (opcode[2] == 'c') ? VC : VS; break;
case 'l':
switch (opcode[2])
{
case 'e': result = LE; break;
case 's': result = LS; break;
case 't': result = LT; break;
}
break;
}
if (result)
{
pc = (pc + 2) + MAKE_INT_16(get_imm(src, SIZE_W));
LOG(("(branch to %06x)\n", pc));
continue;
}
LOG(("(pass)\n"));
op = OTHER;
}
break;
case 'c':
if (OPCODE("clr"))
{
get_value1(src, type1, size);
result = 0;
C = 0;
Z = 1;
N = 0;
V = 0;
#if VERBOSE
switch (size)
{
case 1: LOG(("%02x -> %02x ", value1, 0)); break;
case 2: LOG(("%04x -> %04x ", value1, 0)); break;
case 4: LOG(("%08x -> %08x ", value1, 0)); break;
}
#endif
op = SET1;
}
else if (OPCODE("cmp") || OPCODE("cmpi") || OPCODE("cmpm"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
op_sub(value1, value2, size);
op = TEST;
}
else if (OPCODE("cmpa"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
if (size == SIZE_W && type1 != An)
value1 = MAKE_INT_16(value1);
op_sub(value1, value2, SIZE_L);
op = TEST;
}
break;
case 'd':
if (OPCODE("dbra") || OPCODE("dbf"))
{
get_value1(src, type1, SIZE_W);
value1 -= 1;
value1 &= 0xffff;
set_d(n1, value1, SIZE_W);
if (value1 != 0xffff)
{
pc = (pc + 2) + MAKE_INT_8(get_imm(dst, SIZE_B));
LOG(("--D%d = %04x (branch to %06x)\n", src[0], value1, pc));
continue;
}
LOG(("--D%d = %04x (pass)\n", src[0], value1));
op = OTHER;
}
else if (OPCODE("dbcc") || OPCODE("dbcs") || OPCODE("dbeq") || OPCODE("dbge") ||
OPCODE("dbgt") || OPCODE("dbhi") || OPCODE("dble") || OPCODE("dbls") ||
OPCODE("dblt") || OPCODE("dbmi") || OPCODE("dbne") || OPCODE("dbpl") ||
OPCODE("dbvc") || OPCODE("dbvs") || OPCODE("dbt"))
{
switch (opcode[2])
{
case 'e': result = EQ; break;
case 'h': result = HI; break;
case 'm': result = MI; break;
case 'n': result = NE; break;
case 'p': result = PL; break;
case 't': result = 1; break;
case 'c': result = (opcode[3] == 'c') ? CC : CS; break;
case 'g': result = (opcode[3] == 'e') ? GE : GT; break;
case 'v': result = (opcode[3] == 'c') ? VC : VS; break;
case 'l':
switch (opcode[3])
{
case 'e': result = LE; break;
case 's': result = LS; break;
case 't': result = LT; break;
}
break;
}
if (!result)
{
get_value1(src, type1, SIZE_W);
value1 -= 1;
value1 &= 0xffff;
set_d(n1, value1, SIZE_W);
if (value1 != 0xffff)
{
pc = (pc + 2) + MAKE_INT_8(get_imm(dst, SIZE_B));
LOG(("--D%d = %04x (branch to %06x)\n", n1, value1, pc));
continue;
}
LOG(("--D%d = %04x (pass)\n", n1, value1));
}
#if VERBOSE
else
{
LOG(("D%d = %04x (pass)\n", n1, get_d(n1, SIZE_W)));
}
#endif
op = OTHER;
}
else if (OPCODE("divu"))
{
get_value1(src, type1, SIZE_W);
get_value2(dst, type2, size);
if (value1 != 0)
{
int modulo;
#if VERBOSE
switch (size)
{
case SIZE_W: LOG(("%04x / %04x ", value2, value1)); break;
case SIZE_L: LOG(("%08x / %04x ", value2, value1)); break;
}
#endif
switch (type2)
{
case Dn:
result = (value2 / value1) & 0xffff;
modulo = (value2 % value1) & 0xffff;
set_d(n2, (modulo << 16) | result, 4);
LOG(("(=%04x, modulo=%04x) -> D%d\n", result, modulo, n2));
break;
default:
result = (value2 / value1) & 0xffff;
modulo = (value2 % value1) & 0xffff;
write_ea(addr2, (modulo << 16) | result, 4);
LOG(("(=%04x, modulo=%04x) -> %06x\n", result, modulo, addr2));
break;
}
C = 0;
Z = ZFLAG(result, 2);
N = NFLAG(result, 2);
V = 0;
op = OTHER; // SET2
}
else
{
LOG(("(divide by zero)\n"));
op = INVALID;
}
}
else if (OPCODE("divs"))
{
get_value1(src, type1, SIZE_W);
get_value2(dst, type2, size);
value1 = MAKE_INT_16(value1);
if (value1 != 0)
{
int modulo;
#if VERBOSE
switch (size)
{
case SIZE_W: LOG(("%04x / %04x ", value2, value1 & 0xffff)); break;
case SIZE_L: LOG(("%08x / %04x ", value2, value1 & 0xffff)); break;
}
#endif
switch (type2)
{
case Dn:
result = (value2 / value1) & 0xffff;
modulo = (value2 % value1) & 0xffff;
set_d(n2, (modulo << 16) | result, 4);
LOG(("(=%04x, modulo=%04x) -> D%d\n", result, modulo, n2));
break;
default:
result = (value2 / value1) & 0xffff;
modulo = (value2 % value1) & 0xffff;
write_ea(addr2, (modulo << 16) | result, 4);
LOG(("(=%04x, modulo=%04x) -> %06x\n", result, modulo, addr2));
break;
}
C = 0;
Z = ZFLAG(result, 2);
N = NFLAG(result, 2);
V = 0;
op = OTHER; // SET2
}
else
{
LOG(("(divide by zero)\n"));
op = INVALID;
}
}
break;
case 'e':
if (OPCODE("eor") || OPCODE("eori"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
result = op_eor(value1, value2, size);
op = SET2;
}
else if (OPCODE("exg"))
{
switch (type2)
{
case An:
switch (type1)
{
case An:
value1 = a[n1];
a[n1] = a[n2];
a[n2] = value1;
LOG(("A%d <--> A%d\n", opcode, n1, n2));
break;
case Dn:
value1 = d[n1];
d[n1] = a[n2];
a[n2] = value1;
LOG(("D%d <--> A%d\n", n1, n2));
break;
}
break;
case Dn:
switch (type1)
{
case An:
value1 = a[n1];
a[n1] = d[n2];
d[n2] = value1;
LOG(("A%d <--> D%d\n", opcode, n1, n2));
break;
case Dn:
value1 = d[n1];
d[n1] = d[n2];
d[n2] = value1;
LOG(("D%d <--> D%d\n", n1, n2));
break;
}
break;
}
op = OTHER;
}
else if (OPCODE("ext"))
{
get_value1(src, type1, size);
switch (size)
{
case SIZE_B:
result = MAKE_INT_8(value1);
LOG(("%s\t%02x -> %04x ", opcode, value1, result & 0xffff));
break;
case SIZE_W:
result = MAKE_INT_16(value1);
LOG(("%s\t%04x -> %08x ", opcode, value1, result));
break;
}
size *= 2;
C = 0;
Z = ZFLAG(value1, size);
N = NFLAG(value1, size);
V = 0;
op = SET1;
}
break;
case 'j':
if (OPCODE("jmp"))
{
pc = get_ea(src, a, d, type1, size);
LOG(("06x\n", pc));
continue;
}
else if (OPCODE("jsr"))
{
nest_pc[nest_count++] = pc + opcode_len;
pc = get_ea(src, a, d, type1, size);
LOG(("%06x\n\n", pc));
continue;
}
break;
case 'l':
if (OPCODE("lea"))
{
get_value1(src, type1, SIZE_L);
result = addr1;
LOG(("%06x -> ", result));
op = SET2;
}
else if (OPCODE("lsl"))
{
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
}
else
{
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
value1 = 1;
get_value2(src, type1, size);
}
result = value2;
if (value1 == 0)
{
C = 0;
}
else
{
X = C = (result & (msb >> (value1 - 1))) != 0;
for (i = 0; i < value1; i++)
result = (result << 1) & mask;
}
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x << %d (=%02x) -> ", value2, value1, result)); break;
case SIZE_W: LOG(("%04x << %d (=%04x) -> ", value2, value1, result)); break;
case SIZE_L: LOG(("%08x << %d (=%08x) -> ", value2, value1, result)); break;
}
#endif
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET2;
}
else if (OPCODE("lsr"))
{
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
}
else
{
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
value1 = 1;
get_value2(src, type1, size);
}
result = value2;
if (value1 == 0)
{
C = 0;
}
else
{
X = C = (result & (1 << (value1 - 1))) != 0;
for (i = 0; i < value1; i++)
result = (result >> 1) & mask;
}
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x >> %d (=%02x) -> ", value2, value1, result)); break;
case SIZE_W: LOG(("%04x >> %d (=%04x) -> ", value2, value1, result)); break;
case SIZE_L: LOG(("%08x >> %d (=%08x) -> ", value2, value1, result)); break;
}
#endif
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET2;
}
break;
case 'm':
if (OPCODE("move"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
switch (type2)
{
case An:
LOG(("(Illigal)\n"));
break;
case Dn:
set_d(n2, value1, size);
#if VERBOSE
result = get_d(n2, SIZE_L);
switch (size)
{
case SIZE_B: LOG(("%02x -> D%d (=%08x)\n", value1, n2, result)); break;
case SIZE_W: LOG(("%04x -> D%d (=%08x)\n", value1, n2, result)); break;
case SIZE_L: LOG(("%08x -> D%d (=%08x)\n", value1, n2, result)); break;
}
#endif
break;
case CCR:
C = value1 & (1 << 0);
V = value1 & (1 << 1);
Z = value1 & (1 << 2);
N = value1 & (1 << 3);
X = value1 & (1 << 4);
LOG(("%04x -> CCR (XZNVC = %d%d%d%d%d)\n", value1, X, Z, N, V, C));
break;
case SR:
sr = value1;
C = sr & (1 << 0);
V = sr & (1 << 1);
Z = sr & (1 << 2);
N = sr & (1 << 3);
X = sr & (1 << 4);
LOG(("%04x -> SR (=%04x)\n", value1));
break;
default:
write_ea(addr2, value1, size);
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x -> %06x\n", value1, addr2)); break;
case SIZE_W: LOG(("%04x -> %06x\n", value1, addr2)); break;
case SIZE_L: LOG(("%08x -> %06x\n", value1, addr2)); break;
}
break;
#endif
}
C = 0;
Z = ZFLAG(value1, size);
N = NFLAG(value1, size);
V = 0;
op = OTHER; // SET2
}
else if (OPCODE("movea"))
{
get_value1(src, type1, size);
get_value2(dst, type2, SIZE_L);
if (size == SIZE_W)
value1 = MAKE_INT_16(value1);
result = value1;
LOG(("%08x -> ", result));
op = SET2;
}
else if (OPCODE("movem"))
{
int i, n;
char *p;
p = (type1 == MM) ? src : dst;
i = 0;
if (type1 == MM)
{
if (type2 == PD7)
{
LOG(("%s -> -(A7)\n", src));
if (p[0] == 'A')
{
i = 1;
while (p[i])
{
if (p[i] == '/')
{
i++;
break;
}
n = p[i] - '0';
a[7] -= SIZE_L;
write_ea(a[7], a[n], SIZE_L);
i++;
}
}
if (p[i] == 'D')
{
i++;
while (p[i])
{
n = p[i] - '0';
a[7] -= SIZE_L;
write_ea(a[7], d[n], SIZE_L);
i++;
}
}
}
else
{
addr2 = get_ea(dst, a, d, type2, size);
LOG(("%s -> %06x\n", src, addr2));
if (p[0] == 'D')
{
i = 1;
while (p[i])
{
if (p[i] == '/')
{
i++;
break;
}
n = p[i] - '0';
write_ea(addr2, d[n], size);
addr2 += size;
i++;
}
}
if (p[i] == 'A')
{
i++;
while (p[i])
{
n = p[i] - '0';
write_ea(addr2, a[n], size);
addr2 += size;
i++;
}
}
}
}
else
{
if (type2 == PI7)
{
LOG(("(A7)+ -> %s\n", dst));
if (p[0] == 'D')
{
i = 1;
while (p[i])
{
if (p[i] == '/')
{
i++;
break;
}
n = p[i] - '0';
d[n] = read_ea(a[7], SIZE_L);
a[7] += SIZE_L;
i++;
}
}
if (p[i] == 'A')
{
i++;
while (p[i])
{
n = p[i] - '0';
a[n] = read_ea(a[7], SIZE_L);
a[7] += SIZE_L;
i++;
}
}
}
else
{
addr1 = get_ea(src, a, d, type1, size);
LOG(("%06x -> %s\n", addr1, dst));
if (p[0] == 'D')
{
i++;
while (p[i])
{
if (p[i] == '/')
{
i++;
break;
}
n = p[i] - '0';
value1 = read_ea(addr1, size);
d[n] = (d[n] & ~mask) | value1;
addr1 += size;
i++;
}
}
if (p[i] == 'A')
{
i++;
while (p[i])
{
n = p[i] - '0';
value1 = read_ea(addr1, size);
a[n] = (a[n] & ~mask) | value1;
addr1 += size;
i++;
}
}
}
}
op = OTHER;
}
else if (OPCODE("moveq"))
{
get_value1(src, type1, size);
result = MAKE_INT_8(value1);
set_d(n2, result, SIZE_L);
C = 0;
Z = ZFLAG(result, SIZE_L);
N = NFLAG(result, SIZE_L);
V = 0;
LOG(("%02x -> D%d (=%08x)\n", value1, n2, result));
op = OTHER; // SET2
}
else if (OPCODE("mulu"))
{
get_value1(src, type1, SIZE_W);
get_value2(dst, type2, SIZE_W);
result = value1 * value2;
LOG(("%04x * %04x (=%08x) ->", value1, value2, result));
size *= 2;
C = 0;
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET2;
}
else if (OPCODE("muls"))
{
get_value1(src, type1, SIZE_W);
get_value2(dst, type2, SIZE_W);
value1 = MAKE_INT_16(value1);
value2 = MAKE_INT_16(value2);
result = value1 * value2;
LOG(("%04x * %04x (=%08x) ->", value1 & 0xffff, value2 & 0xffff, result));
size *= 2;
C = 0;
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET2;
}
break;
case 'n':
if (OPCODE("nop"))
{
LOG(("\n"));
op = OTHER;
}
else if (OPCODE("neg"))
{
get_value1(src, type1, size);
result = op_sub(value1, 0, size);
op = SET1;
}
else if (OPCODE("negx"))
{
get_value1(src, type1, size);
result = op_sub(value1 - X, 0, size);
op = SET1;
}
else if (OPCODE("not"))
{
get_value1(src, type1, size);
result = (~value1) & mask;
#if VERBOSE
switch (size)
{
case 1: LOG(("~%02x (=%02x) -> ", value1, result)); break;
case 2: LOG(("~%04x (=%02x) -> ", value1, result)); break;
case 4: LOG(("~%08x (=%02x) -> ", value1, result)); break;
}
#endif
C = 0;
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET1;
}
break;
case 'o':
if (OPCODE("or") || OPCODE("ori"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
result = op_or(value1, value2, size);
op = SET2;
}
break;
case 'r':
if (OPCODE("rts"))
{
if (nest_count == 0)
{
pc = break_point;
LOG(("(break)\n"));
continue;
}
else
{
pc = nest_pc[--nest_count];
LOG(("(return to %06x)\n\n", pc));
continue;
}
}
else if (OPCODE("rol"))
{
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
}
else
{
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
value1 = 1;
get_value2(src, type1, size);
}
result = value2;
if (value1 == 0)
{
C = 0;
}
else
{
for (i = 0; i < value1; i++)
{
C = (result & 1) != 0;
result = ((result << 1) & mask) | C;
}
}
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x << %d (=%02x) -> ", value2, value1, result)); break;
case SIZE_W: LOG(("%04x << %d (=%04x) -> ", value2, value1, result)); break;
case SIZE_L: LOG(("%08x << %d (=%08x) -> ", value2, value1, result)); break;
}
#endif
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET2;
}
else if (OPCODE("ror"))
{
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
}
else
{
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
value1 = 1;
get_value2(src, type1, size);
}
result = value2;
if (value1 == 0)
{
C = 0;
}
else
{
for (i = 0; i < value1; i++)
{
C = (result & 1) != 0;
result = ((result >> 1) & mask) | (C * msb);
}
}
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x >> %d (=%02x) -> ", value2, value1, result)); break;
case SIZE_W: LOG(("%04x >> %d (=%04x) -> ", value2, value1, result)); break;
case SIZE_L: LOG(("%08x >> %d (=%08x) -> ", value2, value1, result)); break;
}
#endif
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET2;
}
else if (OPCODE("roxl"))
{
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
}
else
{
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
value1 = 1;
get_value2(src, type1, size);
}
result = value2;
if (value1 == 0)
{
C = 0;
}
else
{
for (i = 0; i < value1; i++)
{
C = (result & 1) != 0;
result = ((result << 1) & mask) | X;
X = C;
}
}
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x << %d (=%02x) -> ", value2, value1, result)); break;
case SIZE_W: LOG(("%04x << %d (=%04x) -> ", value2, value1, result)); break;
case SIZE_L: LOG(("%08x << %d (=%08x) -> ", value2, value1, result)); break;
}
#endif
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET2;
}
else if (OPCODE("roxr"))
{
if (type2 == Dn)
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
}
else
{
size = SIZE_W;
mask = 0x0000ffff;
msb = 0x00008000;
value1 = 1;
get_value2(src, type1, size);
}
result = value2;
if (value1 == 0)
{
X = C = 0;
}
else
{
for (i = 0; i < value1; i++)
{
C = (result & 1) != 0;
result = ((result >> 1) & mask) | (X * msb);
X = C;
}
}
#if VERBOSE
switch (size)
{
case SIZE_B: LOG(("%02x >> %d (=%02x) -> ", value2, value1, result)); break;
case SIZE_W: LOG(("%04x >> %d (=%04x) -> ", value2, value1, result)); break;
case SIZE_L: LOG(("%08x >> %d (=%08x) -> ", value2, value1, result)); break;
}
#endif
Z = ZFLAG(result, size);
N = NFLAG(result, size);
V = 0;
op = SET2;
}
break;
case 's':
if (OPCODE("sub") || OPCODE("subi"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
result = op_sub(value1, value2, size);
X = C;
op = SET2;
}
else if (OPCODE("suba"))
{
get_value1(src, type1, size);
get_value2(dst, type2, SIZE_L);
if (size == SIZE_W)
value1 = MAKE_INT_16(value1);
result = value2 - value1;
LOG(("%06x - %06x (=%06x) -> ", value2, value1, result));
op = SET2;
}
else if (OPCODE("subq"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
if (type2 == An)
{
if (size == SIZE_W)
value1 = MAKE_INT_16(value1);
result = value2 - value1;
LOG(("%06x - %08x (=%06x) -> ", value2, value1, result));
}
else
{
result = op_sub(value1, value2, size);
X = C;
}
op = SET2;
}
else if (OPCODE("subx"))
{
get_value1(src, type1, size);
get_value2(dst, type2, size);
result = op_sub(value1 - X, value2, size);
X = C;
op = SET2;
}
else if (OPCODE("swap"))
{
get_value1(src, type1, SIZE_L);
value2 = (value1 & 0xffff0000) >> 16;
result = (value1 & 0x0000ffff) << 16;
result |= value2;
LOG(("D%d %08x -> D%d %08x\n", n1, value1, n1, result));
set_d(n1, result, SIZE_L);
op = OTHER;
}
else if (OPCODE("scc") || OPCODE("scs") || OPCODE("seq") || OPCODE("sge") ||
OPCODE("sgt") || OPCODE("shi") || OPCODE("sle") || OPCODE("sls") ||
OPCODE("slt") || OPCODE("smi") || OPCODE("sne") || OPCODE("spl") ||
OPCODE("svc") || OPCODE("svs") || OPCODE("st") || OPCODE("sf"))
{
size = SIZE_B;
get_value1(src, type1, size);
switch (opcode[1])
{
case 'e': result = EQ; break;
case 'h': result = HI; break;
case 'm': result = MI; break;
case 'n': result = NE; break;
case 'p': result = PL; break;
case 't': result = 1; break;
case 'f': result = 0; break;
case 'c': result = (opcode[2] == 'c') ? CC : CS; break;
case 'g': result = (opcode[2] == 'e') ? GE : GT; break;
case 'v': result = (opcode[2] == 'c') ? VC : VS; break;
case 'l':
switch (opcode[2])
{
case 'e': result = LE; break;
case 's': result = LS; break;
case 't': result = LT; break;
}
break;
}
result = (result != 0) ? 0xff : 0;
LOG(("%02x -> ", result));
op = SET1;
}
break;
case 't':
if (OPCODE("tst"))
{
get_value1(src, type1, size);
op_and(mask, value1, size);
op = TEST;
}
break;
}
// 結果
switch (op)
{
case NOTFOUND:
LOG(("not inplemented.\n"));
break;
case SET1:
switch (type1)
{
case An:
set_a(n1, result);
LOG(("A%d\n", n1));
break;
case Dn:
set_d(n1, result, size);
LOG(("D%d\n", n1));
break;
default:
write_ea(addr1, result, size);
LOG(("$%06x\n", addr1));
break;
}
break;
case SET2:
switch (type2)
{
case An:
set_a(n2, result);
LOG(("A%d\n", n2));
break;
case CCR:
C = value1 & (1 << 0);
V = value1 & (1 << 1);
Z = value1 & (1 << 2);
N = value1 & (1 << 3);
X = value1 & (1 << 4);
LOG(("CCR\n"));
break;
case Dn:
set_d(n2, result, size);
LOG(("D%d\n", n2));
break;
default:
write_ea(addr2, result, size);
LOG(("$%06x\n", addr2));
break;
}
break;
case TEST:
LOG(("CCR (XVNZC = %d%d%d%d%d)\n", X, V, N, Z, C));
break;
default:
break;
}
pc += opcode_len;
}
LOG(("-- end --\n\n"));
}