2006-06-12 14:12:52 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// SSSS tt lll lll
|
|
|
|
// SS SS tt ll ll
|
|
|
|
// SS tttttt eeee ll ll aaaa
|
|
|
|
// SSSS tt ee ee ll ll aa
|
|
|
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
|
|
|
// SS SS tt ee ll ll aa aa
|
|
|
|
// SSSS ttt eeeee llll llll aaaaa
|
|
|
|
//
|
2011-12-31 21:56:36 +00:00
|
|
|
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
|
2010-04-10 21:37:23 +00:00
|
|
|
// and the Stella Team
|
2006-06-12 14:12:52 +00:00
|
|
|
//
|
2010-01-10 03:23:32 +00:00
|
|
|
// See the file "License.txt" for information on usage and redistribution of
|
2006-06-12 14:12:52 +00:00
|
|
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
|
|
//
|
2009-05-13 13:55:40 +00:00
|
|
|
// $Id$
|
2006-06-12 14:12:52 +00:00
|
|
|
//============================================================================
|
|
|
|
|
2007-01-14 16:17:57 +00:00
|
|
|
#include <cassert>
|
2008-02-19 12:33:07 +00:00
|
|
|
#include <cstring>
|
2007-01-14 16:17:57 +00:00
|
|
|
|
2006-06-12 14:12:52 +00:00
|
|
|
#include "System.hxx"
|
2008-02-19 12:33:07 +00:00
|
|
|
#include "M6532.hxx"
|
2008-01-24 23:43:24 +00:00
|
|
|
#include "TIA.hxx"
|
2007-01-14 16:17:57 +00:00
|
|
|
#include "Cart4A50.hxx"
|
2006-06-12 14:12:52 +00:00
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-08-19 21:48:28 +00:00
|
|
|
Cartridge4A50::Cartridge4A50(const uInt8* image, uInt32 size,
|
|
|
|
const Settings& settings)
|
|
|
|
: Cartridge(settings)
|
2006-06-12 14:12:52 +00:00
|
|
|
{
|
2007-10-09 23:56:57 +00:00
|
|
|
// Copy the ROM image into my buffer
|
2008-02-19 12:33:07 +00:00
|
|
|
// Supported file sizes are 32/64/128K, which are duplicated if necessary
|
|
|
|
if(size < 65536) size = 32768;
|
|
|
|
else if(size < 131072) size = 65536;
|
|
|
|
else size = 131072;
|
|
|
|
for(uInt32 slice = 0; slice < 131072 / size; ++slice)
|
|
|
|
memcpy(myImage + (slice*size), image, size);
|
2010-11-11 22:24:51 +00:00
|
|
|
|
|
|
|
// We use System::PageAccess.codeAccessBase, but don't allow its use
|
|
|
|
// through a pointer, since the address space of 4A50 carts can change
|
|
|
|
// at the instruction level, and PageAccess is normally defined at an
|
|
|
|
// interval of 64 bytes
|
|
|
|
//
|
|
|
|
// Instead, access will be through the getAccessFlags and setAccessFlags
|
|
|
|
// methods below
|
|
|
|
createCodeAccessBase(131072 + 32768);
|
2006-06-12 14:12:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Cartridge4A50::~Cartridge4A50()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void Cartridge4A50::reset()
|
|
|
|
{
|
2010-08-19 21:48:28 +00:00
|
|
|
// Initialize RAM
|
|
|
|
if(mySettings.getBool("ramrandom"))
|
|
|
|
for(uInt32 i = 0; i < 32768; ++i)
|
|
|
|
myRAM[i] = mySystem->randGenerator().next();
|
|
|
|
else
|
|
|
|
memset(myRAM, 0, 32768);
|
2008-08-01 12:16:00 +00:00
|
|
|
|
2008-01-24 20:43:41 +00:00
|
|
|
mySliceLow = mySliceMiddle = mySliceHigh = 0;
|
|
|
|
myIsRomLow = myIsRomMiddle = myIsRomHigh = true;
|
|
|
|
|
|
|
|
myLastData = 0xff;
|
|
|
|
myLastAddress = 0xffff;
|
2010-03-28 03:13:10 +00:00
|
|
|
|
|
|
|
myBankChanged = true;
|
2006-06-12 14:12:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void Cartridge4A50::install(System& system)
|
|
|
|
{
|
2007-10-09 23:56:57 +00:00
|
|
|
mySystem = &system;
|
|
|
|
uInt16 shift = mySystem->pageShift();
|
|
|
|
uInt16 mask = mySystem->pageMask();
|
|
|
|
|
|
|
|
// Make sure the system we're being installed in has a page size that'll work
|
2008-01-24 20:43:41 +00:00
|
|
|
assert((0x1000 & mask) == 0);
|
2007-10-09 23:56:57 +00:00
|
|
|
|
2010-10-03 00:23:13 +00:00
|
|
|
// Map all of the accesses to call peek and poke (We don't yet indicate RAM areas)
|
|
|
|
System::PageAccess access(0, 0, 0, this, System::PA_READ);
|
2010-04-12 19:56:14 +00:00
|
|
|
|
2008-01-24 20:43:41 +00:00
|
|
|
for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift))
|
2007-10-09 23:56:57 +00:00
|
|
|
mySystem->setPageAccess(i >> shift, access);
|
2008-02-19 12:33:07 +00:00
|
|
|
|
|
|
|
// Mirror all access in TIA and RIOT; by doing so we're taking responsibility
|
|
|
|
// for that address space in peek and poke below.
|
|
|
|
mySystem->tia().install(system, *this);
|
|
|
|
mySystem->m6532().install(system, *this);
|
2006-06-12 14:12:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
uInt8 Cartridge4A50::peek(uInt16 address)
|
|
|
|
{
|
2008-02-21 16:11:15 +00:00
|
|
|
uInt8 value = 0;
|
2007-10-09 23:56:57 +00:00
|
|
|
|
2008-02-19 12:33:07 +00:00
|
|
|
if(!(address & 0x1000)) // Hotspots below 0x1000
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
2008-02-19 12:33:07 +00:00
|
|
|
// Check for RAM or TIA mirroring
|
|
|
|
uInt16 lowAddress = address & 0x3ff;
|
|
|
|
if(lowAddress & 0x80)
|
|
|
|
value = mySystem->m6532().peek(address);
|
|
|
|
else if(!(lowAddress & 0x200))
|
|
|
|
value = mySystem->tia().peek(address);
|
|
|
|
|
2008-02-21 23:58:09 +00:00
|
|
|
checkBankSwitch(address, value);
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-02-19 12:33:07 +00:00
|
|
|
if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
2008-02-19 12:33:07 +00:00
|
|
|
value = myIsRomLow ? myImage[(address & 0x7ff) + mySliceLow]
|
|
|
|
: myRAM[(address & 0x7ff) + mySliceLow];
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff
|
|
|
|
((address & 0x1fff) <= 0x1dff))
|
2007-10-09 23:56:57 +00:00
|
|
|
{
|
2008-02-21 23:58:09 +00:00
|
|
|
value = myIsRomMiddle ? myImage[(address & 0x7ff) + mySliceMiddle + 0x10000]
|
2008-02-19 12:33:07 +00:00
|
|
|
: myRAM[(address & 0x7ff) + mySliceMiddle];
|
2007-10-09 23:56:57 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff
|
2007-10-09 23:56:57 +00:00
|
|
|
{
|
2008-02-21 23:58:09 +00:00
|
|
|
value = myIsRomHigh ? myImage[(address & 0xff) + mySliceHigh + 0x10000]
|
2008-02-19 12:33:07 +00:00
|
|
|
: myRAM[(address & 0xff) + mySliceHigh];
|
2007-10-09 23:56:57 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff
|
2007-10-09 23:56:57 +00:00
|
|
|
{
|
2008-02-21 23:58:09 +00:00
|
|
|
value = myImage[(address & 0xff) + 0x1ff00];
|
2010-03-06 18:56:36 +00:00
|
|
|
if(!bankLocked() && ((myLastData & 0xe0) == 0x60) &&
|
2008-01-24 20:43:41 +00:00
|
|
|
((myLastAddress >= 0x1000) || (myLastAddress < 0x200)))
|
|
|
|
mySliceHigh = (mySliceHigh & 0xf0ff) | ((address & 0x8) << 8) |
|
|
|
|
((address & 0x70) << 4);
|
2007-10-09 23:56:57 +00:00
|
|
|
}
|
|
|
|
}
|
2008-01-24 20:43:41 +00:00
|
|
|
myLastData = value;
|
|
|
|
myLastAddress = address & 0x1fff;
|
2007-10-09 23:56:57 +00:00
|
|
|
|
2008-01-24 20:43:41 +00:00
|
|
|
return value;
|
2006-06-12 14:12:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-03-28 03:13:10 +00:00
|
|
|
bool Cartridge4A50::poke(uInt16 address, uInt8 value)
|
2006-06-12 14:12:52 +00:00
|
|
|
{
|
2008-02-19 12:33:07 +00:00
|
|
|
if(!(address & 0x1000)) // Hotspots below 0x1000
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
2008-02-19 12:33:07 +00:00
|
|
|
// Check for RAM or TIA mirroring
|
|
|
|
uInt16 lowAddress = address & 0x3ff;
|
|
|
|
if(lowAddress & 0x80)
|
|
|
|
mySystem->m6532().poke(address, value);
|
|
|
|
else if(!(lowAddress & 0x200))
|
|
|
|
mySystem->tia().poke(address, value);
|
|
|
|
|
2008-02-21 23:58:09 +00:00
|
|
|
checkBankSwitch(address, value);
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-02-19 12:33:07 +00:00
|
|
|
if((address & 0x1800) == 0x1000) // 2K region at 0x1000 - 0x17ff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
if(!myIsRomLow)
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
2008-01-24 20:43:41 +00:00
|
|
|
myRAM[(address & 0x7ff) + mySliceLow] = value;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
|
|
|
}
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if(((address & 0x1fff) >= 0x1800) && // 1.5K region at 0x1800 - 0x1dff
|
|
|
|
((address & 0x1fff) <= 0x1dff))
|
2007-10-09 23:56:57 +00:00
|
|
|
{
|
2008-01-24 20:43:41 +00:00
|
|
|
if(!myIsRomMiddle)
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
2008-01-24 20:43:41 +00:00
|
|
|
myRAM[(address & 0x7ff) + mySliceMiddle] = value;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
|
|
|
}
|
2007-10-09 23:56:57 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x1f00) == 0x1e00) // 256B region at 0x1e00 - 0x1eff
|
2007-10-09 23:56:57 +00:00
|
|
|
{
|
2008-01-24 20:43:41 +00:00
|
|
|
if(!myIsRomHigh)
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
2008-01-24 20:43:41 +00:00
|
|
|
myRAM[(address & 0xff) + mySliceHigh] = value;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
|
|
|
}
|
2007-10-09 23:56:57 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x1f00) == 0x1f00) // 256B region at 0x1f00 - 0x1fff
|
2007-10-09 23:56:57 +00:00
|
|
|
{
|
2010-03-06 18:56:36 +00:00
|
|
|
if(!bankLocked() && ((myLastData & 0xe0) == 0x60) &&
|
2008-01-24 20:43:41 +00:00
|
|
|
((myLastAddress >= 0x1000) || (myLastAddress < 0x200)))
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
2008-02-19 12:33:07 +00:00
|
|
|
mySliceHigh = (mySliceHigh & 0xf0ff) | ((address & 0x8) << 8) |
|
|
|
|
((address & 0x70) << 4);
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
|
|
|
}
|
2007-10-09 23:56:57 +00:00
|
|
|
}
|
|
|
|
}
|
2008-01-24 20:43:41 +00:00
|
|
|
myLastData = value;
|
|
|
|
myLastAddress = address & 0x1fff;
|
2010-03-28 03:13:10 +00:00
|
|
|
|
|
|
|
return myBankChanged;
|
2006-06-12 14:12:52 +00:00
|
|
|
}
|
|
|
|
|
2007-10-09 23:56:57 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-11-11 22:24:51 +00:00
|
|
|
uInt8 Cartridge4A50::getAccessFlags(uInt16 address)
|
|
|
|
{
|
|
|
|
if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff
|
|
|
|
{
|
|
|
|
if(myIsRomLow)
|
|
|
|
return myCodeAccessBase[(address & 0x7ff) + mySliceLow];
|
|
|
|
else
|
|
|
|
return myCodeAccessBase[131072 + (address & 0x7ff) + mySliceLow];
|
|
|
|
}
|
|
|
|
else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff
|
|
|
|
((address & 0x1fff) <= 0x1dff))
|
|
|
|
{
|
|
|
|
if(myIsRomMiddle)
|
|
|
|
return myCodeAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000];
|
|
|
|
else
|
|
|
|
return myCodeAccessBase[131072 + (address & 0x7ff) + mySliceMiddle];
|
|
|
|
}
|
|
|
|
else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff
|
|
|
|
{
|
|
|
|
if(myIsRomHigh)
|
|
|
|
return myCodeAccessBase[(address & 0xff) + mySliceHigh + 0x10000];
|
|
|
|
else
|
|
|
|
return myCodeAccessBase[131072 + (address & 0xff) + mySliceHigh];
|
|
|
|
}
|
|
|
|
else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff
|
|
|
|
{
|
|
|
|
return myCodeAccessBase[(address & 0xff) + 0x1ff00];
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void Cartridge4A50::setAccessFlags(uInt16 address, uInt8 flags)
|
|
|
|
{
|
|
|
|
if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff
|
|
|
|
{
|
|
|
|
if(myIsRomLow)
|
|
|
|
myCodeAccessBase[(address & 0x7ff) + mySliceLow] |= flags;
|
|
|
|
else
|
|
|
|
myCodeAccessBase[131072 + (address & 0x7ff) + mySliceLow] |= flags;
|
|
|
|
}
|
|
|
|
else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff
|
|
|
|
((address & 0x1fff) <= 0x1dff))
|
|
|
|
{
|
|
|
|
if(myIsRomMiddle)
|
|
|
|
myCodeAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000] |= flags;
|
|
|
|
else
|
|
|
|
myCodeAccessBase[131072 + (address & 0x7ff) + mySliceMiddle] |= flags;
|
|
|
|
}
|
|
|
|
else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff
|
|
|
|
{
|
|
|
|
if(myIsRomHigh)
|
|
|
|
myCodeAccessBase[(address & 0xff) + mySliceHigh + 0x10000] |= flags;
|
|
|
|
else
|
|
|
|
myCodeAccessBase[131072 + (address & 0xff) + mySliceHigh] |= flags;
|
|
|
|
}
|
|
|
|
else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff
|
|
|
|
{
|
|
|
|
myCodeAccessBase[(address & 0xff) + 0x1ff00] |= flags;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2008-02-21 23:58:09 +00:00
|
|
|
void Cartridge4A50::checkBankSwitch(uInt16 address, uInt8 value)
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
2010-03-06 18:56:36 +00:00
|
|
|
if(bankLocked()) return;
|
2008-03-28 23:29:14 +00:00
|
|
|
|
2008-01-24 20:43:41 +00:00
|
|
|
// This scheme contains so many hotspots that it's easier to just check
|
|
|
|
// all of them
|
2008-02-19 12:33:07 +00:00
|
|
|
if(((myLastData & 0xe0) == 0x60) && // Switch lower/middle/upper bank
|
2008-01-24 20:43:41 +00:00
|
|
|
((myLastAddress >= 0x1000) || (myLastAddress < 0x200)))
|
2007-10-09 23:56:57 +00:00
|
|
|
{
|
2008-02-19 12:33:07 +00:00
|
|
|
if((address & 0x0f00) == 0x0c00) // Enable 256B of ROM at 0x1e00 - 0x1eff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
myIsRomHigh = true;
|
|
|
|
mySliceHigh = (address & 0xff) << 8;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x0f00) == 0x0d00) // Enable 256B of RAM at 0x1e00 - 0x1eff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
myIsRomHigh = false;
|
|
|
|
mySliceHigh = (address & 0x7f) << 8;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x0f40) == 0x0e00) // Enable 2K of ROM at 0x1000 - 0x17ff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
myIsRomLow = true;
|
|
|
|
mySliceLow = (address & 0x1f) << 11;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x0f40) == 0x0e40) // Enable 2K of RAM at 0x1000 - 0x17ff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
myIsRomLow = false;
|
|
|
|
mySliceLow = (address & 0xf) << 11;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x0f40) == 0x0f00) // Enable 1.5K of ROM at 0x1800 - 0x1dff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
myIsRomMiddle = true;
|
|
|
|
mySliceMiddle = (address & 0x1f) << 11;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x0f50) == 0x0f40) // Enable 1.5K of RAM at 0x1800 - 0x1dff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
myIsRomMiddle = false;
|
|
|
|
mySliceMiddle = (address & 0xf) << 11;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
|
|
|
|
// Stella helper functions
|
|
|
|
else if((address & 0x0f00) == 0x0400) // Toggle bit A11 of lower block address
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
mySliceLow = mySliceLow ^ 0x800;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x0f00) == 0x0500) // Toggle bit A12 of lower block address
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
mySliceLow = mySliceLow ^ 0x1000;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x0f00) == 0x0800) // Toggle bit A11 of middle block address
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
mySliceMiddle = mySliceMiddle ^ 0x800;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-19 12:33:07 +00:00
|
|
|
else if((address & 0x0f00) == 0x0900) // Toggle bit A12 of middle block address
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
|
|
|
mySliceMiddle = mySliceMiddle ^ 0x1000;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2007-10-09 23:56:57 +00:00
|
|
|
}
|
|
|
|
|
2008-02-22 16:27:07 +00:00
|
|
|
// Zero-page hotspots for upper page
|
|
|
|
// 0xf4, 0xf6, 0xfc, 0xfe for ROM
|
|
|
|
// 0xf5, 0xf7, 0xfd, 0xff for RAM
|
|
|
|
// 0x74 - 0x7f (0x80 bytes lower)
|
|
|
|
if((address & 0xf75) == 0x74) // Enable 256B of ROM at 0x1e00 - 0x1eff
|
2007-10-09 23:56:57 +00:00
|
|
|
{
|
2008-02-22 16:27:07 +00:00
|
|
|
myIsRomHigh = true;
|
|
|
|
mySliceHigh = value << 8;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-02-22 16:27:07 +00:00
|
|
|
}
|
|
|
|
else if((address & 0xf75) == 0x75) // Enable 256B of RAM at 0x1e00 - 0x1eff
|
|
|
|
{
|
|
|
|
myIsRomHigh = false;
|
|
|
|
mySliceHigh = (value & 0x7f) << 8;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-02-22 16:27:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Zero-page hotspots for lower and middle blocks
|
|
|
|
// 0xf8, 0xf9, 0xfa, 0xfb
|
|
|
|
// 0x78, 0x79, 0x7a, 0x7b (0x80 bytes lower)
|
|
|
|
else if((address & 0xf7c) == 0x78)
|
|
|
|
{
|
|
|
|
if((value & 0xf0) == 0) // Enable 2K of ROM at 0x1000 - 0x17ff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
2008-02-22 16:27:07 +00:00
|
|
|
myIsRomLow = true;
|
|
|
|
mySliceLow = (value & 0xf) << 11;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-22 16:27:07 +00:00
|
|
|
else if((value & 0xf0) == 0x40) // Enable 2K of RAM at 0x1000 - 0x17ff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
2008-02-22 16:27:07 +00:00
|
|
|
myIsRomLow = false;
|
|
|
|
mySliceLow = (value & 0xf) << 11;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2008-02-22 16:27:07 +00:00
|
|
|
else if((value & 0xf0) == 0x90) // Enable 1.5K of ROM at 0x1800 - 0x1dff
|
2008-01-24 20:43:41 +00:00
|
|
|
{
|
2008-02-22 16:27:07 +00:00
|
|
|
myIsRomMiddle = true;
|
|
|
|
mySliceMiddle = ((value & 0xf) | 0x10) << 11;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-02-22 16:27:07 +00:00
|
|
|
}
|
|
|
|
else if((value & 0xf0) == 0xc0) // Enable 1.5K of RAM at 0x1800 - 0x1dff
|
|
|
|
{
|
|
|
|
myIsRomMiddle = false;
|
|
|
|
mySliceMiddle = (value & 0xf) << 11;
|
2010-03-28 03:13:10 +00:00
|
|
|
myBankChanged = true;
|
2008-01-24 20:43:41 +00:00
|
|
|
}
|
2007-10-09 23:56:57 +00:00
|
|
|
}
|
2006-06-12 14:12:52 +00:00
|
|
|
}
|
|
|
|
|
2008-01-24 23:43:24 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-08-16 16:41:24 +00:00
|
|
|
bool Cartridge4A50::bank(uInt16)
|
2008-01-24 23:43:24 +00:00
|
|
|
{
|
|
|
|
// Doesn't support bankswitching in the normal sense
|
2010-08-16 16:41:24 +00:00
|
|
|
return false;
|
2008-01-24 23:43:24 +00:00
|
|
|
}
|
|
|
|
|
2007-01-14 16:17:57 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-04-02 22:09:31 +00:00
|
|
|
uInt16 Cartridge4A50::bank() const
|
2007-01-14 16:17:57 +00:00
|
|
|
{
|
2008-01-24 20:43:41 +00:00
|
|
|
// Doesn't support bankswitching in the normal sense
|
2007-01-14 16:17:57 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-04-02 22:09:31 +00:00
|
|
|
uInt16 Cartridge4A50::bankCount() const
|
2007-01-14 16:17:57 +00:00
|
|
|
{
|
2008-03-28 23:29:14 +00:00
|
|
|
// Doesn't support bankswitching in the normal sense
|
2010-03-28 16:01:31 +00:00
|
|
|
// There is one 'virtual' bank that can change in many different ways
|
2008-03-28 23:29:14 +00:00
|
|
|
return 1;
|
2007-01-14 16:17:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
bool Cartridge4A50::patch(uInt16 address, uInt8 value)
|
|
|
|
{
|
2010-03-28 16:01:31 +00:00
|
|
|
if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff
|
|
|
|
{
|
|
|
|
if(myIsRomLow)
|
|
|
|
myImage[(address & 0x7ff) + mySliceLow] = value;
|
|
|
|
else
|
|
|
|
myRAM[(address & 0x7ff) + mySliceLow] = value;
|
|
|
|
}
|
|
|
|
else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff
|
|
|
|
((address & 0x1fff) <= 0x1dff))
|
|
|
|
{
|
|
|
|
if(myIsRomMiddle)
|
|
|
|
myImage[(address & 0x7ff) + mySliceMiddle + 0x10000] = value;
|
|
|
|
else
|
|
|
|
myRAM[(address & 0x7ff) + mySliceMiddle] = value;
|
|
|
|
}
|
|
|
|
else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff
|
|
|
|
{
|
|
|
|
if(myIsRomHigh)
|
|
|
|
myImage[(address & 0xff) + mySliceHigh + 0x10000] = value;
|
|
|
|
else
|
|
|
|
myRAM[(address & 0xff) + mySliceHigh] = value;
|
|
|
|
}
|
|
|
|
else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff
|
|
|
|
{
|
|
|
|
myImage[(address & 0xff) + 0x1ff00] = value;
|
|
|
|
}
|
|
|
|
return myBankChanged = true;
|
2007-01-14 16:17:57 +00:00
|
|
|
}
|
|
|
|
|
2006-06-12 14:12:52 +00:00
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-04-02 22:09:31 +00:00
|
|
|
const uInt8* Cartridge4A50::getImage(int& size) const
|
2006-06-12 14:12:52 +00:00
|
|
|
{
|
2008-03-28 23:29:14 +00:00
|
|
|
size = 131072;
|
2010-03-06 18:56:36 +00:00
|
|
|
return myImage;
|
2006-06-12 14:12:52 +00:00
|
|
|
}
|
OK, another huge commit. I need to commit this now, because things are
starting to go out of sync on my development machines. OK, where to
begin ...
Changed state file format, so older state files will no longer work. The
changes aren't finalized yet, so expect more breakage.
Added getByte() and putByte() methods to serialized data, resulting in
smaller state files (previously, 1-byte values were stored as 4-byte ints).
Totally reworked controller handling code. Controller state is now
explicitly set with an ::update() method, making it easier to serialize.
Some work is still required on the serialization stuff for more advanced
controllers.
Added a 'Serializable' interface to all carts, device, controllers, etc
that can be (de)serialized. This fixes a long-standing design issue
which I personally caused many years ago.
Console switches state (SWCHB register) is now saved to state files.
Added beginnings of movie support. Basically, this saves an initial
state file, and thereafter continuously saves controller and console
switches state. Support is still somewhat rough and there's no UI for
it, but it does successfully save and later load/play state movies.
Removed specific events for driving controllers, and have them use
joystick events instead. This has the nice side effect that
joystick direction remapping 'just works' for driving controllers too.
Fixed issues with paddle emulation seen in 'Night Driver' ROM. Related
to this, removed a hack wrt paddles when grabmouse is enabled. There's
still some work to do when using the mouse to emulate paddles, but the
Stelladaptor and real paddles work fine.
Added beginnings of TrackBall CX-22 controller emulation. It doesn't
actually do anything yet, but the class is there :)
Probably some other stuff that I'm forgetting ...
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1385 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2007-10-03 21:41:19 +00:00
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
bool Cartridge4A50::save(Serializer& out) const
|
|
|
|
{
|
2008-02-21 23:58:09 +00:00
|
|
|
try
|
|
|
|
{
|
2010-05-10 00:50:26 +00:00
|
|
|
out.putString(name());
|
2008-02-21 23:58:09 +00:00
|
|
|
|
|
|
|
// The 32K bytes of RAM
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putByteArray(myRAM, 32768);
|
2008-02-21 23:58:09 +00:00
|
|
|
|
|
|
|
// Index pointers
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putShort(mySliceLow);
|
|
|
|
out.putShort(mySliceMiddle);
|
|
|
|
out.putShort(mySliceHigh);
|
2008-02-21 23:58:09 +00:00
|
|
|
|
|
|
|
// Whether index pointers are for ROM or RAM
|
|
|
|
out.putBool(myIsRomLow);
|
|
|
|
out.putBool(myIsRomMiddle);
|
|
|
|
out.putBool(myIsRomHigh);
|
|
|
|
|
|
|
|
// Last address and data values
|
|
|
|
out.putByte(myLastData);
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putShort(myLastAddress);
|
2008-02-21 23:58:09 +00:00
|
|
|
}
|
2012-05-25 12:41:19 +00:00
|
|
|
catch(...)
|
2008-02-21 23:58:09 +00:00
|
|
|
{
|
2012-05-25 12:41:19 +00:00
|
|
|
cerr << "ERROR: Cartridge4A40::save" << endl;
|
2008-02-21 23:58:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-10-09 23:56:57 +00:00
|
|
|
return true;
|
OK, another huge commit. I need to commit this now, because things are
starting to go out of sync on my development machines. OK, where to
begin ...
Changed state file format, so older state files will no longer work. The
changes aren't finalized yet, so expect more breakage.
Added getByte() and putByte() methods to serialized data, resulting in
smaller state files (previously, 1-byte values were stored as 4-byte ints).
Totally reworked controller handling code. Controller state is now
explicitly set with an ::update() method, making it easier to serialize.
Some work is still required on the serialization stuff for more advanced
controllers.
Added a 'Serializable' interface to all carts, device, controllers, etc
that can be (de)serialized. This fixes a long-standing design issue
which I personally caused many years ago.
Console switches state (SWCHB register) is now saved to state files.
Added beginnings of movie support. Basically, this saves an initial
state file, and thereafter continuously saves controller and console
switches state. Support is still somewhat rough and there's no UI for
it, but it does successfully save and later load/play state movies.
Removed specific events for driving controllers, and have them use
joystick events instead. This has the nice side effect that
joystick direction remapping 'just works' for driving controllers too.
Fixed issues with paddle emulation seen in 'Night Driver' ROM. Related
to this, removed a hack wrt paddles when grabmouse is enabled. There's
still some work to do when using the mouse to emulate paddles, but the
Stelladaptor and real paddles work fine.
Added beginnings of TrackBall CX-22 controller emulation. It doesn't
actually do anything yet, but the class is there :)
Probably some other stuff that I'm forgetting ...
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1385 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2007-10-03 21:41:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
OK, this looks like a huge update, but it's only because of some Serializer
class reworking. Serializer class now handles read/write of state from
files as well as in-memory streams. As a result, Deserializer class has
been removed.
Added state rewinding to the debugger. For now, this is limited to 100
levels of undo, with a new state generated each time a step/trace/frame/
scanline advance is performed. The undo level is 'rolling', in that it
remembers the last 100 levels (so you lose the oldest states when you
start adding more than 100). For now, this is tied to the 'Alt-r' key
in the debugger. Still TODO is add a button for it, and clean up some
TIA output issues when rewinding.
Added support for 6K version of Supercharger ROMs (this fixes issues
with the 6K version of Cubis).
Cleaned up the Serializable infrastructure, making sure that all
classes that need to implement it actually do so now.
Fixed issue with editable widgets in the UI, where pressing Enter
on the keypad wasn't actually being registered.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1849 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2009-08-05 16:05:34 +00:00
|
|
|
bool Cartridge4A50::load(Serializer& in)
|
OK, another huge commit. I need to commit this now, because things are
starting to go out of sync on my development machines. OK, where to
begin ...
Changed state file format, so older state files will no longer work. The
changes aren't finalized yet, so expect more breakage.
Added getByte() and putByte() methods to serialized data, resulting in
smaller state files (previously, 1-byte values were stored as 4-byte ints).
Totally reworked controller handling code. Controller state is now
explicitly set with an ::update() method, making it easier to serialize.
Some work is still required on the serialization stuff for more advanced
controllers.
Added a 'Serializable' interface to all carts, device, controllers, etc
that can be (de)serialized. This fixes a long-standing design issue
which I personally caused many years ago.
Console switches state (SWCHB register) is now saved to state files.
Added beginnings of movie support. Basically, this saves an initial
state file, and thereafter continuously saves controller and console
switches state. Support is still somewhat rough and there's no UI for
it, but it does successfully save and later load/play state movies.
Removed specific events for driving controllers, and have them use
joystick events instead. This has the nice side effect that
joystick direction remapping 'just works' for driving controllers too.
Fixed issues with paddle emulation seen in 'Night Driver' ROM. Related
to this, removed a hack wrt paddles when grabmouse is enabled. There's
still some work to do when using the mouse to emulate paddles, but the
Stelladaptor and real paddles work fine.
Added beginnings of TrackBall CX-22 controller emulation. It doesn't
actually do anything yet, but the class is there :)
Probably some other stuff that I'm forgetting ...
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1385 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2007-10-03 21:41:19 +00:00
|
|
|
{
|
2008-02-21 23:58:09 +00:00
|
|
|
try
|
|
|
|
{
|
2010-05-10 00:50:26 +00:00
|
|
|
if(in.getString() != name())
|
2008-02-21 23:58:09 +00:00
|
|
|
return false;
|
|
|
|
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getByteArray(myRAM, 32768);
|
2008-02-21 23:58:09 +00:00
|
|
|
|
|
|
|
// Index pointers
|
2012-05-20 14:23:48 +00:00
|
|
|
mySliceLow = in.getShort();
|
|
|
|
mySliceMiddle = in.getShort();
|
|
|
|
mySliceHigh = in.getShort();
|
2008-02-21 23:58:09 +00:00
|
|
|
|
|
|
|
// Whether index pointers are for ROM or RAM
|
|
|
|
myIsRomLow = in.getBool();
|
|
|
|
myIsRomMiddle = in.getBool();
|
|
|
|
myIsRomHigh = in.getBool();
|
|
|
|
|
|
|
|
// Last address and data values
|
2012-05-20 14:23:48 +00:00
|
|
|
myLastData = in.getByte();
|
|
|
|
myLastAddress = in.getShort();
|
2008-02-21 23:58:09 +00:00
|
|
|
}
|
2012-05-25 12:41:19 +00:00
|
|
|
catch(...)
|
2008-02-21 23:58:09 +00:00
|
|
|
{
|
2012-05-25 12:41:19 +00:00
|
|
|
cerr << "ERROR: Cartridge4A50::load" << endl;
|
2008-02-21 23:58:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-10-09 23:56:57 +00:00
|
|
|
return true;
|
OK, another huge commit. I need to commit this now, because things are
starting to go out of sync on my development machines. OK, where to
begin ...
Changed state file format, so older state files will no longer work. The
changes aren't finalized yet, so expect more breakage.
Added getByte() and putByte() methods to serialized data, resulting in
smaller state files (previously, 1-byte values were stored as 4-byte ints).
Totally reworked controller handling code. Controller state is now
explicitly set with an ::update() method, making it easier to serialize.
Some work is still required on the serialization stuff for more advanced
controllers.
Added a 'Serializable' interface to all carts, device, controllers, etc
that can be (de)serialized. This fixes a long-standing design issue
which I personally caused many years ago.
Console switches state (SWCHB register) is now saved to state files.
Added beginnings of movie support. Basically, this saves an initial
state file, and thereafter continuously saves controller and console
switches state. Support is still somewhat rough and there's no UI for
it, but it does successfully save and later load/play state movies.
Removed specific events for driving controllers, and have them use
joystick events instead. This has the nice side effect that
joystick direction remapping 'just works' for driving controllers too.
Fixed issues with paddle emulation seen in 'Night Driver' ROM. Related
to this, removed a hack wrt paddles when grabmouse is enabled. There's
still some work to do when using the mouse to emulate paddles, but the
Stelladaptor and real paddles work fine.
Added beginnings of TrackBall CX-22 controller emulation. It doesn't
actually do anything yet, but the class is there :)
Probably some other stuff that I'm forgetting ...
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1385 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
2007-10-03 21:41:19 +00:00
|
|
|
}
|