diff --git a/AppleWinExpress2008.vcproj b/AppleWinExpress2008.vcproj
index 92fe61ea..1b926246 100644
--- a/AppleWinExpress2008.vcproj
+++ b/AppleWinExpress2008.vcproj
@@ -625,6 +625,14 @@
RelativePath=".\source\Keyboard.h"
>
+
+
+
+
diff --git a/AppleWinExpress2013.vcxproj b/AppleWinExpress2013.vcxproj
index 63aa1764..9b32be34 100644
--- a/AppleWinExpress2013.vcxproj
+++ b/AppleWinExpress2013.vcxproj
@@ -71,6 +71,7 @@
+
@@ -154,6 +155,7 @@
+
diff --git a/AppleWinExpress2013.vcxproj.filters b/AppleWinExpress2013.vcxproj.filters
index d1376eee..80023974 100644
--- a/AppleWinExpress2013.vcxproj.filters
+++ b/AppleWinExpress2013.vcxproj.filters
@@ -76,6 +76,9 @@
Source Files\Emulator
+
+ Source Files\Emulator
+
Source Files\Emulator
@@ -312,6 +315,9 @@
Source Files\Emulator
+
+ Source Files\Emulator
+
Source Files\Emulator
diff --git a/AppleWinExpress2015.vcxproj b/AppleWinExpress2015.vcxproj
index 4467abb4..329910e4 100644
--- a/AppleWinExpress2015.vcxproj
+++ b/AppleWinExpress2015.vcxproj
@@ -71,6 +71,7 @@
+
@@ -154,6 +155,7 @@
+
diff --git a/AppleWinExpress2015.vcxproj.filters b/AppleWinExpress2015.vcxproj.filters
index d1376eee..80023974 100644
--- a/AppleWinExpress2015.vcxproj.filters
+++ b/AppleWinExpress2015.vcxproj.filters
@@ -76,6 +76,9 @@
Source Files\Emulator
+
+ Source Files\Emulator
+
Source Files\Emulator
@@ -312,6 +315,9 @@
Source Files\Emulator
+
+ Source Files\Emulator
+
Source Files\Emulator
diff --git a/AppleWinExpress2017.vcxproj b/AppleWinExpress2017.vcxproj
index c1e10c1e..ce3cf6b1 100644
--- a/AppleWinExpress2017.vcxproj
+++ b/AppleWinExpress2017.vcxproj
@@ -71,6 +71,7 @@
+
@@ -154,6 +155,7 @@
+
diff --git a/AppleWinExpress2017.vcxproj.filters b/AppleWinExpress2017.vcxproj.filters
index baba23fc..d9a1afb6 100644
--- a/AppleWinExpress2017.vcxproj.filters
+++ b/AppleWinExpress2017.vcxproj.filters
@@ -76,6 +76,9 @@
Source Files\Emulator
+
+ Source Files\Emulator
+
Source Files\Emulator
@@ -312,6 +315,9 @@
Source Files\Emulator
+
+ Source Files\Emulator
+
Source Files\Emulator
diff --git a/source/Applewin.cpp b/source/Applewin.cpp
index 6ec6a619..cb785c33 100644
--- a/source/Applewin.cpp
+++ b/source/Applewin.cpp
@@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Frame.h"
#include "Harddisk.h"
#include "Joystick.h"
+#include "LanguageCard.h"
#include "Log.h"
#include "Memory.h"
#include "Mockingboard.h"
@@ -102,8 +103,10 @@ IPropertySheet& sg_PropertySheet = * new CPropertySheet;
CSuperSerialCard sg_SSC;
CMouseInterface sg_Mouse;
-SS_CARDTYPE g_Slot4 = CT_Empty;
-SS_CARDTYPE g_Slot5 = CT_Empty;
+SS_CARDTYPE g_Slot0 = CT_LanguageCard; // Just for Apple II or II+ or similar clones
+SS_CARDTYPE g_Slot4 = CT_Empty;
+SS_CARDTYPE g_Slot5 = CT_Empty;
+SS_CARDTYPE g_SlotAux = CT_Extended80Col; // For Apple //e and above
HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $F800..$FFFF
static bool g_bCustomRomF8Failed = false; // Set if custom ROM file failed
@@ -1145,6 +1148,8 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
LPSTR szImageName_harddisk[NUM_HARDDISKS] = {NULL,NULL};
LPSTR szSnapshotName = NULL;
const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput
+ UINT uRamWorksExPages = 0;
+ UINT uSaturnBanks = 0;
while (*lpCmdLine)
{
@@ -1249,37 +1254,30 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
#ifdef RAMWORKS
else if (strcmp(lpCmdLine, "-r") == 0) // RamWorks size [1..127]
{
- g_eMemType = MEM_TYPE_RAMWORKS;
-
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
- g_uMaxExPages = atoi(lpCmdLine);
- if (g_uMaxExPages > kMaxExMemoryBanks)
- g_uMaxExPages = kMaxExMemoryBanks;
+ uRamWorksExPages = atoi(lpCmdLine);
+ if (uRamWorksExPages > kMaxExMemoryBanks)
+ uRamWorksExPages = kMaxExMemoryBanks;
else
- if (g_uMaxExPages < 1)
- g_uMaxExPages = 1;
+ if (uRamWorksExPages < 1)
+ uRamWorksExPages = 1;
}
#endif
-#ifdef SATURN
else if (strcmp(lpCmdLine, "-saturn") == 0) // 64 = Saturn 64K (4 banks), 128 = Saturn 128K (8 banks)
{
- g_eMemType = MEM_TYPE_SATURN;
-
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
- // " The boards consist of 16K banks of memory
- // (4 banks for the 64K board,
- // 8 banks for the 128K), accessed one at a time"
- g_uSaturnTotalBanks = atoi(lpCmdLine) / 16; // number of 16K Banks [1..8]
- if (g_uSaturnTotalBanks > 8)
- g_uSaturnTotalBanks = 8;
+ // "The boards consist of 16K banks of memory (4 banks for the 64K board, 8 banks for the 128K), accessed one at a time" - Ref: "64K/128K RAM BOARD", Saturn Systems, Ch.1 Introduction(pg-5)
+ uSaturnBanks = atoi(lpCmdLine) / 16; // number of 16K Banks [1..8]
+ if (uSaturnBanks > Saturn128K::kMaxSaturnBanks)
+ uSaturnBanks = Saturn128K::kMaxSaturnBanks;
else
- if (g_uSaturnTotalBanks < 1)
- g_uSaturnTotalBanks = 1;
+ if (uSaturnBanks < 1)
+ uSaturnBanks = 1;
+
}
-#endif
else if (strcmp(lpCmdLine, "-f8rom") == 0) // Use custom 2K ROM at [$F800..$FFFF]
{
lpCmdLine = GetCurrArg(lpNextArg);
@@ -1459,6 +1457,22 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
LoadConfiguration();
LogFileOutput("Main: LoadConfiguration()\n");
+ // Apply the memory expansion switches after loading the Apple II machine type
+#ifdef RAMWORKS
+ if (uRamWorksExPages)
+ {
+ SetRamWorksMemorySize(uRamWorksExPages);
+ SetExpansionMemType(CT_RamWorksIII);
+ uRamWorksExPages = 0; // Don't reapply after a restart
+ }
+#endif
+ if (uSaturnBanks)
+ {
+ SetSaturnMemorySize(uSaturnBanks); // Set number of banks before constructing Saturn card
+ SetExpansionMemType(CT_Saturn128K);
+ uSaturnBanks = 0; // Don't reapply after a restart
+ }
+
DebugInitialize();
LogFileOutput("Main: DebugInitialize()\n");
diff --git a/source/Applewin.h b/source/Applewin.h
index a3732ecc..894cae02 100644
--- a/source/Applewin.h
+++ b/source/Applewin.h
@@ -49,8 +49,10 @@ extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (s
extern bool g_bDisableDirectSoundMockingboard; // Cmd line switch: don't init MB support
extern int g_nMemoryClearType; // Cmd line switch: use specific MIP (Memory Initialization Pattern)
+extern SS_CARDTYPE g_Slot0; // LC or Saturn in slot0
extern SS_CARDTYPE g_Slot4; // Mockingboard, Z80, Mouse in slot4
extern SS_CARDTYPE g_Slot5; // Mockingboard, Z80, in slot5
+extern SS_CARDTYPE g_SlotAux;
extern HANDLE g_hCustomRomF8; // NULL if no custom rom
diff --git a/source/Common.h b/source/Common.h
index c78af713..0bdfa9e4 100644
--- a/source/Common.h
+++ b/source/Common.h
@@ -20,7 +20,6 @@ const DWORD dwClksPerFrame = uCyclesPerLine * uLinesPerFrame; // 17030
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define RAMWORKS // 8MB RamWorks III support
-//#define SATURN // SATURN 128K
// Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample
// Assume base freqs are 44.1KHz & 48KHz
@@ -112,6 +111,7 @@ enum AppMode_e
#define REGVALUE_CUSTOM_SPEED "Custom Speed"
#define REGVALUE_EMULATION_SPEED "Emulation Speed"
#define REGVALUE_WINDOW_SCALE "Window Scale"
+#define REGVALUE_SLOT0 "Slot 0"
#define REGVALUE_SLOT1 "Slot 1"
#define REGVALUE_SLOT2 "Slot 2"
#define REGVALUE_SLOT3 "Slot 3"
@@ -193,7 +193,7 @@ enum eApple2Type {
A2TYPE_MAX
};
-inline bool IsApple2(eApple2Type type)
+inline bool IsApple2Plus(eApple2Type type) // Apple ][,][+
{
return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0;
}
@@ -203,6 +203,12 @@ inline bool IsClone(eApple2Type type)
return (type & APPLECLONE_MASK) != 0;
}
+inline bool IsApple2PlusOrClone(eApple2Type type) // Apple ][,][+ or clone ][,][+
+{
+ return ((type & (APPLE2E_MASK|APPLE2C_MASK)) == 0)
+ || (type & APPLECLONE_MASK) && !(type & A2TYPE_CLONE_A2E);
+}
+
extern eApple2Type g_Apple2Type;
inline bool IsOriginal2E(void)
{
diff --git a/source/Configuration/PageAdvanced.cpp b/source/Configuration/PageAdvanced.cpp
index d7ed2d7a..5d63b6bd 100644
--- a/source/Configuration/PageAdvanced.cpp
+++ b/source/Configuration/PageAdvanced.cpp
@@ -259,8 +259,8 @@ int CPageAdvanced::GetCloneMenuItem(void)
void CPageAdvanced::InitFreezeDlgButton(HWND hWnd)
{
- const bool bIsApple2 = IsApple2( m_PropertySheetHelper.GetConfigNew().m_Apple2Type );
- EnableWindow(GetDlgItem(hWnd, IDC_THE_FREEZES_F8_ROM_FW), bIsApple2 ? TRUE : FALSE);
+ const bool bIsApple2Plus = IsApple2Plus( m_PropertySheetHelper.GetConfigNew().m_Apple2Type );
+ EnableWindow(GetDlgItem(hWnd, IDC_THE_FREEZES_F8_ROM_FW), bIsApple2Plus ? TRUE : FALSE);
const UINT CheckTheFreezesRom = m_PropertySheetHelper.GetConfigNew().m_bEnableTheFreezesF8Rom ? BST_CHECKED : BST_UNCHECKED;
CheckDlgButton(hWnd, IDC_THE_FREEZES_F8_ROM_FW, CheckTheFreezesRom);
diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp
index 63a34037..937eccf3 100644
--- a/source/Debugger/Debugger_Display.cpp
+++ b/source/Debugger/Debugger_Display.cpp
@@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../Applewin.h"
#include "../CPU.h"
#include "../Frame.h"
+#include "../LanguageCard.h"
#include "../Memory.h"
#include "../Mockingboard.h"
#include "../Video.h"
@@ -2891,11 +2892,9 @@ void _DrawSoftSwitchLanguageCardBank( RECT & rect, int iBankDisplay, int bg_defa
int iActiveBank = -1;
char sText[ 4 ] = "?"; // Default to RAMWORKS
#ifdef RAMWORKS
- if (g_eMemType == MEM_TYPE_RAMWORKS) { sText[0] = 'r'; iActiveBank = g_uActiveBank; } // RAMWORKS
+ if (GetCurrentExpansionMemType() == CT_RamWorksIII) { sText[0] = 'r'; iActiveBank = GetRamWorksActiveBank(); } // RAMWORKS
#endif
-#ifdef SATURN
- if (g_eMemType == MEM_TYPE_SATURN ) { sText[0] = 's'; iActiveBank = g_uSaturnActiveBank; } // SATURN 64K 128K
-#endif // SATURN
+ if (GetCurrentExpansionMemType() == CT_Saturn128K) { sText[0] = 's'; iActiveBank = GetLanguageCard()->GetActiveBank(); } // SATURN 64K 128K
if (iActiveBank >= 0)
{
diff --git a/source/LanguageCard.cpp b/source/LanguageCard.cpp
new file mode 100644
index 00000000..44c6413f
--- /dev/null
+++ b/source/LanguageCard.cpp
@@ -0,0 +1,376 @@
+/*
+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-2018, Tom Charlesworth, Michael Pohoreski, Nick Westgate
+
+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: Language Card and Saturn 128K emulation
+ *
+ * Author: various
+ */
+
+#include "StdAfx.h"
+
+#include "Applewin.h"
+#include "LanguageCard.h"
+#include "Log.h"
+#include "Memory.h"
+#include "YamlHelper.h"
+
+
+const UINT LanguageCardUnit::kMemModeInitialState = MF_BANK2 | MF_WRITERAM; // !INTCXROM
+
+LanguageCardUnit::LanguageCardUnit(void) :
+ m_uLastRamWrite(0),
+ m_type(CT_LanguageCardIIe)
+{
+ SetMemMainLanguageCard(NULL, true);
+}
+
+DWORD LanguageCardUnit::SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write)
+{
+ memmode &= ~(MF_BANK2 | MF_HIGHRAM);
+
+ if (!(address & 8))
+ memmode |= MF_BANK2;
+
+ if (((address & 2) >> 1) == (address & 1))
+ memmode |= MF_HIGHRAM;
+
+ if (address & 1) // GH#392
+ {
+ if (!write && GetLastRamWrite())
+ {
+ memmode |= MF_WRITERAM; // UTAIIe:5-23
+ }
+ }
+ else
+ {
+ memmode &= ~MF_WRITERAM; // UTAIIe:5-23
+ }
+
+ SetLastRamWrite( ((address & 1) && !write) ); // UTAIIe:5-23
+
+ return memmode;
+}
+
+//-------------------------------------
+
+LanguageCardSlot0::LanguageCardSlot0(void)
+{
+ m_type = CT_LanguageCard;
+ m_pMemory = (LPBYTE) VirtualAlloc(NULL, kMemBankSize, MEM_COMMIT, PAGE_READWRITE);
+ SetMemMainLanguageCard(m_pMemory);
+}
+
+LanguageCardSlot0::~LanguageCardSlot0(void)
+{
+ VirtualFree(m_pMemory, 0, MEM_RELEASE);
+ m_pMemory = NULL;
+}
+
+//
+
+static const UINT kUNIT_LANGUAGECARD_VER = 1;
+static const UINT kSLOT_LANGUAGECARD = 0;
+
+#define SS_YAML_VALUE_CARD_LANGUAGECARD "Language Card"
+
+#define SS_YAML_KEY_MEMORYMODE "Memory Mode"
+#define SS_YAML_KEY_LASTRAMWRITE "Last RAM Write"
+
+std::string LanguageCardSlot0::GetSnapshotMemStructName(void)
+{
+ static const std::string name("Memory Bank");
+ return name;
+}
+
+std::string LanguageCardSlot0::GetSnapshotCardName(void)
+{
+ static const std::string name(SS_YAML_VALUE_CARD_LANGUAGECARD);
+ return name;
+}
+
+void LanguageCardSlot0::SaveLCState(YamlSaveHelper& yamlSaveHelper)
+{
+ yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, GetMemMode() & (MF_WRITERAM|MF_HIGHRAM|MF_BANK2));
+ yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, GetLastRamWrite() ? 1 : 0);
+}
+
+void LanguageCardSlot0::LoadLCState(YamlLoadHelper& yamlLoadHelper)
+{
+ DWORD memMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) & MF_LANGCARD_MASK;
+ BOOL lastRamWrite = yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE;
+ SetMemMode( (GetMemMode() & ~MF_LANGCARD_MASK) | memMode );
+ SetLastRamWrite(lastRamWrite);
+}
+
+void LanguageCardSlot0::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
+{
+ if (!IsApple2PlusOrClone(GetApple2Type()))
+ {
+ _ASSERT(0);
+ LogFileOutput("Warning: Save-state attempted to save %s for //e or above\n", GetSnapshotCardName().c_str());
+ return; // No Language Card support for //e and above
+ }
+
+ YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), kSLOT_LANGUAGECARD, kUNIT_LANGUAGECARD_VER);
+ YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
+
+ SaveLCState(yamlSaveHelper);
+
+ {
+ YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", GetSnapshotMemStructName().c_str());
+ yamlSaveHelper.SaveMemory(m_pMemory, kMemBankSize);
+ }
+}
+
+bool LanguageCardSlot0::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version)
+{
+ if (slot != kSLOT_LANGUAGECARD)
+ throw std::string("Card: wrong slot");
+
+ if (version != kUNIT_LANGUAGECARD_VER)
+ throw std::string("Card: wrong version");
+
+ // "State"
+ LoadLCState(yamlLoadHelper);
+
+ if (!m_pMemory)
+ {
+ m_pMemory = (LPBYTE) VirtualAlloc(NULL, kMemBankSize, MEM_COMMIT, PAGE_READWRITE);
+ if (!m_pMemory)
+ throw std::string("Card: mem alloc failed");
+ }
+
+ if (!yamlLoadHelper.GetSubMap(GetSnapshotMemStructName()))
+ throw std::string("Memory: Missing map name: " + GetSnapshotMemStructName());
+
+ yamlLoadHelper.LoadMemory(m_pMemory, kMemBankSize);
+
+ yamlLoadHelper.PopMap();
+
+ // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2()
+
+ return true;
+}
+
+//-------------------------------------
+
+Saturn128K::Saturn128K(UINT banks)
+{
+ m_type = CT_Saturn128K;
+ m_uSaturnTotalBanks = (banks == 0) ? kMaxSaturnBanks : banks;
+ m_uSaturnActiveBank = 0;
+
+ for (UINT i=0; i> 1) & 4
+ | (address >> 0) & 3;
+
+ if (m_uSaturnActiveBank >= m_uSaturnTotalBanks)
+ {
+ // EG. Run RAMTEST128K tests on a Saturn 64K card
+ // TODO: Saturn::UpdatePaging() should deal with this case:
+ // . Technically read floating-bus, write to nothing
+ // . But the mem cache doesn't support floating-bus reads from non-I/O space
+ m_uSaturnActiveBank = m_uSaturnTotalBanks-1; // FIXME: just prevent crash for now!
+ }
+
+ SetMemMainLanguageCard( m_aSaturnBanks[ m_uSaturnActiveBank ] );
+
+ modechanging = 1;
+ }
+ else
+ {
+ memmode &= ~(MF_BANK2 | MF_HIGHRAM);
+
+ if (!(address & 8))
+ memmode |= MF_BANK2;
+
+ if (((address & 2) >> 1) == (address & 1))
+ memmode |= MF_HIGHRAM;
+
+ if (address & 1 && GetLastRamWrite()) // Saturn differs from Apple's 16K LC: any access (LC is read-only)
+ memmode |= MF_WRITERAM;
+ else
+ memmode &= ~MF_WRITERAM;
+
+ SetLastRamWrite(address & 1); // Saturn differs from Apple's 16K LC: any access (LC is read-only)
+ }
+
+ return memmode;
+}
+
+//
+
+static const UINT kUNIT_SATURN_VER = 1;
+static const UINT kSLOT_SATURN = 0;
+
+#define SS_YAML_VALUE_CARD_SATURN128 "Saturn 128"
+
+#define SS_YAML_KEY_NUM_SATURN_BANKS "Num Saturn Banks"
+#define SS_YAML_KEY_ACTIVE_SATURN_BANK "Active Saturn Bank"
+
+std::string Saturn128K::GetSnapshotMemStructName(void)
+{
+ static const std::string name("Memory Bank");
+ return name;
+}
+
+std::string Saturn128K::GetSnapshotCardName(void)
+{
+ static const std::string name(SS_YAML_VALUE_CARD_SATURN128);
+ return name;
+}
+
+void Saturn128K::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
+{
+ if (!IsApple2PlusOrClone(GetApple2Type()))
+ {
+ _ASSERT(0);
+ LogFileOutput("Warning: Save-state attempted to save %s for //e or above\n", GetSnapshotCardName().c_str());
+ return; // No Saturn support for //e and above
+ }
+
+ YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), kSLOT_SATURN, kUNIT_SATURN_VER);
+ YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
+
+ SaveLCState(yamlSaveHelper);
+
+ yamlSaveHelper.Save("%s: 0x%02X # [1..8] 4=64K, 8=128K card\n", SS_YAML_KEY_NUM_SATURN_BANKS, m_uSaturnTotalBanks);
+ yamlSaveHelper.Save("%s: 0x%02X # [0..7]\n", SS_YAML_KEY_ACTIVE_SATURN_BANK, m_uSaturnActiveBank);
+
+ for(UINT uBank = 0; uBank < m_uSaturnTotalBanks; uBank++)
+ {
+ LPBYTE pMemBase = m_aSaturnBanks[uBank];
+ YamlSaveHelper::Label state(yamlSaveHelper, "%s%02X:\n", GetSnapshotMemStructName().c_str(), uBank);
+ yamlSaveHelper.SaveMemory(pMemBase, kMemBankSize);
+ }
+}
+
+bool Saturn128K::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version)
+{
+ if (slot != kSLOT_SATURN) // fixme
+ throw std::string("Card: wrong slot");
+
+ if (version != kUNIT_SATURN_VER)
+ throw std::string("Card: wrong version");
+
+ // "State"
+ LoadLCState(yamlLoadHelper);
+
+ UINT numBanks = yamlLoadHelper.LoadUint(SS_YAML_KEY_NUM_SATURN_BANKS);
+ UINT activeBank = yamlLoadHelper.LoadUint(SS_YAML_KEY_ACTIVE_SATURN_BANK);
+
+ if (numBanks < 1 || numBanks > kMaxSaturnBanks || activeBank >= numBanks)
+ throw std::string(SS_YAML_KEY_UNIT ": Bad Saturn card state");
+
+ m_uSaturnTotalBanks = numBanks;
+ m_uSaturnActiveBank = activeBank;
+
+ //
+
+ for(UINT uBank = 0; uBank < m_uSaturnTotalBanks; uBank++)
+ {
+ LPBYTE pBank = m_aSaturnBanks[uBank];
+ if (!pBank)
+ {
+ pBank = m_aSaturnBanks[uBank] = (LPBYTE) VirtualAlloc(NULL, kMemBankSize, MEM_COMMIT, PAGE_READWRITE);
+ if (!pBank)
+ throw std::string("Card: mem alloc failed");
+ }
+
+ // "Memory Bankxx"
+ char szBank[3];
+ sprintf(szBank, "%02X", uBank);
+ std::string memName = GetSnapshotMemStructName() + szBank;
+
+ if (!yamlLoadHelper.GetSubMap(memName))
+ throw std::string("Memory: Missing map name: " + memName);
+
+ yamlLoadHelper.LoadMemory(pBank, kMemBankSize);
+
+ yamlLoadHelper.PopMap();
+ }
+
+ SetMemMainLanguageCard( m_aSaturnBanks[ m_uSaturnActiveBank ] );
+
+ // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2()
+
+ return true;
+}
diff --git a/source/LanguageCard.h b/source/LanguageCard.h
new file mode 100644
index 00000000..c3654dfe
--- /dev/null
+++ b/source/LanguageCard.h
@@ -0,0 +1,83 @@
+#pragma once
+
+//
+// Language Card (base unit) for Apple //e and above
+//
+
+class LanguageCardUnit
+{
+public:
+ LanguageCardUnit(void);
+ virtual ~LanguageCardUnit(void) {}
+
+ virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write);
+ virtual void SetMemorySize(UINT banks) {} // No-op for //e and slot-0 16K LC
+ virtual UINT GetActiveBank(void) { return 0; } // Always 0 as only 1x 16K bank
+ virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) { _ASSERT(0); } // Not used for //e
+ virtual bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) { _ASSERT(0); return false; } // Not used for //e
+
+ BOOL GetLastRamWrite(void) { return m_uLastRamWrite; }
+ void SetLastRamWrite(BOOL count) { m_uLastRamWrite = count; }
+ SS_CARDTYPE GetMemoryType(void) { return m_type; }
+
+ static const UINT kMemModeInitialState;
+
+protected:
+ SS_CARDTYPE m_type;
+
+private:
+ UINT m_uLastRamWrite;
+};
+
+//
+// Language Card (slot-0) for Apple II or II+
+//
+
+class LanguageCardSlot0 : public LanguageCardUnit
+{
+public:
+ LanguageCardSlot0(void);
+ virtual ~LanguageCardSlot0(void);
+
+ virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
+ virtual bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);
+
+ static const UINT kMemBankSize = 16*1024;
+ static std::string GetSnapshotCardName(void);
+
+protected:
+ void SaveLCState(class YamlSaveHelper& yamlSaveHelper);
+ void LoadLCState(class YamlLoadHelper& yamlLoadHelper);
+
+private:
+ std::string GetSnapshotMemStructName(void);
+
+ LPBYTE m_pMemory;
+};
+
+//
+// Saturn 128K
+//
+
+class Saturn128K : public LanguageCardSlot0
+{
+public:
+ Saturn128K(UINT banks);
+ virtual ~Saturn128K(void);
+
+ virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write);
+ virtual void SetMemorySize(UINT banks);
+ virtual UINT GetActiveBank(void);
+ virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
+ virtual bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);
+
+ static const UINT kMaxSaturnBanks = 8; // 8 * 16K = 128K
+ static std::string GetSnapshotCardName(void);
+
+private:
+ std::string GetSnapshotMemStructName(void);
+
+ UINT m_uSaturnTotalBanks; // Will be > 0 if Saturn card is installed
+ UINT m_uSaturnActiveBank; // Saturn 128K Language Card Bank 0 .. 7
+ LPBYTE m_aSaturnBanks[kMaxSaturnBanks];
+};
diff --git a/source/Memory.cpp b/source/Memory.cpp
index 4313cae6..a154114b 100644
--- a/source/Memory.cpp
+++ b/source/Memory.cpp
@@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Harddisk.h"
#include "Joystick.h"
#include "Keyboard.h"
+#include "LanguageCard.h"
#include "Log.h"
#include "Memory.h"
#include "Mockingboard.h"
@@ -180,8 +181,6 @@ iofunction IORead[256];
iofunction IOWrite[256];
static LPVOID SlotParameters[NUM_SLOTS];
-static BOOL g_bLastWriteRam = 0;
-
LPBYTE mem = NULL;
//
@@ -197,31 +196,153 @@ static LPBYTE memimage = NULL;
static LPBYTE pCxRomInternal = NULL;
static LPBYTE pCxRomPeripheral = NULL;
-static const DWORD kMemModeInitialState = MF_BANK2 | MF_WRITERAM; // !INTCXROM
-static DWORD memmode = kMemModeInitialState;
+static LPBYTE g_pMemMainLanguageCard = NULL;
+
+static DWORD memmode = LanguageCardUnit::kMemModeInitialState;
static BOOL modechanging = 0; // An Optimisation: means delay calling UpdatePaging() for 1 instruction
-static BOOL Pravets8charmode = 0;
static CNoSlotClock g_NoSlotClock;
+static LanguageCardUnit* g_pLanguageCard = NULL; // For all Apple II, //e and above
#ifdef RAMWORKS
-UINT g_uMaxExPages = 1; // user requested ram pages (default to 1 aux bank: so total = 128KB)
-UINT g_uActiveBank = 0; // 0 = aux 64K for: //e extended 80 Col card, or //c -- ALSO RAMWORKS
+static UINT g_uMaxExPages = 1; // user requested ram pages (default to 1 aux bank: so total = 128KB)
+static UINT g_uActiveBank = 0; // 0 = aux 64K for: //e extended 80 Col card, or //c -- ALSO RAMWORKS
static LPBYTE RWpages[kMaxExMemoryBanks]; // pointers to RW memory banks
#endif
-#ifdef SATURN
-UINT g_uSaturnTotalBanks = 0; // Will be > 0 if Saturn card is "installed"
-UINT g_uSaturnActiveBank = 0; // Saturn 128K Language Card Bank 0 .. 7
-static LPBYTE g_aSaturnPages[8];
-#endif // SATURN
-
-MemoryType_e g_eMemType = MEM_TYPE_NATIVE; // 0 = Native memory, 1=RAMWORKS, 2 = SATURN
-
BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles);
//=============================================================================
+static SS_CARDTYPE g_MemTypeAppleIIPlus = CT_LanguageCard; // Keep a copy so it's not lost if machine type changes, eg: A][ -> A//e -> A][
+static SS_CARDTYPE g_MemTypeAppleIIe = CT_Extended80Col; // Keep a copy so it's not lost if machine type changes, eg: A//e -> A][ -> A//e
+static UINT g_uSaturnBanksFromCmdLine = 0;
+
+// Called from MemLoadSnapshot()
+static void ResetDefaultMachineMemTypes(void)
+{
+ g_MemTypeAppleIIPlus = CT_LanguageCard;
+ g_MemTypeAppleIIe = CT_Extended80Col;
+}
+
+// Called from MemInitialize(), MemLoadSnapshot()
+void SetExpansionMemTypeDefault(void)
+{
+ SS_CARDTYPE defaultType = IsApple2PlusOrClone(GetApple2Type()) ? g_MemTypeAppleIIPlus : g_MemTypeAppleIIe;
+ SetExpansionMemType(defaultType);
+}
+
+// Called from SetExpansionMemTypeDefault(), MemLoadSnapshotAux(), SaveState.cpp_ParseSlots(), cmd-line switch
+void SetExpansionMemType(const SS_CARDTYPE type)
+{
+ SS_CARDTYPE newSlot0Card;
+ SS_CARDTYPE newSlotAuxCard;
+
+ // Set defaults:
+ if (IsApple2PlusOrClone(GetApple2Type()))
+ {
+ newSlot0Card = CT_LanguageCard;
+ newSlotAuxCard = CT_Empty;
+ }
+ else // Apple //e or above
+ {
+ newSlot0Card = CT_Empty; // NB. No slot0 for //e
+ newSlotAuxCard = CT_Extended80Col;
+ }
+
+ if (type == CT_Saturn128K)
+ {
+ g_MemTypeAppleIIPlus = type;
+ if (IsApple2PlusOrClone(GetApple2Type()))
+ newSlot0Card = CT_Saturn128K;
+ else
+ newSlot0Card = CT_Empty; // NB. No slot0 for //e
+ }
+ else if (type == CT_RamWorksIII)
+ {
+ g_MemTypeAppleIIe = type;
+ if (IsApple2PlusOrClone(GetApple2Type()))
+ newSlotAuxCard = CT_Empty; // NB. No aux slot for ][ or ][+
+ else
+ newSlotAuxCard = CT_RamWorksIII;
+ }
+
+ if (IsApple2PlusOrClone(GetApple2Type()))
+ {
+ delete g_pLanguageCard;
+ g_pLanguageCard = NULL;
+
+ if (newSlot0Card == CT_Saturn128K)
+ g_pLanguageCard = new Saturn128K(g_uSaturnBanksFromCmdLine);
+ else // newSlot0Card == CT_LanguageCard
+ g_pLanguageCard = new LanguageCardSlot0;
+ }
+ else
+ {
+ delete g_pLanguageCard;
+ g_pLanguageCard = new LanguageCardUnit;
+ }
+
+ _ASSERT(g_pMemMainLanguageCard);
+
+ g_Slot0 = newSlot0Card;
+ g_SlotAux = newSlotAuxCard;
+}
+
+SS_CARDTYPE GetCurrentExpansionMemType(void)
+{
+ if (IsApple2PlusOrClone(GetApple2Type()))
+ return g_Slot0;
+ else
+ return g_SlotAux;
+}
+
+//
+
+void SetRamWorksMemorySize(UINT pages)
+{
+ g_uMaxExPages = pages;
+}
+
+UINT GetRamWorksActiveBank(void)
+{
+ return g_uActiveBank;
+}
+
+void SetSaturnMemorySize(UINT banks)
+{
+ g_uSaturnBanksFromCmdLine = banks;
+}
+
+//
+
+static BOOL GetLastRamWrite(void)
+{
+ return g_pLanguageCard->GetLastRamWrite();
+}
+
+static void SetLastRamWrite(BOOL count)
+{
+ g_pLanguageCard->SetLastRamWrite(count);
+}
+
+//
+
+void SetMemMainLanguageCard(LPBYTE ptr, bool bMemMain /*=false*/)
+{
+ if (bMemMain)
+ g_pMemMainLanguageCard = memmain+0xC000;
+ else
+ g_pMemMainLanguageCard = ptr;
+}
+
+LanguageCardUnit* GetLanguageCard(void)
+{
+ return g_pLanguageCard;
+}
+
+//=============================================================================
+
static BYTE __stdcall IORead_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
{
return KeybReadData();
@@ -837,7 +958,7 @@ DWORD GetMemMode(void)
return memmode;
}
-static void SetMemMode(const DWORD uNewMemMode)
+void SetMemMode(DWORD uNewMemMode)
{
#if defined(_DEBUG) && 0
static DWORD dwOldDiff = 0;
@@ -881,8 +1002,8 @@ void MemResetPaging()
static void ResetPaging(BOOL initialize)
{
- g_bLastWriteRam = 0;
- SetMemMode(kMemModeInitialState);
+ SetLastRamWrite(0);
+ SetMemMode(LanguageCardUnit::kMemModeInitialState);
UpdatePaging(initialize);
}
@@ -949,24 +1070,24 @@ static void UpdatePaging(BOOL initialize)
{
int bankoffset = (SW_BANK2 ? 0 : 0x1000);
memshadow[loop] = SW_HIGHRAM ? SW_ALTZP ? memaux+(loop << 8)-bankoffset
- : memmain+(loop << 8)-bankoffset
- : memrom+((loop-0xD0) * 0x100);
+ : g_pMemMainLanguageCard+((loop-0xC0)<<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
+ : g_pMemMainLanguageCard+((loop-0xC0)<<8)-bankoffset
: NULL;
}
for (loop = 0xE0; loop < 0x100; loop++)
{
memshadow[loop] = SW_HIGHRAM ? SW_ALTZP ? memaux+(loop << 8)
- : memmain+(loop << 8)
+ : g_pMemMainLanguageCard+((loop-0xC0)<<8)
: memrom+((loop-0xD0) * 0x100);
memwrite[loop] = SW_WRITERAM ? SW_HIGHRAM ? mem+(loop << 8)
: SW_ALTZP ? memaux+(loop << 8)
- : memmain+(loop << 8)
+ : g_pMemMainLanguageCard+((loop-0xC0)<<8)
: NULL;
}
@@ -1043,6 +1164,9 @@ void MemDestroy()
RWpages[0]=NULL;
#endif
+ delete g_pLanguageCard;
+ g_pLanguageCard = NULL;
+
memaux = NULL;
memmain = NULL;
memdirty = NULL;
@@ -1054,6 +1178,8 @@ void MemDestroy()
mem = NULL;
+ g_pMemMainLanguageCard = NULL;
+
ZeroMemory(memwrite, sizeof(memwrite));
ZeroMemory(memshadow,sizeof(memshadow));
}
@@ -1285,20 +1411,27 @@ void MemInitialize()
// this happens when running under valgrind
memimage = (LPBYTE)newloc;
-#ifdef RAMWORKS
- // allocate memory for RAMWorks III - up to 8MB
- g_uActiveBank = 0;
- RWpages[g_uActiveBank] = memaux;
+ //
- UINT i = 1;
- while ((i < g_uMaxExPages) && (RWpages[i] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE)))
- i++;
+ RWpages[0] = memaux;
+
+ SetExpansionMemTypeDefault();
+
+#ifdef RAMWORKS
+ if (GetCurrentExpansionMemType() == CT_RamWorksIII)
+ {
+ // allocate memory for RAMWorks III - up to 8MB
+ g_uActiveBank = 0;
+
+ UINT i = 1;
+ while ((i < g_uMaxExPages) && (RWpages[i] = (LPBYTE) VirtualAlloc(NULL, _6502_MEM_END+1, MEM_COMMIT, PAGE_READWRITE)))
+ i++;
+ while (i < kMaxExMemoryBanks)
+ RWpages[i++] = NULL;
+ }
#endif
-#ifdef SATURN
- for( UINT iPage = 0; iPage < g_uSaturnTotalBanks; iPage++ )
- g_aSaturnPages[ iPage ] = (LPBYTE) VirtualAlloc( NULL, 1024 * 16,MEM_COMMIT,PAGE_READWRITE); // Saturn Pages are 16K / bank, Max 8 Banks/Card
-#endif // SATURN
+ //
MemInitializeROM();
MemInitializeCustomF8ROM();
@@ -1723,69 +1856,7 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
// DETERMINE THE NEW MEMORY PAGING MODE.
if ((address >= 0x80) && (address <= 0x8F))
{
- SetMemMode(memmode & ~(MF_BANK2 | MF_HIGHRAM));
-
-#ifdef SATURN
-/*
- Bin Addr.
- $C0N0 4K Bank A, RAM read, Write protect
- $C0N1 4K Bank A, ROM read, Write enabled
- $C0N2 4K Bank A, ROM read, Write protect
- $C0N3 4K Bank A, RAM read, Write enabled
- 0100 $C0N4 select 16K Bank 1
- 0101 $C0N5 select 16K Bank 2
- 0110 $C0N6 select 16K Bank 3
- 0111 $C0N7 select 16K Bank 4
- $C0N8 4K Bank B, RAM read, Write protect
- $C0N9 4K Bank B, ROM read, Write enabled
- $C0NA 4K Bank B, ROM read, Write protect
- $C0NB 4K Bank B, RAM read, Write enabled
- 1100 $C0NC select 16K Bank 5
- 1101 $C0ND select 16K Bank 6
- 1110 $C0NE select 16K Bank 7
- 1111 $C0NF select 16K Bank 8
-*/
- if (g_uSaturnTotalBanks)
- {
- if ((address & 7) > 3)
- {
- g_uSaturnActiveBank = 0 // Saturn 128K Language Card Bank 0 .. 7
- | (address >> 1) & 4
- | (address >> 0) & 3
- ;
-
- // TODO: Update paging()
-
- goto _done_saturn;
- }
-
- // Fall into 16K IO switches
- }
-
-#endif // SATURN
- {
- // Apple 16K Language Card
- if (!(address & 8))
- SetMemMode(memmode | MF_BANK2);
-
- // C081 C089 Read ROM, Write enable
- // C082 C08A Read ROM, Write protect
- if (((address & 2) >> 1) == (address & 1))
- SetMemMode(memmode | MF_HIGHRAM);
-
- if (address & 1) // GH#392
- {
- if (!write && g_bLastWriteRam)
- {
- SetMemMode(memmode | MF_WRITERAM); // UTAIIe:5-23
- }
- }
- else
- {
- SetMemMode(memmode & ~(MF_WRITERAM)); // UTAIIe:5-23
- }
- }
- g_bLastWriteRam = (address & 1) && (!write); // UTAIIe:5-23
+ SetMemMode( g_pLanguageCard->SetPaging(address, memmode, modechanging, write ? true : false) );
}
else if (!IS_APPLE2)
{
@@ -1814,33 +1885,32 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
{
g_uActiveBank = value;
memaux = RWpages[g_uActiveBank];
- UpdatePaging(0); // Initialize=0
+ UpdatePaging(FALSE); // Initialize=FALSE
}
break;
#endif
}
}
-#ifdef SATURN
-_done_saturn:
-#endif // SATURN
-
- // 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.
- //
- // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour.
- // - although any data-race is probably a bug in the 6502 code too.
- if ((address >= 4) && (address <= 5) &&
- ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) {
- modechanging = 1;
- return write ? 0 : MemReadFloatingBus(1, nExecutedCycles);
- }
- if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) &&
- (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) ||
- ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) {
- modechanging = 1;
- return write ? 0 : MemReadFloatingBus(1, nExecutedCycles);
+ if (GetCurrentExpansionMemType() != CT_Saturn128K) // TODO: Not sure this optimisation is valid for Saturn, so skip it for now
+ {
+ // 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.
+ //
+ // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour.
+ // - although any data-race is probably a bug in the 6502 code too.
+ if ((address >= 4) && (address <= 5) &&
+ ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) {
+ modechanging = 1;
+ return write ? 0 : MemReadFloatingBus(1, nExecutedCycles);
+ }
+ if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) &&
+ (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) ||
+ ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) {
+ modechanging = 1;
+ return write ? 0 : MemReadFloatingBus(1, nExecutedCycles);
+ }
}
// IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND
@@ -1903,7 +1973,7 @@ LPVOID MemGetSlotParameters(UINT uSlot)
void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux)
{
SetMemMode(MemMode ^ MF_INTCXROM); // Convert from SLOTCXROM to INTCXROM
- g_bLastWriteRam = LastWriteRam;
+ SetLastRamWrite(LastWriteRam);
memcpy(memmain, pMemMain, nMemMainSize);
memcpy(memaux, pMemAux, nMemAuxSize);
@@ -1918,8 +1988,6 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE*
//
-#define UNIT_AUXSLOT_VER 1
-
#define SS_YAML_KEY_MEMORYMODE "Memory Mode"
#define SS_YAML_KEY_LASTRAMWRITE "Last RAM Write"
#define SS_YAML_KEY_IOSELECT "IO_SELECT"
@@ -1927,6 +1995,10 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE*
#define SS_YAML_KEY_EXPANSIONROMTYPE "Expansion ROM Type"
#define SS_YAML_KEY_PERIPHERALROMSLOT "Peripheral ROM Slot"
+//
+
+static const UINT kUNIT_AUXSLOT_VER = 1;
+
#define SS_YAML_VALUE_CARD_80COL "80 Column"
#define SS_YAML_VALUE_CARD_EXTENDED80COL "Extended 80 Column"
#define SS_YAML_VALUE_CARD_RAMWORKSIII "RamWorksIII"
@@ -1958,19 +2030,19 @@ static std::string MemGetSnapshotAuxMemStructName(void)
return name;
}
-static void MemSaveSnapshotMemory(YamlSaveHelper& yamlSaveHelper, bool bIsMainMem, UINT bank=0)
+static void MemSaveSnapshotMemory(YamlSaveHelper& yamlSaveHelper, bool bIsMainMem, UINT bank=0, UINT size=64*1024)
{
LPBYTE pMemBase = MemGetBankPtr(bank);
if (bIsMainMem)
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotMainMemStructName().c_str());
- yamlSaveHelper.SaveMemory(pMemBase, 64*1024);
+ yamlSaveHelper.SaveMemory(pMemBase, size);
}
else
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s%02X:\n", MemGetSnapshotAuxMemStructName().c_str(), bank-1);
- yamlSaveHelper.SaveMemory(pMemBase, 64*1024);
+ yamlSaveHelper.SaveMemory(pMemBase, size);
}
}
@@ -1979,29 +2051,56 @@ void MemSaveSnapshot(YamlSaveHelper& yamlSaveHelper)
// Scope so that "Memory" & "Main Memory" are at same indent level
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotStructName().c_str());
- yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, memmode ^ MF_INTCXROM); // Convert from INTCXROM to SLOTCXROM
- yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, g_bLastWriteRam ? 1 : 0);
+ DWORD saveMemMode = 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);
+ if (!IsApple2PlusOrClone(GetApple2Type())) // NB. This is set later for II,II+ by slot-0 LC or Saturn
+ yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, GetLastRamWrite() ? 1 : 0);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IOSELECT, IO_SELECT);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IOSELECT_INT, INTC8ROM ? 1 : 0);
yamlSaveHelper.SaveUint(SS_YAML_KEY_EXPANSIONROMTYPE, (UINT) g_eExpansionRomType);
yamlSaveHelper.SaveUint(SS_YAML_KEY_PERIPHERALROMSLOT, g_uPeripheralRomSlot);
}
- MemSaveSnapshotMemory(yamlSaveHelper, true);
+ if (IsApple2PlusOrClone(GetApple2Type()))
+ MemSaveSnapshotMemory(yamlSaveHelper, true, 0, 48*1024); // NB. Language Card/Saturn provides the remaining 16K (or multiple) bank(s)
+ else
+ MemSaveSnapshotMemory(yamlSaveHelper, true);
}
-bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper)
+bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
{
if (!yamlLoadHelper.GetSubMap(MemGetSnapshotStructName()))
return false;
- SetMemMode( yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) ^ MF_INTCXROM ); // Convert from SLOTCXROM to INTCXROM
- g_bLastWriteRam = yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE;
+ // Create default LC type for AppleII machine (do prior to loading saved LC state)
+ ResetDefaultMachineMemTypes();
+ SetExpansionMemTypeDefault();
+
+ //
+
IO_SELECT = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_IOSELECT);
INTC8ROM = yamlLoadHelper.LoadUint(SS_YAML_KEY_IOSELECT_INT) ? true : false;
g_eExpansionRomType = (eExpansionRomType) yamlLoadHelper.LoadUint(SS_YAML_KEY_EXPANSIONROMTYPE);
g_uPeripheralRomSlot = yamlLoadHelper.LoadUint(SS_YAML_KEY_PERIPHERALROMSLOT);
+ if (version == 1)
+ {
+ SetMemMode( yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) ^ MF_INTCXROM ); // Convert from SLOTCXROM to INTCXROM
+ SetLastRamWrite( yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE );
+ }
+ else
+ {
+ UINT uMemMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE);
+ if (IsApple2PlusOrClone(GetApple2Type()))
+ uMemMode &= ~MF_LANGCARD_MASK; // For II,II+: clear LC bits - set later by slot-0 LC or Saturn
+ SetMemMode(uMemMode);
+
+ if (!IsApple2PlusOrClone(GetApple2Type()))
+ SetLastRamWrite( yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE ); // NB. This is set later for II,II+ by slot-0 LC or Saturn
+ }
+
yamlLoadHelper.PopMap();
//
@@ -2009,7 +2108,9 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper)
if (!yamlLoadHelper.GetSubMap( MemGetSnapshotMainMemStructName() ))
throw std::string("Card: Expected key: ") + MemGetSnapshotMainMemStructName();
+ memset(memmain, 0, _6502_MEM_END+1); // Clear it, as high 16K may not be in the save-state (eg. the case of Saturn replacing LC)
yamlLoadHelper.LoadMemory(memmain, _6502_MEM_END+1);
+ memcpy(g_pMemMainLanguageCard, memmain+0xC000, LanguageCardSlot0::kMemBankSize);
memset(memdirty, 0, 0x100);
yamlLoadHelper.PopMap();
@@ -2024,6 +2125,7 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper)
return true;
}
+// TODO: Switch from checking 'g_uMaxExPages == n' to using g_SlotAux
void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper)
{
if (IS_APPLE2)
@@ -2036,7 +2138,7 @@ void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper)
_ASSERT(g_uMaxExPages == 1);
}
- yamlSaveHelper.UnitHdr(MemGetSnapshotUnitAuxSlotName(), UNIT_AUXSLOT_VER);
+ yamlSaveHelper.UnitHdr(MemGetSnapshotUnitAuxSlotName(), kUNIT_AUXSLOT_VER);
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
std::string card = g_uMaxExPages == 0 ? SS_YAML_VALUE_CARD_80COL : // todo: support empty slot
@@ -2054,32 +2156,37 @@ void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper)
bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version)
{
- if (version != UNIT_AUXSLOT_VER)
+ if (version != kUNIT_AUXSLOT_VER)
throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Version mismatch");
// "State"
UINT numAuxBanks = yamlLoadHelper.LoadUint(SS_YAML_KEY_NUMAUXBANKS);
UINT activeAuxBank = yamlLoadHelper.LoadUint(SS_YAML_KEY_ACTIVEAUXBANK);
+ SS_CARDTYPE type = CT_Empty;
std::string card = yamlLoadHelper.LoadString(SS_YAML_KEY_CARD);
if (card == SS_YAML_VALUE_CARD_80COL)
{
+ type = CT_80Col;
if (numAuxBanks != 0 || activeAuxBank != 0)
throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state");
}
else if (card == SS_YAML_VALUE_CARD_EXTENDED80COL)
{
+ type = CT_Extended80Col;
if (numAuxBanks != 1 || activeAuxBank != 0)
throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state");
}
else if (card == SS_YAML_VALUE_CARD_RAMWORKSIII)
{
+ type = CT_RamWorksIII;
if (numAuxBanks < 2 || numAuxBanks > 0x7F || (activeAuxBank+1) > numAuxBanks)
throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state");
}
else
{
// todo: support empty slot
+ type = CT_Empty;
throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Unknown card: " + card);
}
@@ -2093,7 +2200,7 @@ bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version)
LPBYTE pBank = MemGetBankPtr(uBank);
if (!pBank)
{
- pBank = RWpages[uBank-1] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE);
+ pBank = RWpages[uBank-1] = (LPBYTE) VirtualAlloc(NULL, _6502_MEM_END+1, MEM_COMMIT, PAGE_READWRITE);
if (!pBank)
throw std::string("Card: mem alloc failed");
}
@@ -2111,6 +2218,9 @@ bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version)
yamlLoadHelper.PopMap();
}
+ g_Slot0 = CT_Empty;
+ g_SlotAux = type;
+
memaux = RWpages[g_uActiveBank];
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2()
diff --git a/source/Memory.h b/source/Memory.h
index 191a5b26..ff81ddab 100644
--- a/source/Memory.h
+++ b/source/Memory.h
@@ -13,6 +13,8 @@
#define MF_INTCXROM 0x00000200
#define MF_WRITERAM 0x00000400 // Language Card RAM is Write Enabled
#define MF_IMAGEMASK 0x000003F7
+#define MF_LANGCARD_MASK (MF_WRITERAM|MF_HIGHRAM|MF_BANK2)
+
enum
{
@@ -39,18 +41,8 @@ enum MemoryInitPattern_e
, NUM_MIP
};
-enum MemoryType_e
-{
- MEM_TYPE_NATIVE = 0,
- MEM_TYPE_RAMWORKS = 1,
- MEM_TYPE_SATURN = 2,
- NUM_MEM_TYPE = 3
-};
-
typedef BYTE (__stdcall *iofunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE nWriteValue, ULONG nExecutedCycles);
-extern MemoryType_e g_eMemType;
-
extern iofunction IORead[256];
extern iofunction IOWrite[256];
extern LPBYTE memwrite[0x100];
@@ -63,11 +55,6 @@ extern UINT g_uMaxExPages; // user requested ram pages (from cmd line)
extern UINT g_uActiveBank;
#endif
-#ifdef SATURN
-extern UINT g_uSaturnTotalBanks;
-extern UINT g_uSaturnActiveBank; // Saturn 128K Language Card Bank 0 .. 7
-#endif // SATURN
-
void RegisterIoHandler(UINT uSlot, iofunction IOReadC0, iofunction IOWriteC0, iofunction IOReadCx, iofunction IOWriteCx, LPVOID lpSlotParameter, BYTE* pExpansionRom);
void MemDestroy ();
@@ -78,6 +65,7 @@ LPBYTE MemGetMainPtr(const WORD);
LPBYTE MemGetBankPtr(const UINT nBank);
LPBYTE MemGetCxRomPeripheral();
DWORD GetMemMode(void);
+void SetMemMode(DWORD memmode);
bool MemIsAddrCodeMemory(const USHORT addr);
void MemInitialize ();
void MemInitializeROM(void);
@@ -93,10 +81,20 @@ LPVOID MemGetSlotParameters (UINT uSlot);
void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux);
std::string MemGetSnapshotUnitAuxSlotName(void);
void MemSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
-bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper);
+bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version);
void MemSaveSnapshotAux(class YamlSaveHelper& yamlSaveHelper);
bool MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT version);
BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles);
BYTE __stdcall MemSetPaging(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
+
+enum SS_CARDTYPE;
+void SetExpansionMemType(const SS_CARDTYPE type);
+SS_CARDTYPE GetCurrentExpansionMemType(void);
+
+void SetRamWorksMemorySize(UINT pages);
+UINT GetRamWorksActiveBank(void);
+void SetSaturnMemorySize(UINT banks);
+void SetMemMainLanguageCard(LPBYTE ptr, bool bMemMain=false);
+class LanguageCardUnit* GetLanguageCard(void);
diff --git a/source/SaveState.cpp b/source/SaveState.cpp
index 4870e9d6..c248b81b 100644
--- a/source/SaveState.cpp
+++ b/source/SaveState.cpp
@@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Frame.h"
#include "Joystick.h"
#include "Keyboard.h"
+#include "LanguageCard.h"
#include "Memory.h"
#include "Mockingboard.h"
#include "MouseInterface.h"
@@ -64,7 +65,7 @@ static YamlHelper yamlHelper;
#define SS_FILE_VER 2
-#define UNIT_APPLE2_VER 1
+#define UNIT_APPLE2_VER 2
#define UNIT_SLOTS_VER 1
//-----------------------------------------------------------------------------
@@ -323,7 +324,7 @@ static UINT ParseFileHdr(void)
static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version)
{
- if (version != UNIT_APPLE2_VER)
+ if (version == 0 || version > UNIT_APPLE2_VER)
throw std::string(SS_YAML_KEY_UNIT ": Apple2: Version mismatch");
std::string model = yamlLoadHelper.LoadString(SS_YAML_KEY_MODEL);
@@ -337,7 +338,7 @@ static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version)
KeybLoadSnapshot(yamlLoadHelper);
SpkrLoadSnapshot(yamlLoadHelper);
VideoLoadSnapshot(yamlLoadHelper);
- MemLoadSnapshot(yamlLoadHelper);
+ MemLoadSnapshot(yamlLoadHelper, version);
// g_Apple2Type may've changed: so redraw frame (title, buttons, leds, etc)
VideoReinitialize(); // g_CharsetType changed
@@ -358,7 +359,8 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version)
break; // done all slots
const int slot = strtoul(scalar.c_str(), NULL, 10); // NB. aux slot supported as a different "unit"
- if (slot < 1 || slot > 7)
+ // NB. slot-0 only supported for Apple II or II+ (or similar clones)
+ if (slot < 0 || slot > 7)
throw std::string("Slots: Invalid slot #: ") + scalar;
yamlLoadHelper.GetSubMap(scalar);
@@ -414,6 +416,18 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version)
m_ConfigNew.m_bEnableHDD = true;
type = CT_GenericHDD;
}
+ else if (card == LanguageCardSlot0::GetSnapshotCardName())
+ {
+ type = CT_LanguageCard;
+ SetExpansionMemType(type);
+ bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, version);
+ }
+ else if (card == Saturn128K::GetSnapshotCardName())
+ {
+ type = CT_Saturn128K;
+ SetExpansionMemType(type);
+ bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, version);
+ }
else
{
bIsCardSupported = false;
@@ -477,6 +491,7 @@ static void Snapshot_LoadState_v2(void)
//
CConfigNeedingRestart ConfigOld;
+ //ConfigOld.m_Slot[0] = CT_LanguageCard; // fixme: II/II+=LC, //e=empty
ConfigOld.m_Slot[1] = CT_GenericPrinter; // fixme
ConfigOld.m_Slot[2] = CT_SSC; // fixme
//ConfigOld.m_Slot[3] = CT_Uthernet; // todo
@@ -489,7 +504,6 @@ static void Snapshot_LoadState_v2(void)
m_ConfigNew.m_SlotAux = CT_Empty;
m_ConfigNew.m_bEnableHDD = false;
//m_ConfigNew.m_bEnableTheFreezesF8Rom = ?; // todo: when support saving config
- //m_ConfigNew.m_bEnhanceDisk = ?; // todo: when support saving config
MemReset();
PravetsReset();
@@ -591,6 +605,9 @@ void Snapshot_SaveState(void)
yamlSaveHelper.UnitHdr(GetSnapshotUnitSlotsName(), UNIT_SLOTS_VER);
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
+ if (IsApple2PlusOrClone(GetApple2Type()))
+ GetLanguageCard()->SaveSnapshot(yamlSaveHelper); // Language Card or Saturn 128K
+
Printer_SaveSnapshot(yamlSaveHelper);
sg_SSC.SaveSnapshot(yamlSaveHelper);
diff --git a/source/SaveState_Structs_common.h b/source/SaveState_Structs_common.h
index 2ba29f81..8a44ce8f 100644
--- a/source/SaveState_Structs_common.h
+++ b/source/SaveState_Structs_common.h
@@ -46,9 +46,6 @@ enum SS_UNIT_TYPE
const UINT nMemMainSize = 64*1024;
const UINT nMemAuxSize = 64*1024;
-const UINT kSLOT_LANG = 0;
-const UINT kSLOT_AUX = 8;
-
struct SS_CARD_HDR
{
SS_UNIT_HDR UnitHdr;
@@ -70,10 +67,13 @@ enum SS_CARDTYPE
CT_Phasor, // Soundcard
CT_Echo, // Soundcard
CT_SAM, // Soundcard: Software Automated Mouth
- CT_80Col, // 80 column card (no memory)
+ CT_80Col, // 80 column card (1K)
CT_Extended80Col, // Extended 80-col card (64K)
CT_RamWorksIII, // RamWorksIII (up to 8MB)
CT_Uthernet,
+ CT_LanguageCard, // Apple][ or ][+ in slot-0
+ CT_LanguageCardIIe, // Apple//e LC instance (not a card)
+ CT_Saturn128K, // Saturn 128K (but may be populated with less RAM, in multiples of 16K)
};
/////////////////////////////////////////////////////////////////////////////////