using System; namespace BizHawk.Emulation.CPUs.M68K { public partial class M68000 { private 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!"); } private 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!"); } private 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!"); } private 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 + GetIndex()); 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!"); } private 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!"); } private 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!"); } private 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: // (d16,An) addr = A[reg].s32 + ReadWord(PC); PC += 2; return addr; 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!"); } private string DisassembleValue(int mode, int reg, int size, ref int pc) { string value; 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: // (d16,An) // TODO need to figure out how to print signed-hex value = string.Format("(${0:X},A{1})", ReadWord(pc), reg); pc += 2; return value; case 6: return "NOT IMPLEMENTED"; // (d8,An,Xn) //return ReadByte(A[reg].Long + GetIndex()); case 7: switch (reg) { case 0: // (imm).W value = String.Format("(${0:X})", ReadWord(pc)); pc += 2; return value; case 1: // (imm).L value = String.Format("(${0:X})", ReadLong(pc)); pc += 4; return value; case 2: // (d16,PC) value = String.Format("(${0:X})", pc + ReadWord(pc)); pc += 2; return value; case 3: // (d8,PC,Xn) return "NOT IMPLEMENTED"; /* uint _pc = PC; value = ReadByte((_pc + GetIndex())); return value;*/ 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!"); } private 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"); } private 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: // (d16,An) addr = ReadWord(pc); pc += 2; return String.Format("({0},A{1})", addr, reg); case 6: return "NOT IMPLEMENTED"; // (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: return "NOT IMPLEMENTED"; // (d8,PC,Xn) case 4: return "INVALID"; // immediate } break; } throw new Exception("Invalid addressing mode!"); } private 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!"); } } } private 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!"); } } } private 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!"); } } } private 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; } private 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; } } }