AppleWin/source/Mockingboard.h

183 lines
6.1 KiB
C++

#pragma once
#include "6522.h"
#include "AY8910.h"
#include "Card.h"
#include "SoundCore.h"
#include "SSI263.h"
#include "SynchronousEventManager.h"
class MockingboardCard : public Card
{
public:
MockingboardCard(UINT slot, SS_CARDTYPE type);
virtual ~MockingboardCard(void);
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
virtual void Destroy();
virtual void Reset(const bool powerCycle);
virtual void Update(const ULONG executedCycles);
virtual void SaveSnapshot(YamlSaveHelper& yamlSaveHelper);
virtual bool LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version);
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
static BYTE __stdcall IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
static BYTE __stdcall PhasorIO(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles);
BYTE IOReadInternal(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles);
BYTE IOWriteInternal(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
BYTE PhasorIOInternal(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nExecutedCycles);
void ReinitializeClock(void);
void MuteControl(bool mute);
void UpdateCycles(ULONG executedCycles);
bool IsActive(void);
void SetVolume(DWORD dwVolume, DWORD dwVolumeMax);
void SetCumulativeCycles(void);
UINT MB_Update(void);
short** GetVoiceBuffers(void) { return m_ppAYVoiceBuffer; }
int GetNumSamplesError(void) { return m_numSamplesError; }
void SetNumSamplesError(int numSamplesError) { m_numSamplesError = numSamplesError; }
#ifdef _DEBUG
void CheckCumulativeCycles(void);
void Get6522IrqDescription(std::string& desc);
#endif
bool Is6522IRQ(void);
UINT64 GetLastCumulativeCycles(void);
void UpdateIFR(BYTE nDevice, BYTE clr_mask, BYTE set_mask);
BYTE GetPCR(BYTE nDevice);
bool IsAnyTimer1Active(void);
struct DEBUGGER_MB_SUBUNIT
{
BYTE regsSY6522[SY6522::SIZE_6522_REGS];
bool timer1Active;
bool timer2Active;
BYTE regsAY8913[NUM_AY8913_PER_SUBUNIT][16];
BYTE nAYCurrentRegister[NUM_AY8913_PER_SUBUNIT];
char szState[NUM_AY8913_PER_SUBUNIT][3]; // "--"(INACTIVE), "RD", "WR", "LA"
bool isAYLatchedAddressValid[NUM_AY8913_PER_SUBUNIT];
};
struct DEBUGGER_MB_CARD
{
SS_CARDTYPE type;
DEBUGGER_MB_SUBUNIT subUnit[NUM_SUBUNITS_PER_MB];
};
void GetSnapshotForDebugger(DEBUGGER_MB_CARD* const pMBForDebugger);
static std::string GetSnapshotCardName(void);
static std::string GetSnapshotCardNamePhasor(void);
static std::string GetSnapshotCardNameMegaAudio(void);
static std::string GetSnapshotCardNameSDMusic(void);
static const unsigned short NUM_MB_CHANNELS = 2;
static const DWORD SAMPLE_RATE = 44100; // Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample
private:
enum MockingboardUnitState_e { AY_NOP0, AY_NOP1, AY_INACTIVE, AY_READ, AY_NOP4, AY_NOP5, AY_WRITE, AY_LATCH };
struct MB_SUBUNIT
{
SY6522 sy6522;
AY8913 ay8913[NUM_AY8913_PER_SUBUNIT]; // Phasor has 2x AY per 6522
SSI263 ssi263;
BYTE nAY8910Number;
BYTE nAYCurrentRegister[NUM_AY8913_PER_SUBUNIT];
MockingboardUnitState_e state[NUM_AY8913_PER_SUBUNIT]; // AY's PSG function
bool isAYLatchedAddressValid[NUM_AY8913_PER_SUBUNIT];
bool isChipSelected[NUM_AY8913_PER_SUBUNIT];
bool isBusDriven;
MB_SUBUNIT(UINT slot, SS_CARDTYPE type) : sy6522(slot, type == CT_MegaAudio), ssi263(slot)
{
nAY8910Number = 0;
// sy6522 & ssi263 have already been default constructed
// Reset() called from MockingboardCard ctor
}
void Reset(SS_CARDTYPE type)
{
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_Phasor ? false : true; // Only Phasor is false, all other MB variants are true
isChipSelected[1] = false;
SetBusState(false);
}
void SetBusState(bool state)
{
isBusDriven = state;
sy6522.SetBusBeingDriven(state);
}
};
void WriteToORB(BYTE subunit, BYTE subunitForAY=0);
void AY8913_Reset(BYTE subunit);
void AY8913_Write(BYTE subunit, BYTE ay, BYTE value);
void UpdateIFRandIRQ(MB_SUBUNIT* pMB, BYTE clr_mask, BYTE set_mask);
void Phasor_SaveSnapshot(YamlSaveHelper& yamlSaveHelper);
bool Phasor_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version);
static int MB_SyncEventCallback(int id, int /*cycles*/, ULONG uExecutedCycles);
int MB_SyncEventCallbackInternal(int id, int /*cycles*/, ULONG uExecutedCycles);
//-------------------------------------
// MAME interface
BYTE AYReadReg(BYTE subunit, BYTE ay, int r);
void _AYWriteReg(BYTE subunit, BYTE ay, int r, int v);
void AY8910_reset(BYTE subunit, BYTE ay);
void AY8910Update(BYTE subunit, BYTE ay, INT16** buffer, int nNumSamples);
void AY8910_InitAll(int nClock, int nSampleRate);
void AY8910_InitClock(int nClock);
BYTE* AY8910_GetRegsPtr(BYTE subunit, BYTE ay);
void AY8910UpdateSetCycles();
UINT AY8910_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, BYTE subunit, BYTE ay, const std::string& suffix);
UINT AY8910_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, BYTE subunit, BYTE ay, const std::string& suffix);
UINT64 m_lastAYUpdateCycle;
//-------------------------------------
static const UINT SY6522_DEVICE_A = 0;
static const UINT SY6522_DEVICE_B = 1;
static const UINT AY8913_DEVICE_A = 0;
static const UINT AY8913_DEVICE_B = 1; // Phasor only
// Chip offsets from card base:
static const UINT SY6522A_Offset = 0x00;
static const UINT SY6522B_Offset = 0x80;
static const UINT SSI263B_Offset = 0x20;
static const UINT SSI263A_Offset = 0x40;
// MB has 2x (1x SY6522 + 1x AY8913), Phasor has 2x (1x SY6522 + 2x AY8913)
MB_SUBUNIT m_MBSubUnit[NUM_SUBUNITS_PER_MB];
static const UINT kNumSyncEvents = NUM_SY6522 * SY6522::kNumTimersPer6522;
SyncEvent* m_syncEvent[kNumSyncEvents];
UINT64 m_lastCumulativeCycle;
short* m_ppAYVoiceBuffer[NUM_VOICES];
UINT64 m_inActiveCycleCount;
bool m_regAccessedFlag;
bool m_isActive;
//
bool m_phasorEnable;
PHASOR_MODE m_phasorMode;
UINT m_phasorClockScaleFactor;
//
UINT64 m_lastMBUpdateCycle;
int m_numSamplesError;
};