using System; using System.Runtime.InteropServices; namespace NXSNES { public class Ricoh5A22 : ICyclic { private IMemory mem; [Flags] public enum Status : int { C = 0x001, Z = 0x002, I = 0x004, D = 0x008, X = 0x010, M = 0x020, V = 0x040, N = 0x080, E = 0x100 }; /* FIXME: not portable to big-endian systems */ [StructLayout(LayoutKind.Explicit)] public struct Registers { [FieldOffset(0)] public ushort A; [FieldOffset(0)] public byte AL; [FieldOffset(1)] public byte AH; [FieldOffset(2)] public byte DB; /* Data Bank Register */ [FieldOffset(4)] public ushort X; [FieldOffset(4)] public byte XL; [FieldOffset(5)] public byte XH; [FieldOffset(6)] public ushort Y; [FieldOffset(6)] public byte YL; [FieldOffset(7)] public byte YH; [FieldOffset(8)] public ushort D; /* Direct Page Pointer */ [FieldOffset(8)] public byte DL; [FieldOffset(9)] public byte DH; [FieldOffset(10)] public ushort SP; /* Stack Pointer */ [FieldOffset(12)] public int PL; /* Program Counter Long */ [FieldOffset(12)] public ushort PC; /* Program Counter */ [FieldOffset(14)] public byte PB; /* Program Bank */ [FieldOffset(16)] public Status S; /* Status */ } public Registers R; private long nextClock = 0; private const long OneCycle = 6; /* Prototype for one micro-op. Returns the index of the next micro-op * to execute for the current instruction, or null if this is the last * micro-op to execute. */ private delegate int? Microcode(out long accessTime); /* A jagged array consisting of the microcode to execute for each * instruction. The opcode fetch-and-decode micro-op is *not* included; * this is automatically added. */ private Microcode[][] microcode = new Microcode[256][]; private int operand; public static class EmulationVectors { public const int IRQBRK = 0xfffe; public const int Reset = 0xfffc; public const int NMI = 0xfffa; public const int Abort = 0xfff8; public const int COP = 0xfff4; } public static class NativeVectors { public const int IRQ = 0xffee; public const int NMI = 0xffea; public const int Abort = 0xffe8; public const int BRK = 0xffe6; public const int COP = 0xffe5; } /* ---------------------------------------------------------------------------- * Opcode archetypes * ------------------------------------------------------------------------- */ #if XXX private void SetZN(ushort x) { if (x == 0) R.S |= Status.Z; else R.S &= ~Status.Z; if ((x & 0x8000) == 0x8000) R.S |= Status.N; else R.S &= ~Status.N; } private void ADC(ushort d) { d += (ushort)(R.S & Status.C); uint r = (uint)(R.A + d); if ((r & 0xffff0000) != 0) R.S |= Status.C; else R.S &= ~Status.C; if (((R.A & d & 0x8000) != 0 && (r & 0x8000) == 0) || ((R.A & 0x8000) == 0 && (d & 0x8000) == 0 && (r & 0x8000) != 0)) R.S |= Status.V; else R.S &= ~Status.V; R.A = (ushort)r; SetZN(R.A); } #endif /* ---------------------------------------------------------------------------- * Addressing modes * ------------------------------------------------------------------------- */ private Microcode[] Immediate, DirectRead; private int offset; private void CreateAddressingModes() { Immediate = new Microcode[] { (out long time) => { /* 0: IDL */ operand = mem.GetByte(R.PC++, out time); if ((R.S & Status.M) == 0) return 1; else return null; }, (out long time) => { /* 1: IDH */ operand |= ((int)(mem.GetByte(R.PC++, out time)) << 8); return null; } }; DirectRead = new Microcode[] { (out long time) => { /* 0: DO */ offset = mem.GetByte(R.PC, out time); if (R.DL != 0) return 1; /* One extra cycle, below. */ else { R.PC++; return 2; /* Don't need the extra cycle. */ } }, (out long time) => { /* 1: IO */ R.PC++; time = OneCycle; return 2; }, (out long time) => { /* 2: Data Low */ operand = mem.GetByte(R.DL + offset, out time); if ((R.S & Status.M) == 0) return 3; else return null; }, (out long time) => { /* 3: Data High */ operand |= ((int)(mem.GetByte(R.DL + offset + 1, out time)) << 8); return null; } }; } /* ---------------------------------------------------------------------------- * Opcode implementations * ------------------------------------------------------------------------- */ /*private void ADCImmediate16() { ADC(Immediate16()); }*/ /* ---------------------------------------------------------------------------- * Initialization and interrupts * ------------------------------------------------------------------------- */ public Ricoh5A22(IMemory m) { CreateAddressingModes(); microcode[0x69] = new Microcode[] { }; //OpcodesN16[0x69] = ADCImmediate16; mem = m; } public void Reset() { R.S = Status.E; // R.PC = mem.GetWord(EmulationVectors.Reset); R.PB = 0; } /* ---------------------------------------------------------------------------- * The main run loop * ------------------------------------------------------------------------- */ #if XXX public void Step() { int op = mem.GetByte(R.PL); R.PC++; if ((R.S & Status.E) == 0) { if ((R.S & Status.M) == 0) OpcodesN16[op](); else OpcodesN8[op](); } else { if ((R.S & Status.M) == 0) OpcodesE16[op](); else OpcodesE8[op](); } } #endif public long Step(long clock) { return clock + 6; } } }