Each LC/Saturn maintains its own local memmode. Rename global memmode to g_memmode

This commit is contained in:
tomcw 2024-03-09 16:45:09 +00:00
parent cffa53aff6
commit c7335600c4
3 changed files with 66 additions and 53 deletions

View File

@ -51,7 +51,8 @@ LanguageCardUnit * LanguageCardUnit::create(UINT slot)
LanguageCardUnit::LanguageCardUnit(SS_CARDTYPE type, UINT slot) : LanguageCardUnit::LanguageCardUnit(SS_CARDTYPE type, UINT slot) :
Card(type, slot), Card(type, slot),
m_uLastRamWrite(0) m_uLastRamWrite(0),
m_memmode(kMemModeInitialState)
{ {
if (type != CT_Saturn128K && m_slot != LanguageCardUnit::kSlot0) if (type != CT_Saturn128K && m_slot != LanguageCardUnit::kSlot0)
ThrowErrorInvalidSlot(); ThrowErrorInvalidSlot();
@ -77,7 +78,7 @@ BYTE __stdcall LanguageCardUnit::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValu
UINT uSlot = ((uAddr & 0xff) >> 4) - 8; UINT uSlot = ((uAddr & 0xff) >> 4) - 8;
LanguageCardUnit* pLC = (LanguageCardUnit*) MemGetSlotParameters(uSlot); LanguageCardUnit* pLC = (LanguageCardUnit*) MemGetSlotParameters(uSlot);
DWORD memmode = GetMemMode(); DWORD memmode = pLC->GetLCMemMode();
DWORD lastmemmode = memmode; DWORD lastmemmode = memmode;
memmode &= ~(MF_BANK2 | MF_HIGHRAM); 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 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. // WRITE TABLES.
if (lastmemmode != memmode) if (lastmemmode != memmode)
{ {
SetMemMode((GetMemMode() & ~MF_LANGCARD_MASK) | (memmode & MF_LANGCARD_MASK));
MemUpdatePaging(0); // Initialize=0 MemUpdatePaging(0); // Initialize=0
} }
@ -198,7 +200,7 @@ const std::string& LanguageCardSlot0::GetSnapshotCardName(void)
void LanguageCardSlot0::SaveLCState(YamlSaveHelper& yamlSaveHelper) 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); 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 else
{ {
memmode = GetMemMode(); memmode = pLC->GetLCMemMode();
lastmemmode = memmode; lastmemmode = memmode;
memmode &= ~(MF_BANK2 | MF_HIGHRAM); 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; memmode &= ~MF_WRITERAM;
pLC->SetLastRamWrite(uAddr & 1); // Saturn differs from Apple's 16K LC: any access (LC is read-only) 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 // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND
// WRITE TABLES. // WRITE TABLES.
if ((lastmemmode != memmode) || bBankChanged) if ((lastmemmode != memmode) || bBankChanged)
{ {
if (lastmemmode != memmode)
SetMemMode((GetMemMode() & ~MF_LANGCARD_MASK) | (memmode & MF_LANGCARD_MASK));
MemUpdatePaging(0); // Initialize=0 MemUpdatePaging(0); // Initialize=0
} }

View File

@ -26,6 +26,8 @@ public:
BOOL GetLastRamWrite(void) { return m_uLastRamWrite; } BOOL GetLastRamWrite(void) { return m_uLastRamWrite; }
void SetLastRamWrite(BOOL count) { m_uLastRamWrite = count; } 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(); } SS_CARDTYPE GetMemoryType(void) { return QueryType(); }
bool IsOpcodeRMWabs(WORD addr); bool IsOpcodeRMWabs(WORD addr);
@ -39,6 +41,7 @@ protected:
private: private:
UINT m_uLastRamWrite; UINT m_uLastRamWrite;
UINT m_memmode;
}; };
// //

View File

@ -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 // . 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. // 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_80STORE (g_memmode & MF_80STORE)
#define SW_ALTZP (memmode & MF_ALTZP) #define SW_ALTZP (g_memmode & MF_ALTZP)
#define SW_AUXREAD (memmode & MF_AUXREAD) #define SW_AUXREAD (g_memmode & MF_AUXREAD)
#define SW_AUXWRITE (memmode & MF_AUXWRITE) #define SW_AUXWRITE (g_memmode & MF_AUXWRITE)
#define SW_BANK2 (memmode & MF_BANK2) #define SW_BANK2 (g_memmode & MF_BANK2)
#define SW_HIGHRAM (memmode & MF_HIGHRAM) #define SW_HIGHRAM (g_memmode & MF_HIGHRAM)
#define SW_HIRES (memmode & MF_HIRES) #define SW_HIRES (g_memmode & MF_HIRES)
#define SW_PAGE2 (memmode & MF_PAGE2) #define SW_PAGE2 (g_memmode & MF_PAGE2)
#define SW_SLOTC3ROM (memmode & MF_SLOTC3ROM) #define SW_SLOTC3ROM (g_memmode & MF_SLOTC3ROM)
#define SW_INTCXROM (memmode & MF_INTCXROM) #define SW_INTCXROM (g_memmode & MF_INTCXROM)
#define SW_WRITERAM (memmode & MF_WRITERAM) #define SW_WRITERAM (g_memmode & MF_WRITERAM)
#define SW_IOUDIS (memmode & MF_IOUDIS) #define SW_IOUDIS (g_memmode & MF_IOUDIS)
#define SW_ALTROM0 (memmode & MF_ALTROM0) // For Copam Base64A #define SW_ALTROM0 (g_memmode & MF_ALTROM0) // For Copam Base64A
#define SW_ALTROM1 (memmode & MF_ALTROM1) // For Copam Base64A #define SW_ALTROM1 (g_memmode & MF_ALTROM1) // For Copam Base64A
/* /*
MEMORY MANAGEMENT SOFT SWITCHES MEMORY MANAGEMENT SOFT SWITCHES
@ -224,7 +224,7 @@ static LPBYTE pCxRomPeripheral = NULL;
static LPBYTE g_pMemMainLanguageCard = 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 BOOL modechanging = 0; // An Optimisation: means delay calling UpdatePaging() for 1 instruction
static UINT memrompages = 1; 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 0xC: return IO_Null(pc, addr, bWrite, d, nExecutedCycles);
case 0xD: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); case 0xD: return IO_Null(pc, addr, bWrite, d, nExecutedCycles);
case 0xE: if (IS_APPLE2C()) 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 else
return IO_Null(pc, addr, bWrite, d, nExecutedCycles); return IO_Null(pc, addr, bWrite, d, nExecutedCycles);
break; break;
case 0xF: if (IS_APPLE2C()) 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 else
return IO_Null(pc, addr, bWrite, d, nExecutedCycles); return IO_Null(pc, addr, bWrite, d, nExecutedCycles);
break; break;
@ -1080,14 +1080,14 @@ static bool IsCardInSlot(UINT slot)
DWORD GetMemMode(void) DWORD GetMemMode(void)
{ {
return memmode; return g_memmode;
} }
void SetMemMode(DWORD uNewMemMode) void SetMemMode(DWORD uNewMemMode)
{ {
#if defined(_DEBUG) && 0 #if defined(_DEBUG) && 0
static DWORD dwOldDiff = 0; static DWORD dwOldDiff = 0;
DWORD dwDiff = memmode ^ uNewMemMode; DWORD dwDiff = g_memmode ^ uNewMemMode;
dwDiff &= ~(MF_SLOTC3ROM | MF_INTCXROM); dwDiff &= ~(MF_SLOTC3ROM | MF_INTCXROM);
if (dwOldDiff != dwDiff) if (dwOldDiff != dwDiff)
{ {
@ -1122,7 +1122,7 @@ void SetMemMode(DWORD uNewMemMode)
OutputDebugString(str.c_str()); OutputDebugString(str.c_str());
} }
#endif #endif
memmode = uNewMemMode; g_memmode = uNewMemMode;
} }
//=========================================================================== //===========================================================================
@ -1962,7 +1962,7 @@ void MemReset()
mem = memimage; mem = memimage;
// INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE // INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE
ResetPaging(TRUE); // Initialize=1, init memmode ResetPaging(TRUE); // Initialize=1, init g_memmode
MemAnnunciatorReset(); MemAnnunciatorReset();
// INITIALIZE & RESET THE CPU // 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) BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nExecutedCycles)
{ {
address &= 0xFF; address &= 0xFF;
DWORD lastmemmode = memmode; DWORD lastmemmode = g_memmode;
#if defined(_DEBUG) && defined(DEBUG_FLIP_TIMINGS) #if defined(_DEBUG) && defined(DEBUG_FLIP_TIMINGS)
DebugFlip(address, nExecutedCycles); DebugFlip(address, nExecutedCycles);
#endif #endif
@ -2036,22 +2036,22 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
{ {
switch (address) switch (address)
{ {
case 0x00: SetMemMode(memmode & ~MF_80STORE); break; case 0x00: SetMemMode(g_memmode & ~MF_80STORE); break;
case 0x01: SetMemMode(memmode | MF_80STORE); break; case 0x01: SetMemMode(g_memmode | MF_80STORE); break;
case 0x02: SetMemMode(memmode & ~MF_AUXREAD); break; case 0x02: SetMemMode(g_memmode & ~MF_AUXREAD); break;
case 0x03: SetMemMode(memmode | MF_AUXREAD); break; case 0x03: SetMemMode(g_memmode | MF_AUXREAD); break;
case 0x04: SetMemMode(memmode & ~MF_AUXWRITE); break; case 0x04: SetMemMode(g_memmode & ~MF_AUXWRITE); break;
case 0x05: SetMemMode(memmode | MF_AUXWRITE); break; case 0x05: SetMemMode(g_memmode | MF_AUXWRITE); break;
case 0x06: SetMemMode(memmode & ~MF_INTCXROM); break; case 0x06: SetMemMode(g_memmode & ~MF_INTCXROM); break;
case 0x07: SetMemMode(memmode | MF_INTCXROM); break; case 0x07: SetMemMode(g_memmode | MF_INTCXROM); break;
case 0x08: SetMemMode(memmode & ~MF_ALTZP); break; case 0x08: SetMemMode(g_memmode & ~MF_ALTZP); break;
case 0x09: SetMemMode(memmode | MF_ALTZP); break; case 0x09: SetMemMode(g_memmode | MF_ALTZP); break;
case 0x0A: SetMemMode(memmode & ~MF_SLOTC3ROM); break; case 0x0A: SetMemMode(g_memmode & ~MF_SLOTC3ROM); break;
case 0x0B: SetMemMode(memmode | MF_SLOTC3ROM); break; case 0x0B: SetMemMode(g_memmode | MF_SLOTC3ROM); break;
case 0x54: SetMemMode(memmode & ~MF_PAGE2); break; case 0x54: SetMemMode(g_memmode & ~MF_PAGE2); break;
case 0x55: SetMemMode(memmode | MF_PAGE2); break; case 0x55: SetMemMode(g_memmode | MF_PAGE2); break;
case 0x56: SetMemMode(memmode & ~MF_HIRES); break; case 0x56: SetMemMode(g_memmode & ~MF_HIRES); break;
case 0x57: SetMemMode(memmode | MF_HIRES); break; case 0x57: SetMemMode(g_memmode | MF_HIRES); break;
#ifdef RAMWORKS #ifdef RAMWORKS
case 0x71: // extended memory aux page number case 0x71: // extended memory aux page number
case 0x73: // Ramworks III set 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) switch (address)
{ {
case 0x58: SetMemMode(memmode & ~MF_ALTROM0); break; case 0x58: SetMemMode(g_memmode & ~MF_ALTROM0); break;
case 0x59: SetMemMode(memmode | MF_ALTROM0); break; case 0x59: SetMemMode(g_memmode | MF_ALTROM0); break;
case 0x5A: SetMemMode(memmode & ~MF_ALTROM1); break; case 0x5A: SetMemMode(g_memmode & ~MF_ALTROM1); break;
case 0x5B: SetMemMode(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 // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND
// WRITE TABLES. // 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 // 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) if (!SW_INTCXROM)
{ {
@ -2136,6 +2136,9 @@ bool MemOptimizeForModeChanging(WORD programcounter, WORD address)
{ {
if (IsAppleIIeOrAbove(GetApple2Type())) 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 // 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 // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL
// IT DOES SO. // IT DOES SO.
@ -2149,6 +2152,8 @@ bool MemOptimizeForModeChanging(WORD programcounter, WORD address)
return true; 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 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) == 0x00C0048D) || // Next: STA $C004(RAMWRTOFF) or STA $C005(RAMWRTON)
((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) // or STA $C002(RAMRDOFF) or STA $C003(RAMRDON) ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) // or STA $C002(RAMRDOFF) or STA $C003(RAMRDON)
@ -2178,7 +2183,7 @@ void MemAnnunciatorReset(void)
if (IsCopamBase64A(GetApple2Type())) if (IsCopamBase64A(GetApple2Type()))
{ {
SetMemMode(memmode & ~(MF_ALTROM0|MF_ALTROM1)); SetMemMode(g_memmode & ~(MF_ALTROM0|MF_ALTROM1));
UpdatePaging(FALSE); // Initialize=FALSE UpdatePaging(FALSE); // Initialize=FALSE
} }
} }
@ -2286,7 +2291,7 @@ void MemSaveSnapshot(YamlSaveHelper& yamlSaveHelper)
// Scope so that "Memory" & "Main Memory" are at same indent level // Scope so that "Memory" & "Main Memory" are at same indent level
{ {
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotStructName().c_str()); YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotStructName().c_str());
DWORD saveMemMode = memmode; DWORD saveMemMode = g_memmode;
if (IsApple2PlusOrClone(GetApple2Type())) if (IsApple2PlusOrClone(GetApple2Type()))
saveMemMode &= ~MF_LANGCARD_MASK; // For II,II+: clear LC bits - set later by slot-0 LC or Saturn 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); yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, saveMemMode);