diff --git a/Applewin.vcproj b/Applewin.vcproj
index 1d9106a3..aec6316c 100644
--- a/Applewin.vcproj
+++ b/Applewin.vcproj
@@ -209,6 +209,14 @@
Name="Source"
Filter=".cpp"
>
+
+
+
+
@@ -305,6 +313,14 @@
RelativePath=".\source\Mockingboard.h"
>
+
+
+
+
@@ -673,6 +689,10 @@
RelativePath=".\source\Common.h"
>
+
+
diff --git a/resource/Applewin.rc b/resource/Applewin.rc
index 3a61f2b2..e3676eea 100644
--- a/resource/Applewin.rc
+++ b/resource/Applewin.rc
@@ -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"
/////////////////////////////////////////////////////////////////////////////
//
diff --git a/resource/resource.h b/resource/resource.h
index 820ce8c8..45fddaf6 100644
--- a/resource/resource.h
+++ b/resource/resource.h
@@ -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
diff --git a/source/6821.cpp b/source/6821.cpp
new file mode 100644
index 00000000..c0266ccf
--- /dev/null
+++ b/source/6821.cpp
@@ -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;
+}
diff --git a/source/6821.h b/source/6821.h
new file mode 100644
index 00000000..75187dd2
--- /dev/null
+++ b/source/6821.h
@@ -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;
+};
diff --git a/source/Applewin.cpp b/source/Applewin.cpp
index bac87f60..80141f7d 100644
--- a/source/Applewin.cpp
+++ b/source/Applewin.cpp
@@ -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);
diff --git a/source/Applewin.h b/source/Applewin.h
index 7454709d..a66b413a 100644
--- a/source/Applewin.h
+++ b/source/Applewin.h
@@ -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();
diff --git a/source/CPU.cpp b/source/CPU.cpp
index 8735bde4..3e173896 100644
--- a/source/CPU.cpp
+++ b/source/CPU.cpp
@@ -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;
diff --git a/source/CPU.h b/source/CPU.h
index e6f3303c..311ed24b 100644
--- a/source/CPU.h
+++ b/source/CPU.h
@@ -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();
diff --git a/source/Common.h b/source/Common.h
index ec5774a8..cd63a235 100644
--- a/source/Common.h
+++ b/source/Common.h
@@ -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
- };
\ No newline at end of file
+ };
+
+enum eBUTTON {BUTTON0=0, BUTTON1};
+enum eBUTTONSTATE {BUTTON_UP=0, BUTTON_DOWN};
diff --git a/source/Frame.cpp b/source/Frame.cpp
index 61f8700c..ff87958b 100644
--- a/source/Frame.cpp
+++ b/source/Frame.cpp
@@ -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;
diff --git a/source/Frame.h b/source/Frame.h
index f32e6a14..a4082b04 100644
--- a/source/Frame.h
+++ b/source/Frame.h
@@ -25,3 +25,5 @@ LRESULT CALLBACK FrameWndProc (
UINT message,
WPARAM wparam,
LPARAM lparam );
+
+extern bool g_bScrollLock_FullSpeed;
diff --git a/source/Harddisk.cpp b/source/Harddisk.cpp
index 616c2d51..a0ee19f6 100644
--- a/source/Harddisk.cpp
+++ b/source/Harddisk.cpp
@@ -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;
diff --git a/source/Joystick.cpp b/source/Joystick.cpp
index 90c2eeea..0647e36b 100644
--- a/source/Joystick.cpp
+++ b/source/Joystick.cpp
@@ -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 ")
diff --git a/source/Joystick.h b/source/Joystick.h
index 79b92832..3127d07c 100644
--- a/source/Joystick.h
+++ b/source/Joystick.h
@@ -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 ();
diff --git a/source/Memory.cpp b/source/Memory.cpp
index 1fef3817..db84f860 100644
--- a/source/Memory.cpp
+++ b/source/Memory.cpp
@@ -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);
}
//===========================================================================
diff --git a/source/Memory.h b/source/Memory.h
index 892eb1f3..59156ba0 100644
--- a/source/Memory.h
+++ b/source/Memory.h
@@ -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);
diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp
index 58f918e1..80105dfc 100644
--- a/source/Mockingboard.cpp
+++ b/source/Mockingboard.cpp
@@ -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; iOn6821_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();
+}
diff --git a/source/MouseInterface.h b/source/MouseInterface.h
new file mode 100644
index 00000000..43995156
--- /dev/null
+++ b/source/MouseInterface.h
@@ -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;
+};
diff --git a/source/PropertySheetPage.cpp b/source/PropertySheetPage.cpp
index bcb90452..ccf170ff 100644
--- a/source/PropertySheetPage.cpp
+++ b/source/PropertySheetPage.cpp
@@ -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);
diff --git a/source/PropertySheetPage.h b/source/PropertySheetPage.h
index a7abfd71..ab32beca 100644
--- a/source/PropertySheetPage.h
+++ b/source/PropertySheetPage.h
@@ -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;
diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp
index 74517cae..ff9985dc 100644
--- a/source/SerialComms.cpp
+++ b/source/SerialComms.cpp
@@ -87,10 +87,6 @@ CSuperSerialCard::CSuperSerialCard()
memset(&m_o, 0, sizeof(m_o));
}
-CSuperSerialCard::~CSuperSerialCard()
-{
-}
-
//===========================================================================
// TODO: Serial Comms - UI Property Sheet Page:
diff --git a/source/SerialComms.h b/source/SerialComms.h
index 44aefda9..9b6df460 100644
--- a/source/SerialComms.h
+++ b/source/SerialComms.h
@@ -23,7 +23,7 @@ class CSuperSerialCard
{
public:
CSuperSerialCard();
- ~CSuperSerialCard();
+ virtual ~CSuperSerialCard() {}
void CommInitialize(LPBYTE pCxRomPeripheral, UINT uSlot);
void CommReset();
diff --git a/source/Speaker.cpp b/source/Speaker.cpp
index adbf9654..5301f092 100644
--- a/source/Speaker.cpp
+++ b/source/Speaker.cpp
@@ -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;
diff --git a/source/Structs.h b/source/Structs.h
index 50129101..57c21c25 100644
--- a/source/Structs.h
+++ b/source/Structs.h
@@ -147,6 +147,7 @@ enum SS_CARDTYPE
CT_GenericPrinter,
CT_GenericHDD, // Hard disk
CT_GenericClock,
+ CT_MouseInterface,
};
/////////////////////////////////////////////////////////////////////////////////
diff --git a/source/Video.cpp b/source/Video.cpp
index a7431af8..ba19677a 100644
--- a/source/Video.cpp
+++ b/source/Video.cpp
@@ -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
+ }
+}
+
+//===========================================================================
diff --git a/source/Video.h b/source/Video.h
index 5c563a24..02893978 100644
--- a/source/Video.h
+++ b/source/Video.h
@@ -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();