599 lines
21 KiB
C#
599 lines
21 KiB
C#
using System;
|
|
using System.Text;
|
|
|
|
namespace BizHawk.Emulation.CPUs.M68000
|
|
{
|
|
partial class MC68000
|
|
{
|
|
void MOVE()
|
|
{
|
|
int size = ((op >> 12) & 0x03);
|
|
int dstMode = ((op >> 6) & 0x07);
|
|
int dstReg = ((op >> 9) & 0x07);
|
|
int srcMode = ((op >> 3) & 0x07);
|
|
int srcReg = (op & 0x07);
|
|
|
|
int value = 0;
|
|
switch (size)
|
|
{
|
|
case 1: // Byte
|
|
value = ReadValueB(srcMode, srcReg);
|
|
WriteValueB(dstMode, dstReg, (sbyte) value);
|
|
PendingCycles -= MoveCyclesBW[srcMode + (srcMode == 7 ? srcReg : 0), dstMode + (dstMode == 7 ? dstReg : 0)];
|
|
N = (value & 0x80) != 0;
|
|
break;
|
|
case 3: // Word
|
|
value = ReadValueW(srcMode, srcReg);
|
|
WriteValueW(dstMode, dstReg, (short)value);
|
|
PendingCycles -= MoveCyclesBW[srcMode + (srcMode == 7 ? srcReg : 0), dstMode + (dstMode == 7 ? dstReg : 0)];
|
|
N = (value & 0x8000) != 0;
|
|
break;
|
|
case 2: // Long
|
|
value = ReadValueL(srcMode, srcReg);
|
|
WriteValueL(dstMode, dstReg, value);
|
|
PendingCycles -= MoveCyclesL[srcMode + (srcMode == 7 ? srcReg : 0), dstMode + (dstMode == 7 ? dstReg : 0)];
|
|
N = (value & 0x80000000) != 0;
|
|
break;
|
|
}
|
|
|
|
V = false;
|
|
C = false;
|
|
Z = (value == 0);
|
|
}
|
|
|
|
void MOVE_Disasm(DisassemblyInfo info)
|
|
{
|
|
int size = ((op >> 12) & 0x03);
|
|
int dstMode = ((op >> 6) & 0x07);
|
|
int dstReg = ((op >> 9) & 0x07);
|
|
int srcMode = ((op >> 3) & 0x07);
|
|
int srcReg = (op & 0x07);
|
|
|
|
int pc = info.PC + 2;
|
|
|
|
switch (size)
|
|
{
|
|
case 1:
|
|
info.Mnemonic = "move.b";
|
|
info.Args = DisassembleValue(srcMode, srcReg, 1, ref pc) +", ";
|
|
info.Args += DisassembleValue(dstMode, dstReg, 1, ref pc);
|
|
break;
|
|
case 3:
|
|
info.Mnemonic = "move.w";
|
|
info.Args = DisassembleValue(srcMode, srcReg, 2, ref pc) + ", ";
|
|
info.Args += DisassembleValue(dstMode, dstReg, 2, ref pc);
|
|
break;
|
|
case 2:
|
|
info.Mnemonic = "move.l";
|
|
info.Args = DisassembleValue(srcMode, srcReg, 4, ref pc) + ", ";
|
|
info.Args += DisassembleValue(dstMode, dstReg, 4, ref pc);
|
|
break;
|
|
}
|
|
|
|
info.Length = pc - info.PC;
|
|
}
|
|
|
|
void MOVEA()
|
|
{
|
|
int size = ((op >> 12) & 0x03);
|
|
int dstReg = ((op >> 9) & 0x07);
|
|
int srcMode = ((op >> 3) & 0x07);
|
|
int srcReg = (op & 0x07);
|
|
|
|
if (size == 3) // Word
|
|
{
|
|
A[dstReg].s32 = ReadValueW(srcMode, srcReg);
|
|
switch (srcMode)
|
|
{
|
|
case 0: PendingCycles -= 4; break;
|
|
case 1: PendingCycles -= 4; break;
|
|
case 2: PendingCycles -= 8; break;
|
|
case 3: PendingCycles -= 8; break;
|
|
case 4: PendingCycles -= 10; break;
|
|
case 5: PendingCycles -= 12; break;
|
|
case 6: PendingCycles -= 14; break;
|
|
case 7:
|
|
switch (srcReg)
|
|
{
|
|
case 0: PendingCycles -= 12; break;
|
|
case 1: PendingCycles -= 16; break;
|
|
case 2: PendingCycles -= 12; break;
|
|
case 3: PendingCycles -= 14; break;
|
|
case 4: PendingCycles -= 8; break;
|
|
default: throw new InvalidOperationException();
|
|
}
|
|
break;
|
|
}
|
|
} else { // Long
|
|
A[dstReg].s32 = ReadValueL(srcMode, srcReg);
|
|
switch (srcMode)
|
|
{
|
|
case 0: PendingCycles -= 4; break;
|
|
case 1: PendingCycles -= 4; break;
|
|
case 2: PendingCycles -= 12; break;
|
|
case 3: PendingCycles -= 12; break;
|
|
case 4: PendingCycles -= 14; break;
|
|
case 5: PendingCycles -= 16; break;
|
|
case 6: PendingCycles -= 18; break;
|
|
case 7:
|
|
switch (srcReg)
|
|
{
|
|
case 0: PendingCycles -= 16; break;
|
|
case 1: PendingCycles -= 20; break;
|
|
case 2: PendingCycles -= 16; break;
|
|
case 3: PendingCycles -= 18; break;
|
|
case 4: PendingCycles -= 12; break;
|
|
default: throw new InvalidOperationException();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MOVEA_Disasm(DisassemblyInfo info)
|
|
{
|
|
int size = ((op >> 12) & 0x03);
|
|
int dstReg = ((op >> 9) & 0x07);
|
|
int srcMode = ((op >> 3) & 0x07);
|
|
int srcReg = (op & 0x07);
|
|
int pc = info.PC + 2;
|
|
|
|
if (size == 3)
|
|
{
|
|
info.Mnemonic = "movea.w";
|
|
info.Args = DisassembleValue(srcMode, srcReg, 2, ref pc) + ", A" + dstReg;
|
|
} else {
|
|
info.Mnemonic = "movea.l";
|
|
info.Args = DisassembleValue(srcMode, srcReg, 4, ref pc) + ", A" + dstReg;
|
|
}
|
|
info.Length = pc - info.PC;
|
|
}
|
|
|
|
void MOVEQ()
|
|
{
|
|
int value = (sbyte) op; // 8-bit data payload is sign-extended to 32-bits.
|
|
N = (value & 0x80) != 0;
|
|
Z = (value == 0);
|
|
V = false;
|
|
C = false;
|
|
D[(op >> 9) & 7].s32 = value;
|
|
PendingCycles -= 4;
|
|
}
|
|
|
|
void MOVEQ_Disasm(DisassemblyInfo info)
|
|
{
|
|
info.Mnemonic = "moveq";
|
|
info.Args = String.Format("{0}, D{1}", (sbyte) op, (op >> 9) & 7);
|
|
}
|
|
|
|
void MOVEM0()
|
|
{
|
|
// Move register to memory
|
|
int size = (op >> 6) & 1;
|
|
int dstMode = (op >> 3) & 7;
|
|
int dstReg = (op >> 0) & 7;
|
|
|
|
ushort registers = (ushort) ReadWord(PC); PC += 2;
|
|
int address = ReadAddress(dstMode, dstReg);
|
|
int regCount = 0;
|
|
|
|
if (size == 0)
|
|
{
|
|
// word-assign
|
|
if (dstMode == 4) // decrement address
|
|
{
|
|
for (int i = 7; i >= 0; i--)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
address -= 2;
|
|
WriteWord(address, A[i].s16);
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
for (int i = 7; i >= 0; i--)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
address -= 2;
|
|
WriteWord(address, D[i].s16);
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
A[dstReg].s32 = address;
|
|
}
|
|
else
|
|
{ // increment address
|
|
for (int i = 7; i >= 0; i--)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
WriteWord(address, A[i].s16);
|
|
address += 2;
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
for (int i = 7; i >= 0; i--)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
WriteWord(address, D[i].s16);
|
|
address += 2;
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
}
|
|
PendingCycles -= regCount*4;
|
|
} else {
|
|
// long-assign
|
|
if (dstMode == 4) // decrement address
|
|
{
|
|
for (int i=7; i>= 0; i--)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
address -= 4;
|
|
WriteLong(address, A[i].s32);
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
for (int i = 7; i >= 0; i--)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
address -= 4;
|
|
WriteLong(address, D[i].s32);
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
A[dstReg].s32 = address;
|
|
} else { // increment address
|
|
for (int i = 7; i >= 0; i--)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
WriteLong(address, A[i].s32);
|
|
address += 4;
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
for (int i = 7; i >= 0; i--)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
WriteLong(address, D[i].s32);
|
|
address += 4;
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
}
|
|
PendingCycles -= regCount * 8;
|
|
}
|
|
|
|
switch (dstMode)
|
|
{
|
|
case 2: PendingCycles -= 8; break;
|
|
case 3: PendingCycles -= 8; break;
|
|
case 4: PendingCycles -= 8; break;
|
|
case 5: PendingCycles -= 12; break;
|
|
case 6: PendingCycles -= 14; break;
|
|
case 7:
|
|
switch (dstReg)
|
|
{
|
|
case 0: PendingCycles -= 12; break;
|
|
case 1: PendingCycles -= 16; break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MOVEM1()
|
|
{
|
|
// Move memory to register
|
|
int size = (op >> 6) & 1;
|
|
int srcMode = (op >> 3) & 7;
|
|
int srcReg = (op >> 0) & 7;
|
|
|
|
ushort registers = (ushort)ReadWord(PC); PC += 2;
|
|
int address = ReadAddress(srcMode, srcReg);
|
|
int regCount = 0;
|
|
|
|
if (size == 0)
|
|
{
|
|
// word-assign
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
D[i].s32 = ReadWord(address);
|
|
address += 2;
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
A[i].s32 = ReadWord(address);
|
|
address += 2;
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
PendingCycles -= regCount * 4;
|
|
if (srcMode == 3)
|
|
A[srcReg].s32 = address;
|
|
} else {
|
|
// long-assign
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
D[i].s32 = ReadLong(address);
|
|
address += 4;
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if ((registers & 1) == 1)
|
|
{
|
|
A[i].s32 = ReadLong(address);
|
|
address += 4;
|
|
regCount++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
PendingCycles -= regCount * 8;
|
|
if (srcMode == 3)
|
|
A[srcReg].s32 = address;
|
|
}
|
|
|
|
switch (srcMode)
|
|
{
|
|
case 2: PendingCycles -= 12; break;
|
|
case 3: PendingCycles -= 12; break;
|
|
case 4: PendingCycles -= 12; break;
|
|
case 5: PendingCycles -= 16; break;
|
|
case 6: PendingCycles -= 18; break;
|
|
case 7:
|
|
switch (srcReg)
|
|
{
|
|
case 0: PendingCycles -= 16; break;
|
|
case 1: PendingCycles -= 20; break;
|
|
case 2: PendingCycles -= 16; break;
|
|
case 3: PendingCycles -= 18; break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static string DisassembleRegisterList0(ushort registers)
|
|
{
|
|
var str = new StringBuilder();
|
|
int count = 0;
|
|
for (int i = 0; i<8; i++)
|
|
{
|
|
if ((registers & 0x8000) != 0)
|
|
{
|
|
if (count > 0) str.Append(",");
|
|
str.Append("D"+i);
|
|
count++;
|
|
}
|
|
registers <<= 1;
|
|
}
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if ((registers & 0x8000) != 0)
|
|
{
|
|
if (count > 0) str.Append(",");
|
|
str.Append("A"+i);
|
|
count++;
|
|
}
|
|
registers <<= 1;
|
|
}
|
|
return str.ToString();
|
|
}
|
|
|
|
static string DisassembleRegisterList1(ushort registers)
|
|
{
|
|
var str = new StringBuilder();
|
|
int count = 0;
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if ((registers & 1) != 0)
|
|
{
|
|
if (count > 0) str.Append(",");
|
|
str.Append("D" + i);
|
|
count++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if ((registers & 1) != 0)
|
|
{
|
|
if (count > 0) str.Append(",");
|
|
str.Append("A" + i);
|
|
count++;
|
|
}
|
|
registers >>= 1;
|
|
}
|
|
return str.ToString();
|
|
}
|
|
|
|
void MOVEM0_Disasm(DisassemblyInfo info)
|
|
{
|
|
int size = (op >> 6) & 1;
|
|
int mode = (op >> 3) & 7;
|
|
int reg = (op >> 0) & 7;
|
|
int pc = info.PC + 2;
|
|
|
|
ushort registers = (ushort)ReadWord(pc); pc += 2;
|
|
string address = DisassembleAddress(mode, reg, ref pc);
|
|
|
|
info.Mnemonic = size == 0 ? "movem.w" : "movem.l";
|
|
info.Args = DisassembleRegisterList0(registers) + ", " + address;
|
|
info.Length = pc - info.PC;
|
|
}
|
|
|
|
void MOVEM1_Disasm(DisassemblyInfo info)
|
|
{
|
|
int size = (op >> 6) & 1;
|
|
int mode = (op >> 3) & 7;
|
|
int reg = (op >> 0) & 7;
|
|
int pc = info.PC + 2;
|
|
|
|
ushort registers = (ushort)ReadWord(pc); pc += 2;
|
|
string address = DisassembleAddress(mode, reg, ref pc);
|
|
|
|
info.Mnemonic = size == 0 ? "movem.w" : "movem.l";
|
|
info.Args = address + ", " + DisassembleRegisterList1(registers);
|
|
info.Length = pc - info.PC;
|
|
}
|
|
|
|
void LEA()
|
|
{
|
|
int mode = (op >> 3) & 7;
|
|
int sReg = (op >> 0) & 7;
|
|
int dReg = (op >> 9) & 7;
|
|
|
|
A[dReg].u32 = (uint)ReadAddress(mode, sReg);
|
|
switch (mode)
|
|
{
|
|
case 2: PendingCycles -= 4; break;
|
|
case 5: PendingCycles -= 8; break;
|
|
case 6: PendingCycles -= 12; break;
|
|
case 7:
|
|
switch (sReg)
|
|
{
|
|
case 0: PendingCycles -= 8; break;
|
|
case 1: PendingCycles -= 12; break;
|
|
case 2: PendingCycles -= 8; break;
|
|
case 3: PendingCycles -= 12; break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void LEA_Disasm(DisassemblyInfo info)
|
|
{
|
|
int pc = info.PC + 2;
|
|
|
|
int mode = (op >> 3) & 7;
|
|
int sReg = (op >> 0) & 7;
|
|
int dReg = (op >> 9) & 7;
|
|
|
|
info.Mnemonic = "lea";
|
|
info.Args = DisassembleAddress(mode, sReg, ref pc);
|
|
info.Args += ", A"+dReg;
|
|
|
|
info.Length = pc - info.PC;
|
|
}
|
|
|
|
void CLR()
|
|
{
|
|
int size = (op >> 6) & 3;
|
|
int mode = (op >> 3) & 7;
|
|
int reg = (op >> 0) & 7;
|
|
|
|
switch (size)
|
|
{
|
|
case 0: WriteValueB(mode, reg, 0); PendingCycles -= mode == 0 ? 4 : 8 + EACyclesBW[mode, reg]; break;
|
|
case 1: WriteValueW(mode, reg, 0); PendingCycles -= mode == 0 ? 4 : 8 + EACyclesBW[mode, reg]; break;
|
|
case 2: WriteValueL(mode, reg, 0); PendingCycles -= mode == 0 ? 6 : 12 + EACyclesL[mode, reg]; break;
|
|
}
|
|
|
|
N = V = C = false;
|
|
Z = true;
|
|
}
|
|
|
|
void CLR_Disasm(DisassemblyInfo info)
|
|
{
|
|
int pc = info.PC + 2;
|
|
int size = (op >> 6) & 3;
|
|
int mode = (op >> 3) & 7;
|
|
int reg = (op >> 0) & 7;
|
|
|
|
switch (size)
|
|
{
|
|
case 0: info.Mnemonic = "clr.b"; info.Args = DisassembleValue(mode, reg, 1, ref pc); break;
|
|
case 1: info.Mnemonic = "clr.w"; info.Args = DisassembleValue(mode, reg, 2, ref pc); break;
|
|
case 2: info.Mnemonic = "clr.l"; info.Args = DisassembleValue(mode, reg, 4, ref pc); break;
|
|
}
|
|
info.Length = pc - info.PC;
|
|
}
|
|
|
|
void EXT()
|
|
{
|
|
int size = (op >> 6) & 1;
|
|
int reg = op & 7;
|
|
switch (size)
|
|
{
|
|
case 0: D[reg].s16 = D[reg].s8; break;
|
|
case 1: D[reg].s32 = D[reg].s16; break;
|
|
}
|
|
PendingCycles -= 4;
|
|
}
|
|
|
|
void EXT_Disasm(DisassemblyInfo info)
|
|
{
|
|
int pc = info.PC;
|
|
int size = (op >> 6) & 1;
|
|
int reg = op & 7;
|
|
switch (size)
|
|
{
|
|
case 0: info.Mnemonic = "ext.w"; info.Args = "D" + reg; break;
|
|
case 1: info.Mnemonic = "ext.l"; info.Args = "D" + reg; break;
|
|
}
|
|
|
|
}
|
|
|
|
void PEA()
|
|
{
|
|
int mode = (op >> 3) & 7;
|
|
int reg = (op >> 0) & 7;
|
|
int ea = ReadAddress(mode, reg);
|
|
A[7].s32 -= 4;
|
|
WriteLong(A[7].s32, ea);
|
|
|
|
switch (mode)
|
|
{
|
|
case 2: PendingCycles -= 12; break;
|
|
case 5: PendingCycles -= 16; break;
|
|
case 6: PendingCycles -= 20; break;
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: PendingCycles -= 16; break;
|
|
case 1: PendingCycles -= 20; break;
|
|
case 2: PendingCycles -= 16; break;
|
|
case 3: PendingCycles -= 20; break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void PEA_Disasm(DisassemblyInfo info)
|
|
{
|
|
int pc = info.PC + 2;
|
|
int mode = (op >> 3) & 7;
|
|
int reg = (op >> 0) & 7;
|
|
|
|
info.Mnemonic = "pea";
|
|
info.Args = DisassembleAddress(mode, reg, ref pc);
|
|
info.Length = pc - info.PC;
|
|
}
|
|
}
|
|
}
|