StoicGoose.Unity/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs

140 lines
3.0 KiB
C#

using StoicGoose.Core.Interfaces;
namespace StoicGoose.Core.CPU
{
public sealed partial class V30MZ : IComponent
{
// TODO: attempt prefetch emulation (Meitantei Conan - Nishi no Meitantei Saidai no Kiki; cart changes banks on startup, can no longer execute jump, execs garbage)
/* Parent machine instance */
readonly IMachine machine = default;
/* General registers */
Register16 ax, bx, cx, dx;
ushort sp, bp, si, di;
/* Segment registers */
ushort cs, ds, ss, es;
/* Status and instruction registers */
ushort ip;
Flags flags;
bool halted;
int opCycles, intCycles;
/* Public properties for registers */
public Register16 AX { get => ax; set => ax = value; }
public Register16 BX { get => bx; set => bx = value; }
public Register16 CX { get => cx; set => cx = value; }
public Register16 DX { get => dx; set => dx = value; }
public ushort SP { get => sp; set => sp = value; }
public ushort BP { get => bp; set => bp = value; }
public ushort SI { get => si; set => si = value; }
public ushort DI { get => di; set => di = value; }
public ushort CS { get => cs; set => cs = value; }
public ushort DS { get => ds; set => ds = value; }
public ushort SS { get => ss; set => ss = value; }
public ushort ES { get => es; set => es = value; }
public ushort IP { get => ip; set => ip = value; }
public bool IsHalted { get => halted; set => halted = value; }
public V30MZ(IMachine machine)
{
this.machine = machine;
Reset();
}
public void Reset()
{
/* CPU reset */
flags = Flags.ReservedB1 | Flags.ReservedB12 | Flags.ReservedB13 | Flags.ReservedB14 | Flags.ReservedB15;
ip = 0x0000;
cs = 0xFFFF;
ds = 0x0000;
ss = 0x0000;
es = 0x0000;
/* Initialized by WS bootstrap */
ax.Word = 0x0000;
dx.Word = 0x0000;
bp = 0x0000;
ss = 0x0000;
sp = 0x2000;
ds = 0x0000;
es = 0x0000;
/* Misc variables */
halted = false;
opCycles = intCycles = 0;
ResetPrefixes();
modRm.Reset();
}
public void Shutdown()
{
//
}
public void Interrupt(int vector)
{
/* Resume execution */
halted = false;
/* Read interrupt handler's segment & offset */
var offset = ReadMemory16(0, (ushort)((vector * 4) + 0));
var segment = ReadMemory16(0, (ushort)((vector * 4) + 2));
/* Push state, clear flags, etc. */
Push((ushort)flags);
Push(cs);
Push(ip);
ClearFlags(Flags.InterruptEnable);
ClearFlags(Flags.Trap);
ResetPrefixes();
modRm.Reset();
intCycles = 32;
/* Continue with interrupt handler */
cs = segment;
ip = offset;
}
public int Step()
{
var cycles = 0;
if (halted)
{
/* CPU is halted */
cycles++;
}
else
{
/* Read any prefixes & opcode */
byte opcode;
while (!HandlePrefixes(opcode = ReadMemory8(cs, ip++))) { }
/* Execute instruction */
opCycles = instructions[opcode](this);
cycles += opCycles;
opCycles = 0;
}
cycles += intCycles;
intCycles = 0;
/* Reset state for next instruction */
ResetPrefixes();
modRm.Reset();
return cycles;
}
}
}