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) }; /////////////////////////////////////////////////////////////////////////////////