2006-02-25 20:50:29 +00:00
/*
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
2007-04-01 15:24:52 +00:00
Copyright ( C ) 2006 - 2007 , Tom Charlesworth , Michael Pohoreski
2006-02-25 20:50:29 +00:00
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: Memory emulation
*
* Author : Various
2016-03-21 23:48:02 +00:00
*
2017-05-13 21:07:53 +00:00
* In comments , UTAIIe is an abbreviation for a reference to " Understanding the Apple //e " by James Sather
2006-02-25 20:50:29 +00:00
*/
# include "StdAfx.h"
2014-08-13 20:30:35 +00:00
2020-11-11 21:15:27 +00:00
# include "Memory.h"
2020-11-29 17:30:06 +00:00
# include "Interface.h"
2020-11-26 21:50:06 +00:00
# include "Core.h"
2019-12-19 19:42:30 +00:00
# include "CardManager.h"
2014-08-13 20:30:35 +00:00
# include "CPU.h"
# include "Disk.h"
2010-01-03 18:43:08 +00:00
# include "Harddisk.h"
2014-08-14 17:03:12 +00:00
# include "Joystick.h"
2014-08-13 20:30:35 +00:00
# include "Keyboard.h"
2018-10-26 18:23:30 +00:00
# include "LanguageCard.h"
2018-01-26 11:03:44 +00:00
# include "Log.h"
2014-08-13 20:30:35 +00:00
# include "Mockingboard.h"
2007-08-06 21:38:35 +00:00
# include "MouseInterface.h"
2015-01-03 11:31:19 +00:00
# include "NTSC.h"
2010-08-28 20:04:24 +00:00
# include "NoSlotClock.h"
2021-01-17 10:48:06 +00:00
# include "Pravets.h"
2014-08-13 20:30:35 +00:00
# include "ParallelPrinter.h"
# include "Registry.h"
2016-03-21 23:48:02 +00:00
# include "SAM.h"
2021-09-10 12:57:55 +00:00
# include "FourPlay.h"
# include "SNESMAX.h"
2014-08-13 20:30:35 +00:00
# include "SerialComms.h"
# include "Speaker.h"
# include "Tape.h"
2021-10-18 19:23:46 +00:00
# include "Tfe/tfe.h"
2019-02-02 15:51:27 +00:00
# include "RGBMonitor.h"
2014-08-13 20:30:35 +00:00
2009-01-09 23:27:29 +00:00
# include "z80emu.h"
2018-02-24 15:12:40 +00:00
# include "Z80VICE/z80.h"
# include "../resource/resource.h"
# include "Configuration/IPropertySheet.h"
# include "Debugger/DebugDefs.h"
2016-03-21 23:48:02 +00:00
# include "YamlHelper.h"
2014-08-13 20:30:35 +00:00
2020-12-10 21:28:12 +00:00
// In this file allocate the 64KB of RAM with aligned memory allocations (0x10000)
// to ease mapping between Apple ][ and host memory space (while debugging).
2020-12-10 21:08:15 +00:00
// this is not available in Visual Studio
// https://en.cppreference.com/w/c/memory/aligned_alloc
# ifdef _MSC_VER
// VirtualAlloc is aligned
# define ALIGNED_ALLOC(size) (LPBYTE)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE)
# define ALIGNED_FREE(ptr) VirtualFree(ptr, 0, MEM_RELEASE)
# else
// use plain "new" in gcc (where debugging needs are less important)
# define ALIGNED_ALLOC(size) new BYTE[size]
# define ALIGNED_FREE(ptr) delete [] ptr
# endif
2018-04-06 21:36:54 +00:00
// UTAIIe:5-28 (GH#419)
// . Sather uses INTCXROM instead of SLOTCXROM' (used by the Apple//e Tech Ref Manual), so keep to this
// convention too since UTAIIe is the reference for most of the logic that we implement in the emulator.
2006-02-25 20:50:29 +00:00
# define SW_80STORE (memmode & MF_80STORE)
# define SW_ALTZP (memmode & MF_ALTZP)
# define SW_AUXREAD (memmode & MF_AUXREAD)
# define SW_AUXWRITE (memmode & MF_AUXWRITE)
# define SW_BANK2 (memmode & MF_BANK2)
# define SW_HIGHRAM (memmode & MF_HIGHRAM)
# define SW_HIRES (memmode & MF_HIRES)
# define SW_PAGE2 (memmode & MF_PAGE2)
# define SW_SLOTC3ROM (memmode & MF_SLOTC3ROM)
2018-04-06 21:36:54 +00:00
# define SW_INTCXROM (memmode & MF_INTCXROM)
2006-02-25 20:50:29 +00:00
# define SW_WRITERAM (memmode & MF_WRITERAM)
2019-04-06 10:18:48 +00:00
# define SW_IOUDIS (memmode & MF_IOUDIS)
2020-07-06 19:52:31 +00:00
# define SW_ALTROM0 (memmode & MF_ALTROM0) // For Copam Base64A
# define SW_ALTROM1 (memmode & MF_ALTROM1) // For Copam Base64A
2006-02-25 20:50:29 +00:00
2009-02-13 08:16:03 +00:00
/*
MEMORY MANAGEMENT SOFT SWITCHES
$ C000 W 80 STOREOFF Allow page2 to switch video page1 page2
$ C001 W 80 STOREON Allow page2 to switch main & aux video memory
$ C002 W RAMRDOFF Read enable main memory from $ 0200 - $ BFFF
2018-09-16 21:02:35 +00:00
$ C003 W RAMRDON Read enable aux memory from $ 0200 - $ BFFF
2009-02-13 08:16:03 +00:00
$ C004 W RAMWRTOFF Write enable main memory from $ 0200 - $ BFFF
$ C005 W RAMWRTON Write enable aux memory from $ 0200 - $ BFFF
2017-05-22 20:52:15 +00:00
$ C006 W INTCXROMOFF Enable slot ROM from $ C100 - $ C7FF ( but $ C800 - $ CFFF depends on INTC8ROM )
2009-02-13 08:16:03 +00:00
$ C007 W INTCXROMON Enable main ROM from $ C100 - $ CFFF
2014-09-14 15:12:55 +00:00
$ C008 W ALTZPOFF Enable main memory from $ 0000 - $ 01FF & avl BSR
2009-02-13 08:16:03 +00:00
$ C009 W ALTZPON Enable aux memory from $ 0000 - $ 01FF & avl BSR
$ C00A W SLOTC3ROMOFF Enable main ROM from $ C300 - $ C3FF
$ C00B W SLOTC3ROMON Enable slot ROM from $ C300 - $ C3FF
2020-10-31 16:10:18 +00:00
$ C07E W IOUDIS [ //c] On: disable IOU access for addresses $C058 to $C05F; enable access to DHIRES switch
$ C07F W IOUDIS [ //c] Off: enable IOU access for addresses $C058 to $C05F; disable access to DHIRES switch
2009-02-13 08:16:03 +00:00
VIDEO SOFT SWITCHES
$ C00C W 80 COLOFF Turn off 80 column display
$ C00D W 80 COLON Turn on 80 column display
$ C00E W ALTCHARSETOFF Turn off alternate characters
$ C00F W ALTCHARSETON Turn on alternate characters
2021-11-30 21:41:02 +00:00
$ C022 R / W SCREENCOLOR [ IIgs ] text foreground and background colors ( also VidHD )
$ C029 R / W NEWVIDEO [ IIgs ] Select new video modes ( also VidHD )
$ C034 R / W BORDERCOLOR [ IIgs ] b3 : 0 are border color ( also VidHD )
$ C035 R / W SHADOW [ IIgs ] auxmem - to - bank - E1 shadowing ( also VidHD )
2009-02-13 08:16:03 +00:00
$ C050 R / W TEXTOFF Select graphics mode
$ C051 R / W TEXTON Select text mode
$ C052 R / W MIXEDOFF Use full screen for graphics
$ C053 R / W MIXEDON Use graphics with 4 lines of text
$ C054 R / W PAGE2OFF Select panel display ( or main video memory )
$ C055 R / W PAGE2ON Select page2 display ( or aux video memory )
$ C056 R / W HIRESOFF Select low resolution graphics
$ C057 R / W HIRESON Select high resolution graphics
2020-01-18 16:42:49 +00:00
$ C05E R / W DHIRESON Select double ( 14 M ) resolution graphics
$ C05F R / W DHIRESOFF Select single ( 7 M ) resolution graphics
2009-02-13 08:16:03 +00:00
SOFT SWITCH STATUS FLAGS
$ C010 R7 AKD 1 = key pressed 0 = keys free ( clears strobe )
$ C011 R7 BSRBANK2 1 = bank2 available 0 = bank1 available
2018-04-06 21:36:54 +00:00
$ C012 R7 BSRREADRAM 1 = BSR active for read 0 = $ D000 - $ FFFF active ( BSR = Bank Switch RAM )
2009-02-13 08:16:03 +00:00
$ C013 R7 RAMRD 0 = main $ 0200 - $ BFFF active reads 1 = aux active
$ C014 R7 RAMWRT 0 = main $ 0200 - $ BFFF active writes 1 = aux writes
$ C015 R7 INTCXROM 1 = main $ C100 - $ CFFF ROM active 0 = slot active
$ C016 R7 ALTZP 1 = aux $ 0000 - $ 1FF + auxBSR 0 = main available
$ C017 R7 SLOTC3ROM 1 = slot $ C3 ROM active 0 = main $ C3 ROM active
$ C018 R7 80 STORE 1 = page2 switches main / aux 0 = page2 video
$ C019 R7 VERTBLANK 1 = vertical retrace on 0 = vertical retrace off
$ C01A R7 TEXT 1 = text mode is active 0 = graphics mode active
$ C01B R7 MIXED 1 = mixed graphics & text 0 = full screen
$ C01C R7 PAGE2 1 = video page2 selected or aux
$ C01D R7 HIRES 1 = high resolution graphics 0 = low resolution
$ C01E R7 ALTCHARSET 1 = alt character set on 0 = alt char set off
$ C01F R7 80 COL 1 = 80 col display on 0 = 80 col display off
2020-10-31 16:10:18 +00:00
$ C07E R7 RDIOUDIS [ //c] 1=IOUDIS off 0=IOUDIS on
$ C07F R7 RDDHIRES [ Enhanced //e? or //c] 1=DHIRES on 0=DHIRES off
2009-02-13 08:16:03 +00:00
*/
2007-05-28 11:16:42 +00:00
//-----------------------------------------------------------------------------
2013-07-11 21:21:58 +00:00
// Notes
// -----
//
// memimage
// - 64KB
2018-09-16 21:02:35 +00:00
//
// mem
// (a pointer to memimage 64KB)
// - a 64KB r/w memory cache
2013-07-11 21:21:58 +00:00
// - reflects the current readable memory in the 6502's 64K address space
// . excludes $Cxxx I/O memory
// . could be a mix of RAM/ROM, main/aux, etc
2018-09-16 21:02:35 +00:00
// - may also reflect the current writeable memory (on a 256-page granularity) if the write page addr == read page addr
// . for this case, the memdirty flag(s) are valid
// . when writes instead occur to backing-store, then memdirty flag(s) can be ignored
2013-07-11 21:21:58 +00:00
//
// memmain, memaux
2018-09-16 21:02:35 +00:00
// - physical contiguous 64KB "backing-store" for main & aux respectively
// - NB. 4K bank1 BSR is at $C000-$CFFF
2013-07-11 21:21:58 +00:00
//
// memwrite
2018-09-16 21:02:35 +00:00
// - 1 pointer entry per 256-byte page
2013-07-11 21:21:58 +00:00
// - used to write to a page
2018-09-16 21:02:35 +00:00
// - if RD & WR point to the same 256-byte RAM page, then memwrite will point to the page in 'mem'
// . ie. when SW_AUXREAD==SW_AUXWRITE, or 4K-BSR is r/w, or 8K BSR is r/w, or SW_80STORE=1
// . So 'mem' remains correct for both r&w operations, but the physical 64K mem block becomes stale
// - if RD & WR point to different 256-byte pages, then memwrite will point to the page in the physical 64K mem block
// . writes will still set the dirty flag (but can be ignored)
// . UpdatePaging() ignores this, as it only copies back to the physical 64K mem block when memshadow changes (for that 256-byte page)
2013-07-11 21:21:58 +00:00
//
// memdirty
// - 1 byte entry per 256-byte page
// - set when a write occurs to a 256-byte page
2018-09-16 21:02:35 +00:00
// - indicates that 'mem' (ie. the cache) is out-of-sync with the "physical" 64K backing-store memory
// - NB. a page's dirty flag is only useful(valid) when 'mem' is used for both read & write for the corresponding page
// When they differ, then writes go directly to the backing-store.
// . In this case, the dirty flag will just force a memcpy() to the same address in backing-store.
2013-07-11 21:21:58 +00:00
//
// memshadow
2018-09-16 21:02:35 +00:00
// - 1 pointer entry per 256-byte page
// - reflects how 'mem' is setup for read operations (at a 256-byte granularity)
2013-07-11 21:21:58 +00:00
// . EG: if ALTZP=1, then:
// . mem will have copies of memaux's ZP & stack
// . memshadow[0] = &memaux[0x0000]
// . memshadow[1] = &memaux[0x0100]
//
2007-05-28 11:16:42 +00:00
static LPBYTE memshadow [ 0x100 ] ;
LPBYTE memwrite [ 0x100 ] ;
iofunction IORead [ 256 ] ;
iofunction IOWrite [ 256 ] ;
static LPVOID SlotParameters [ NUM_SLOTS ] ;
2006-02-25 20:50:29 +00:00
LPBYTE mem = NULL ;
2007-05-28 11:16:42 +00:00
//
2006-02-25 20:50:29 +00:00
static LPBYTE memaux = NULL ;
2007-05-28 11:16:42 +00:00
static LPBYTE memmain = NULL ;
2006-02-25 20:50:29 +00:00
LPBYTE memdirty = NULL ;
2007-05-28 11:16:42 +00:00
static LPBYTE memrom = NULL ;
2006-02-25 20:50:29 +00:00
static LPBYTE memimage = NULL ;
2007-05-28 11:16:42 +00:00
static LPBYTE pCxRomInternal = NULL ;
static LPBYTE pCxRomPeripheral = NULL ;
2018-10-26 18:23:30 +00:00
static LPBYTE g_pMemMainLanguageCard = NULL ;
static DWORD memmode = LanguageCardUnit : : kMemModeInitialState ;
2013-07-11 21:21:58 +00:00
static BOOL modechanging = 0 ; // An Optimisation: means delay calling UpdatePaging() for 1 instruction
2006-03-09 21:10:40 +00:00
2020-07-06 19:24:16 +00:00
static UINT memrompages = 1 ;
2020-06-10 19:56:00 +00:00
static CNoSlotClock * g_NoSlotClock = new CNoSlotClock ;
2018-10-26 18:23:30 +00:00
static LanguageCardUnit * g_pLanguageCard = NULL ; // For all Apple II, //e and above
2010-08-28 20:04:24 +00:00
2006-02-25 20:50:29 +00:00
# ifdef RAMWORKS
2018-10-26 18:23:30 +00:00
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
2016-03-21 23:48:02 +00:00
static LPBYTE RWpages [ kMaxExMemoryBanks ] ; // pointers to RW memory banks
2006-02-25 20:50:29 +00:00
# endif
2019-04-06 10:18:48 +00:00
static const UINT kNumAnnunciators = 4 ;
static bool g_Annunciator [ kNumAnnunciators ] = { } ;
2018-10-26 18:23:30 +00:00
BYTE __stdcall IO_Annunciator ( WORD programcounter , WORD address , BYTE write , BYTE value , ULONG nCycles ) ;
//=============================================================================
2017-04-27 21:02:02 +00:00
2018-11-04 15:07:46 +00:00
// Default memory types on a VM restart
// - can be overwritten by cmd-line or loading a save-state
static SS_CARDTYPE g_MemTypeAppleII = CT_Empty ;
2018-10-26 18:23:30 +00:00
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 ;
2017-04-27 21:02:02 +00:00
2020-07-06 19:24:16 +00:00
const UINT CxRomSize = 4 * 1024 ;
const UINT Apple2RomSize = 12 * 1024 ;
const UINT Apple2eRomSize = Apple2RomSize + CxRomSize ;
//const UINT Pravets82RomSize = 12*1024;
//const UINT Pravets8ARomSize = Pravets82RomSize+CxRomSize;
2020-07-06 19:52:31 +00:00
const UINT MaxRomPages = 4 ; // For Copam Base64A
2020-07-06 19:24:16 +00:00
const UINT Base64ARomSize = MaxRomPages * Apple2RomSize ;
2018-10-26 18:23:30 +00:00
// Called from MemLoadSnapshot()
static void ResetDefaultMachineMemTypes ( void )
{
2018-11-04 15:07:46 +00:00
g_MemTypeAppleII = CT_Empty ;
2018-10-26 18:23:30 +00:00
g_MemTypeAppleIIPlus = CT_LanguageCard ;
g_MemTypeAppleIIe = CT_Extended80Col ;
}
2019-01-05 22:20:51 +00:00
// Called from MemInitialize(), MemLoadSnapshot()
2018-11-04 15:07:46 +00:00
static void SetExpansionMemTypeDefault ( void )
2018-10-26 18:23:30 +00:00
{
2018-11-04 15:07:46 +00:00
SS_CARDTYPE defaultType = IsApple2Original ( GetApple2Type ( ) ) ? g_MemTypeAppleII
: IsApple2PlusOrClone ( GetApple2Type ( ) ) ? g_MemTypeAppleIIPlus
: g_MemTypeAppleIIe ;
2018-10-26 18:23:30 +00:00
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:
2018-11-04 15:07:46 +00:00
if ( IsApple2Original ( GetApple2Type ( ) ) )
{
newSlot0Card = CT_Empty ;
newSlotAuxCard = CT_Empty ;
}
else if ( IsApple2PlusOrClone ( GetApple2Type ( ) ) )
2018-10-26 18:23:30 +00:00
{
newSlot0Card = CT_LanguageCard ;
newSlotAuxCard = CT_Empty ;
}
else // Apple //e or above
{
newSlot0Card = CT_Empty ; // NB. No slot0 for //e
newSlotAuxCard = CT_Extended80Col ;
}
2018-11-04 15:07:46 +00:00
if ( type = = CT_LanguageCard | | type = = CT_Saturn128K )
2018-10-26 18:23:30 +00:00
{
2018-11-04 15:07:46 +00:00
g_MemTypeAppleII = type ;
2018-10-26 18:23:30 +00:00
g_MemTypeAppleIIPlus = type ;
if ( IsApple2PlusOrClone ( GetApple2Type ( ) ) )
2018-11-04 15:07:46 +00:00
newSlot0Card = type ;
2018-10-26 18:23:30 +00:00
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
2018-11-04 15:07:46 +00:00
newSlotAuxCard = type ;
2018-10-26 18:23:30 +00:00
}
2020-10-11 16:34:44 +00:00
GetCardMgr ( ) . Insert ( SLOT0 , newSlot0Card ) ;
GetCardMgr ( ) . InsertAux ( newSlotAuxCard ) ;
2018-11-09 20:51:51 +00:00
}
void CreateLanguageCard ( void )
{
delete g_pLanguageCard ;
g_pLanguageCard = NULL ;
2018-10-26 18:23:30 +00:00
if ( IsApple2PlusOrClone ( GetApple2Type ( ) ) )
{
2020-10-11 16:34:44 +00:00
if ( GetCardMgr ( ) . QuerySlot ( SLOT0 ) = = CT_Saturn128K )
2018-10-26 18:23:30 +00:00
g_pLanguageCard = new Saturn128K ( g_uSaturnBanksFromCmdLine ) ;
2020-10-11 16:34:44 +00:00
else if ( GetCardMgr ( ) . QuerySlot ( SLOT0 ) = = CT_LanguageCard )
2018-10-26 18:23:30 +00:00
g_pLanguageCard = new LanguageCardSlot0 ;
2018-11-04 15:07:46 +00:00
else
g_pLanguageCard = NULL ;
2018-10-26 18:23:30 +00:00
}
else
{
g_pLanguageCard = new LanguageCardUnit ;
}
}
SS_CARDTYPE GetCurrentExpansionMemType ( void )
{
if ( IsApple2PlusOrClone ( GetApple2Type ( ) ) )
2020-10-11 16:34:44 +00:00
return GetCardMgr ( ) . QuerySlot ( SLOT0 ) ;
2018-10-26 18:23:30 +00:00
else
2020-10-11 16:34:44 +00:00
return GetCardMgr ( ) . QueryAux ( ) ;
2018-10-26 18:23:30 +00:00
}
//
void SetRamWorksMemorySize ( UINT pages )
{
g_uMaxExPages = pages ;
}
UINT GetRamWorksActiveBank ( void )
{
return g_uActiveBank ;
}
void SetSaturnMemorySize ( UINT banks )
{
g_uSaturnBanksFromCmdLine = banks ;
}
//
static BOOL GetLastRamWrite ( void )
{
2018-11-04 15:07:46 +00:00
if ( g_pLanguageCard )
return g_pLanguageCard - > GetLastRamWrite ( ) ;
return 0 ;
2018-10-26 18:23:30 +00:00
}
static void SetLastRamWrite ( BOOL count )
{
2018-11-04 15:07:46 +00:00
if ( g_pLanguageCard )
g_pLanguageCard - > SetLastRamWrite ( count ) ;
2018-10-26 18:23:30 +00:00
}
//
void SetMemMainLanguageCard ( LPBYTE ptr , bool bMemMain /*=false*/ )
{
if ( bMemMain )
g_pMemMainLanguageCard = memmain + 0xC000 ;
else
g_pMemMainLanguageCard = ptr ;
}
LanguageCardUnit * GetLanguageCard ( void )
{
2018-11-04 15:07:46 +00:00
_ASSERT ( g_pLanguageCard ) ;
2018-10-26 18:23:30 +00:00
return g_pLanguageCard ;
}
2006-02-25 20:50:29 +00:00
2020-02-22 11:38:25 +00:00
LPBYTE GetCxRomPeripheral ( void )
{
return pCxRomPeripheral ; // Can be NULL if at MODE_LOGO
}
2007-05-28 11:16:42 +00:00
//=============================================================================
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IORead_C00x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2018-06-30 13:30:30 +00:00
return KeybReadData ( ) ;
2006-02-25 20:50:29 +00:00
}
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IOWrite_C00x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
if ( ( addr & 0xf ) < = 0xB )
2018-03-03 21:27:50 +00:00
return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
else
2020-12-28 16:25:29 +00:00
return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
//-------------------------------------
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IORead_C01x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2018-06-30 13:30:30 +00:00
if ( IS_APPLE2 ) // Include Pravets machines too?
return KeybReadFlag ( ) ;
bool res = false ;
2007-05-28 11:16:42 +00:00
switch ( addr & 0xf )
2006-03-12 09:05:39 +00:00
{
2018-06-30 13:30:30 +00:00
case 0x0 : return KeybReadFlag ( ) ;
case 0x1 : res = SW_BANK2 ? true : false ; break ;
case 0x2 : res = SW_HIGHRAM ? true : false ; break ;
case 0x3 : res = SW_AUXREAD ? true : false ; break ;
case 0x4 : res = SW_AUXWRITE ? true : false ; break ;
case 0x5 : res = SW_INTCXROM ? true : false ; break ;
case 0x6 : res = SW_ALTZP ? true : false ; break ;
case 0x7 : res = SW_SLOTC3ROM ? true : false ; break ;
case 0x8 : res = SW_80STORE ? true : false ; break ;
2020-12-28 16:25:29 +00:00
case 0x9 : res = GetVideo ( ) . VideoGetVblBar ( nExecutedCycles ) ; break ;
case 0xA : res = GetVideo ( ) . VideoGetSWTEXT ( ) ; break ;
case 0xB : res = GetVideo ( ) . VideoGetSWMIXED ( ) ; break ;
2018-06-30 13:30:30 +00:00
case 0xC : res = SW_PAGE2 ? true : false ; break ;
2020-12-28 16:25:29 +00:00
case 0xD : res = GetVideo ( ) . VideoGetSWHIRES ( ) ; break ;
case 0xE : res = GetVideo ( ) . VideoGetSWAltCharSet ( ) ; break ;
case 0xF : res = GetVideo ( ) . VideoGetSW80COL ( ) ; break ;
2006-03-12 09:05:39 +00:00
}
2007-05-28 11:16:42 +00:00
2018-06-30 13:30:30 +00:00
return KeybGetKeycode ( ) | ( res ? 0x80 : 0 ) ;
2007-05-28 11:16:42 +00:00
}
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IOWrite_C01x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2018-06-30 13:30:30 +00:00
return KeybReadFlag ( ) ;
2007-05-28 11:16:42 +00:00
}
//-------------------------------------
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IORead_C02x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2018-03-03 21:27:50 +00:00
return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IOWrite_C02x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2021-11-30 21:41:02 +00:00
if ( GetCardMgr ( ) . QuerySlot ( SLOT3 ) = = CT_VidHD )
{
if ( addr = = 0xC022 | | addr = = 0xC029 )
GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
}
2021-01-17 10:48:06 +00:00
return TapeWrite ( pc , addr , bWrite , d , nExecutedCycles ) ; // $C020 TAPEOUT
2007-05-28 11:16:42 +00:00
}
//-------------------------------------
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IORead_C03x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2018-03-03 21:27:50 +00:00
return SpkrToggle ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IOWrite_C03x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2021-11-30 21:41:02 +00:00
if ( GetCardMgr ( ) . QuerySlot ( SLOT3 ) = = CT_VidHD )
{
// NB. Writes to $C03x addresses will still toggle the speaker, even with a VidHD present
if ( addr = = 0xC034 | | addr = = 0xC035 )
GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
}
2018-03-03 21:27:50 +00:00
return SpkrToggle ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
//-------------------------------------
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IORead_C04x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2018-03-03 21:27:50 +00:00
return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IOWrite_C04x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2018-03-03 21:27:50 +00:00
return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
//-------------------------------------
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IORead_C05x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
switch ( addr & 0xf )
{
2020-12-28 16:25:29 +00:00
case 0x0 : return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x1 : return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x2 : return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x3 : return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
2018-03-03 21:27:50 +00:00
case 0x4 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x5 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x6 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x7 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x8 : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x9 : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xA : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xB : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xC : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xD : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
2019-04-06 10:18:48 +00:00
case 0xE : // fall through...
2020-04-02 19:17:32 +00:00
case 0xF : if ( IsApple2PlusOrClone ( GetApple2Type ( ) ) )
IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
else
2020-12-28 16:25:29 +00:00
return ( ! SW_IOUDIS ) ? GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles )
2020-04-02 19:17:32 +00:00
: IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
return 0 ;
}
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IOWrite_C05x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
switch ( addr & 0xf )
{
2020-12-28 16:25:29 +00:00
case 0x0 : return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x1 : return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x2 : return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x3 : return GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles ) ;
2018-03-03 21:27:50 +00:00
case 0x4 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x5 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x6 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x7 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x8 : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x9 : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xA : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xB : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xC : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xD : return IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
2019-04-06 10:18:48 +00:00
case 0xE : // fall through...
2020-04-02 19:17:32 +00:00
case 0xF : if ( IsApple2PlusOrClone ( GetApple2Type ( ) ) )
IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
else
2020-12-28 16:25:29 +00:00
return ( ! SW_IOUDIS ) ? GetVideo ( ) . VideoSetMode ( pc , addr , bWrite , d , nExecutedCycles )
2020-04-02 19:17:32 +00:00
: IO_Annunciator ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
return 0 ;
}
//-------------------------------------
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IORead_C06x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2008-06-20 23:47:25 +00:00
{
2018-04-06 21:36:54 +00:00
switch ( addr & 0x7 ) // address bit 4 is ignored (UTAIIe:7-5)
2006-03-12 09:05:39 +00:00
{
2021-01-17 10:48:06 +00:00
case 0x0 : return TapeRead ( pc , addr , bWrite , d , nExecutedCycles ) ; //$C060 TAPEIN
2018-03-03 21:27:50 +00:00
case 0x1 : return JoyReadButton ( pc , addr , bWrite , d , nExecutedCycles ) ; //$C061 Digital input 0 (If bit 7=1 then JoyButton 0 or OpenApple is pressed)
case 0x2 : return JoyReadButton ( pc , addr , bWrite , d , nExecutedCycles ) ; //$C062 Digital input 1 (If bit 7=1 then JoyButton 1 or ClosedApple is pressed)
case 0x3 : return JoyReadButton ( pc , addr , bWrite , d , nExecutedCycles ) ; //$C063 Digital input 2
case 0x4 : return JoyReadPosition ( pc , addr , bWrite , d , nExecutedCycles ) ; //$C064 Analog input 0
case 0x5 : return JoyReadPosition ( pc , addr , bWrite , d , nExecutedCycles ) ; //$C065 Analog input 1
case 0x6 : return JoyReadPosition ( pc , addr , bWrite , d , nExecutedCycles ) ; //$C066 Analog input 2
case 0x7 : return JoyReadPosition ( pc , addr , bWrite , d , nExecutedCycles ) ; //$C067 Analog input 3
2007-05-28 11:16:42 +00:00
}
return 0 ;
}
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IOWrite_C06x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2008-06-20 23:47:25 +00:00
switch ( addr & 0xf )
{
case 0x0 :
2018-03-03 21:27:50 +00:00
if ( g_Apple2Type = = A2TYPE_PRAVETS8A )
2021-01-17 10:48:06 +00:00
return GetPravets ( ) . SetCapsLockAllowed ( d ) ;
2008-06-20 23:47:25 +00:00
else
2021-01-17 10:48:06 +00:00
return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2008-06-20 23:47:25 +00:00
}
2021-01-17 10:48:06 +00:00
return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
//-------------------------------------
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IORead_C07x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2019-04-06 17:23:42 +00:00
// Apple//e TRM, pg-258: "Reading or writing any address in the range $C070-$C07F also triggers the paddle timer and resets the VBLINT(*)." (*) //c only!
JoyResetPosition ( nExecutedCycles ) ; //$C07X Analog input reset
2019-04-06 10:26:33 +00:00
2007-05-28 11:16:42 +00:00
switch ( addr & 0xf )
{
2019-04-06 17:23:42 +00:00
case 0x0 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2018-03-03 21:27:50 +00:00
case 0x1 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x2 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x3 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x4 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x5 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x6 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x7 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x8 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x9 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xA : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xB : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xC : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xD : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2020-10-31 16:10:18 +00:00
case 0xE : return IS_APPLE2C ( ) ? MemReadFloatingBus ( SW_IOUDIS ? true : false , nExecutedCycles ) // GH#636
2019-04-06 10:18:48 +00:00
: IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2020-12-28 16:25:29 +00:00
case 0xF : return IsEnhancedIIEorIIC ( ) ? MemReadFloatingBus ( GetVideo ( ) . VideoGetSWDHIRES ( ) , nExecutedCycles ) // GH#636
2019-04-06 10:18:48 +00:00
: IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
}
return 0 ;
}
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IOWrite_C07x ( WORD pc , WORD addr , BYTE bWrite , BYTE d , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2019-04-06 17:23:42 +00:00
// Apple//e TRM, pg-258: "Reading or writing any address in the range $C070-$C07F also triggers the paddle timer and resets the VBLINT(*)." (*) //c only!
JoyResetPosition ( nExecutedCycles ) ; //$C07X Analog input reset
2019-04-06 10:18:48 +00:00
2007-05-28 11:16:42 +00:00
switch ( addr & 0xf )
{
2019-04-06 17:56:00 +00:00
case 0x0 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
# ifdef RAMWORKS
2018-03-03 21:27:50 +00:00
case 0x1 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ; // extended memory card set page
case 0x2 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x3 : return MemSetPaging ( pc , addr , bWrite , d , nExecutedCycles ) ; // Ramworks III set page
2007-05-28 11:16:42 +00:00
# else
2018-03-03 21:27:50 +00:00
case 0x1 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x2 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x3 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
# endif
2018-03-03 21:27:50 +00:00
case 0x4 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x5 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x6 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x7 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x8 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0x9 : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xA : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xB : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xC : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
case 0xD : return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
2020-10-31 16:10:18 +00:00
case 0xE : if ( IS_APPLE2C ( ) )
2019-04-06 10:18:48 +00:00
SetMemMode ( memmode & ~ MF_IOUDIS ) ; // disable IOU access for addresses $C058 to $C05F; enable access to DHIRES switch
else
return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
break ;
2020-10-31 16:10:18 +00:00
case 0xF : if ( IS_APPLE2C ( ) )
2019-04-06 10:18:48 +00:00
SetMemMode ( memmode | MF_IOUDIS ) ; // enable IOU access for addresses $C058 to $C05F; disable access to DHIRES switch
else
return IO_Null ( pc , addr , bWrite , d , nExecutedCycles ) ;
break ;
2007-05-28 11:16:42 +00:00
}
return 0 ;
}
//-----------------------------------------------------------------------------
static iofunction IORead_C0xx [ 8 ] =
{
IORead_C00x , // Keyboard
IORead_C01x , // Memory/Video
IORead_C02x , // Cassette
IORead_C03x , // Speaker
IORead_C04x ,
IORead_C05x , // Video
IORead_C06x , // Joystick
IORead_C07x , // Joystick/Video
} ;
static iofunction IOWrite_C0xx [ 8 ] =
{
IOWrite_C00x , // Memory/Video
IOWrite_C01x , // Keyboard
IOWrite_C02x , // Cassette
IOWrite_C03x , // Speaker
IOWrite_C04x ,
IOWrite_C05x , // Video/Memory
IOWrite_C06x ,
IOWrite_C07x , // Joystick/Ramworks
} ;
2017-05-21 16:35:35 +00:00
static BYTE IO_SELECT = 0 ;
static bool INTC8ROM = false ; // UTAIIe:5-28
2007-05-28 11:16:42 +00:00
static BYTE * ExpansionRom [ NUM_SLOTS ] ;
enum eExpansionRomType { eExpRomNull = 0 , eExpRomInternal , eExpRomPeripheral } ;
static eExpansionRomType g_eExpansionRomType = eExpRomNull ;
static UINT g_uPeripheralRomSlot = 0 ;
//=============================================================================
2018-03-03 21:27:50 +00:00
BYTE __stdcall IO_Null ( WORD programcounter , WORD address , BYTE write , BYTE value , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
if ( ! write )
2018-03-03 21:27:50 +00:00
return MemReadFloatingBus ( nExecutedCycles ) ;
2007-05-28 11:16:42 +00:00
else
2006-03-12 09:05:39 +00:00
return 0 ;
2007-05-28 11:16:42 +00:00
}
2018-03-03 21:27:50 +00:00
BYTE __stdcall IO_Annunciator ( WORD programcounter , WORD address , BYTE write , BYTE value , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
// Apple//e ROM:
2019-04-06 10:18:48 +00:00
// . $FA6F: LDA $C058 (SETAN0) ; AN0 = TTL LO
// . $FA72: LDA $C05A (SETAN1) ; AN1 = TTL LO
// . $C2B5: LDA $C05D (CLRAN2) ;SETUP
// . $C2B8: LDA $C05F (CLRAN3) ; ANNUNCIATORS
2007-05-28 11:16:42 +00:00
// NB. AN3: For //e & //c these locations are now used to enabled/disabled DHIRES
2014-02-16 14:39:26 +00:00
2019-04-06 10:18:48 +00:00
g_Annunciator [ ( address > > 1 ) & 3 ] = ( address & 1 ) ? true : false ;
2014-02-16 14:39:26 +00:00
if ( address > = 0xC058 & & address < = 0xC05B )
JoyportControl ( address & 0x3 ) ; // AN0 and AN1 control
2020-07-06 19:52:31 +00:00
if ( address > = 0xC058 & & address < = 0xC05B & & IsCopamBase64A ( GetApple2Type ( ) ) )
MemSetPaging ( programcounter , address , write , value , nExecutedCycles ) ;
2014-02-16 14:39:26 +00:00
2020-04-02 19:17:32 +00:00
if ( address > = 0xC05C & & address < = 0xC05D & & IsApple2JPlus ( GetApple2Type ( ) ) )
NTSC_VideoInitAppleType ( ) ; // AN2 switches between Katakana & ASCII video rom chars (GH#773)
2008-12-15 15:08:05 +00:00
if ( ! write )
2018-03-03 21:27:50 +00:00
return MemReadFloatingBus ( nExecutedCycles ) ;
2008-12-15 15:08:05 +00:00
else
return 0 ;
2007-05-28 11:16:42 +00:00
}
2010-09-06 20:15:05 +00:00
inline bool IsPotentialNoSlotClockAccess ( const WORD address )
{
2018-04-06 21:36:54 +00:00
// UAIIe:5-28
2010-09-06 20:15:05 +00:00
const BYTE AddrHi = address > > 8 ;
2018-04-06 21:36:54 +00:00
return ( ( ( SW_INTCXROM | | ! SW_SLOTC3ROM ) & & ( AddrHi = = 0xC3 ) ) | | // Internal ROM at [$C100-CFFF or $C300-C3FF] && AddrHi == $C3
( SW_INTCXROM & & ( AddrHi = = 0xC8 ) ) ) ; // Internal ROM at [$C100-CFFF] && AddrHi == $C8
2010-09-06 20:15:05 +00:00
}
2012-01-21 14:36:35 +00:00
static bool IsCardInSlot ( const UINT uSlot ) ;
2007-05-28 11:16:42 +00:00
// Enabling expansion ROM ($C800..$CFFF]:
// . Enable if: Enable1 && Enable2
// . Enable1 = I/O SELECT' (6502 accesses $Csxx)
// - Reset when 6502 accesses $CFFF
// . Enable2 = I/O STROBE' (6502 accesses [$C800..$CFFF])
2017-03-12 21:45:55 +00:00
// TODO:
2017-05-21 16:35:35 +00:00
// . IO_SELECT and INTC8ROM are sticky - they only getting reset by $CFFF and MemReset()
2017-03-12 21:45:55 +00:00
// . Check Sather UAIIe, but I assume that a 6502 access to a non-$Csxx (and non-expansion ROM) location will clear IO_SELECT
// NB. ProDOS boot sets IO_SELECT=0x04 (its scan for boot devices?), as slot2 contains a card (ie. SSC) with an expansion ROM.
2017-05-13 21:07:53 +00:00
//
// -----------
// UTAIIe:5-28
// $C100-C2FF
2018-04-06 21:36:54 +00:00
// INTCXROM SLOTC3ROM $C400-CFFF $C300-C3FF
2017-05-13 21:07:53 +00:00
// 0 0 slot internal
// 0 1 slot slot
// 1 0 internal internal
// 1 1 internal internal
//
2017-09-23 18:29:59 +00:00
// NB. if (INTCXROM || INTC8ROM) == true then internal ROM
//
2017-05-13 21:07:53 +00:00
// -----------
//
2017-05-21 16:35:35 +00:00
// INTC8ROM: Unreadable soft switch (UTAIIe:5-28)
2017-09-23 18:29:59 +00:00
// . Set: On access to $C3XX with SLOTC3ROM reset
// - "From this point, $C800-$CFFF will stay assigned to motherboard ROM until
// an access is made to $CFFF or until the MMU detects a system reset."
// . Reset: On access to $CFFF or an MMU reset
2017-05-21 16:35:35 +00:00
//
2017-05-13 21:07:53 +00:00
2018-03-03 21:27:50 +00:00
static BYTE __stdcall IO_Cxxx ( WORD programcounter , WORD address , BYTE write , BYTE value , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
if ( address = = 0xCFFF )
{
// Disable expansion ROM at [$C800..$CFFF]
2017-05-21 16:35:35 +00:00
// . SSC will disable on an access to $CFxx - but ROM only accesses $CFFF, so it doesn't matter
2007-05-28 11:16:42 +00:00
IO_SELECT = 0 ;
2017-05-21 16:35:35 +00:00
INTC8ROM = false ;
2007-05-28 11:16:42 +00:00
g_uPeripheralRomSlot = 0 ;
2018-04-06 21:36:54 +00:00
if ( ! SW_INTCXROM )
2007-05-28 11:16:42 +00:00
{
2018-04-06 21:36:54 +00:00
// NB. SW_INTCXROM==1 ensures that internal rom stays switched in
2009-02-13 08:16:03 +00:00
memset ( pCxRomPeripheral + 0x800 , 0 , FIRMWARE_EXPANSION_SIZE ) ;
memset ( mem + FIRMWARE_EXPANSION_BEGIN , 0 , FIRMWARE_EXPANSION_SIZE ) ;
2007-05-28 11:16:42 +00:00
g_eExpansionRomType = eExpRomNull ;
}
// NB. IO_SELECT won't get set, so ROM won't be switched back in...
}
//
BYTE IO_STROBE = 0 ;
2018-04-06 21:36:54 +00:00
if ( IS_APPLE2 | | ! SW_INTCXROM )
2007-05-28 11:16:42 +00:00
{
2009-02-13 08:16:03 +00:00
if ( ( address > = APPLE_SLOT_BEGIN ) & & ( address < = APPLE_SLOT_END ) )
2007-05-28 11:16:42 +00:00
{
2017-03-12 21:45:55 +00:00
const UINT uSlot = ( address > > 8 ) & 0x7 ;
if ( uSlot ! = 3 )
{
if ( ExpansionRom [ uSlot ] )
IO_SELECT | = 1 < < uSlot ;
}
else // slot3
{
if ( ( SW_SLOTC3ROM ) & & ExpansionRom [ uSlot ] )
IO_SELECT | = 1 < < uSlot ; // Slot3 & Peripheral ROM
else if ( ! SW_SLOTC3ROM )
2017-05-21 16:35:35 +00:00
INTC8ROM = true ; // Slot3 & Internal ROM
2017-03-12 21:45:55 +00:00
}
2007-05-28 11:16:42 +00:00
}
2009-02-13 08:16:03 +00:00
else if ( ( address > = FIRMWARE_EXPANSION_BEGIN ) & & ( address < = FIRMWARE_EXPANSION_END ) )
2007-05-28 11:16:42 +00:00
{
2017-05-21 16:35:35 +00:00
if ( ! INTC8ROM ) // [GH#423] UTAIIe:5-28: if INTCXROM or INTC8ROM is configured for internal response,
// then access to $C800-$CFFF results in ROMEN1' low (active) and I/O STROBE' high (inactive)
IO_STROBE = 1 ;
2007-05-28 11:16:42 +00:00
}
//
if ( IO_SELECT & & IO_STROBE )
{
// Enable Peripheral Expansion ROM
UINT uSlot = 1 ;
for ( ; uSlot < NUM_SLOTS ; uSlot + + )
{
if ( IO_SELECT & ( 1 < < uSlot ) )
{
BYTE RemainingSelected = IO_SELECT & ~ ( 1 < < uSlot ) ;
_ASSERT ( RemainingSelected = = 0 ) ;
break ;
}
}
if ( ExpansionRom [ uSlot ] & & ( g_uPeripheralRomSlot ! = uSlot ) )
{
2009-02-13 08:16:03 +00:00
memcpy ( pCxRomPeripheral + 0x800 , ExpansionRom [ uSlot ] , FIRMWARE_EXPANSION_SIZE ) ;
memcpy ( mem + FIRMWARE_EXPANSION_BEGIN , ExpansionRom [ uSlot ] , FIRMWARE_EXPANSION_SIZE ) ;
2007-05-28 11:16:42 +00:00
g_eExpansionRomType = eExpRomPeripheral ;
g_uPeripheralRomSlot = uSlot ;
}
}
2017-05-21 16:35:35 +00:00
else if ( INTC8ROM & & ( g_eExpansionRomType ! = eExpRomInternal ) )
2007-05-28 11:16:42 +00:00
{
// Enable Internal ROM
// . Get this for PR#3
2009-02-13 08:16:03 +00:00
memcpy ( mem + FIRMWARE_EXPANSION_BEGIN , pCxRomInternal + 0x800 , FIRMWARE_EXPANSION_SIZE ) ;
2007-05-28 11:16:42 +00:00
g_eExpansionRomType = eExpRomInternal ;
g_uPeripheralRomSlot = 0 ;
}
}
2020-11-02 21:41:02 +00:00
// NSC only for //e at internal C3/C8 ROMs, as II/II+ has no internal ROM here! (GH#827)
if ( ! IS_APPLE2 & & g_NoSlotClock & & IsPotentialNoSlotClockAccess ( address ) )
2010-08-28 20:04:24 +00:00
{
2020-11-25 21:57:34 +00:00
if ( g_NoSlotClock - > ReadWrite ( address , value , write ) )
return value ;
2010-08-28 20:04:24 +00:00
}
2018-04-06 21:36:54 +00:00
if ( ! IS_APPLE2 & & SW_INTCXROM )
2007-05-28 11:16:42 +00:00
{
// !SW_SLOTC3ROM = Internal ROM: $C300-C3FF
2018-04-06 21:36:54 +00:00
// SW_INTCXROM = Internal ROM: $C100-CFFF
2007-05-28 11:16:42 +00:00
2017-05-21 16:35:35 +00:00
if ( ( address > = 0xC300 ) & & ( address < = 0xC3FF ) )
{
if ( ! SW_SLOTC3ROM ) // GH#423
INTC8ROM = true ;
}
2009-02-13 08:16:03 +00:00
else if ( ( address > = FIRMWARE_EXPANSION_BEGIN ) & & ( address < = FIRMWARE_EXPANSION_END ) )
2017-05-21 16:35:35 +00:00
{
if ( ! INTC8ROM ) // GH#423
IO_STROBE = 1 ;
}
2007-05-28 11:16:42 +00:00
2017-05-21 16:35:35 +00:00
if ( INTC8ROM & & ( g_eExpansionRomType ! = eExpRomInternal ) )
2007-05-28 11:16:42 +00:00
{
// Enable Internal ROM
2009-02-13 08:16:03 +00:00
memcpy ( mem + FIRMWARE_EXPANSION_BEGIN , pCxRomInternal + 0x800 , FIRMWARE_EXPANSION_SIZE ) ;
2007-05-28 11:16:42 +00:00
g_eExpansionRomType = eExpRomInternal ;
g_uPeripheralRomSlot = 0 ;
}
2006-03-12 09:05:39 +00:00
}
2007-05-28 11:16:42 +00:00
2012-01-21 14:36:35 +00:00
if ( address > = APPLE_SLOT_BEGIN & & address < = APPLE_SLOT_END )
{
const UINT uSlot = ( address > > 8 ) & 0x7 ;
2017-03-10 22:00:01 +00:00
const bool bPeripheralSlotRomEnabled = IS_APPLE2 ? true // A][
: // A//e or above
2018-04-06 21:36:54 +00:00
( ! SW_INTCXROM & & // Peripheral (card) ROMs enabled in $C100..$C7FF
2017-03-10 22:00:01 +00:00
! ( ! SW_SLOTC3ROM & & uSlot = = 3 ) ) ; // Internal C3 ROM disabled in $C300 when slot == 3
2017-03-12 21:45:55 +00:00
// Fix for GH#149 and GH#164
2017-03-10 22:00:01 +00:00
if ( bPeripheralSlotRomEnabled & & ! IsCardInSlot ( uSlot ) ) // Slot is empty
2013-03-10 23:44:30 +00:00
{
2018-03-03 21:27:50 +00:00
return IO_Null ( programcounter , address , write , value , nExecutedCycles ) ;
2013-03-10 23:44:30 +00:00
}
2012-01-21 14:36:35 +00:00
}
2009-02-13 08:16:03 +00:00
if ( ( g_eExpansionRomType = = eExpRomNull ) & & ( address > = FIRMWARE_EXPANSION_BEGIN ) )
2018-03-03 21:27:50 +00:00
return IO_Null ( programcounter , address , write , value , nExecutedCycles ) ;
2013-03-10 23:44:30 +00:00
return mem [ address ] ;
2007-05-28 11:16:42 +00:00
}
2020-11-25 21:57:34 +00:00
BYTE __stdcall IO_F8xx ( WORD programcounter , WORD address , BYTE write , BYTE value , ULONG nCycles ) // NSC for Apple II/II+ (GH#827)
{
2021-04-18 10:23:06 +00:00
if ( IS_APPLE2 & & g_NoSlotClock & & ! SW_HIGHRAM & & ! SW_WRITERAM )
2020-11-25 21:57:34 +00:00
{
if ( g_NoSlotClock - > ReadWrite ( address , value , write ) )
return value ;
}
//
if ( ! write )
{
return * ( mem + address ) ;
}
else
{
memdirty [ address > > 8 ] = 0xFF ;
LPBYTE page = memwrite [ address > > 8 ] ;
if ( page )
* ( page + ( address & 0xFF ) ) = value ;
return 0 ;
}
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2007-05-28 11:16:42 +00:00
2013-03-10 23:44:30 +00:00
static struct SlotInfo
{
bool bHasCard ;
iofunction IOReadCx ;
iofunction IOWriteCx ;
} g_SlotInfo [ NUM_SLOTS ] = { 0 } ;
2007-05-28 11:16:42 +00:00
static void InitIoHandlers ( )
{
UINT i = 0 ;
for ( ; i < 8 ; i + + ) // C00x..C07x
{
IORead [ i ] = IORead_C0xx [ i ] ;
IOWrite [ i ] = IOWrite_C0xx [ i ] ;
}
for ( ; i < 16 ; i + + ) // C08x..C0Fx
{
IORead [ i ] = IO_Null ;
IOWrite [ i ] = IO_Null ;
}
//
for ( ; i < 256 ; i + + ) // C10x..CFFx
{
2017-05-21 21:06:37 +00:00
IORead [ i ] = IO_Cxxx ;
IOWrite [ i ] = IO_Cxxx ;
2007-05-28 11:16:42 +00:00
}
//
for ( i = 0 ; i < NUM_SLOTS ; i + + )
2013-03-10 23:44:30 +00:00
{
g_SlotInfo [ i ] . bHasCard = false ;
2017-05-21 21:06:37 +00:00
g_SlotInfo [ i ] . IOReadCx = IO_Cxxx ;
g_SlotInfo [ i ] . IOWriteCx = IO_Cxxx ;
2007-05-28 11:16:42 +00:00
ExpansionRom [ i ] = NULL ;
2013-03-10 23:44:30 +00:00
}
2007-05-28 11:16:42 +00:00
}
// All slots [0..7] must register their handlers
void RegisterIoHandler ( UINT uSlot , iofunction IOReadC0 , iofunction IOWriteC0 , iofunction IOReadCx , iofunction IOWriteCx , LPVOID lpSlotParameter , BYTE * pExpansionRom )
{
_ASSERT ( uSlot < NUM_SLOTS ) ;
SlotParameters [ uSlot ] = lpSlotParameter ;
IORead [ uSlot + 8 ] = IOReadC0 ;
IOWrite [ uSlot + 8 ] = IOWriteC0 ;
if ( uSlot = = 0 ) // Don't trash C0xx handlers
return ;
2017-05-21 21:06:37 +00:00
if ( IOReadCx = = NULL ) IOReadCx = IO_Cxxx ;
if ( IOWriteCx = = NULL ) IOWriteCx = IO_Cxxx ;
2007-05-28 11:16:42 +00:00
for ( UINT i = 0 ; i < 16 ; i + + )
{
IORead [ uSlot * 16 + i ] = IOReadCx ;
IOWrite [ uSlot * 16 + i ] = IOWriteCx ;
}
2013-03-10 23:44:30 +00:00
g_SlotInfo [ uSlot ] . bHasCard = true ;
g_SlotInfo [ uSlot ] . IOReadCx = IOReadCx ;
g_SlotInfo [ uSlot ] . IOWriteCx = IOWriteCx ;
2007-05-28 11:16:42 +00:00
// What about [$C80x..$CFEx]? - Do any cards use this as I/O memory?
ExpansionRom [ uSlot ] = pExpansionRom ;
2006-02-25 20:50:29 +00:00
}
2021-11-01 20:12:42 +00:00
void UnregisterIoHandler ( UINT uSlot )
{
RegisterIoHandler ( uSlot , NULL , NULL , NULL , NULL , NULL , NULL ) ;
g_SlotInfo [ uSlot ] . bHasCard = false ;
}
2018-04-06 21:36:54 +00:00
// From UTAIIe:5-28: Since INTCXROM==1 then state of SLOTC3ROM is not important
2013-03-10 23:44:30 +00:00
static void IoHandlerCardsOut ( void )
{
2018-04-06 21:36:54 +00:00
_ASSERT ( SW_INTCXROM ) ;
2017-05-13 21:07:53 +00:00
2013-03-10 23:44:30 +00:00
for ( UINT uSlot = 1 ; uSlot < NUM_SLOTS ; uSlot + + )
{
for ( UINT i = 0 ; i < 16 ; i + + )
{
2017-05-21 21:06:37 +00:00
IORead [ uSlot * 16 + i ] = IO_Cxxx ;
IOWrite [ uSlot * 16 + i ] = IO_Cxxx ;
2013-03-10 23:44:30 +00:00
}
}
}
static void IoHandlerCardsIn ( void )
2012-01-21 14:36:35 +00:00
{
2018-04-06 21:36:54 +00:00
_ASSERT ( ! SW_INTCXROM ) ;
2017-05-13 21:07:53 +00:00
2013-03-10 23:44:30 +00:00
for ( UINT uSlot = 1 ; uSlot < NUM_SLOTS ; uSlot + + )
{
2017-05-13 21:07:53 +00:00
iofunction ioreadcx = g_SlotInfo [ uSlot ] . IOReadCx ;
iofunction iowritecx = g_SlotInfo [ uSlot ] . IOWriteCx ;
if ( uSlot = = 3 & & ! SW_SLOTC3ROM )
{
2018-04-06 21:36:54 +00:00
// From UTAIIe:5-28: If INTCXROM==0 && SLOTC3ROM==0 Then $C300-C3FF is internal ROM
2017-05-21 21:06:37 +00:00
ioreadcx = IO_Cxxx ;
iowritecx = IO_Cxxx ;
2017-05-13 21:07:53 +00:00
}
2013-03-10 23:44:30 +00:00
for ( UINT i = 0 ; i < 16 ; i + + )
{
2017-05-13 21:07:53 +00:00
IORead [ uSlot * 16 + i ] = ioreadcx ;
IOWrite [ uSlot * 16 + i ] = iowritecx ;
2013-03-10 23:44:30 +00:00
}
}
}
2012-01-21 14:36:35 +00:00
2013-03-10 23:44:30 +00:00
static bool IsCardInSlot ( const UINT uSlot )
{
return g_SlotInfo [ uSlot ] . bHasCard ;
2012-01-21 14:36:35 +00:00
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2007-05-28 11:16:42 +00:00
2018-03-20 01:49:08 +00:00
DWORD GetMemMode ( void )
{
return memmode ;
}
2018-10-26 18:23:30 +00:00
void SetMemMode ( DWORD uNewMemMode )
2013-07-11 21:21:58 +00:00
{
# if defined(_DEBUG) && 0
static DWORD dwOldDiff = 0 ;
DWORD dwDiff = memmode ^ uNewMemMode ;
2018-04-06 21:36:54 +00:00
dwDiff & = ~ ( MF_SLOTC3ROM | MF_INTCXROM ) ;
2013-07-11 21:21:58 +00:00
if ( dwOldDiff ! = dwDiff )
{
dwOldDiff = dwDiff ;
char szStr [ 100 ] ;
char * psz = szStr ;
psz + = sprintf ( psz , " diff = %08X " , dwDiff ) ;
psz + = sprintf ( psz , " 80=%d " , SW_80STORE ? 1 : 0 ) ;
psz + = sprintf ( psz , " ALTZP=%d " , SW_ALTZP ? 1 : 0 ) ;
psz + = sprintf ( psz , " AUXR=%d " , SW_AUXREAD ? 1 : 0 ) ;
psz + = sprintf ( psz , " AUXW=%d " , SW_AUXWRITE ? 1 : 0 ) ;
psz + = sprintf ( psz , " BANK2=%d " , SW_BANK2 ? 1 : 0 ) ;
psz + = sprintf ( psz , " HIRAM=%d " , SW_HIGHRAM ? 1 : 0 ) ;
psz + = sprintf ( psz , " HIRES=%d " , SW_HIRES ? 1 : 0 ) ;
psz + = sprintf ( psz , " PAGE2=%d " , SW_PAGE2 ? 1 : 0 ) ;
psz + = sprintf ( psz , " C3=%d " , SW_SLOTC3ROM ? 1 : 0 ) ;
2018-04-06 21:36:54 +00:00
psz + = sprintf ( psz , " CX=%d " , SW_INTCXROM ? 1 : 0 ) ;
2013-07-11 21:21:58 +00:00
psz + = sprintf ( psz , " WRAM=%d " , SW_WRITERAM ? 1 : 0 ) ;
psz + = sprintf ( psz , " \n " ) ;
OutputDebugString ( szStr ) ;
}
# endif
memmode = uNewMemMode ;
}
//===========================================================================
2016-03-21 23:48:02 +00:00
static void ResetPaging ( BOOL initialize ) ;
static void UpdatePaging ( BOOL initialize ) ;
// Call by:
2018-03-20 01:49:08 +00:00
// . CtrlReset() Soft-reset (Ctrl+Reset) for //e
2016-03-21 23:48:02 +00:00
void MemResetPaging ( )
{
ResetPaging ( 0 ) ; // Initialize=0
}
2014-09-28 21:04:12 +00:00
static void ResetPaging ( BOOL initialize )
2007-05-28 11:16:42 +00:00
{
2018-10-26 18:23:30 +00:00
SetLastRamWrite ( 0 ) ;
2018-11-04 15:07:46 +00:00
2020-10-11 16:34:44 +00:00
if ( IsApple2PlusOrClone ( GetApple2Type ( ) ) & & GetCardMgr ( ) . QuerySlot ( SLOT0 ) = = CT_Empty )
2018-11-04 15:07:46 +00:00
SetMemMode ( 0 ) ;
else
SetMemMode ( LanguageCardUnit : : kMemModeInitialState ) ;
2014-09-28 21:04:12 +00:00
UpdatePaging ( initialize ) ;
2006-02-25 20:50:29 +00:00
}
2007-05-28 11:16:42 +00:00
//===========================================================================
2013-09-14 21:46:39 +00:00
void MemUpdatePaging ( BOOL initialize )
{
2014-09-28 21:04:12 +00:00
UpdatePaging ( initialize ) ;
2013-09-14 21:46:39 +00:00
}
2014-09-28 21:04:12 +00:00
static void UpdatePaging ( BOOL initialize )
2007-05-28 11:16:42 +00:00
{
2018-11-09 20:51:51 +00:00
modechanging = 0 ;
2007-05-28 11:16:42 +00:00
// SAVE THE CURRENT PAGING SHADOW TABLE
LPBYTE oldshadow [ 256 ] ;
2014-09-28 21:04:12 +00:00
if ( ! initialize )
2020-12-12 11:09:14 +00:00
memcpy ( oldshadow , memshadow , 256 * sizeof ( LPBYTE ) ) ;
2007-05-28 11:16:42 +00:00
// UPDATE THE PAGING TABLES BASED ON THE NEW PAGING SWITCH VALUES
UINT loop ;
if ( initialize )
{
for ( loop = 0x00 ; loop < 0xC0 ; loop + + )
memwrite [ loop ] = mem + ( loop < < 8 ) ;
for ( loop = 0xC0 ; loop < 0xD0 ; loop + + )
memwrite [ loop ] = NULL ;
}
2014-09-28 21:04:12 +00:00
for ( loop = 0x00 ; loop < 0x02 ; loop + + )
memshadow [ loop ] = SW_ALTZP ? memaux + ( loop < < 8 ) : memmain + ( loop < < 8 ) ;
2006-02-25 20:50:29 +00:00
2007-05-28 11:16:42 +00:00
for ( loop = 0x02 ; loop < 0xC0 ; loop + + )
{
memshadow [ loop ] = SW_AUXREAD ? memaux + ( loop < < 8 )
: memmain + ( loop < < 8 ) ;
memwrite [ loop ] = ( ( SW_AUXREAD ! = 0 ) = = ( SW_AUXWRITE ! = 0 ) )
? mem + ( loop < < 8 )
: SW_AUXWRITE ? memaux + ( loop < < 8 )
: memmain + ( loop < < 8 ) ;
}
2014-09-28 21:04:12 +00:00
for ( loop = 0xC0 ; loop < 0xC8 ; loop + + )
2007-05-28 11:16:42 +00:00
{
2018-09-16 21:02:35 +00:00
memdirty [ loop ] = 0 ; // mem(cache) can't be dirty for ROM (but STA $Csnn will set the dirty flag)
2014-09-28 21:04:12 +00:00
const UINT uSlotOffset = ( loop & 0x0f ) * 0x100 ;
if ( loop = = 0xC3 )
2018-04-06 21:36:54 +00:00
memshadow [ loop ] = ( SW_SLOTC3ROM & & ! SW_INTCXROM ) ? pCxRomPeripheral + uSlotOffset // C300..C3FF - Slot 3 ROM (all 0x00's)
2014-09-28 21:04:12 +00:00
: pCxRomInternal + uSlotOffset ; // C300..C3FF - Internal ROM
else
2018-04-06 21:36:54 +00:00
memshadow [ loop ] = ! SW_INTCXROM ? pCxRomPeripheral + uSlotOffset // C000..C7FF - SSC/Disk][/etc
2014-09-28 21:04:12 +00:00
: pCxRomInternal + uSlotOffset ; // C000..C7FF - Internal ROM
}
2007-05-28 11:16:42 +00:00
2014-09-28 21:04:12 +00:00
for ( loop = 0xC8 ; loop < 0xD0 ; loop + + )
{
2018-09-16 21:02:35 +00:00
memdirty [ loop ] = 0 ; // mem(cache) can't be dirty for ROM (but STA $Cnnn will set the dirty flag)
2014-09-28 21:04:12 +00:00
const UINT uRomOffset = ( loop & 0x0f ) * 0x100 ;
2018-04-06 21:36:54 +00:00
memshadow [ loop ] = ( ! SW_INTCXROM & & ! INTC8ROM ) ? pCxRomPeripheral + uRomOffset // C800..CFFF - Peripheral ROM (GH#486)
2017-09-22 21:23:13 +00:00
: pCxRomInternal + uRomOffset ; // C800..CFFF - Internal ROM
2007-05-28 11:16:42 +00:00
}
2020-07-06 19:52:31 +00:00
const int selectedrompage = ( SW_ALTROM0 ? 1 : 0 ) | ( SW_ALTROM1 ? 2 : 0 ) ;
# ifdef _DEBUG
if ( selectedrompage ) { _ASSERT ( IsCopamBase64A ( GetApple2Type ( ) ) ) ; }
# endif
const int romoffset = ( selectedrompage % memrompages ) * Apple2RomSize ; // Only Copam Base64A has a non-zero romoffset
2007-05-28 11:16:42 +00:00
for ( loop = 0xD0 ; loop < 0xE0 ; loop + + )
{
2020-07-06 19:52:31 +00:00
const int bankoffset = ( SW_BANK2 ? 0 : 0x1000 ) ;
2007-05-28 11:16:42 +00:00
memshadow [ loop ] = SW_HIGHRAM ? SW_ALTZP ? memaux + ( loop < < 8 ) - bankoffset
2018-10-26 18:23:30 +00:00
: g_pMemMainLanguageCard + ( ( loop - 0xC0 ) < < 8 ) - bankoffset
2020-07-06 19:24:16 +00:00
: memrom + ( ( loop - 0xD0 ) * 0x100 ) + romoffset ;
2007-05-28 11:16:42 +00:00
memwrite [ loop ] = SW_WRITERAM ? SW_HIGHRAM ? mem + ( loop < < 8 )
: SW_ALTZP ? memaux + ( loop < < 8 ) - bankoffset
2018-10-26 18:23:30 +00:00
: g_pMemMainLanguageCard + ( ( loop - 0xC0 ) < < 8 ) - bankoffset
2007-05-28 11:16:42 +00:00
: NULL ;
}
for ( loop = 0xE0 ; loop < 0x100 ; loop + + )
{
memshadow [ loop ] = SW_HIGHRAM ? SW_ALTZP ? memaux + ( loop < < 8 )
2018-10-26 18:23:30 +00:00
: g_pMemMainLanguageCard + ( ( loop - 0xC0 ) < < 8 )
2020-07-06 19:24:16 +00:00
: memrom + ( ( loop - 0xD0 ) * 0x100 ) + romoffset ;
2007-05-28 11:16:42 +00:00
memwrite [ loop ] = SW_WRITERAM ? SW_HIGHRAM ? mem + ( loop < < 8 )
: SW_ALTZP ? memaux + ( loop < < 8 )
2018-10-26 18:23:30 +00:00
: g_pMemMainLanguageCard + ( ( loop - 0xC0 ) < < 8 )
2007-05-28 11:16:42 +00:00
: NULL ;
}
if ( SW_80STORE )
{
for ( loop = 0x04 ; loop < 0x08 ; loop + + )
{
memshadow [ loop ] = SW_PAGE2 ? memaux + ( loop < < 8 )
: memmain + ( loop < < 8 ) ;
memwrite [ loop ] = mem + ( loop < < 8 ) ;
}
if ( SW_HIRES )
{
for ( loop = 0x20 ; loop < 0x40 ; loop + + )
{
memshadow [ loop ] = SW_PAGE2 ? memaux + ( loop < < 8 )
: memmain + ( loop < < 8 ) ;
memwrite [ loop ] = mem + ( loop < < 8 ) ;
}
}
}
// MOVE MEMORY BACK AND FORTH AS NECESSARY BETWEEN THE SHADOW AREAS AND
// THE MAIN RAM IMAGE TO KEEP BOTH SETS OF MEMORY CONSISTENT WITH THE NEW
// PAGING SHADOW TABLE
2013-07-11 21:21:58 +00:00
//
// NB. the condition 'loop <= 1' is there because:
// . Page0 (ZP) : memdirty[0] is set when the 6502 CPU does a ZP-write, but perhaps older versions didn't set this flag (eg. the asm version?).
// . Page1 (stack) : memdirty[1] is NOT set when the 6502 CPU writes to this page with JSR, etc.
2014-09-28 21:04:12 +00:00
for ( loop = 0x00 ; loop < 0x100 ; loop + + )
2007-05-28 11:16:42 +00:00
{
2014-09-28 21:04:12 +00:00
if ( initialize | | ( oldshadow [ loop ] ! = memshadow [ loop ] ) )
2007-05-28 11:16:42 +00:00
{
2014-09-28 21:04:12 +00:00
if ( ! initialize & &
( ( * ( memdirty + loop ) & 1 ) | | ( loop < = 1 ) ) )
2007-05-28 11:16:42 +00:00
{
2014-09-28 21:04:12 +00:00
* ( memdirty + loop ) & = ~ 1 ;
2020-12-12 11:09:14 +00:00
memcpy ( oldshadow [ loop ] , mem + ( loop < < 8 ) , 256 ) ;
2007-05-28 11:16:42 +00:00
}
2014-09-28 21:04:12 +00:00
2020-12-12 11:09:14 +00:00
memcpy ( mem + ( loop < < 8 ) , memshadow [ loop ] , 256 ) ;
2007-05-28 11:16:42 +00:00
}
}
2006-02-25 20:50:29 +00:00
}
//
// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE -----
//
//===========================================================================
2007-05-28 11:16:42 +00:00
2014-09-28 21:04:12 +00:00
void MemDestroy ( )
2007-05-28 11:16:42 +00:00
{
2020-12-10 21:08:15 +00:00
ALIGNED_FREE ( memaux ) ;
ALIGNED_FREE ( memmain ) ;
ALIGNED_FREE ( memimage ) ;
delete [ ] memdirty ;
delete [ ] memrom ;
2007-05-28 11:16:42 +00:00
2020-12-10 21:08:15 +00:00
delete [ ] pCxRomInternal ;
delete [ ] pCxRomPeripheral ;
2007-05-28 11:16:42 +00:00
2006-02-25 20:50:29 +00:00
# ifdef RAMWORKS
for ( UINT i = 1 ; i < g_uMaxExPages ; i + + )
{
if ( RWpages [ i ] )
{
2020-12-10 21:08:15 +00:00
ALIGNED_FREE ( RWpages [ i ] ) ;
2006-02-25 20:50:29 +00:00
RWpages [ i ] = NULL ;
}
}
RWpages [ 0 ] = NULL ;
# endif
2007-05-28 11:16:42 +00:00
2018-10-26 18:23:30 +00:00
delete g_pLanguageCard ;
g_pLanguageCard = NULL ;
2007-05-28 11:16:42 +00:00
memaux = NULL ;
memmain = NULL ;
memdirty = NULL ;
memrom = NULL ;
memimage = NULL ;
pCxRomInternal = NULL ;
pCxRomPeripheral = NULL ;
mem = NULL ;
2020-12-10 21:08:15 +00:00
memset ( memwrite , 0 , sizeof ( memwrite ) ) ;
memset ( memshadow , 0 , sizeof ( memshadow ) ) ;
2006-02-25 20:50:29 +00:00
}
2006-03-12 09:05:39 +00:00
//===========================================================================
2017-05-13 21:07:53 +00:00
bool MemCheckSLOTC3ROM ( )
{
return SW_SLOTC3ROM ? true : false ;
}
2018-04-06 21:36:54 +00:00
bool MemCheckINTCXROM ( )
2007-05-28 11:16:42 +00:00
{
2018-04-06 21:36:54 +00:00
return SW_INTCXROM ? true : false ;
2007-05-28 11:16:42 +00:00
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2013-07-11 21:21:58 +00:00
2018-09-16 21:02:35 +00:00
static void BackMainImage ( void )
{
for ( UINT loop = 0 ; loop < 256 ; loop + + )
{
if ( memshadow [ loop ] & & ( ( * ( memdirty + loop ) & 1 ) | | ( loop < = 1 ) ) )
2020-12-12 11:09:14 +00:00
memcpy ( memshadow [ loop ] , mem + ( loop < < 8 ) , 256 ) ;
2018-09-16 21:02:35 +00:00
* ( memdirty + loop ) & = ~ 1 ;
}
}
//===========================================================================
2013-07-13 21:32:08 +00:00
static LPBYTE MemGetPtrBANK1 ( const WORD offset , const LPBYTE pMemBase )
{
if ( ( offset & 0xF000 ) ! = 0xC000 ) // Requesting RAM at physical addr $Cxxx (ie. 4K RAM BANK1)
return NULL ;
2016-03-21 23:48:02 +00:00
// NB. This works for memaux when set to any RWpages[] value, ie. RamWork III "just works"
2013-07-13 21:32:08 +00:00
const BYTE bank1page = ( offset > > 8 ) & 0xF ;
return ( memshadow [ 0xD0 + bank1page ] = = pMemBase + ( 0xC0 + bank1page ) * 256 )
? mem + offset + 0x1000 // Return ptr to $Dxxx address - 'mem' has (a potentially dirty) 4K RAM BANK1 mapped in at $D000
: pMemBase + offset ; // Else return ptr to $Cxxx address
}
//-------------------------------------
2013-07-11 21:21:58 +00:00
LPBYTE MemGetAuxPtr ( const WORD offset )
2006-02-25 20:50:29 +00:00
{
2013-07-13 21:32:08 +00:00
LPBYTE lpMem = MemGetPtrBANK1 ( offset , memaux ) ;
if ( lpMem )
return lpMem ;
2013-07-11 21:21:58 +00:00
2013-07-13 21:32:08 +00:00
lpMem = ( memshadow [ ( offset > > 8 ) ] = = ( memaux + ( offset & 0xFF00 ) ) )
2013-07-11 21:21:58 +00:00
? mem + offset // Return 'mem' copy if possible, as page could be dirty
2006-02-25 20:50:29 +00:00
: memaux + offset ;
# ifdef RAMWORKS
2018-09-10 20:28:08 +00:00
// Video scanner (for 14M video modes) always fetches from 1st 64K aux bank (UTAIIe ref?)
2020-12-28 16:25:29 +00:00
if ( ( ( SW_PAGE2 & & SW_80STORE ) | | GetVideo ( ) . VideoGetSW80COL ( ) ) & &
2018-09-10 20:28:08 +00:00
(
( ( ( offset & 0xFF00 ) > = 0x0400 ) & & ( ( offset & 0xFF00 ) < = 0x0700 ) ) | |
( SW_HIRES & & ( ( offset & 0xFF00 ) > = 0x2000 ) & & ( ( offset & 0xFF00 ) < = 0x3F00 ) )
)
)
{
2007-05-28 11:16:42 +00:00
lpMem = ( memshadow [ ( offset > > 8 ) ] = = ( RWpages [ 0 ] + ( offset & 0xFF00 ) ) )
2006-02-25 20:50:29 +00:00
? mem + offset
: RWpages [ 0 ] + offset ;
}
# endif
return lpMem ;
}
2013-07-13 21:32:08 +00:00
//-------------------------------------
2013-07-11 21:21:58 +00:00
2018-09-16 21:02:35 +00:00
// if memshadow == memmain
// so RD memmain
// case: RD == WR
// so RD(mem),WR(mem)
// so 64K memmain could be incorrect
// *therefore mem is correct
// case: RD != WR
// so RD(mem),WR(memaux)
// doesn't matter since RD != WR, then it's guaranteed that memaux is correct
// *therefore either mem or memmain is correct
// else ; memshadow != memmain
// so RD memaux (or ROM)
// case: RD == WR
// so RD(mem),WR(mem)
// so 64K memaux could be incorrect
// *therefore memmain is correct
// case: RD != WR
// so RD(mem),WR(memmain)
// doesn't matter since RD != WR, then it's guaranteed that memmain is correct
// *therefore memmain is correct
//
// *OR*
//
// Is the mem(cache) setup to read (via memshadow) from memmain?
// . if yes, then return the mem(cache) address as writes (via memwrite) may've made the mem(cache) dirty.
// . if no, then return memmain, as the mem(cache) isn't involved in memmain (any writes will go directly to this backing-store).
//
2013-07-11 21:21:58 +00:00
LPBYTE MemGetMainPtr ( const WORD offset )
2007-05-28 11:16:42 +00:00
{
2013-07-13 21:32:08 +00:00
LPBYTE lpMem = MemGetPtrBANK1 ( offset , memmain ) ;
if ( lpMem )
return lpMem ;
2013-07-11 21:21:58 +00:00
return ( memshadow [ ( offset > > 8 ) ] = = ( memmain + ( offset & 0xFF00 ) ) )
? mem + offset // Return 'mem' copy if possible, as page could be dirty
: memmain + offset ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2007-05-28 11:16:42 +00:00
2018-09-16 21:02:35 +00:00
// Used by:
// . Savestate: MemSaveSnapshotMemory(), MemLoadSnapshotAux()
// . Debugger : CmdMemorySave(), CmdMemoryLoad()
2013-04-26 21:55:45 +00:00
LPBYTE MemGetBankPtr ( const UINT nBank )
{
2013-08-30 21:43:37 +00:00
BackMainImage ( ) ; // Flush any dirty pages to back-buffer
2013-04-26 21:55:45 +00:00
2013-08-30 21:43:37 +00:00
# ifdef RAMWORKS
2013-04-26 21:55:45 +00:00
if ( nBank > g_uMaxExPages )
return NULL ;
2013-08-30 21:43:37 +00:00
if ( nBank = = 0 )
return memmain ;
2013-04-26 21:55:45 +00:00
return RWpages [ nBank - 1 ] ;
2013-08-30 21:43:37 +00:00
# else
return ( nBank = = 0 ) ? memmain :
( nBank = = 1 ) ? memaux :
NULL ;
# endif
2013-04-26 21:55:45 +00:00
}
//===========================================================================
2007-08-06 21:38:35 +00:00
LPBYTE MemGetCxRomPeripheral ( )
{
return pCxRomPeripheral ;
}
//===========================================================================
2017-03-10 22:00:01 +00:00
// Post:
// . true: code memory
// . false: I/O memory or floating bus
bool MemIsAddrCodeMemory ( const USHORT addr )
{
if ( addr < 0xC000 | | addr > FIRMWARE_EXPANSION_END ) // Assume all A][ types have at least 48K
return true ;
if ( addr < APPLE_SLOT_BEGIN ) // [$C000..C0FF]
return false ;
2018-04-06 21:36:54 +00:00
if ( ! IS_APPLE2 & & SW_INTCXROM ) // [$C100..C7FF] //e or Enhanced //e internal ROM
2017-03-10 22:00:01 +00:00
return true ;
if ( ! IS_APPLE2 & & ! SW_SLOTC3ROM & & ( addr > > 8 ) = = 0xC3 ) // [$C300..C3FF] //e or Enhanced //e internal ROM
return true ;
if ( addr < = APPLE_SLOT_END ) // [$C100..C7FF]
{
const UINT uSlot = ( addr > > 8 ) & 0x7 ;
2017-03-18 15:18:14 +00:00
return IsCardInSlot ( uSlot ) ;
2017-03-10 22:00:01 +00:00
}
// [$C800..CFFF]
if ( g_eExpansionRomType = = eExpRomNull )
2017-03-12 21:45:55 +00:00
{
2017-05-21 16:35:35 +00:00
if ( IO_SELECT | | INTC8ROM ) // Was at $Csxx and now in [$C800..$CFFF]
2017-03-12 21:45:55 +00:00
return true ;
2017-03-10 22:00:01 +00:00
return false ;
2017-03-12 21:45:55 +00:00
}
2017-03-10 22:00:01 +00:00
return true ;
}
//===========================================================================
2012-03-20 23:17:06 +00:00
void MemInitialize ( )
2007-05-28 11:16:42 +00:00
{
// ALLOCATE MEMORY FOR THE APPLE MEMORY IMAGE AND ASSOCIATED DATA STRUCTURES
2020-12-10 21:08:15 +00:00
memaux = ALIGNED_ALLOC ( _6502_MEM_LEN ) ;
memmain = ALIGNED_ALLOC ( _6502_MEM_LEN ) ;
memimage = ALIGNED_ALLOC ( _6502_MEM_LEN ) ;
2007-05-28 11:16:42 +00:00
2020-12-10 21:08:15 +00:00
memdirty = new BYTE [ 0x100 ] ;
memrom = new BYTE [ 0x3000 * MaxRomPages ] ;
pCxRomInternal = new BYTE [ CxRomSize ] ;
pCxRomPeripheral = new BYTE [ CxRomSize ] ;
2007-05-28 11:16:42 +00:00
if ( ! memaux | | ! memdirty | | ! memimage | | ! memmain | | ! memrom | | ! pCxRomInternal | | ! pCxRomPeripheral )
2006-06-27 02:34:46 +00:00
{
2021-01-19 20:37:43 +00:00
GetFrame ( ) . FrameMessageBox (
2006-06-27 02:34:46 +00:00
TEXT ( " The emulator was unable to allocate the memory it " )
TEXT ( " requires. Further execution is not possible. " ) ,
2019-09-07 09:16:51 +00:00
g_pAppTitle . c_str ( ) ,
2006-06-27 02:34:46 +00:00
MB_ICONSTOP | MB_SETFOREGROUND ) ;
ExitProcess ( 1 ) ;
}
2018-10-26 18:23:30 +00:00
RWpages [ 0 ] = memaux ;
SetExpansionMemTypeDefault ( ) ;
2016-03-21 23:48:02 +00:00
2018-10-26 18:23:30 +00:00
# ifdef RAMWORKS
2020-10-11 16:34:44 +00:00
if ( GetCardMgr ( ) . QueryAux ( ) = = CT_RamWorksIII )
2018-10-26 18:23:30 +00:00
{
// allocate memory for RAMWorks III - up to 8MB
g_uActiveBank = 0 ;
UINT i = 1 ;
2020-12-10 21:08:15 +00:00
while ( ( i < g_uMaxExPages ) & & ( RWpages [ i ] = ALIGNED_ALLOC ( _6502_MEM_LEN ) ) )
2018-10-26 18:23:30 +00:00
i + + ;
while ( i < kMaxExMemoryBanks )
RWpages [ i + + ] = NULL ;
}
2006-02-25 20:50:29 +00:00
# endif
2018-10-26 18:23:30 +00:00
//
2017-04-27 21:02:02 +00:00
2018-11-09 20:51:51 +00:00
CreateLanguageCard ( ) ;
2016-03-21 23:48:02 +00:00
MemInitializeROM ( ) ;
2020-03-25 23:05:02 +00:00
MemInitializeCustomROM ( ) ;
2016-03-21 23:48:02 +00:00
MemInitializeCustomF8ROM ( ) ;
MemInitializeIO ( ) ;
MemReset ( ) ;
}
void MemInitializeROM ( void )
{
2006-06-27 02:34:46 +00:00
// READ THE APPLE FIRMWARE ROMS INTO THE ROM IMAGE
2007-05-28 11:16:42 +00:00
UINT ROM_SIZE = 0 ;
2021-01-19 20:37:43 +00:00
WORD resourceId = 0 ;
2007-05-28 11:16:42 +00:00
switch ( g_Apple2Type )
{
2021-01-19 20:37:43 +00:00
case A2TYPE_APPLE2 : resourceId = IDR_APPLE2_ROM ; ROM_SIZE = Apple2RomSize ; break ;
case A2TYPE_APPLE2PLUS : resourceId = IDR_APPLE2_PLUS_ROM ; ROM_SIZE = Apple2RomSize ; break ;
case A2TYPE_APPLE2JPLUS : resourceId = IDR_APPLE2_JPLUS_ROM ; ROM_SIZE = Apple2RomSize ; break ;
case A2TYPE_APPLE2E : resourceId = IDR_APPLE2E_ROM ; ROM_SIZE = Apple2eRomSize ; break ;
case A2TYPE_APPLE2EENHANCED : resourceId = IDR_APPLE2E_ENHANCED_ROM ; ROM_SIZE = Apple2eRomSize ; break ;
case A2TYPE_PRAVETS82 : resourceId = IDR_PRAVETS_82_ROM ; ROM_SIZE = Apple2RomSize ; break ;
case A2TYPE_PRAVETS8M : resourceId = IDR_PRAVETS_8M_ROM ; ROM_SIZE = Apple2RomSize ; break ;
case A2TYPE_PRAVETS8A : resourceId = IDR_PRAVETS_8C_ROM ; ROM_SIZE = Apple2eRomSize ; break ;
case A2TYPE_TK30002E : resourceId = IDR_TK3000_2E_ROM ; ROM_SIZE = Apple2eRomSize ; break ;
case A2TYPE_BASE64A : resourceId = IDR_BASE_64A_ROM ; ROM_SIZE = Base64ARomSize ; break ;
2007-05-28 11:16:42 +00:00
}
2006-03-13 23:46:57 +00:00
2021-01-19 20:37:43 +00:00
BYTE * pData = NULL ;
if ( resourceId )
{
pData = GetFrame ( ) . GetResource ( resourceId , " ROM " , ROM_SIZE ) ;
}
if ( pData = = NULL )
2006-02-26 01:20:36 +00:00
{
2006-06-27 02:34:46 +00:00
TCHAR sRomFileName [ MAX_PATH ] ;
2007-05-28 11:16:42 +00:00
switch ( g_Apple2Type )
{
2014-07-14 04:31:28 +00:00
case A2TYPE_APPLE2 : _tcscpy ( sRomFileName , TEXT ( " APPLE2.ROM " ) ) ; break ;
case A2TYPE_APPLE2PLUS : _tcscpy ( sRomFileName , TEXT ( " APPLE2_PLUS.ROM " ) ) ; break ;
2020-04-02 19:17:32 +00:00
case A2TYPE_APPLE2JPLUS : _tcscpy ( sRomFileName , TEXT ( " APPLE2_JPLUS.ROM " ) ) ; break ;
2014-07-14 04:31:28 +00:00
case A2TYPE_APPLE2E : _tcscpy ( sRomFileName , TEXT ( " APPLE2E.ROM " ) ) ; break ;
2012-09-16 21:53:07 +00:00
case A2TYPE_APPLE2EENHANCED : _tcscpy ( sRomFileName , TEXT ( " APPLE2E_ENHANCED.ROM " ) ) ; break ;
2014-07-14 04:31:28 +00:00
case A2TYPE_PRAVETS82 : _tcscpy ( sRomFileName , TEXT ( " PRAVETS82.ROM " ) ) ; break ;
case A2TYPE_PRAVETS8M : _tcscpy ( sRomFileName , TEXT ( " PRAVETS8M.ROM " ) ) ; break ;
case A2TYPE_PRAVETS8A : _tcscpy ( sRomFileName , TEXT ( " PRAVETS8C.ROM " ) ) ; break ;
2016-10-22 22:20:23 +00:00
case A2TYPE_TK30002E : _tcscpy ( sRomFileName , TEXT ( " TK3000e.ROM " ) ) ; break ;
2020-07-06 19:24:16 +00:00
case A2TYPE_BASE64A : _tcscpy ( sRomFileName , TEXT ( " BASE64A.ROM " ) ) ; break ;
2014-07-14 04:31:28 +00:00
default :
2012-03-20 23:17:06 +00:00
{
_tcscpy ( sRomFileName , TEXT ( " Unknown type! " ) ) ;
2020-12-20 15:32:51 +00:00
GetPropertySheet ( ) . ConfigSaveApple2Type ( A2TYPE_APPLE2EENHANCED ) ;
2012-03-20 23:17:06 +00:00
}
2007-05-28 11:16:42 +00:00
}
2006-06-27 02:34:46 +00:00
2018-01-26 11:03:44 +00:00
TCHAR sText [ MAX_PATH ] ;
2019-08-25 18:21:33 +00:00
StringCbPrintf ( sText , sizeof ( sText ) , TEXT ( " Unable to open the required firmware ROM data file. \n \n File: %s " ) , sRomFileName ) ;
2018-01-26 11:03:44 +00:00
LogFileOutput ( " %s \n " , sText ) ;
2006-02-26 01:20:36 +00:00
2021-01-19 20:37:43 +00:00
GetFrame ( ) . FrameMessageBox (
2006-06-27 02:34:46 +00:00
sText ,
2019-09-07 09:16:51 +00:00
g_pAppTitle . c_str ( ) ,
2006-06-27 02:34:46 +00:00
MB_ICONSTOP | MB_SETFOREGROUND ) ;
2018-01-26 11:03:44 +00:00
2006-02-26 01:20:36 +00:00
ExitProcess ( 1 ) ;
}
2007-05-28 11:16:42 +00:00
memset ( pCxRomInternal , 0 , CxRomSize ) ;
memset ( pCxRomPeripheral , 0 , CxRomSize ) ;
if ( ROM_SIZE = = Apple2eRomSize )
{
memcpy ( pCxRomInternal , pData , CxRomSize ) ;
pData + = CxRomSize ;
ROM_SIZE - = CxRomSize ;
}
2020-07-06 19:24:16 +00:00
memrompages = MAX ( MaxRomPages , ROM_SIZE / Apple2RomSize ) ;
_ASSERT ( ROM_SIZE % Apple2RomSize = = 0 ) ;
memcpy ( memrom , pData , ROM_SIZE ) ; // ROM at $D000...$FFFF, one or several pages
2016-03-21 23:48:02 +00:00
}
2008-02-22 21:28:35 +00:00
2016-03-21 23:48:02 +00:00
void MemInitializeCustomF8ROM ( void )
{
2008-02-22 21:28:35 +00:00
const UINT F8RomSize = 0x800 ;
2018-11-04 15:07:46 +00:00
const UINT F8RomOffset = Apple2RomSize - F8RomSize ;
2021-01-19 20:37:43 +00:00
FrameBase & frame = GetFrame ( ) ;
2018-11-04 15:07:46 +00:00
2020-10-11 16:34:44 +00:00
if ( IsApple2Original ( GetApple2Type ( ) ) & & GetCardMgr ( ) . QuerySlot ( SLOT0 ) = = CT_LanguageCard )
2018-11-04 15:07:46 +00:00
{
2021-01-19 20:37:43 +00:00
BYTE * pData = frame . GetResource ( IDR_APPLE2_PLUS_ROM , " ROM " , Apple2RomSize ) ;
if ( pData = = NULL )
2018-11-04 15:07:46 +00:00
{
2021-01-19 20:37:43 +00:00
frame . FrameMessageBox ( " Failed to read F8 (auto-start) ROM for language card in original Apple][ " , TEXT ( " AppleWin Error " ) , MB_OK ) ;
2018-11-04 15:07:46 +00:00
}
2021-01-19 20:37:43 +00:00
else
2018-11-04 15:07:46 +00:00
{
2021-01-19 20:37:43 +00:00
memcpy ( memrom + F8RomOffset , pData + F8RomOffset , F8RomSize ) ;
2018-11-04 15:07:46 +00:00
}
}
2008-02-22 21:28:35 +00:00
if ( g_hCustomRomF8 ! = INVALID_HANDLE_VALUE )
{
2020-03-27 20:31:06 +00:00
std : : vector < BYTE > oldRom ( memrom , memrom + Apple2RomSize ) ; // range ctor: [first,last)
2016-03-21 23:48:02 +00:00
2008-02-22 21:28:35 +00:00
SetFilePointer ( g_hCustomRomF8 , 0 , NULL , FILE_BEGIN ) ;
DWORD uNumBytesRead ;
2018-11-04 15:07:46 +00:00
BOOL bRes = ReadFile ( g_hCustomRomF8 , memrom + F8RomOffset , F8RomSize , & uNumBytesRead , NULL ) ;
2008-02-22 21:28:35 +00:00
if ( uNumBytesRead ! = F8RomSize )
{
2020-03-27 20:31:06 +00:00
memcpy ( memrom , & oldRom [ 0 ] , Apple2RomSize ) ; // ROM at $D000...$FFFF
2008-02-22 21:28:35 +00:00
bRes = FALSE ;
}
2018-11-09 20:51:51 +00:00
// NB. If succeeded, then keep g_hCustomRomF8 handle open - so that any next restart can load it again
2008-02-22 21:28:35 +00:00
if ( ! bRes )
{
2021-01-19 20:37:43 +00:00
GetFrame ( ) . FrameMessageBox ( " Failed to read custom F8 rom " , TEXT ( " AppleWin Error " ) , MB_OK ) ;
2008-02-22 21:28:35 +00:00
CloseHandle ( g_hCustomRomF8 ) ;
g_hCustomRomF8 = INVALID_HANDLE_VALUE ;
// Failed, so use default rom...
}
}
2020-12-20 15:32:51 +00:00
if ( GetPropertySheet ( ) . GetTheFreezesF8Rom ( ) & & IS_APPLE2 )
2008-02-22 21:28:35 +00:00
{
2021-01-19 20:37:43 +00:00
BYTE * pData = frame . GetResource ( IDR_FREEZES_F8_ROM , " ROM " , 0x800 ) ;
if ( pData )
2008-02-22 21:28:35 +00:00
{
memcpy ( memrom + Apple2RomSize - F8RomSize , pData , F8RomSize ) ;
}
}
2016-03-21 23:48:02 +00:00
}
2007-05-28 11:16:42 +00:00
2020-03-25 23:05:02 +00:00
void MemInitializeCustomROM ( void )
{
if ( g_hCustomRom = = INVALID_HANDLE_VALUE )
return ;
SetFilePointer ( g_hCustomRom , 0 , NULL , FILE_BEGIN ) ;
DWORD uNumBytesRead ;
BOOL bRes = TRUE ;
if ( GetFileSize ( g_hCustomRom , NULL ) = = Apple2eRomSize )
{
2020-03-26 22:16:00 +00:00
std : : vector < BYTE > oldRomC0 ( pCxRomInternal , pCxRomInternal + CxRomSize ) ; // range ctor: [first,last)
2020-03-25 23:05:02 +00:00
bRes = ReadFile ( g_hCustomRom , pCxRomInternal , CxRomSize , & uNumBytesRead , NULL ) ;
if ( uNumBytesRead ! = CxRomSize )
{
memcpy ( pCxRomInternal , & oldRomC0 [ 0 ] , CxRomSize ) ; // ROM at $C000...$CFFF
bRes = FALSE ;
}
}
if ( bRes )
{
2020-03-26 22:16:00 +00:00
std : : vector < BYTE > oldRom ( memrom , memrom + Apple2RomSize ) ; // range ctor: [first,last)
2020-03-25 23:05:02 +00:00
bRes = ReadFile ( g_hCustomRom , memrom , Apple2RomSize , & uNumBytesRead , NULL ) ;
if ( uNumBytesRead ! = Apple2RomSize )
{
memcpy ( memrom , & oldRom [ 0 ] , Apple2RomSize ) ; // ROM at $D000...$FFFF
bRes = FALSE ;
}
}
// NB. If succeeded, then keep g_hCustomRom handle open - so that any next restart can load it again
if ( ! bRes )
{
2021-01-19 20:37:43 +00:00
GetFrame ( ) . FrameMessageBox ( " Failed to read custom rom " , TEXT ( " AppleWin Error " ) , MB_OK ) ;
2020-03-25 23:05:02 +00:00
CloseHandle ( g_hCustomRom ) ;
g_hCustomRom = INVALID_HANDLE_VALUE ;
// Failed, so use default rom...
}
}
2016-03-21 23:48:02 +00:00
// Called by:
// . MemInitialize()
// . Snapshot_LoadState_v2()
//
// Since called by LoadState(), then this must not init any cards
// - it should only init the card I/O hooks
void MemInitializeIO ( void )
{
InitIoHandlers ( ) ;
2006-02-25 20:50:29 +00:00
2018-11-09 20:51:51 +00:00
if ( g_pLanguageCard )
2021-11-11 21:45:55 +00:00
g_pLanguageCard - > InitializeIO ( NULL ) ;
2018-11-09 20:51:51 +00:00
else
RegisterIoHandler ( LanguageCardUnit : : kSlot0 , IO_Null , IO_Null , NULL , NULL , NULL , NULL ) ;
2006-02-25 20:50:29 +00:00
2021-11-11 21:45:55 +00:00
GetCardMgr ( ) . InitializeIO ( pCxRomPeripheral ) ;
2006-02-25 20:50:29 +00:00
}
2017-09-22 21:23:13 +00:00
// Called by:
// . Snapshot_LoadState_v2()
2020-06-08 21:06:17 +00:00
void MemInitializeCardSlotAndExpansionRomFromSnapshot ( void )
2017-09-22 21:23:13 +00:00
{
2020-06-08 21:06:17 +00:00
// Remove all the cards' ROMs at $Csnn if internal ROM is enabled
if ( IsAppleIIeOrAbove ( GetApple2Type ( ) ) & & SW_INTCXROM )
IoHandlerCardsOut ( ) ;
// Potentially init a card's expansion ROM
2017-09-22 21:23:13 +00:00
const UINT uSlot = g_uPeripheralRomSlot ;
if ( ExpansionRom [ uSlot ] = = NULL )
return ;
_ASSERT ( g_eExpansionRomType = = eExpRomPeripheral ) ;
memcpy ( pCxRomPeripheral + 0x800 , ExpansionRom [ uSlot ] , FIRMWARE_EXPANSION_SIZE ) ;
// NB. Copied to /mem/ by UpdatePaging(TRUE)
}
2014-07-16 15:41:45 +00:00
inline DWORD getRandomTime ( )
{
return rand ( ) ^ timeGetTime ( ) ; // We can't use g_nCumulativeCycles as it will be zero on a fresh execution.
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2006-06-27 02:34:46 +00:00
// Called by:
2020-06-08 20:11:12 +00:00
// . MemInitialize() eg. on AppleWin start & restart (eg. h/w config changes)
2006-02-25 20:50:29 +00:00
// . ResetMachineState() eg. Power-cycle ('Apple-Go' button)
2016-03-21 23:48:02 +00:00
// . Snapshot_LoadState_v2()
2014-09-28 21:04:12 +00:00
void MemReset ( )
2006-02-25 20:50:29 +00:00
{
2006-06-27 02:34:46 +00:00
// INITIALIZE THE PAGING TABLES
2020-12-10 21:08:15 +00:00
memset ( memshadow , 0 , 256 * sizeof ( LPBYTE ) ) ;
memset ( memwrite , 0 , 256 * sizeof ( LPBYTE ) ) ;
2006-02-25 20:50:29 +00:00
2006-06-27 02:34:46 +00:00
// INITIALIZE THE RAM IMAGES
2020-12-10 21:08:15 +00:00
memset ( memaux , 0 , 0x10000 ) ;
memset ( memmain , 0 , 0x10000 ) ;
2006-02-25 20:50:29 +00:00
2016-03-21 23:48:02 +00:00
// Init the I/O ROM vars
IO_SELECT = 0 ;
2017-05-21 16:35:35 +00:00
INTC8ROM = false ;
2016-03-21 23:48:02 +00:00
g_eExpansionRomType = eExpRomNull ;
g_uPeripheralRomSlot = 0 ;
2020-12-10 21:08:15 +00:00
memset ( memdirty , 0 , 0x100 ) ;
2019-07-05 22:01:19 +00:00
2016-03-21 23:48:02 +00:00
//
2006-03-03 18:54:41 +00:00
int iByte ;
2006-03-09 21:10:40 +00:00
2014-07-15 19:37:04 +00:00
// Memory is pseudo-initialized across various models of Apple ][ //e //c
// We chose a random one for nostalgia's sake
// To inspect:
// F2. Ctrl-F2. CALL-151, C050 C053 C057
// OR
// F2, Ctrl-F2, F7, HGR
2020-10-11 16:14:03 +00:00
DWORD randTime = getRandomTime ( ) ;
2014-09-08 21:25:29 +00:00
MemoryInitPattern_e eMemoryInitPattern = static_cast < MemoryInitPattern_e > ( g_nMemoryClearType ) ;
2014-07-18 03:18:59 +00:00
2014-09-08 21:25:29 +00:00
if ( g_nMemoryClearType < 0 ) // random
2014-08-24 06:07:02 +00:00
{
2020-10-11 16:14:03 +00:00
eMemoryInitPattern = static_cast < MemoryInitPattern_e > ( randTime % NUM_MIP ) ;
2014-07-15 19:37:04 +00:00
2014-08-24 06:07:02 +00:00
// Don't use unless manually specified as a
// few badly written programs will not work correctly
// due to buffer overflows or not initializig memory before using.
2014-09-08 21:25:29 +00:00
if ( eMemoryInitPattern = = MIP_PAGE_ADDRESS_LOW )
eMemoryInitPattern = MIP_FF_FF_00_00 ;
2014-08-24 06:07:02 +00:00
}
2014-09-08 21:25:29 +00:00
switch ( eMemoryInitPattern )
2006-03-03 18:54:41 +00:00
{
2014-07-15 19:37:04 +00:00
case MIP_FF_FF_00_00 :
2014-07-16 04:14:05 +00:00
for ( iByte = 0x0000 ; iByte < 0xC000 ; iByte + = 4 ) // NB. ODD 16-bit words are zero'd above...
2014-07-15 19:37:04 +00:00
{
2014-07-16 04:14:05 +00:00
memmain [ iByte + 0 ] = 0xFF ;
memmain [ iByte + 1 ] = 0xFF ;
}
2006-03-03 18:54:41 +00:00
2014-07-16 04:28:26 +00:00
// Exceptions: xx28 xx29 xx68 xx69 Apple //e
2014-07-16 04:14:05 +00:00
for ( iByte = 0x0000 ; iByte < 0xC000 ; iByte + = 512 )
{
2020-10-11 16:14:03 +00:00
randTime = getRandomTime ( ) ;
memmain [ iByte + 0x28 ] = ( randTime > > 0 ) & 0xFF ;
memmain [ iByte + 0x29 ] = ( randTime > > 8 ) & 0xFF ;
randTime = getRandomTime ( ) ;
memmain [ iByte + 0x68 ] = ( randTime > > 0 ) & 0xFF ;
memmain [ iByte + 0x69 ] = ( randTime > > 8 ) & 0xFF ;
2014-07-15 19:37:04 +00:00
}
break ;
case MIP_FF_00_FULL_PAGE :
2014-09-08 01:29:47 +00:00
// https://github.com/AppleWin/AppleWin/issues/225
// AppleWin 1.25 RC2 fails to boot Castle Wolfenstein #225
// This causes Castle Wolfenstein to not boot properly 100% with an error:
// ?OVERFLOW ERROR IN 10
// http://mirrors.apple2.org.za/ftp.apple.asimov.net/images/games/action/wolfenstein/castle_wolfenstein-fixed.dsk
2014-07-15 19:37:04 +00:00
for ( iByte = 0x0000 ; iByte < 0xC000 ; iByte + = 512 )
{
memset ( & memmain [ iByte ] , 0xFF , 256 ) ;
2014-07-16 03:55:28 +00:00
// Exceptions: xx28: 00 xx68:00 Apple //e Platinum NTSC
2014-07-15 19:37:04 +00:00
memmain [ iByte + 0x28 ] = 0x00 ;
memmain [ iByte + 0x68 ] = 0x00 ;
}
break ;
case MIP_00_FF_HALF_PAGE :
2014-07-16 03:55:28 +00:00
for ( iByte = 0x0080 ; iByte < 0xC000 ; iByte + = 256 ) // NB. start = 0x80, delta = 0x100 !
2014-07-15 19:37:04 +00:00
memset ( & memmain [ iByte ] , 0xFF , 128 ) ;
break ;
case MIP_FF_00_HALF_PAGE :
for ( iByte = 0x0000 ; iByte < 0xC000 ; iByte + = 256 )
memset ( & memmain [ iByte ] , 0xFF , 128 ) ;
break ;
2014-07-18 03:42:19 +00:00
case MIP_RANDOM :
2016-03-21 23:48:02 +00:00
unsigned char random [ 256 ] ;
2014-07-18 03:42:19 +00:00
for ( iByte = 0x0000 ; iByte < 0xC000 ; iByte + = 256 )
{
for ( int i = 0 ; i < 256 ; i + + )
{
2020-10-11 16:14:03 +00:00
randTime = getRandomTime ( ) ;
random [ ( i + 0 ) & 0xFF ] = ( randTime > > 0 ) & 0xFF ;
random [ ( i + 1 ) & 0xFF ] = ( randTime > > 11 ) & 0xFF ;
2014-07-18 03:42:19 +00:00
}
memcpy ( & memmain [ iByte ] , random , 256 ) ;
}
break ;
case MIP_PAGE_ADDRESS_LOW :
for ( iByte = 0x0000 ; iByte < 0xC000 ; iByte + + )
memmain [ iByte ] = iByte & 0xFF ;
break ;
case MIP_PAGE_ADDRESS_HIGH :
for ( iByte = 0x0000 ; iByte < 0xC000 ; iByte + = 256 )
memset ( & memmain [ iByte ] , ( iByte > > 8 ) , 256 ) ;
break ;
default : // MIP_ZERO -- nothing to do
break ;
2006-03-03 18:54:41 +00:00
}
2014-07-14 04:31:28 +00:00
// https://github.com/AppleWin/AppleWin/issues/206
2014-07-15 19:37:04 +00:00
// Work-around for a cold-booting bug in "Pooyan" which expects RNDL and RNDH to be non-zero.
2020-10-11 16:14:03 +00:00
randTime = getRandomTime ( ) ;
memmain [ 0x4E ] = 0x20 | ( randTime > > 0 ) & 0xFF ;
memmain [ 0x4F ] = 0x20 | ( randTime > > 8 ) & 0xFF ;
2014-07-14 04:00:45 +00:00
2014-08-23 06:20:58 +00:00
// https://github.com/AppleWin/AppleWin/issues/222
2014-08-24 06:07:02 +00:00
// MIP_PAGE_ADDRESS_LOW breaks a few badly written programs!
2014-08-23 06:20:58 +00:00
// "Beautiful Boot by Mini Appler" reads past $61FF into $6200
// - "BeachParty-PoacherWars-DaytonDinger-BombsAway.dsk"
// - "Dung Beetles, Ms. PacMan, Pooyan, Star Cruiser, Star Thief, Invas. Force.dsk"
memmain [ 0x620B ] = 0x0 ;
2016-03-21 23:48:02 +00:00
2014-08-24 06:07:02 +00:00
// https://github.com/AppleWin/AppleWin/issues/222
// MIP_PAGE_ADDRESS_LOW
// "Copy II+ v5.0.dsk"
// There is a strange memory checker from $1B03 .. $1C25
// Stuck in loop at $1BC2: JSR $F88E INSDS2 before crashing to $0: 00 BRK
memmain [ 0xBFFD ] = 0 ;
memmain [ 0xBFFE ] = 0 ;
memmain [ 0xBFFF ] = 0 ;
2014-08-23 06:20:58 +00:00
2006-06-27 02:34:46 +00:00
// SET UP THE MEMORY IMAGE
2014-09-28 21:04:12 +00:00
mem = memimage ;
2006-02-25 20:50:29 +00:00
2006-06-27 02:34:46 +00:00
// INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE
2020-06-08 21:06:17 +00:00
ResetPaging ( TRUE ) ; // Initialize=1, init memmode
2020-07-07 19:54:46 +00:00
MemAnnunciatorReset ( ) ;
2007-05-28 11:16:42 +00:00
// INITIALIZE & RESET THE CPU
// . Do this after ROM has been copied back to mem[], so that PC is correctly init'ed from 6502's reset vector
CpuInitialize ( ) ;
2008-06-20 23:47:25 +00:00
//Sets Caps Lock = false (Pravets 8A/C only)
2016-03-21 23:48:02 +00:00
z80_reset ( ) ; // NB. Also called above in CpuInitialize()
2020-06-08 20:11:12 +00:00
2020-06-10 19:56:00 +00:00
if ( g_NoSlotClock )
g_NoSlotClock - > Reset ( ) ; // NB. Power-cycle, but not RESET signal
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2007-05-28 11:16:42 +00:00
2007-08-06 21:38:35 +00:00
BYTE MemReadFloatingBus ( const ULONG uExecutedCycles )
2006-03-12 09:05:39 +00:00
{
2018-02-02 20:19:48 +00:00
return mem [ NTSC_VideoGetScannerAddress ( uExecutedCycles ) ] ; // OK: This does the 2-cycle adjust for ANSI STORY (End Credits)
2006-03-12 09:05:39 +00:00
}
//===========================================================================
2007-08-06 21:38:35 +00:00
BYTE MemReadFloatingBus ( const BYTE highbit , const ULONG uExecutedCycles )
2006-03-12 09:05:39 +00:00
{
2016-11-17 19:52:49 +00:00
BYTE r = MemReadFloatingBus ( uExecutedCycles ) ;
2018-06-30 13:30:30 +00:00
return ( r & ~ 0x80 ) | ( highbit ? 0x80 : 0 ) ;
2006-03-12 09:05:39 +00:00
}
2006-02-25 20:50:29 +00:00
//===========================================================================
2014-02-16 14:39:26 +00:00
//#define DEBUG_FLIP_TIMINGS
# if defined(_DEBUG) && defined(DEBUG_FLIP_TIMINGS)
2018-03-03 21:27:50 +00:00
static void DebugFlip ( WORD address , ULONG nExecutedCycles )
2014-02-16 14:39:26 +00:00
{
static unsigned __int64 uLastFlipCycle = 0 ;
static unsigned int uLastPage = - 1 ;
if ( address ! = 0x54 & & address ! = 0x55 )
return ;
const unsigned int uNewPage = address & 1 ;
if ( uLastPage = = uNewPage )
return ;
uLastPage = uNewPage ;
2018-03-03 21:27:50 +00:00
CpuCalcCycles ( nExecutedCycles ) ; // Update g_nCumulativeCycles
2014-02-16 14:39:26 +00:00
const unsigned int uCyclesBetweenFlips = ( unsigned int ) ( uLastFlipCycle ? g_nCumulativeCycles - uLastFlipCycle : 0 ) ;
uLastFlipCycle = g_nCumulativeCycles ;
if ( ! uCyclesBetweenFlips )
return ; // 1st time in func
const double fFreq = CLK_6502 / ( double ) uCyclesBetweenFlips ;
char szStr [ 100 ] ;
sprintf ( szStr , " Cycles between flips = %d (%f Hz) \n " , uCyclesBetweenFlips , fFreq ) ;
OutputDebugString ( szStr ) ;
}
# endif
2018-03-03 21:27:50 +00:00
BYTE __stdcall MemSetPaging ( WORD programcounter , WORD address , BYTE write , BYTE value , ULONG nExecutedCycles )
2007-05-28 11:16:42 +00:00
{
2014-07-14 04:31:28 +00:00
address & = 0xFF ;
DWORD lastmemmode = memmode ;
2014-02-16 14:39:26 +00:00
# if defined(_DEBUG) && defined(DEBUG_FLIP_TIMINGS)
2018-03-03 21:27:50 +00:00
DebugFlip ( address , nExecutedCycles ) ;
2014-02-16 14:39:26 +00:00
# endif
2006-02-25 20:50:29 +00:00
2014-07-14 04:31:28 +00:00
// DETERMINE THE NEW MEMORY PAGING MODE.
2018-11-09 20:51:51 +00:00
if ( ! IS_APPLE2 )
2007-05-28 11:16:42 +00:00
{
2014-07-14 04:31:28 +00:00
switch ( address )
2007-05-28 11:16:42 +00:00
{
2014-07-14 04:31:28 +00:00
case 0x00 : SetMemMode ( memmode & ~ MF_80STORE ) ; break ;
case 0x01 : SetMemMode ( memmode | MF_80STORE ) ; break ;
case 0x02 : SetMemMode ( memmode & ~ MF_AUXREAD ) ; break ;
case 0x03 : SetMemMode ( memmode | MF_AUXREAD ) ; break ;
case 0x04 : SetMemMode ( memmode & ~ MF_AUXWRITE ) ; break ;
case 0x05 : SetMemMode ( memmode | MF_AUXWRITE ) ; break ;
2018-04-06 21:36:54 +00:00
case 0x06 : SetMemMode ( memmode & ~ MF_INTCXROM ) ; break ;
case 0x07 : SetMemMode ( memmode | MF_INTCXROM ) ; break ;
2014-07-14 04:31:28 +00:00
case 0x08 : SetMemMode ( memmode & ~ MF_ALTZP ) ; break ;
case 0x09 : SetMemMode ( memmode | MF_ALTZP ) ; break ;
case 0x0A : SetMemMode ( memmode & ~ MF_SLOTC3ROM ) ; break ;
case 0x0B : SetMemMode ( memmode | MF_SLOTC3ROM ) ; break ;
case 0x54 : SetMemMode ( memmode & ~ MF_PAGE2 ) ; break ;
case 0x55 : SetMemMode ( memmode | MF_PAGE2 ) ; break ;
case 0x56 : SetMemMode ( memmode & ~ MF_HIRES ) ; break ;
case 0x57 : SetMemMode ( memmode | MF_HIRES ) ; break ;
# ifdef RAMWORKS
case 0x71 : // extended memory aux page number
case 0x73 : // Ramworks III set aux page number
if ( ( value < g_uMaxExPages ) & & RWpages [ value ] )
{
2016-03-21 23:48:02 +00:00
g_uActiveBank = value ;
memaux = RWpages [ g_uActiveBank ] ;
2018-10-26 18:23:30 +00:00
UpdatePaging ( FALSE ) ; // Initialize=FALSE
2014-07-14 04:31:28 +00:00
}
break ;
# endif
2007-05-28 11:16:42 +00:00
}
2014-07-14 04:31:28 +00:00
}
2020-07-06 19:52:31 +00:00
if ( IsCopamBase64A ( GetApple2Type ( ) ) )
2020-07-06 19:24:16 +00:00
{
switch ( address )
{
case 0x58 : SetMemMode ( memmode & ~ MF_ALTROM0 ) ; break ;
case 0x59 : SetMemMode ( memmode | MF_ALTROM0 ) ; break ;
case 0x5A : SetMemMode ( memmode & ~ MF_ALTROM1 ) ; break ;
case 0x5B : SetMemMode ( memmode | MF_ALTROM1 ) ; break ;
}
}
2018-11-10 10:30:19 +00:00
if ( MemOptimizeForModeChanging ( programcounter , address ) )
return write ? 0 : MemReadFloatingBus ( nExecutedCycles ) ;
2014-07-14 04:31:28 +00:00
// IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND
// WRITE TABLES.
if ( ( lastmemmode ! = memmode ) | | modechanging )
{
2018-04-06 21:36:54 +00:00
// 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 ) ) )
2007-05-28 11:16:42 +00:00
{
2018-04-06 21:36:54 +00:00
if ( ! SW_INTCXROM )
2014-07-14 04:31:28 +00:00
{
2017-05-21 16:35:35 +00:00
if ( ! INTC8ROM ) // GH#423
{
// Disable Internal ROM
// . Similar to $CFFF access
// . None of the peripheral cards can be driving the bus - so use the null ROM
memset ( pCxRomPeripheral + 0x800 , 0 , FIRMWARE_EXPANSION_SIZE ) ;
memset ( mem + FIRMWARE_EXPANSION_BEGIN , 0 , FIRMWARE_EXPANSION_SIZE ) ;
g_eExpansionRomType = eExpRomNull ;
g_uPeripheralRomSlot = 0 ;
}
2014-07-14 04:31:28 +00:00
IoHandlerCardsIn ( ) ;
}
else
{
// Enable Internal ROM
memcpy ( mem + 0xC800 , pCxRomInternal + 0x800 , FIRMWARE_EXPANSION_SIZE ) ;
g_eExpansionRomType = eExpRomInternal ;
g_uPeripheralRomSlot = 0 ;
IoHandlerCardsOut ( ) ;
}
2007-05-28 11:16:42 +00:00
}
2014-09-28 21:04:12 +00:00
UpdatePaging ( 0 ) ; // Initialize=0
2014-07-14 04:31:28 +00:00
}
2006-02-25 20:50:29 +00:00
2018-06-30 17:21:28 +00:00
// Replicate 80STORE, PAGE2 and HIRES to video sub-system
2014-07-14 04:31:28 +00:00
if ( ( address < = 1 ) | | ( ( address > = 0x54 ) & & ( address < = 0x57 ) ) )
2020-12-28 16:25:29 +00:00
return GetVideo ( ) . VideoSetMode ( programcounter , address , write , value , nExecutedCycles ) ;
2006-03-12 09:05:39 +00:00
2018-03-03 21:27:50 +00:00
return write ? 0 : MemReadFloatingBus ( nExecutedCycles ) ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2018-11-10 10:30:19 +00:00
bool MemOptimizeForModeChanging ( WORD programcounter , WORD address )
{
2020-06-07 17:25:34 +00:00
if ( IsAppleIIeOrAbove ( GetApple2Type ( ) ) )
2018-11-10 10:30:19 +00:00
{
// 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 ) & & // Now: RAMWRTOFF or RAMWRTON
( ( * ( LPDWORD ) ( mem + programcounter ) & 0x00FFFEFF ) = = 0x00C0028D ) ) // Next: STA $C002(RAMRDOFF) or STA $C003(RAMRDON)
{
modechanging = 1 ;
return true ;
}
if ( ( address > = 0x80 ) & & ( address < = 0x8F ) & & ( programcounter < 0xC000 ) & & // Now: LC
( ( ( * ( LPDWORD ) ( mem + programcounter ) & 0x00FFFEFF ) = = 0x00C0048D ) | | // Next: STA $C004(RAMWRTOFF) or STA $C005(RAMWRTON)
( ( * ( LPDWORD ) ( mem + programcounter ) & 0x00FFFEFF ) = = 0x00C0028D ) ) ) // or STA $C002(RAMRDOFF) or STA $C003(RAMRDON)
{
modechanging = 1 ;
return true ;
}
}
return false ;
}
//===========================================================================
2014-09-28 21:04:12 +00:00
LPVOID MemGetSlotParameters ( UINT uSlot )
2006-02-25 20:50:29 +00:00
{
2007-05-28 11:16:42 +00:00
_ASSERT ( uSlot < NUM_SLOTS ) ;
return SlotParameters [ uSlot ] ;
2006-02-25 20:50:29 +00:00
}
//===========================================================================
2020-07-07 19:54:46 +00:00
void MemAnnunciatorReset ( void )
{
for ( UINT i = 0 ; i < kNumAnnunciators ; i + + )
g_Annunciator [ i ] = 0 ;
if ( IsCopamBase64A ( GetApple2Type ( ) ) )
{
SetMemMode ( memmode & ~ ( MF_ALTROM0 | MF_ALTROM1 ) ) ;
UpdatePaging ( FALSE ) ; // Initialize=FALSE
}
}
2019-04-06 14:17:18 +00:00
bool MemGetAnnunciator ( UINT annunciator )
{
return g_Annunciator [ annunciator ] ;
}
//===========================================================================
2020-06-10 19:56:00 +00:00
bool MemHasNoSlotClock ( void )
{
return g_NoSlotClock ! = NULL ;
}
void MemInsertNoSlotClock ( void )
{
if ( ! MemHasNoSlotClock ( ) )
g_NoSlotClock = new CNoSlotClock ;
g_NoSlotClock - > Reset ( ) ;
}
void MemRemoveNoSlotClock ( void )
{
delete g_NoSlotClock ;
g_NoSlotClock = NULL ;
}
//===========================================================================
2013-07-11 21:21:58 +00:00
// NB. Don't need to save 'modechanging', as this is just an optimisation to save calling UpdatePaging() twice.
// . If we were to save the state when 'modechanging' is set, then on restoring the state, the 6502 code will immediately update the read memory mode.
// . This will work correctly.
2016-03-21 23:48:02 +00:00
# define SS_YAML_KEY_MEMORYMODE "Memory Mode"
# define SS_YAML_KEY_LASTRAMWRITE "Last RAM Write"
# define SS_YAML_KEY_IOSELECT "IO_SELECT"
2017-05-21 16:35:35 +00:00
# define SS_YAML_KEY_IOSELECT_INT "IO_SELECT_InternalROM" // INTC8ROM
2016-03-21 23:48:02 +00:00
# define SS_YAML_KEY_EXPANSIONROMTYPE "Expansion ROM Type"
# define SS_YAML_KEY_PERIPHERALROMSLOT "Peripheral ROM Slot"
2019-04-06 10:18:48 +00:00
# define SS_YAML_KEY_ANNUNCIATOR "Annunciator"
2016-03-21 23:48:02 +00:00
2018-10-26 18:23:30 +00:00
//
2019-02-02 15:51:27 +00:00
// Unit version history:
// 2: Added version field to card's state
static const UINT kUNIT_AUXSLOT_VER = 2 ;
// Unit version history:
// 2: Added: RGB card state
2019-04-06 14:17:18 +00:00
// 3: Extended: RGB card state ('80COL changed')
static const UINT kUNIT_CARD_VER = 3 ;
2018-10-26 18:23:30 +00:00
2016-03-21 23:48:02 +00:00
# define SS_YAML_VALUE_CARD_80COL "80 Column"
# define SS_YAML_VALUE_CARD_EXTENDED80COL "Extended 80 Column"
# define SS_YAML_VALUE_CARD_RAMWORKSIII "RamWorksIII"
# define SS_YAML_KEY_NUMAUXBANKS "Num Aux Banks"
# define SS_YAML_KEY_ACTIVEAUXBANK "Active Aux Bank"
static std : : string MemGetSnapshotStructName ( void )
{
static const std : : string name ( " Memory " ) ;
return name ;
}
std : : string MemGetSnapshotUnitAuxSlotName ( void )
{
static const std : : string name ( " Auxiliary Slot " ) ;
return name ;
}
static std : : string MemGetSnapshotMainMemStructName ( void )
{
static const std : : string name ( " Main Memory " ) ;
return name ;
}
static std : : string MemGetSnapshotAuxMemStructName ( void )
{
static const std : : string name ( " Auxiliary Memory Bank " ) ;
return name ;
}
2018-10-26 18:23:30 +00:00
static void MemSaveSnapshotMemory ( YamlSaveHelper & yamlSaveHelper , bool bIsMainMem , UINT bank = 0 , UINT size = 64 * 1024 )
2016-03-21 23:48:02 +00:00
{
LPBYTE pMemBase = MemGetBankPtr ( bank ) ;
if ( bIsMainMem )
2006-02-25 20:50:29 +00:00
{
2016-03-21 23:48:02 +00:00
YamlSaveHelper : : Label state ( yamlSaveHelper , " %s: \n " , MemGetSnapshotMainMemStructName ( ) . c_str ( ) ) ;
2018-10-26 18:23:30 +00:00
yamlSaveHelper . SaveMemory ( pMemBase , size ) ;
2006-02-25 20:50:29 +00:00
}
2016-03-21 23:48:02 +00:00
else
{
YamlSaveHelper : : Label state ( yamlSaveHelper , " %s%02X: \n " , MemGetSnapshotAuxMemStructName ( ) . c_str ( ) , bank - 1 ) ;
2018-10-26 18:23:30 +00:00
yamlSaveHelper . SaveMemory ( pMemBase , size ) ;
2016-03-21 23:48:02 +00:00
}
}
2006-02-25 20:50:29 +00:00
2016-03-21 23:48:02 +00:00
void MemSaveSnapshot ( YamlSaveHelper & yamlSaveHelper )
{
// Scope so that "Memory" & "Main Memory" are at same indent level
{
YamlSaveHelper : : Label state ( yamlSaveHelper , " %s: \n " , MemGetSnapshotStructName ( ) . c_str ( ) ) ;
2018-10-26 18:23:30 +00:00
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 ) ;
2016-03-21 23:48:02 +00:00
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_IOSELECT , IO_SELECT ) ;
2017-05-21 16:35:35 +00:00
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_IOSELECT_INT , INTC8ROM ? 1 : 0 ) ;
2016-03-21 23:48:02 +00:00
yamlSaveHelper . SaveUint ( SS_YAML_KEY_EXPANSIONROMTYPE , ( UINT ) g_eExpansionRomType ) ;
yamlSaveHelper . SaveUint ( SS_YAML_KEY_PERIPHERALROMSLOT , g_uPeripheralRomSlot ) ;
2019-04-06 10:18:48 +00:00
for ( UINT i = 0 ; i < kNumAnnunciators ; i + + )
{
std : : string annunciator = SS_YAML_KEY_ANNUNCIATOR + std : : string ( 1 , ' 0 ' + i ) ;
yamlSaveHelper . SaveBool ( annunciator . c_str ( ) , g_Annunciator [ i ] ) ;
}
2016-03-21 23:48:02 +00:00
}
2018-10-26 18:23:30 +00:00
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 ) ;
2006-02-25 20:50:29 +00:00
}
2019-04-06 14:17:18 +00:00
bool MemLoadSnapshot ( YamlLoadHelper & yamlLoadHelper , UINT unitVersion )
2006-02-25 20:50:29 +00:00
{
2016-03-21 23:48:02 +00:00
if ( ! yamlLoadHelper . GetSubMap ( MemGetSnapshotStructName ( ) ) )
return false ;
2018-10-26 18:23:30 +00:00
// Create default LC type for AppleII machine (do prior to loading saved LC state)
ResetDefaultMachineMemTypes ( ) ;
2019-04-06 14:17:18 +00:00
if ( unitVersion = = 1 )
2018-11-09 20:51:51 +00:00
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
2018-10-26 18:23:30 +00:00
SetExpansionMemTypeDefault ( ) ;
2018-11-09 20:51:51 +00:00
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
2018-10-26 18:23:30 +00:00
//
2016-03-21 23:48:02 +00:00
IO_SELECT = ( BYTE ) yamlLoadHelper . LoadUint ( SS_YAML_KEY_IOSELECT ) ;
2017-05-21 16:35:35 +00:00
INTC8ROM = yamlLoadHelper . LoadUint ( SS_YAML_KEY_IOSELECT_INT ) ? true : false ;
2016-03-21 23:48:02 +00:00
g_eExpansionRomType = ( eExpansionRomType ) yamlLoadHelper . LoadUint ( SS_YAML_KEY_EXPANSIONROMTYPE ) ;
g_uPeripheralRomSlot = yamlLoadHelper . LoadUint ( SS_YAML_KEY_PERIPHERALROMSLOT ) ;
2019-04-06 14:17:18 +00:00
if ( unitVersion = = 1 )
2018-10-26 18:23:30 +00:00
{
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
}
2019-06-28 20:34:34 +00:00
if ( unitVersion > = 3 )
2019-04-06 10:18:48 +00:00
{
for ( UINT i = 0 ; i < kNumAnnunciators ; i + + )
{
std : : string annunciator = SS_YAML_KEY_ANNUNCIATOR + std : : string ( 1 , ' 0 ' + i ) ;
g_Annunciator [ i ] = yamlLoadHelper . LoadBool ( annunciator . c_str ( ) ) ;
}
}
2016-03-21 23:48:02 +00:00
yamlLoadHelper . PopMap ( ) ;
2006-02-25 20:50:29 +00:00
2016-03-21 23:48:02 +00:00
//
if ( ! yamlLoadHelper . GetSubMap ( MemGetSnapshotMainMemStructName ( ) ) )
throw std : : string ( " Card: Expected key: " ) + MemGetSnapshotMainMemStructName ( ) ;
2018-10-27 17:16:32 +00:00
memset ( memmain + 0xC000 , 0 , LanguageCardSlot0 : : kMemBankSize ) ; // Clear it, as high 16K may not be in the save-state's "Main Memory" (eg. the case of II+ Saturn replacing //e LC)
2020-12-10 21:08:15 +00:00
yamlLoadHelper . LoadMemory ( memmain , _6502_MEM_LEN ) ;
2019-04-06 14:17:18 +00:00
if ( unitVersion = = 1 & & IsApple2PlusOrClone ( GetApple2Type ( ) ) )
2018-10-27 17:16:32 +00:00
{
// v1 for II/II+ doesn't have a dedicated slot-0 LC, instead the 16K is stored as the top 16K of memmain
memcpy ( g_pMemMainLanguageCard , memmain + 0xC000 , LanguageCardSlot0 : : kMemBankSize ) ;
memset ( memmain + 0xC000 , 0 , LanguageCardSlot0 : : kMemBankSize ) ;
}
2013-07-11 21:21:58 +00:00
memset ( memdirty , 0 , 0x100 ) ;
2006-02-25 20:50:29 +00:00
2016-03-21 23:48:02 +00:00
yamlLoadHelper . PopMap ( ) ;
2006-02-25 20:50:29 +00:00
//
2016-03-21 23:48:02 +00:00
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2()
UpdatePaging ( 1 ) ; // Initialize=1 (Still needed, even with call to MemUpdatePaging() - why?)
2017-09-22 21:23:13 +00:00
// TC-TODO: At this point, the cards haven't been loaded, so the card's expansion ROM is unknown - so pointless(?) calling this now
2006-02-25 20:50:29 +00:00
2016-03-21 23:48:02 +00:00
return true ;
}
2006-02-25 20:50:29 +00:00
2018-10-26 18:23:30 +00:00
// TODO: Switch from checking 'g_uMaxExPages == n' to using g_SlotAux
2016-03-21 23:48:02 +00:00
void MemSaveSnapshotAux ( YamlSaveHelper & yamlSaveHelper )
{
if ( IS_APPLE2 )
{
return ; // No Aux slot for AppleII
}
2019-04-06 10:18:48 +00:00
if ( IS_APPLE2C ( ) )
2016-03-21 23:48:02 +00:00
{
_ASSERT ( g_uMaxExPages = = 1 ) ;
}
2018-10-26 18:23:30 +00:00
yamlSaveHelper . UnitHdr ( MemGetSnapshotUnitAuxSlotName ( ) , kUNIT_AUXSLOT_VER ) ;
2016-03-21 23:48:02 +00:00
2019-02-02 15:51:27 +00:00
// Unit state
2016-03-21 23:48:02 +00:00
{
2019-02-02 15:51:27 +00:00
YamlSaveHelper : : Label unitState ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_STATE ) ;
std : : string card = g_uMaxExPages = = 0 ? SS_YAML_VALUE_CARD_80COL : // todo: support empty slot
g_uMaxExPages = = 1 ? SS_YAML_VALUE_CARD_EXTENDED80COL :
SS_YAML_VALUE_CARD_RAMWORKSIII ;
yamlSaveHelper . SaveString ( SS_YAML_KEY_CARD , card . c_str ( ) ) ;
2019-04-06 14:17:18 +00:00
yamlSaveHelper . Save ( " %s: %d \n " , SS_YAML_KEY_VERSION , kUNIT_CARD_VER ) ;
2019-02-02 15:51:27 +00:00
// Card state
{
YamlSaveHelper : : Label cardState ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_STATE ) ;
yamlSaveHelper . Save ( " %s: 0x%02X # [0,1..7F] 0=no aux mem, 1=128K system, etc \n " , SS_YAML_KEY_NUMAUXBANKS , g_uMaxExPages ) ;
yamlSaveHelper . Save ( " %s: 0x%02X # [ 0..7E] 0=memaux \n " , SS_YAML_KEY_ACTIVEAUXBANK , g_uActiveBank ) ;
for ( UINT uBank = 1 ; uBank < = g_uMaxExPages ; uBank + + )
{
MemSaveSnapshotMemory ( yamlSaveHelper , false , uBank ) ;
}
RGB_SaveSnapshot ( yamlSaveHelper ) ;
}
2016-03-21 23:48:02 +00:00
}
}
2019-02-02 15:51:27 +00:00
static void MemLoadSnapshotAuxCommon ( YamlLoadHelper & yamlLoadHelper , const std : : string & card )
2016-03-21 23:48:02 +00:00
{
// "State"
UINT numAuxBanks = yamlLoadHelper . LoadUint ( SS_YAML_KEY_NUMAUXBANKS ) ;
UINT activeAuxBank = yamlLoadHelper . LoadUint ( SS_YAML_KEY_ACTIVEAUXBANK ) ;
2018-10-26 18:23:30 +00:00
SS_CARDTYPE type = CT_Empty ;
2016-03-21 23:48:02 +00:00
if ( card = = SS_YAML_VALUE_CARD_80COL )
{
2018-10-26 18:23:30 +00:00
type = CT_80Col ;
2016-03-21 23:48:02 +00:00
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 )
{
2018-10-26 18:23:30 +00:00
type = CT_Extended80Col ;
2016-03-21 23:48:02 +00:00
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 )
{
2018-10-26 18:23:30 +00:00
type = CT_RamWorksIII ;
2016-03-21 23:48:02 +00:00
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
2018-10-26 18:23:30 +00:00
type = CT_Empty ;
2016-03-21 23:48:02 +00:00
throw std : : string ( SS_YAML_KEY_UNIT " : AuxSlot: Unknown card: " + card ) ;
}
g_uMaxExPages = numAuxBanks ;
g_uActiveBank = activeAuxBank ;
//
for ( UINT uBank = 1 ; uBank < = g_uMaxExPages ; uBank + + )
{
LPBYTE pBank = MemGetBankPtr ( uBank ) ;
if ( ! pBank )
{
2020-12-10 21:08:15 +00:00
pBank = RWpages [ uBank - 1 ] = ALIGNED_ALLOC ( _6502_MEM_LEN ) ;
2016-03-21 23:48:02 +00:00
}
// "Auxiliary Memory Bankxx"
char szBank [ 3 ] ;
sprintf ( szBank , " %02X " , uBank - 1 ) ;
std : : string auxMemName = MemGetSnapshotAuxMemStructName ( ) + szBank ;
if ( ! yamlLoadHelper . GetSubMap ( auxMemName ) )
throw std : : string ( " Memory: Missing map name: " + auxMemName ) ;
2020-12-10 21:08:15 +00:00
yamlLoadHelper . LoadMemory ( pBank , _6502_MEM_LEN ) ;
2016-03-21 23:48:02 +00:00
yamlLoadHelper . PopMap ( ) ;
}
2020-10-11 16:34:44 +00:00
GetCardMgr ( ) . Remove ( SLOT0 ) ;
GetCardMgr ( ) . InsertAux ( type ) ;
2018-10-26 18:23:30 +00:00
2016-03-21 23:48:02 +00:00
memaux = RWpages [ g_uActiveBank ] ;
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2()
2019-02-02 15:51:27 +00:00
}
static void MemLoadSnapshotAuxVer1 ( YamlLoadHelper & yamlLoadHelper )
{
std : : string card = yamlLoadHelper . LoadString ( SS_YAML_KEY_CARD ) ;
MemLoadSnapshotAuxCommon ( yamlLoadHelper , card ) ;
}
2019-04-06 14:17:18 +00:00
static void MemLoadSnapshotAuxVer2 ( YamlLoadHelper & yamlLoadHelper )
2019-02-02 15:51:27 +00:00
{
std : : string card = yamlLoadHelper . LoadString ( SS_YAML_KEY_CARD ) ;
UINT cardVersion = yamlLoadHelper . LoadUint ( SS_YAML_KEY_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 ) ;
MemLoadSnapshotAuxCommon ( yamlLoadHelper , card ) ;
2019-04-06 14:17:18 +00:00
RGB_LoadSnapshot ( yamlLoadHelper , cardVersion ) ;
2019-02-02 15:51:27 +00:00
}
2019-04-06 14:17:18 +00:00
bool MemLoadSnapshotAux ( YamlLoadHelper & yamlLoadHelper , UINT unitVersion )
2019-02-02 15:51:27 +00:00
{
2019-04-06 14:17:18 +00:00
if ( unitVersion < 1 | | unitVersion > kUNIT_AUXSLOT_VER )
2019-02-02 15:51:27 +00:00
throw std : : string ( SS_YAML_KEY_UNIT " : AuxSlot: Version mismatch " ) ;
2019-04-06 14:17:18 +00:00
if ( unitVersion = = 1 )
2019-02-02 15:51:27 +00:00
MemLoadSnapshotAuxVer1 ( yamlLoadHelper ) ;
else
2019-04-06 14:17:18 +00:00
MemLoadSnapshotAuxVer2 ( yamlLoadHelper ) ;
2016-03-21 23:48:02 +00:00
return true ;
2006-02-25 20:50:29 +00:00
}
2020-06-10 19:56:00 +00:00
void NoSlotClockSaveSnapshot ( YamlSaveHelper & yamlSaveHelper )
{
if ( g_NoSlotClock )
g_NoSlotClock - > SaveSnapshot ( yamlSaveHelper ) ;
}
void NoSlotClockLoadSnapshot ( YamlLoadHelper & yamlLoadHelper )
{
if ( ! g_NoSlotClock )
g_NoSlotClock = new CNoSlotClock ;
g_NoSlotClock - > LoadSnapshot ( yamlLoadHelper ) ;
}