Updated DPC+ code to latest version from Spiceware. Hopefully we can get

final support for this completed before the 3.1 release next week.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2015 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-04-18 15:01:38 +00:00
parent 6dc6d959b5
commit 10022676e9
2 changed files with 95 additions and 168 deletions

View File

@ -1,8 +1,8 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// 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
@ -28,7 +28,6 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size)
: myFastFetch(false),
myLDAimmediate(false),
mySelectByte(0),
myMusicVolume(0),
mySystemCycles(0),
myFractionalClocks(0.0)
{
@ -41,7 +40,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size)
// Copy the display ROM image into my buffer
memcpy(myDisplayImage, image + 4096 * 6, 4096);
// Copy the Frequency ROM image into my buffer
memcpy(myFrequencyImage, image + 4096 * 6 + 4096, 1024);
@ -49,8 +48,8 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size)
for(uInt16 i = 0; i < 8; ++i)
myTops[i] = myBottoms[i] = myCounters[i] = myFlags[i] = myFractionalIncrements[i] = 0;
// Set waveforms to square waves
myMusicWaveforms[0] = myMusicWaveforms[1] = myMusicWaveforms[2] = 0xAAAAAAAA;
// 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+"
@ -91,10 +90,10 @@ void CartridgeDPCPlus::install(System& system)
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
assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0));
// Map all of the accesses to call peek and poke
System::PageAccess access;
access.directPeekBase = 0;
@ -103,7 +102,7 @@ void CartridgeDPCPlus::install(System& system)
access.type = System::PA_READ;
for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift))
mySystem->setPageAccess(i >> shift, access);
// Install pages for the startup bank
bank(myStartBank);
}
@ -128,23 +127,21 @@ inline void CartridgeDPCPlus::updateMusicModeDataFetchers()
// Calculate the number of cycles since the last update
Int32 cycles = mySystem->cycles() - mySystemCycles;
mySystemCycles = mySystem->cycles();
// 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;
if(wholeClocks <= 0)
{
return;
}
// Let's update counters and flags of the music mode data fetchers
for(int x = 5; x <= 7; ++x)
for(int x = 0; x <= 2; ++x)
{
myMusicCounters[x - 5] += myMusicFrequencies[x - 5];
if (myMusicFrequencies[x-5]>myMusicCounters[x-5])
myMusicWaveforms[x-5] = (myMusicWaveforms[x-5]>>1)|(myMusicWaveforms[x-5]<<31);
myMusicCounters[x] += myMusicFrequencies[x];
}
}
@ -153,66 +150,7 @@ inline void CartridgeDPCPlus::writeByte(uInt8 value)
{
switch (mySelectByte & 0x7F)
{
case 0x00:
{
myMusicWaveforms[0] = (myMusicWaveforms[0] & 0xFFFFFF00) | value;
break;
}
case 0x01:
{
myMusicWaveforms[0] = (myMusicWaveforms[0] & 0xFFFF00FF) | (value<<8);
break;
}
case 0x02:
{
myMusicWaveforms[0] = (myMusicWaveforms[0] & 0xFF00FFFF) | (value<<16);
break;
}
case 0x03:
{
myMusicWaveforms[0] = (myMusicWaveforms[0] & 0x00FFFFFF) | (value<<24);
break;
}
case 0x04:
{
myMusicWaveforms[1] = (myMusicWaveforms[1] & 0xFFFFFF00) | value;
break;
}
case 0x05:
{
myMusicWaveforms[1] = (myMusicWaveforms[1] & 0xFFFF00FF) | (value<<8);
break;
}
case 0x06:
{
myMusicWaveforms[1] = (myMusicWaveforms[1] & 0xFF00FFFF) | (value<<16);
break;
}
case 0x07:
{
myMusicWaveforms[1] = (myMusicWaveforms[1] & 0x00FFFFFF) | (value<<24);
break;
}
case 0x08:
{
myMusicWaveforms[2] = (myMusicWaveforms[2] & 0xFFFFFF00) | value;
break;
}
case 0x09:
{
myMusicWaveforms[2] = (myMusicWaveforms[2] & 0xFFFF00FF) | (value<<8);
break;
}
case 0x0A:
{
myMusicWaveforms[2] = (myMusicWaveforms[2] & 0xFF00FFFF) | (value<<16);
break;
}
case 0x0B:
{
myMusicWaveforms[2] = (myMusicWaveforms[2] & 0x00FFFFFF) | (value<<24);
break;
}
// reserved
}
if (mySelectByte & 0x80)
@ -225,7 +163,7 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
address &= 0x0FFF;
uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
// In debugger/bank-locked mode, we ignore all hotspots and in general
// anything that can change the internal state of the cart
if(bankLocked())
@ -235,19 +173,19 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
if(myFastFetch && myLDAimmediate)
{
if(peekvalue < 0x0028)
// if #value is a read-register then we want to use that as the address
// if #value is a read-register then we want to use that as the address
address = peekvalue;
}
myLDAimmediate = false;
if(address < 0x0028)
{
uInt8 result = 0;
// Get the index of the data fetcher that's being accessed
uInt32 index = address & 0x07;
uInt32 function = (address >> 3) & 0x07;
// Update flag register for selected data fetcher
if((myCounters[index] & 0x00ff) == ((myTops[index]+1) & 0xff))
{
@ -257,7 +195,7 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
{
myFlags[index] = 0x00;
}
switch(function)
{
case 0x00:
@ -268,36 +206,37 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
clockRandomNumberGenerator();
result = myRandomNumber & 0xFF;
break;
case 0x01: // RANDOM0PRIOR - return to prior and return byte 0 of random
priorClockRandomNumberGenerator();
result = myRandomNumber & 0xFF;
break;
case 0x02: // RANDOM1
result = (myRandomNumber>>8) & 0xFF;
break;
case 0x03: // RANDOM2
result = (myRandomNumber>>16) & 0xFF;
break;
case 0x04: // RANDOM3
result = (myRandomNumber>>24) & 0xFF;
break;
case 0x05: // AMPLITUDE
{
// Update the music data fetchers (counter & flag)
updateMusicModeDataFetchers();
uInt32 i = myMusicVolume +
(((myMusicWaveforms[0] >> 31) & 1) ? (myMusicVolume >> 12): 0) +
(((myMusicWaveforms[1] >> 31) & 1) ? (myMusicVolume >> 16): 0) +
(((myMusicWaveforms[2] >> 31) & 1) ? (myMusicVolume >> 24): 0);
// using myImageCopy[] instead of myDisplayImage[] because waveforms
// could also be in the 1K Frequency table.
uInt32 i = myImageCopy[6*4096 + (myMusicWaveforms[0] << 5) + (myMusicCounters[0] >> 27)] +
myImageCopy[6*4096 + (myMusicWaveforms[1] << 5) + (myMusicCounters[1] >> 27)] +
myImageCopy[6*4096 + (myMusicWaveforms[2] << 5) + (myMusicCounters[2] >> 27)];
result = (uInt8)i;
break;
break;
}
case 0x06: // reserved
@ -306,30 +245,30 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
}
break;
}
// DFxDATA - display data read
case 0x01:
{
result = myDisplayImage[myCounters[index]];
myCounters[index] = (myCounters[index] + 0x1) & 0x0fff;
myCounters[index] = (myCounters[index] + 0x1) & 0x0fff;
break;
}
// DFxDATAW - display data read AND'd w/flag ("windowed")
case 0x02:
{
result = myDisplayImage[myCounters[index]] & myFlags[index];
myCounters[index] = (myCounters[index] + 0x1) & 0x0fff;
myCounters[index] = (myCounters[index] + 0x1) & 0x0fff;
break;
}
}
// DFxFRACDATA - display data read w/fractional increment
case 0x03:
{
result = myDisplayImage[myFractionalCounters[index] >> 8];
myFractionalCounters[index] = (myFractionalCounters[index] + myFractionalIncrements[index]) & 0x0fffff;
myFractionalCounters[index] = (myFractionalCounters[index] + myFractionalIncrements[index]) & 0x0fffff;
break;
}
}
case 0x04:
{
@ -349,15 +288,15 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
case 0x07: // reserved
break;
}
break;
break;
}
default:
{
result = 0;
}
}
return result;
}
else
@ -369,36 +308,36 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
// Set the current bank to the first 4k bank
bank(0);
break;
case 0x0FF7:
// Set the current bank to the second 4k bank
bank(1);
break;
case 0x0FF8:
// Set the current bank to the third 4k bank
bank(2);
break;
case 0x0FF9:
// Set the current bank to the fourth 4k bank
bank(3);
break;
case 0x0FFA:
// Set the current bank to the fifth 4k bank
bank(4);
break;
case 0x0FFB:
// Set the current bank to the last 4k bank
bank(5);
break;
default:
break;
}
if(myFastFetch)
myLDAimmediate = (peekvalue == 0xA9);
@ -410,25 +349,25 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
{
address &= 0x0FFF;
if((address >= 0x0028) && (address < 0x0080))
if((address >= 0x0028) && (address < 0x0080))
{
// Get the index of the data fetcher that's being accessed
uInt32 index = address & 0x07;
uInt32 index = address & 0x07;
uInt32 function = ((address - 0x28) >> 3) & 0x0f;
switch(function)
{
//DFxFRACLOW - fractional data pointer low byte
case 0x00:
myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F0000) | ((uInt16)value << 8);
break;
// DFxFRACHI - fractional data pointer high byte
case 0x01:
myFractionalCounters[index] = (((uInt16)value & 0x0F) << 16) | (myFractionalCounters[index] & 0x00ffff);
break;
//DFxFRACINC - Fractional Increment amount
case 0x02:
myFractionalIncrements[index] = value;
@ -440,17 +379,17 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
myTops[index] = value;
myFlags[index] = 0x00;
break;
// DFxBOT - set bottom of window (for reads of DFxDATAW)
case 0x04:
myBottoms[index] = value;
break;
// DFxLOW - data pointer low byte
case 0x05:
myCounters[index] = (myCounters[index] & 0x0F00) | value ;
break;
// Control registers
case 0x06:
switch (index)
@ -471,18 +410,15 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
case 0x04: // reserved
break;
case 0x05: // VOLUME0
myMusicVolume = (myMusicVolume & 0xFFFF00FF) | ((value & 0x0F)<<12);
case 0x05: // WAVEFORM0
case 0x06: // WAVEFORM1
case 0x07: // WAVEFORM2
// make sure index isn't beyond the 29K cartridge space
// not sure how the Harmony handles it (most likely uses the ARM code),
// but we want to make sure an invalid memory access doesn't crash Stella.
if (value >=159) value = 0;
myMusicWaveforms[index - 5] = value;
break;
case 0x06: // VOLUME1
myMusicVolume = (myMusicVolume & 0xFF00FFFF) | ((value & 0x0F)<<16);
break;
case 0x07: // VOLUME2
myMusicVolume = (myMusicVolume & 0x00FFFFFF) | ((value & 0x0F)<<24);
break;
}
break;
@ -493,14 +429,14 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
myDisplayImage[myCounters[index]] = value;
break;
}
// DFxHI - data pointer high byte
case 0x08:
{
myCounters[index] = (((uInt16)value & 0x0F) << 8) | (myCounters[index] & 0x00ff);
break;
}
}
case 0x09:
{
switch (index)
@ -533,7 +469,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
case 0x05: // NOTE0
case 0x06: // NOTE1
case 0x07: // NOTE2
{
{
myMusicFrequencies[index-5] = myFrequencyImage[(value<<2)] +
(myFrequencyImage[(value<<2)+1]<<8) +
(myFrequencyImage[(value<<2)+2]<<16) +
@ -545,7 +481,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
}
break;
}
// DFxWRITE - write into data bank
case 0x0a:
{
@ -553,12 +489,12 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
myCounters[index] = (myCounters[index] + 0x1) & 0x0fff;
break;
}
default:
{
break;
}
}
}
}
else
{
@ -569,32 +505,32 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
// Set the current bank to the first 4k bank
bank(0);
break;
case 0x0FF7:
// Set the current bank to the second 4k bank
bank(1);
break;
case 0x0FF8:
// Set the current bank to the third 4k bank
bank(2);
break;
case 0x0FF9:
// Set the current bank to the fourth 4k bank
bank(3);
break;
case 0x0FFA:
// Set the current bank to the fifth 4k bank
bank(4);
break;
case 0x0FFB:
// Set the current bank to the last 4k bank
bank(5);
break;
default:
break;
}
@ -604,7 +540,7 @@ bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeDPCPlus::bank(uInt16 bank)
{
{
if(bankLocked()) return;
// Remember what bank we're in
@ -638,12 +574,12 @@ bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value)
}
else
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt8* CartridgeDPCPlus::getImage(int& size) const
{
size = 4096 * 6 + 4096 + 255;
size = 4096 * 6 + 4096 + 1024 + 255;
return myImageCopy;
}
@ -675,7 +611,7 @@ bool CartridgeDPCPlus::save(Serializer& out) const
out.putInt(8);
for(i = 0; i < 8; ++i)
out.putInt(myCounters[i]);
// The counter registers for the fractional data fetchers
out.putInt(8);
for(i = 0; i < 8; ++i)
@ -698,13 +634,10 @@ bool CartridgeDPCPlus::save(Serializer& out) const
// Control Byte to update
out.putByte((char) mySelectByte);
// The music volume
out.putInt(myMusicVolume);
// The music counters
out.putInt(3);
for(i = 0; i < 3; ++i)
out.putInt(myMusicCounters[i]);
out.putInt(myMusicCounters[i]);
// The music frequencies
out.putInt(3);
@ -783,23 +716,20 @@ bool CartridgeDPCPlus::load(Serializer& in)
// Control Byte to update
mySelectByte = (uInt8) in.getByte();
// The music volume
myMusicVolume = (uInt32) in.getInt();
// The music mode counters for the data fetchers
limit = (uInt32) in.getInt();
for(i = 0; i < limit; ++i)
myMusicCounters[i] = (uInt32) in.getInt();
myMusicCounters[i] = (uInt32) in.getInt();
// The music mode frequency addends for the data fetchers
limit = (uInt32) in.getInt();
for(i = 0; i < limit; ++i)
myMusicFrequencies[i] = (uInt32) in.getInt();
myMusicFrequencies[i] = (uInt32) in.getInt();
// The music waveforms
limit = (uInt32) in.getInt();
for(i = 0; i < limit; ++i)
myMusicWaveforms[i] = (uInt32) in.getInt();
myMusicWaveforms[i] = (uInt16) in.getInt();
// The random number generator register
myRandomNumber = (uInt32) in.getInt();

View File

@ -26,9 +26,9 @@ class System;
#include "Cart.hxx"
/**
Cartridge class used for DPC+. There are six 4K program banks, a
4K display bank, and the DPC chip. For complete details on the DPC chip
see David P. Crane's United States Patent Number 4,644,495.
Cartridge class used for DPC+. There are six 4K program banks, a 4K
display bank, 1K frequency table and the DPC chip. For complete details on
the DPC chip see David P. Crane's United States Patent Number 4,644,495.
@author Darrell Spice Jr, Fred Quimby, Stephen Anthony
@version $Id$
@ -208,9 +208,6 @@ class CartridgeDPCPlus : public Cartridge
// Control Byte to update
uInt8 mySelectByte;
// The music volume
uInt32 myMusicVolume;
// The music mode counters
uInt32 myMusicCounters[3];
@ -218,8 +215,8 @@ class CartridgeDPCPlus : public Cartridge
uInt32 myMusicFrequencies[3];
// The music waveforms
uInt32 myMusicWaveforms[3];
uInt16 myMusicWaveforms[3];
// The random number generator register
uInt32 myRandomNumber;