626 lines
17 KiB
C#
626 lines
17 KiB
C#
using System;
|
|
|
|
namespace BizHawk.Emulation.Cores.Components.M68000
|
|
{
|
|
partial class MC68000
|
|
{
|
|
sbyte ReadValueB(int mode, int reg)
|
|
{
|
|
sbyte value;
|
|
switch (mode)
|
|
{
|
|
case 0: // Dn
|
|
return D[reg].s8;
|
|
case 1: // An
|
|
return A[reg].s8;
|
|
case 2: // (An)
|
|
return ReadByte(A[reg].s32);
|
|
case 3: // (An)+
|
|
value = ReadByte(A[reg].s32);
|
|
A[reg].s32 += reg == 7 ? 2 : 1;
|
|
return value;
|
|
case 4: // -(An)
|
|
A[reg].s32 -= reg == 7 ? 2 : 1;
|
|
return ReadByte(A[reg].s32);
|
|
case 5: // (d16,An)
|
|
value = ReadByte((A[reg].s32 + ReadWord(PC))); PC += 2;
|
|
return value;
|
|
case 6: // (d8,An,Xn)
|
|
return ReadByte(A[reg].s32 + GetIndex());
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: // (imm).W
|
|
value = ReadByte(ReadWord(PC)); PC += 2;
|
|
return value;
|
|
case 1: // (imm).L
|
|
value = ReadByte(ReadLong(PC)); PC += 4;
|
|
return value;
|
|
case 2: // (d16,PC)
|
|
value = ReadByte(PC + ReadWord(PC)); PC += 2;
|
|
return value;
|
|
case 3: // (d8,PC,Xn)
|
|
int pc = PC;
|
|
value = ReadByte((pc + GetIndex()));
|
|
return value;
|
|
case 4: // immediate
|
|
value = (sbyte)ReadWord(PC); PC += 2;
|
|
return value;
|
|
default:
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
short ReadValueW(int mode, int reg)
|
|
{
|
|
short value;
|
|
switch (mode)
|
|
{
|
|
case 0: // Dn
|
|
return D[reg].s16;
|
|
case 1: // An
|
|
return A[reg].s16;
|
|
case 2: // (An)
|
|
return ReadWord(A[reg].s32);
|
|
case 3: // (An)+
|
|
value = ReadWord(A[reg].s32);
|
|
A[reg].s32 += 2;
|
|
return value;
|
|
case 4: // -(An)
|
|
A[reg].s32 -= 2;
|
|
return ReadWord(A[reg].s32);
|
|
case 5: // (d16,An)
|
|
value = ReadWord((A[reg].s32 + ReadWord(PC))); PC += 2;
|
|
return value;
|
|
case 6: // (d8,An,Xn)
|
|
return ReadWord(A[reg].s32 + GetIndex());
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: // (imm).W
|
|
value = ReadWord(ReadWord(PC)); PC += 2;
|
|
return value;
|
|
case 1: // (imm).L
|
|
value = ReadWord(ReadLong(PC)); PC += 4;
|
|
return value;
|
|
case 2: // (d16,PC)
|
|
value = ReadWord(PC + ReadWord(PC)); PC += 2;
|
|
return value;
|
|
case 3: // (d8,PC,Xn)
|
|
int pc = PC;
|
|
value = ReadWord((pc + GetIndex()));
|
|
return value;
|
|
case 4: // immediate
|
|
value = ReadWord(PC); PC += 2;
|
|
return value;
|
|
default:
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
int ReadValueL(int mode, int reg)
|
|
{
|
|
int value;
|
|
switch (mode)
|
|
{
|
|
case 0: // Dn
|
|
return D[reg].s32;
|
|
case 1: // An
|
|
return A[reg].s32;
|
|
case 2: // (An)
|
|
return ReadLong(A[reg].s32);
|
|
case 3: // (An)+
|
|
value = ReadLong(A[reg].s32);
|
|
A[reg].s32 += 4;
|
|
return value;
|
|
case 4: // -(An)
|
|
A[reg].s32 -= 4;
|
|
return ReadLong(A[reg].s32);
|
|
case 5: // (d16,An)
|
|
value = ReadLong((A[reg].s32 + ReadWord(PC))); PC += 2;
|
|
return value;
|
|
case 6: // (d8,An,Xn)
|
|
return ReadLong(A[reg].s32 + GetIndex());
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: // (imm).W
|
|
value = ReadLong(ReadWord(PC)); PC += 2;
|
|
return value;
|
|
case 1: // (imm).L
|
|
value = ReadLong(ReadLong(PC)); PC += 4;
|
|
return value;
|
|
case 2: // (d16,PC)
|
|
value = ReadLong(PC + ReadWord(PC)); PC += 2;
|
|
return value;
|
|
case 3: // (d8,PC,Xn)
|
|
int pc = PC;
|
|
value = ReadLong((pc + GetIndex()));
|
|
return value;
|
|
case 4: // immediate
|
|
value = ReadLong(PC); PC += 4;
|
|
return value;
|
|
default:
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
sbyte PeekValueB(int mode, int reg)
|
|
{
|
|
sbyte value;
|
|
switch (mode)
|
|
{
|
|
case 0: // Dn
|
|
return D[reg].s8;
|
|
case 1: // An
|
|
return A[reg].s8;
|
|
case 2: // (An)
|
|
return ReadByte(A[reg].s32);
|
|
case 3: // (An)+
|
|
value = ReadByte(A[reg].s32);
|
|
A[reg].s32 += reg == 7 ? 2 : 1;
|
|
return value;
|
|
case 4: // -(An)
|
|
A[reg].s32 -= reg == 7 ? 2 : 1;
|
|
return ReadByte(A[reg].s32);
|
|
case 5: // (d16,An)
|
|
value = ReadByte((A[reg].s32 + ReadWord(PC)));
|
|
return value;
|
|
case 6: // (d8,An,Xn)
|
|
return ReadByte(A[reg].s32 + PeekIndex());
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: // (imm).W
|
|
value = ReadByte(ReadWord(PC));
|
|
return value;
|
|
case 1: // (imm).L
|
|
value = ReadByte(ReadLong(PC));
|
|
return value;
|
|
case 2: // (d16,PC)
|
|
value = ReadByte(PC + ReadWord(PC));
|
|
return value;
|
|
case 3: // (d8,PC,Xn)
|
|
value = ReadByte((PC + PeekIndex()));
|
|
return value;
|
|
case 4: // immediate
|
|
return (sbyte)ReadWord(PC);
|
|
default:
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
short PeekValueW(int mode, int reg)
|
|
{
|
|
short value;
|
|
switch (mode)
|
|
{
|
|
case 0: // Dn
|
|
return D[reg].s16;
|
|
case 1: // An
|
|
return A[reg].s16;
|
|
case 2: // (An)
|
|
return ReadWord(A[reg].s32);
|
|
case 3: // (An)+
|
|
value = ReadWord(A[reg].s32);
|
|
A[reg].s32 += 2;
|
|
return value;
|
|
case 4: // -(An)
|
|
A[reg].s32 -= 2;
|
|
return ReadWord(A[reg].s32);
|
|
case 5: // (d16,An)
|
|
value = ReadWord((A[reg].s32 + ReadWord(PC)));
|
|
return value;
|
|
case 6: // (d8,An,Xn)
|
|
return ReadWord(A[reg].s32 + PeekIndex());
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: // (imm).W
|
|
value = ReadWord(ReadWord(PC));
|
|
return value;
|
|
case 1: // (imm).L
|
|
value = ReadWord(ReadLong(PC));
|
|
return value;
|
|
case 2: // (d16,PC)
|
|
value = ReadWord(PC + ReadWord(PC));
|
|
return value;
|
|
case 3: // (d8,PC,Xn)
|
|
value = ReadWord((PC + PeekIndex()));
|
|
return value;
|
|
case 4: // immediate
|
|
return ReadWord(PC);
|
|
default:
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
int PeekValueL(int mode, int reg)
|
|
{
|
|
int value;
|
|
switch (mode)
|
|
{
|
|
case 0: // Dn
|
|
return D[reg].s32;
|
|
case 1: // An
|
|
return A[reg].s32;
|
|
case 2: // (An)
|
|
return ReadLong(A[reg].s32);
|
|
case 3: // (An)+
|
|
value = ReadLong(A[reg].s32);
|
|
A[reg].s32 += 4;
|
|
return value;
|
|
case 4: // -(An)
|
|
A[reg].s32 -= 4;
|
|
return ReadLong(A[reg].s32);
|
|
case 5: // (d16,An)
|
|
value = ReadLong((A[reg].s32 + ReadWord(PC)));
|
|
return value;
|
|
case 6: // (d8,An,Xn)
|
|
return ReadLong(A[reg].s32 + PeekIndex());
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: // (imm).W
|
|
value = ReadLong(ReadWord(PC));
|
|
return value;
|
|
case 1: // (imm).L
|
|
value = ReadLong(ReadLong(PC));
|
|
return value;
|
|
case 2: // (d16,PC)
|
|
value = ReadLong(PC + ReadWord(PC));
|
|
return value;
|
|
case 3: // (d8,PC,Xn)
|
|
value = ReadLong((PC + PeekIndex()));
|
|
return value;
|
|
case 4: // immediate
|
|
return ReadLong(PC);
|
|
default:
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
int ReadAddress(int mode, int reg)
|
|
{
|
|
int addr;
|
|
switch (mode)
|
|
{
|
|
case 0: throw new Exception("Invalid addressing mode!"); // Dn
|
|
case 1: throw new Exception("Invalid addressing mode!"); // An
|
|
case 2: return A[reg].s32; // (An)
|
|
case 3: return A[reg].s32; // (An)+
|
|
case 4: return A[reg].s32; // -(An)
|
|
case 5: addr = A[reg].s32 + ReadWord(PC); PC += 2; return addr; // (d16,An)
|
|
case 6: return A[reg].s32 + GetIndex(); // (d8,An,Xn)
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: addr = ReadWord(PC); PC += 2; return addr; // (imm).w
|
|
case 1: addr = ReadLong(PC); PC += 4; return addr; // (imm).l
|
|
case 2: addr = PC; addr += ReadWord(PC); PC += 2; return addr; // (d16,PC)
|
|
case 3: addr = PC; addr += GetIndex(); return addr; // (d8,PC,Xn)
|
|
case 4: throw new Exception("Invalid addressing mode!"); // immediate
|
|
}
|
|
break;
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
string DisassembleValue(int mode, int reg, int size, ref int pc)
|
|
{
|
|
string value;
|
|
int addr;
|
|
switch (mode)
|
|
{
|
|
case 0: return "D" + reg; // Dn
|
|
case 1: return "A" + reg; // An
|
|
case 2: return "(A" + reg + ")"; // (An)
|
|
case 3: return "(A" + reg + ")+"; // (An)+
|
|
case 4: return "-(A" + reg + ")"; // -(An)
|
|
case 5: value = string.Format("(${0:X},A{1})", ReadWord(pc), reg); pc += 2; return value; // (d16,An)
|
|
case 6: addr = ReadWord(pc); pc += 2; return DisassembleIndex("A" + reg, (short)addr); // (d8,An,Xn)
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: value = String.Format("(${0:X})", ReadWord(pc)); pc += 2; return value; // (imm).W
|
|
case 1: value = String.Format("(${0:X})", ReadLong(pc)); pc += 4; return value; // (imm).L
|
|
case 2: value = String.Format("(${0:X})", pc + ReadWord(pc)); pc += 2; return value; // (d16,PC)
|
|
case 3: addr = ReadWord(pc); pc += 2; return DisassembleIndex("PC", (short)addr); // (d8,PC,Xn)
|
|
case 4:
|
|
switch (size)
|
|
{
|
|
case 1: value = String.Format("${0:X}", (byte)ReadWord(pc)); pc += 2; return value;
|
|
case 2: value = String.Format("${0:X}", ReadWord(pc)); pc += 2; return value;
|
|
case 4: value = String.Format("${0:X}", ReadLong(pc)); pc += 4; return value;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
string DisassembleImmediate(int size, ref int pc)
|
|
{
|
|
int immed;
|
|
switch (size)
|
|
{
|
|
case 1:
|
|
immed = (byte)ReadWord(pc); pc += 2;
|
|
return String.Format("${0:X}", immed);
|
|
case 2:
|
|
immed = (ushort)ReadWord(pc); pc += 2;
|
|
return String.Format("${0:X}", immed);
|
|
case 4:
|
|
immed = ReadLong(pc); pc += 4;
|
|
return String.Format("${0:X}", immed);
|
|
}
|
|
throw new ArgumentException("Invalid size");
|
|
}
|
|
|
|
string DisassembleAddress(int mode, int reg, ref int pc)
|
|
{
|
|
int addr;
|
|
switch (mode)
|
|
{
|
|
case 0: return "INVALID"; // Dn
|
|
case 1: return "INVALID"; // An
|
|
case 2: return "(A" + reg + ")"; // (An)
|
|
case 3: return "(A" + reg + ")+"; // (An)+
|
|
case 4: return "-(A" + reg + ")"; // -(An)
|
|
case 5: addr = ReadWord(pc); pc += 2; return String.Format("({0},A{1})", addr, reg); // (d16,An)
|
|
case 6: addr = ReadWord(pc); pc += 2; return DisassembleIndex("A" + reg, (short)addr); // (d8,An,Xn)
|
|
case 7:
|
|
switch (reg)
|
|
{
|
|
case 0: addr = ReadWord(pc); pc += 2; return String.Format("${0:X}.w", addr); // (imm).w
|
|
case 1: addr = ReadLong(pc); pc += 4; return String.Format("${0:X}.l", addr); // (imm).l
|
|
case 2: addr = ReadWord(pc); pc += 2; return String.Format("(${0:X},PC)", addr); // (d16,PC)
|
|
case 3: addr = ReadWord(pc); pc += 2; return DisassembleIndex("PC", (short)addr); // (d8,PC,Xn)
|
|
case 4: return "INVALID"; // immediate
|
|
}
|
|
break;
|
|
}
|
|
throw new Exception("Invalid addressing mode!");
|
|
}
|
|
|
|
void WriteValueB(int mode, int reg, sbyte value)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case 0x00: // Dn
|
|
D[reg].s8 = value;
|
|
return;
|
|
case 0x01: // An
|
|
A[reg].s32 = value;
|
|
return;
|
|
case 0x02: // (An)
|
|
WriteByte(A[reg].s32, value);
|
|
return;
|
|
case 0x03: // (An)+
|
|
WriteByte(A[reg].s32, value);
|
|
A[reg].s32 += reg == 7 ? 2 : 1;
|
|
return;
|
|
case 0x04: // -(An)
|
|
A[reg].s32 -= reg == 7 ? 2 : 1;
|
|
WriteByte(A[reg].s32, value);
|
|
return;
|
|
case 0x05: // (d16,An)
|
|
WriteByte(A[reg].s32 + ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x06: // (d8,An,Xn)
|
|
WriteByte(A[reg].s32 + GetIndex(), value);
|
|
return;
|
|
case 0x07:
|
|
switch (reg)
|
|
{
|
|
case 0x00: // (imm).W
|
|
WriteByte(ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x01: // (imm).L
|
|
WriteByte(ReadLong(PC), value); PC += 4;
|
|
return;
|
|
case 0x02: // (d16,PC)
|
|
WriteByte(PC + ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x03: // (d8,PC,Xn)
|
|
int pc = PC;
|
|
WriteByte(pc + PeekIndex(), value);
|
|
PC += 2;
|
|
return;
|
|
default: throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
}
|
|
|
|
void WriteValueW(int mode, int reg, short value)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case 0x00: // Dn
|
|
D[reg].s16 = value;
|
|
return;
|
|
case 0x01: // An
|
|
A[reg].s32 = value;
|
|
return;
|
|
case 0x02: // (An)
|
|
WriteWord(A[reg].s32, value);
|
|
return;
|
|
case 0x03: // (An)+
|
|
WriteWord(A[reg].s32, value);
|
|
A[reg].s32 += 2;
|
|
return;
|
|
case 0x04: // -(An)
|
|
A[reg].s32 -= 2;
|
|
WriteWord(A[reg].s32, value);
|
|
return;
|
|
case 0x05: // (d16,An)
|
|
WriteWord(A[reg].s32 + ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x06: // (d8,An,Xn)
|
|
WriteWord(A[reg].s32 + GetIndex(), value);
|
|
return;
|
|
case 0x07:
|
|
switch (reg)
|
|
{
|
|
case 0x00: // (imm).W
|
|
WriteWord(ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x01: // (imm).L
|
|
WriteWord(ReadLong(PC), value); PC += 4;
|
|
return;
|
|
case 0x02: // (d16,PC)
|
|
WriteWord(PC + ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x03: // (d8,PC,Xn)
|
|
int pc = PC;
|
|
WriteWord(pc + PeekIndex(), value);
|
|
PC += 2;
|
|
return;
|
|
default: throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
}
|
|
|
|
void WriteValueL(int mode, int reg, int value)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case 0x00: // Dn
|
|
D[reg].s32 = value;
|
|
return;
|
|
case 0x01: // An
|
|
A[reg].s32 = value;
|
|
return;
|
|
case 0x02: // (An)
|
|
WriteLong(A[reg].s32, value);
|
|
return;
|
|
case 0x03: // (An)+
|
|
WriteLong(A[reg].s32, value);
|
|
A[reg].s32 += 4;
|
|
return;
|
|
case 0x04: // -(An)
|
|
A[reg].s32 -= 4;
|
|
WriteLong(A[reg].s32, value);
|
|
return;
|
|
case 0x05: // (d16,An)
|
|
WriteLong(A[reg].s32 + ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x06: // (d8,An,Xn)
|
|
WriteLong(A[reg].s32 + GetIndex(), value);
|
|
return;
|
|
case 0x07:
|
|
switch (reg)
|
|
{
|
|
case 0x00: // (imm).W
|
|
WriteLong(ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x01: // (imm).L
|
|
WriteLong(ReadLong(PC), value); PC += 4;
|
|
return;
|
|
case 0x02: // (d16,PC)
|
|
WriteLong(PC + ReadWord(PC), value); PC += 2;
|
|
return;
|
|
case 0x03: // (d8,PC,Xn)
|
|
int pc = PC;
|
|
WriteLong(pc + PeekIndex(), value);
|
|
PC += 2;
|
|
return;
|
|
default: throw new Exception("Invalid addressing mode!");
|
|
}
|
|
}
|
|
}
|
|
|
|
int GetIndex()
|
|
{
|
|
//Console.WriteLine("IN INDEX PORTION - NOT VERIFIED!!!");
|
|
// TODO kid chameleon triggers this in startup sequence
|
|
|
|
short extension = ReadWord(PC); PC += 2;
|
|
|
|
int da = (extension >> 15) & 0x1;
|
|
int reg = (extension >> 12) & 0x7;
|
|
int size = (extension >> 11) & 0x1;
|
|
int scale = (extension >> 9) & 0x3;
|
|
sbyte displacement = (sbyte)extension;
|
|
|
|
int indexReg;
|
|
switch (scale)
|
|
{
|
|
case 0: indexReg = 1; break;
|
|
case 1: indexReg = 2; break;
|
|
case 2: indexReg = 4; break;
|
|
default: indexReg = 8; break;
|
|
}
|
|
if (da == 0)
|
|
indexReg *= size == 0 ? D[reg].s16 : D[reg].s32;
|
|
else
|
|
indexReg *= size == 0 ? A[reg].s16 : A[reg].s32;
|
|
|
|
return displacement + indexReg;
|
|
}
|
|
|
|
int PeekIndex()
|
|
{
|
|
//Console.WriteLine("IN INDEX PORTION - NOT VERIFIED!!!");
|
|
|
|
short extension = ReadWord(PC);
|
|
|
|
int da = (extension >> 15) & 0x1;
|
|
int reg = (extension >> 12) & 0x7;
|
|
int size = (extension >> 11) & 0x1;
|
|
int scale = (extension >> 9) & 0x3;
|
|
sbyte displacement = (sbyte)extension;
|
|
|
|
int indexReg;
|
|
switch (scale)
|
|
{
|
|
case 0: indexReg = 1; break;
|
|
case 1: indexReg = 2; break;
|
|
case 2: indexReg = 4; break;
|
|
default: indexReg = 8; break;
|
|
}
|
|
if (da == 0)
|
|
indexReg *= size == 0 ? D[reg].s16 : D[reg].s32;
|
|
else
|
|
indexReg *= size == 0 ? A[reg].s16 : A[reg].s32;
|
|
|
|
return displacement + indexReg;
|
|
}
|
|
|
|
string DisassembleIndex(string baseRegister, short extension)
|
|
{
|
|
int d_a = (extension >> 15) & 0x1;
|
|
int reg = (extension >> 12) & 0x7;
|
|
int size = (extension >> 11) & 0x1;
|
|
int scale = (extension >> 9) & 0x3;
|
|
sbyte displacement = (sbyte)extension;
|
|
|
|
string scaleFactor;
|
|
switch (scale)
|
|
{
|
|
case 0: scaleFactor = ""; break;
|
|
case 1: scaleFactor = "2"; break;
|
|
case 2: scaleFactor = "4"; break;
|
|
default: scaleFactor = "8"; break;
|
|
}
|
|
|
|
string offsetRegister = (d_a == 0) ? "D" : "A";
|
|
string sizeStr = size == 0 ? ".w" : ".l";
|
|
string displacementStr = displacement == 0 ? "" : ("," + displacement);
|
|
return string.Format("({0},{1}{2}{3}{4}{5})", baseRegister, scaleFactor, offsetRegister, reg, sizeStr, displacementStr);
|
|
}
|
|
}
|
|
} |