/* 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-2007, 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: Memory emulation * * Author: Various */ /* Adaptation for SDL and POSIX (l) by beom beotiger, Nov-Dec 2007 */ #include "stdafx.h" //#pragma hdrstop #include "MouseInterface.h" #include "resource.h" #include "wwrapper.h" #include // for mlock - munlock #include #define MF_80STORE 0x00000001 #define MF_ALTZP 0x00000002 #define MF_AUXREAD 0x00000004 #define MF_AUXWRITE 0x00000008 #define MF_BANK2 0x00000010 #define MF_HIGHRAM 0x00000020 #define MF_HIRES 0x00000040 #define MF_PAGE2 0x00000080 #define MF_SLOTC3ROM 0x00000100 #define MF_SLOTCXROM 0x00000200 #define MF_WRITERAM 0x00000400 #define MF_IMAGEMASK 0x000003F7 #define SW_80STORE (memmode & MF_80STORE) #define SW_ALTZP (memmode & MF_ALTZP) #define SW_AUXREAD (memmode & MF_AUXREAD) #define SW_AUXWRITE (memmode & MF_AUXWRITE) #define SW_BANK2 (memmode & MF_BANK2) #define SW_HIGHRAM (memmode & MF_HIGHRAM) #define SW_HIRES (memmode & MF_HIRES) #define SW_PAGE2 (memmode & MF_PAGE2) #define SW_SLOTC3ROM (memmode & MF_SLOTC3ROM) #define SW_SLOTCXROM (memmode & MF_SLOTCXROM) #define SW_WRITERAM (memmode & MF_WRITERAM) //----------------------------------------------------------------------------- //static DWORD imagemode; static LPBYTE memshadow[0x100]; LPBYTE memwrite[0x100]; iofunction IORead[256]; iofunction IOWrite[256]; static LPVOID SlotParameters[NUM_SLOTS]; //static BOOL fastpaging = 0; // Redundant: only ever set to 0, by MemSetFastPaging(0) //static DWORD image = 0; //static DWORD lastimage = 0; static BOOL lastwriteram = 0; LPBYTE mem = NULL; // static LPBYTE memaux = NULL; static LPBYTE memmain = NULL; LPBYTE memdirty = NULL; static LPBYTE memrom = NULL; static LPBYTE memimage = NULL; static LPBYTE pCxRomInternal = NULL; static LPBYTE pCxRomPeripheral = NULL; // static DWORD memmode = MF_BANK2 | MF_SLOTCXROM | MF_WRITERAM; static BOOL modechanging = 0; MemoryInitPattern_e g_eMemoryInitPattern = MIP_FF_FF_00_00; #ifdef RAMWORKS UINT g_uMaxExPages = 1; // user requested ram pages static LPBYTE RWpages[128]; // pointers to RW memory banks #endif BYTE /*__stdcall*/ IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); static void UpdatePaging(BOOL initialize, BOOL updatewriteonly); //============================================================================= static BYTE /*__stdcall*/ IORead_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return KeybReadData(pc, addr, bWrite, d, nCyclesLeft); } static BYTE /*__stdcall*/ IOWrite_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { if ((addr & 0xf) <= 0xB) return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); else return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); } //------------------------------------- static BYTE /*__stdcall*/ IORead_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { switch (addr & 0xf) { case 0x0: return KeybReadFlag(pc, addr, bWrite, d, nCyclesLeft); case 0x1: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x2: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x3: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x4: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x5: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x6: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x9: return VideoCheckVbl(pc, addr, bWrite, d, nCyclesLeft); case 0xA: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0xD: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft); case 0xE: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); case 0xF: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); } return 0; } static BYTE /*__stdcall*/ IOWrite_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return KeybReadFlag(pc, addr, bWrite, d, nCyclesLeft); } //------------------------------------- static BYTE /*__stdcall*/ IORead_C02x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } static BYTE /*__stdcall*/ IOWrite_C02x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } //------------------------------------- static BYTE /*__stdcall*/ IORead_C03x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return SpkrToggle(pc, addr, bWrite, d, nCyclesLeft); } static BYTE /*__stdcall*/ IOWrite_C03x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return SpkrToggle(pc, addr, bWrite, d, nCyclesLeft); } //------------------------------------- static BYTE /*__stdcall*/ IORead_C04x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } static BYTE /*__stdcall*/ IOWrite_C04x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } //------------------------------------- static BYTE /*__stdcall*/ IORead_C05x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { switch (addr & 0xf) { case 0x0: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0x1: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0x2: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0x3: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0x4: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x5: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x6: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0x9: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xA: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xD: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xE: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0xF: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); } return 0; } static BYTE /*__stdcall*/ IOWrite_C05x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { switch (addr & 0xf) { case 0x0: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0x1: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0x2: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0x3: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0x4: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x5: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x6: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0x9: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xA: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xD: return IO_Annunciator(pc, addr, bWrite, d, nCyclesLeft); case 0xE: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); case 0xF: return VideoSetMode(pc, addr, bWrite, d, nCyclesLeft); } return 0; } //------------------------------------- static BYTE /*__stdcall*/ IORead_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { switch (addr & 0xf) { case 0x0: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x1: return JoyReadButton(pc, addr, bWrite, d, nCyclesLeft); case 0x2: return JoyReadButton(pc, addr, bWrite, d, nCyclesLeft); case 0x3: return JoyReadButton(pc, addr, bWrite, d, nCyclesLeft); case 0x4: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); case 0x5: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); case 0x6: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return JoyReadPosition(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x9: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xA: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xD: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xE: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xF: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } return 0; } static BYTE /*__stdcall*/ IOWrite_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } //------------------------------------- static BYTE /*__stdcall*/ IORead_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { switch (addr & 0xf) { case 0x0: return JoyResetPosition(pc, addr, bWrite, d, nCyclesLeft); case 0x1: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x2: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x3: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x4: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x5: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x6: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x9: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xA: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xD: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xE: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xF: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft); } return 0; } static BYTE /*__stdcall*/ IOWrite_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) { switch (addr & 0xf) { case 0x0: return JoyResetPosition(pc, addr, bWrite, d, nCyclesLeft); #ifdef RAMWORKS case 0x1: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); // extended memory card set page case 0x2: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x3: return MemSetPaging(pc, addr, bWrite, d, nCyclesLeft); // Ramworks III set page #else case 0x1: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x2: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x3: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); #endif case 0x4: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x5: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x6: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x7: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x8: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0x9: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xA: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xB: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xC: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xD: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xE: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); case 0xF: return IO_Null(pc, addr, bWrite, d, nCyclesLeft); } return 0; } //----------------------------------------------------------------------------- static iofunction IORead_C0xx[8] = { IORead_C00x, // Keyboard IORead_C01x, // Memory/Video IORead_C02x, // Cassette IORead_C03x, // Speaker IORead_C04x, IORead_C05x, // Video IORead_C06x, // Joystick IORead_C07x, // Joystick/Video }; static iofunction IOWrite_C0xx[8] = { IOWrite_C00x, // Memory/Video IOWrite_C01x, // Keyboard IOWrite_C02x, // Cassette IOWrite_C03x, // Speaker IOWrite_C04x, IOWrite_C05x, // Video/Memory IOWrite_C06x, IOWrite_C07x, // Joystick/Ramworks }; static BYTE IO_SELECT; static BYTE IO_SELECT_InternalROM; static BYTE* ExpansionRom[NUM_SLOTS]; enum eExpansionRomType {eExpRomNull=0, eExpRomInternal, eExpRomPeripheral}; static eExpansionRomType g_eExpansionRomType = eExpRomNull; static UINT g_uPeripheralRomSlot = 0; //============================================================================= BYTE /*__stdcall*/ IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft) { if (!write) return MemReadFloatingBus(nCyclesLeft); else return 0; } BYTE /*__stdcall*/ IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft) { // Apple//e ROM: // . PC=FA6F: LDA $C058 (SETAN0) // . PC=FA72: LDA $C05A (SETAN1) // . PC=C2B5: LDA $C05D (CLRAN2) // NB. AN3: For //e & //c these locations are now used to enabled/disabled DHIRES return 0; } // Enabling expansion ROM ($C800..$CFFF]: // . Enable if: Enable1 && Enable2 // . Enable1 = I/O SELECT' (6502 accesses $Csxx) // - Reset when 6502 accesses $CFFF // . Enable2 = I/O STROBE' (6502 accesses [$C800..$CFFF]) BYTE /*__stdcall*/ IORead_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft) { if (address == 0xCFFF) { // Disable expansion ROM at [$C800..$CFFF] // . SSC will disable on an access to $CFxx - but ROM only writes to $CFFF, so it doesn't matter IO_SELECT = 0; IO_SELECT_InternalROM = 0; g_uPeripheralRomSlot = 0; if (SW_SLOTCXROM) { // NB. SW_SLOTCXROM==0 ensures that internal rom stays switched in memset(pCxRomPeripheral+0x800, 0, 0x800); memset(mem+0xC800, 0, 0x800); g_eExpansionRomType = eExpRomNull; } // NB. IO_SELECT won't get set, so ROM won't be switched back in... } // BYTE IO_STROBE = 0; if (IS_APPLE2 || SW_SLOTCXROM) { if ((address >= 0xC100) && (address <= 0xC7FF)) { const UINT uSlot = (address >> 8) & 0xF; if ((uSlot != 3) && ExpansionRom[uSlot]) IO_SELECT |= 1<= 0xC800) && (address <= 0xCFFF)) { IO_STROBE = 1; } // if (IO_SELECT && IO_STROBE) { // Enable Peripheral Expansion ROM UINT uSlot=1; for (; uSlot= 0xC100) && (address <= 0xC7FF)) // Don't care about state of SW_SLOTC3ROM IO_SELECT_InternalROM = 1; else if ((address >= 0xC800) && (address <= 0xCFFF)) IO_STROBE = 1; if (!SW_SLOTCXROM && IO_SELECT_InternalROM && IO_STROBE && (g_eExpansionRomType != eExpRomInternal)) { // Enable Internal ROM memcpy(mem+0xC800, pCxRomInternal+0x800, 0x800); g_eExpansionRomType = eExpRomInternal; g_uPeripheralRomSlot = 0; } } if ((g_eExpansionRomType == eExpRomNull) && (address >= 0xC800)) return IO_Null(programcounter, address, write, value, nCyclesLeft); else return mem[address]; } BYTE /*__stdcall*/ IOWrite_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft) { return 0; } //=========================================================================== static BYTE g_bmSlotInit = 0; static void InitIoHandlers() { g_bmSlotInit = 0; UINT i=0; for (; i<8; i++) // C00x..C07x { IORead[i] = IORead_C0xx[i]; IOWrite[i] = IOWrite_C0xx[i]; } for (; i<16; i++) // C08x..C0Fx { IORead[i] = IO_Null; IOWrite[i] = IO_Null; } // for (; i<256; i++) // C10x..CFFx { IORead[i] = IORead_Cxxx; IOWrite[i] = IOWrite_Cxxx; } // IO_SELECT = 0; IO_SELECT_InternalROM = 0; g_eExpansionRomType = eExpRomNull; g_uPeripheralRomSlot = 0; for (i=0; i= 3) && // ((imagemode[imagenum] & MF_IMAGEMASK) == (memmode & MF_IMAGEMASK)))) // found = 1; // else // ++imagenum; // while ((imagenum <= lastimage) && !found); // if (found) { // image = imagenum; // mem = memimage+(image << 16); // if (imagemode[image] != memmode) { // imagemode[image] = memmode; // UpdatePaging(0,1); // } // } // else { // if (lastimage < MAXIMAGES-1) { // imagenum = ++lastimage; // if (lastimage >= 3) // VirtualAlloc(memimage+lastimage*0x10000,0x10000,MEM_COMMIT,PAGE_READWRITE); // } // else { // static DWORD nextimage = 0; // if (nextimage > lastimage) // nextimage = 0; // imagenum = nextimage++; // } // imagemode[image = imagenum] = memmode; // mem = memimage+(image << 16); // UpdatePaging(1,0); // } //} //=========================================================================== static void UpdatePaging (BOOL initialize, BOOL updatewriteonly) { // SAVE THE CURRENT PAGING SHADOW TABLE LPBYTE oldshadow[256]; if (!(initialize || updatewriteonly /*|| fastpaging*/ )) CopyMemory(oldshadow,memshadow,256*sizeof(LPBYTE)); // UPDATE THE PAGING TABLES BASED ON THE NEW PAGING SWITCH VALUES UINT loop; if (initialize) { for (loop = 0x00; loop < 0xC0; loop++) memwrite[loop] = mem+(loop << 8); for (loop = 0xC0; loop < 0xD0; loop++) memwrite[loop] = NULL; } if (!updatewriteonly) { for (loop = 0x00; loop < 0x02; loop++) memshadow[loop] = SW_ALTZP ? memaux+(loop << 8) : memmain+(loop << 8); } for (loop = 0x02; loop < 0xC0; loop++) { memshadow[loop] = SW_AUXREAD ? memaux+(loop << 8) : memmain+(loop << 8); memwrite[loop] = ((SW_AUXREAD != 0) == (SW_AUXWRITE != 0)) ? mem+(loop << 8) : SW_AUXWRITE ? memaux+(loop << 8) : memmain+(loop << 8); } if (!updatewriteonly) { for (loop = 0xC0; loop < 0xC8; loop++) { const UINT uSlotOffset = (loop & 0x0f) * 0x100; if (loop == 0xC3) memshadow[loop] = (SW_SLOTC3ROM && SW_SLOTCXROM) ? pCxRomPeripheral+uSlotOffset // C300..C3FF - Slot 3 ROM (all 0x00's) : pCxRomInternal+uSlotOffset; // C300..C3FF - Internal ROM else memshadow[loop] = SW_SLOTCXROM ? pCxRomPeripheral+uSlotOffset // C000..C7FF - SSC/Disk][/etc : pCxRomInternal+uSlotOffset; // C000..C7FF - Internal ROM } for (loop = 0xC8; loop < 0xD0; loop++) { const UINT uRomOffset = (loop & 0x0f) * 0x100; memshadow[loop] = pCxRomInternal+uRomOffset; // C800..CFFF - Internal ROM } } for (loop = 0xD0; loop < 0xE0; loop++) { int bankoffset = (SW_BANK2 ? 0 : 0x1000); memshadow[loop] = SW_HIGHRAM ? SW_ALTZP ? memaux+(loop << 8)-bankoffset : memmain+(loop << 8)-bankoffset : memrom+((loop-0xD0) * 0x100); memwrite[loop] = SW_WRITERAM ? SW_HIGHRAM ? mem+(loop << 8) : SW_ALTZP ? memaux+(loop << 8)-bankoffset : memmain+(loop << 8)-bankoffset : NULL; } for (loop = 0xE0; loop < 0x100; loop++) { memshadow[loop] = SW_HIGHRAM ? SW_ALTZP ? memaux+(loop << 8) : memmain+(loop << 8) : memrom+((loop-0xD0) * 0x100); memwrite[loop] = SW_WRITERAM ? SW_HIGHRAM ? mem+(loop << 8) : SW_ALTZP ? memaux+(loop << 8) : memmain+(loop << 8) : NULL; } if (SW_80STORE) { for (loop = 0x04; loop < 0x08; loop++) { memshadow[loop] = SW_PAGE2 ? memaux+(loop << 8) : memmain+(loop << 8); memwrite[loop] = mem+(loop << 8); } if (SW_HIRES) { for (loop = 0x20; loop < 0x40; loop++) { memshadow[loop] = SW_PAGE2 ? memaux+(loop << 8) : memmain+(loop << 8); memwrite[loop] = mem+(loop << 8); } } } // MOVE MEMORY BACK AND FORTH AS NECESSARY BETWEEN THE SHADOW AREAS AND // THE MAIN RAM IMAGE TO KEEP BOTH SETS OF MEMORY CONSISTENT WITH THE NEW // PAGING SHADOW TABLE if (!updatewriteonly) { for (loop = 0x00; loop < 0x100; loop++) { if (initialize || (oldshadow[loop] != memshadow[loop])) { if ((!(initialize/* || fastpaging*/)) && ((*(memdirty+loop) & 1) || (loop <= 1))) { *(memdirty+loop) &= ~1; CopyMemory(oldshadow[loop],mem+(loop << 8),256); } CopyMemory(mem+(loop << 8),memshadow[loop],256); } } } } // // ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- // //=========================================================================== // TODO: >= Apple2e only? BYTE /*__stdcall*/ MemCheckPaging (WORD, WORD address, BYTE, BYTE, ULONG) { address &= 0xFF; BOOL result = 0; switch (address) { case 0x11: result = SW_BANK2; break; case 0x12: result = SW_HIGHRAM; break; case 0x13: result = SW_AUXREAD; break; case 0x14: result = SW_AUXWRITE; break; case 0x15: result = !SW_SLOTCXROM; break; case 0x16: result = SW_ALTZP; break; case 0x17: result = SW_SLOTC3ROM; break; case 0x18: result = SW_80STORE; break; case 0x1C: result = SW_PAGE2; break; case 0x1D: result = SW_HIRES; break; } return KeybGetKeycode() | (result ? 0x80 : 0); } //=========================================================================== const unsigned int _6502_MEM_END = 0xFFFF; // define memory area void MemDestroy () { //if (fastpaging) // MemSetFastPaging(0); // VirtualFree(memimage,MAX(0x30000,0x10000*1),MEM_DECOMMIT); VirtualFree(memaux ,0,MEM_RELEASE); VirtualFree(memmain ,0,MEM_RELEASE); VirtualFree(memdirty,0,MEM_RELEASE); VirtualFree(memrom ,0,MEM_RELEASE); munlock(memimage, _6502_MEM_END + 1); /* POSIX: unlock memory from swapping */ VirtualFree(memimage,0,MEM_RELEASE); VirtualFree(pCxRomInternal,0,MEM_RELEASE); VirtualFree(pCxRomPeripheral,0,MEM_RELEASE); #ifdef RAMWORKS for (UINT i=1; i> 8)] == (memaux+(offset & 0xFF00))) ? mem+offset : memaux+offset; #ifdef RAMWORKS if ( ((SW_PAGE2 && SW_80STORE) || VideoGetSW80COL()) && ( ( ((offset & 0xFF00)>=0x0400) && ((offset & 0xFF00)<=0700) ) || ( SW_HIRES && ((offset & 0xFF00)>=0x2000) && ((offset & 0xFF00)<=0x3F00) ) ) ) { lpMem = (memshadow[(offset >> 8)] == (RWpages[0]+(offset & 0xFF00))) ? mem+offset : RWpages[0]+offset; } #endif return lpMem; } //=========================================================================== LPBYTE MemGetMainPtr (WORD offset) { return (memshadow[(offset >> 8)] == (memmain+(offset & 0xFF00))) ? mem+offset : memmain+offset; } //=========================================================================== LPBYTE MemGetCxRomPeripheral() { return pCxRomPeripheral; } //=========================================================================== void MemPreInitialize () { // Init the I/O handlers InitIoHandlers(); } //=========================================================================== int MemInitialize() // returns -1 if any eror during initialization { const UINT CxRomSize = 4*1024; const UINT Apple2RomSize = 12*1024; const UINT Apple2eRomSize = Apple2RomSize+CxRomSize; // ALLOCATE MEMORY FOR THE APPLE MEMORY IMAGE AND ASSOCIATED DATA STRUCTURES memaux = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); memmain = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); memdirty = (LPBYTE)VirtualAlloc(NULL,0x100 ,MEM_COMMIT,PAGE_READWRITE); memrom = (LPBYTE)VirtualAlloc(NULL,0x5000 ,MEM_COMMIT,PAGE_READWRITE); // // THE MEMIMAGE BUFFER CAN CONTAIN EITHER MULTIPLE MEMORY IMAGES OR ONE MEMORY IMAGE WITH COMPILER DATA // memimage = (LPBYTE)VirtualAlloc(NULL, // MAX(0x30000,MAXIMAGES*0x10000), // MEM_RESERVE,PAGE_NOACCESS); memimage = (LPBYTE)VirtualAlloc(NULL,_6502_MEM_END + 1,/*MEM_RESERVE*/MEM_COMMIT,/*PAGE_NOACCESS*/PAGE_READWRITE); /* POSIX : lock memory from swapping */ mlock(memimage, _6502_MEM_END + 1); pCxRomInternal = (LPBYTE) VirtualAlloc(NULL, CxRomSize, MEM_COMMIT, PAGE_READWRITE); pCxRomPeripheral = (LPBYTE) VirtualAlloc(NULL, CxRomSize, MEM_COMMIT, PAGE_READWRITE); if (!memaux || !memdirty || !memimage || !memmain || !memrom || !pCxRomInternal || !pCxRomPeripheral) { /* MessageBox( GetDesktopWindow(), TEXT("The emulator was unable to allocate the memory it ") TEXT("requires. Further execution is not possible."), g_pAppTitle, MB_ICONSTOP | MB_SETFOREGROUND); ExitProcess(1);*/ fprintf(stderr, "Unable to allocate required memory. Sorry.\n"); return -1; } // LPVOID newloc = VirtualAlloc(memimage,0x30000,MEM_COMMIT,PAGE_READWRITE); // LPVOID newloc = VirtualAlloc(memimage,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); // if (newloc != memimage) // MessageBox( // GetDesktopWindow(), // TEXT("The emulator has detected a bug in your operating ") // TEXT("system. While changing the attributes of a memory ") // TEXT("object, the operating system also changed its ") // TEXT("location."), // g_pAppTitle, // MB_ICONEXCLAMATION | MB_SETFOREGROUND); #ifdef RAMWORKS // allocate memory for RAMWorks III - up to 8MB RWpages[0] = memaux; UINT i = 1; while ((i < g_uMaxExPages) && (RWpages[i] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE))) i++; #endif // READ THE APPLE FIRMWARE ROMS INTO THE ROM IMAGE #define IDR_APPLE2_ROM "Apple2.rom" #define IDR_APPLE2_PLUS_ROM "Apple2_Plus.rom" #define IDR_APPLE2E_ROM "Apple2e.rom" #define IDR_APPLE2E_ENHANCED_ROM "Apple2e_Enhanced.rom" UINT ROM_SIZE = 0; char * RomFileName = NULL; // HRSRC hResInfo = NULL; switch (g_Apple2Type) { case A2TYPE_APPLE2: RomFileName = Apple2_rom; ROM_SIZE = Apple2RomSize; break; case A2TYPE_APPLE2PLUS:RomFileName = Apple2plus_rom; ROM_SIZE = Apple2RomSize; break; case A2TYPE_APPLE2E:RomFileName = Apple2e_rom; ROM_SIZE = Apple2eRomSize; break; case A2TYPE_APPLE2EEHANCED:RomFileName = Apple2eEnhanced_rom; ROM_SIZE = Apple2eRomSize; break; /*case A2TYPE_PRAVEC8C:RomFileName = IDR_PRAVEC_8C; ROM_SIZE = Apple2Pravec8CSize;break;*/ } if(RomFileName == NULL) { /* TCHAR sRomFileName[ MAX_PATH ]; switch (g_Apple2Type) { case A2TYPE_APPLE2: _tcscpy(sRomFileName, TEXT("APPLE2.ROM")); break; case A2TYPE_APPLE2PLUS: _tcscpy(sRomFileName, TEXT("APPLE2_PLUS.ROM")); break; case A2TYPE_APPLE2E: _tcscpy(sRomFileName, TEXT("APPLE2E.ROM")); break; case A2TYPE_APPLE2EEHANCED: _tcscpy(sRomFileName, TEXT("APPLE2E_ENHANCED.ROM")); break; } TCHAR sText[ MAX_PATH ]; wsprintf( sText, TEXT("Unable to open the required firmware ROM data file.\n\nFile: %s"), sRomFileName ); MessageBox( GetDesktopWindow(), sText, g_pAppTitle, MB_ICONSTOP | MB_SETFOREGROUND); ExitProcess(1);*/ // could not find any suitable rom?? fprintf(stderr, "Unable to find rom for specified computer type! Sorry\n"); return -1; } /* void * BUFFER = malloc(ROM_SIZE); if(BUFFER == NULL) { fprintf(stderr, "Unable to allocate %d bytes of memory for ROM.\n", ROM_SIZE); return -1; } FILE * romfile; romfile = fopen(RomFileName, "rb"); if(romfile == NULL) { fprintf(stderr, "Unable to open %s ROM file\n", RomFileName); free(BUFFER); return -1; } if(GetFileSize(romfile, NULL) != ROM_SIZE) { fprintf(stderr, "Size of %s ROM file mismatch required %d\n", RomFileName, ROM_SIZE); fclose(romfile); free(BUFFER); return -1; } UINT nbytes = fread(BUFFER, 1, ROM_SIZE, romfile); fclose(romfile); if(nbytes != ROM_SIZE) { fprintf(stderr, "Size of %s ROM file mismatches required %d bytes\n", RomFileName, ROM_SIZE); free(BUFFER); return -1; // have not read enough? } */ // DWORD dwResSize = SizeofResource(NULL, hResInfo); // if(dwResSize != ROM_SIZE) // return; // // HGLOBAL hResData = LoadResource(NULL, hResInfo); // if(hResData == NULL) // return; BYTE* pData = (BYTE*) RomFileName; // NB. Don't need to unlock resource /* if (pData == NULL) return; */ // memset(pCxRomInternal,0,CxRomSize); memset(pCxRomPeripheral,0,CxRomSize); if (ROM_SIZE == Apple2eRomSize) { memcpy(pCxRomInternal, pData, CxRomSize); pData += CxRomSize; ROM_SIZE -= CxRomSize; } _ASSERT(ROM_SIZE == Apple2RomSize); memcpy(memrom, pData, Apple2RomSize); // ROM at $D000...$FFFF // free(BUFFER); // const UINT uSlot = 0; RegisterIoHandler(uSlot, MemSetPaging, MemSetPaging, NULL, NULL, NULL, NULL); // printf("Apple ROM loaded and registered\n"); PrintLoadRom(pCxRomPeripheral, 1); // $C100 : Parallel printer f/w sg_SSC.CommInitialize(pCxRomPeripheral, 2); // $C200 : SSC if (g_Slot4 == CT_MouseInterface) sg_Mouse.Initialize(pCxRomPeripheral, 4); // $C400 : Mouse f/w DiskLoadRom(pCxRomPeripheral, 6); // $C600 : Disk][ f/w HD_Load_Rom(pCxRomPeripheral, 7); // $C700 : HDD f/w MemReset(); return 0; // all is OK?? } //=========================================================================== // Called by: // . MemInitialize() // . ResetMachineState() eg. Power-cycle ('Apple-Go' button) // . Snapshot_LoadState() void MemReset () { //// TURN OFF FAST PAGING IF IT IS CURRENTLY ACTIVE //MemSetFastPaging(0); // INITIALIZE THE PAGING TABLES ZeroMemory(memshadow,256*sizeof(LPBYTE)); ZeroMemory(memwrite ,256*sizeof(LPBYTE)); // INITIALIZE THE RAM IMAGES ZeroMemory(memaux ,0x10000); ZeroMemory(memmain,0x10000); int iByte; if (g_eMemoryInitPattern == MIP_FF_FF_00_00) { for( iByte = 0x0000; iByte < 0xC000; ) { memmain[ iByte++ ] = 0xFF; memmain[ iByte++ ] = 0xFF; iByte++; iByte++; } } // SET UP THE MEMORY IMAGE mem = memimage; //image = 0; // INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE ResetPaging(1); // INITIALIZE & RESET THE CPU // . Do this after ROM has been copied back to mem[], so that PC is correctly init'ed from 6502's reset vector CpuInitialize(); } //=========================================================================== // Call by: // . Soft-reset (Ctrl+Reset) // . Snapshot_LoadState() void MemResetPaging () { ResetPaging(0); } //=========================================================================== // Called by Disk][ I/O only BYTE MemReturnRandomData (BYTE highbit) { static const BYTE retval[16] = {0x00,0x2D,0x2D,0x30,0x30,0x32,0x32,0x34, 0x35,0x39,0x43,0x43,0x43,0x60,0x7F,0x7F}; BYTE r = (BYTE)(rand() & 0xFF); if (r <= 170) return 0x20 | (highbit ? 0x80 : 0); else return retval[r & 15] | (highbit ? 0x80 : 0); } //=========================================================================== BYTE MemReadFloatingBus(const ULONG uExecutedCycles) { return*(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); } //=========================================================================== BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles) { BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles)); return (r & ~0x80) | ((highbit) ? 0x80 : 0); } //=========================================================================== //void MemSetFastPaging (BOOL on) { // if (fastpaging && modechanging) { // modechanging = 0; // UpdateFastPaging(); // } // else if (!fastpaging) { // BackMainImage(); // if (lastimage >= 3) // VirtualFree(memimage+0x30000,(lastimage-2) << 16,MEM_DECOMMIT); // } // fastpaging = on; // image = 0; // mem = memimage; // lastimage = 0; // imagemode[0] = memmode; // if (!fastpaging) // UpdatePaging(1,0); //} //=========================================================================== BYTE /*__stdcall*/ MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft) { address &= 0xFF; DWORD lastmemmode = memmode; // DETERMINE THE NEW MEMORY PAGING MODE. if ((address >= 0x80) && (address <= 0x8F)) { BOOL writeram = (address & 1); memmode &= ~(MF_BANK2 | MF_HIGHRAM | MF_WRITERAM); lastwriteram = 1; // note: because diags.do doesn't set switches twice! if (lastwriteram && writeram) memmode |= MF_WRITERAM; if (!(address & 8)) memmode |= MF_BANK2; if (((address & 2) >> 1) == (address & 1)) memmode |= MF_HIGHRAM; lastwriteram = writeram; } else if (!IS_APPLE2) { switch (address) { case 0x00: memmode &= ~MF_80STORE; break; case 0x01: memmode |= MF_80STORE; break; case 0x02: memmode &= ~MF_AUXREAD; break; case 0x03: memmode |= MF_AUXREAD; break; case 0x04: memmode &= ~MF_AUXWRITE; break; case 0x05: memmode |= MF_AUXWRITE; break; case 0x06: memmode |= MF_SLOTCXROM; break; case 0x07: memmode &= ~MF_SLOTCXROM; break; case 0x08: memmode &= ~MF_ALTZP; break; case 0x09: memmode |= MF_ALTZP; break; case 0x0A: memmode &= ~MF_SLOTC3ROM; break; case 0x0B: memmode |= MF_SLOTC3ROM; break; case 0x54: memmode &= ~MF_PAGE2; break; case 0x55: memmode |= MF_PAGE2; break; case 0x56: memmode &= ~MF_HIRES; break; case 0x57: memmode |= MF_HIRES; break; #ifdef RAMWORKS case 0x71: // extended memory aux page number case 0x73: // Ramworks III set aux page number if ((value < g_uMaxExPages) && RWpages[value]) { memaux = RWpages[value]; //memmode &= ~MF_RWPMASK; //memmode |= value; //if (fastpaging) // UpdateFastPaging(); //else UpdatePaging(0,0); } break; #endif } } // IF THE EMULATED PROGRAM HAS JUST UPDATE THE MEMORY WRITE MODE AND IS // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL // IT DOES SO. if ((address >= 4) && (address <= 5) && ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) { modechanging = 1; return write ? 0 : MemReadFloatingBus(1, nCyclesLeft); } if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) && (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) || ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) { modechanging = 1; return write ? 0 : MemReadFloatingBus(1, nCyclesLeft); } // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND // WRITE TABLES. if ((lastmemmode != memmode) || modechanging) { modechanging = 0; if ((lastmemmode & MF_SLOTCXROM) != (memmode & MF_SLOTCXROM)) { if (SW_SLOTCXROM) { // Disable Internal ROM // . Similar to $CFFF access // . None of the peripheral cards can be driving the bus - so use the null ROM memset(pCxRomPeripheral+0x800, 0, 0x800); memset(mem+0xC800, 0, 0x800); g_eExpansionRomType = eExpRomNull; g_uPeripheralRomSlot = 0; } else { // Enable Internal ROM memcpy(mem+0xC800, pCxRomInternal+0x800, 0x800); g_eExpansionRomType = eExpRomInternal; g_uPeripheralRomSlot = 0; } } //// IF FAST PAGING IS ACTIVE, WE KEEP MULTIPLE COMPLETE MEMORY IMAGES //// AND WRITE TABLES, AND SWITCH BETWEEN THEM. THE FAST PAGING VERSION //// OF THE CPU EMULATOR KEEPS ALL OF THE IMAGES COHERENT. //if (fastpaging) // UpdateFastPaging(); // IF FAST PAGING IS NOT ACTIVE THEN WE KEEP ONLY ONE MEMORY IMAGE AND // WRITE TABLE, AND UPDATE THEM EVERY TIME PAGING IS CHANGED. //else UpdatePaging(0,0); } if ((address <= 1) || ((address >= 0x54) && (address <= 0x57))) return VideoSetMode(programcounter,address,write,value,nCyclesLeft); return write ? 0 : MemReadFloatingBus(nCyclesLeft); } //=========================================================================== //void MemTrimImages () { // if (fastpaging && (lastimage > 2)) // { // if (modechanging) { // modechanging = 0; // UpdateFastPaging(); // } // static DWORD trimnumber = 0; // if ((image != trimnumber) && // (image != lastimage) && // (trimnumber < lastimage)) { // imagemode[trimnumber] = imagemode[lastimage]; // VirtualFree(memimage+(lastimage-- << 16),0x10000,MEM_DECOMMIT); // DWORD realimage = image; // image = trimnumber; // mem = memimage+(image << 16); // memmode = imagemode[image]; // UpdatePaging(1,0); // image = realimage; // mem = memimage+(image << 16); // memmode = imagemode[image]; // } // if (++trimnumber >= lastimage) // trimnumber = 0; // } //} //=========================================================================== LPVOID MemGetSlotParameters (UINT uSlot) { _ASSERT(uSlot < NUM_SLOTS); return SlotParameters[uSlot]; } //=========================================================================== DWORD MemGetSnapshot(SS_BaseMemory* pSS) { pSS->dwMemMode = memmode; pSS->bLastWriteRam = lastwriteram; for(DWORD dwOffset = 0x0000; dwOffset < 0x10000; dwOffset+=0x100) { memcpy(pSS->nMemMain+dwOffset, MemGetMainPtr((WORD)dwOffset), 0x100); memcpy(pSS->nMemAux+dwOffset, MemGetAuxPtr((WORD)dwOffset), 0x100); } return 0; } DWORD MemSetSnapshot(SS_BaseMemory* pSS) { memmode = pSS->dwMemMode; lastwriteram = pSS->bLastWriteRam; memcpy(memmain, pSS->nMemMain, nMemMainSize); memcpy(memaux, pSS->nMemAux, nMemAuxSize); // modechanging = 0; UpdatePaging(1,0); // Initialize=1, UpdateWriteOnly=0 return 0; }