2010-03-18 17:34:53 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
2010-04-18 15:01:38 +00:00
|
|
|
// SSSS tt lll lll
|
|
|
|
// SS SS tt ll ll
|
|
|
|
// SS tttttt eeee ll ll aaaa
|
2010-03-18 17:34:53 +00:00
|
|
|
// 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
|
|
|
|
//
|
2014-01-12 17:23:42 +00:00
|
|
|
// Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony
|
2010-04-10 21:37:23 +00:00
|
|
|
// and the Stella Team
|
2010-03-18 17:34:53 +00:00
|
|
|
//
|
|
|
|
// See the file "License.txt" for information on usage and redistribution of
|
|
|
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
|
|
|
|
2011-05-10 15:04:19 +00:00
|
|
|
#ifdef DEBUGGER_SUPPORT
|
|
|
|
#include "Debugger.hxx"
|
|
|
|
#endif
|
2010-03-18 17:34:53 +00:00
|
|
|
#include "System.hxx"
|
2011-01-16 21:23:03 +00:00
|
|
|
#include "Thumbulator.hxx"
|
2010-03-18 17:34:53 +00:00
|
|
|
#include "CartDPCPlus.hxx"
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-08-19 21:48:28 +00:00
|
|
|
CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
|
|
|
const Settings& settings)
|
|
|
|
: Cartridge(settings),
|
|
|
|
myFastFetch(false),
|
2010-04-03 12:45:20 +00:00
|
|
|
myLDAimmediate(false),
|
2011-01-08 16:02:00 +00:00
|
|
|
myParameterPointer(0),
|
2010-04-02 18:56:50 +00:00
|
|
|
mySystemCycles(0),
|
|
|
|
myFractionalClocks(0.0)
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-05-02 22:52:59 +00:00
|
|
|
// Store image, making sure it's at least 29KB
|
|
|
|
uInt32 minsize = 4096 * 6 + 4096 + 1024 + 255;
|
|
|
|
mySize = BSPF_max(minsize, size);
|
|
|
|
myImage = new uInt8[mySize];
|
|
|
|
memcpy(myImage, image, size);
|
2010-10-03 18:19:09 +00:00
|
|
|
createCodeAccessBase(4096 * 6);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2010-05-02 22:52:59 +00:00
|
|
|
// Pointer to the program ROM (24K @ 0 byte offset)
|
|
|
|
myProgramImage = myImage;
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2011-01-16 21:23:03 +00:00
|
|
|
// Pointer to the display RAM
|
|
|
|
myDisplayImage = myDPCRAM + 0xC00;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2012-10-02 14:56:31 +00:00
|
|
|
// Pointer to the Frequency RAM
|
|
|
|
myFrequencyImage = myDisplayImage + 0x1000;
|
2010-05-02 22:52:59 +00:00
|
|
|
|
|
|
|
// If the image is larger than 29K, we assume any excess at the
|
|
|
|
// beginning is ARM code, and skip over it
|
|
|
|
if(size > 29 * 1024)
|
2013-04-20 22:23:42 +00:00
|
|
|
myProgramImage += (size - 29 * 1024);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
#ifdef THUMB_SUPPORT
|
2011-01-16 21:23:03 +00:00
|
|
|
// Create Thumbulator ARM emulator
|
|
|
|
myThumbEmulator = new Thumbulator((uInt16*)(myProgramImage-0xC00),
|
2011-11-07 22:50:23 +00:00
|
|
|
(uInt16*)myDPCRAM,
|
|
|
|
settings.getBool("thumb.trapfatal"));
|
2011-04-16 16:53:41 +00:00
|
|
|
#endif
|
2012-06-04 19:20:27 +00:00
|
|
|
setInitialState();
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2010-04-25 23:33:49 +00:00
|
|
|
// DPC+ always starts in bank 5
|
2010-03-28 03:13:10 +00:00
|
|
|
myStartBank = 5;
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
CartridgeDPCPlus::~CartridgeDPCPlus()
|
|
|
|
{
|
2010-05-02 22:52:59 +00:00
|
|
|
delete[] myImage;
|
2011-01-16 21:23:03 +00:00
|
|
|
|
2011-04-16 16:53:41 +00:00
|
|
|
#ifdef THUMB_SUPPORT
|
2011-01-16 21:23:03 +00:00
|
|
|
delete myThumbEmulator;
|
2011-04-16 16:53:41 +00:00
|
|
|
#endif
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void CartridgeDPCPlus::reset()
|
|
|
|
{
|
|
|
|
// Update cycles to the current system cycles
|
|
|
|
mySystemCycles = mySystem->cycles();
|
|
|
|
myFractionalClocks = 0.0;
|
|
|
|
|
2012-06-04 19:20:27 +00:00
|
|
|
setInitialState();
|
|
|
|
|
|
|
|
// Upon reset we switch to the startup bank
|
|
|
|
bank(myStartBank);
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void CartridgeDPCPlus::setInitialState()
|
|
|
|
{
|
2012-06-03 18:05:14 +00:00
|
|
|
// Reset various ROM and RAM locations
|
|
|
|
memset(myDPCRAM, 0, 8192);
|
|
|
|
|
|
|
|
// Copy initial DPC display data and Frequency table state to Harmony RAM
|
|
|
|
memcpy(myDisplayImage, myProgramImage + 0x6000, 0x1400);
|
|
|
|
|
|
|
|
// Initialize the DPC data fetcher registers
|
2013-04-21 20:02:55 +00:00
|
|
|
for(int i = 0; i < 8; ++i)
|
2012-06-03 18:05:14 +00:00
|
|
|
myTops[i] = myBottoms[i] = myCounters[i] = myFractionalIncrements[i] =
|
|
|
|
myFractionalCounters[i] = 0;
|
|
|
|
|
|
|
|
// Set waveforms to first waveform entry
|
|
|
|
myMusicWaveforms[0] = myMusicWaveforms[1] = myMusicWaveforms[2] = 0;
|
|
|
|
|
|
|
|
// Initialize the DPC's random number generator register (must be non-zero)
|
|
|
|
myRandomNumber = 0x2B435044; // "DPC+"
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void CartridgeDPCPlus::systemCyclesReset()
|
|
|
|
{
|
|
|
|
// Get the current system cycle
|
|
|
|
uInt32 cycles = mySystem->cycles();
|
|
|
|
|
|
|
|
// Adjust the cycle counter so that it reflects the new value
|
|
|
|
mySystemCycles -= cycles;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
void CartridgeDPCPlus::install(System& system)
|
|
|
|
{
|
|
|
|
mySystem = &system;
|
|
|
|
uInt16 shift = mySystem->pageShift();
|
|
|
|
uInt16 mask = mySystem->pageMask();
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
// Make sure the system we're being installed in has a page size that'll work
|
|
|
|
assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0));
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-10-03 18:19:09 +00:00
|
|
|
System::PageAccess access(0, 0, 0, this, System::PA_READ);
|
2010-10-03 00:23:13 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
// Map all of the accesses to call peek and poke
|
2010-10-03 18:19:09 +00:00
|
|
|
for(uInt32 i = 0x1000; i < 0x1080; i += (1 << shift))
|
2010-03-18 17:34:53 +00:00
|
|
|
mySystem->setPageAccess(i >> shift, access);
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-28 03:13:10 +00:00
|
|
|
// Install pages for the startup bank
|
|
|
|
bank(myStartBank);
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
inline void CartridgeDPCPlus::clockRandomNumberGenerator()
|
|
|
|
{
|
2010-03-28 03:13:10 +00:00
|
|
|
// Update random number generator (32-bit LFSR)
|
2011-01-08 16:02:00 +00:00
|
|
|
myRandomNumber = ((myRandomNumber & (1<<10)) ? 0x10adab1e: 0x00) ^
|
|
|
|
((myRandomNumber >> 11) | (myRandomNumber << 21));
|
2010-03-28 03:13:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
inline void CartridgeDPCPlus::priorClockRandomNumberGenerator()
|
|
|
|
{
|
|
|
|
// Update random number generator (32-bit LFSR, reversed)
|
2011-01-08 16:02:00 +00:00
|
|
|
myRandomNumber = ((myRandomNumber & (1<<31)) ?
|
|
|
|
((0x10adab1e^myRandomNumber) << 11) | ((0x10adab1e^myRandomNumber) >> 21) :
|
|
|
|
(myRandomNumber << 11) | (myRandomNumber >> 21));
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
inline void CartridgeDPCPlus::updateMusicModeDataFetchers()
|
|
|
|
{
|
|
|
|
// Calculate the number of cycles since the last update
|
|
|
|
Int32 cycles = mySystem->cycles() - mySystemCycles;
|
|
|
|
mySystemCycles = mySystem->cycles();
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
// Calculate the number of DPC OSC clocks since the last update
|
|
|
|
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
|
|
|
|
Int32 wholeClocks = (Int32)clocks;
|
|
|
|
myFractionalClocks = clocks - (double)wholeClocks;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
if(wholeClocks <= 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
// Let's update counters and flags of the music mode data fetchers
|
2010-04-18 15:01:38 +00:00
|
|
|
for(int x = 0; x <= 2; ++x)
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-04-18 15:01:38 +00:00
|
|
|
myMusicCounters[x] += myMusicFrequencies[x];
|
2010-04-04 13:15:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-04-25 23:33:49 +00:00
|
|
|
inline void CartridgeDPCPlus::callFunction(uInt8 value)
|
2010-04-04 13:15:35 +00:00
|
|
|
{
|
2011-04-16 16:53:41 +00:00
|
|
|
// myParameter
|
2011-01-09 15:21:23 +00:00
|
|
|
uInt16 ROMdata = (myParameter[1] << 8) + myParameter[0];
|
2010-04-25 23:33:49 +00:00
|
|
|
switch (value)
|
2010-04-04 13:15:35 +00:00
|
|
|
{
|
2011-01-08 16:02:00 +00:00
|
|
|
case 0: // Parameter Pointer reset
|
2011-01-09 15:21:23 +00:00
|
|
|
myParameterPointer = 0;
|
2011-01-08 16:02:00 +00:00
|
|
|
break;
|
|
|
|
case 1: // Copy ROM to fetcher
|
|
|
|
for(int i = 0; i < myParameter[3]; ++i)
|
2011-01-09 15:21:23 +00:00
|
|
|
myDisplayImage[myCounters[myParameter[2] & 0x7]+i] = myProgramImage[ROMdata+i];
|
2011-01-08 16:02:00 +00:00
|
|
|
myParameterPointer = 0;
|
|
|
|
break;
|
|
|
|
case 2: // Copy value to fetcher
|
|
|
|
for(int i = 0; i < myParameter[3]; ++i)
|
|
|
|
myDisplayImage[myCounters[myParameter[2]]+i] = myParameter[0];
|
|
|
|
myParameterPointer = 0;
|
|
|
|
break;
|
2011-04-16 16:53:41 +00:00
|
|
|
#ifdef THUMB_SUPPORT
|
2011-01-16 21:23:03 +00:00
|
|
|
case 254:
|
2011-04-16 16:53:41 +00:00
|
|
|
case 255:
|
|
|
|
// Call user written ARM code (most likely be C compiled for ARM)
|
2011-05-10 15:04:19 +00:00
|
|
|
try {
|
|
|
|
myThumbEmulator->run();
|
|
|
|
}
|
2011-05-24 16:04:48 +00:00
|
|
|
catch(const string& error) {
|
2012-06-03 18:05:14 +00:00
|
|
|
if(!mySystem->autodetectMode())
|
2011-05-24 16:04:48 +00:00
|
|
|
{
|
|
|
|
#ifdef DEBUGGER_SUPPORT
|
|
|
|
Debugger::debugger().startWithFatalError(error);
|
2011-05-26 16:14:46 +00:00
|
|
|
#else
|
|
|
|
cout << error << endl;
|
2011-05-24 16:04:48 +00:00
|
|
|
#endif
|
|
|
|
}
|
2011-05-10 15:04:19 +00:00
|
|
|
}
|
2010-04-25 23:33:49 +00:00
|
|
|
break;
|
2011-04-16 16:53:41 +00:00
|
|
|
#endif
|
2010-04-18 15:01:38 +00:00
|
|
|
// reserved
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
uInt8 CartridgeDPCPlus::peek(uInt16 address)
|
|
|
|
{
|
|
|
|
address &= 0x0FFF;
|
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
|
2010-05-12 00:01:06 +00:00
|
|
|
uInt8 flag;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
|
|
|
// anything that can change the internal state of the cart
|
|
|
|
if(bankLocked())
|
|
|
|
return peekvalue;
|
|
|
|
|
2010-04-03 12:45:20 +00:00
|
|
|
// Check if we're in Fast Fetch mode and the prior byte was an A9 (LDA #value)
|
2010-04-02 18:56:50 +00:00
|
|
|
if(myFastFetch && myLDAimmediate)
|
|
|
|
{
|
|
|
|
if(peekvalue < 0x0028)
|
2010-04-18 15:01:38 +00:00
|
|
|
// if #value is a read-register then we want to use that as the address
|
2010-04-02 18:56:50 +00:00
|
|
|
address = peekvalue;
|
|
|
|
}
|
|
|
|
myLDAimmediate = false;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
if(address < 0x0028)
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
|
|
|
uInt8 result = 0;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
// Get the index of the data fetcher that's being accessed
|
|
|
|
uInt32 index = address & 0x07;
|
|
|
|
uInt32 function = (address >> 3) & 0x07;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-05-12 00:01:06 +00:00
|
|
|
// Update flag for selected data fetcher
|
|
|
|
flag = (((myTops[index]-(myCounters[index] & 0x00ff)) & 0xFF) > ((myTops[index]-myBottoms[index]) & 0xFF)) ? 0xFF : 0;
|
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
switch(function)
|
|
|
|
{
|
|
|
|
case 0x00:
|
|
|
|
{
|
2010-03-28 03:13:10 +00:00
|
|
|
switch(index)
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x00: // RANDOM0NEXT - advance and return byte 0 of random
|
2010-03-28 03:13:10 +00:00
|
|
|
clockRandomNumberGenerator();
|
|
|
|
result = myRandomNumber & 0xFF;
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x01: // RANDOM0PRIOR - return to prior and return byte 0 of random
|
2010-03-28 03:13:10 +00:00
|
|
|
priorClockRandomNumberGenerator();
|
|
|
|
result = myRandomNumber & 0xFF;
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x02: // RANDOM1
|
2010-03-28 03:13:10 +00:00
|
|
|
result = (myRandomNumber>>8) & 0xFF;
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x03: // RANDOM2
|
2010-03-28 03:13:10 +00:00
|
|
|
result = (myRandomNumber>>16) & 0xFF;
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x04: // RANDOM3
|
2010-03-28 03:13:10 +00:00
|
|
|
result = (myRandomNumber>>24) & 0xFF;
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x05: // AMPLITUDE
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-03-28 03:13:10 +00:00
|
|
|
// Update the music data fetchers (counter & flag)
|
|
|
|
updateMusicModeDataFetchers();
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2011-11-05 22:31:40 +00:00
|
|
|
// using myDisplayImage[] instead of myProgramImage[] because waveforms
|
|
|
|
// can be modified during runtime.
|
|
|
|
uInt32 i = myDisplayImage[(myMusicWaveforms[0] << 5) + (myMusicCounters[0] >> 27)] +
|
|
|
|
myDisplayImage[(myMusicWaveforms[1] << 5) + (myMusicCounters[1] >> 27)] +
|
|
|
|
myDisplayImage[(myMusicWaveforms[2] << 5) + (myMusicCounters[2] >> 27)];
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
result = (uInt8)i;
|
2010-04-18 15:01:38 +00:00
|
|
|
break;
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
2010-04-02 18:56:50 +00:00
|
|
|
|
|
|
|
case 0x06: // reserved
|
|
|
|
case 0x07: // reserved
|
|
|
|
break;
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxDATA - display data read
|
2010-03-18 17:34:53 +00:00
|
|
|
case 0x01:
|
|
|
|
{
|
2010-04-02 18:56:50 +00:00
|
|
|
result = myDisplayImage[myCounters[index]];
|
2010-04-18 15:01:38 +00:00
|
|
|
myCounters[index] = (myCounters[index] + 0x1) & 0x0fff;
|
2010-03-18 17:34:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxDATAW - display data read AND'd w/flag ("windowed")
|
2010-03-18 17:34:53 +00:00
|
|
|
case 0x02:
|
|
|
|
{
|
2010-05-12 00:01:06 +00:00
|
|
|
result = myDisplayImage[myCounters[index]] & flag;
|
2010-04-18 15:01:38 +00:00
|
|
|
myCounters[index] = (myCounters[index] + 0x1) & 0x0fff;
|
2010-03-18 17:34:53 +00:00
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
}
|
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxFRACDATA - display data read w/fractional increment
|
2010-03-28 03:13:10 +00:00
|
|
|
case 0x03:
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-04-02 18:56:50 +00:00
|
|
|
result = myDisplayImage[myFractionalCounters[index] >> 8];
|
2010-04-18 15:01:38 +00:00
|
|
|
myFractionalCounters[index] = (myFractionalCounters[index] + myFractionalIncrements[index]) & 0x0fffff;
|
2010-03-18 17:34:53 +00:00
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
}
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x04:
|
|
|
|
{
|
|
|
|
switch (index)
|
|
|
|
{
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x00: // DF0FLAG
|
|
|
|
case 0x01: // DF1FLAG
|
|
|
|
case 0x02: // DF2FLAG
|
|
|
|
case 0x03: // DF3FLAG
|
2010-04-02 18:56:50 +00:00
|
|
|
{
|
2010-05-12 00:01:06 +00:00
|
|
|
result = flag;
|
2010-04-02 18:56:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 0x04: // reserved
|
|
|
|
case 0x05: // reserved
|
|
|
|
case 0x06: // reserved
|
|
|
|
case 0x07: // reserved
|
|
|
|
break;
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
break;
|
2010-04-02 18:56:50 +00:00
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Switch banks if necessary
|
|
|
|
switch(address)
|
|
|
|
{
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FF6:
|
|
|
|
// Set the current bank to the first 4k bank
|
|
|
|
bank(0);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FF7:
|
|
|
|
// Set the current bank to the second 4k bank
|
|
|
|
bank(1);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FF8:
|
|
|
|
// Set the current bank to the third 4k bank
|
|
|
|
bank(2);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FF9:
|
|
|
|
// Set the current bank to the fourth 4k bank
|
|
|
|
bank(3);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FFA:
|
|
|
|
// Set the current bank to the fifth 4k bank
|
|
|
|
bank(4);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FFB:
|
|
|
|
// Set the current bank to the last 4k bank
|
|
|
|
bank(5);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
default:
|
2010-03-18 17:34:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
if(myFastFetch)
|
|
|
|
myLDAimmediate = (peekvalue == 0xA9);
|
|
|
|
|
|
|
|
return peekvalue;
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-03-28 03:13:10 +00:00
|
|
|
bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
|
|
|
address &= 0x0FFF;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
|
|
|
if((address >= 0x0028) && (address < 0x0080))
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
|
|
|
// Get the index of the data fetcher that's being accessed
|
2010-04-18 15:01:38 +00:00
|
|
|
uInt32 index = address & 0x07;
|
2010-04-02 18:56:50 +00:00
|
|
|
uInt32 function = ((address - 0x28) >> 3) & 0x0f;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
switch(function)
|
|
|
|
{
|
2010-04-04 13:15:35 +00:00
|
|
|
//DFxFRACLOW - fractional data pointer low byte
|
2010-03-18 17:34:53 +00:00
|
|
|
case 0x00:
|
2010-04-02 18:56:50 +00:00
|
|
|
myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F0000) | ((uInt16)value << 8);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxFRACHI - fractional data pointer high byte
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x01:
|
|
|
|
myFractionalCounters[index] = (((uInt16)value & 0x0F) << 16) | (myFractionalCounters[index] & 0x00ffff);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
//DFxFRACINC - Fractional Increment amount
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x02:
|
2010-03-28 03:13:10 +00:00
|
|
|
myFractionalIncrements[index] = value;
|
2010-04-02 18:56:50 +00:00
|
|
|
myFractionalCounters[index] = myFractionalCounters[index] & 0x0FFF00;
|
2010-03-28 03:13:10 +00:00
|
|
|
break;
|
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxTOP - set top of window (for reads of DFxDATAW)
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x03:
|
2010-03-18 17:34:53 +00:00
|
|
|
myTops[index] = value;
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxBOT - set bottom of window (for reads of DFxDATAW)
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x04:
|
2010-03-18 17:34:53 +00:00
|
|
|
myBottoms[index] = value;
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxLOW - data pointer low byte
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x05:
|
|
|
|
myCounters[index] = (myCounters[index] & 0x0F00) | value ;
|
2010-03-18 17:34:53 +00:00
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
// Control registers
|
|
|
|
case 0x06:
|
|
|
|
switch (index)
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x00: // FASTFETCH - turns on LDA #<DFxDATA mode of value is 0
|
2010-04-02 18:56:50 +00:00
|
|
|
myFastFetch = (value == 0);
|
|
|
|
break;
|
2010-04-04 13:15:35 +00:00
|
|
|
|
2010-04-25 23:33:49 +00:00
|
|
|
case 0x01: // PARAMETER - set parameter used by CALLFUNCTION (not all functions use the parameter)
|
2011-01-09 15:21:23 +00:00
|
|
|
if(myParameterPointer < 8)
|
|
|
|
myParameter[myParameterPointer++] = value;
|
2010-04-03 12:45:20 +00:00
|
|
|
break;
|
2010-04-04 13:15:35 +00:00
|
|
|
|
2010-04-25 23:33:49 +00:00
|
|
|
case 0x02: // CALLFUNCTION
|
|
|
|
callFunction(value);
|
2010-04-03 12:45:20 +00:00
|
|
|
break;
|
2010-04-04 13:15:35 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x03: // reserved
|
|
|
|
case 0x04: // reserved
|
|
|
|
break;
|
2010-04-04 13:15:35 +00:00
|
|
|
|
2010-04-18 15:01:38 +00:00
|
|
|
case 0x05: // WAVEFORM0
|
|
|
|
case 0x06: // WAVEFORM1
|
|
|
|
case 0x07: // WAVEFORM2
|
2010-04-25 23:33:49 +00:00
|
|
|
myMusicWaveforms[index - 5] = value & 0x7f;
|
2010-04-02 18:56:50 +00:00
|
|
|
break;
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxPUSH - Push value into data bank
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x07:
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
2010-04-02 18:56:50 +00:00
|
|
|
myCounters[index] = (myCounters[index] - 0x1) & 0x0fff;
|
|
|
|
myDisplayImage[myCounters[index]] = value;
|
2010-03-28 03:13:10 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxHI - data pointer high byte
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x08:
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-04-02 18:56:50 +00:00
|
|
|
myCounters[index] = (((uInt16)value & 0x0F) << 8) | (myCounters[index] & 0x00ff);
|
2010-03-28 03:13:10 +00:00
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
}
|
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x09:
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
|
|
|
switch (index)
|
|
|
|
{
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x00: // RRESET - Random Number Generator Reset
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
|
|
|
myRandomNumber = 0x2B435044; // "DPC+"
|
|
|
|
break;
|
|
|
|
}
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x01: // RWRITE0 - update byte 0 of random number
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
|
|
|
myRandomNumber = (myRandomNumber & 0xFFFFFF00) | value;
|
|
|
|
break;
|
|
|
|
}
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x02: // RWRITE1 - update byte 1 of random number
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
|
|
|
myRandomNumber = (myRandomNumber & 0xFFFF00FF) | (value<<8);
|
|
|
|
break;
|
|
|
|
}
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x03: // RWRITE2 - update byte 2 of random number
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
|
|
|
myRandomNumber = (myRandomNumber & 0xFF00FFFF) | (value<<16);
|
|
|
|
break;
|
|
|
|
}
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x04: // RWRITE3 - update byte 3 of random number
|
2010-03-28 03:13:10 +00:00
|
|
|
{
|
|
|
|
myRandomNumber = (myRandomNumber & 0x00FFFFFF) | (value<<24);
|
|
|
|
break;
|
|
|
|
}
|
2010-04-04 13:15:35 +00:00
|
|
|
case 0x05: // NOTE0
|
|
|
|
case 0x06: // NOTE1
|
|
|
|
case 0x07: // NOTE2
|
2010-04-18 15:01:38 +00:00
|
|
|
{
|
2010-04-03 12:45:20 +00:00
|
|
|
myMusicFrequencies[index-5] = myFrequencyImage[(value<<2)] +
|
2010-04-02 18:56:50 +00:00
|
|
|
(myFrequencyImage[(value<<2)+1]<<8) +
|
|
|
|
(myFrequencyImage[(value<<2)+2]<<16) +
|
|
|
|
(myFrequencyImage[(value<<2)+3]<<24);
|
2010-03-28 03:13:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2010-03-18 17:34:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// DFxWRITE - write into data bank
|
2010-04-02 18:56:50 +00:00
|
|
|
case 0x0a:
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-04-02 18:56:50 +00:00
|
|
|
myDisplayImage[myCounters[index]] = value;
|
|
|
|
myCounters[index] = (myCounters[index] + 0x1) & 0x0fff;
|
2010-03-18 17:34:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-28 03:13:10 +00:00
|
|
|
default:
|
2010-04-02 18:56:50 +00:00
|
|
|
{
|
2010-03-28 03:13:10 +00:00
|
|
|
break;
|
2010-04-02 18:56:50 +00:00
|
|
|
}
|
2010-04-18 15:01:38 +00:00
|
|
|
}
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Switch banks if necessary
|
|
|
|
switch(address)
|
|
|
|
{
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FF6:
|
|
|
|
// Set the current bank to the first 4k bank
|
|
|
|
bank(0);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FF7:
|
|
|
|
// Set the current bank to the second 4k bank
|
|
|
|
bank(1);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FF8:
|
|
|
|
// Set the current bank to the third 4k bank
|
|
|
|
bank(2);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FF9:
|
|
|
|
// Set the current bank to the fourth 4k bank
|
|
|
|
bank(3);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FFA:
|
|
|
|
// Set the current bank to the fifth 4k bank
|
|
|
|
bank(4);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-22 17:24:08 +00:00
|
|
|
case 0x0FFB:
|
|
|
|
// Set the current bank to the last 4k bank
|
|
|
|
bank(5);
|
|
|
|
break;
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-03-28 03:13:10 +00:00
|
|
|
return false;
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-08-16 16:41:24 +00:00
|
|
|
bool CartridgeDPCPlus::bank(uInt16 bank)
|
2010-04-18 15:01:38 +00:00
|
|
|
{
|
2010-08-16 16:41:24 +00:00
|
|
|
if(bankLocked()) return false;
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// Remember what bank we're in
|
|
|
|
myCurrentBank = bank;
|
2010-10-03 18:19:09 +00:00
|
|
|
uInt16 offset = myCurrentBank << 12;
|
|
|
|
uInt16 shift = mySystem->pageShift();
|
|
|
|
|
|
|
|
// Setup the page access methods for the current bank
|
|
|
|
System::PageAccess access(0, 0, 0, this, System::PA_READ);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2010-10-03 18:19:09 +00:00
|
|
|
// Map Program ROM image into the system
|
|
|
|
for(uInt32 address = 0x1080; address < 0x2000; address += (1 << shift))
|
|
|
|
{
|
|
|
|
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
|
|
|
mySystem->setPageAccess(address >> shift, access);
|
|
|
|
}
|
2010-08-16 16:41:24 +00:00
|
|
|
return myBankChanged = true;
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-04-02 22:09:31 +00:00
|
|
|
uInt16 CartridgeDPCPlus::bank() const
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
|
|
|
return myCurrentBank;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-04-02 22:09:31 +00:00
|
|
|
uInt16 CartridgeDPCPlus::bankCount() const
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
|
|
|
return 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value)
|
|
|
|
{
|
2010-03-30 20:36:13 +00:00
|
|
|
address &= 0x0FFF;
|
|
|
|
|
|
|
|
// For now, we ignore attempts to patch the DPC address space
|
|
|
|
if(address >= 0x0080)
|
|
|
|
{
|
|
|
|
myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
|
|
|
return myBankChanged = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
2010-04-18 15:01:38 +00:00
|
|
|
}
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
2010-04-02 22:09:31 +00:00
|
|
|
const uInt8* CartridgeDPCPlus::getImage(int& size) const
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2010-05-02 22:52:59 +00:00
|
|
|
size = mySize;
|
|
|
|
return myImage;
|
2010-03-18 17:34:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
bool CartridgeDPCPlus::save(Serializer& out) const
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2010-05-10 00:50:26 +00:00
|
|
|
out.putString(name());
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// Indicates which bank is currently active
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putShort(myCurrentBank);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2012-06-03 18:05:14 +00:00
|
|
|
// Harmony RAM
|
|
|
|
out.putByteArray(myDPCRAM, 8192);
|
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
// The top registers for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putByteArray(myTops, 8);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// The bottom registers for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putByteArray(myBottoms, 8);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// The counter registers for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putShortArray(myCounters, 8);
|
2010-04-18 15:01:38 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
// The counter registers for the fractional data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putIntArray(myFractionalCounters, 8);
|
2010-04-02 18:56:50 +00:00
|
|
|
|
2010-03-28 03:13:10 +00:00
|
|
|
// The fractional registers for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putByteArray(myFractionalIncrements, 8);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
// The Fast Fetcher Enabled flag
|
|
|
|
out.putBool(myFastFetch);
|
|
|
|
out.putBool(myLDAimmediate);
|
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// Control Byte to update
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putByteArray(myParameter, 8);
|
2010-04-03 12:45:20 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// The music counters
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putIntArray(myMusicCounters, 3);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// The music frequencies
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putIntArray(myMusicFrequencies, 3);
|
2010-04-03 12:45:20 +00:00
|
|
|
|
|
|
|
// The music waveforms
|
2012-05-20 14:23:48 +00:00
|
|
|
out.putShortArray(myMusicWaveforms, 3);
|
2010-04-03 12:45:20 +00:00
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
// The random number generator register
|
2010-04-02 19:32:06 +00:00
|
|
|
out.putInt(myRandomNumber);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
out.putInt(mySystemCycles);
|
|
|
|
out.putInt((uInt32)(myFractionalClocks * 100000000.0));
|
|
|
|
}
|
2012-05-25 12:41:19 +00:00
|
|
|
catch(...)
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2012-05-25 12:41:19 +00:00
|
|
|
cerr << "ERROR: CartridgeDPCPlus::save" << endl;
|
2010-03-18 17:34:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
bool CartridgeDPCPlus::load(Serializer& in)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2010-05-10 00:50:26 +00:00
|
|
|
if(in.getString() != name())
|
2010-03-18 17:34:53 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Indicates which bank is currently active
|
2012-05-20 14:23:48 +00:00
|
|
|
myCurrentBank = in.getShort();
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2012-06-03 18:05:14 +00:00
|
|
|
// Harmony RAM
|
|
|
|
in.getByteArray(myDPCRAM, 8192);
|
|
|
|
|
2010-03-18 17:34:53 +00:00
|
|
|
// The top registers for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getByteArray(myTops, 8);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// The bottom registers for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getByteArray(myBottoms, 8);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// The counter registers for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getShortArray(myCounters, 8);
|
2010-04-02 18:56:50 +00:00
|
|
|
|
2010-04-02 19:32:06 +00:00
|
|
|
// The counter registers for the fractional data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getIntArray(myFractionalCounters, 8);
|
2010-03-28 03:13:10 +00:00
|
|
|
|
|
|
|
// The fractional registers for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getByteArray(myFractionalIncrements, 8);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
2010-04-02 18:56:50 +00:00
|
|
|
// The Fast Fetcher Enabled flag
|
|
|
|
myFastFetch = in.getBool();
|
|
|
|
myLDAimmediate = in.getBool();
|
|
|
|
|
2010-04-04 13:15:35 +00:00
|
|
|
// Control Byte to update
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getByteArray(myParameter, 8);
|
2010-04-03 12:45:20 +00:00
|
|
|
|
2010-03-28 03:13:10 +00:00
|
|
|
// The music mode counters for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getIntArray(myMusicCounters, 3);
|
2010-04-03 12:45:20 +00:00
|
|
|
|
2010-03-28 03:13:10 +00:00
|
|
|
// The music mode frequency addends for the data fetchers
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getIntArray(myMusicFrequencies, 3);
|
2010-04-03 12:45:20 +00:00
|
|
|
|
|
|
|
// The music waveforms
|
2012-05-20 14:23:48 +00:00
|
|
|
in.getShortArray(myMusicWaveforms, 3);
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// The random number generator register
|
2012-05-20 14:23:48 +00:00
|
|
|
myRandomNumber = in.getInt();
|
2010-03-18 17:34:53 +00:00
|
|
|
|
|
|
|
// Get system cycles and fractional clocks
|
2012-05-20 14:23:48 +00:00
|
|
|
mySystemCycles = (Int32)in.getInt();
|
2010-03-18 17:34:53 +00:00
|
|
|
myFractionalClocks = (double)in.getInt() / 100000000.0;
|
|
|
|
}
|
2012-05-25 12:41:19 +00:00
|
|
|
catch(...)
|
2010-03-18 17:34:53 +00:00
|
|
|
{
|
2012-05-25 12:41:19 +00:00
|
|
|
cerr << "ERROR: CartridgeDPCPlus::load" << endl;
|
2010-03-18 17:34:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, go to the current bank
|
|
|
|
bank(myCurrentBank);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|