// Based on Apple in PC's mousecard.cpp // - Permission given by Kyle Kim to reuse in AppleWin /* Contiki v1.3: . I still see 2 cases of abnormal operation. These occur during boot up, during some period of disk access. . See Contiki's IRQ() in apple2-stdmou.s ** Normal operation ** : h/w asserts IRQ <6502 jumps to IRQ vector> . MOUSE_SERVE : h/w deasserts IRQ . MOUSE_READ . RTS with C=1 : h/w asserts IRQ <6502 jumps to IRQ vector> . MOUSE_SERVE : h/w deasserts IRQ . MOUSE_READ . RTS with C=1 Etc. ** Abnormal operation ** : h/w asserts IRQ <6502 jumps to IRQ vector> . MOUSE_SERVE (for VBL EVENT) : h/w deasserts IRQ : h/w asserts IRQ . MOUSE_READ - this clears the mouse IRQ status byte in the mouse-card's "h/w" . RTS with C=1 <6502 jumps to IRQ vector> . MOUSE_SERVE (for MOVEMENT EVENT) : h/w deasserts IRQ - but IRQ status byte is 0 . RTS with C=0 */ #include "StdAfx.h" #include "MouseInterface.h" #include "Common.h" #include "Core.h" // g_SynchronousEventMgr #include "CardManager.h" #include "CPU.h" #include "Interface.h" // FrameSetCursorPosByMousePos() #include "Memory.h" #include "NTSC.h" // NTSC_GetCyclesUntilVBlank() #include "YamlHelper.h" #include "../resource/resource.h" #ifdef _DEBUG #define _DEBUG_SPURIOUS_IRQ #endif // Sets mouse mode #define MOUSE_SET 0x00 // Reads mouse position #define MOUSE_READ 0x10 // Services mouse interrupt #define MOUSE_SERV 0x20 // Clears mouse positions to 0 (for delta mode) #define MOUSE_CLEAR 0x30 // Sets mouse position to a user-defined pos #define MOUSE_POS 0x40 // Resets mouse clamps to default values // Sets mouse position to 0,0 #define MOUSE_INIT 0x50 // Sets mouse bounds in a window #define MOUSE_CLAMP 0x60 // Sets mouse to upper-left corner of clamp win #define MOUSE_HOME 0x70 // Set VBL Timing : 0x90 is 60Hz, 0x91 is 50Hz #define MOUSE_TIME 0x90 #define BIT0 0x01 #define BIT1 0x02 #define BIT2 0x04 #define BIT3 0x08 #define BIT4 0x10 #define BIT5 0x20 #define BIT6 0x40 #define BIT7 0x80 // Interrupt status byte //Bit 7 6 5 4 3 2 1 0 // | | | | | | | | #define STAT_PREV_BUTTON1 (1<<0) // | | | | | | | \--- Previously, button 1 was up (0) or down (1) #define STAT_INT_MOVEMENT (1<<1) // | | | | | | \----- Movement interrupt #define STAT_INT_BUTTON (1<<2) // | | | | | \------- Button 0/1 interrupt #define STAT_INT_VBL (1<<3) // | | | | \--------- VBL interrupt #define STAT_CURR_BUTTON1 (1<<4) // | | | \----------- Currently, button 1 is up (0) or down (1) #define STAT_MOVEMENT_SINCE_READMOUSE (1<<5) // | | \------------- X/Y moved since last READMOUSE #define STAT_PREV_BUTTON0 (1<<6) // | \--------------- Previously, button 0 was up (0) or down (1) #define STAT_CURR_BUTTON0 (1<<7) // \----------------- Currently, button 0 is up (0) or down (1) #define STAT_INT_ALL (STAT_INT_VBL | STAT_INT_BUTTON | STAT_INT_MOVEMENT) // Mode byte //Bit 7 6 5 4 3 2 1 0 // | | | | | | | | #define MODE_MOUSE_ON (1<<0) // | | | | | | | \--- Mouse off (0) or on (1) #define MODE_INT_MOVEMENT (1<<1) // | | | | | | \----- Interrupt if mouse is moved #define MODE_INT_BUTTON (1<<2) // | | | | | \------- Interrupt if button is pressed #define MODE_INT_VBL (1<<3) // | | | | \--------- Interrupt on VBL [*1] #define MODE_RESERVED4 (1<<4) // | | | \----------- Reserved #define MODE_RESERVED5 (1<<5) // | | \------------- Reserved #define MODE_RESERVED6 (1<<6) // | \--------------- Reserved #define MODE_RESERVED7 (1<<7) // \----------------- Reserved #define MODE_INT_ALL STAT_INT_ALL // [*1] "A mode byte of $08 (mouse off but VBL interrupt on) will generate VBL interrupts." // Ref. Apple II Technical Notes - Mouse #3: "Mode Byte of the SetMouse Routine" //=========================================================================== void M6821_Listener_B( void* objTo, BYTE byData ) { ((CMouseInterface*)objTo)->On6821_B( byData ); } void M6821_Listener_A( void* objTo, BYTE byData ) { ((CMouseInterface*)objTo)->On6821_A( byData ); } //=========================================================================== CMouseInterface::CMouseInterface(UINT slot) : Card(CT_MouseInterface, slot), m_pSlotRom(NULL), m_syncEvent(slot, 0, SyncEventCallback) // use slot# as "unique" id for MouseInterfaces { if (m_slot != 4) // fixme ThrowErrorInvalidSlot(); m_6821.SetListenerB( this, M6821_Listener_B ); m_6821.SetListenerA( this, M6821_Listener_A ); // Uninitialize(); InitializeROM(); Reset(true); } CMouseInterface::~CMouseInterface() { delete [] m_pSlotRom; if (m_syncEvent.m_active) g_SynchronousEventMgr.Remove(m_syncEvent.m_id); } //=========================================================================== void CMouseInterface::InitializeROM(void) { _ASSERT(m_pSlotRom == NULL); if (m_pSlotRom) return; const UINT FW_SIZE = 2*1024; BYTE* pData = GetFrame().GetResource(IDR_MOUSEINTERFACE_FW, "FIRMWARE", FW_SIZE); if(pData == NULL) return; m_pSlotRom = new BYTE [FW_SIZE]; memcpy(m_pSlotRom, pData, FW_SIZE); } void CMouseInterface::InitializeIO(LPBYTE pCxRomPeripheral) { // m_bActive = true; m_bEnabled = true; SetSlotRom(); // Pre: m_bActive == true RegisterIoHandler(m_slot, &CMouseInterface::IORead, &CMouseInterface::IOWrite, NULL, NULL, this, NULL); if (m_syncEvent.m_active) g_SynchronousEventMgr.Remove(m_syncEvent.m_id); m_syncEvent.m_cyclesRemaining = NTSC_GetCyclesUntilVBlank(0); g_SynchronousEventMgr.Insert(&m_syncEvent); } #if 0 void CMouseInterface::Uninitialize() { // m_bActive = false; } #endif void CMouseInterface::Reset(const bool /* powerCycle */) { m_by6821A = 0; m_by6821B = 0x40; // Set PB6 m_6821.SetPB(m_by6821B); m_bVBL = false; m_byMode = 0; // m_nX = 0; m_nY = 0; m_iX = 0; m_iMinX = 0; m_iMaxX = 1023; m_iY = 0; m_iMinY = 0; m_iMaxY = 1023; m_bButtons[0] = m_bButtons[1] = false; // Clear(); memset( m_byBuff, 0, sizeof( m_byBuff ) ); SetSlotRom(); // NB. Leave the syncEvent in the list - otherwise nothing else will re-add it! } void CMouseInterface::SetSlotRom() { // if (!m_bActive) // return; LPBYTE pCxRomPeripheral = MemGetCxRomPeripheral(); if (pCxRomPeripheral == NULL) return; UINT uOffset = (m_by6821B << 7) & 0x0700; memcpy(pCxRomPeripheral+m_slot*256, m_pSlotRom+uOffset, 256); if (mem) memcpy(mem+0xC000+m_slot*256, m_pSlotRom+uOffset, 256); } //=========================================================================== BYTE __stdcall CMouseInterface::IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles) { UINT uSlot = ((uAddr & 0xff) >> 4) - 8; CMouseInterface* pMouseIF = (CMouseInterface*) MemGetSlotParameters(uSlot); BYTE byRS; byRS = uAddr & 3; return pMouseIF->m_6821.Read( byRS ); } BYTE __stdcall CMouseInterface::IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles) { UINT uSlot = ((uAddr & 0xff) >> 4) - 8; CMouseInterface* pMouseIF = (CMouseInterface*) MemGetSlotParameters(uSlot); BYTE byRS; byRS = uAddr & 3; pMouseIF->m_6821.Write( byRS, uValue ); return 0; } //=========================================================================== void CMouseInterface::On6821_A(BYTE byData) { m_by6821A = byData; } void CMouseInterface::On6821_B(BYTE byData) { BYTE byDiff = ( m_by6821B ^ byData ) & 0x3E; if ( byDiff ) { m_by6821B &= ~0x3E; m_by6821B |= byData & 0x3E; if ( byDiff & BIT5 ) // Write to 0285 chip { if ( byData & BIT5 ) m_by6821B |= BIT7; // OK, I'm ready to read from MC6821 else // Clock Activate for read { m_byBuff[m_nBuffPos++] = m_by6821A; if ( m_nBuffPos == 1 ) OnCommand(); if ( m_nBuffPos == m_nDataLen || m_nBuffPos > 7 ) { OnWrite(); // Have written all, Commit the command. m_nBuffPos = 0; } m_by6821B &= ~BIT7; // for next reading m_6821.SetPB( m_by6821B ); } } if ( byDiff & BIT4 ) // Read from 0285 chip ? { if ( byData & BIT4 ) m_by6821B &= ~BIT6; // OK, I'll prepare next value else // Clock Activate for write { if ( m_nBuffPos ) // if m_nBuffPos is 0, something goes wrong! m_nBuffPos++; if ( m_nBuffPos == m_nDataLen || m_nBuffPos > 7 ) m_nBuffPos = 0; // Have read all, ready for next command. else m_6821.SetPA( m_byBuff[m_nBuffPos] ); m_by6821B |= BIT6; // for next writing } } m_6821.SetPB( m_by6821B ); // SetSlotRom(); // Update Cn00 ROM page } } void CMouseInterface::OnCommand() { #ifdef _DEBUG_SPURIOUS_IRQ static UINT uSpuriousIrqCount = 0; BYTE byOldState = m_byState; #endif switch( m_byBuff[0] & 0xF0 ) { case MOUSE_SET: m_nDataLen = 1; m_byMode = m_byBuff[0] & 0x0F; break; case MOUSE_READ: // Read m_nDataLen = 6; m_byState &= STAT_MOVEMENT_SINCE_READMOUSE; m_nX = m_iX; m_nY = m_iY; if ( m_bBtn0 ) m_byState |= STAT_PREV_BUTTON0; // Previous Button 0 if ( m_bBtn1 ) m_byState |= STAT_PREV_BUTTON1; // Previous Button 1 m_bBtn0 = m_bButtons[0]; m_bBtn1 = m_bButtons[1]; if ( m_bBtn0 ) m_byState |= STAT_CURR_BUTTON0; // Current Button 0 if ( m_bBtn1 ) m_byState |= STAT_CURR_BUTTON1; // Current Button 1 m_byBuff[1] = m_nX & 0xFF; m_byBuff[2] = ( m_nX >> 8 ) & 0xFF; m_byBuff[3] = m_nY & 0xFF; m_byBuff[4] = ( m_nY >> 8 ) & 0xFF; m_byBuff[5] = m_byState; // button 0/1 interrupt status m_byState &= ~STAT_MOVEMENT_SINCE_READMOUSE; #ifdef _DEBUG_SPURIOUS_IRQ LogOutput("[MOUSE_READ] Old=%02X New=%02X\n", byOldState, m_byState); #endif break; case MOUSE_SERV: m_nDataLen = 2; m_byBuff[1] = m_byState & ~STAT_MOVEMENT_SINCE_READMOUSE; // reason of interrupt #ifdef _DEBUG_SPURIOUS_IRQ if ((m_byMode & MODE_INT_ALL) && (m_byBuff[1] & MODE_INT_ALL) == 0) { uSpuriousIrqCount++; LogOutput("[MOUSE_SERV] 0x%04X Buff[1]=0x%02X, ***\n", uSpuriousIrqCount, m_byBuff[1]); } else { LogOutput("[MOUSE_SERV] ------ Buff[1]=0x%02X\n", m_byBuff[1]); } #endif CpuIrqDeassert(IS_MOUSE); break; case MOUSE_CLEAR: Clear(); // [TC] NB. Don't reset clamp values (eg. Fantavision) m_nDataLen = 1; break; case MOUSE_POS: m_nDataLen = 5; break; case MOUSE_INIT: m_nDataLen = 3; m_byBuff[1] = 0xFF; // I don't know what it is break; case MOUSE_CLAMP: m_nDataLen = 5; break; case MOUSE_HOME: m_nDataLen = 1; SetPositionAbs( 0, 0 ); break; case MOUSE_TIME: // 0x90 switch( m_byBuff[0] & 0x0C ) { case 0x00: m_nDataLen = 1; break; // write cmd ( #$90 is DATATIME 60Hz, #$91 is 50Hz ) case 0x04: m_nDataLen = 3; break; // write cmd, $0478, $04F8 case 0x08: m_nDataLen = 2; break; // write cmd, $0578 case 0x0C: m_nDataLen = 4; break; // write cmd, $0478, $04F8, $0578 } break; case 0xA0: m_nDataLen = 2; break; case 0xB0: case 0xC0: m_nDataLen = 1; break; default: m_nDataLen = 1; //TRACE( "CMD : UNKNOWN CMD : #$%02X\n", m_byBuff[0] ); //_ASSERT(0); break; } m_6821.SetPA( m_byBuff[1] ); } void CMouseInterface::OnWrite() { int nMin, nMax; switch( m_byBuff[0] & 0xF0 ) { case MOUSE_CLAMP: // Blazing Paddles: // . MOUSE_CLAMP(Y, 0xFFEC, 0x00D3) // . MOUSE_CLAMP(X, 0xFFEC, 0x012B) nMin = ( m_byBuff[3] << 8 ) | m_byBuff[1]; nMax = ( m_byBuff[4] << 8 ) | m_byBuff[2]; if ( m_byBuff[0] & 1 ) // Clamp Y SetClampY( nMin, nMax ); else // Clamp X SetClampX( nMin, nMax ); break; case MOUSE_POS: m_nX = ( m_byBuff[2] << 8 ) | m_byBuff[1]; m_nY = ( m_byBuff[4] << 8 ) | m_byBuff[3]; SetPositionAbs( m_nX, m_nY ); break; case MOUSE_INIT: m_nX = 0; m_nY = 0; SetClampX( 0, 1023 ); SetClampY( 0, 1023 ); SetPositionAbs( 0, 0 ); break; } } void CMouseInterface::OnMouseEvent(bool bEventVBL) { int byState = 0; if ((m_byMode & MODE_INT_VBL) && bEventVBL) byState |= STAT_INT_VBL; if (m_byMode & MODE_MOUSE_ON) { if (m_nX != m_iX || m_nY != m_iY) { byState |= STAT_INT_MOVEMENT | STAT_MOVEMENT_SINCE_READMOUSE; // X/Y moved since last READMOUSE | Movement interrupt m_byState |= STAT_MOVEMENT_SINCE_READMOUSE; // [TC] Used by CopyII+9.1 and ProTERM3.1 } if (m_bBtn0 != m_bButtons[0] || m_bBtn1 != m_bButtons[1]) byState |= STAT_INT_BUTTON; // Button 0/1 interrupt byState &= ((m_byMode & MODE_INT_ALL) | STAT_MOVEMENT_SINCE_READMOUSE); // [TC] Keep "X/Y moved since last READMOUSE" for next MOUSE_READ (Contiki v1.3 uses this) } else // if MOUSE OFF then only consider VBL (GH#1138) { byState &= STAT_INT_VBL; } if ( byState & STAT_INT_ALL ) { m_byState |= byState; CpuIrqAssert(IS_MOUSE); #ifdef _DEBUG_SPURIOUS_IRQ LogOutput("[MOUSE EVNT] 0x%02X Mode=0x%02X\n", m_byState, m_byMode); #endif } } int CMouseInterface::SyncEventCallback(int id, int cycles, ULONG /*uExecutedCycles*/) { GetCardMgr().GetMouseCard()->OnMouseEvent(true); return NTSC_GetCyclesUntilVBlank(cycles); } void CMouseInterface::Clear() { m_nBuffPos = 0; m_nDataLen = 1; // m_byMode = 0; // Not for BeagleWrite / MultiScribe m_byState = 0; m_nX = 0; m_nY = 0; m_bBtn0 = false; m_bBtn1 = false; SetPositionAbs( 0, 0 ); // CpuIrqDeassert(IS_MOUSE); } //=========================================================================== int CMouseInterface::ClampX() { if ( m_iX > m_iMaxX ) { m_iX = m_iMaxX; return 1; } else if ( m_iX < m_iMinX ) { m_iX = m_iMinX; return -1; } return 0; } int CMouseInterface::ClampY() { if ( m_iY > m_iMaxY ) { m_iY = m_iMaxY; return 1; } else if ( m_iY < m_iMinY ) { m_iY = m_iMinY; return -1; } return 0; } void CMouseInterface::SetClampX(int iMinX, int iMaxX) { if ( (UINT)iMinX > 0xFFFF || (UINT)iMaxX > 0xFFFF ) { _ASSERT(0); return; } if ( iMinX > iMaxX ) { // For Blazing Paddles int iNewMaxX = (iMinX + iMaxX) & 0xFFFF; iMinX = 0; iMaxX = iNewMaxX; } m_iMaxX = iMaxX; m_iMinX = iMinX; ClampX(); } void CMouseInterface::SetClampY(int iMinY, int iMaxY) { if ( (UINT)iMinY > 0xFFFF || (UINT)iMaxY > 0xFFFF ) { _ASSERT(0); return; } if ( iMinY > iMaxY ) { // For Blazing Paddles int iNewMaxY = (iMinY + iMaxY) & 0xFFFF; iMinY = 0; iMaxY = iNewMaxY; } m_iMaxY = iMaxY; m_iMinY = iMinY; ClampY(); } void CMouseInterface::SetPositionAbs(int x, int y) { m_iX = x; m_iY = y; GetFrame().FrameSetCursorPosByMousePos(); } void CMouseInterface::SetPositionRel(long dX, long dY, int* pOutOfBoundsX, int* pOutOfBoundsY) { m_iX += dX; *pOutOfBoundsX = ClampX(); m_iY += dY; *pOutOfBoundsY = ClampY(); OnMouseEvent(); } void CMouseInterface::SetButton(eBUTTON Button, eBUTTONSTATE State) { m_bButtons[Button] = (State == BUTTON_DOWN); OnMouseEvent(); } #define SS_YAML_VALUE_CARD_MOUSE "Mouse Card" #define SS_YAML_KEY_MC6821 "MC6821" #define SS_YAML_KEY_PRA "PRA" #define SS_YAML_KEY_DDRA "DDRA" #define SS_YAML_KEY_CRA "CRA" #define SS_YAML_KEY_PRB "PRB" #define SS_YAML_KEY_DDRB "DDRB" #define SS_YAML_KEY_CRB "CRB" #define SS_YAML_KEY_IA "IA" #define SS_YAML_KEY_IB "IB" #define SS_YAML_KEY_DATALEN "DataLen" #define SS_YAML_KEY_MODE "Mode" #define SS_YAML_KEY_6821B "6821B" #define SS_YAML_KEY_6821A "6821A" #define SS_YAML_KEY_BUFF "Buffer" #define SS_YAML_KEY_BUFFPOS "Buffer Position" #define SS_YAML_KEY_MOUSESTATE "State" #define SS_YAML_KEY_X "X" #define SS_YAML_KEY_Y "Y" #define SS_YAML_KEY_BTN0 "Btn0" #define SS_YAML_KEY_BTN1 "Btn1" #define SS_YAML_KEY_VBL "VBL" #define SS_YAML_KEY_IX "iX" #define SS_YAML_KEY_IMINX "iMinX" #define SS_YAML_KEY_IMAXX "iMaxX" #define SS_YAML_KEY_IY "iY" #define SS_YAML_KEY_IMINY "iMinY" #define SS_YAML_KEY_IMAXY "iMaxY" #define SS_YAML_KEY_BUTTON0 "Button0" #define SS_YAML_KEY_BUTTON1 "Button1" #define SS_YAML_KEY_ENABLED "Enabled" const std::string& CMouseInterface::GetSnapshotCardName(void) { static const std::string name(SS_YAML_VALUE_CARD_MOUSE); return name; } void CMouseInterface::SaveSnapshotMC6821(YamlSaveHelper& yamlSaveHelper, std::string key) { mc6821_t mc6821; BYTE byIA; BYTE byIB; m_6821.Get6821(mc6821, byIA, byIB); YamlSaveHelper::Label label(yamlSaveHelper, "%s:\n", key.c_str()); yamlSaveHelper.SaveUint(SS_YAML_KEY_PRA, mc6821.pra); yamlSaveHelper.SaveUint(SS_YAML_KEY_DDRA, mc6821.ddra); yamlSaveHelper.SaveUint(SS_YAML_KEY_CRA, mc6821.cra); yamlSaveHelper.SaveUint(SS_YAML_KEY_PRB, mc6821.prb); yamlSaveHelper.SaveUint(SS_YAML_KEY_DDRB, mc6821.ddrb); yamlSaveHelper.SaveUint(SS_YAML_KEY_CRB, mc6821.crb); yamlSaveHelper.SaveUint(SS_YAML_KEY_IA, byIA); yamlSaveHelper.SaveUint(SS_YAML_KEY_IB, byIB); } void CMouseInterface::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) { // if (!m_bActive) // return; YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, 1); YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); SaveSnapshotMC6821(yamlSaveHelper, SS_YAML_KEY_MC6821); yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_DATALEN, m_nDataLen); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MODE, m_byMode); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_6821B, m_by6821B); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_6821A, m_by6821A); // New label { YamlSaveHelper::Label buffer(yamlSaveHelper, "%s:\n", SS_YAML_KEY_BUFF); yamlSaveHelper.SaveMemory(m_byBuff, sizeof(m_byBuff)); } yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_BUFFPOS, m_nBuffPos); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MOUSESTATE, m_byState); yamlSaveHelper.SaveUint(SS_YAML_KEY_X, m_nX); yamlSaveHelper.SaveUint(SS_YAML_KEY_Y, m_nY); yamlSaveHelper.SaveBool(SS_YAML_KEY_BTN0, m_bBtn0); yamlSaveHelper.SaveBool(SS_YAML_KEY_BTN1, m_bBtn1); yamlSaveHelper.SaveBool(SS_YAML_KEY_VBL, m_bVBL); yamlSaveHelper.SaveUint(SS_YAML_KEY_IX, m_iX); yamlSaveHelper.SaveUint(SS_YAML_KEY_IMINX, m_iMinX); yamlSaveHelper.SaveUint(SS_YAML_KEY_IMAXX, m_iMaxX); yamlSaveHelper.SaveUint(SS_YAML_KEY_IY, m_iY); yamlSaveHelper.SaveUint(SS_YAML_KEY_IMINY, m_iMinY); yamlSaveHelper.SaveUint(SS_YAML_KEY_IMAXY, m_iMaxY); yamlSaveHelper.SaveBool(SS_YAML_KEY_BUTTON0, m_bButtons[0]); yamlSaveHelper.SaveBool(SS_YAML_KEY_BUTTON1, m_bButtons[1]); yamlSaveHelper.SaveBool(SS_YAML_KEY_ENABLED, m_bEnabled); } void CMouseInterface::LoadSnapshotMC6821(YamlLoadHelper& yamlLoadHelper, std::string key) { if (!yamlLoadHelper.GetSubMap(key)) throw std::runtime_error("Card: Expected key: " + key); mc6821_t mc6821; mc6821.pra = yamlLoadHelper.LoadUint(SS_YAML_KEY_PRA); mc6821.ddra = yamlLoadHelper.LoadUint(SS_YAML_KEY_DDRA); mc6821.cra = yamlLoadHelper.LoadUint(SS_YAML_KEY_CRA); mc6821.prb = yamlLoadHelper.LoadUint(SS_YAML_KEY_PRB); mc6821.ddrb = yamlLoadHelper.LoadUint(SS_YAML_KEY_DDRB); mc6821.crb = yamlLoadHelper.LoadUint(SS_YAML_KEY_CRB); BYTE byIA = yamlLoadHelper.LoadUint(SS_YAML_KEY_IA); BYTE byIB = yamlLoadHelper.LoadUint(SS_YAML_KEY_IB); m_6821.Set6821(mc6821, byIA, byIB); yamlLoadHelper.PopMap(); } bool CMouseInterface::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) { if (version != 1) ThrowErrorInvalidVersion(version); LoadSnapshotMC6821(yamlLoadHelper, SS_YAML_KEY_MC6821); m_nDataLen = yamlLoadHelper.LoadUint(SS_YAML_KEY_DATALEN); m_byMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_MODE); m_by6821B = yamlLoadHelper.LoadUint(SS_YAML_KEY_6821B); m_by6821A = yamlLoadHelper.LoadUint(SS_YAML_KEY_6821A); if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_BUFF)) throw std::runtime_error("Card: Expected key: " SS_YAML_KEY_BUFF); yamlLoadHelper.LoadMemory(m_byBuff, sizeof(m_byBuff)); yamlLoadHelper.PopMap(); m_nBuffPos = yamlLoadHelper.LoadUint(SS_YAML_KEY_BUFFPOS); m_byState = yamlLoadHelper.LoadUint(SS_YAML_KEY_MOUSESTATE); m_nX = yamlLoadHelper.LoadInt(SS_YAML_KEY_X); m_nY = yamlLoadHelper.LoadInt(SS_YAML_KEY_Y); m_bBtn0 = yamlLoadHelper.LoadBool(SS_YAML_KEY_BTN0); m_bBtn1 = yamlLoadHelper.LoadBool(SS_YAML_KEY_BTN1); m_bVBL = yamlLoadHelper.LoadBool(SS_YAML_KEY_VBL); m_iX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IX); m_iMinX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMINX); m_iMaxX = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMAXX); m_iY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IY); m_iMinY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMINY); m_iMaxY = yamlLoadHelper.LoadInt(SS_YAML_KEY_IMAXY); m_bButtons[0] = yamlLoadHelper.LoadBool(SS_YAML_KEY_BUTTON0); m_bButtons[1] = yamlLoadHelper.LoadBool(SS_YAML_KEY_BUTTON1); m_bEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_ENABLED); // MemInitializeIO() calls Initialize() which sets true if (m_byState & STAT_INT_ALL) // GH#677 CpuIrqAssert(IS_MOUSE); return true; }