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