BizHawk/BizHawk.Emulation.Cores/CPUs/68000/Memory.cs

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);
}
}
}