Apple II: Language Card and Saturn support for slot-0 (PR #589)

Support for #408:
* added slot-0 LC and Saturn 128K for Apple II and II+
* added save-state support
  - for slot-0 LC/Saturn, save the LC state in the slot-0 card, not the //e MMU; and switch to a new Apple2 unit ver2
* added g_Slot0, g_SlotAux
* added new LanguageCard.cpp/h to project and moved Saturn code into these new files.
* updated VS2013,2015,2017 projects
This commit is contained in:
TomCh 2018-10-26 11:23:30 -07:00 committed by GitHub
parent 91a6227da1
commit 46274d4d1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 824 additions and 187 deletions

View File

@ -625,6 +625,14 @@
RelativePath=".\source\Keyboard.h"
>
</File>
<File
RelativePath=".\source\LanguageCard.cpp"
>
</File>
<File
RelativePath=".\source\LanguageCard.h"
>
</File>
<File
RelativePath=".\source\Log.cpp"
>

View File

@ -71,6 +71,7 @@
<ClInclude Include="source\Harddisk.h" />
<ClInclude Include="source\Joystick.h" />
<ClInclude Include="source\Keyboard.h" />
<ClInclude Include="source\LanguageCard.h" />
<ClInclude Include="source\Log.h" />
<ClInclude Include="source\Memory.h" />
<ClInclude Include="source\Mockingboard.h" />
@ -154,6 +155,7 @@
<ClCompile Include="source\Harddisk.cpp" />
<ClCompile Include="source\Joystick.cpp" />
<ClCompile Include="source\Keyboard.cpp" />
<ClCompile Include="source\LanguageCard.cpp" />
<ClCompile Include="source\Log.cpp" />
<ClCompile Include="source\Memory.cpp" />
<ClCompile Include="source\Mockingboard.cpp" />

View File

@ -76,6 +76,9 @@
<ClCompile Include="source\Keyboard.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="source\LanguageCard.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="source\Log.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
@ -312,6 +315,9 @@
<ClInclude Include="source\Keyboard.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\LanguageCard.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\Log.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>

View File

@ -71,6 +71,7 @@
<ClInclude Include="source\Harddisk.h" />
<ClInclude Include="source\Joystick.h" />
<ClInclude Include="source\Keyboard.h" />
<ClInclude Include="source\LanguageCard.h" />
<ClInclude Include="source\Log.h" />
<ClInclude Include="source\Memory.h" />
<ClInclude Include="source\Mockingboard.h" />
@ -154,6 +155,7 @@
<ClCompile Include="source\Harddisk.cpp" />
<ClCompile Include="source\Joystick.cpp" />
<ClCompile Include="source\Keyboard.cpp" />
<ClCompile Include="source\LanguageCard.cpp" />
<ClCompile Include="source\Log.cpp" />
<ClCompile Include="source\Memory.cpp" />
<ClCompile Include="source\Mockingboard.cpp" />

View File

@ -76,6 +76,9 @@
<ClCompile Include="source\Keyboard.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="source\LanguageCard.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="source\Log.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
@ -312,6 +315,9 @@
<ClInclude Include="source\Keyboard.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\LanguageCard.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\Log.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>

View File

@ -71,6 +71,7 @@
<ClInclude Include="source\Harddisk.h" />
<ClInclude Include="source\Joystick.h" />
<ClInclude Include="source\Keyboard.h" />
<ClInclude Include="source\LanguageCard.h" />
<ClInclude Include="source\Log.h" />
<ClInclude Include="source\Memory.h" />
<ClInclude Include="source\Mockingboard.h" />
@ -154,6 +155,7 @@
<ClCompile Include="source\Harddisk.cpp" />
<ClCompile Include="source\Joystick.cpp" />
<ClCompile Include="source\Keyboard.cpp" />
<ClCompile Include="source\LanguageCard.cpp" />
<ClCompile Include="source\Log.cpp" />
<ClCompile Include="source\Memory.cpp" />
<ClCompile Include="source\Mockingboard.cpp" />

View File

@ -76,6 +76,9 @@
<ClCompile Include="source\Keyboard.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="source\LanguageCard.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="source\Log.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
@ -312,6 +315,9 @@
<ClInclude Include="source\Keyboard.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\LanguageCard.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\Log.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>

View File

@ -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");

View File

@ -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

View File

@ -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)
{

View File

@ -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);

View File

@ -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)
{

376
source/LanguageCard.cpp Normal file
View File

@ -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<kMaxSaturnBanks; i++)
m_aSaturnBanks[i] = NULL;
for (UINT i = 0; i < m_uSaturnTotalBanks; i++)
m_aSaturnBanks[i] = (LPBYTE) VirtualAlloc(NULL, kMemBankSize, MEM_COMMIT, PAGE_READWRITE); // Saturn banks are 16K, max 8 banks/card
SetMemMainLanguageCard( m_aSaturnBanks[ m_uSaturnActiveBank ] );
}
Saturn128K::~Saturn128K(void)
{
for (UINT i = 0; i < m_uSaturnTotalBanks; i++)
{
if (m_aSaturnBanks[i])
{
VirtualFree(m_aSaturnBanks[i], 0, MEM_RELEASE);
m_aSaturnBanks[i] = NULL;
}
}
}
void Saturn128K::SetMemorySize(UINT banks)
{
m_uSaturnTotalBanks = banks;
}
UINT Saturn128K::GetActiveBank(void)
{
return m_uSaturnActiveBank;
}
DWORD Saturn128K::SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool /*write*/)
{
/*
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
*/
_ASSERT(m_uSaturnTotalBanks);
if (!m_uSaturnTotalBanks)
return memmode;
if (address & (1<<2))
{
m_uSaturnActiveBank = 0 // Saturn 128K Language Card Bank 0 .. 7
| (address >> 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;
}

83
source/LanguageCard.h Normal file
View File

@ -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];
};

View File

@ -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()

View File

@ -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);

View File

@ -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);

View File

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