2007-08-06 21:38:35 +00:00
// Based on Apple in PC's mousecard.cpp
// - Permission given by Kyle Kim to reuse in AppleWin
2008-06-20 21:35:55 +00:00
/*
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
*/
2018-02-24 15:12:40 +00:00
# include "StdAfx.h"
2020-11-11 21:15:27 +00:00
# include "MouseInterface.h"
2014-08-14 16:48:38 +00:00
# include "Common.h"
2010-02-14 21:11:26 +00:00
2020-11-26 21:50:06 +00:00
# include "Core.h" // g_SynchronousEventMgr
2020-10-11 15:08:05 +00:00
# include "CardManager.h"
2014-08-13 20:30:35 +00:00
# include "CPU.h"
2020-11-29 17:30:06 +00:00
# include "Interface.h" // FrameSetCursorPosByMousePos()
2014-08-13 20:30:35 +00:00
# include "Memory.h"
2020-10-11 15:08:05 +00:00
# include "NTSC.h" // NTSC_GetCyclesUntilVBlank()
2015-12-05 16:50:27 +00:00
# include "YamlHelper.h"
2014-08-13 20:30:35 +00:00
2018-02-24 15:12:40 +00:00
# include "../resource/resource.h"
2009-02-17 01:35:04 +00:00
# ifdef _DEBUG
# define _DEBUG_SPURIOUS_IRQ
# endif
2007-08-06 21:38:35 +00:00
// 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
2008-06-20 21:35:55 +00:00
// 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
2022-11-17 22:23:20 +00:00
# define MODE_INT_VBL (1<<3) // | | | | \--------- Interrupt on VBL [*1]
2008-06-20 21:35:55 +00:00
# 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
2022-11-17 22:23:20 +00:00
// [*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"
2009-01-09 23:27:29 +00:00
//===========================================================================
2008-06-20 21:35:55 +00:00
2009-01-09 23:27:29 +00:00
void M6821_Listener_B ( void * objTo , BYTE byData )
2007-08-06 21:38:35 +00:00
{
( ( CMouseInterface * ) objTo ) - > On6821_B ( byData ) ;
}
2009-01-09 23:27:29 +00:00
void M6821_Listener_A ( void * objTo , BYTE byData )
2007-08-06 21:38:35 +00:00
{
( ( CMouseInterface * ) objTo ) - > On6821_A ( byData ) ;
}
//===========================================================================
2019-12-19 19:42:30 +00:00
CMouseInterface : : CMouseInterface ( UINT slot ) :
2021-11-01 21:01:28 +00:00
Card ( CT_MouseInterface , slot ) ,
2020-10-11 15:08:05 +00:00
m_pSlotRom ( NULL ) ,
m_syncEvent ( slot , 0 , SyncEventCallback ) // use slot# as "unique" id for MouseInterfaces
2007-08-06 21:38:35 +00:00
{
2021-11-25 20:23:21 +00:00
if ( m_slot ! = 4 ) // fixme
2022-01-30 21:25:40 +00:00
ThrowErrorInvalidSlot ( ) ;
2021-11-25 20:23:21 +00:00
2007-08-06 21:38:35 +00:00
m_6821 . SetListenerB ( this , M6821_Listener_B ) ;
m_6821 . SetListenerA ( this , M6821_Listener_A ) ;
2019-12-19 19:42:30 +00:00
// Uninitialize();
InitializeROM ( ) ;
2022-03-11 22:17:03 +00:00
Reset ( true ) ;
2007-08-06 21:38:35 +00:00
}
CMouseInterface : : ~ CMouseInterface ( )
{
delete [ ] m_pSlotRom ;
2020-10-11 15:08:05 +00:00
if ( m_syncEvent . m_active )
g_SynchronousEventMgr . Remove ( m_syncEvent . m_id ) ;
2007-08-06 21:38:35 +00:00
}
//===========================================================================
2019-12-19 19:42:30 +00:00
void CMouseInterface : : InitializeROM ( void )
2007-08-06 21:38:35 +00:00
{
2019-12-19 19:42:30 +00:00
_ASSERT ( m_pSlotRom = = NULL ) ;
if ( m_pSlotRom )
return ;
2007-08-06 21:38:35 +00:00
const UINT FW_SIZE = 2 * 1024 ;
2021-01-19 20:37:43 +00:00
BYTE * pData = GetFrame ( ) . GetResource ( IDR_MOUSEINTERFACE_FW , " FIRMWARE " , FW_SIZE ) ;
2007-08-06 21:38:35 +00:00
if ( pData = = NULL )
return ;
2019-12-19 19:42:30 +00:00
m_pSlotRom = new BYTE [ FW_SIZE ] ;
memcpy ( m_pSlotRom , pData , FW_SIZE ) ;
}
2007-08-06 21:38:35 +00:00
2021-11-01 20:39:26 +00:00
void CMouseInterface : : InitializeIO ( LPBYTE pCxRomPeripheral )
2019-12-19 19:42:30 +00:00
{
// m_bActive = true;
m_bEnabled = true ;
2007-12-02 14:55:32 +00:00
SetSlotRom ( ) ; // Pre: m_bActive == true
2021-11-01 21:01:28 +00:00
RegisterIoHandler ( m_slot , & CMouseInterface : : IORead , & CMouseInterface : : IOWrite , NULL , NULL , this , NULL ) ;
2020-10-11 15:08:05 +00:00
if ( m_syncEvent . m_active ) g_SynchronousEventMgr . Remove ( m_syncEvent . m_id ) ;
m_syncEvent . m_cyclesRemaining = NTSC_GetCyclesUntilVBlank ( 0 ) ;
g_SynchronousEventMgr . Insert ( & m_syncEvent ) ;
2007-08-06 21:38:35 +00:00
}
2019-12-19 19:42:30 +00:00
#if 0
2007-12-01 21:21:40 +00:00
void CMouseInterface : : Uninitialize ( )
{
2019-12-19 19:42:30 +00:00
// m_bActive = false;
2007-12-01 21:21:40 +00:00
}
2019-12-19 19:42:30 +00:00
# endif
2007-12-01 21:21:40 +00:00
2022-03-11 22:17:03 +00:00
void CMouseInterface : : Reset ( const bool /* powerCycle */ )
2007-12-01 21:21:40 +00:00
{
m_by6821A = 0 ;
m_by6821B = 0x40 ; // Set PB6
m_6821 . SetPB ( m_by6821B ) ;
2008-06-20 21:35:55 +00:00
m_bVBL = false ;
2014-09-29 21:43:15 +00:00
m_byMode = 0 ;
2007-12-01 21:21:40 +00:00
//
2007-12-02 14:55:32 +00:00
m_nX = 0 ;
m_nY = 0 ;
2007-12-01 21:21:40 +00:00
m_iX = 0 ;
m_iMinX = 0 ;
m_iMaxX = 1023 ;
m_iY = 0 ;
m_iMinY = 0 ;
m_iMaxY = 1023 ;
2016-02-20 17:57:23 +00:00
m_bButtons [ 0 ] = m_bButtons [ 1 ] = false ;
2007-12-01 21:21:40 +00:00
//
Clear ( ) ;
memset ( m_byBuff , 0 , sizeof ( m_byBuff ) ) ;
SetSlotRom ( ) ;
2020-10-11 15:08:05 +00:00
// NB. Leave the syncEvent in the list - otherwise nothing else will re-add it!
2007-12-01 21:21:40 +00:00
}
2007-08-06 21:38:35 +00:00
void CMouseInterface : : SetSlotRom ( )
{
2019-12-19 19:42:30 +00:00
// if (!m_bActive)
// return;
2007-12-01 21:21:40 +00:00
2007-08-06 21:38:35 +00:00
LPBYTE pCxRomPeripheral = MemGetCxRomPeripheral ( ) ;
if ( pCxRomPeripheral = = NULL )
return ;
UINT uOffset = ( m_by6821B < < 7 ) & 0x0700 ;
2021-11-01 21:01:28 +00:00
memcpy ( pCxRomPeripheral + m_slot * 256 , m_pSlotRom + uOffset , 256 ) ;
2007-08-06 21:38:35 +00:00
if ( mem )
2021-11-01 21:01:28 +00:00
memcpy ( mem + 0xC000 + m_slot * 256 , m_pSlotRom + uOffset , 256 ) ;
2007-08-06 21:38:35 +00:00
}
//===========================================================================
2018-03-03 21:27:50 +00:00
BYTE __stdcall CMouseInterface : : IORead ( WORD PC , WORD uAddr , BYTE bWrite , BYTE uValue , ULONG nExecutedCycles )
2007-08-06 21:38:35 +00:00
{
UINT uSlot = ( ( uAddr & 0xff ) > > 4 ) - 8 ;
CMouseInterface * pMouseIF = ( CMouseInterface * ) MemGetSlotParameters ( uSlot ) ;
BYTE byRS ;
byRS = uAddr & 3 ;
return pMouseIF - > m_6821 . Read ( byRS ) ;
}
2018-03-03 21:27:50 +00:00
BYTE __stdcall CMouseInterface : : IOWrite ( WORD PC , WORD uAddr , BYTE bWrite , BYTE uValue , ULONG nExecutedCycles )
2007-08-06 21:38:35 +00:00
{
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 ( )
{
2008-06-20 21:35:55 +00:00
# ifdef _DEBUG_SPURIOUS_IRQ
static UINT uSpuriousIrqCount = 0 ;
BYTE byOldState = m_byState ;
# endif
2007-08-06 21:38:35 +00:00
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 ;
2008-06-20 21:35:55 +00:00
m_byState & = STAT_MOVEMENT_SINCE_READMOUSE ;
2007-08-06 21:38:35 +00:00
m_nX = m_iX ;
m_nY = m_iY ;
2008-06-20 21:35:55 +00:00
if ( m_bBtn0 ) m_byState | = STAT_PREV_BUTTON0 ; // Previous Button 0
if ( m_bBtn1 ) m_byState | = STAT_PREV_BUTTON1 ; // Previous Button 1
2007-08-06 21:38:35 +00:00
m_bBtn0 = m_bButtons [ 0 ] ;
m_bBtn1 = m_bButtons [ 1 ] ;
2008-06-20 21:35:55 +00:00
if ( m_bBtn0 ) m_byState | = STAT_CURR_BUTTON0 ; // Current Button 0
if ( m_bBtn1 ) m_byState | = STAT_CURR_BUTTON1 ; // Current Button 1
2007-08-06 21:38:35 +00:00
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 ;
2008-06-20 21:35:55 +00:00
m_byBuff [ 5 ] = m_byState ; // button 0/1 interrupt status
m_byState & = ~ STAT_MOVEMENT_SINCE_READMOUSE ;
# ifdef _DEBUG_SPURIOUS_IRQ
2022-02-13 21:37:05 +00:00
LogOutput ( " [MOUSE_READ] Old=%02X New=%02X \n " , byOldState , m_byState ) ;
2008-06-20 21:35:55 +00:00
# endif
2007-08-06 21:38:35 +00:00
break ;
case MOUSE_SERV :
m_nDataLen = 2 ;
2008-06-20 21:35:55 +00:00
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 + + ;
2022-02-13 21:37:05 +00:00
LogOutput ( " [MOUSE_SERV] 0x%04X Buff[1]=0x%02X, *** \n " , uSpuriousIrqCount , m_byBuff [ 1 ] ) ;
2008-06-20 21:35:55 +00:00
}
else
{
2022-02-13 21:37:05 +00:00
LogOutput ( " [MOUSE_SERV] ------ Buff[1]=0x%02X \n " , m_byBuff [ 1 ] ) ;
2008-06-20 21:35:55 +00:00
}
# endif
2007-08-06 21:38:35 +00:00
CpuIrqDeassert ( IS_MOUSE ) ;
break ;
case MOUSE_CLEAR :
2007-12-01 21:21:40 +00:00
Clear ( ) ; // [TC] NB. Don't reset clamp values (eg. Fantavision)
2007-08-06 21:38:35 +00:00
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 ;
2007-12-02 14:55:32 +00:00
SetPositionAbs ( 0 , 0 ) ;
2007-08-06 21:38:35 +00:00
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 :
2008-05-17 23:20:33 +00:00
// Blazing Paddles:
// . MOUSE_CLAMP(Y, 0xFFEC, 0x00D3)
// . MOUSE_CLAMP(X, 0xFFEC, 0x012B)
2007-08-06 21:38:35 +00:00
nMin = ( m_byBuff [ 3 ] < < 8 ) | m_byBuff [ 1 ] ;
nMax = ( m_byBuff [ 4 ] < < 8 ) | m_byBuff [ 2 ] ;
if ( m_byBuff [ 0 ] & 1 ) // Clamp Y
2007-12-02 14:55:32 +00:00
SetClampY ( nMin , nMax ) ;
2007-08-06 21:38:35 +00:00
else // Clamp X
2007-12-02 14:55:32 +00:00
SetClampX ( nMin , nMax ) ;
2007-08-06 21:38:35 +00:00
break ;
case MOUSE_POS :
m_nX = ( m_byBuff [ 2 ] < < 8 ) | m_byBuff [ 1 ] ;
m_nY = ( m_byBuff [ 4 ] < < 8 ) | m_byBuff [ 3 ] ;
2007-12-02 14:55:32 +00:00
SetPositionAbs ( m_nX , m_nY ) ;
2007-08-06 21:38:35 +00:00
break ;
case MOUSE_INIT :
m_nX = 0 ;
m_nY = 0 ;
2007-12-02 14:55:32 +00:00
SetClampX ( 0 , 1023 ) ;
SetClampY ( 0 , 1023 ) ;
SetPositionAbs ( 0 , 0 ) ;
2007-08-06 21:38:35 +00:00
break ;
}
}
2008-06-20 21:35:55 +00:00
void CMouseInterface : : OnMouseEvent ( bool bEventVBL )
2007-08-06 21:38:35 +00:00
{
int byState = 0 ;
2022-11-17 22:23:20 +00:00
if ( ( m_byMode & MODE_INT_VBL ) & & bEventVBL )
byState | = STAT_INT_VBL ;
2007-08-06 21:38:35 +00:00
2022-11-17 22:23:20 +00:00
if ( m_byMode & MODE_MOUSE_ON )
2013-08-09 22:04:02 +00:00
{
2022-11-17 22:23:20 +00:00
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
}
2013-08-09 22:04:02 +00:00
2022-11-17 22:23:20 +00:00
if ( m_bBtn0 ! = m_bButtons [ 0 ] | | m_bBtn1 ! = m_bButtons [ 1 ] )
byState | = STAT_INT_BUTTON ; // Button 0/1 interrupt
2008-06-20 21:35:55 +00:00
2022-11-17 22:23:20 +00:00
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 ;
}
2007-08-06 21:38:35 +00:00
2008-06-20 21:35:55 +00:00
if ( byState & STAT_INT_ALL )
2007-08-06 21:38:35 +00:00
{
m_byState | = byState ;
CpuIrqAssert ( IS_MOUSE ) ;
2008-06-20 21:35:55 +00:00
# ifdef _DEBUG_SPURIOUS_IRQ
2022-02-13 21:37:05 +00:00
LogOutput ( " [MOUSE EVNT] 0x%02X Mode=0x%02X \n " , m_byState , m_byMode ) ;
2008-06-20 21:35:55 +00:00
# endif
2007-08-06 21:38:35 +00:00
}
}
2020-10-11 15:08:05 +00:00
int CMouseInterface : : SyncEventCallback ( int id , int cycles , ULONG /*uExecutedCycles*/ )
2007-08-06 21:38:35 +00:00
{
2020-10-11 16:34:44 +00:00
GetCardMgr ( ) . GetMouseCard ( ) - > OnMouseEvent ( true ) ;
2020-10-11 15:08:05 +00:00
return NTSC_GetCyclesUntilVBlank ( cycles ) ;
2007-08-06 21:38:35 +00:00
}
2007-12-01 21:21:40 +00:00
void CMouseInterface : : Clear ( )
2007-08-06 21:38:35 +00:00
{
m_nBuffPos = 0 ;
m_nDataLen = 1 ;
2012-08-12 12:47:02 +00:00
// m_byMode = 0; // Not for BeagleWrite / MultiScribe
2007-08-06 21:38:35 +00:00
m_byState = 0 ;
m_nX = 0 ;
m_nY = 0 ;
2016-02-20 17:57:23 +00:00
m_bBtn0 = false ;
m_bBtn1 = false ;
2007-12-02 14:55:32 +00:00
SetPositionAbs ( 0 , 0 ) ;
2007-08-06 21:38:35 +00:00
// CpuIrqDeassert(IS_MOUSE);
}
//===========================================================================
2008-05-17 23:20:33 +00:00
int CMouseInterface : : ClampX ( )
2007-12-02 14:55:32 +00:00
{
if ( m_iX > m_iMaxX )
2008-05-17 23:20:33 +00:00
{
2007-12-02 14:55:32 +00:00
m_iX = m_iMaxX ;
2008-05-17 23:20:33 +00:00
return 1 ;
}
2007-12-02 14:55:32 +00:00
else if ( m_iX < m_iMinX )
2008-05-17 23:20:33 +00:00
{
2007-12-02 14:55:32 +00:00
m_iX = m_iMinX ;
2008-05-17 23:20:33 +00:00
return - 1 ;
}
return 0 ;
2007-12-02 14:55:32 +00:00
}
2008-05-17 23:20:33 +00:00
int CMouseInterface : : ClampY ( )
2007-12-02 14:55:32 +00:00
{
if ( m_iY > m_iMaxY )
2008-05-17 23:20:33 +00:00
{
2007-12-02 14:55:32 +00:00
m_iY = m_iMaxY ;
2008-05-17 23:20:33 +00:00
return 1 ;
}
2007-12-02 14:55:32 +00:00
else if ( m_iY < m_iMinY )
2008-05-17 23:20:33 +00:00
{
2007-12-02 14:55:32 +00:00
m_iY = m_iMinY ;
2008-05-17 23:20:33 +00:00
return - 1 ;
}
return 0 ;
2007-12-02 14:55:32 +00:00
}
void CMouseInterface : : SetClampX ( int iMinX , int iMaxX )
2007-08-06 21:38:35 +00:00
{
2008-05-17 23:20:33 +00:00
if ( ( UINT ) iMinX > 0xFFFF | | ( UINT ) iMaxX > 0xFFFF )
{
_ASSERT ( 0 ) ;
2007-08-06 21:38:35 +00:00
return ;
2008-05-17 23:20:33 +00:00
}
if ( iMinX > iMaxX )
{
// For Blazing Paddles
int iNewMaxX = ( iMinX + iMaxX ) & 0xFFFF ;
iMinX = 0 ;
iMaxX = iNewMaxX ;
}
2007-08-06 21:38:35 +00:00
m_iMaxX = iMaxX ;
m_iMinX = iMinX ;
2007-12-02 14:55:32 +00:00
ClampX ( ) ;
2007-08-06 21:38:35 +00:00
}
2007-12-02 14:55:32 +00:00
void CMouseInterface : : SetClampY ( int iMinY , int iMaxY )
2007-08-06 21:38:35 +00:00
{
2008-05-17 23:20:33 +00:00
if ( ( UINT ) iMinY > 0xFFFF | | ( UINT ) iMaxY > 0xFFFF )
{
_ASSERT ( 0 ) ;
2007-08-06 21:38:35 +00:00
return ;
2008-05-17 23:20:33 +00:00
}
if ( iMinY > iMaxY )
{
// For Blazing Paddles
int iNewMaxY = ( iMinY + iMaxY ) & 0xFFFF ;
iMinY = 0 ;
iMaxY = iNewMaxY ;
}
2007-08-06 21:38:35 +00:00
m_iMaxY = iMaxY ;
m_iMinY = iMinY ;
2007-12-02 14:55:32 +00:00
ClampY ( ) ;
2007-08-06 21:38:35 +00:00
}
2007-12-02 14:55:32 +00:00
void CMouseInterface : : SetPositionAbs ( int x , int y )
2007-08-06 21:38:35 +00:00
{
2007-12-02 14:55:32 +00:00
m_iX = x ;
m_iY = y ;
2020-12-24 15:08:50 +00:00
GetFrame ( ) . FrameSetCursorPosByMousePos ( ) ;
2007-08-06 21:38:35 +00:00
}
2008-05-17 23:20:33 +00:00
void CMouseInterface : : SetPositionRel ( long dX , long dY , int * pOutOfBoundsX , int * pOutOfBoundsY )
2007-08-06 21:38:35 +00:00
{
2008-05-17 23:20:33 +00:00
m_iX + = dX ;
* pOutOfBoundsX = ClampX ( ) ;
2007-08-06 21:38:35 +00:00
2008-05-17 23:20:33 +00:00
m_iY + = dY ;
* pOutOfBoundsY = ClampY ( ) ;
2007-12-01 21:21:40 +00:00
2007-08-06 21:38:35 +00:00
OnMouseEvent ( ) ;
}
void CMouseInterface : : SetButton ( eBUTTON Button , eBUTTONSTATE State )
{
2016-02-20 17:57:23 +00:00
m_bButtons [ Button ] = ( State = = BUTTON_DOWN ) ;
2007-08-06 21:38:35 +00:00
OnMouseEvent ( ) ;
}
2008-05-17 23:20:33 +00:00
2015-12-05 16:50:27 +00:00
# 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"
2022-02-28 20:52:18 +00:00
const std : : string & CMouseInterface : : GetSnapshotCardName ( void )
2015-12-05 16:50:27 +00:00
{
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 ( ) ) ;
2016-02-24 21:51:20 +00:00
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 ) ;
2015-12-05 16:50:27 +00:00
}
2021-11-25 20:23:21 +00:00
void CMouseInterface : : SaveSnapshot ( YamlSaveHelper & yamlSaveHelper )
2015-12-05 16:50:27 +00:00
{
2019-12-19 19:42:30 +00:00
// if (!m_bActive)
// return;
2015-12-05 16:50:27 +00:00
2021-11-01 21:01:28 +00:00
YamlSaveHelper : : Slot slot ( yamlSaveHelper , GetSnapshotCardName ( ) , m_slot , 1 ) ;
2015-12-05 16:50:27 +00:00
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 ) ;
2016-03-04 21:26:14 +00:00
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_MODE , m_byMode ) ;
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_6821B , m_by6821B ) ;
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_6821A , m_by6821A ) ;
2015-12-05 16:50:27 +00:00
// New label
{
YamlSaveHelper : : Label buffer ( yamlSaveHelper , " %s: \n " , SS_YAML_KEY_BUFF ) ;
2016-02-24 22:54:53 +00:00
yamlSaveHelper . SaveMemory ( m_byBuff , sizeof ( m_byBuff ) ) ;
2015-12-05 16:50:27 +00:00
}
yamlSaveHelper . Save ( " %s: %d \n " , SS_YAML_KEY_BUFFPOS , m_nBuffPos ) ;
2016-03-04 21:26:14 +00:00
yamlSaveHelper . SaveHexUint8 ( SS_YAML_KEY_MOUSESTATE , m_byState ) ;
2016-02-24 21:51:20 +00:00
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 ) ;
2015-12-05 16:50:27 +00:00
}
void CMouseInterface : : LoadSnapshotMC6821 ( YamlLoadHelper & yamlLoadHelper , std : : string key )
{
if ( ! yamlLoadHelper . GetSubMap ( key ) )
2021-12-18 16:37:28 +00:00
throw std : : runtime_error ( " Card: Expected key: " + key ) ;
2015-12-05 16:50:27 +00:00
mc6821_t mc6821 ;
2016-02-24 22:38:59 +00:00
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 ) ;
2015-12-05 16:50:27 +00:00
2016-02-24 22:38:59 +00:00
BYTE byIA = yamlLoadHelper . LoadUint ( SS_YAML_KEY_IA ) ;
BYTE byIB = yamlLoadHelper . LoadUint ( SS_YAML_KEY_IB ) ;
2015-12-05 16:50:27 +00:00
m_6821 . Set6821 ( mc6821 , byIA , byIB ) ;
yamlLoadHelper . PopMap ( ) ;
}
2021-11-25 20:23:21 +00:00
bool CMouseInterface : : LoadSnapshot ( YamlLoadHelper & yamlLoadHelper , UINT version )
2015-12-05 16:50:27 +00:00
{
if ( version ! = 1 )
2022-01-30 21:25:40 +00:00
ThrowErrorInvalidVersion ( version ) ;
2015-12-05 16:50:27 +00:00
LoadSnapshotMC6821 ( yamlLoadHelper , SS_YAML_KEY_MC6821 ) ;
2016-02-24 22:38:59 +00:00
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 ) ;
2015-12-05 16:50:27 +00:00
if ( ! yamlLoadHelper . GetSubMap ( SS_YAML_KEY_BUFF ) )
2021-12-18 16:37:28 +00:00
throw std : : runtime_error ( " Card: Expected key: " SS_YAML_KEY_BUFF ) ;
2016-02-24 22:38:59 +00:00
yamlLoadHelper . LoadMemory ( m_byBuff , sizeof ( m_byBuff ) ) ;
2015-12-05 16:50:27 +00:00
yamlLoadHelper . PopMap ( ) ;
2016-02-24 22:38:59 +00:00
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
2015-12-05 16:50:27 +00:00
2019-08-26 19:10:33 +00:00
if ( m_byState & STAT_INT_ALL ) // GH#677
CpuIrqAssert ( IS_MOUSE ) ;
2015-12-05 16:50:27 +00:00
return true ;
}