Merge from Tom branch to trunk

. Mouse interface now implemented & selectable from UI
. Scroll Lock toggle also configurable from UI
This commit is contained in:
tomch 2007-08-06 21:38:35 +00:00
parent 6342a9d33a
commit 333666c2f0
29 changed files with 1558 additions and 191 deletions

View File

@ -209,6 +209,14 @@
Name="Source"
Filter=".cpp"
>
<File
RelativePath=".\source\6821.cpp"
>
</File>
<File
RelativePath=".\source\6821.h"
>
</File>
<File
RelativePath=".\source\Applewin.cpp"
>
@ -305,6 +313,14 @@
RelativePath=".\source\Mockingboard.h"
>
</File>
<File
RelativePath=".\source\MouseInterface.cpp"
>
</File>
<File
RelativePath=".\source\MouseInterface.h"
>
</File>
<File
RelativePath=".\source\ParallelPrinter.cpp"
>
@ -673,6 +689,10 @@
RelativePath=".\source\Common.h"
>
</File>
<File
RelativePath=".\resource\MouseInterface.rom"
>
</File>
<File
RelativePath=".\resource\resource.h"
>

View File

@ -75,10 +75,10 @@ IDB_DEBUG_FONT_7X8 BITMAP "Debug_Font.bmp"
// Dialog
//
IDD_PROPPAGE_CONFIG DIALOG 0, 0, 210, 221
IDD_PROPPAGE_CONFIG DIALOGEX 0, 0, 210, 221
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU
CAPTION "Configuration"
FONT 8, "MS Sans Serif"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
GROUPBOX "Emulation Speed Control",IDC_STATIC,5,115,200,85
CONTROL "Use &Authentic Machine Speed",IDC_AUTHENTIC_SPEED,
@ -98,6 +98,7 @@ BEGIN
COMBOBOX IDC_SERIALPORT,45,48,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Monochrome Color...",IDC_MONOCOLOR,15,90,80,14
PUSHBUTTON "Ethernet Settings...",IDC_ETHERNET,15,70,78,14
CONTROL "Mouse interface in slot 4",IDC_MOUSE_IN_SLOT4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,206,106,10
END
IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 210, 221
@ -117,6 +118,8 @@ BEGIN
LTEXT "Y-trim:",IDC_STATIC,115,72,28,8
CTEXT "0",IDC_STATIC,137,65,24,20,SS_CENTERIMAGE
CONTROL "Spin1",IDC_SPIN_YTRIM,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNLEFT | UDS_AUTOBUDDY,161,69,10,14
CONTROL "Scroll Lock acts as toggle for full-speed CPU",IDC_SCROLLLOCK_TOGGLE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,114,166,10
LTEXT "(Shift+Insert during emulation)",IDC_STATIC,89,166,94,8
END
@ -207,8 +210,8 @@ DISK_ICON ICON "DISK.ICO"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,13,2,0
PRODUCTVERSION 1,13,2,0
FILEVERSION 1,13,3,0
PRODUCTVERSION 1,13,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -226,12 +229,12 @@ BEGIN
VALUE "Comments", "http://applewin.berlios.de"
VALUE "CompanyName", "Michael O'Brien, Oliver Schmidt, Tom Charlesworth"
VALUE "FileDescription", "Apple //e Emulator for Windows"
VALUE "FileVersion", "1, 13, 2, 0"
VALUE "FileVersion", "1, 13, 3, 0"
VALUE "InternalName", "APPLEWIN"
VALUE "LegalCopyright", "© 1994-2007 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis"
VALUE "OriginalFilename", "APPLEWIN.EXE"
VALUE "ProductName", "Apple //e Emulator"
VALUE "ProductVersion", "1, 13, 2, 0"
VALUE "ProductVersion", "1, 13, 3, 0"
END
END
BLOCK "VarFileInfo"
@ -263,6 +266,7 @@ IDR_SSC_FW FIRMWARE "SSC.rom"
IDR_HDDRVR_FW FIRMWARE "Hddrvr.bin"
IDR_PRINTDRVR_FW FIRMWARE "Parallel.rom"
IDR_MOCKINGBOARD_D_FW FIRMWARE "Mockingboard-D.rom"
IDR_MOUSEINTERFACE_FW FIRMWARE "MouseInterface.rom"
/////////////////////////////////////////////////////////////////////////////
//
@ -272,7 +276,7 @@ IDR_MOCKINGBOARD_D_FW FIRMWARE "Mockingboard-D.rom"
IDR_APPLE2_ROM ROM "Apple2.rom"
IDR_APPLE2_PLUS_ROM ROM "Apple2_Plus.rom"
IDR_APPLE2E_ROM ROM "Apple2e.rom"
IDR_APPLE2E_ENHANCED_ROM ROM "Apple2e_Enhanced.rom"
IDR_APPLE2E_ENHANCED_ROM ROM "Apple2e_Enhanced.rom"
/////////////////////////////////////////////////////////////////////////////
//

View File

@ -38,6 +38,7 @@
#define IDR_DISK2_FW 133
#define IDR_SSC_FW 134
#define IDR_MOCKINGBOARD_D_FW 135
#define IDR_MOUSEINTERFACE_FW 136
#define IDC_KEYB_BUFFER_ENABLE 1005
#define IDC_SAVESTATE 1006
#define IDC_SAVESTATE_ON_EXIT 1007
@ -72,6 +73,8 @@
#define IDS_OK 1040
#define IDS_CANCEL 1041
#define IDC_ETHERNET 1042
#define IDC_SCROLLLOCK_TOGGLE 1043
#define IDC_MOUSE_IN_SLOT4 1044
#define IDM_EXIT 40001
#define IDM_HELP 40002
#define IDM_ABOUT 40003
@ -84,9 +87,9 @@
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 136
#define _APS_NEXT_RESOURCE_VALUE 137
#define _APS_NEXT_COMMAND_VALUE 40007
#define _APS_NEXT_CONTROL_VALUE 1043
#define _APS_NEXT_CONTROL_VALUE 1045
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

531
AppleWin/source/6821.cpp Normal file
View File

@ -0,0 +1,531 @@
// Based on MAME's 6821pia.c
// - by Kyle Kim (Apple in PC)
//
// From mame.txt (http://www.mame.net/readme.html)
//
// VI. Reuse of Source Code
// --------------------------
// This chapter might not apply to specific portions of MAME (e.g. CPU
// emulators) which bear different copyright notices.
// The source code cannot be used in a commercial product without the written
// authorization of the authors. Use in non-commercial products is allowed, and
// indeed encouraged. If you use portions of the MAME source code in your
// program, however, you must make the full source code freely available as
// well.
// Usage of the _information_ contained in the source code is free for any use.
// However, given the amount of time and energy it took to collect this
// information, if you find new information we would appreciate if you made it
// freely available as well.
//
#include "stdafx.h"
#include "6821.h"
// Ctrl-A(B) register bit mask define
/*
0 1
bit0 IRQ1_DISABLED IRQ1_ENABLED
bit1 C1_HIGH_TO_LOW C1_LOW_TO_HIGH
bit2 DDR_SELECTED OUTPUT_SELECTED
bit3 RESET_C2 SET_C2 ( C2_OUTPUT & C2_SETMODE )
bit3 STROBE_C1_RESET STROBE_E_RESET ( C2_OUTPUT & C2_STROBE_MODE )
bit4 C2_STROBE_MODE C2_SETMODE ( C2_OUTPUT )
bit3 IRQ2_DISABLED IRQ2_ENABLED ( C2_INPUT )
bit4 C2_HIGH_TO_LOW C2_HIGH_TO_LOW ( C2_INPUT )
bit5 C2_INPUT C2_OUTPUT
*/
#define PIA_IRQ1 0x80
#define PIA_IRQ2 0x40
#define SET_IRQ1(c) c |= PIA_IRQ1;
#define SET_IRQ2(c) c |= PIA_IRQ2;
#define CLEAR_IRQ1(c) c &= ~PIA_IRQ1;
#define CLEAR_IRQ2(c) c &= ~PIA_IRQ2;
#define IRQ1(c) ( c & PIA_IRQ1 )
#define IRQ2(c) ( c & PIA_IRQ2 )
#define IRQ1_ENABLED(c) ( c & 0x01 )
#define IRQ1_DISABLED(c) !( c & 0x01 )
#define C1_LOW_TO_HIGH(c) ( c & 0x02 )
#define C1_HIGH_TO_LOW(c) !( c & 0x02 )
#define OUTPUT_SELECTED(c) ( c & 0x04 )
#define DDR_SELECTED(c) !( c & 0x04 )
#define IRQ2_ENABLED(c) ( c & 0x08 )
#define IRQ2_DISABLED(c) !( c & 0x08 )
#define STROBE_E_RESET(c) ( c & 0x08 )
#define STROBE_C1_RESET(c) !( c & 0x08 )
#define SET_C2(c) ( c & 0x08 )
#define RESET_C2(c) !( c & 0x08 )
#define C2_LOW_TO_HIGH(c) ( c & 0x10 )
#define C2_HIGH_TO_LOW(c) !( c & 0x10 )
#define C2_SET_MODE(c) ( c & 0x10 )
#define C2_STROBE_MODE(c) !( c & 0x10 )
#define C2_OUTPUT(c) ( c & 0x20 )
#define C2_INPUT(c) !( c & 0x20 )
#define PIA_W_CALLBACK(st, val) \
if ( st.func ) st.func( this, st.objTo, 0, val )
//////////////////////////////////////////////////////////////////////
C6821::C6821()
{
Reset();
m_stOutA.objTo = NULL;
m_stOutA.func = NULL;
m_stOutB.objTo = NULL;
m_stOutB.func = NULL;
m_stOutCA2.objTo = NULL;
m_stOutCA2.func = NULL;
m_stOutCB2.objTo = NULL;
m_stOutCB2.func = NULL;
m_stOutIRQA.objTo = NULL;
m_stOutIRQA.func = NULL;
m_stOutIRQB.objTo = NULL;
m_stOutIRQB.func = NULL;
}
C6821::~C6821()
{
}
void C6821::SetListenerA(void *objTo, mem_write_handler func)
{
m_stOutA.objTo = objTo;
m_stOutA.func = func;
}
void C6821::SetListenerB(void *objTo, mem_write_handler func)
{
m_stOutB.objTo = objTo;
m_stOutB.func = func;
}
void C6821::SetListenerCA2(void *objTo, mem_write_handler func)
{
m_stOutCA2.objTo = objTo;
m_stOutCA2.func = func;
}
void C6821::SetListenerCB2(void *objTo, mem_write_handler func)
{
m_stOutCB2.objTo = objTo;
m_stOutCB2.func = func;
}
BYTE C6821::Read(BYTE byRS)
{
BYTE retval = 0;
byRS &= 3;
switch ( byRS )
{
/******************* port A output/DDR read *******************/
case PIA_DDRA:
// read output register
if ( OUTPUT_SELECTED(m_byCTLA) )
{
// combine input and output values
retval = ( m_byOA & m_byDDRA ) | ( m_byIA & ~m_byDDRA );
// IRQ flags implicitly cleared by a read
CLEAR_IRQ1( m_byCTLA );
CLEAR_IRQ1( m_byCTLB );
UpdateInterrupts();
// CA2 is configured as output and in read strobe mode
if ( C2_OUTPUT(m_byCTLA) && C2_STROBE_MODE(m_byCTLA) )
{
// this will cause a transition low; call the output function if we're currently high
if ( m_byOCA2 )
PIA_W_CALLBACK( m_stOutCA2, 0 );
m_byOCA2 = 0;
// if the CA2 strobe is cleared by the E, reset it right away
if ( STROBE_E_RESET( m_byCTLA ) )
{
PIA_W_CALLBACK( m_stOutCA2, 1 );
m_byOCA2 = 1;
}
}
}
// read DDR register
else
{
retval = m_byDDRA;
}
break;
/******************* port B output/DDR read *******************/
case PIA_DDRB:
// read output register
if ( OUTPUT_SELECTED( m_byCTLB ) )
{
// combine input and output values
retval = ( m_byOB & m_byDDRB ) + ( m_byIB & ~m_byDDRB );
// IRQ flags implicitly cleared by a read
CLEAR_IRQ2( m_byCTLA );
CLEAR_IRQ2( m_byCTLB );
UpdateInterrupts();
}
/* read DDR register */
else
{
retval = m_byDDRB;
}
break;
/******************* port A control read *******************/
case PIA_CTLA:
// read control register
retval = m_byCTLA;
// when CA2 is an output, IRQA2 = 0, and is not affected by CA2 transitions.
if ( C2_OUTPUT( m_byCTLA ) )
retval &= ~PIA_IRQ2;
break;
/******************* port B control read *******************/
case PIA_CTLB:
retval = m_byCTLB;
// when CB2 is an output, IRQB2 = 0, and is not affected by CB2 transitions.
if ( C2_OUTPUT( m_byCTLB ) )
retval &= ~PIA_IRQ2;
break;
}
return retval;
}
void C6821::Write(BYTE byRS, BYTE byData)
{
byRS &= 3;
switch( byRS )
{
/******************* port A output/DDR write *******************/
case PIA_DDRA:
// write output register
if ( OUTPUT_SELECTED( m_byCTLA ) )
{
// update the output value
m_byOA = byData;
// send it to the output function
if ( m_byDDRA )
PIA_W_CALLBACK( m_stOutA, m_byOA & m_byDDRA );
}
// write DDR register
else
{
if ( m_byDDRA != byData )
{
m_byDDRA = byData;
// send it to the output function
if ( m_byDDRA )
PIA_W_CALLBACK( m_stOutA, m_byOA & m_byDDRA );
}
}
break;
/******************* port B output/DDR write *******************/
case PIA_DDRB:
// write output register
if ( OUTPUT_SELECTED( m_byCTLB ) )
{
// update the output value
m_byOB = byData;
// send it to the output function
if ( m_byDDRB )
PIA_W_CALLBACK( m_stOutB, m_byOB & m_byDDRB );
// CB2 is configured as output and in write strobe mode
if ( C2_OUTPUT( m_byCTLB ) && C2_STROBE_MODE( m_byCTLB ) )
{
// this will cause a transition low; call the output function if we're currently high
if ( m_byOCB2 )
PIA_W_CALLBACK( m_stOutCB2, 0 );
m_byOCB2 = 0;
// if the CB2 strobe is cleared by the E, reset it right away
if ( STROBE_E_RESET( m_byCTLB ) )
{
PIA_W_CALLBACK( m_stOutCB2, 1 );
m_byOCB2 = 1;
}
}
}
// write DDR register
else
{
if ( m_byDDRB != byData )
{
m_byDDRB = byData;
// send it to the output function
if ( m_byDDRB )
PIA_W_CALLBACK( m_stOutB, m_byOB & m_byDDRB );
}
}
break;
/******************* port A control write *******************/
case PIA_CTLA:
// Bit 7 and 6 read only
byData &= 0x3f;
// CA2 is configured as output and in set/reset mode
if ( C2_OUTPUT( byData ) )
{
// determine the new value
int temp = SET_C2( byData ) ? 1 : 0;
// if this creates a transition, call the CA2 output function
if ( m_byOCA2 ^ temp)
PIA_W_CALLBACK( m_stOutCA2, temp );
// set the new value
m_byOCA2 = temp;
}
// update the control register
m_byCTLA = ( m_byCTLA & ~0x3F ) | byData;
// update externals
UpdateInterrupts();
break;
/******************* port B control write *******************/
case PIA_CTLB:
/* Bit 7 and 6 read only - PD 16/01/00 */
byData &= 0x3f;
// CB2 is configured as output and in set/reset mode
if ( C2_OUTPUT( byData ) )
{
// determine the new value
int temp = SET_C2( byData ) ? 1 : 0;
// if this creates a transition, call the CA2 output function
if ( m_byOCB2 ^ temp)
PIA_W_CALLBACK( m_stOutCB2, temp );
// set the new value
m_byOCB2 = temp;
}
// update the control register
m_byCTLB = ( m_byCTLB & ~0x3F ) | byData;
// update externals
UpdateInterrupts();
break;
}
}
void C6821::Reset()
{
m_byIA = 0;
m_byCA1 = 0;
m_byICA2 = 0;
m_byOA = 0;
m_byOCA2 = 0;
m_byDDRA = 0;
m_byCTLA = 0;
m_byIRQAState = 0;
m_byIB = 0;
m_byCB1 = 0;
m_byICB2 = 0;
m_byOB = 0;
m_byOCB2 = 0;
m_byDDRB = 0;
m_byCTLB = 0;
m_byIRQBState = 0;
}
void C6821::UpdateInterrupts()
{
BYTE byNewState;
// start with IRQ A
byNewState = 0;
if ( ( IRQ1( m_byCTLA ) && IRQ1_ENABLED( m_byCTLA ) ) ||
( IRQ2( m_byCTLA ) && IRQ2_ENABLED( m_byCTLA ) ) )
byNewState = 1;
if ( byNewState != m_byIRQAState )
{
m_byIRQAState = byNewState;
PIA_W_CALLBACK( m_stOutIRQA, m_byIRQAState );
}
/* then do IRQ B */
byNewState = 0;
if ( ( IRQ1( m_byCTLB ) && IRQ1_ENABLED( m_byCTLB ) ) ||
( IRQ2( m_byCTLB ) && IRQ2_ENABLED( m_byCTLB ) ) )
byNewState = 1;
if ( byNewState != m_byIRQBState )
{
m_byIRQBState = byNewState;
PIA_W_CALLBACK( m_stOutIRQB, m_byIRQBState );
}
}
void C6821::SetCA1(BYTE byData)
{
byData = byData ? 1 : 0;
// the new state has caused a transition
if ( m_byCA1 ^ byData )
{
// handle the active transition
if ( ( byData && C1_LOW_TO_HIGH( m_byCTLA ) ) ||
( !byData && C1_HIGH_TO_LOW( m_byCTLA ) ) )
{
// mark the IRQ
SET_IRQ1(m_byCTLA);
// update externals
UpdateInterrupts();
// CA2 is configured as output and in read strobe mode and cleared by a CA1 transition
if ( C2_OUTPUT( m_byCTLA ) && C2_STROBE_MODE( m_byCTLA ) && STROBE_C1_RESET( m_byCTLA ) )
{
// call the CA2 output function
if ( !m_byOCA2 )
PIA_W_CALLBACK( m_stOutCA2, 1 );
// clear CA2
m_byOCA2 = 1;
}
}
}
// set the new value for CA1
m_byCA1 = byData;
}
void C6821::SetCA2(BYTE byData)
{
byData = byData ? 1 : 0;
// CA2 is in input mode
if ( C2_INPUT( m_byCTLA ) )
{
// the new state has caused a transition
if ( m_byICA2 ^ byData )
{
// handle the active transition
if ( ( byData && C2_LOW_TO_HIGH( m_byCTLA ) ) ||
( !byData && C2_HIGH_TO_LOW( m_byCTLA ) ) )
{
// mark the IRQ
SET_IRQ2( m_byCTLA );
// update externals
UpdateInterrupts();
}
}
}
// set the new value for CA2
m_byICA2 = byData;
}
void C6821::SetCB1(BYTE byData)
{
byData = byData ? 1 : 0;
// the new state has caused a transition
if ( m_byCB1 ^ byData )
{
// handle the active transition
if ( ( byData && C1_LOW_TO_HIGH( m_byCTLB ) ) ||
( !byData && C1_HIGH_TO_LOW( m_byCTLB ) ) )
{
// mark the IRQ
SET_IRQ1( m_byCTLB );
// update externals
UpdateInterrupts();
// CB2 is configured as output and in read strobe mode and cleared by a CA1 transition
if ( C2_OUTPUT( m_byCTLB ) && C2_STROBE_MODE( m_byCTLB ) && STROBE_C1_RESET( m_byCTLB ) )
{
// the IRQ1 flag must have also been cleared
if ( !IRQ1( m_byCTLB ) )
{
// call the CB2 output function
if ( !m_byOCB2 )
PIA_W_CALLBACK( m_stOutCB2, 1 );
// clear CB2
m_byOCB2 = 1;
}
}
}
}
// set the new value for CA1
m_byCB1 = byData;
}
void C6821::SetCB2(BYTE byData)
{
byData = byData ? 1 : 0;
// CA2 is in input mode
if ( C2_INPUT( m_byCTLB ) )
{
// the new state has caused a transition
if ( m_byICB2 ^ byData )
{
// handle the active transition
if ( ( byData && C2_LOW_TO_HIGH( m_byCTLB ) ) ||
( !byData && C2_HIGH_TO_LOW( m_byCTLB ) ) )
{
// mark the IRQ
SET_IRQ2( m_byCTLB );
// update externals
UpdateInterrupts();
}
}
}
// set the new value for CA2
m_byICB2 = byData;
}
void C6821::SetPA(BYTE byData)
{
m_byIA = byData;
}
void C6821::SetPB(BYTE byData)
{
m_byIB = byData;
}
BYTE C6821::GetPA()
{
return m_byOA & m_byDDRA;
}
BYTE C6821::GetPB()
{
return m_byOB & m_byDDRB;
}

68
AppleWin/source/6821.h Normal file
View File

@ -0,0 +1,68 @@
// Motorola MC6821 PIA
typedef void (*mem_write_handler) (void* objFrom, void* objTo, int nAddr, BYTE byData);
typedef struct _STWriteHandler
{
void* objTo;
mem_write_handler func;
} STWriteHandler;
//
#define PIA_DDRA 0
#define PIA_CTLA 1
#define PIA_DDRB 2
#define PIA_CTLB 3
class C6821
{
public:
C6821();
virtual ~C6821();
BYTE GetPB();
BYTE GetPA();
void SetPB(BYTE byData);
void SetPA(BYTE byData);
void SetCA1( BYTE byData );
void SetCA2( BYTE byData );
void SetCB1( BYTE byData );
void SetCB2( BYTE byData );
void Reset();
BYTE Read( BYTE byRS );
void Write( BYTE byRS, BYTE byData );
void UpdateInterrupts();
void SetListenerA( void *objTo, mem_write_handler func );
void SetListenerB( void *objTo, mem_write_handler func );
void SetListenerCA2( void *objTo, mem_write_handler func );
void SetListenerCB2( void *objTo, mem_write_handler func );
protected:
BYTE m_byIA;
BYTE m_byCA1;
BYTE m_byICA2;
BYTE m_byOA;
BYTE m_byOCA2;
BYTE m_byDDRA;
BYTE m_byCTLA;
BYTE m_byIRQAState;
BYTE m_byIB;
BYTE m_byCB1;
BYTE m_byICB2;
BYTE m_byOB;
BYTE m_byOCB2;
BYTE m_byDDRB;
BYTE m_byCTLB;
BYTE m_byIRQBState;
STWriteHandler m_stOutA;
STWriteHandler m_stOutB;
STWriteHandler m_stOutCA2;
STWriteHandler m_stOutCB2;
STWriteHandler m_stOutIRQA;
STWriteHandler m_stOutIRQB;
};

View File

@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#pragma hdrstop
#include "MouseInterface.h"
char VERSIONSTRING[] = "xx.yy.zz.ww";
@ -64,7 +65,10 @@ DWORD g_dwCyclesThisFrame = 0;
FILE* g_fh = NULL;
bool g_bDisableDirectSound = false;
CSuperSerialCard sg_SSC;
CSuperSerialCard sg_SSC;
CMouseInterface sg_Mouse;
UINT g_Slot4 = CT_Mockingboard; // CT_Mockingboard or CT_MouseInterface
//===========================================================================
@ -95,8 +99,12 @@ void ContinueExecution()
//
bool bScrollLock_FullSpeed = g_uScrollLockToggle
? g_bScrollLock_FullSpeed
: (GetKeyState(VK_SCROLL) < 0);
g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) ||
(GetKeyState(VK_SCROLL) < 0) ||
bScrollLock_FullSpeed ||
(DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) );
if(g_bFullSpeed)
@ -198,7 +206,7 @@ void ContinueExecution()
pageflipping--;
}
MB_EndOfFrame();
MB_EndOfVideoFrame();
}
//
@ -390,6 +398,10 @@ void LoadConfiguration ()
DWORD dwTmp;
if(LOAD(TEXT(REGVALUE_MOUSE_IN_SLOT4), &dwTmp))
g_uMouseInSlot4 = dwTmp;
g_Slot4 = g_uMouseInSlot4 ? CT_MouseInterface : CT_Mockingboard;
if(LOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp))
SpkrSetVolume(dwTmp, PSP_GetVolumeMax());
@ -416,6 +428,9 @@ void LoadConfiguration ()
if(LOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp))
JoySetTrim((short)dwTmp, false);
if(LOAD(TEXT(REGVALUE_SCROLLLOCK_TOGGLE), &dwTmp))
g_uScrollLockToggle = dwTmp;
//
char szFilename[MAX_PATH] = {0};
@ -706,7 +721,9 @@ int APIENTRY WinMain (HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
// ENTER THE MAIN MESSAGE LOOP
EnterMessageLoop();
MB_Reset();
sg_Mouse.Uninitialize(); // Maybe restarting due to switching slot-4 card from mouse to MB
}
while (restart);

View File

@ -33,4 +33,6 @@ extern DWORD g_dwCyclesThisFrame;
extern FILE* g_fh; // Filehandle for log file
extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB support)
extern UINT g_Slot4; // Mockingboard or Mouse in slot4
void SetCurrentCLK6502();

View File

@ -86,6 +86,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#pragma hdrstop
#include "MouseInterface.h"
#define AF_SIGN 0x80
#define AF_OVERFLOW 0x40
@ -112,7 +113,11 @@ unsigned __int64 g_nCumulativeCycles = 0;
static ULONG g_nCyclesSubmitted; // Number of cycles submitted to CpuExecute()
static ULONG g_nCyclesExecuted;
static signed long g_uInternalExecutedCycles;
//static signed long g_uInternalExecutedCycles;
// TODO: Use IRQ_CHECK_TIMEOUT=128 when running at full-speed else with IRQ_CHECK_TIMEOUT=1
// - What about when running benchmark?
static const int IRQ_CHECK_TIMEOUT = 128;
static signed int g_nIrqCheckTimeout = IRQ_CHECK_TIMEOUT;
//
@ -143,7 +148,7 @@ static volatile BOOL g_bNmiFlank = FALSE; // Positive going flank on NMI line
| (flagz ? AF_ZERO : 0) \
| AF_RESERVED | AF_BREAK;
// CYC(a): This can be optimised, as only certain opcodes will affect uExtraCycles
#define CYC(a) uExecutedCycles += (a)+uExtraCycles; MB_UpdateCycles((a)+uExtraCycles);
#define CYC(a) uExecutedCycles += (a)+uExtraCycles; g_nIrqCheckTimeout -= (a)+uExtraCycles;
#define POP (*(mem+((regs.sp >= 0x1FF) ? (regs.sp = 0x100) : ++regs.sp)))
#define PUSH(a) *(mem+regs.sp--) = (a); \
if (regs.sp < 0x100) \
@ -227,6 +232,10 @@ static volatile BOOL g_bNmiFlank = FALSE; // Positive going flank on NMI line
else \
addr = *(LPWORD)(mem+base);
#define REL addr = (signed char)*(mem+regs.pc++);
// Optimiation note:
// . Opcodes that generate zero-page addresses can't be accessing $C000..$CFFF
// so they could be paired with special READZP/WRITEZP macros (instead of READ/WRITE)
#define ZPG addr = *(mem+regs.pc++);
#define ZPGX addr = ((*(mem+regs.pc++))+regs.x) & 0xFF;
#define ZPGY addr = ((*(mem+regs.pc++))+regs.y) & 0xFF;
@ -783,7 +792,7 @@ UINT g_nMean = 0;
UINT g_nMin = 0xFFFFFFFF;
UINT g_nMax = 0;
static inline void DoIrqProfiling(DWORD uCycles)
static __forceinline void DoIrqProfiling(DWORD uCycles)
{
#ifdef _DEBUG
if(regs.ps & AF_INTERRUPT)
@ -814,8 +823,75 @@ static inline void DoIrqProfiling(DWORD uCycles)
//===========================================================================
static __forceinline int Fetch(BYTE& iOpcode, ULONG uExecutedCycles)
{
//g_uInternalExecutedCycles = uExecutedCycles;
// iOpcode = *(mem+regs.pc);
iOpcode = ((regs.pc & 0xF000) == 0xC000)
? IORead[(regs.pc>>4) & 0xFF](regs.pc,regs.pc,0,0,uExecutedCycles) // Fetch opcode from I/O memory, but params are still from mem[]
: *(mem+regs.pc);
if (CheckDebugBreak( iOpcode ))
return 0;
regs.pc++;
return 1;
}
//#define ENABLE_NMI_SUPPORT // Not used - so don't enable
static __forceinline void NMI(ULONG& uExecutedCycles, UINT& uExtraCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz)
{
#ifdef ENABLE_NMI_SUPPORT
if(g_bNmiFlank)
{
// NMI signals are only serviced once
g_bNmiFlank = FALSE;
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
PUSH(regs.pc >> 8)
PUSH(regs.pc & 0xFF)
EF_TO_AF
PUSH(regs.ps & ~AF_BREAK)
regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL;
regs.pc = * (WORD*) (mem+0xFFFA);
CYC(7)
}
#endif
}
static __forceinline void IRQ(ULONG& uExecutedCycles, UINT& uExtraCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz)
{
if(g_bmIRQ && !(regs.ps & AF_INTERRUPT))
{
// IRQ signals are deasserted when a specific r/w operation is done on device
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
PUSH(regs.pc >> 8)
PUSH(regs.pc & 0xFF)
EF_TO_AF
PUSH(regs.ps & ~AF_BREAK)
regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL;
regs.pc = * (WORD*) (mem+0xFFFE);
CYC(7)
}
}
static __forceinline void CheckInterruptSources(ULONG uExecutedCycles)
{
if (g_nIrqCheckTimeout < 0)
{
MB_UpdateCycles(uExecutedCycles);
sg_Mouse.SetVBlank(VideoGetVbl(uExecutedCycles));
g_nIrqCheckTimeout = IRQ_CHECK_TIMEOUT;
}
}
//===========================================================================
static DWORD Cpu65C02 (DWORD uTotalCycles)
{
// Optimisation:
// . Copy the global /regs/ vars to stack-based local vars
// (Oliver Schmidt says this gives a performance gain, see email - The real deal: "1.10.5")
WORD addr;
BOOL flagc; // must always be 0 or 1, no other values allowed
BOOL flagn; // must always be 0 or 0x80.
@ -825,26 +901,19 @@ static DWORD Cpu65C02 (DWORD uTotalCycles)
WORD temp2;
WORD val;
AF_TO_EF
DWORD uExecutedCycles = 0;
ULONG uExecutedCycles = 0;
BOOL bSlowerOnPagecross; // Set if opcode writes to memory (eg. ASL, STA)
WORD base;
bool bBreakOnInvalid = false;
bool bBreakOnInvalid = false;
do
{
g_uInternalExecutedCycles = uExecutedCycles;
USHORT uExtraCycles = 0;
UINT uExtraCycles = 0;
BYTE iOpcode;
// BYTE iOpcode = *(mem+regs.pc);
BYTE iOpcode = ((regs.pc & 0xF000) == 0xC000)
? IORead[(regs.pc>>4) & 0xFF](regs.pc,regs.pc,0,0,uExecutedCycles) // Fetch opcode from I/O memory, but params are still from mem[]
: *(mem+regs.pc);
if (CheckDebugBreak( iOpcode ))
if (!Fetch(iOpcode, uExecutedCycles))
break;
regs.pc++;
switch (iOpcode)
{
case 0x00: BRK CYC(7) break;
@ -1105,32 +1174,10 @@ static DWORD Cpu65C02 (DWORD uTotalCycles)
case 0xFF: INV NOP CYC(2) break;
}
if(g_bNmiFlank)
{
// NMI signals are only serviced once
g_bNmiFlank = FALSE;
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
PUSH(regs.pc >> 8)
PUSH(regs.pc & 0xFF)
EF_TO_AF
PUSH(regs.ps & ~AF_BREAK)
regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL;
regs.pc = * (WORD*) (mem+0xFFFA);
CYC(7)
}
if(g_bmIRQ && !(regs.ps & AF_INTERRUPT))
{
// IRQ signals are deasserted when a specific r/w operation is done on device
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
PUSH(regs.pc >> 8)
PUSH(regs.pc & 0xFF)
EF_TO_AF
PUSH(regs.ps & ~AF_BREAK)
regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL;
regs.pc = * (WORD*) (mem+0xFFFE);
CYC(7)
}
CheckInterruptSources(uExecutedCycles);
NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
if (bBreakOnInvalid)
break;
@ -1154,26 +1201,19 @@ static DWORD Cpu6502 (DWORD uTotalCycles)
WORD temp2;
WORD val;
AF_TO_EF
DWORD uExecutedCycles = 0;
ULONG uExecutedCycles = 0;
BOOL bSlowerOnPagecross; // Set if opcode writes to memory (eg. ASL, STA)
WORD base;
bool bBreakOnInvalid = false;
do
{
g_uInternalExecutedCycles = uExecutedCycles;
USHORT uExtraCycles = 0;
UINT uExtraCycles = 0;
BYTE iOpcode;
// BYTE iOpcode = *(mem+regs.pc);
BYTE iOpcode = ((regs.pc & 0xF000) == 0xC000)
? IORead[(regs.pc>>4) & 0xFF](regs.pc,regs.pc,0,0,uExecutedCycles)
: *(mem+regs.pc);
if (CheckDebugBreak( iOpcode ))
if (!Fetch(iOpcode, uExecutedCycles))
break;
regs.pc++;
switch (iOpcode)
{
case 0x00: BRK CYC(7) break;
@ -1434,32 +1474,9 @@ static DWORD Cpu6502 (DWORD uTotalCycles)
case 0xFF: INV ABSX INS CYC(7) break;
}
if(g_bNmiFlank && !regs.bJammed)
{
// NMI signals are only serviced once
g_bNmiFlank = FALSE;
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
PUSH(regs.pc >> 8)
PUSH(regs.pc & 0xFF)
EF_TO_AF
PUSH(regs.ps & ~AF_BREAK)
regs.ps = regs.ps | AF_INTERRUPT;
regs.pc = * (WORD*) (mem+0xFFFA);
CYC(7)
}
if(g_bmIRQ && !(regs.ps & AF_INTERRUPT) && !regs.bJammed)
{
// IRQ signals are deasserted when a specific r/w operation is done on device
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
PUSH(regs.pc >> 8)
PUSH(regs.pc & 0xFF)
EF_TO_AF
PUSH(regs.ps & ~AF_BREAK)
regs.ps = regs.ps | AF_INTERRUPT;
regs.pc = * (WORD*) (mem+0xFFFE);
CYC(7)
}
CheckInterruptSources(uExecutedCycles);
NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
if (bBreakOnInvalid)
break;
@ -1502,10 +1519,11 @@ void CpuDestroy ()
// g_nCyclesExecuted
// g_nCumulativeCycles
//
void CpuCalcCycles(ULONG nCyclesExecuted)
void CpuCalcCycles(ULONG nExecutedCycles)
{
// Calc # of cycles executed since this func was last called
ULONG nCycles = nCyclesExecuted - g_nCyclesExecuted;
ULONG nCycles = nExecutedCycles - g_nCyclesExecuted;
_ASSERT( (LONG)nCycles >= 0 );
g_nCyclesExecuted += nCycles;
g_nCumulativeCycles += nCycles;
@ -1513,11 +1531,26 @@ void CpuCalcCycles(ULONG nCyclesExecuted)
//===========================================================================
ULONG CpuGetCyclesThisFrame()
// Old method with g_uInternalExecutedCycles runs faster!
// Old vs New
// - 68.0,69.0MHz vs 66.7, 67.2MHz (with check for VBL IRQ every opcode)
// - 89.6,88.9MHz vs 87.2, 87.9MHz (without check for VBL IRQ)
// - 75.9, 78.5MHz (with check for VBL IRQ every 128 cycles)
// - 137.9,135.6MHz (with check for VBL IRQ & MB_Update every 128 cycles)
#if 0 // TODO: Measure perf increase by using this new method
ULONG CpuGetCyclesThisFrame(ULONG) // Old func using g_uInternalExecutedCycles
{
CpuCalcCycles(g_uInternalExecutedCycles);
return g_dwCyclesThisFrame + g_nCyclesExecuted;
}
#else
ULONG CpuGetCyclesThisFrame(ULONG nExecutedCycles)
{
CpuCalcCycles(nExecutedCycles);
return g_dwCyclesThisFrame + g_nCyclesExecuted;
}
#endif
//===========================================================================
@ -1528,11 +1561,19 @@ DWORD CpuExecute (DWORD uCycles)
g_nCyclesSubmitted = uCycles;
g_nCyclesExecuted = 0;
//
MB_StartOfCpuExecute();
if (uCycles == 0) // Do single step
uExecutedCycles = InternalCpuExecute(0);
else // Do multi-opcode emulation
uExecutedCycles = InternalCpuExecute(uCycles);
MB_UpdateCycles(uExecutedCycles); // Update 6522s (NB. Do this before updating g_nCumulativeCycles below)
//
UINT nRemainingCycles = uExecutedCycles - g_nCyclesExecuted;
g_nCumulativeCycles += nRemainingCycles;

View File

@ -14,9 +14,9 @@ extern regsrec regs;
extern unsigned __int64 g_nCumulativeCycles;
void CpuDestroy ();
void CpuCalcCycles(ULONG nCyclesLeft);
void CpuCalcCycles(ULONG nExecutedCycles);
DWORD CpuExecute (DWORD);
ULONG CpuGetCyclesThisFrame();
ULONG CpuGetCyclesThisFrame(ULONG nExecutedCycles);
void CpuInitialize ();
void CpuSetupBenchmark ();
void CpuIrqReset();

View File

@ -80,6 +80,8 @@ enum AppMode_e
#define REGVALUE_HDD_IMAGE2 "Harddisk Image 2"
#define REGVALUE_PDL_XTRIM "PDL X-Trim"
#define REGVALUE_PDL_YTRIM "PDL Y-Trim"
#define REGVALUE_SCROLLLOCK_TOGGLE "ScrollLock Toggle"
#define REGVALUE_MOUSE_IN_SLOT4 "Mouse in slot 4"
// Preferences
#define REGVALUE_PREF_START_DIR TEXT("Starting Directory")
@ -95,7 +97,7 @@ typedef BYTE (__stdcall *iofunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE
typedef struct _IMAGE__ { int unused; } *HIMAGE;
enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC};
enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE};
//
@ -114,4 +116,7 @@ enum eApple2Type {
A2TYPE_APPLE2EEHANCED,
// A2TYPE_APPLE2C=APPLE2C_MASK, // Placeholder
A2TYPE_MAX
};
};
enum eBUTTON {BUTTON0=0, BUTTON1};
enum eBUTTONSTATE {BUTTON_UP=0, BUTTON_DOWN};

View File

@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#pragma hdrstop
#include "MouseInterface.h"
#include "..\resource\resource.h"
#define ENABLE_MENU 0
@ -90,6 +91,8 @@ void SetFullScreenMode ();
void SetNormalMode ();
void SetUsingCursor (BOOL);
bool g_bScrollLock_FullSpeed = false;
//===========================================================================
void CreateGdiObjects () {
ZeroMemory(buttonbitmap,BUTTONS*sizeof(HBITMAP));
@ -609,7 +612,9 @@ LRESULT CALLBACK FrameWndProc (
SoundCore_SetFade(FADE_IN);
}
else if (wparam == VK_CAPITAL)
{
KeybToggleCapsLock();
}
else if (wparam == VK_PAUSE)
{
SetUsingCursor(0);
@ -632,6 +637,10 @@ LRESULT CALLBACK FrameWndProc (
VideoRedrawScreen();
g_bResetTiming = true;
}
else if ((wparam == VK_SCROLL) && g_uScrollLockToggle)
{
g_bScrollLock_FullSpeed = !g_bScrollLock_FullSpeed;
}
else if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_LOGO) || (g_nAppMode == MODE_STEPPING))
{
// Note about Alt Gr (Right-Alt):
@ -654,37 +663,53 @@ LRESULT CALLBACK FrameWndProc (
break;
case WM_KEYUP:
if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1)) {
buttondown = -1;
if (fullscreen)
EraseButton(wparam-VK_F1);
else
DrawButton((HDC)0,wparam-VK_F1);
ProcessButtonClick(wparam-VK_F1);
}
else
JoyProcessKey((int)wparam,((lparam & 0x01000000) != 0),0,0);
break;
if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1))
{
buttondown = -1;
if (fullscreen)
EraseButton(wparam-VK_F1);
else
DrawButton((HDC)0,wparam-VK_F1);
ProcessButtonClick(wparam-VK_F1);
}
else
{
JoyProcessKey((int)wparam,((lparam & 0x01000000) != 0),0,0);
}
break;
case WM_LBUTTONDOWN:
if (buttondown == -1) {
if (buttondown == -1)
{
int x = LOWORD(lparam);
int y = HIWORD(lparam);
if ((x >= buttonx) &&
(y >= buttony) &&
(y <= buttony+BUTTONS*BUTTONCY)) {
(y <= buttony+BUTTONS*BUTTONCY))
{
buttonactive = buttondown = (y-buttony-1)/BUTTONCY;
DrawButton((HDC)0,buttonactive);
SetCapture(window);
}
else if (usingcursor)
{
if (wparam & (MK_CONTROL | MK_SHIFT))
{
SetUsingCursor(0);
}
else
JoySetButton(0,1);
else if ((x < buttonx) && JoyUsingMouse() &&
((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING)))
{
if (sg_Mouse.Active())
sg_Mouse.SetButton(BUTTON0, BUTTON_DOWN);
else
JoySetButton(BUTTON0, BUTTON_DOWN);
}
}
else if ( ((x < buttonx) && JoyUsingMouse() && ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING))) ||
(sg_Mouse.Active()) )
{
SetUsingCursor(1);
}
DebuggerMouseClick( x, y );
}
RelayEvent(WM_LBUTTONDOWN,wparam,lparam);
@ -704,7 +729,12 @@ LRESULT CALLBACK FrameWndProc (
buttonactive = -1;
}
else if (usingcursor)
JoySetButton(0,0);
{
if (sg_Mouse.Active())
sg_Mouse.SetButton(BUTTON0, BUTTON_UP);
else
JoySetButton(BUTTON0, BUTTON_UP);
}
RelayEvent(WM_LBUTTONUP,wparam,lparam);
break;
@ -730,10 +760,13 @@ LRESULT CALLBACK FrameWndProc (
if (buttonover != -1)
DrawButton((HDC)0,buttonover);
}
else if (usingcursor) {
else if (usingcursor)
{
DrawCrosshairs(x,y);
JoySetPosition(x-viewportx-2,VIEWPORTCX-4,
y-viewporty-2,VIEWPORTCY-4);
if (sg_Mouse.Active())
sg_Mouse.SetPosition(x-viewportx-2, VIEWPORTCX-4, y-viewporty-2, VIEWPORTCY-4);
else
JoySetPosition(x-viewportx-2, VIEWPORTCX-4, y-viewporty-2, VIEWPORTCY-4);
}
RelayEvent(WM_MOUSEMOVE,wparam,lparam);
break;
@ -832,7 +865,10 @@ LRESULT CALLBACK FrameWndProc (
}
if (usingcursor)
{
JoySetButton(1,(message == WM_RBUTTONDOWN));
if (sg_Mouse.Active())
sg_Mouse.SetButton(BUTTON1, (message == WM_RBUTTONDOWN) ? BUTTON_DOWN : BUTTON_UP);
else
JoySetButton(BUTTON1, (message == WM_RBUTTONDOWN) ? BUTTON_DOWN : BUTTON_UP);
}
RelayEvent(message,wparam,lparam);
break;

View File

@ -25,3 +25,5 @@ LRESULT CALLBACK FrameWndProc (
UINT message,
WPARAM wparam,
LPARAM lparam );
extern bool g_bScrollLock_FullSpeed;

View File

@ -217,7 +217,6 @@ static LPCTSTR HD_DiskGetName (int nDrive)
static BYTE __stdcall HD_IO_EMUL (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
static const DWORD HDDRVR_SIZE = 0x100;
static LPBYTE lpMemC000 = NULL;
bool HD_CardIsEnabled()
{
@ -231,13 +230,14 @@ void HD_SetEnabled(bool bEnabled)
g_bHD_Enabled = bEnabled;
if(lpMemC000 == NULL) // This will be NULL when called after loading value from Registry
LPBYTE pCxRomPeripheral = MemGetCxRomPeripheral();
if(pCxRomPeripheral == NULL) // This will be NULL when called after loading value from Registry
return;
if(g_bHD_Enabled)
HD_Load_Rom(lpMemC000, g_uSlot);
HD_Load_Rom(pCxRomPeripheral, g_uSlot);
else
memset(lpMemC000 + g_uSlot*256, 0, HDDRVR_SIZE);
memset(pCxRomPeripheral + g_uSlot*256, 0, HDDRVR_SIZE);
RegisterIoHandler(g_uSlot, HD_IO_EMUL, HD_IO_EMUL, NULL, NULL, NULL, NULL);
}
@ -249,8 +249,6 @@ LPCTSTR HD_GetFullName (int nDrive)
VOID HD_Load_Rom(LPBYTE pCxRomPeripheral, UINT uSlot)
{
lpMemC000 = pCxRomPeripheral; // Keep a copy for HD_SetEnabled()
if(!g_bHD_Enabled)
return;

View File

@ -39,6 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#pragma hdrstop
#include "MouseInterface.h"
#define BUTTONTIME 5000
@ -365,7 +366,7 @@ BOOL JoyProcessKey (int virtkey, BOOL extended, BOOL down, BOOL autorep)
//===========================================================================
BYTE __stdcall JoyReadButton (WORD, WORD address, BYTE, BYTE, ULONG)
BYTE __stdcall JoyReadButton (WORD, WORD address, BYTE, BYTE, ULONG nCyclesLeft)
{
address &= 0xFF;
@ -397,7 +398,7 @@ BYTE __stdcall JoyReadButton (WORD, WORD address, BYTE, BYTE, ULONG)
break;
}
return MemReadFloatingBus(pressed);
return MemReadFloatingBus(pressed, nCyclesLeft);
}
//===========================================================================
@ -433,7 +434,7 @@ BYTE __stdcall JoyReadPosition (WORD programcounter, WORD address, BYTE, BYTE, U
BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL));
return MemReadFloatingBus(nPdlCntrActive);
return MemReadFloatingBus(nPdlCntrActive, nCyclesLeft);
}
//===========================================================================
@ -455,13 +456,13 @@ BYTE __stdcall JoyResetPosition (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft)
if(joyinfo[joytype[1]].device == DEVICE_JOYSTICK)
CheckJoystick1();
return MemReadFloatingBus();
return MemReadFloatingBus(nCyclesLeft);
}
//===========================================================================
// Called when mouse is being used as a joystick && mouse button changes
void JoySetButton (int number, BOOL down)
void JoySetButton (eBUTTON number, eBUTTONSTATE down)
{
if (number > 1) // Sanity check on mouse button #
return;
@ -473,7 +474,7 @@ void JoySetButton (int number, BOOL down)
// If it is 2nd joystick that is being emulated with mouse, then re-map button #
if(joyinfo[joytype[1]].device == DEVICE_MOUSE)
{
number = 1; // 2nd joystick controls Apple button #1
number = BUTTON1; // 2nd joystick controls Apple button #1
}
setbutton[number] = down;
@ -507,6 +508,15 @@ BOOL JoySetEmulationType (HWND window, DWORD newtype, int nJoystickNumber)
else if ((joyinfo[newtype].device == DEVICE_MOUSE) &&
(joyinfo[joytype[nJoystickNumber]].device != DEVICE_MOUSE))
{
if (sg_Mouse.Active())
{
MessageBox(window,
TEXT("Mouse interface card is enabled - unable to use mouse for joystick emulation."),
TEXT("Configuration"),
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
return 0;
}
MessageBox(window,
TEXT("To begin emulating a joystick with your mouse, move ")
TEXT("the mouse cursor over the emulated screen of a running ")

View File

@ -7,7 +7,7 @@ extern DWORD joytype[2];
void JoyInitialize ();
BOOL JoyProcessKey (int,BOOL,BOOL,BOOL);
void JoyReset ();
void JoySetButton (int,BOOL);
void JoySetButton (eBUTTON,eBUTTONSTATE);
BOOL JoySetEmulationType (HWND,DWORD,int);
void JoySetPosition (int,int,int,int);
void JoyUpdatePosition ();

View File

@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#pragma hdrstop
#include "MouseInterface.h"
#include "..\resource\resource.h"
#define MF_80STORE 0x00000001
@ -362,15 +363,15 @@ static UINT g_uPeripheralRomSlot = 0;
//=============================================================================
BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
{
if (!write)
return MemReadFloatingBus();
return MemReadFloatingBus(nCyclesLeft);
else
return 0;
}
BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
{
// Apple//e ROM:
// . PC=FA6F: LDA $C058 (SETAN0)
@ -387,7 +388,7 @@ BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYT
// - Reset when 6502 accesses $CFFF
// . Enable2 = I/O STROBE' (6502 accesses [$C800..$CFFF])
BYTE __stdcall IORead_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
BYTE __stdcall IORead_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
{
if (address == 0xCFFF)
{
@ -483,12 +484,12 @@ BYTE __stdcall IORead_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE v
}
if ((g_eExpansionRomType == eExpRomNull) && (address >= 0xC800))
return IO_Null(programcounter, address, write, value, nCycles);
return IO_Null(programcounter, address, write, value, nCyclesLeft);
else
return mem[address];
}
BYTE __stdcall IOWrite_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
BYTE __stdcall IOWrite_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
{
return 0;
}
@ -865,6 +866,13 @@ LPBYTE MemGetMainPtr (WORD offset)
//===========================================================================
LPBYTE MemGetCxRomPeripheral()
{
return pCxRomPeripheral;
}
//===========================================================================
void MemPreInitialize ()
{
// Init the I/O handlers
@ -989,10 +997,12 @@ void MemInitialize()
const UINT uSlot = 0;
RegisterIoHandler(uSlot, MemSetPaging, MemSetPaging, NULL, NULL, NULL, NULL);
PrintLoadRom(pCxRomPeripheral, 1); // $C100 : Parallel printer f/w
sg_SSC.CommInitialize(pCxRomPeripheral, 2); // $C200 : SSC
DiskLoadRom(pCxRomPeripheral, 6); // $C600 : Disk][ f/w
HD_Load_Rom(pCxRomPeripheral, 7); // $C700 : HDD f/w
PrintLoadRom(pCxRomPeripheral, 1); // $C100 : Parallel printer f/w
sg_SSC.CommInitialize(pCxRomPeripheral, 2); // $C200 : SSC
if (g_Slot4 == CT_MouseInterface)
sg_Mouse.Initialize(pCxRomPeripheral, 4); // $C400 : Mouse f/w
DiskLoadRom(pCxRomPeripheral, 6); // $C600 : Disk][ f/w
HD_Load_Rom(pCxRomPeripheral, 7); // $C700 : HDD f/w
MemReset();
}
@ -1069,16 +1079,16 @@ BYTE MemReturnRandomData (BYTE highbit)
//===========================================================================
BYTE MemReadFloatingBus()
BYTE MemReadFloatingBus(const ULONG uExecutedCycles)
{
return*(LPBYTE)(mem + VideoGetScannerAddress());
return*(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles));
}
//===========================================================================
BYTE MemReadFloatingBus(BYTE const highbit)
BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles)
{
BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress());
BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles));
return (r & ~0x80) | ((highbit) ? 0x80 : 0);
}
@ -1103,7 +1113,7 @@ BYTE MemReadFloatingBus(BYTE const highbit)
//}
//===========================================================================
BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE value, ULONG)
BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
{
address &= 0xFF;
DWORD lastmemmode = memmode;
@ -1166,13 +1176,13 @@ BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE
if ((address >= 4) && (address <= 5) &&
((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) {
modechanging = 1;
return write ? 0 : MemReadFloatingBus(1);
return write ? 0 : MemReadFloatingBus(1, nCyclesLeft);
}
if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) &&
(((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) ||
((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) {
modechanging = 1;
return write ? 0 : MemReadFloatingBus(1);
return write ? 0 : MemReadFloatingBus(1, nCyclesLeft);
}
// IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND
@ -1216,9 +1226,9 @@ BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE
}
if ((address <= 1) || ((address >= 0x54) && (address <= 0x57)))
return VideoSetMode(programcounter,address,write,value,0);
return VideoSetMode(programcounter,address,write,value,nCyclesLeft);
return write ? 0 : MemReadFloatingBus();
return write ? 0 : MemReadFloatingBus(nCyclesLeft);
}
//===========================================================================

View File

@ -26,10 +26,11 @@ bool MemGet80Store();
bool MemCheckSLOTCXROM();
LPBYTE MemGetAuxPtr (WORD);
LPBYTE MemGetMainPtr (WORD);
LPBYTE MemGetCxRomPeripheral();
void MemPreInitialize ();
void MemInitialize ();
BYTE MemReadFloatingBus();
BYTE MemReadFloatingBus(BYTE highbit);
BYTE MemReadFloatingBus(const ULONG uExecutedCycles);
BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles);
void MemReset ();
void MemResetPaging ();
BYTE MemReturnRandomData (BYTE highbit);

View File

@ -145,6 +145,7 @@ static SY6522_AY8910 g_MB[NUM_AY8910];
// Timer vars
static ULONG g_n6522TimerPeriod = 0;
static USHORT g_nMBTimerDevice = 0; // SY6522 device# which is generating timer IRQ
static UINT64 g_uLastCumulativeCycles = 0;
// SSI263 vars:
static USHORT g_nSSI263Device = 0; // SSI263 device# which is generating phoneme-complete IRQ
@ -1307,8 +1308,11 @@ void MB_Initialize()
//
const UINT uSlot4 = 4;
RegisterIoHandler(uSlot4, PhasorIO, PhasorIO, MB_Read, MB_Write, NULL, NULL);
if (g_Slot4 == CT_Mockingboard)
{
const UINT uSlot4 = 4;
RegisterIoHandler(uSlot4, PhasorIO, PhasorIO, MB_Read, MB_Write, NULL, NULL);
}
const UINT uSlot5 = 5;
RegisterIoHandler(uSlot5, PhasorIO, PhasorIO, MB_Read, MB_Write, NULL, NULL);
@ -1354,7 +1358,7 @@ void MB_Reset()
static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
{
CpuCalcCycles(nCyclesLeft);
MB_UpdateCycles(nCyclesLeft);
if(!IS_APPLE2 && !MemCheckSLOTCXROM())
return mem[nAddr];
@ -1404,7 +1408,7 @@ static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULO
static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
{
CpuCalcCycles(nCyclesLeft);
MB_UpdateCycles(nCyclesLeft);
if(!IS_APPLE2 && !MemCheckSLOTCXROM())
return 0;
@ -1502,8 +1506,14 @@ void MB_Demute()
//-----------------------------------------------------------------------------
// Called by CpuExecute() before doing CPU emulation
void MB_StartOfCpuExecute()
{
g_uLastCumulativeCycles = g_nCumulativeCycles;
}
// Called by ContinueExecution() at the end of every video frame
void MB_EndOfFrame()
void MB_EndOfVideoFrame()
{
if(g_SoundcardType == SC_NONE)
return;
@ -1514,13 +1524,20 @@ void MB_EndOfFrame()
//-----------------------------------------------------------------------------
// Called by InternalCpuExecute() after every opcode
// OLD: Called by CpuExecute() & CpuCalcCycles()
void MB_UpdateCycles(USHORT nClocks)
// Called by InternalCpuExecute() after every N opcodes
// OLD: Called by InternalCpuExecute() after every opcode
// OLD: void MB_UpdateCycles(USHORT nClocks)
void MB_UpdateCycles(ULONG uExecutedCycles)
{
if(g_SoundcardType == SC_NONE)
return;
CpuCalcCycles(uExecutedCycles);
UINT64 uCycles = g_nCumulativeCycles - g_uLastCumulativeCycles;
g_uLastCumulativeCycles = g_nCumulativeCycles;
_ASSERT(uCycles < 0x10000);
USHORT nClocks = (USHORT) uCycles;
for(int i=0; i<NUM_SY6522; i++)
{
SY6522_AY8910* pMB = &g_MB[i];

View File

@ -9,9 +9,10 @@ void MB_Destroy();
void MB_Reset();
void MB_Mute();
void MB_Demute();
void MB_EndOfFrame();
void MB_StartOfCpuExecute();
void MB_EndOfVideoFrame();
void MB_CheckIRQ();
void MB_UpdateCycles(USHORT nClocks);
void MB_UpdateCycles(ULONG uExecutedCycles);
eSOUNDCARDTYPE MB_GetSoundcardType();
void MB_SetSoundcardType(eSOUNDCARDTYPE NewSoundcardType);
double MB_GetFramePeriod();

View File

@ -0,0 +1,431 @@
// Based on Apple in PC's mousecard.cpp
// - Permission given by Kyle Kim to reuse in AppleWin
#include "stdafx.h"
#pragma hdrstop
#include "..\resource\resource.h"
#include "MouseInterface.h"
// 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
WRITE_HANDLER( M6821_Listener_B )
{
((CMouseInterface*)objTo)->On6821_B( byData );
}
WRITE_HANDLER( M6821_Listener_A )
{
((CMouseInterface*)objTo)->On6821_A( byData );
}
//CALLBACK_HANDLER( MouseHandler )
//{
// ((CMouseInterface*)objTo)->OnMouseEvent();
//}
//===========================================================================
CMouseInterface::CMouseInterface() :
m_pSlotRom(NULL)
{
m_6821.SetListenerB( this, M6821_Listener_B );
m_6821.SetListenerA( this, M6821_Listener_A );
// g_cDIMouse.SetMouseListener( this, MouseHandler );
m_by6821A = 0;
m_by6821B = 0x40; // Set PB6
m_6821.SetPB(m_by6821B);
m_bVBL = FALSE;
//
m_iX = 0;
m_iMinX = 0;
m_iMaxX = 1023;
m_iRangeX = 0;
m_iY = 0;
m_iMinY = 0;
m_iMaxY = 1023;
m_iRangeY = 0;
m_bButtons[0] = m_bButtons[1] = FALSE;
//
Reset();
memset( m_byBuff, 0, sizeof( m_byBuff ) );
m_bActive = false;
}
CMouseInterface::~CMouseInterface()
{
delete [] m_pSlotRom;
}
//===========================================================================
void CMouseInterface::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot)
{
const UINT FW_SIZE = 2*1024;
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_MOUSEINTERFACE_FW), "FIRMWARE");
if(hResInfo == NULL)
return;
DWORD dwResSize = SizeofResource(NULL, hResInfo);
if(dwResSize != FW_SIZE)
return;
HGLOBAL hResData = LoadResource(NULL, hResInfo);
if(hResData == NULL)
return;
BYTE* pData = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource
if(pData == NULL)
return;
m_uSlot = uSlot;
if (m_pSlotRom == NULL)
{
m_pSlotRom = new BYTE [FW_SIZE];
if (m_pSlotRom)
memcpy(m_pSlotRom, pData, FW_SIZE);
}
//
SetSlotRom();
RegisterIoHandler(uSlot, &CMouseInterface::IORead, &CMouseInterface::IOWrite, NULL, NULL, this, NULL);
m_bActive = true;
}
void CMouseInterface::SetSlotRom()
{
LPBYTE pCxRomPeripheral = MemGetCxRomPeripheral();
if (pCxRomPeripheral == NULL)
return;
UINT uOffset = (m_by6821B << 7) & 0x0700;
memcpy(pCxRomPeripheral+m_uSlot*256, m_pSlotRom+uOffset, 256);
if (mem)
memcpy(mem+0xC000+m_uSlot*256, m_pSlotRom+uOffset, 256);
}
//===========================================================================
BYTE __stdcall CMouseInterface::IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft)
{
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 nCyclesLeft)
{
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()
{
//char szDbg[256];
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 &= 0x20;
m_nX = m_iX;
m_nY = m_iY;
if ( m_bBtn0 ) m_byState |= 0x40; // Previous Button 0
if ( m_bBtn1 ) m_byState |= 0x01; // Previous Button 1
m_bBtn0 = m_bButtons[0];
m_bBtn1 = m_bButtons[1];
if ( m_bBtn0 ) m_byState |= 0x80; // Current Button 0
if ( m_bBtn1 ) m_byState |= 0x10; // 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 &= ~0x20;
//sprintf(szDbg, "[MOUSE-READ] IRQ=0x%02X X=(0x%02X-0x%02X) Y=(0x%02X-0x%02X) \n", m_byBuff[5], m_byBuff[1], m_byBuff[2], m_byBuff[3], m_byBuff[4]); OutputDebugString(szDbg);
break;
case MOUSE_SERV:
m_nDataLen = 2;
m_byBuff[1] = m_byState & ~0x20; // reason of interrupt
CpuIrqDeassert(IS_MOUSE);
//sprintf(szDbg, "[MOUSE-SERV] IRQ=0x%02X\n", m_byBuff[1]); OutputDebugString(szDbg);
break;
case MOUSE_CLEAR:
Reset();
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;
SetPosition( 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:
nMin = ( m_byBuff[3] << 8 ) | m_byBuff[1];
nMax = ( m_byBuff[4] << 8 ) | m_byBuff[2];
if ( m_byBuff[0] & 1 ) // Clamp Y
ClampY( nMin, nMax );
else // Clamp X
ClampX( nMin, nMax );
break;
case MOUSE_POS:
m_nX = ( m_byBuff[2] << 8 ) | m_byBuff[1];
m_nY = ( m_byBuff[4] << 8 ) | m_byBuff[3];
SetPosition( m_nX, m_nY );
break;
case MOUSE_INIT:
m_nX = 0;
m_nY = 0;
ClampX( 0, 1023 );
ClampY( 0, 1023 );
SetPosition( 0, 0 );
break;
}
}
void CMouseInterface::OnMouseEvent()
{
int byState = 0;
if ( !( m_byMode & 1 ) ) // Mouse Off
return;
BOOL bBtn0 = m_bButtons[0];
BOOL bBtn1 = m_bButtons[1];
if ( m_nX != m_iX || m_nY != m_iY )
byState |= 0x22; // X/Y moved since last READMOUSE | Movement interrupt
if ( m_bBtn0 != bBtn0 || m_bBtn1 != bBtn1 )
byState |= 0x04; // Button 0/1 interrupt
if ( m_bVBL )
byState |= 0x08;
byState &= m_byMode & 0x2E;
if ( byState & 0x0E )
{
//char szDbg[256];
//sprintf(szDbg, "[MOUSE] 0x%02X, %04d(%04d), %04d(%04d), %d\n", byState, m_iX, m_nX, m_iY, m_nY, bBtn0); OutputDebugString(szDbg);
m_byState |= byState;
CpuIrqAssert(IS_MOUSE);
}
}
void CMouseInterface::SetVBlank(bool bVBL)
{
if ( m_bVBL != bVBL )
{
m_bVBL = bVBL;
if ( m_bVBL ) // Rising edge
OnMouseEvent();
}
}
void CMouseInterface::Reset()
{
m_nBuffPos = 0;
m_nDataLen = 1;
m_byMode = 0;
m_byState = 0;
m_nX = 0;
m_nY = 0;
m_bBtn0 = 0;
m_bBtn1 = 0;
ClampX( 0, 1023 );
ClampY( 0, 1023 );
SetPosition( 0, 0 );
// CpuIrqDeassert(IS_MOUSE);
}
//===========================================================================
void CMouseInterface::ClampX(int iMinX, int iMaxX)
{
if ( iMinX < 0 || iMinX > iMaxX )
return;
m_iMaxX = iMaxX;
m_iMinX = iMinX;
if ( m_iX > m_iMaxX ) m_iX = m_iMaxX; else if ( m_iX < m_iMinX ) m_iX = m_iMinX;
}
void CMouseInterface::ClampY(int iMinY, int iMaxY)
{
if ( iMinY < 0 || iMinY > iMaxY )
return;
m_iMaxY = iMaxY;
m_iMinY = iMinY;
if ( m_iY > m_iMaxY ) m_iY = m_iMaxY; else if ( m_iY < m_iMinX ) m_iY = m_iMinY;
}
void CMouseInterface::SetPosition(int xvalue, int yvalue)
{
if ((m_iRangeX == 0) || (m_iRangeY == 0))
{
m_iX = m_iMinX;
m_iY = m_iMinY;
return;
}
m_iX = (UINT) ((xvalue*m_iMaxX) / m_iRangeX);
m_iY = (UINT) ((yvalue*m_iMaxY) / m_iRangeY);
}
void CMouseInterface::SetPosition(int xvalue, int xrange, int yvalue, int yrange)
{
m_iRangeX = (UINT) xrange;
m_iRangeY = (UINT) yrange;
SetPosition(xvalue, yvalue);
OnMouseEvent();
}
void CMouseInterface::SetButton(eBUTTON Button, eBUTTONSTATE State)
{
m_bButtons[Button]= (State == BUTTON_DOWN) ? TRUE : FALSE;
OnMouseEvent();
}

View File

@ -0,0 +1,79 @@
#include "6821.h"
#include "Common.h"
#define WRITE_HANDLER(func) void func( void* objFrom, void* objTo, int nAddr, BYTE byData )
#define CALLBACK_HANDLER(func) void func( void* objFrom, void* objTo, LPARAM lParam )
extern class CMouseInterface sg_Mouse;
class CMouseInterface
{
public:
CMouseInterface();
virtual ~CMouseInterface();
void Initialize(LPBYTE pCxRomPeripheral, UINT uSlot);
void Uninitialize(){ m_bActive = false; }
void SetSlotRom();
static BYTE __stdcall IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft);
static BYTE __stdcall IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft);
void SetPosition(int xvalue, int xrange, int yvalue, int yrange);
void SetButton(eBUTTON Button, eBUTTONSTATE State);
bool Active() { return m_bActive; }
void SetVBlank(bool bVBL);
protected:
void On6821_A(BYTE byData);
void On6821_B(BYTE byData);
void OnCommand();
void OnWrite();
void OnMouseEvent();
void Reset();
friend WRITE_HANDLER( M6821_Listener_A );
friend WRITE_HANDLER( M6821_Listener_B );
//friend CALLBACK_HANDLER( MouseHandler );
void SetPosition(int xvalue, int yvalue);
void ClampX(int iMinX, int iMaxX);
void ClampY(int iMinY, int iMaxY);
C6821 m_6821;
int m_nDataLen;
BYTE m_byMode;
BYTE m_by6821B;
BYTE m_by6821A;
BYTE m_byBuff[8]; // m_byBuff[0] is mode byte
int m_nBuffPos;
BYTE m_byState;
int m_nX;
int m_nY;
BOOL m_bBtn0;
BOOL m_bBtn1;
bool m_bVBL;
//
UINT m_iX;
UINT m_iRangeX;
UINT m_iMinX;
UINT m_iMaxX;
UINT m_iY;
UINT m_iRangeY;
UINT m_iMinY;
UINT m_iMaxY;
BOOL m_bButtons[2];
//
bool m_bActive;
LPBYTE m_pSlotRom;
UINT m_uSlot;
};

View File

@ -101,6 +101,9 @@ enum {PG_CONFIG=0, PG_INPUT, PG_SOUND, PG_SAVESTATE, PG_DISK, PG_NUM_SHEETS};
UINT g_nLastPage = PG_CONFIG;
UINT g_uScrollLockToggle = 0;
UINT g_uMouseInSlot4 = 0;
//===========================================================================
static void FillComboBox (HWND window, int controlid, LPCTSTR choices, int currentchoice)
@ -224,15 +227,17 @@ static void ConfigDlg_OK(HWND window, BOOL afterclose)
if (NewApple2Type != g_Apple2Type)
{
if (MessageBox(window,
TEXT(
"You have changed the emulated computer "
"type. This change will not take effect "
"until the next time you restart the "
"emulator.\n\n"
"Would you like to restart the emulator now?"),
TEXT("Configuration"),
MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES)
TEXT(
"You have changed the emulated computer "
"type. This change will not take effect "
"until the next time you restart the "
"emulator.\n\n"
"Would you like to restart the emulator now?"),
TEXT("Configuration"),
MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES)
{
afterclose = WM_USER_RESTART;
}
}
if (videotype != newvidtype)
@ -257,6 +262,7 @@ static void ConfigDlg_OK(HWND window, BOOL afterclose)
SAVE(TEXT("Custom Speed") ,IsDlgButtonChecked(window,IDC_CUSTOM_SPEED));
SAVE(TEXT("Emulation Speed") ,g_dwSpeed);
SAVE(TEXT("Video Emulation") ,videotype);
SAVE(TEXT(REGVALUE_MOUSE_IN_SLOT4),g_uMouseInSlot4);
//
@ -332,6 +338,31 @@ static BOOL CALLBACK ConfigDlgProc (HWND window,
VideoChooseColor();
break;
case IDC_MOUSE_IN_SLOT4:
UINT uNewState = IsDlgButtonChecked(window, IDC_MOUSE_IN_SLOT4) ? 1 : 0;
LPCSTR pMsg = uNewState ?
TEXT("The emulator needs to restart as the slot configuration has changed.\n")
TEXT("Also Mockingboard/Phasor cards won't be available in slot 4.\n\n")
TEXT("Would you like to restart the emulator now?")
:
TEXT("The emulator needs to restart as the slot configuration has changed.\n")
TEXT("(Mockingboard/Phasor cards will now be available in slot 4.)\n\n")
TEXT("Would you like to restart the emulator now?");
if (MessageBox(window,
pMsg,
TEXT("Configuration"),
MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES)
{
g_uMouseInSlot4 = uNewState;
afterclose = WM_USER_RESTART;
PropSheet_PressButton(GetParent(window), PSBTN_OK);
}
else
{
CheckDlgButton(window, IDC_MOUSE_IN_SLOT4, g_uMouseInSlot4 ? BST_CHECKED : BST_UNCHECKED);
}
break;
#if 0
case IDC_RECALIBRATE:
RegSaveValue(TEXT(""),TEXT("RunningOnOS"),0,0);
@ -384,6 +415,8 @@ static BOOL CALLBACK ConfigDlgProc (HWND window,
EnableTrackbar(window, custom);
}
CheckDlgButton(window, IDC_MOUSE_IN_SLOT4, g_uMouseInSlot4 ? BST_CHECKED : BST_UNCHECKED);
afterclose = 0;
break;
}
@ -444,6 +477,7 @@ static void InputDlg_OK(HWND window, BOOL afterclose)
SAVE(TEXT("Joystick 1 Emulation"),joytype[1]);
SAVE(TEXT(REGVALUE_PDL_XTRIM),JoyGetTrim(true));
SAVE(TEXT(REGVALUE_PDL_YTRIM),JoyGetTrim(false));
SAVE(TEXT(REGVALUE_SCROLLLOCK_TOGGLE),g_uScrollLockToggle);
// SAVE(TEXT(REGVALUE_KEYB_BUFFER_ENABLE),KeybGetBufferMode() ? 1 : 0);
//
@ -527,11 +561,14 @@ static BOOL CALLBACK InputDlgProc (HWND window,
InitJoystickChoices(window, JN_JOYSTICK0, IDC_JOYSTICK0); // Re-init joy0 list
}
break;
// case IDC_KEYB_BUFFER_ENABLE:
// break;
case IDC_SCROLLLOCK_TOGGLE:
g_uScrollLockToggle = IsDlgButtonChecked(window, IDC_SCROLLLOCK_TOGGLE) ? 1 : 0;
break;
case IDC_PASTE_FROM_CLIPBOARD:
ClipboardInitiatePaste();
break;
// case IDC_KEYB_BUFFER_ENABLE:
// break;
}
break;
@ -548,6 +585,7 @@ static BOOL CALLBACK InputDlgProc (HWND window,
SendDlgItemMessage(window, IDC_SPIN_XTRIM, UDM_SETPOS, 0, MAKELONG(JoyGetTrim(true),0));
SendDlgItemMessage(window, IDC_SPIN_YTRIM, UDM_SETPOS, 0, MAKELONG(JoyGetTrim(false),0));
CheckDlgButton(window, IDC_SCROLLLOCK_TOGGLE, g_uScrollLockToggle ? BST_CHECKED : BST_UNCHECKED);
// CheckDlgButton(window, IDC_KEYB_BUFFER_ENABLE, KeybGetBufferMode() ? BST_CHECKED : BST_UNCHECKED);
}
}
@ -675,6 +713,11 @@ static BOOL CALLBACK SoundDlgProc (HWND window,
CheckRadioButton(window, IDC_MB_ENABLE, IDC_SOUNDCARD_DISABLE, nID);
if (g_uMouseInSlot4)
{
EnableWindow(GetDlgItem(window, IDC_PHASOR_ENABLE), FALSE);
}
afterclose = 0;
}
}
@ -734,7 +777,18 @@ static int SaveStateSelectImage(HWND hWindow, TCHAR* pszTitle, bool bSave)
TCHAR szDirectory[MAX_PATH] = TEXT("");
TCHAR szFilename[MAX_PATH];
strcpy(szFilename, Snapshot_GetFilename());
// Attempt to use drive1's image name as the name for the .aws file
LPCTSTR pDiskName0 = DiskGetName(0);
if (pDiskName0 && pDiskName0[0])
{
strcpy(szFilename, pDiskName0);
strcpy(&szFilename[strlen(pDiskName0)], ".aws");
// NB. OK'ing this property sheet will call Snapshot_SetFilename() with this new filename
}
else
{
strcpy(szFilename, Snapshot_GetFilename());
}
RegLoadString(TEXT("Preferences"),REGVALUE_PREF_START_DIR,1,szDirectory,MAX_PATH);

View File

@ -6,3 +6,6 @@ bool PSP_SaveStateSelectImage(HWND hWindow, bool bSave);
void ui_tfe_settings_dialog(HWND hwnd);
void * get_tfe_interface(void);
void get_tfe_enabled(int *tfe_enabled);
extern UINT g_uScrollLockToggle;
extern UINT g_uMouseInSlot4;

View File

@ -87,10 +87,6 @@ CSuperSerialCard::CSuperSerialCard()
memset(&m_o, 0, sizeof(m_o));
}
CSuperSerialCard::~CSuperSerialCard()
{
}
//===========================================================================
// TODO: Serial Comms - UI Property Sheet Page:

View File

@ -23,7 +23,7 @@ class CSuperSerialCard
{
public:
CSuperSerialCard();
~CSuperSerialCard();
virtual ~CSuperSerialCard() {}
void CommInitialize(LPBYTE pCxRomPeripheral, UINT uSlot);
void CommReset();

View File

@ -492,7 +492,7 @@ BYTE __stdcall SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft)
}
return MemReadFloatingBus();
return MemReadFloatingBus(nCyclesLeft);
}
//=============================================================================
@ -802,7 +802,7 @@ static ULONG Spkr_SubmitWaveBuffer_FullSpeed(short* pSpeakerBuffer, ULONG nNumSa
static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
{
char szDbg[200];
//char szDbg[200];
nDbgSpkrCnt++;
if(!SpeakerVoice.bActive)
@ -838,7 +838,7 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
dwByteOffset = dwCurrentPlayCursor + (g_dwDSSpkrBufferSize/8)*3; // Ideal: 0.375 is between 0.25 & 0.50 full
dwByteOffset %= g_dwDSSpkrBufferSize;
sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X [REINIT]\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset); OutputDebugString(szDbg);
//sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X [REINIT]\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset); OutputDebugString(szDbg);
}
else
{
@ -849,7 +849,7 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
// |-----PxxxxxW-----|
if((dwByteOffset > dwCurrentPlayCursor) && (dwByteOffset < dwCurrentWriteCursor))
{
sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
//sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
dwByteOffset = dwCurrentWriteCursor;
nNumSamplesError = 0;
bBufferError = true;
@ -860,7 +860,7 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
// |xxW----------Pxxx|
if((dwByteOffset > dwCurrentPlayCursor) || (dwByteOffset < dwCurrentWriteCursor))
{
sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
//sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
dwByteOffset = dwCurrentWriteCursor;
nNumSamplesError = 0;
bBufferError = true;

View File

@ -147,6 +147,7 @@ enum SS_CARDTYPE
CT_GenericPrinter,
CT_GenericHDD, // Hard disk
CT_GenericClock,
CT_MouseInterface,
};
/////////////////////////////////////////////////////////////////////////////////

View File

@ -1570,11 +1570,11 @@ void VideoBenchmark () {
}
//===========================================================================
BYTE __stdcall VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG)
BYTE __stdcall VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG nCyclesLeft)
{
address &= 0xFF;
if (address == 0x7F)
return MemReadFloatingBus(SW_DHIRES != 0);
return MemReadFloatingBus(SW_DHIRES != 0, nCyclesLeft);
else {
BOOL result = 0;
switch (address) {
@ -1601,7 +1601,7 @@ void VideoCheckPage (BOOL force) {
}
//===========================================================================
BYTE __stdcall VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG)
BYTE __stdcall VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft)
{
/*
// Drol expects = 80
@ -1644,7 +1644,7 @@ BYTE __stdcall VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG)
*/
bool bVblBar;
VideoGetScannerAddress(&bVblBar);
VideoGetScannerAddress(&bVblBar, nCyclesLeft);
BYTE r = KeybGetKeycode();
return (r & ~0x80) | ((bVblBar) ? 0x80 : 0);
}
@ -2042,7 +2042,7 @@ void VideoResetState () {
}
//===========================================================================
BYTE __stdcall VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG)
BYTE __stdcall VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG nCyclesLeft)
{
address &= 0xFF;
DWORD oldpage2 = SW_PAGE2;
@ -2097,7 +2097,7 @@ BYTE __stdcall VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG)
}
lastpageflip = emulmsec;
}
return MemReadFloatingBus();
return MemReadFloatingBus(nCyclesLeft);
}
//===========================================================================
@ -2160,11 +2160,11 @@ DWORD VideoSetSnapshot(SS_IO_Video* pSS)
//===========================================================================
WORD VideoGetScannerAddress(bool* pbVblBar_OUT)
WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles)
{
// get video scanner position
//
int nCycles = CpuGetCyclesThisFrame();
int nCycles = CpuGetCyclesThisFrame(uExecutedCycles);
// machine state switches
//
@ -2270,3 +2270,39 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT)
}
//===========================================================================
// Derived from VideoGetScannerAddress()
bool VideoGetVbl(const DWORD uExecutedCycles)
{
// get video scanner position
//
int nCycles = CpuGetCyclesThisFrame(uExecutedCycles);
// calculate video parameters according to display standard
//
int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines;
// calculate vertical scanning state
//
int nVLine = nCycles / kHClocks; // which vertical scanning line
int nVState = kVLine0State + nVLine; // V state bits
if ((nVLine >= kVPresetLine)) // check for previous vertical state preset
{
nVState -= nScanLines; // compensate for preset
}
int v_3 = (nVState >> 6) & 1;
int v_4 = (nVState >> 7) & 1;
// update VBL' state
//
if (v_4 & v_3) // VBL?
{
return false; // Y: VBL' is false
}
else
{
return true; // N: VBL' is true
}
}
//===========================================================================

View File

@ -63,7 +63,8 @@ void VideoRedrawScreen ();
void VideoRefreshScreen ();
void VideoReinitialize ();
void VideoResetState ();
WORD VideoGetScannerAddress(bool* pbVblBar_OUT = NULL);
WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles);
bool VideoGetVbl(DWORD uExecutedCycles);
void VideoUpdateVbl (DWORD dwCyclesThisFrame);
void VideoUpdateFlash();
bool VideoGetSW80COL();