mirror of https://github.com/stella-emu/stella.git
Various updates to the 'CTY' scheme, all by SpiceWare:
- music support - autodetection support - creation of 60K ROMs For the latter, I still need to see how we will distribute those ROMs, and get them added to the database.
This commit is contained in:
parent
8f03a48f11
commit
7982f7cb9b
|
@ -104,6 +104,10 @@
|
|||
|
||||
* Added recently released 'Arkyology' prototype ROM to the database.
|
||||
|
||||
* Added premliminary support for 'CTY' bankswitching scheme and recently
|
||||
released 'Chetiry' ROMs. Special thanks to SpiceWare for adding music
|
||||
support to this scheme.
|
||||
|
||||
* For UNIX systems: in the ROM launcher, when using symlinks use the
|
||||
symlink pathname instead of the underlying filesystem pathname.
|
||||
|
||||
|
|
|
@ -3587,7 +3587,7 @@ Ms Pac-Man (Stella extended codes):
|
|||
<tr><td>BUS </td><td>Experimental</td><td>.BUS </td></tr>
|
||||
<tr><td>CDF </td><td>Chris, Darrell, Fred</td><td>.CDF </td></tr>
|
||||
<tr><td>CM ¹</td><td>Spectravideo CompuMate </td><td>.CM </td></tr>
|
||||
<tr><td>CTY ¹²</td><td>CDW - Chetiry </td><td>.CTY </td></tr>
|
||||
<tr><td>CTY ²</td><td>CDW - Chetiry </td><td>.CTY </td></tr>
|
||||
<tr><td>CV </td><td>Commavid extra ram </td><td>.CV </td></tr>
|
||||
<tr><td>CV+ </td><td>Extended Commavid extra ram</td><td>.CVP </td></tr>
|
||||
<tr><td>DASH </td><td>Boulder Dash 2 </td><td>.DAS </td></tr>
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "OSystem.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "System.hxx"
|
||||
#include "CartCTYTunes.hxx"
|
||||
#include "CartCTY.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -27,7 +26,7 @@ CartridgeCTY::CartridgeCTY(const BytePtr& image, uInt32 size,
|
|||
: Cartridge(osystem.settings()),
|
||||
myOSystem(osystem),
|
||||
myOperationType(0),
|
||||
myCounter(0),
|
||||
myTunePosition(0),
|
||||
myLDAimmediate(false),
|
||||
myRandomNumber(0x2B435044),
|
||||
myRamAccessTimeout(0),
|
||||
|
@ -39,16 +38,24 @@ CartridgeCTY::CartridgeCTY(const BytePtr& image, uInt32 size,
|
|||
memcpy(myImage, image.get(), std::min(32768u, size));
|
||||
createCodeAccessBase(32768);
|
||||
|
||||
// Default to no tune data in case user is utilizing an old ROM
|
||||
memset(myTuneData, 0, 28*1024);
|
||||
|
||||
// Extract tune data if it exists
|
||||
if (size > 32768u)
|
||||
memcpy(myTuneData, image.get() + 32768u, size - 32768u);
|
||||
|
||||
// Point to the first tune
|
||||
myFrequencyImage = CartCTYTunes;
|
||||
myFrequencyImage = myTuneData;
|
||||
|
||||
for(uInt8 i = 0; i < 3; i++)
|
||||
myMusicCounters[i] = myMusicFrequencies[i] = 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCTY::reset()
|
||||
{
|
||||
initializeRAM(myRAM, 64);
|
||||
|
||||
// Remember startup bank (not bank 0, since that's ARM code)
|
||||
initializeStartBank(1);
|
||||
|
||||
myRAM[0] = myRAM[1] = myRAM[2] = myRAM[3] = 0xFF;
|
||||
|
@ -94,15 +101,23 @@ uInt8 CartridgeCTY::peek(uInt16 address)
|
|||
// Update the music data fetchers (counter & flag)
|
||||
updateMusicModeDataFetchers();
|
||||
|
||||
#if 0
|
||||
// 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)];
|
||||
return = (uInt8)i;
|
||||
#endif
|
||||
return 0xF2; // FIXME - return frequency value here
|
||||
uInt8 i = 0;
|
||||
|
||||
/*
|
||||
in the ARM driver registers 8-10 are the music counters 0-2
|
||||
lsr r2, r8, #31
|
||||
add r2, r2, r9, lsr #31
|
||||
add r2, r2, r10, lsr #31
|
||||
lsl r2, r2, #2
|
||||
*/
|
||||
|
||||
i = myMusicCounters[0] >> 31;
|
||||
i = i + (myMusicCounters[1] >> 31);
|
||||
i = i + (myMusicCounters[2] >> 31);
|
||||
i <<= 2;
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
else
|
||||
myLDAimmediate = false;
|
||||
|
@ -132,9 +147,9 @@ uInt8 CartridgeCTY::peek(uInt16 address)
|
|||
((myRandomNumber >> 11) | (myRandomNumber << 21));
|
||||
return myRandomNumber & 0xFF;
|
||||
case 0x02: // Get Tune position (low byte)
|
||||
return myCounter & 0xFF;
|
||||
return myTunePosition & 0xFF;
|
||||
case 0x03: // Get Tune position (high byte)
|
||||
return (myCounter >> 8) & 0xFF;
|
||||
return (myTunePosition >> 8) & 0xFF;
|
||||
default:
|
||||
return myRAM[address];
|
||||
}
|
||||
|
@ -175,7 +190,7 @@ bool CartridgeCTY::poke(uInt16 address, uInt8 value)
|
|||
//cerr << "POKE: address=" << HEX4 << address << ", value=" << HEX2 << value << endl;
|
||||
if(address < 0x0040) // Write port is at $1000 - $103F (64 bytes)
|
||||
{
|
||||
switch(address) // FIXME for functionality
|
||||
switch(address)
|
||||
{
|
||||
case 0x00: // Operation type for $1FF4
|
||||
myOperationType = value;
|
||||
|
@ -184,10 +199,16 @@ bool CartridgeCTY::poke(uInt16 address, uInt8 value)
|
|||
myRandomNumber = 0x2B435044;
|
||||
break;
|
||||
case 0x02: // Reset fetcher to beginning of tune
|
||||
myCounter = 0;
|
||||
myTunePosition = 0;
|
||||
myMusicCounters[0] = 0;
|
||||
myMusicCounters[1] = 0;
|
||||
myMusicCounters[2] = 0;
|
||||
myMusicFrequencies[0] = 0;
|
||||
myMusicFrequencies[1] = 0;
|
||||
myMusicFrequencies[2] = 0;
|
||||
break;
|
||||
case 0x03: // Advance fetcher to next tune position
|
||||
myCounter = (myCounter + 3) & 0x0fff;
|
||||
updateTune();
|
||||
break;
|
||||
default:
|
||||
myRAM[address] = value;
|
||||
|
@ -283,11 +304,14 @@ bool CartridgeCTY::save(Serializer& out) const
|
|||
out.putByteArray(myRAM, 64);
|
||||
|
||||
out.putByte(myOperationType);
|
||||
out.putShort(myCounter);
|
||||
out.putShort(myTunePosition);
|
||||
out.putBool(myLDAimmediate);
|
||||
out.putInt(myRandomNumber);
|
||||
out.putLong(myAudioCycles);
|
||||
out.putDouble(myFractionalClocks);
|
||||
out.putIntArray(myMusicCounters, 3);
|
||||
out.putIntArray(myMusicFrequencies, 3);
|
||||
out.putLong(myFrequencyImage - myTuneData);
|
||||
|
||||
}
|
||||
catch(...)
|
||||
|
@ -309,11 +333,14 @@ bool CartridgeCTY::load(Serializer& in)
|
|||
in.getByteArray(myRAM, 64);
|
||||
|
||||
myOperationType = in.getByte();
|
||||
myCounter = in.getShort();
|
||||
myTunePosition = in.getShort();
|
||||
myLDAimmediate = in.getBool();
|
||||
myRandomNumber = in.getInt();
|
||||
myAudioCycles = in.getLong();
|
||||
myFractionalClocks = in.getDouble();
|
||||
in.getIntArray(myMusicCounters, 3);
|
||||
in.getIntArray(myMusicFrequencies, 3);
|
||||
myFrequencyImage = myTuneData + in.getLong();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -415,10 +442,62 @@ void CartridgeCTY::loadTune(uInt8 index)
|
|||
// Each tune is offset by 4096 bytes
|
||||
// Instead of copying non-modifiable data around (as would happen on the
|
||||
// Harmony), we simply point to the appropriate tune
|
||||
myFrequencyImage = CartCTYTunes + (index << 12);
|
||||
myFrequencyImage = myTuneData + (index << 12);
|
||||
|
||||
// Reset to beginning of tune
|
||||
myCounter = 0;
|
||||
myTunePosition = 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCTY::updateTune()
|
||||
{
|
||||
//UpdateTune:
|
||||
// /* Float data bus */
|
||||
// strb r8, [r0, #+0x01]
|
||||
//
|
||||
// /* Increment song position */
|
||||
// add r7, r7, #1 r7 = songPosition
|
||||
//
|
||||
// /* Read song data (0 = continue) */
|
||||
// msr cpsr_c, #MODE_FIQ|I_BIT|F_BIT
|
||||
// ldrb r2, [r14], #1 r14 = myTunePosition, r2 = note
|
||||
// cmp r2, #0
|
||||
// ldrne r11, [r6, +r2, lsl #2] r6 +r2 = ourFrequencyTable[note]. Why lsl #2?
|
||||
// ldrb r2, [r14], #1 r11 = myMusicFrequency[0]
|
||||
// cmp r2, #0
|
||||
// ldrne r12, [r6, +r2, lsl #2] r12 = myMusicFrequency[1]
|
||||
// ldrb r2, [r14], #1
|
||||
// cmp r2, #1
|
||||
// ldrcs r13, [r6, +r2, lsl #2] r13 = myMusicFrequency[2]
|
||||
//
|
||||
// /* Reset tune */
|
||||
// mvneq r7, #0
|
||||
// moveq r14, r4 r4 = start of tune data
|
||||
// msr cpsr_c, #MODE_SYS|I_BIT|F_BIT
|
||||
//
|
||||
// /* Wait until address changes */
|
||||
//WaitAddrChangeA:
|
||||
// ldrh r2, [r0, #+0x16]
|
||||
// cmp r1, r2
|
||||
// beq WaitAddrChangeA
|
||||
// b NewAddress
|
||||
|
||||
myTunePosition += 1;
|
||||
uInt16 songPosition = (myTunePosition - 1) *3;
|
||||
|
||||
uInt8 note = myFrequencyImage[songPosition + 0];
|
||||
if (note)
|
||||
myMusicFrequencies[0] = ourFrequencyTable[note];
|
||||
|
||||
note = myFrequencyImage[songPosition + 1];
|
||||
if (note)
|
||||
myMusicFrequencies[1] = ourFrequencyTable[note];
|
||||
|
||||
note = myFrequencyImage[songPosition + 2];
|
||||
if (note == 1)
|
||||
myTunePosition = 0;
|
||||
else
|
||||
myMusicFrequencies[2] = ourFrequencyTable[note];
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -511,5 +590,139 @@ inline void CartridgeCTY::updateMusicModeDataFetchers()
|
|||
// Let's update counters and flags of the music mode data fetchers
|
||||
if(wholeClocks > 0)
|
||||
for(int x = 0; x <= 2; ++x)
|
||||
; //myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
|
||||
myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt32 CartridgeCTY::ourFrequencyTable[63] =
|
||||
{
|
||||
// this should really be referenced from within the ROM, but its part of
|
||||
// the Harmony/Melody CTY Driver, which does not appear to be in the ROM.
|
||||
|
||||
0, // CONT 0 Continue Note
|
||||
0, // REPEAT 1 Repeat Song
|
||||
0, // REST 2 Note Rest
|
||||
/*
|
||||
3511350 // C0
|
||||
3720300 // C0s
|
||||
3941491 // D0
|
||||
4175781 // D0s
|
||||
4424031 // E0
|
||||
4687313 // F0
|
||||
4965841 // F0s
|
||||
5261120 // G0
|
||||
5496699 // G0s
|
||||
|
||||
5905580 // A1
|
||||
6256694 // A1s
|
||||
6628853 // B1
|
||||
7022916 // C1
|
||||
7440601 // C1s
|
||||
7882983 // D1
|
||||
8351778 // D1s
|
||||
8848277 // E1
|
||||
9374625 // F1
|
||||
9931897 // F1s
|
||||
10522455 // G1
|
||||
11148232 // G1s
|
||||
*/
|
||||
11811160, // A2
|
||||
12513387, // A2s
|
||||
13257490, // B2
|
||||
14045832, // C2
|
||||
14881203, // C2s
|
||||
15765966, // D2
|
||||
16703557, // D2s
|
||||
17696768, // E2
|
||||
18749035, // F2
|
||||
19864009, // F2s
|
||||
21045125, // G2
|
||||
22296464, // G2s
|
||||
|
||||
23622320, // A3
|
||||
25026989, // A3s
|
||||
26515195, // B3
|
||||
28091878, // C3
|
||||
29762191, // C3s
|
||||
31531932, // D3
|
||||
33406900, // D3s
|
||||
35393537, // E3
|
||||
37498071, // F3
|
||||
39727803, // F3s
|
||||
42090250, // G3
|
||||
44592927, // G3s
|
||||
|
||||
47244640, // A4
|
||||
50053978, // A4s
|
||||
53030391, // B4
|
||||
56183756, // C4 (Middle C)
|
||||
59524596, // C4s
|
||||
63064079, // D4
|
||||
66814014, // D4s
|
||||
70787074, // E4
|
||||
74996142, // F4
|
||||
79455606, // F4s
|
||||
84180285, // G4
|
||||
89186069, // G4s
|
||||
|
||||
94489281, // A5
|
||||
100107957, // A5s
|
||||
106060567, // B5
|
||||
112367297, // C5
|
||||
119048977, // C5s
|
||||
126128157, // D5
|
||||
133628029, // D5s
|
||||
141573933, // E5
|
||||
149992288, // F5
|
||||
158911428, // F5s
|
||||
168360785, // G5
|
||||
178371925, // G5s
|
||||
|
||||
188978561, // A6
|
||||
200215913, // A6s
|
||||
212121348, // B6
|
||||
224734593, // C6
|
||||
238098169, // C6s
|
||||
252256099, // D6
|
||||
267256058, // D6s
|
||||
283147866, // E6
|
||||
299984783, // F6
|
||||
317822855, // F6s
|
||||
336721571, // G6
|
||||
356744064 // G6s
|
||||
/*
|
||||
377957122 // A7
|
||||
400431612 // A7s
|
||||
424242481 // B7
|
||||
449469401 // C7
|
||||
476196124 // C7s
|
||||
504512198 // D7
|
||||
534512116 // D7s
|
||||
566295948 // E7
|
||||
599969565 // F7
|
||||
635645496 // F7s
|
||||
673443141 // G7
|
||||
713488128 // G7s
|
||||
|
||||
755914244 // A8
|
||||
800863224 // A8s
|
||||
848484963 // B8
|
||||
898938588 // C8
|
||||
952392248 // C8s
|
||||
1009024398 // D8
|
||||
1069024232 // D8s
|
||||
1132591895 // E8
|
||||
1199939130 // F8
|
||||
1271290992 // F8s
|
||||
1346886282 // G8
|
||||
1426976255 // G8s
|
||||
|
||||
1511828488 // A9
|
||||
1601726449 // A9s
|
||||
1696969925 // B9
|
||||
1797877176 // C9
|
||||
1904784495 // C9s
|
||||
2018048796 // D9
|
||||
2138048463 // D9s
|
||||
*/
|
||||
};
|
||||
|
|
|
@ -83,8 +83,6 @@ class System;
|
|||
The tune table functionality is also based on Harmony EEPROM, where
|
||||
7 4K tunes are stored (28K total). The 'index' for operation 1 can
|
||||
therefore be in the range 0 - 6, indicating which tune to load.
|
||||
For this implementation, the 28K tune data is in the 'CartCTYTunes'
|
||||
header file.
|
||||
|
||||
DPC+:
|
||||
The music functionality is quite similar to the DPC+ scheme.
|
||||
|
@ -256,6 +254,8 @@ class CartridgeCTY : public Cartridge
|
|||
*/
|
||||
void updateMusicModeDataFetchers();
|
||||
|
||||
void updateTune();
|
||||
|
||||
private:
|
||||
// OSsytem currently in use
|
||||
const OSystem& myOSystem;
|
||||
|
@ -263,6 +263,9 @@ class CartridgeCTY : public Cartridge
|
|||
// The 32K ROM image of the cartridge
|
||||
uInt8 myImage[32768];
|
||||
|
||||
// The 28K ROM image of the music
|
||||
uInt8 myTuneData[28*1024];
|
||||
|
||||
// The 64 bytes of RAM accessible at $1000 - $1080
|
||||
uInt8 myRAM[64];
|
||||
|
||||
|
@ -270,11 +273,17 @@ class CartridgeCTY : public Cartridge
|
|||
uInt8 myOperationType;
|
||||
|
||||
// Pointer to the 28K frequency table (points to the start of one
|
||||
// of seven 4K tunes in CartCTYTunes)
|
||||
// of seven 4K tunes in myTuneData)
|
||||
const uInt8* myFrequencyImage;
|
||||
|
||||
// The counter register for the data fetcher
|
||||
uInt16 myCounter;
|
||||
uInt16 myTunePosition;
|
||||
|
||||
// The music mode counters
|
||||
uInt32 myMusicCounters[3];
|
||||
|
||||
// The music frequency
|
||||
uInt32 myMusicFrequencies[3];
|
||||
|
||||
// Flags that last byte peeked was A9 (LDA #)
|
||||
bool myLDAimmediate;
|
||||
|
@ -301,6 +310,8 @@ class CartridgeCTY : public Cartridge
|
|||
// Indicates the offset into the ROM image (aligns to current bank)
|
||||
uInt16 myBankOffset;
|
||||
|
||||
static const uInt32 ourFrequencyTable[63];
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeCTY() = delete;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -445,13 +445,18 @@ Bankswitch::Type CartDetector::autodetectType(const BytePtr& image, uInt32 size)
|
|||
type = Bankswitch::Type::_CDF;
|
||||
else if(isProbablyDPCplus(image, size))
|
||||
type = Bankswitch::Type::_DPCP;
|
||||
else if(isProbablyCTY(image, size))
|
||||
type = Bankswitch::Type::_CTY;
|
||||
else if(isProbablyFA2(image, size))
|
||||
type = Bankswitch::Type::_FA2;
|
||||
else
|
||||
type = Bankswitch::Type::_F4;
|
||||
}
|
||||
else if(size == 60*1024) // 60K
|
||||
{
|
||||
if(isProbablyCTY(image, size))
|
||||
type = Bankswitch::Type::_CTY;
|
||||
else
|
||||
type = Bankswitch::Type::_F4;
|
||||
}
|
||||
else if(size == 64*1024) // 64K
|
||||
{
|
||||
if(isProbably3E(image, size))
|
||||
|
@ -662,9 +667,10 @@ bool CartDetector::isProbably4A50(const BytePtr& image, uInt32 size)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartDetector::isProbablyCTY(const BytePtr&, uInt32)
|
||||
bool CartDetector::isProbablyCTY(const BytePtr& image, uInt32 size)
|
||||
{
|
||||
return false; // TODO - add autodetection
|
||||
uInt8 signature[] = { 'L', 'E', 'N', 'I', 'N' };
|
||||
return searchForBytes(image.get(), size, signature, 5, 1);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
Loading…
Reference in New Issue