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