Refactor Language Card (#593)

* Refactor Language Card:
. MemSetPaging() now not used for $C080-C08F accesses.
  - Instead LC registers its own I/O handler like all other slot 1-7 cards.
. Saturn uses base LC's 16K for bank0

* Move all 'modechanging = 0' to UpdatePaging()
This commit is contained in:
TomCh 2018-11-09 20:51:51 +00:00 committed by GitHub
parent f9b7d9326e
commit 42c58f54e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 70 deletions

View File

@ -49,19 +49,28 @@ LanguageCardUnit::~LanguageCardUnit(void)
SetMemMainLanguageCard(NULL);
}
DWORD LanguageCardUnit::SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write)
void LanguageCardUnit::InitializeIO(void)
{
RegisterIoHandler(kSlot0, &LanguageCardUnit::IO, &LanguageCardUnit::IO, NULL, NULL, this, NULL);
}
BYTE __stdcall LanguageCardUnit::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles)
{
LanguageCardUnit* pLC = (LanguageCardUnit*) MemGetSlotParameters(kSlot0);
DWORD memmode = GetMemMode();
DWORD lastmemmode = memmode;
memmode &= ~(MF_BANK2 | MF_HIGHRAM);
if (!(address & 8))
if (!(uAddr & 8))
memmode |= MF_BANK2;
if (((address & 2) >> 1) == (address & 1))
if (((uAddr & 2) >> 1) == (uAddr & 1))
memmode |= MF_HIGHRAM;
if (address & 1) // GH#392
if (uAddr & 1) // GH#392
{
if (!write && GetLastRamWrite())
if (!bWrite && pLC->GetLastRamWrite())
{
memmode |= MF_WRITERAM; // UTAIIe:5-23
}
@ -71,9 +80,36 @@ DWORD LanguageCardUnit::SetPaging(WORD address, DWORD memmode, BOOL& modechangin
memmode &= ~MF_WRITERAM; // UTAIIe:5-23
}
SetLastRamWrite( ((address & 1) && !write) ); // UTAIIe:5-23
pLC->SetLastRamWrite( ((uAddr & 1) && !bWrite) ); // UTAIIe:5-23
SetMemMode(memmode);
return memmode;
//
if (IS_APPLE2E)
{
// IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS
// ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL
// IT DOES SO.
//
// 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 ((PC < 0xC000) &&
(((*(LPDWORD)(mem+PC) & 0x00FFFEFF) == 0x00C0048D) || // Next: STA $C004 or STA $C005
((*(LPDWORD)(mem+PC) & 0x00FFFEFF) == 0x00C0028D))) // Next: STA $C002 or STA $C003
{
SetModeChanging(1);
return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles);
}
}
// IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND
// WRITE TABLES.
if (lastmemmode != memmode)
{
MemUpdatePaging(0); // Initialize=0
}
return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles);
}
//-------------------------------------
@ -94,7 +130,7 @@ LanguageCardSlot0::~LanguageCardSlot0(void)
//
static const UINT kUNIT_LANGUAGECARD_VER = 1;
static const UINT kSLOT_LANGUAGECARD = 0;
static const UINT kSLOT_LANGUAGECARD = LanguageCardUnit::kSlot0;
#define SS_YAML_VALUE_CARD_LANGUAGECARD "Language Card"
@ -188,7 +224,9 @@ Saturn128K::Saturn128K(UINT banks)
for (UINT i=0; i<kMaxSaturnBanks; i++)
m_aSaturnBanks[i] = NULL;
for (UINT i = 0; i < m_uSaturnTotalBanks; i++)
m_aSaturnBanks[0] = m_pMemory; // Reuse memory allocated in base ctor
for (UINT i = 1; 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 ] );
@ -196,7 +234,9 @@ Saturn128K::Saturn128K(UINT banks)
Saturn128K::~Saturn128K(void)
{
for (UINT i = 0; i < m_uSaturnTotalBanks; i++)
m_aSaturnBanks[0] = NULL; // just zero this - deallocated in base ctor
for (UINT i = 1; i < m_uSaturnTotalBanks; i++)
{
if (m_aSaturnBanks[i])
{
@ -216,7 +256,12 @@ UINT Saturn128K::GetActiveBank(void)
return m_uSaturnActiveBank;
}
DWORD Saturn128K::SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool /*write*/)
void Saturn128K::InitializeIO(void)
{
RegisterIoHandler(kSlot0, &Saturn128K::IO, &Saturn128K::IO, NULL, NULL, this, NULL);
}
BYTE __stdcall Saturn128K::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles)
{
/*
Bin Addr.
@ -237,54 +282,70 @@ DWORD Saturn128K::SetPaging(WORD address, DWORD memmode, BOOL& modechanging, boo
1110 $C0NE select 16K Bank 7
1111 $C0NF select 16K Bank 8
*/
_ASSERT(m_uSaturnTotalBanks);
if (!m_uSaturnTotalBanks)
return memmode;
Saturn128K* pLC = (Saturn128K*) MemGetSlotParameters(kSlot0);
if (address & (1<<2))
_ASSERT(pLC->m_uSaturnTotalBanks);
if (!pLC->m_uSaturnTotalBanks)
return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles);
bool bBankChanged = false;
DWORD memmode=0, lastmemmode=0;
if (uAddr & (1<<2))
{
m_uSaturnActiveBank = 0 // Saturn 128K Language Card Bank 0 .. 7
| (address >> 1) & 4
| (address >> 0) & 3;
pLC->m_uSaturnActiveBank = 0 // Saturn 128K Language Card Bank 0 .. 7
| (uAddr >> 1) & 4
| (uAddr >> 0) & 3;
if (m_uSaturnActiveBank >= m_uSaturnTotalBanks)
if (pLC->m_uSaturnActiveBank >= pLC->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!
pLC->m_uSaturnActiveBank = pLC->m_uSaturnTotalBanks-1; // FIXME: just prevent crash for now!
}
SetMemMainLanguageCard( m_aSaturnBanks[ m_uSaturnActiveBank ] );
modechanging = 1;
SetMemMainLanguageCard( pLC->m_aSaturnBanks[ pLC->m_uSaturnActiveBank ] );
bBankChanged = true;
}
else
{
memmode = GetMemMode();
lastmemmode = memmode;
memmode &= ~(MF_BANK2 | MF_HIGHRAM);
if (!(address & 8))
if (!(uAddr & 8))
memmode |= MF_BANK2;
if (((address & 2) >> 1) == (address & 1))
if (((uAddr & 2) >> 1) == (uAddr & 1))
memmode |= MF_HIGHRAM;
if (address & 1 && GetLastRamWrite()) // Saturn differs from Apple's 16K LC: any access (LC is read-only)
if (uAddr & 1 && pLC->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)
pLC->SetLastRamWrite(uAddr & 1); // Saturn differs from Apple's 16K LC: any access (LC is read-only)
SetMemMode(memmode);
}
return memmode;
// NB. Unlike LC, no need to check if next opcode is STA $C002-5, as Saturn is not for //e
// IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND
// WRITE TABLES.
if ((lastmemmode != memmode) || bBankChanged)
{
MemUpdatePaging(0); // Initialize=0
}
return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles);
}
//
static const UINT kUNIT_SATURN_VER = 1;
static const UINT kSLOT_SATURN = 0;
static const UINT kSLOT_SATURN = LanguageCardUnit::kSlot0;
#define SS_YAML_VALUE_CARD_SATURN128 "Saturn 128"

View File

@ -10,7 +10,7 @@ public:
LanguageCardUnit(void);
virtual ~LanguageCardUnit(void);
virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write);
virtual void InitializeIO(void);
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
@ -20,7 +20,10 @@ public:
void SetLastRamWrite(BOOL count) { m_uLastRamWrite = count; }
SS_CARDTYPE GetMemoryType(void) { return m_type; }
static BYTE __stdcall IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles);
static const UINT kMemModeInitialState;
static const UINT kSlot0 = 0;
protected:
SS_CARDTYPE m_type;
@ -49,10 +52,10 @@ protected:
void SaveLCState(class YamlSaveHelper& yamlSaveHelper);
void LoadLCState(class YamlLoadHelper& yamlLoadHelper);
LPBYTE m_pMemory;
private:
std::string GetSnapshotMemStructName(void);
LPBYTE m_pMemory;
};
//
@ -65,12 +68,14 @@ public:
Saturn128K(UINT banks);
virtual ~Saturn128K(void);
virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write);
virtual void InitializeIO(void);
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 BYTE __stdcall IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles);
// "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)
static const UINT kMaxSaturnBanks = 8; // 8 * 16K = 128K
static std::string GetSnapshotCardName(void);

View File

@ -229,7 +229,7 @@ static void ResetDefaultMachineMemTypes(void)
g_MemTypeAppleIIe = CT_Extended80Col;
}
// Called from MemInitialize(), MemLoadSnapshot()
// Called from MemInitialize(), MemLoadSnapshot(), MemSetSnapshot_v1()
static void SetExpansionMemTypeDefault(void)
{
SS_CARDTYPE defaultType = IsApple2Original(GetApple2Type()) ? g_MemTypeAppleII
@ -280,25 +280,28 @@ void SetExpansionMemType(const SS_CARDTYPE type)
newSlotAuxCard = type;
}
g_Slot0 = newSlot0Card;
g_SlotAux = newSlotAuxCard;
}
void CreateLanguageCard(void)
{
delete g_pLanguageCard;
g_pLanguageCard = NULL;
if (IsApple2PlusOrClone(GetApple2Type()))
{
delete g_pLanguageCard;
if (newSlot0Card == CT_Saturn128K)
if (g_Slot0 == CT_Saturn128K)
g_pLanguageCard = new Saturn128K(g_uSaturnBanksFromCmdLine);
else if (newSlot0Card == CT_LanguageCard)
else if (g_Slot0 == CT_LanguageCard)
g_pLanguageCard = new LanguageCardSlot0;
else
g_pLanguageCard = NULL;
}
else
{
delete g_pLanguageCard;
g_pLanguageCard = new LanguageCardUnit;
}
g_Slot0 = newSlot0Card;
g_SlotAux = newSlotAuxCard;
}
SS_CARDTYPE GetCurrentExpansionMemType(void)
@ -969,6 +972,11 @@ static bool IsCardInSlot(const UINT uSlot)
//===========================================================================
void SetModeChanging(BOOL value)
{
modechanging = value;
}
DWORD GetMemMode(void)
{
return memmode;
@ -1037,6 +1045,8 @@ void MemUpdatePaging(BOOL initialize)
static void UpdatePaging(BOOL initialize)
{
modechanging = 0;
// SAVE THE CURRENT PAGING SHADOW TABLE
LPBYTE oldshadow[256];
if (!initialize)
@ -1437,7 +1447,7 @@ void MemInitialize()
SetExpansionMemTypeDefault();
#ifdef RAMWORKS
if (GetCurrentExpansionMemType() == CT_RamWorksIII)
if (g_SlotAux == CT_RamWorksIII)
{
// allocate memory for RAMWorks III - up to 8MB
g_uActiveBank = 0;
@ -1452,6 +1462,8 @@ void MemInitialize()
//
CreateLanguageCard();
MemInitializeROM();
MemInitializeCustomF8ROM();
MemInitializeIO();
@ -1580,9 +1592,10 @@ void MemInitializeCustomF8ROM(void)
{
memcpy(memrom, OldRom, Apple2RomSize); // ROM at $D000...$FFFF
bRes = FALSE;
// NB. Keep g_hCustomRomF8 handle open - so that any next restart can load it again
}
// NB. If succeeded, then keep g_hCustomRomF8 handle open - so that any next restart can load it again
if (!bRes)
{
MessageBox( g_hFrameWindow, "Failed to read custom F8 rom", TEXT("AppleWin Error"), MB_OK );
@ -1616,8 +1629,10 @@ void MemInitializeIO(void)
{
InitIoHandlers();
const UINT uSlot = 0;
RegisterIoHandler(uSlot, MemSetPaging, MemSetPaging, NULL, NULL, NULL, NULL);
if (g_pLanguageCard)
g_pLanguageCard->InitializeIO();
else
RegisterIoHandler(LanguageCardUnit::kSlot0, IO_Null, IO_Null, NULL, NULL, NULL, NULL);
// TODO: Cleanup peripheral setup!!!
PrintLoadRom(pCxRomPeripheral, 1); // $C100 : Parallel printer f/w
@ -1904,12 +1919,7 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
#endif
// DETERMINE THE NEW MEMORY PAGING MODE.
if (address >= 0x80 && address <= 0x8F)
{
if (!IS_APPLE2 || (IsApple2PlusOrClone(GetApple2Type()) && g_Slot0 != CT_Empty))
SetMemMode( g_pLanguageCard->SetPaging(address, memmode, modechanging, write ? true : false) );
}
else if (!IS_APPLE2)
if (!IS_APPLE2)
{
switch (address)
{
@ -1943,24 +1953,19 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
}
}
if (GetCurrentExpansionMemType() != CT_Saturn128K) // TODO: Not sure this optimisation is valid for Saturn, so skip it for now
if (IS_APPLE2E)
{
// IF THE EMULATED PROGRAM HAS JUST UPDATE THE MEMORY WRITE MODE AND IS
// IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS
// ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL
// 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)) {
((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) // Next: STA $C002 or STA $C003
{
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);
return 0; // For $C004 & $C005: entry to this func is always via a write to $C004 or $C005
}
}
@ -1968,8 +1973,6 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE
// WRITE TABLES.
if ((lastmemmode != memmode) || modechanging)
{
modechanging = 0;
// NB. Must check MF_SLOTC3ROM too, as IoHandlerCardsIn() depends on both MF_INTCXROM|MF_SLOTC3ROM
if ((lastmemmode & (MF_INTCXROM|MF_SLOTC3ROM)) != (memmode & (MF_INTCXROM|MF_SLOTC3ROM)))
{
@ -2027,6 +2030,7 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE*
ResetDefaultMachineMemTypes();
g_MemTypeAppleII = CT_LanguageCard; // SSv1 doesn't save machine type - so if current machine is Apple II then give it 64K + LC
SetExpansionMemTypeDefault();
CreateLanguageCard(); // Create LC here, as for SSv1 there is no slot-0 state
SetMemMode(MemMode ^ MF_INTCXROM); // Convert from SLOTCXROM to INTCXROM
SetLastRamWrite(LastWriteRam);
@ -2037,7 +2041,6 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE*
//
modechanging = 0;
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v1()
UpdatePaging(1); // Initialize=1
}
@ -2133,8 +2136,12 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
// Create default LC type for AppleII machine (do prior to loading saved LC state)
ResetDefaultMachineMemTypes();
if (version == 1)
g_MemTypeAppleII = CT_LanguageCard; // version=1: original Apple II always had a LC
g_MemTypeAppleII = CT_LanguageCard; // version=1: original Apple II always has a LC
else
g_MemTypeAppleIIPlus = CT_Empty; // version=2+: Apple II/II+ initially start with slot-0 empty
SetExpansionMemTypeDefault();
CreateLanguageCard(); // Create default LC now for: (a) //e which has no slot-0 LC (so this is final)
// (b) II/II+ which get re-created later if slot-0 has a card
//
@ -2181,7 +2188,6 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
//
modechanging = 0;
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2()
UpdatePaging(1); // Initialize=1 (Still needed, even with call to MemUpdatePaging() - why?)
// TC-TODO: At this point, the cards haven't been loaded, so the card's expansion ROM is unknown - so pointless(?) calling this now

View File

@ -66,6 +66,7 @@ LPBYTE MemGetBankPtr(const UINT nBank);
LPBYTE MemGetCxRomPeripheral();
DWORD GetMemMode(void);
void SetMemMode(DWORD memmode);
void SetModeChanging(BOOL value);
bool MemIsAddrCodeMemory(const USHORT addr);
void MemInitialize ();
void MemInitializeROM(void);
@ -92,6 +93,7 @@ BYTE __stdcall MemSetPaging(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExec
enum SS_CARDTYPE;
void SetExpansionMemType(const SS_CARDTYPE type);
SS_CARDTYPE GetCurrentExpansionMemType(void);
void CreateLanguageCard(void);
void SetRamWorksMemorySize(UINT pages);
UINT GetRamWorksActiveBank(void);

View File

@ -371,7 +371,6 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version)
if (!yamlLoadHelper.GetSubMap(std::string(SS_YAML_KEY_STATE)))
throw std::string(SS_YAML_KEY_UNIT ": Expected sub-map name: " SS_YAML_KEY_STATE);
bool bIsCardSupported = true;
SS_CARDTYPE type = CT_Empty;
bool bRes = false;
@ -420,21 +419,22 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version)
{
type = CT_LanguageCard;
SetExpansionMemType(type);
CreateLanguageCard();
bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, version);
}
else if (card == Saturn128K::GetSnapshotCardName())
{
type = CT_Saturn128K;
SetExpansionMemType(type);
CreateLanguageCard();
bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, version);
}
else
{
bIsCardSupported = false;
throw std::string("Slots: Unknown card: " + card); // todo: don't throw - just ignore & continue
}
if (bRes && bIsCardSupported)
if (bRes)
{
m_ConfigNew.m_Slot[slot] = type;
}