diff --git a/source/LanguageCard.cpp b/source/LanguageCard.cpp index a9146faa..3ca2c513 100644 --- a/source/LanguageCard.cpp +++ b/source/LanguageCard.cpp @@ -51,7 +51,8 @@ LanguageCardUnit * LanguageCardUnit::create(UINT slot) LanguageCardUnit::LanguageCardUnit(SS_CARDTYPE type, UINT slot) : Card(type, slot), - m_uLastRamWrite(0) + m_uLastRamWrite(0), + m_memmode(kMemModeInitialState) { if (type != CT_Saturn128K && m_slot != LanguageCardUnit::kSlot0) ThrowErrorInvalidSlot(); @@ -77,7 +78,7 @@ BYTE __stdcall LanguageCardUnit::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValu UINT uSlot = ((uAddr & 0xff) >> 4) - 8; LanguageCardUnit* pLC = (LanguageCardUnit*) MemGetSlotParameters(uSlot); - DWORD memmode = GetMemMode(); + DWORD memmode = pLC->GetLCMemMode(); DWORD lastmemmode = memmode; memmode &= ~(MF_BANK2 | MF_HIGHRAM); @@ -104,7 +105,7 @@ BYTE __stdcall LanguageCardUnit::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValu } pLC->SetLastRamWrite( ((uAddr & 1) && !bWrite) ); // UTAIIe:5-23 - SetMemMode(memmode); + pLC->SetLCMemMode(memmode); // @@ -115,6 +116,7 @@ BYTE __stdcall LanguageCardUnit::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValu // WRITE TABLES. if (lastmemmode != memmode) { + SetMemMode((GetMemMode() & ~MF_LANGCARD_MASK) | (memmode & MF_LANGCARD_MASK)); MemUpdatePaging(0); // Initialize=0 } @@ -198,7 +200,7 @@ const std::string& LanguageCardSlot0::GetSnapshotCardName(void) void LanguageCardSlot0::SaveLCState(YamlSaveHelper& yamlSaveHelper) { - yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, GetMemMode() & (MF_WRITERAM|MF_HIGHRAM|MF_BANK2)); + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, GetMemMode() & MF_LANGCARD_MASK); yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, GetLastRamWrite() ? 1 : 0); } @@ -354,7 +356,7 @@ BYTE __stdcall Saturn128K::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULO } else { - memmode = GetMemMode(); + memmode = pLC->GetLCMemMode(); lastmemmode = memmode; memmode &= ~(MF_BANK2 | MF_HIGHRAM); @@ -370,15 +372,18 @@ BYTE __stdcall Saturn128K::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULO memmode &= ~MF_WRITERAM; pLC->SetLastRamWrite(uAddr & 1); // Saturn differs from Apple's 16K LC: any access (LC is read-only) - SetMemMode(memmode); + pLC->SetLCMemMode(memmode); } - // NB. Unlike LC, no need to check if next opcode is STA $C002-5, as Saturn is not for //e + // NB. Saturn can be put in any slot but MemOptimizeForModeChanging() currently only supports LC in slot 0. + // . This optimization (check if next opcode is STA $C002-5) isn't essential, so skip it for now. // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND // WRITE TABLES. if ((lastmemmode != memmode) || bBankChanged) { + if (lastmemmode != memmode) + SetMemMode((GetMemMode() & ~MF_LANGCARD_MASK) | (memmode & MF_LANGCARD_MASK)); MemUpdatePaging(0); // Initialize=0 } diff --git a/source/LanguageCard.h b/source/LanguageCard.h index bad7d982..12c459d2 100644 --- a/source/LanguageCard.h +++ b/source/LanguageCard.h @@ -26,6 +26,8 @@ public: BOOL GetLastRamWrite(void) { return m_uLastRamWrite; } void SetLastRamWrite(BOOL count) { m_uLastRamWrite = count; } + UINT GetLCMemMode(void) { return m_memmode; } + void SetLCMemMode(UINT memmode) { m_memmode = memmode; } SS_CARDTYPE GetMemoryType(void) { return QueryType(); } bool IsOpcodeRMWabs(WORD addr); @@ -39,6 +41,7 @@ protected: private: UINT m_uLastRamWrite; + UINT m_memmode; }; // diff --git a/source/Memory.cpp b/source/Memory.cpp index 3c291fa5..4358c14a 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -76,20 +76,20 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // . Sather uses INTCXROM instead of SLOTCXROM' (used by the Apple//e Tech Ref Manual), so keep to this // convention too since UTAIIe is the reference for most of the logic that we implement in the emulator. -#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_INTCXROM (memmode & MF_INTCXROM) -#define SW_WRITERAM (memmode & MF_WRITERAM) -#define SW_IOUDIS (memmode & MF_IOUDIS) -#define SW_ALTROM0 (memmode & MF_ALTROM0) // For Copam Base64A -#define SW_ALTROM1 (memmode & MF_ALTROM1) // For Copam Base64A +#define SW_80STORE (g_memmode & MF_80STORE) +#define SW_ALTZP (g_memmode & MF_ALTZP) +#define SW_AUXREAD (g_memmode & MF_AUXREAD) +#define SW_AUXWRITE (g_memmode & MF_AUXWRITE) +#define SW_BANK2 (g_memmode & MF_BANK2) +#define SW_HIGHRAM (g_memmode & MF_HIGHRAM) +#define SW_HIRES (g_memmode & MF_HIRES) +#define SW_PAGE2 (g_memmode & MF_PAGE2) +#define SW_SLOTC3ROM (g_memmode & MF_SLOTC3ROM) +#define SW_INTCXROM (g_memmode & MF_INTCXROM) +#define SW_WRITERAM (g_memmode & MF_WRITERAM) +#define SW_IOUDIS (g_memmode & MF_IOUDIS) +#define SW_ALTROM0 (g_memmode & MF_ALTROM0) // For Copam Base64A +#define SW_ALTROM1 (g_memmode & MF_ALTROM1) // For Copam Base64A /* MEMORY MANAGEMENT SOFT SWITCHES @@ -224,7 +224,7 @@ static LPBYTE pCxRomPeripheral = NULL; static LPBYTE g_pMemMainLanguageCard = NULL; -static DWORD memmode = LanguageCardUnit::kMemModeInitialState; +static DWORD g_memmode = LanguageCardUnit::kMemModeInitialState; static BOOL modechanging = 0; // An Optimisation: means delay calling UpdatePaging() for 1 instruction static UINT memrompages = 1; @@ -650,12 +650,12 @@ static BYTE __stdcall IOWrite_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON case 0xC: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); case 0xD: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); case 0xE: if (IS_APPLE2C()) - SetMemMode(memmode | MF_IOUDIS); // On: disable IOU access for addresses $C058 to $C05F; enable access to DHIRES switch + SetMemMode(g_memmode | MF_IOUDIS); // On: disable IOU access for addresses $C058 to $C05F; enable access to DHIRES switch else return IO_Null(pc, addr, bWrite, d, nExecutedCycles); break; case 0xF: if (IS_APPLE2C()) - SetMemMode(memmode & ~MF_IOUDIS); // Off: enable IOU access for addresses $C058 to $C05F; disable access to DHIRES switch + SetMemMode(g_memmode & ~MF_IOUDIS); // Off: enable IOU access for addresses $C058 to $C05F; disable access to DHIRES switch else return IO_Null(pc, addr, bWrite, d, nExecutedCycles); break; @@ -1080,14 +1080,14 @@ static bool IsCardInSlot(UINT slot) DWORD GetMemMode(void) { - return memmode; + return g_memmode; } void SetMemMode(DWORD uNewMemMode) { #if defined(_DEBUG) && 0 static DWORD dwOldDiff = 0; - DWORD dwDiff = memmode ^ uNewMemMode; + DWORD dwDiff = g_memmode ^ uNewMemMode; dwDiff &= ~(MF_SLOTC3ROM | MF_INTCXROM); if (dwOldDiff != dwDiff) { @@ -1122,7 +1122,7 @@ void SetMemMode(DWORD uNewMemMode) OutputDebugString(str.c_str()); } #endif - memmode = uNewMemMode; + g_memmode = uNewMemMode; } //=========================================================================== @@ -1962,7 +1962,7 @@ void MemReset() mem = memimage; // INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE - ResetPaging(TRUE); // Initialize=1, init memmode + ResetPaging(TRUE); // Initialize=1, init g_memmode MemAnnunciatorReset(); // INITIALIZE & RESET THE CPU @@ -2026,7 +2026,7 @@ static void DebugFlip(WORD address, ULONG nExecutedCycles) BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nExecutedCycles) { address &= 0xFF; - DWORD lastmemmode = memmode; + DWORD lastmemmode = g_memmode; #if defined(_DEBUG) && defined(DEBUG_FLIP_TIMINGS) DebugFlip(address, nExecutedCycles); #endif @@ -2036,22 +2036,22 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE { switch (address) { - case 0x00: SetMemMode(memmode & ~MF_80STORE); break; - case 0x01: SetMemMode(memmode | MF_80STORE); break; - case 0x02: SetMemMode(memmode & ~MF_AUXREAD); break; - case 0x03: SetMemMode(memmode | MF_AUXREAD); break; - case 0x04: SetMemMode(memmode & ~MF_AUXWRITE); break; - case 0x05: SetMemMode(memmode | MF_AUXWRITE); break; - case 0x06: SetMemMode(memmode & ~MF_INTCXROM); break; - case 0x07: SetMemMode(memmode | MF_INTCXROM); break; - case 0x08: SetMemMode(memmode & ~MF_ALTZP); break; - case 0x09: SetMemMode(memmode | MF_ALTZP); break; - case 0x0A: SetMemMode(memmode & ~MF_SLOTC3ROM); break; - case 0x0B: SetMemMode(memmode | MF_SLOTC3ROM); break; - case 0x54: SetMemMode(memmode & ~MF_PAGE2); break; - case 0x55: SetMemMode(memmode | MF_PAGE2); break; - case 0x56: SetMemMode(memmode & ~MF_HIRES); break; - case 0x57: SetMemMode(memmode | MF_HIRES); break; + case 0x00: SetMemMode(g_memmode & ~MF_80STORE); break; + case 0x01: SetMemMode(g_memmode | MF_80STORE); break; + case 0x02: SetMemMode(g_memmode & ~MF_AUXREAD); break; + case 0x03: SetMemMode(g_memmode | MF_AUXREAD); break; + case 0x04: SetMemMode(g_memmode & ~MF_AUXWRITE); break; + case 0x05: SetMemMode(g_memmode | MF_AUXWRITE); break; + case 0x06: SetMemMode(g_memmode & ~MF_INTCXROM); break; + case 0x07: SetMemMode(g_memmode | MF_INTCXROM); break; + case 0x08: SetMemMode(g_memmode & ~MF_ALTZP); break; + case 0x09: SetMemMode(g_memmode | MF_ALTZP); break; + case 0x0A: SetMemMode(g_memmode & ~MF_SLOTC3ROM); break; + case 0x0B: SetMemMode(g_memmode | MF_SLOTC3ROM); break; + case 0x54: SetMemMode(g_memmode & ~MF_PAGE2); break; + case 0x55: SetMemMode(g_memmode | MF_PAGE2); break; + case 0x56: SetMemMode(g_memmode & ~MF_HIRES); break; + case 0x57: SetMemMode(g_memmode | MF_HIRES); break; #ifdef RAMWORKS case 0x71: // extended memory aux page number case 0x73: // Ramworks III set aux page number @@ -2079,10 +2079,10 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE { switch (address) { - case 0x58: SetMemMode(memmode & ~MF_ALTROM0); break; - case 0x59: SetMemMode(memmode | MF_ALTROM0); break; - case 0x5A: SetMemMode(memmode & ~MF_ALTROM1); break; - case 0x5B: SetMemMode(memmode | MF_ALTROM1); break; + case 0x58: SetMemMode(g_memmode & ~MF_ALTROM0); break; + case 0x59: SetMemMode(g_memmode | MF_ALTROM0); break; + case 0x5A: SetMemMode(g_memmode & ~MF_ALTROM1); break; + case 0x5B: SetMemMode(g_memmode | MF_ALTROM1); break; } } @@ -2091,10 +2091,10 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND // WRITE TABLES. - if ((lastmemmode != memmode) || modechanging) + if ((lastmemmode != g_memmode) || modechanging) { // NB. Must check MF_SLOTC3ROM too, as IoHandlerCardsIn() depends on both MF_INTCXROM|MF_SLOTC3ROM - if ((lastmemmode & (MF_INTCXROM|MF_SLOTC3ROM)) != (memmode & (MF_INTCXROM|MF_SLOTC3ROM))) + if ((lastmemmode & (MF_INTCXROM|MF_SLOTC3ROM)) != (g_memmode & (MF_INTCXROM|MF_SLOTC3ROM))) { if (!SW_INTCXROM) { @@ -2136,6 +2136,9 @@ bool MemOptimizeForModeChanging(WORD programcounter, WORD address) { if (IsAppleIIeOrAbove(GetApple2Type())) { + if (programcounter > 0xFFFC) // Prevent out of bounds access! + return false; + // IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL // IT DOES SO. @@ -2149,6 +2152,8 @@ bool MemOptimizeForModeChanging(WORD programcounter, WORD address) return true; } + // TODO: support Saturn in any slot. + // NB. GH#602 asks for any examples of this happening: if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) && // Now: LC (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) || // Next: STA $C004(RAMWRTOFF) or STA $C005(RAMWRTON) ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) // or STA $C002(RAMRDOFF) or STA $C003(RAMRDON) @@ -2178,7 +2183,7 @@ void MemAnnunciatorReset(void) if (IsCopamBase64A(GetApple2Type())) { - SetMemMode(memmode & ~(MF_ALTROM0|MF_ALTROM1)); + SetMemMode(g_memmode & ~(MF_ALTROM0|MF_ALTROM1)); UpdatePaging(FALSE); // Initialize=FALSE } } @@ -2286,7 +2291,7 @@ void MemSaveSnapshot(YamlSaveHelper& yamlSaveHelper) // Scope so that "Memory" & "Main Memory" are at same indent level { YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotStructName().c_str()); - DWORD saveMemMode = memmode; + DWORD saveMemMode = g_memmode; if (IsApple2PlusOrClone(GetApple2Type())) saveMemMode &= ~MF_LANGCARD_MASK; // For II,II+: clear LC bits - set later by slot-0 LC or Saturn yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, saveMemMode);