/* AppleWin : An Apple //e emulator for Windows Copyright (C) 1994-1996, Michael O'Brien Copyright (C) 1999-2001, Oliver Schmidt Copyright (C) 2002-2005, Tom Charlesworth Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski AppleWin is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. AppleWin is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with AppleWin; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Description: 6502/65C02 emulation * * Author: Various */ // TO DO: // . All these CPP macros need to be converted to inline funcs // // Note about bWrtMem: // ------------------- // . This is used to determine if a cycle needs to be added for a page-crossing. // // Modes that are affected: // . ABS,X; ABS,Y; (IND),Y // // The following opcodes (when indexed) add a cycle if page is crossed: // . ADC, AND, Bxx, CMP, EOR, LDA, LDX, LDY, ORA, SBC // . NB. Those opcode that DO NOT write to memory. // . 65C02: JMP (ABS-INDIRECT)? : Bug fixed for 65C02 // . 65C02: JMP (ABS-INDIRECT,X)? // // The following opcodes (when indexed) DO NOT add a cycle if page is crossed: // . ASL, DEC, INC, LSR, ROL, ROR, STA, STX, STY // . NB. Those opcode that DO write to memory. // // What about these: // . 65C02: STZ?, TRB?, TSB? // // NB. 'Zero-page indexed' opcodes wrap back to zero-page. // // NB2. bWrtMem can't be used for r/w detection, as these opcodes don’t init this flag: // . $2C BIT ABS (because there is no BIT ABS,X or BIT ABS,Y) // . $EC CPX ABS // . $CC CPY ABS // 65C02 info: // + Read-modify-write instructions abs indexed in same page take 6 cycles (cf. 7 cycles for 6502) // - ASL, DEC, INC, LSR, ROL, ROR // #include "StdAfx.h" #pragma hdrstop #define AF_SIGN 0x80 #define AF_OVERFLOW 0x40 #define AF_RESERVED 0x20 #define AF_BREAK 0x10 #define AF_DECIMAL 0x08 #define AF_INTERRUPT 0x04 #define AF_ZERO 0x02 #define AF_CARRY 0x01 #define SHORTOPCODES 22 #define BENCHOPCODES 33 typedef DWORD (__stdcall *cpuexecutetype)(DWORD); typedef void (__stdcall *cpugetcodetype)(WORD,LPBYTE *,DWORD *); typedef void (__stdcall *cpuinittype )(LPBYTE,LPBYTE *,LPBYTE *,DWORD,DWORD, LPVOID,iofunction *,iofunction *,LPBYTE, cxfunction, cxfunction); typedef DWORD (__stdcall *cpuversiontype)(void); static BYTE benchopcode[BENCHOPCODES] = {0x06,0x16,0x24,0x45,0x48,0x65,0x68,0x76, 0x84,0x85,0x86,0x91,0x94,0xA4,0xA5,0xA6, 0xB1,0xB4,0xC0,0xC4,0xC5,0xE6, 0x19,0x6D,0x8D,0x99,0x9D,0xAD,0xB9,0xBD, 0xDD,0xED,0xEE}; DWORD cpuemtype = CPU_COMPILING; static cpuexecutetype cpuexecutefunc[3] = {NULL,NULL,NULL}; static cpugetcodetype cpugetcodefunc[3] = {NULL,NULL,NULL}; static cpuinittype cpuinitfunc[3] = {NULL,NULL,NULL}; static cpuversiontype cpuversionfunc[3] = {NULL,NULL,NULL}; static HINSTANCE cpulibrary[3] = {(HINSTANCE)0,(HINSTANCE)0,(HINSTANCE)0}; regsrec regs; unsigned __int64 g_nCumulativeCycles = 0; static ULONG g_nCyclesSubmitted; // Number of cycles submitted to CpuExecute() static ULONG g_nCyclesExecuted; static signed long nInternalCyclesLeft; // // Assume all interrupt sources assert until the device is told to stop: // - eg by r/w to device's register or a machine reset static bool g_bCritSectionValid = false; // Deleting CritialSection when not valid causes crash on Win98 static CRITICAL_SECTION g_CriticalSection; // To guard /g_bmIRQ/ static volatile UINT32 g_bmIRQ = 0; /**************************************************************************** * * GENERAL PURPOSE MACROS * ***/ #define AF_TO_EF flagc = (regs.ps & AF_CARRY); \ flagn = (regs.ps & AF_SIGN); \ flagv = (regs.ps & AF_OVERFLOW); \ flagz = (regs.ps & AF_ZERO); #define EF_TO_AF regs.ps = (regs.ps & ~(AF_CARRY | AF_SIGN | \ AF_OVERFLOW | AF_ZERO)) \ | (flagc ? AF_CARRY : 0) \ | (flagn ? AF_SIGN : 0) \ | (flagv ? AF_OVERFLOW : 0) \ | (flagz ? AF_ZERO : 0); #define CMOS if (!apple2e) { \ ++cycles; \ break; \ } // CYC(a): This can be optimised, as only certain opcodes will affect uExtraCycles #define CYC(a) cycles += a+uExtraCycles; MB_UpdateCycles(a+uExtraCycles); #define POP (*(mem+((regs.sp >= 0x1FF) ? (regs.sp = 0x100) : ++regs.sp))) #define PUSH(a) *(mem+regs.sp--) = (a); \ if (regs.sp < 0x100) \ regs.sp = 0x1FF; #define READ ( \ ((addr & 0xFF00) == 0xC000) \ ? ioread[addr & 0xFF](regs.pc,(BYTE)addr,0,0,nInternalCyclesLeft) \ : ( \ (((addr & 0xFF00) == 0xC400) || ((addr & 0xFF00) == 0xC500)) \ ? CxReadFunc(regs.pc, addr, 0, 0, nInternalCyclesLeft) \ : *(mem+addr) \ ) \ ) #define SETNZ(a) { \ flagn = ((a) & 0x80); \ flagz = !(a & 0xFF); \ } #define SETZ(a) flagz = !(a & 0xFF); #define TOBCD(a) (((((a)/10) % 10) << 4) | ((a) % 10)) #define TOBIN(a) (((a) >> 4)*10 + ((a) & 0x0F)) #define WRITE(a) { \ memdirty[addr >> 8] = 0xFF; \ LPBYTE page = memwrite[0][addr >> 8]; \ if (page) \ *(page+(addr & 0xFF)) = (BYTE)(a); \ else if ((addr & 0xFF00) == 0xC000) \ iowrite[addr & 0xFF](regs.pc,(BYTE)addr,1,(BYTE)(a),nInternalCyclesLeft); \ else if(((addr & 0xFF00) == 0xC400) || ((addr & 0xFF00) == 0xC500)) \ CxWriteFunc(regs.pc, addr, 1, (BYTE)(a), nInternalCyclesLeft); \ } // #define CLKS_BRANCH 2 // ExtraCycles: // +1 if branch taken // +1 if page boundary crossed #define BRANCH_TAKEN { \ base = regs.pc; \ regs.pc += addr; \ if ((base ^ regs.pc) & 0xFF00) \ uExtraCycles=2; \ else \ uExtraCycles=1; \ } // #define CHECK_PAGE_CHANGE if (!bWrtMem) { \ if ((base ^ addr) & 0xFF00) \ uExtraCycles=1; \ } /**************************************************************************** * * ADDRESSING MODE MACROS * ***/ #define ABS addr = *(LPWORD)(mem+regs.pc); regs.pc += 2; #define ABSIINDX addr = *(LPWORD)(mem+(*(LPWORD)(mem+regs.pc))+(WORD)regs.x); regs.pc += 2; #define ABSX base = (*(LPWORD)(mem+regs.pc)); addr = base+(WORD)regs.x; regs.pc += 2; CHECK_PAGE_CHANGE; #define ABSY base = (*(LPWORD)(mem+regs.pc)); addr = base+(WORD)regs.y; regs.pc += 2; CHECK_PAGE_CHANGE; #define IABS addr = *(LPWORD)(mem+*(LPWORD)(mem+regs.pc)); regs.pc += 2; #define IMM addr = regs.pc++; #define INDX addr = *(LPWORD)(mem+(((*(mem+regs.pc++))+regs.x) & 0xFF)); #define INDY base = (*(LPWORD)(mem+*(mem+regs.pc++))); addr = base+(WORD)regs.y; CHECK_PAGE_CHANGE; #define IZPG addr = *(LPWORD)(mem+*(mem+regs.pc++)); #define REL addr = (signed char)*(mem+regs.pc++); #define ZPG addr = *(mem+regs.pc++); #define ZPGX addr = ((*(mem+regs.pc++))+regs.x) & 0xFF; #define ZPGY addr = ((*(mem+regs.pc++))+regs.y) & 0xFF; /**************************************************************************** * * INSTRUCTION MACROS * ***/ #define ADC bWrtMem = 0; \ temp = READ; \ if (regs.ps & AF_DECIMAL) { \ val = TOBIN(regs.a)+TOBIN(temp)+(flagc != 0); \ flagc = (val > 99); \ regs.a = TOBCD(val); \ if (apple2e) \ SETNZ(regs.a); \ } \ else { \ val = regs.a+temp+(flagc != 0); \ flagc = (val > 0xFF); \ flagv = (((regs.a & 0x80) == (temp & 0x80)) && \ ((regs.a & 0x80) != (val & 0x80))); \ regs.a = val & 0xFF; \ SETNZ(regs.a); \ } #define AND bWrtMem = 0; \ regs.a &= READ; \ SETNZ(regs.a) #define ASL bWrtMem = 1; \ val = READ << 1; \ flagc = (val > 0xFF); \ SETNZ(val) \ WRITE(val) #define ASLA val = regs.a << 1; \ flagc = (val > 0xFF); \ SETNZ(val) \ regs.a = (BYTE)val; #define BCC if (!flagc) BRANCH_TAKEN; #define BCS if ( flagc) BRANCH_TAKEN; #define BEQ if ( flagz) BRANCH_TAKEN; #define BIT val = READ; \ flagz = !(regs.a & val); \ flagn = val & 0x80; \ flagv = val & 0x40; #define BITI flagz = !(regs.a & READ); #define BMI if ( flagn) BRANCH_TAKEN; #define BNE if (!flagz) BRANCH_TAKEN; #define BPL if (!flagn) BRANCH_TAKEN; #define BRA BRANCH_TAKEN; #define BRK regs.pc++; \ PUSH(regs.pc >> 8) \ PUSH(regs.pc & 0xFF) \ EF_TO_AF \ regs.ps |= AF_BREAK; \ PUSH(regs.ps) \ regs.ps |= AF_INTERRUPT; \ regs.pc = *(LPWORD)(mem+0xFFFE); #define BVC if (!flagv) BRANCH_TAKEN; #define BVS if ( flagv) BRANCH_TAKEN; #define CLC flagc = 0; #define CLD regs.ps &= ~AF_DECIMAL; #define CLI regs.ps &= ~AF_INTERRUPT; #define CLV flagv = 0; #define CMP bWrtMem = 0; \ val = READ; \ flagc = (regs.a >= val); \ val = regs.a-val; \ SETNZ(val) #define CPX val = READ; \ flagc = (regs.x >= val); \ val = regs.x-val; \ SETNZ(val) #define CPY val = READ; \ flagc = (regs.y >= val); \ val = regs.y-val; \ SETNZ(val) #define DEA --regs.a; \ SETNZ(regs.a) #define DEC bWrtMem = 1; \ val = READ-1; \ SETNZ(val) \ WRITE(val) #define DEX --regs.x; \ SETNZ(regs.x) #define DEY --regs.y; \ SETNZ(regs.y) #define EOR bWrtMem = 0; \ regs.a ^= READ; \ SETNZ(regs.a) #define INA ++regs.a; \ SETNZ(regs.a) #define INC bWrtMem = 1; \ val = READ+1; \ SETNZ(val) \ WRITE(val) #define INX ++regs.x; \ SETNZ(regs.x) #define INY ++regs.y; \ SETNZ(regs.y) #define JMP regs.pc = addr; #define JSR --regs.pc; \ PUSH(regs.pc >> 8) \ PUSH(regs.pc & 0xFF) \ regs.pc = addr; #define LDA bWrtMem = 0; \ regs.a = READ; \ SETNZ(regs.a) #define LDX bWrtMem = 0; \ regs.x = READ; \ SETNZ(regs.x) #define LDY bWrtMem = 0; \ regs.y = READ; \ SETNZ(regs.y) #define LSR bWrtMem = 1; \ val = READ; \ flagc = (val & 1); \ flagn = 0; \ val >>= 1; \ SETZ(val) \ WRITE(val) #define LSRA flagc = (regs.a & 1); \ flagn = 0; \ regs.a >>= 1; \ SETZ(regs.a) #define NOP #define ORA bWrtMem = 0; \ regs.a |= READ; \ SETNZ(regs.a) #define PHA PUSH(regs.a) #define PHP EF_TO_AF \ regs.ps |= AF_RESERVED; \ PUSH(regs.ps) #define PHX PUSH(regs.x) #define PHY PUSH(regs.y) #define PLA regs.a = POP; \ SETNZ(regs.a) #define PLP regs.ps = POP; \ AF_TO_EF #define PLX regs.x = POP; \ SETNZ(regs.x) #define PLY regs.y = POP; \ SETNZ(regs.y) #define ROL bWrtMem = 1; \ val = (READ << 1) | (flagc != 0); \ flagc = (val > 0xFF); \ SETNZ(val) \ WRITE(val) #define ROLA val = (((WORD)regs.a) << 1) | (flagc != 0); \ flagc = (val > 0xFF); \ regs.a = val & 0xFF; \ SETNZ(regs.a); #define ROR bWrtMem = 1; \ temp = READ; \ val = (temp >> 1) | (flagc ? 0x80 : 0); \ flagc = temp & 1; \ SETNZ(val) \ WRITE(val) #define RORA val = (((WORD)regs.a) >> 1) | (flagc ? 0x80 : 0); \ flagc = regs.a & 1; \ regs.a = val & 0xFF; \ SETNZ(regs.a) #define RTI regs.ps = POP; \ AF_TO_EF \ regs.pc = POP; \ regs.pc |= (((WORD)POP) << 8); #define RTS regs.pc = POP; \ regs.pc |= (((WORD)POP) << 8); \ ++regs.pc; #define SBC bWrtMem = 0; \ temp = READ; \ if (regs.ps & AF_DECIMAL) { \ val = TOBIN(regs.a)-TOBIN(temp)-!flagc; \ flagc = (val < 0x8000); \ if (!flagc) val += 100; /* adjust val if carry so TOBCD macro works as intended */ \ regs.a = TOBCD(val); \ if (apple2e) \ SETNZ(regs.a); \ } \ else { \ val = regs.a-temp-!flagc; \ flagc = (val < 0x8000); \ flagv = (((regs.a & 0x80) != (temp & 0x80)) && \ ((regs.a & 0x80) != (val & 0x80))); \ regs.a = val & 0xFF; \ SETNZ(regs.a); \ } #define SEC flagc = 1; #define SED regs.ps |= AF_DECIMAL; #define SEI regs.ps |= AF_INTERRUPT; #define STA bWrtMem = 1; \ WRITE(regs.a) #define STX bWrtMem = 1; \ WRITE(regs.x) #define STY bWrtMem = 1; \ WRITE(regs.y) #define STZ bWrtMem = 1; \ WRITE(0) #define TAX regs.x = regs.a; \ SETNZ(regs.x) #define TAY regs.y = regs.a; \ SETNZ(regs.y) #define TRB bWrtMem = 1; \ val = READ; \ flagz = !(regs.a & val); \ val &= ~regs.a; \ WRITE(val) #define TSB bWrtMem = 1; \ val = READ; \ flagz = !(regs.a & val); \ val |= regs.a; \ WRITE(val) #define TSX regs.x = regs.sp & 0xFF; \ SETNZ(regs.x) #define TXA regs.a = regs.x; \ SETNZ(regs.a) #define TXS regs.sp = 0x100 | regs.x; #define TYA regs.a = regs.y; \ SETNZ(regs.a) void RequestDebugger() { PostMessage( g_hFrameWindow, WM_KEYDOWN, DEBUG_TOGGLE_KEY, 0 ); PostMessage( g_hFrameWindow, WM_KEYUP , DEBUG_TOGGLE_KEY, 0 ); } bool CheckDebugBreak( int iOpcode ) { // Rnning at full speed? (debugger not running) if ((mode != MODE_DEBUG) && (mode != MODE_STEPPING)) { if (((iOpcode == 0) && IsDebugBreakOnInvalid(0)) || ((g_iDebugOnOpcode) && (g_iDebugOnOpcode == iOpcode))) // User wants to enter debugger on opcode? { RequestDebugger(); return true; } } return false; } // Break into debugger on invalid opcodes #define INVALID1 ; if (IsDebugBreakOnInvalid(1)) { RequestDebugger(); bBreakOnInvalid = true; } #define INVALID2 if (apple2e) ++regs.pc ; if (IsDebugBreakOnInvalid(2)) { RequestDebugger(); bBreakOnInvalid = true; } #define INVALID3 if (apple2e) regs.pc += 2; if (IsDebugBreakOnInvalid(3)) { RequestDebugger(); bBreakOnInvalid = true; } /**************************************************************************** * * OPCODE TABLE * ***/ unsigned __int64 g_nCycleIrqStart; unsigned __int64 g_nCycleIrqEnd; UINT g_nCycleIrqTime; UINT g_nIdx = 0; const UINT BUFFER_SIZE = 4096; // 80 secs UINT g_nBuffer[BUFFER_SIZE]; UINT g_nMean = 0; UINT g_nMin = 0xFFFFFFFF; UINT g_nMax = 0; static inline void DoIrqProfiling(DWORD cycles) { #ifdef _DEBUG if(regs.ps & AF_INTERRUPT) return; // Still in Apple's ROM g_nCycleIrqEnd = g_nCumulativeCycles + cycles; g_nCycleIrqTime = (UINT) (g_nCycleIrqEnd - g_nCycleIrqStart); if(g_nCycleIrqTime > g_nMax) g_nMax = g_nCycleIrqTime; if(g_nCycleIrqTime < g_nMin) g_nMin = g_nCycleIrqTime; if(g_nIdx == BUFFER_SIZE) return; g_nBuffer[g_nIdx] = g_nCycleIrqTime; g_nIdx++; if(g_nIdx == BUFFER_SIZE) { UINT nTotal = 0; for(UINT i=0; i> 8) PUSH(regs.pc & 0xFF) EF_TO_AF regs.ps |= AF_RESERVED; PUSH(regs.ps) regs.ps |= AF_INTERRUPT; regs.pc = * (WORD*) (mem+0xFFFE); CYC(7) } if (bBreakOnInvalid) break; } while (cycles < totalcycles); EF_TO_AF return cycles; } // // ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- // //=========================================================================== void CpuDestroy () { int loop = 3; while (loop--) { if (cpulibrary[loop]) FreeLibrary(cpulibrary[loop]); cpuexecutefunc[loop] = NULL; cpugetcodefunc[loop] = NULL; cpulibrary[loop] = (HINSTANCE)0; } if (g_bCritSectionValid) { DeleteCriticalSection(&g_CriticalSection); g_bCritSectionValid = false; } } //=========================================================================== // Pre: // Call this when an IO-reg is access & accurate cycle info is needed // Post: // g_nCyclesExecuted // g_nCumulativeCycles // void CpuCalcCycles(ULONG nCyclesLeft) { ULONG nCycles; if((nCyclesLeft & 0x80000000) == 0) { nCyclesLeft >>= 8; nCycles = g_nCyclesSubmitted - (g_nCyclesExecuted + nCyclesLeft); // Always +ve _ASSERT(!(nCycles & 0x8000000)); } else { nCyclesLeft = ~nCyclesLeft; nCyclesLeft >>= 8; nCycles = nCyclesLeft + 1; nCycles = (g_nCyclesSubmitted + nCycles) - g_nCyclesExecuted; } g_nCyclesExecuted += nCycles; g_nCumulativeCycles += nCycles; if (cpuexecutefunc[cpuemtype]) MB_UpdateCycles((USHORT) nCycles); // OLD: Support external dll emulator } //=========================================================================== ULONG CpuGetCyclesThisFrame() { CpuCalcCycles(nInternalCyclesLeft); // TODO: simplify the whole cycle system! return g_dwCyclesThisFrame + g_nCyclesExecuted; } //=========================================================================== DWORD CpuExecute (DWORD cycles) { static BOOL laststep = 0; DWORD result = 0; g_nCyclesSubmitted = cycles; g_nCyclesExecuted = 0; // IF WE ARE SINGLE STEPPING, USE THE INTERPRETIVE EMULATOR if (!cycles) { laststep = 1; if (cpuexecutefunc[1]) result=cpuexecutefunc[1](0); else result=InternalCpuExecute(0); } // OTHERWISE, USE THE CURRENT EMULATOR. else { if (laststep) { CpuResetCompilerData(); laststep = 0; } // Don't break into 0xFFFF chunks, as at 4Mhz, /cycles/ > 0xFFFF (Spkr code ASSERTs) // DLLs accept a 23-bit number for cycles. if (cpuexecutefunc[cpuemtype]) result=cpuexecutefunc[cpuemtype](cycles); else result=InternalCpuExecute(cycles); } // IF WE ARE USING THE EXTERNAL 6502 64K EMULATOR, MARK PAGES $40-$BF AS // DIRTY, BECAUSE IT DOES NOT KEEP TRACK OF DIRTY PAGES IN THAT RANGE. if ((!apple2e) && cpuexecutefunc[1]) { int page = 0xC0; while (page-- > 0x40) *(memdirty+page) = 0xFF; } UINT nRemainingCycles = result - g_nCyclesExecuted; g_nCumulativeCycles += nRemainingCycles; if (cpuexecutefunc[cpuemtype]) MB_UpdateCycles((USHORT) nRemainingCycles); // OLD: Support external dll emulator return result; } //=========================================================================== void CpuGetCode (WORD address, LPBYTE *codeptr, DWORD *codelength) { *codeptr = NULL; *codelength = 0; if (cpugetcodefunc[0]) cpugetcodefunc[0](address,codeptr,codelength); } //=========================================================================== #define MIN_DLL_VERSION 1 void CpuInitialize () { CpuDestroy(); regs.a = 0; regs.x = 0; regs.y = 0; regs.ps = 0x20; regs.pc = *(LPWORD)(mem+0xFFFC); regs.sp = 0x01FF; InitializeCriticalSection(&g_CriticalSection); g_bCritSectionValid = true; CpuIrqReset(); #ifdef _X86_ // TO DO: // . FreeLibrary isn't being called if DLLs' version is too low // . This code is going to get ditched, so ignore this! if (mem) { TCHAR filename[MAX_PATH]; _tcscpy(filename,progdir); _tcscat(filename,TEXT("65C02C.DLL")); cpulibrary[CPU_COMPILING] = LoadLibrary(filename); _tcscpy(filename,progdir); _tcscat(filename,apple2e ? TEXT("65C02.DLL") : TEXT("6502.DLL")); cpulibrary[CPU_INTERPRETIVE] = LoadLibrary(filename); if (!cpulibrary[CPU_INTERPRETIVE]) { _tcscpy(filename,progdir); _tcscat(filename,TEXT("65C02.DLL")); cpulibrary[CPU_INTERPRETIVE] = LoadLibrary(filename); } _tcscpy(filename,progdir); _tcscat(filename,TEXT("65C02P.DLL")); cpulibrary[CPU_FASTPAGING] = LoadLibrary(filename); if (!cpulibrary[CPU_COMPILING]) cpulibrary[CPU_COMPILING] = cpulibrary[CPU_INTERPRETIVE]; int loop = 3; while (loop--) if (cpulibrary[loop]) { cpuversionfunc[loop] = (cpuversiontype)GetProcAddress(cpulibrary[loop], TEXT("CpuVersion")); if (cpuversionfunc[loop] && (cpuversionfunc[loop]()>=MIN_DLL_VERSION)) { cpuexecutefunc[loop] = (cpuexecutetype)GetProcAddress(cpulibrary[loop], TEXT("CpuExecute")); cpugetcodefunc[loop] = (cpugetcodetype)GetProcAddress(cpulibrary[loop], TEXT("CpuGetCode")); cpuinitfunc[loop] = (cpuinittype)GetProcAddress(cpulibrary[loop], TEXT("CpuInitialize")); if (cpuinitfunc[loop]) cpuinitfunc[loop](mem,memshadow[0],memwrite[0], image,lastimage, ®s,ioread,iowrite,memdirty, CxReadFunc,CxWriteFunc); } } } #endif } //=========================================================================== void CpuReinitialize () { if (cpulibrary[cpuemtype] && cpuinitfunc[cpuemtype]) cpuinitfunc[cpuemtype](mem,memshadow[0],memwrite[0], image,lastimage, ®s,ioread,iowrite,memdirty, CxReadFunc,CxWriteFunc); } //=========================================================================== void CpuResetCompilerData () { if (cpulibrary[CPU_COMPILING] && (cpulibrary[CPU_COMPILING] != cpulibrary[CPU_INTERPRETIVE])) ZeroMemory(mem+0x10000,0x20000); } //=========================================================================== void CpuSetupBenchmark () { regs.a = 0; regs.x = 0; regs.y = 0; regs.pc = 0x300; regs.sp = 0x1FF; // CREATE CODE SEGMENTS CONSISTING OF GROUPS OF COMMONLY-USED OPCODES { int addr = 0x300; int opcode = 0; do { *(mem+addr++) = benchopcode[opcode]; *(mem+addr++) = benchopcode[opcode]; if (opcode >= SHORTOPCODES) *(mem+addr++) = 0; if ((++opcode >= BENCHOPCODES) || ((addr & 0x0F) >= 0x0B)) { *(mem+addr++) = 0x4C; *(mem+addr++) = (opcode >= BENCHOPCODES) ? 0x00 : ((addr >> 4)+1) << 4; *(mem+addr++) = 0x03; while (addr & 0x0F) ++addr; } } while (opcode < BENCHOPCODES); } } //=========================================================================== BOOL CpuSupportsFastPaging () { return (cpulibrary[CPU_FASTPAGING] != (HINSTANCE)0); } //=========================================================================== void CpuIrqReset() { _ASSERT(g_bCritSectionValid); if (g_bCritSectionValid) EnterCriticalSection(&g_CriticalSection); g_bmIRQ = 0; if (g_bCritSectionValid) LeaveCriticalSection(&g_CriticalSection); } void CpuIrqAssert(eIRQSRC Device) { _ASSERT(g_bCritSectionValid); if (g_bCritSectionValid) EnterCriticalSection(&g_CriticalSection); g_bmIRQ |= 1<A = regs.a; pSS->X = regs.x; pSS->Y = regs.y; pSS->P = regs.ps; pSS->S = (BYTE) (regs.sp & 0xff); pSS->PC = regs.pc; pSS->g_nCumulativeCycles = g_nCumulativeCycles; return 0; } DWORD CpuSetSnapshot(SS_CPU6502* pSS) { regs.a = pSS->A; regs.x = pSS->X; regs.y = pSS->Y; regs.ps = pSS->P; regs.sp = (USHORT)pSS->S + 0x100; regs.pc = pSS->PC; CpuIrqReset(); g_nCumulativeCycles = pSS->g_nCumulativeCycles; return 0; }