using System;
using System.Collections.Generic;
using System.Text;
namespace dotnes
{
namespace Core
{
public enum InterruptType
{
None, // no interrupt
IRQ, // standard interrupt
NMI, // non-maskable interrupt
Quit // special code for exiting emulation
};
public interface IMachine
{
byte Read(UInt16 address);
void Write(UInt16 address, byte value);
void BadOp(byte op);
InterruptType CheckInterrupt();
void Debug();
}
public struct CPURegisters
{
public const byte FlagCarry = 0x01;
public const byte FlagZero = 0x02;
public const byte FlagIrq = 0x04;
public const byte FlagDecimal = 0x08;
public const byte FlagBreak = 0x10;
public const byte FlagOverflow = 0x40;
public const byte FlagNegative = 0x80;
public UInt16 PC;
public byte S;
public byte A;
public byte X;
public byte Y;
public byte Z;
public byte P;
}
public class CPU
{
public CPU(IMachine machine)
{
this.machine = machine;
}
public void Reset()
{
}
///
/// Runs the emulator for a specified number of cycles.
///
/// the number of cycles to run
/// The number of cycles left to run. Each opcode takes a specific number of cycles,
/// and if the function needs to execute
///
// This function executes 'cycles' CPU cycles. Each opcode takes a specified number of cycles
// to run, so enough opcodes must be executed to add up to be equal or greater than the number
// of cycles specified to run.
// Suppose that 2000 cycles need to be executed for each scanline. Assume that, for Execute(2000),
// enough opcodes have been executed to add up to 1998 cycles of run time; the number of cycles executed
// so far is less than necessary, so another opcode needs to be executed. The next opcode may take
// 2 cycles which would add up to 2000 and that scanline would be finished, but it might instead take 5,
// which would add up to 2003 cycles -- those extra 3 cycles would run over and be executed on the next scanline.
public int Execute(int cycles)
{
while (cycles > 0)
{
#if ENABLE_DEBUGGER
// did we hit the breakpoint?
if (Registers.PC == Breakpoint)
Debugging = true;
machine.Debug();
#endif
byte op = machine.Read(Registers.PC++);
cycles -= ProcessOpcode(op);
}
return cycles;
}
public void Interrupt(InterruptType type)
{
if ((type == InterruptType.IRQ) && (Registers.P & CPURegisters.FlagIrq) == 0)
return;
}
private void StackPush(byte val)
{
}
private byte StackPull()
{
return 0;
}
///
/// Executes one opcode.
///
/// the opcode to execute
/// the number of cycles the execution took
private int ProcessOpcode(byte op)
{
switch (op)
{
default:
// we don't know what this opcode is. the machine might, though;
// this is a common way to do BIOS calls and whatnot
machine.BadOp(op);
break;
}
return 0;
}
public bool Debugging;
public UInt16 Breakpoint;
public CPURegisters Registers;
private IMachine machine;
}
}
}