diff --git a/AppleWin/source/CPU.cpp b/AppleWin/source/CPU.cpp index cf0755c9..02148503 100644 --- a/AppleWin/source/CPU.cpp +++ b/AppleWin/source/CPU.cpp @@ -415,7 +415,8 @@ void CpuDestroy () //=========================================================================== // Description: -// Call this when an IO-reg is access & accurate cycle info is needed +// Call this when an IO-reg is accessed & accurate cycle info is needed +// NB. Safe to call multiple times from the same IO function handler (as 'nExecutedCycles - g_nCyclesExecuted' will be zero the 2nd time) // Pre: // nExecutedCycles = # of cycles executed by Cpu6502() or Cpu65C02() for this iteration of ContinueExecution() // Post: diff --git a/AppleWin/source/Common.h b/AppleWin/source/Common.h index ae136499..cd5a36f8 100644 --- a/AppleWin/source/Common.h +++ b/AppleWin/source/Common.h @@ -139,6 +139,7 @@ enum AppMode_e #define WM_USER_BOOT WM_USER+8 #define WM_USER_FULLSCREEN WM_USER+9 +// TODO-TC: Refactor codebase by renaming /nCyclesLeft/ to /uExecutedCycles/ typedef BYTE (__stdcall *iofunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE nWriteValue, ULONG nCyclesLeft); typedef struct _IMAGE__ { int unused; } *HIMAGE; // DiskImage's /ImageInfo/ is hidden behind HIMAGE diff --git a/AppleWin/source/Joystick.cpp b/AppleWin/source/Joystick.cpp index e0716abb..b2da2659 100644 --- a/AppleWin/source/Joystick.cpp +++ b/AppleWin/source/Joystick.cpp @@ -99,6 +99,12 @@ static unsigned __int64 g_nJoyCntrResetCycle = 0; // Abs cycle that joystick cou static short g_nPdlTrimX = 0; static short g_nPdlTrimY = 0; +enum {JOYPORT_LEFTRIGHT=0, JOYPORT_UPDOWN=1}; + +static UINT g_bJoyportEnabled = 0; // Set to use Joyport to drive the 3 button inputs +static UINT g_uJoyportActiveStick = 0; +static UINT g_uJoyportReadMode = JOYPORT_LEFTRIGHT; + //=========================================================================== void CheckJoystick0() { @@ -425,7 +431,58 @@ static void DoAutofire(UINT uButton, BOOL& pressed) lastPressed[uButton] = nowPressed; } -BYTE __stdcall JoyReadButton(WORD, WORD address, BYTE, BYTE, ULONG nCyclesLeft) +BYTE __stdcall JoyportReadButton(WORD address, ULONG nCyclesLeft) +{ + BOOL pressed = 0; + + if (g_uJoyportActiveStick == 0) + { + switch (address) + { + case 0x61: + pressed = (buttonlatch[0] || joybutton[0] || setbutton[0] /*|| keydown[JK_OPENAPPLE]*/); + if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) // BUG? joytype[1] should be [0] ? + pressed = (pressed || keydown[JK_BUTTON0]); + buttonlatch[0] = 0; + break; + + case 0x62: // Left or Up + if (g_uJoyportReadMode == JOYPORT_LEFTRIGHT) // LEFT + { + if (xpos[0] == 0) // TODO: More range for mouse control? + pressed = 1; + } + else // UP + { + if (ypos[0] == 0) // TODO: More range for mouse control? + pressed = 1; + } + break; + + case 0x63: // Right or Down + if (g_uJoyportReadMode == JOYPORT_LEFTRIGHT) // RIGHT + { + if (xpos[0] >= 255) // TODO: More range for mouse control? + pressed = 1; + } + else // DOWN + { + if (ypos[0] >= 255) // TODO: More range for mouse control? + pressed = 1; + } + break; + } + } + else // TODO: stick #1 + { + } + + pressed = pressed ? 0 : 1; // Invert as Joyport signals are active low + + return MemReadFloatingBus(pressed, nCyclesLeft); +} + +BYTE __stdcall JoyReadButton(WORD pc, WORD address, BYTE, BYTE, ULONG nCyclesLeft) { address &= 0xFF; @@ -434,12 +491,19 @@ BYTE __stdcall JoyReadButton(WORD, WORD address, BYTE, BYTE, ULONG nCyclesLeft) if(joyinfo[joytype[1]] == DEVICE_JOYSTICK) CheckJoystick1(); + if (g_bJoyportEnabled) + { + // Some extra logic to stop the Joyport forcing a self-test at CTRL+RESET + if ((address != 0x62) || (address == 0x62 && pc != 0xC242 && pc != 0xC2BE)) // Original //e ($C242), Enhanced //e ($C2BE) + return JoyportReadButton(address, nCyclesLeft); + } + BOOL pressed = 0; switch (address) { case 0x61: pressed = (buttonlatch[0] || joybutton[0] || setbutton[0] || keydown[JK_OPENAPPLE]); - if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) + if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) // BUG? joytype[1] should be [0] ? pressed = (pressed || keydown[JK_BUTTON0]); buttonlatch[0] = 0; DoAutofire(0, pressed); @@ -705,6 +769,49 @@ short JoyGetTrim(bool bAxisX) //=========================================================================== +// Joyport truth-table: +// +// AN0 AN1 /PB0 /PB1 /PB2 +// ------------------------------------ +// 0 0 Trigger-1 Left-1 Right-1 +// 0 1 Trigger-1 Up-1 Down-1 +// 1 0 Trigger-2 Left-2 Right-2 +// 1 1 Trigger-2 Up-2 Down-2 + +#if 0 +void JoyportEnable(const bool bEnable) +{ + if (IS_APPLE2C) + g_bJoyportEnabled = false; + else + g_bJoyportEnabled = bEnable ? 1 : 0; +} +#endif + +void JoyportControl(const UINT uControl) +{ + if (!g_bJoyportEnabled) + return; + + switch (uControl) + { + case 0: // AN0 clr + g_uJoyportActiveStick = 0; + break; + case 1: // AN0 set + g_uJoyportActiveStick = 1; + break; + case 2: // AN1 clr + g_uJoyportReadMode = JOYPORT_LEFTRIGHT; + break; + case 3: // AN1 set + g_uJoyportReadMode = JOYPORT_UPDOWN; + break; + } +} + +//=========================================================================== + DWORD JoyGetSnapshot(SS_IO_Joystick* pSS) { pSS->g_nJoyCntrResetCycle = g_nJoyCntrResetCycle; diff --git a/AppleWin/source/Joystick.h b/AppleWin/source/Joystick.h index c4d42477..32cfeb72 100644 --- a/AppleWin/source/Joystick.h +++ b/AppleWin/source/Joystick.h @@ -23,6 +23,7 @@ BOOL JoyUsingKeyboardNumpad(); void JoyDisableUsingMouse(); void JoySetTrim(short nValue, bool bAxisX); short JoyGetTrim(bool bAxisX); +void JoyportControl(const UINT uControl); DWORD JoyGetSnapshot(SS_IO_Joystick* pSS); DWORD JoySetSnapshot(SS_IO_Joystick* pSS); diff --git a/AppleWin/source/Memory.cpp b/AppleWin/source/Memory.cpp index 22f31799..50d99d96 100644 --- a/AppleWin/source/Memory.cpp +++ b/AppleWin/source/Memory.cpp @@ -488,6 +488,12 @@ BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYT // . PC=C2B5: LDA $C05D (CLRAN2) // NB. AN3: For //e & //c these locations are now used to enabled/disabled DHIRES + + if (address >= 0xC058 && address <= 0xC05B) + { + JoyportControl(address & 0x3); // AN0 and AN1 control + } + if (!write) return MemReadFloatingBus(nCyclesLeft); else @@ -1467,10 +1473,46 @@ BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles) //} //=========================================================================== + +//#define DEBUG_FLIP_TIMINGS + +#if defined(_DEBUG) && defined(DEBUG_FLIP_TIMINGS) +static void DebugFlip(WORD address, ULONG nCyclesLeft) +{ + static unsigned __int64 uLastFlipCycle = 0; + static unsigned int uLastPage = -1; + + if (address != 0x54 && address != 0x55) + return; + + const unsigned int uNewPage = address & 1; + if (uLastPage == uNewPage) + return; + uLastPage = uNewPage; + + CpuCalcCycles(nCyclesLeft); // Update g_nCumulativeCycles + + const unsigned int uCyclesBetweenFlips = (unsigned int) (uLastFlipCycle ? g_nCumulativeCycles - uLastFlipCycle : 0); + uLastFlipCycle = g_nCumulativeCycles; + + if (!uCyclesBetweenFlips) + return; // 1st time in func + + const double fFreq = CLK_6502 / (double)uCyclesBetweenFlips; + + char szStr[100]; + sprintf(szStr, "Cycles between flips = %d (%f Hz)\n", uCyclesBetweenFlips, fFreq); + OutputDebugString(szStr); +} +#endif + BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft) { address &= 0xFF; DWORD lastmemmode = memmode; +#if defined(_DEBUG) && defined(DEBUG_FLIP_TIMINGS) + DebugFlip(address, nCyclesLeft); +#endif // DETERMINE THE NEW MEMORY PAGING MODE. if ((address >= 0x80) && (address <= 0x8F))