Support MegaAudio card for mb-audit v1.4

This commit is contained in:
tomcw 2023-04-02 16:44:11 +01:00
parent cd9136ef1d
commit 4b05c2ca0a
10 changed files with 53 additions and 15 deletions

View File

@ -110,7 +110,8 @@ USHORT SY6522::SetTimerSyncEvent(BYTE reg, USHORT timerLatch)
if (syncEvent->m_active)
g_SynchronousEventMgr.Remove(syncEvent->m_id);
syncEvent->SetCycles(timerLatch + kExtraTimerCycles + opcodeCycleAdjust);
const UINT kMegaAudioAdjust = m_isMegaAudio ? 1 : 0; // MegaAudio asserts IRQ 1 cycle late!
syncEvent->SetCycles(timerLatch + kExtraTimerCycles + opcodeCycleAdjust + kMegaAudioAdjust);
g_SynchronousEventMgr.Insert(syncEvent);
// It doesn't matter if this overflows (ie. >0xFFFF), since on completion of current opcode it'll be corrected
@ -175,10 +176,12 @@ void SY6522::Write(BYTE nReg, BYTE nValue)
m_regs.TIMER1_LATCH.h = nValue;
break;
case 0x08: // TIMER2L
if (m_isMegaAudio) break; // MegaAudio: Assume no Timer2
m_regs.TIMER2_LATCH.l = nValue;
break;
case 0x09: // TIMER2H
{
if (m_isMegaAudio) break; // MegaAudio: Assume no Timer2
UpdateIFR(IxR_TIMER2); // Clear Timer2 Interrupt Flag
m_regs.TIMER2_LATCH.h = nValue; // NB. Real 6522 doesn't have TIMER2_LATCH.h
m_regs.TIMER2_COUNTER.w = SetTimerSyncEvent(nReg, m_regs.TIMER2_LATCH.w);
@ -347,10 +350,12 @@ BYTE SY6522::Read(BYTE nReg)
nValue = m_regs.TIMER1_LATCH.h;
break;
case 0x08: // TIMER2L
if (m_isMegaAudio) break; // MegaAudio: Assume no Timer2
nValue = GetTimer2Counter(nReg) & 0xff;
UpdateIFR(IxR_TIMER2);
break;
case 0x09: // TIMER2H
if (m_isMegaAudio) break; // MegaAudio: Assume no Timer2
nValue = GetTimer2Counter(nReg) >> 8;
break;
case 0x0a: // SERIAL_SHIFT
@ -370,6 +375,8 @@ BYTE SY6522::Read(BYTE nReg)
break;
case 0x0e: // IER
nValue = 0x80 | m_regs.IER; // GH#567
if (m_isMegaAudio)
nValue &= 0x7F;
break;
case 0x0f: // ORA_NO_HS
nValue = m_regs.ORA;

View File

@ -3,7 +3,7 @@
class SY6522
{
public:
SY6522(UINT slot) : m_slot(slot)
SY6522(UINT slot, bool isMegaAudio) : m_slot(slot), m_isMegaAudio(isMegaAudio)
{
for (UINT i = 0; i < kNumTimersPer6522; i++)
m_syncEvent[i] = NULL;
@ -143,4 +143,5 @@ private:
class SyncEvent* m_syncEvent[kNumTimersPer6522];
UINT m_slot;
bool m_isMegaAudio;
};

View File

@ -159,6 +159,8 @@ std::string Card::GetCardName(const SS_CARDTYPE cardType)
return VidHDCard::GetSnapshotCardName();
case CT_Uthernet2:
return Uthernet2::GetSnapshotCardName();
case CT_MegaAudio:
return MockingboardCard::GetSnapshotCardNameMegaAudio();
default:
return "Unknown";
}
@ -230,6 +232,10 @@ SS_CARDTYPE Card::GetCardType(const std::string & card)
{
return CT_Uthernet2;
}
else if (card == MockingboardCard::GetSnapshotCardNameMegaAudio())
{
return CT_MegaAudio;
}
else
{
throw std::runtime_error("Slots: Unknown card: " + card); // todo: don't throw - just ignore & continue

View File

@ -25,6 +25,7 @@ enum SS_CARDTYPE
CT_SNESMAX, // 2 port Nintendo NES/SNES controller serial interface card
CT_VidHD,
CT_Uthernet2,
CT_MegaAudio, // Soundcard
};
enum SLOTS { SLOT0=0, SLOT1, SLOT2, SLOT3, SLOT4, SLOT5, SLOT6, SLOT7, NUM_SLOTS, SLOT_AUX, GAME_IO_CONNECTOR };

View File

@ -66,6 +66,7 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
m_slot[slot] = m_pSSC = new CSuperSerialCard(slot);
break;
case CT_MockingboardC:
case CT_MegaAudio:
m_slot[slot] = new MockingboardCard(slot, type);
break;
case CT_GenericPrinter:

View File

@ -175,6 +175,8 @@ bool ProcessCmdLine(LPSTR lpCmdLine)
}
if (strcmp(lpCmdLine, "hdc") == 0)
g_cmdLine.slotInsert[slot] = CT_GenericHDD;
if (strcmp(lpCmdLine, "megaaudio") == 0)
g_cmdLine.slotInsert[slot] = CT_MegaAudio;
if (strcmp(lpCmdLine, "parallel") == 0)
{
if (slot == SLOT1)

View File

@ -62,7 +62,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//---------------------------------------------------------------------------
MockingboardCard::MockingboardCard(UINT slot, SS_CARDTYPE type) : Card(type, slot), m_MBSubUnit{slot, slot}
MockingboardCard::MockingboardCard(UINT slot, SS_CARDTYPE type) : Card(type, slot), m_MBSubUnit{ {slot, type}, {slot, type} }
{
m_lastCumulativeCycle = 0;
m_lastAYUpdateCycle = 0;
@ -206,7 +206,8 @@ void MockingboardCard::WriteToORB(BYTE subunit)
{
BYTE value = m_MBSubUnit[subunit].sy6522.Read(SY6522::rORB);
if (subunit == 0 && // SC01 only at $Cn00 (not $Cn80)
if ((QueryType() == CT_MockingboardC || QueryType() == CT_Phasor) && // Not CT_MegaAudio
subunit == 0 && // SC01 only at $Cn00 (not $Cn80)
m_MBSubUnit[subunit].sy6522.Read(SY6522::rPCR) == 0xB0)
{
// Votrax speech data
@ -748,10 +749,13 @@ BYTE MockingboardCard::IOWriteInternal(WORD PC, WORD nAddr, BYTE bWrite, BYTE nV
WriteToORB(subunit);
#if !DBG_MB_SS_CARD
if (nAddr & 0x40)
m_MBSubUnit[1].ssi263.Write(nAddr&0x7, nValue); // 2nd 6522 is used for 1st speech chip
if (nAddr & 0x20)
m_MBSubUnit[0].ssi263.Write(nAddr&0x7, nValue); // 1st 6522 is used for 2nd speech chip
if (QueryType() == CT_MockingboardC || QueryType() == CT_Phasor) // Not CT_MegaAudio
{
if (nAddr & 0x40)
m_MBSubUnit[1].ssi263.Write(nAddr & 0x7, nValue); // 2nd 6522 is used for 1st speech chip
if (nAddr & 0x20)
m_MBSubUnit[0].ssi263.Write(nAddr & 0x7, nValue); // 1st 6522 is used for 2nd speech chip
}
#endif
return 0;
@ -821,10 +825,10 @@ BYTE MockingboardCard::PhasorIOInternal(WORD PC, WORD nAddr, BYTE bWrite, BYTE n
void MockingboardCard::InitializeIO(LPBYTE pCxRomPeripheral)
{
if (QueryType() == CT_MockingboardC)
RegisterIoHandler(m_slot, IO_Null, IO_Null, IORead, IOWrite, this, NULL);
else // Phasor
if (QueryType() == CT_Phasor)
RegisterIoHandler(m_slot, PhasorIO, PhasorIO, IORead, IOWrite, this, NULL);
else // All other Mockingboard variants
RegisterIoHandler(m_slot, IO_Null, IO_Null, IORead, IOWrite, this, NULL);
if (g_bDisableDirectSound || g_bDisableDirectSoundMockingboard)
return;
@ -1146,6 +1150,12 @@ std::string MockingboardCard::GetSnapshotCardNamePhasor(void)
return name;
}
std::string MockingboardCard::GetSnapshotCardNameMegaAudio(void)
{
static const std::string name("MEGA Audio");
return name;
}
void MockingboardCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
if (QueryType() == CT_Phasor)
@ -1153,7 +1163,11 @@ void MockingboardCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
//
YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);
std::string cardName = GetSnapshotCardName();
if (QueryType() == CT_MegaAudio)
cardName = GetSnapshotCardNameMegaAudio();
YamlSaveHelper::Slot slot(yamlSaveHelper, cardName, m_slot, kUNIT_VERSION);
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);

View File

@ -68,6 +68,7 @@ public:
static std::string GetSnapshotCardName(void);
static std::string GetSnapshotCardNamePhasor(void);
static std::string GetSnapshotCardNameMegaAudio(void);
private:
enum MockingboardUnitState_e { AY_NOP0, AY_NOP1, AY_INACTIVE, AY_READ, AY_NOP4, AY_NOP5, AY_WRITE, AY_LATCH };
@ -83,7 +84,7 @@ private:
bool isAYLatchedAddressValid[NUM_AY8913_PER_SUBUNIT];
bool isChipSelected[NUM_AY8913_PER_SUBUNIT];
MB_SUBUNIT(UINT slot) : sy6522(slot), ssi263(slot)
MB_SUBUNIT(UINT slot, SS_CARDTYPE type) : sy6522(slot, type == CT_MegaAudio), ssi263(slot)
{
nAY8910Number = 0;
// sy6522 & ssi263 have already been default constructed
@ -95,7 +96,7 @@ private:
nAYCurrentRegister[0] = nAYCurrentRegister[1] = 0; // not valid
state[0] = state[1] = AY_INACTIVE;
isAYLatchedAddressValid[0] = isAYLatchedAddressValid[1] = false; // after AY reset
isChipSelected[0] = type == CT_MockingboardC ? true : false;
isChipSelected[0] = type == CT_Phasor ? false : true; // Only Phasor is false, all other MB variants are true
isChipSelected[1] = false;
}
};

View File

@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bool MockingboardCardManager::IsMockingboard(UINT slot)
{
SS_CARDTYPE type = GetCardMgr().QuerySlot(slot);
return type == CT_MockingboardC || type == CT_Phasor;
return type == CT_MockingboardC || type == CT_Phasor || type == CT_MegaAudio;
}
void MockingboardCardManager::ReinitializeClock(void)

View File

@ -775,6 +775,11 @@ static void RepeatInitialization(void)
GetCardMgr().Insert(SLOT3, g_cmdLine.slotInsert[SLOT3]);
}
if (g_cmdLine.slotInsert[SLOT4] != CT_Empty)
{
GetCardMgr().Insert(SLOT4, g_cmdLine.slotInsert[SLOT4]);
}
if (g_cmdLine.slotInsert[SLOT5] != CT_Empty)
{
if (GetCardMgr().QuerySlot(SLOT5) != CT_Disk2) // Ignore if already got Disk2 in slot 5