mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-12-22 09:30:15 +00:00
759 lines
21 KiB
C++
759 lines
21 KiB
C++
// 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 **
|
|
|
|
<VBL EVENT> : h/w asserts IRQ
|
|
<6502 jumps to IRQ vector>
|
|
. MOUSE_SERVE : h/w deasserts IRQ
|
|
. MOUSE_READ
|
|
. RTS with C=1
|
|
|
|
<VBL EVENT> : h/w asserts IRQ
|
|
<6502 jumps to IRQ vector>
|
|
. MOUSE_SERVE : h/w deasserts IRQ
|
|
. MOUSE_READ
|
|
. RTS with C=1
|
|
|
|
Etc.
|
|
|
|
** Abnormal operation **
|
|
|
|
<VBL EVENT> : h/w asserts IRQ
|
|
<6502 jumps to IRQ vector>
|
|
. MOUSE_SERVE (for VBL EVENT) : h/w deasserts IRQ
|
|
<VBL EVENT> : 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;
|
|
}
|