diff --git a/AppleWin/Applewin.vcproj b/AppleWin/Applewin.vcproj index 1d9106a3..aec6316c 100644 --- a/AppleWin/Applewin.vcproj +++ b/AppleWin/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/AppleWin/resource/Applewin.rc b/AppleWin/resource/Applewin.rc index 3a61f2b2..e3676eea 100644 --- a/AppleWin/resource/Applewin.rc +++ b/AppleWin/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/AppleWin/resource/resource.h b/AppleWin/resource/resource.h index 820ce8c8..45fddaf6 100644 --- a/AppleWin/resource/resource.h +++ b/AppleWin/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/AppleWin/source/6821.cpp b/AppleWin/source/6821.cpp new file mode 100644 index 00000000..c0266ccf --- /dev/null +++ b/AppleWin/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/AppleWin/source/6821.h b/AppleWin/source/6821.h new file mode 100644 index 00000000..75187dd2 --- /dev/null +++ b/AppleWin/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/AppleWin/source/Applewin.cpp b/AppleWin/source/Applewin.cpp index bac87f60..80141f7d 100644 --- a/AppleWin/source/Applewin.cpp +++ b/AppleWin/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/AppleWin/source/Applewin.h b/AppleWin/source/Applewin.h index 7454709d..a66b413a 100644 --- a/AppleWin/source/Applewin.h +++ b/AppleWin/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/AppleWin/source/CPU.cpp b/AppleWin/source/CPU.cpp index 8735bde4..3e173896 100644 --- a/AppleWin/source/CPU.cpp +++ b/AppleWin/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/AppleWin/source/CPU.h b/AppleWin/source/CPU.h index e6f3303c..311ed24b 100644 --- a/AppleWin/source/CPU.h +++ b/AppleWin/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/AppleWin/source/Common.h b/AppleWin/source/Common.h index ec5774a8..cd63a235 100644 --- a/AppleWin/source/Common.h +++ b/AppleWin/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/AppleWin/source/Frame.cpp b/AppleWin/source/Frame.cpp index 61f8700c..ff87958b 100644 --- a/AppleWin/source/Frame.cpp +++ b/AppleWin/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/AppleWin/source/Frame.h b/AppleWin/source/Frame.h index f32e6a14..a4082b04 100644 --- a/AppleWin/source/Frame.h +++ b/AppleWin/source/Frame.h @@ -25,3 +25,5 @@ LRESULT CALLBACK FrameWndProc ( UINT message, WPARAM wparam, LPARAM lparam ); + +extern bool g_bScrollLock_FullSpeed; diff --git a/AppleWin/source/Harddisk.cpp b/AppleWin/source/Harddisk.cpp index 616c2d51..a0ee19f6 100644 --- a/AppleWin/source/Harddisk.cpp +++ b/AppleWin/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/AppleWin/source/Joystick.cpp b/AppleWin/source/Joystick.cpp index 90c2eeea..0647e36b 100644 --- a/AppleWin/source/Joystick.cpp +++ b/AppleWin/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/AppleWin/source/Joystick.h b/AppleWin/source/Joystick.h index 79b92832..3127d07c 100644 --- a/AppleWin/source/Joystick.h +++ b/AppleWin/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/AppleWin/source/Memory.cpp b/AppleWin/source/Memory.cpp index 1fef3817..db84f860 100644 --- a/AppleWin/source/Memory.cpp +++ b/AppleWin/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/AppleWin/source/Memory.h b/AppleWin/source/Memory.h index 892eb1f3..59156ba0 100644 --- a/AppleWin/source/Memory.h +++ b/AppleWin/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/AppleWin/source/Mockingboard.cpp b/AppleWin/source/Mockingboard.cpp index 58f918e1..80105dfc 100644 --- a/AppleWin/source/Mockingboard.cpp +++ b/AppleWin/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/AppleWin/source/MouseInterface.h b/AppleWin/source/MouseInterface.h new file mode 100644 index 00000000..43995156 --- /dev/null +++ b/AppleWin/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/AppleWin/source/PropertySheetPage.cpp b/AppleWin/source/PropertySheetPage.cpp index bcb90452..ccf170ff 100644 --- a/AppleWin/source/PropertySheetPage.cpp +++ b/AppleWin/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/AppleWin/source/PropertySheetPage.h b/AppleWin/source/PropertySheetPage.h index a7abfd71..ab32beca 100644 --- a/AppleWin/source/PropertySheetPage.h +++ b/AppleWin/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/AppleWin/source/SerialComms.cpp b/AppleWin/source/SerialComms.cpp index 74517cae..ff9985dc 100644 --- a/AppleWin/source/SerialComms.cpp +++ b/AppleWin/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/AppleWin/source/SerialComms.h b/AppleWin/source/SerialComms.h index 44aefda9..9b6df460 100644 --- a/AppleWin/source/SerialComms.h +++ b/AppleWin/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/AppleWin/source/Speaker.cpp b/AppleWin/source/Speaker.cpp index adbf9654..5301f092 100644 --- a/AppleWin/source/Speaker.cpp +++ b/AppleWin/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/AppleWin/source/Structs.h b/AppleWin/source/Structs.h index 50129101..57c21c25 100644 --- a/AppleWin/source/Structs.h +++ b/AppleWin/source/Structs.h @@ -147,6 +147,7 @@ enum SS_CARDTYPE CT_GenericPrinter, CT_GenericHDD, // Hard disk CT_GenericClock, + CT_MouseInterface, }; ///////////////////////////////////////////////////////////////////////////////// diff --git a/AppleWin/source/Video.cpp b/AppleWin/source/Video.cpp index a7431af8..ba19677a 100644 --- a/AppleWin/source/Video.cpp +++ b/AppleWin/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/AppleWin/source/Video.h b/AppleWin/source/Video.h index 5c563a24..02893978 100644 --- a/AppleWin/source/Video.h +++ b/AppleWin/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();