From 52e7d61c7efaff92f8ba27b67cbec4978974dcf3 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 22 Apr 2018 14:37:59 +0100 Subject: [PATCH 001/128] SSC: . DCD state is now a mirror of DSR unless -dcd switch is used. (Fixes #553) . Removed -dsr,-dtr switches, so -modem is now an alias for -dcd. (Also for #553) . Wait for events (RLSD,DSR,CTS) in CommThread and call GetCommModemStatus() in CommThread. --- source/Applewin.cpp | 16 +-------- source/SerialComms.cpp | 80 ++++++++++++++++-------------------------- source/SerialComms.h | 9 ++--- 3 files changed, 34 insertions(+), 71 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 37909826..7505d533 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1210,24 +1210,10 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { g_bMultiMon = true; } - else if (strcmp(lpCmdLine, "-dcd") == 0) // GH#386 + else if ((strcmp(lpCmdLine, "-dcd") == 0) || (strcmp(lpCmdLine, "-modem") == 0)) // GH#386 { sg_SSC.SupportDCD(true); } - else if (strcmp(lpCmdLine, "-dsr") == 0) // GH#386 - { - sg_SSC.SupportDSR(true); - } - else if (strcmp(lpCmdLine, "-dtr") == 0) // GH#386 - { - sg_SSC.SupportDTR(true); - } - else if (strcmp(lpCmdLine, "-modem") == 0) // GH#386 - { - sg_SSC.SupportDCD(true); - sg_SSC.SupportDSR(true); - sg_SSC.SupportDTR(true); - } else // unsupported { LogFileOutput("Unsupported arg: %s\n", lpCmdLine); diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp index 0964ba9a..7cde6fca 100644 --- a/source/SerialComms.cpp +++ b/source/SerialComms.cpp @@ -68,9 +68,7 @@ CSuperSerialCard::CSuperSerialCard() : m_aySerialPortChoices(NULL), m_uTCPChoiceItemIdx(0), m_uSlot(0), - m_bCfgSupportDCD(false), - m_bCfgSupportDSR(false), - m_bCfgSupportDTR(false) + m_bCfgSupportDCD(false) { memset(m_ayCurrentSerialPortName, 0, sizeof(m_ayCurrentSerialPortName)); m_dwSerialPortItem = 0; @@ -119,6 +117,7 @@ void CSuperSerialCard::InternalReset() m_uDTR = DTR_CONTROL_DISABLE; m_uRTS = RTS_CONTROL_DISABLE; + m_dwModemStatus = m_kDefaultModemStatus; } CSuperSerialCard::~CSuperSerialCard() @@ -524,11 +523,8 @@ void CSuperSerialCard::UpdateCommandReg(BYTE command) m_bRxIrqEnabled = false; } - if (m_bCfgSupportDTR) // GH#386 - { - // Data Terminal Ready (DTR) setting (0=set DTR high (indicates 'not ready')) - m_uDTR = (m_uCommandByte & CMD_DTR) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE; - } + // Data Terminal Ready (DTR) setting (0=set DTR high (indicates 'not ready')) (GH#386) + m_uDTR = (m_uCommandByte & CMD_DTR) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE; } BYTE __stdcall CSuperSerialCard::CommCommand(WORD, WORD, BYTE write, BYTE value, ULONG) @@ -754,29 +750,21 @@ BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG) if (!CheckComm()) return ST_DSR | ST_DCD | ST_TX_EMPTY; - static DWORD modemStatus = 0; - if (m_bCfgSupportDCD || m_bCfgSupportDSR) + DWORD modemStatus = m_kDefaultModemStatus; + if (m_hCommHandle != INVALID_HANDLE_VALUE) { - if (m_hCommHandle != INVALID_HANDLE_VALUE) + modemStatus = m_dwModemStatus; // Take a copy of this volatile variable + if (!m_bCfgSupportDCD) // Default: DSR state is mirrored to DCD (GH#553) { - // Call GetCommModemStatus() outside of the critical section. For Win7-64: takes 1-2msecs! - static DWORD dwLastTimeGettingModemStatus = 0; - DWORD dwCurrTime = GetTickCount(); - if (dwCurrTime - dwLastTimeGettingModemStatus > 8) // Limit reading status to twice a 16.6ms video frame (arbitrary throttle limit) - { - // Only permit periodic reading, otherwise a tight 6502 polling loop can kill emulator performance! - GetCommModemStatus(m_hCommHandle, &modemStatus); // Returns 0x30 = MS_DSR_ON|MS_CTS_ON - dwLastTimeGettingModemStatus = dwCurrTime; - } - } - else if (m_hCommListenSocket != INVALID_SOCKET) - { - if (m_hCommAcceptSocket != INVALID_SOCKET) - modemStatus = MS_RLSD_ON | MS_DSR_ON | MS_CTS_ON; - else - modemStatus = 0; + modemStatus &= ~MS_RLSD_ON; + if (modemStatus & MS_DSR_ON) + modemStatus |= MS_RLSD_ON; } } + else if (m_hCommListenSocket != INVALID_SOCKET && m_hCommAcceptSocket != INVALID_SOCKET) + { + modemStatus = MS_RLSD_ON | MS_DSR_ON | MS_CTS_ON; + } // @@ -803,17 +791,8 @@ BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG) // - BYTE DSR = 0; - BYTE DCD = 0; - - if ((m_hCommHandle != INVALID_HANDLE_VALUE) && (m_bCfgSupportDCD || m_bCfgSupportDSR)) // GH#386 - { - if (m_bCfgSupportDSR) - DSR = (modemStatus & MS_DSR_ON) ? 0x00 : ST_DSR; - - if (m_bCfgSupportDCD) - DCD = (modemStatus & MS_RLSD_ON) ? 0x00 : ST_DCD; - } + BYTE DSR = (modemStatus & MS_DSR_ON) ? 0x00 : ST_DSR; // DSR is active low (see SY6551 datasheet) (GH#386) + BYTE DCD = (modemStatus & MS_RLSD_ON) ? 0x00 : ST_DCD; // DCD is active low (see SY6551 datasheet) (GH#386) // @@ -825,7 +804,7 @@ BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG) BYTE uStatus = IRQ | DSR - | DCD // Need 0x00 (ie. DCD is active) to allow ZLink to start up + | DCD | TX_EMPTY | RX_FULL; @@ -882,17 +861,11 @@ BYTE __stdcall CSuperSerialCard::CommDipSw(WORD, WORD addr, BYTE, BYTE, ULONG) BYTE SW2_5 = m_DIPSWCurrent.bLinefeed ? 0 : 1; // SW2-5 (LF: yes-ON(0); no-OFF(1)) - BYTE CTS = 0; // GH#311 + BYTE CTS = 1; // Default to CTS being false. (Support CTS in DIPSW: GH#311) if (CheckComm() && m_hCommHandle != INVALID_HANDLE_VALUE) - { - DWORD modemStatus = 0; - if (GetCommModemStatus(m_hCommHandle, &modemStatus)) - CTS = (modemStatus & MS_CTS_ON) ? 0 : 1; // CTS is true when 0 - } + CTS = (m_dwModemStatus & MS_CTS_ON) ? 0 : 1; // CTS active low (see SY6551 datasheet) else if (m_hCommListenSocket != INVALID_SOCKET) - { CTS = (m_hCommAcceptSocket != INVALID_SOCKET) ? 0 : 1; - } // SSC-54: sw = SW2_1<<7 | // b7 : SW2-1 @@ -1070,10 +1043,18 @@ void CSuperSerialCard::CheckCommEvent(DWORD dwEvtMask) LeaveCriticalSection(&m_CriticalSection); } } - else if (dwEvtMask & EV_TXEMPTY) + + if (dwEvtMask & EV_TXEMPTY) { TransmitDone(); } + + if (dwEvtMask & (EV_RLSD|EV_DSR|EV_CTS)) + { + // For Win7-64: takes 1-2msecs! + // Don't read from main emulation thread, otherwise a tight 6502 polling loop can kill emulator performance! + GetCommModemStatus(m_hCommHandle, const_cast(&m_dwModemStatus)); + } } DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter) @@ -1081,8 +1062,7 @@ DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter) CSuperSerialCard* pSSC = (CSuperSerialCard*) lpParameter; char szDbg[100]; - BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_TXEMPTY | EV_RXCHAR); -// BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_RXCHAR); // Just RX + BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_RLSD | EV_DSR | EV_CTS | EV_TXEMPTY | EV_RXCHAR); if (!bRes) { sprintf(szDbg, "SSC: CommThread(): SetCommMask() failed\n"); diff --git a/source/SerialComms.h b/source/SerialComms.h index cfc393ca..89231dfa 100644 --- a/source/SerialComms.h +++ b/source/SerialComms.h @@ -43,8 +43,6 @@ public: void SetSerialPortName(const char* pSerialPortName); bool IsActive() { return (m_hCommHandle != INVALID_HANDLE_VALUE) || (m_hCommListenSocket != INVALID_SOCKET); } void SupportDCD(bool bEnable) { m_bCfgSupportDCD = bEnable; } // Status - void SupportDSR(bool bEnable) { m_bCfgSupportDSR = bEnable; } // Status - void SupportDTR(bool bEnable) { m_bCfgSupportDTR = bEnable; } // Control void CommTcpSerialAccept(); void CommTcpSerialReceive(); @@ -139,12 +137,11 @@ private: BYTE* m_pExpansionRom; UINT m_uSlot; - // Modem bool m_bCfgSupportDCD; - bool m_bCfgSupportDSR; - bool m_bCfgSupportDTR; UINT m_uDTR; - // Modem (end) + + static const DWORD m_kDefaultModemStatus = 0; // MS_RLSD_OFF(=DCD_OFF), MS_DSR_OFF, MS_CTS_OFF + volatile DWORD m_dwModemStatus; // Updated by CommThread when any of RLSD|DSR|CTS changes / Read by main thread - CommStatus()& CommDipSw() UINT m_uRTS; }; From a7a4ee28ccab46c0d1e9e4bc058aed0972740f0a Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 22 Apr 2018 15:16:51 +0100 Subject: [PATCH 002/128] Help: Added a new help page about AppleWin's SSC emulation. (Fixes #554) --- help/Table of Contents.hhc | 6 ++- help/card-ssc.html | 81 ++++++++++++++++++++++++++++++++++++++ help/cfg-config.html | 10 +---- help/toc.html | 1 + 4 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 help/card-ssc.html diff --git a/help/Table of Contents.hhc b/help/Table of Contents.hhc index 00c06e4e..552359e1 100644 --- a/help/Table of Contents.hhc +++ b/help/Table of Contents.hhc @@ -84,7 +84,11 @@
  • - + + +
  • + +
  • diff --git a/help/card-ssc.html b/help/card-ssc.html new file mode 100644 index 00000000..b55a7325 --- /dev/null +++ b/help/card-ssc.html @@ -0,0 +1,81 @@ + + + + Super Serial Card + + + +

    Super Serial Card

    +
    +

    Super Serial Card:

    +

    AppleWin emulates a Super Serial Card (aka SSC) in slot-2, with the jumper block in the MODEM position.

    +

    The SSC can be configured to communicate externally either via the host PC's COM serial port or TCP port 1977.

    + +

    See the Configuration tab's 'Serial Port' menu to select a COM serial port or the TCP port.

    + +

    The SSC currently has these hardcoded DIP switch settings:

    +
      +
    • DIP SW1: +
        +
      • Baud rate = 19200 +
      • Mode = CIC (ie. SSC) +
      +
    • DIP SW2: +
        +
      • 1 stop-bit +
      • 8-bit byte size +
      • No parity +
      • Linefeed off +
      • Interrupts enabled +
      +
    + +

    Notes:

    +
      +
    • The SSC emulation supports both Rx and Tx interrupts, RTS/CTS, DSR/DTR, and the undocumented 115200 baud rate. +
    • The TCP mode can expose buggy Rx interrupt handling code where the 6551's Status register is read more than once in the Interrupt Service Routine (ISR). +
        +
      • Details: TCP mode doesn't throttle the serial data rate, so after reading the Status register (to clear the Rx interrupt) the Rx interrupt may get asserted immediately if there is more data in the TCP receive buffer, resulting in a missed interrupt (and therefore missed Rx data). +
      +
    • The 6551's Command register's DSR (bit0) must be set, to enable interrupts (Rx, Tx) along with the respective Rx and/or Tx bits (bit3:1). This is part of the 6551 specification, but (DSR bit) has only been enforced by AppleWin since 1.27.4. +
    + +

    Unsupported features are:

    +
      +
    • Configuring the DIP switches (not a problem, since most functions can be set in software). +
    • 6551 ACIA Command register: Echo mode(bit4=1) and Transmit BRK (bit3:2=3). +
    • 6551 ACIA Control register: external clock (bit4=0). +
    • 6551 ACIA baud rates: 50, 75, 109.92, 134.58, 150 all map to 110 baud. +
    • 6551 ACIA baud rate: 1800 maps to 2400 baud. +
    • 6551 ACIA baud rate: 3600 maps to 4800 baud. +
    • 6551 ACIA baud rate: 7200 maps to 9600 baud. +
    • 6551 ACIA Status register's error bits: overrun, framing and parity (these are all hardcoded to 0). +
    • 6551 ACIA Status register's DCD bit (Data Carrier Detect). This is just set the same as DSR. +
        +
      • NB. Use command line -dcd to force AppleWin to use the state of the MS_RLSD_ON bit from GetCommModemStatus(). +
      +
    • NMOS 6551 ACIA CTS bug: transmission of an already-started frame will stop immediately when CTS is taken false, the byte will be lost, and the TxD line will go to marking. +
        +
      • NB. The CMOS 6551's will finish the frame, so assume that AppleWin emulates a CMOS 6551. +
      +
    • AppleWin's 6502/65C02 emulation doesn't emulate the false read for STA $C088,X (where X=$20). +
        +
      • Don't do this to write to the 6551's Transmit register. +
      • On AppleWin this is fine, but on real hardware (in full duplex mode) you may falsely read (and clear) the 6551's Receive register. +
      • Instead (like the SSC's firmware) do this: STA $BFFF,Y (where Y=$A9). +
      +
    +
    +
    + +

    Using TCP mode with the Apple // Game Server:

    + The TCP interface to the SSC can be used by the Apple // Game Server (AGS).
    + For details see the notes that comes with AGS, but in summary:
    +
      +
    • Boot the Apple II to AppleSoft (ie. power on and hit Ctrl-Reset) and type IN#2. +
    • From a Windows DOS box, start AGS with "localhost 1977 apple2e". This will boot the emulated Apple II from AGS. +
    • Nb. Only Enhanced Apple //e is working at the moment. +
    + + diff --git a/help/cfg-config.html b/help/cfg-config.html index c19eb595..e8e027cf 100644 --- a/help/cfg-config.html +++ b/help/cfg-config.html @@ -55,14 +55,8 @@
    Serial Port:
    - This option will remap the emulated Apple's serial port to your PC's - serial port (or TCP port 1977). The Apple Super Serial Card (SSC) is emulated in slot-2.
    - The TCP interface to the Apple SSC can be used by the Apple // Game Server. - For details see the notes that comes with AGS:
    -
  • Boot the Apple II to AppleSoft (ie. power on and hit Ctrl-Reset) and type IN#2. -
  • From a Windows DOS box, start AGS with "localhost 1977 apple2e". This will boot the emulated Apple II from AGS. -
  • Nb. Only Enhanced Apple //e is working at the moment. -
    + This option will remap the emulated Apple's serial port to your PC's serial port (or TCP port 1977).
    + See Super Serial Card for more details.

    Ethernet Settings...:
    diff --git a/help/toc.html b/help/toc.html index d5094673..2645c74b 100644 --- a/help/toc.html +++ b/help/toc.html @@ -30,6 +30,7 @@
  • Save-state Files
  • Sound
  • Clock +
  • Super Serial card
  • Uthernet network card
  • Command line
  • AppleWin Configuration From 54d159c0444e649b611674fc0aa91e5e47ec37cd Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 22 Apr 2018 15:22:05 +0100 Subject: [PATCH 003/128] Help: Updated command-line to only describe -dcd (ie. removed -dsr, -dtr switches). --- help/CommandLine.html | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/help/CommandLine.html b/help/CommandLine.html index 700a528e..106d71c6 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -63,15 +63,11 @@ i.e. 00:20 20 20 20 ... for page $20
  • -modem
    - Shorthand for passing -dtr -dcd -dsr
    + Shorthand for passing -dcd
    Use with GBBS Pro (or any other BBS package). See the GBBS Pro 2.2 book from Call-A.P.P.L.E.

    - -dtr
    - Support SSC's DTR (Data Terminal Ready) control bit

    -dcd
    - Support SSC's DCD (Data Carrier Detect) status bit

    - -dtr
    - Support SSC's DSR (Data Set Ready) status bit

    + For the SSC's 6551's Status register's DCD bit, use this switch to force AppleWin to use the state of the MS_RLSD_ON bit from GetCommModemStatus().



    From ba090ebcef1828db12851f07c76ab36fc161dfa7 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 23 Apr 2018 21:34:09 +0100 Subject: [PATCH 004/128] SSC: Change DIPSW1's baud rate to 9600 (was 19200) & reflect this change in the help doc for SSC --- help/card-ssc.html | 15 ++++++++++----- source/SerialComms.cpp | 6 +++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/help/card-ssc.html b/help/card-ssc.html index b55a7325..4c6ee7a8 100644 --- a/help/card-ssc.html +++ b/help/card-ssc.html @@ -18,8 +18,8 @@
    • DIP SW1:
        -
      • Baud rate = 19200 -
      • Mode = CIC (ie. SSC) +
      • Baud rate = 9600 +
      • Mode = CIC (ie. SSC's Communication Mode)
    • DIP SW2:
        @@ -33,17 +33,22 @@

        Notes:

          -
        • The SSC emulation supports both Rx and Tx interrupts, RTS/CTS, DSR/DTR, and the undocumented 115200 baud rate. +
        • The SSC emulation supports both Rx and Tx interrupts (for both COM and TCP modes), RTS/CTS, DSR/DTR, and the undocumented 115200 baud rate. +
        • For the TCP mode it doesn't matter what baud rate, stop-bit, byte size and parity are set to. +
            +
          • It always uses an unthrottled data-rate of 8-bit bytes (no stop-bit, no parity). +
          • When there's an active TCP connection, then the 6551's Status register has DCD,DSR bits clear (active low), and DIPSW2 has CTS bit clear (active low). When there's no TCP connection, then all these bits are set (inactive). +
        • The TCP mode can expose buggy Rx interrupt handling code where the 6551's Status register is read more than once in the Interrupt Service Routine (ISR).
            -
          • Details: TCP mode doesn't throttle the serial data rate, so after reading the Status register (to clear the Rx interrupt) the Rx interrupt may get asserted immediately if there is more data in the TCP receive buffer, resulting in a missed interrupt (and therefore missed Rx data). +
          • Details: TCP mode doesn't throttle the serial data-rate, so after reading the Status register (to clear the Rx interrupt) the Rx interrupt may get asserted immediately if there is more data in the TCP receive buffer, resulting in a missed interrupt (and therefore missed Rx data).
        • The 6551's Command register's DSR (bit0) must be set, to enable interrupts (Rx, Tx) along with the respective Rx and/or Tx bits (bit3:1). This is part of the 6551 specification, but (DSR bit) has only been enforced by AppleWin since 1.27.4.

        Unsupported features are:

          -
        • Configuring the DIP switches (not a problem, since most functions can be set in software). +
        • Can't configure the DIP switches (not a problem, since most functions can be set in software).
        • 6551 ACIA Command register: Echo mode(bit4=1) and Transmit BRK (bit3:2=3).
        • 6551 ACIA Control register: external clock (bit4=0).
        • 6551 ACIA baud rates: 50, 75, 109.92, 134.58, 150 all map to 110 baud. diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp index 7cde6fca..241eb2a8 100644 --- a/source/SerialComms.cpp +++ b/source/SerialComms.cpp @@ -47,11 +47,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define TCP_SERIAL_PORT 1977 -// Default: 19200-8-N-1 +// Default: 9600-8-N-1 SSC_DIPSW CSuperSerialCard::m_DIPSWDefault = { // DIPSW1: - CBR_19200, + CBR_9600, // Use 9600, as a 1MHz Apple II can only handle up to 9600 bps [Ref.1] FWMODE_CIC, // DIPSW2: @@ -559,7 +559,7 @@ BYTE __stdcall CSuperSerialCard::CommControl(WORD, WORD, BYTE write, BYTE value, // Plus running in "fast" mode) cannot handle 19.2 kbps, and even 9600 // bps on these machines requires either some highly optimised code or // a decent buffer in the device being accessed. The faster Apples - // have no difficulty with this speed, however. + // have no difficulty with this speed, however. [Ref.1] case 0x00: m_uBaudRate = CBR_115200; break; // Internal clk: undoc'd 115.2K (or 16x external clock) case 0x01: // fall through [50 bps] From 2fdc270837a8f59304123e6069e89a5995e721d6 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 5 May 2018 16:56:15 +0100 Subject: [PATCH 005/128] SSC: Make default baud-rate consistent (9600) --- source/SerialComms.cpp | 4 ++-- source/SerialComms.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp index 241eb2a8..b67ab756 100644 --- a/source/SerialComms.cpp +++ b/source/SerialComms.cpp @@ -98,7 +98,7 @@ void CSuperSerialCard::InternalReset() // . NB. MOS6551 datasheet: Hardware reset: b#00000010 (so ACIA not init'd on IN#2!) UpdateCommandReg(0); - m_uBaudRate = CBR_19200; // Undefined, as CONTROL.CLK_SOURCE=0=External clock is not supported for SSC - so nominally use 19200 + m_uBaudRate = m_kDefaultBaudRate; // Undefined, as CONTROL.CLK_SOURCE=0=External clock is not supported for SSC - so nominally AppleWin default m_uStopBits = ONESTOPBIT; m_uByteSize = 8; m_uParity = NOPARITY; @@ -171,7 +171,7 @@ UINT CSuperSerialCard::BaudRateToIndex(UINT uBaudRate) _ASSERT(0); LogFileOutput("SSC: BaudRateToIndex(): unsupported rate: %d\n", uBaudRate); - return BaudRateToIndex(CBR_19200); // nominally use 19200 + return BaudRateToIndex(m_kDefaultBaudRate); // nominally use AppleWin default } //=========================================================================== diff --git a/source/SerialComms.h b/source/SerialComms.h index 89231dfa..3d38fd96 100644 --- a/source/SerialComms.h +++ b/source/SerialComms.h @@ -96,6 +96,7 @@ private: static SSC_DIPSW m_DIPSWDefault; SSC_DIPSW m_DIPSWCurrent; + static const UINT m_kDefaultBaudRate = CBR_9600; UINT m_uBaudRate; UINT m_uStopBits; UINT m_uByteSize; From 7beaf610d239ee6bea4e6ee1cfe39e5f9796f6a3 Mon Sep 17 00:00:00 2001 From: tomcw Date: Thu, 10 May 2018 13:47:26 +0100 Subject: [PATCH 006/128] SSC: . Save-state: SSC unit v2 - support DCD flag, removed redundant vars --- source/SerialComms.cpp | 208 ++++++++++++++++++++++------------------- source/SerialComms.h | 2 + 2 files changed, 113 insertions(+), 97 deletions(-) diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp index b67ab756..77302924 100644 --- a/source/SerialComms.cpp +++ b/source/SerialComms.cpp @@ -91,26 +91,18 @@ void CSuperSerialCard::InternalReset() { GetDIPSW(); - // SY6551 datasheet: Hardware reset sets Control register to 0 - the DIPSW settings are not used by h/w to setup this register - m_uControlByte = 0; - // SY6551 datasheet: Hardware reset sets Command register to 0 // . NB. MOS6551 datasheet: Hardware reset: b#00000010 (so ACIA not init'd on IN#2!) - UpdateCommandReg(0); - - m_uBaudRate = m_kDefaultBaudRate; // Undefined, as CONTROL.CLK_SOURCE=0=External clock is not supported for SSC - so nominally AppleWin default - m_uStopBits = ONESTOPBIT; - m_uByteSize = 8; - m_uParity = NOPARITY; + // SY6551 datasheet: Hardware reset sets Control register to 0 - the DIPSW settings are not used by h/w to setup this register + UpdateCommandAndControlRegs(0, 0); // Baud=External clock! 8-N-1 // - m_vuRxCurrBuffer = 0; - m_vbTxIrqPending = false; m_vbRxIrqPending = false; m_vbTxEmpty = true; + m_vuRxCurrBuffer = 0; m_qComSerialBuffer[0].clear(); m_qComSerialBuffer[1].clear(); m_qTcpSerialBuffer.clear(); @@ -468,6 +460,13 @@ BYTE __stdcall CSuperSerialCard::CommProgramReset(WORD, WORD, BYTE, BYTE, ULONG) //=========================================================================== +void CSuperSerialCard::UpdateCommandAndControlRegs(BYTE uCommandByte, BYTE uControlByte) +{ + // UpdateCommandReg() first to initialise m_uParity, before calling UpdateControlReg() + UpdateCommandReg(uCommandByte); + UpdateControlReg(uControlByte); +} + void CSuperSerialCard::UpdateCommandReg(BYTE command) { m_uCommandByte = command; @@ -514,6 +513,10 @@ void CSuperSerialCard::UpdateCommandReg(BYTE command) if (m_DIPSWCurrent.bInterrupts && m_uCommandByte & CMD_DTR) { + // Assume enabling Rx IRQ if STATUS.ST_RX_FULL *does not* trigger an IRQ + // . EG. Disable Rx IRQ, receive a byte (don't read STATUS or RX_DATA register), enable Rx IRQ + // Assume enabling Tx IRQ if STATUS.ST_TX_EMPTY *does not* trigger an IRQ + // . otherwise there'd be a "false" TX Empty IRQ even if nothing had ever been transferred! m_bTxIrqEnabled = (m_uCommandByte & CMD_TX_MASK) == CMD_TX_IRQ_ENA_RTS_LOW; m_bRxIrqEnabled = (m_uCommandByte & CMD_RX_IRQ_DIS) == 0; } @@ -543,6 +546,67 @@ BYTE __stdcall CSuperSerialCard::CommCommand(WORD, WORD, BYTE write, BYTE value, //=========================================================================== +void CSuperSerialCard::UpdateControlReg(BYTE control) +{ + m_uControlByte = control; + + // UPDATE THE BAUD RATE + switch (m_uControlByte & 0x0F) + { + // Note that 1 MHz Apples (everything other than the Apple IIgs and //c + // Plus running in "fast" mode) cannot handle 19.2 kbps, and even 9600 + // bps on these machines requires either some highly optimised code or + // a decent buffer in the device being accessed. The faster Apples + // have no difficulty with this speed, however. [Ref.1] + + case 0x00: m_uBaudRate = CBR_115200; break; // Internal clk: undoc'd 115.2K (or 16x external clock) + case 0x01: // fall through [50 bps] + case 0x02: // fall through [75 bps] + case 0x03: // fall through [109.92 bps] + case 0x04: // fall through [134.58 bps] + case 0x05: m_uBaudRate = CBR_110; break; // [150 bps] + case 0x06: m_uBaudRate = CBR_300; break; + case 0x07: m_uBaudRate = CBR_600; break; + case 0x08: m_uBaudRate = CBR_1200; break; + case 0x09: // fall through [1800 bps] + case 0x0A: m_uBaudRate = CBR_2400; break; + case 0x0B: // fall through [3600 bps] + case 0x0C: m_uBaudRate = CBR_4800; break; + case 0x0D: // fall through [7200 bps] + case 0x0E: m_uBaudRate = CBR_9600; break; + case 0x0F: m_uBaudRate = CBR_19200; break; + } + + if (m_uControlByte & 0x10) + { + // receiver clock source [0= external, 1= internal] + } + + // UPDATE THE BYTE SIZE + switch (m_uControlByte & 0x60) + { + case 0x00: m_uByteSize = 8; break; + case 0x20: m_uByteSize = 7; break; + case 0x40: m_uByteSize = 6; break; + case 0x60: m_uByteSize = 5; break; + } + + // UPDATE THE NUMBER OF STOP BITS + if (m_uControlByte & 0x80) + { + if ((m_uByteSize == 8) && (m_uParity != NOPARITY)) + m_uStopBits = ONESTOPBIT; + else if ((m_uByteSize == 5) && (m_uParity == NOPARITY)) + m_uStopBits = ONE5STOPBITS; + else + m_uStopBits = TWOSTOPBITS; + } + else + { + m_uStopBits = ONESTOPBIT; + } +} + BYTE __stdcall CSuperSerialCard::CommControl(WORD, WORD, BYTE write, BYTE value, ULONG) { if (!CheckComm()) @@ -550,64 +614,7 @@ BYTE __stdcall CSuperSerialCard::CommControl(WORD, WORD, BYTE write, BYTE value, if (write && (value != m_uControlByte)) { - m_uControlByte = value; - - // UPDATE THE BAUD RATE - switch (m_uControlByte & 0x0F) - { - // Note that 1 MHz Apples (everything other than the Apple IIgs and //c - // Plus running in "fast" mode) cannot handle 19.2 kbps, and even 9600 - // bps on these machines requires either some highly optimised code or - // a decent buffer in the device being accessed. The faster Apples - // have no difficulty with this speed, however. [Ref.1] - - case 0x00: m_uBaudRate = CBR_115200; break; // Internal clk: undoc'd 115.2K (or 16x external clock) - case 0x01: // fall through [50 bps] - case 0x02: // fall through [75 bps] - case 0x03: // fall through [109.92 bps] - case 0x04: // fall through [134.58 bps] - case 0x05: m_uBaudRate = CBR_110; break; // [150 bps] - case 0x06: m_uBaudRate = CBR_300; break; - case 0x07: m_uBaudRate = CBR_600; break; - case 0x08: m_uBaudRate = CBR_1200; break; - case 0x09: // fall through [1800 bps] - case 0x0A: m_uBaudRate = CBR_2400; break; - case 0x0B: // fall through [3600 bps] - case 0x0C: m_uBaudRate = CBR_4800; break; - case 0x0D: // fall through [7200 bps] - case 0x0E: m_uBaudRate = CBR_9600; break; - case 0x0F: m_uBaudRate = CBR_19200; break; - } - - if (m_uControlByte & 0x10) - { - // receiver clock source [0= external, 1= internal] - } - - // UPDATE THE BYTE SIZE - switch (m_uControlByte & 0x60) - { - case 0x00: m_uByteSize = 8; break; - case 0x20: m_uByteSize = 7; break; - case 0x40: m_uByteSize = 6; break; - case 0x60: m_uByteSize = 5; break; - } - - // UPDATE THE NUMBER OF STOP BITS - if (m_uControlByte & 0x80) - { - if ((m_uByteSize == 8) && (m_uParity != NOPARITY)) - m_uStopBits = ONESTOPBIT; - else if ((m_uByteSize == 5) && (m_uParity == NOPARITY)) - m_uStopBits = ONE5STOPBITS; - else - m_uStopBits = TWOSTOPBITS; - } - else - { - m_uStopBits = ONESTOPBIT; - } - + UpdateControlReg(value); UpdateCommState(); } @@ -1354,20 +1361,22 @@ void CSuperSerialCard::SetSnapshot_v1( const DWORD baudrate, const BYTE parity, const BYTE stopbits) { - m_uBaudRate = baudrate; - m_uStopBits = stopbits; - m_uByteSize = bytesize; -// m_dwCommInactivity = comminactivity; // Obsolete - m_uControlByte = controlbyte; -// m_uParity = parity; // Redundant: derived from commandbyte in UpdateCommandReg() -// memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize); -// m_vRecvBytes = recvbytes; + // Redundant: + // . baudrate, stopbits, bytesize (encapsulated in controlbyte) + // . parity (encapsulated in commandbyte) + // Obsolete: + // . comminactivity - UpdateCommandReg(commandbyte); + UpdateCommandAndControlRegs(commandbyte, controlbyte); } //=========================================================================== +// Unit version history: +// 2: Added: Support DCD flag +// Removed: redundant data (encapsulated in Command & Control bytes) +static const UINT kUNIT_VERSION = 2; + #define SS_YAML_VALUE_CARD_SSC "Super Serial Card" #define SS_YAML_KEY_DIPSWDEFAULT "DIPSW Default" @@ -1389,6 +1398,7 @@ void CSuperSerialCard::SetSnapshot_v1( const DWORD baudrate, #define SS_YAML_KEY_RXIRQPENDING "RX IRQ Pending" #define SS_YAML_KEY_WRITTENTX "Written TX" #define SS_YAML_KEY_SERIALPORTNAME "Serial Port Name" +#define SS_YAML_KEY_SUPPORT_DCD "Support DCD" std::string CSuperSerialCard::GetSnapshotCardName(void) { @@ -1410,23 +1420,17 @@ void CSuperSerialCard::SaveSnapshotDIPSW(YamlSaveHelper& yamlSaveHelper, std::st void CSuperSerialCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) { - YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_uSlot, 1); + YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_uSlot, kUNIT_VERSION); YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); SaveSnapshotDIPSW(yamlSaveHelper, SS_YAML_KEY_DIPSWDEFAULT, m_DIPSWDefault); SaveSnapshotDIPSW(yamlSaveHelper, SS_YAML_KEY_DIPSWCURRENT, m_DIPSWCurrent); - yamlSaveHelper.SaveUint(SS_YAML_KEY_BAUDRATE, m_uBaudRate); - yamlSaveHelper.SaveUint(SS_YAML_KEY_STOPBITS, m_uStopBits); - yamlSaveHelper.SaveUint(SS_YAML_KEY_BYTESIZE, m_uByteSize); - yamlSaveHelper.SaveUint(SS_YAML_KEY_PARITY, m_uParity); // Redundant yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_CONTROL, m_uControlByte); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, m_uCommandByte); - yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, 0); // Obsolete - yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQENABLED, m_bTxIrqEnabled); // Redundant - yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQENABLED, m_bRxIrqEnabled); // Redundant yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQPENDING, m_vbTxIrqPending); yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQPENDING, m_vbRxIrqPending); yamlSaveHelper.SaveBool(SS_YAML_KEY_WRITTENTX, m_vbTxEmpty); + yamlSaveHelper.SaveBool(SS_YAML_KEY_SUPPORT_DCD, m_bCfgSupportDCD); yamlSaveHelper.SaveString(SS_YAML_KEY_SERIALPORTNAME, GetSerialPortName()); } @@ -1451,27 +1455,37 @@ bool CSuperSerialCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, U if (slot != 2) // fixme throw std::string("Card: wrong slot"); - if (version != 1) + if (version < 1 || version > kUNIT_VERSION) throw std::string("Card: wrong version"); LoadSnapshotDIPSW(yamlLoadHelper, SS_YAML_KEY_DIPSWDEFAULT, m_DIPSWDefault); LoadSnapshotDIPSW(yamlLoadHelper, SS_YAML_KEY_DIPSWCURRENT, m_DIPSWCurrent); - m_uBaudRate = yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE); - m_uStopBits = yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS); - m_uByteSize = yamlLoadHelper.LoadUint(SS_YAML_KEY_BYTESIZE); - yamlLoadHelper.LoadUint(SS_YAML_KEY_PARITY); // Redundant: derived from uCommandByte in UpdateCommandReg() - m_uControlByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_CONTROL); + if (version == 1) // Consume redundant/obsolete data + { + yamlLoadHelper.LoadUint(SS_YAML_KEY_PARITY); // Redundant: derived from uCommandByte in UpdateCommandReg() + yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQENABLED); // Redundant: derived from uCommandByte in UpdateCommandReg() + yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQENABLED); // Redundant: derived from uCommandByte in UpdateCommandReg() + + yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE); // Redundant: derived from uControlByte in UpdateControlReg() + yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS); // Redundant: derived from uControlByte in UpdateControlReg() + yamlLoadHelper.LoadUint(SS_YAML_KEY_BYTESIZE); // Redundant: derived from uControlByte in UpdateControlReg() + + yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); // Obsolete (so just consume) + } + else if (version >= 2) + { + SupportDCD( yamlLoadHelper.LoadBool(SS_YAML_KEY_SUPPORT_DCD) ); + } + UINT uCommandByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND); - yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); // Obsolete (so just consume) - yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQENABLED); // Redundant: derived from uCommandByte in UpdateCommandReg() - yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQENABLED); // Redundant: derived from uCommandByte in UpdateCommandReg() + UINT uControlByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_CONTROL); + UpdateCommandAndControlRegs(uCommandByte, uControlByte); + m_vbTxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQPENDING); m_vbRxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQPENDING); m_vbTxEmpty = yamlLoadHelper.LoadBool(SS_YAML_KEY_WRITTENTX); - UpdateCommandReg(uCommandByte); - std::string serialPortName = yamlLoadHelper.LoadString(SS_YAML_KEY_SERIALPORTNAME); SetSerialPortName(serialPortName.c_str()); diff --git a/source/SerialComms.h b/source/SerialComms.h index 3d38fd96..6d10bb9f 100644 --- a/source/SerialComms.h +++ b/source/SerialComms.h @@ -62,7 +62,9 @@ private: BYTE __stdcall CommProgramReset(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); void InternalReset(); + void UpdateCommandAndControlRegs(BYTE command, BYTE control); void UpdateCommandReg(BYTE command); + void UpdateControlReg(BYTE control); void GetDIPSW(); void SetDIPSWDefaults(); UINT BaudRateToIndex(UINT uBaudRate); From 3e7cc361ff3929d7c8689b2674aa1787d7e47a15 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 13 May 2018 17:33:13 +0100 Subject: [PATCH 007/128] #555: Fix for displaying colour dots & vertical lines in the far right hand column --- source/NTSC.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index b3ed5520..70578e6d 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -481,7 +481,7 @@ inline uint16_t getLoResBits( uint8_t iByte ) //=========================================================================== inline uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable ) { - g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; // 14-bit + g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; // 12-bit return *(uint32_t*) &pTable[ g_nSignalBitsNTSC ]; } @@ -731,10 +731,10 @@ inline void updateVideoScannerHorzEOL() else { // NOTE: This writes out-of-bounds for a 560x384 framebuffer - g_pFuncUpdateHuePixel(0); - g_pFuncUpdateHuePixel(0); - g_pFuncUpdateHuePixel(0); g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); // BUGFIX: ARCHON: green fringe on end of line + g_pFuncUpdateHuePixel(0); + g_pFuncUpdateHuePixel(0); + g_pFuncUpdateHuePixel(0); } } @@ -745,7 +745,6 @@ inline void updateVideoScannerHorzEOL() g_nVideoClockVert = 0; updateFlashRate(); - //VideoRefreshScreen(); // ContinueExecution() calls VideoRefreshScreen() every dwClksPerFrame (17030) } if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) @@ -1182,7 +1181,7 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires uint8_t a = pAux [0]; bits = ((m & 0x7f) << 7) | (a & 0x7f); - bits = (bits << 1) | g_nLastColumnPixelNTSC; + bits = (bits << 1) | g_nLastColumnPixelNTSC; // TC: needed else colours are wrong phase updatePixels( bits ); g_nLastColumnPixelNTSC = (bits >> 14) & 3; } From ad12a8e6d29876d7d196a6d6f208ae64f90e32c5 Mon Sep 17 00:00:00 2001 From: tomcw Date: Thu, 24 May 2018 21:34:26 +0100 Subject: [PATCH 008/128] Fix for #555: . Start video rendering from screen position -1 (ie. 1 DHGR pixel offscreen) . Allows 559th DHGR vertical column to be visible . But now an HGR HCOLOR=2 vertical line at column 0 is only 1 DHGR pixel wide Also: . Fix TEXT80 to be aligned with DHGR . Fix FLASH in TEXT80 (inverse aux bits needed to be masked with 0x7f) --- source/NTSC.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 70578e6d..42d35096 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -658,6 +658,9 @@ inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTa #endif //=========================================================================== + +// NB. g_nLastColumnPixelNTSC = bits.b13 will be superseded by these parent funcs which use bits.b14: +// . updateScreenDoubleHires80(), updateScreenDoubleLores80(), updateScreenText80() inline void updatePixels( uint16_t bits ) { if (g_nColorBurstPixels < 2) @@ -683,7 +686,7 @@ inline void updatePixels( uint16_t bits ) /* #7 of 7 */ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; g_pFuncUpdateBnWPixel(bits & 1); - g_nLastColumnPixelNTSC=bits& 1 ; bits >>= 1; + g_nLastColumnPixelNTSC = bits & 1; } else { @@ -708,7 +711,7 @@ inline void updatePixels( uint16_t bits ) /* #7 of 7 */ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 0000 0abc g_pFuncUpdateHuePixel(bits & 1); - g_nLastColumnPixelNTSC=bits& 1 ; bits >>= 1; // 0000 0000 0000 00ab + g_nLastColumnPixelNTSC = bits & 1; } } @@ -723,7 +726,7 @@ inline void updateVideoScannerHorzEOL() if (g_nColorBurstPixels < 2) { // NOTE: This writes out-of-bounds for a 560x384 framebuffer - g_pFuncUpdateBnWPixel(0); + g_pFuncUpdateBnWPixel(g_nLastColumnPixelNTSC); g_pFuncUpdateBnWPixel(0); g_pFuncUpdateBnWPixel(0); g_pFuncUpdateBnWPixel(0); @@ -731,7 +734,7 @@ inline void updateVideoScannerHorzEOL() else { // NOTE: This writes out-of-bounds for a 560x384 framebuffer - g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); // BUGFIX: ARCHON: green fringe on end of line + g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); g_pFuncUpdateHuePixel(0); g_pFuncUpdateHuePixel(0); g_pFuncUpdateHuePixel(0); @@ -1154,8 +1157,6 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 //=========================================================================== void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires { - uint16_t bits; - if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) { g_pFuncUpdateTextScreen( cycles6502 ); @@ -1180,10 +1181,10 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires uint8_t m = pMain[0]; uint8_t a = pAux [0]; - bits = ((m & 0x7f) << 7) | (a & 0x7f); - bits = (bits << 1) | g_nLastColumnPixelNTSC; // TC: needed else colours are wrong phase + uint16_t bits = ((m & 0x7f) << 7) | (a & 0x7f); + bits = (bits << 1) | g_nLastColumnPixelNTSC; updatePixels( bits ); - g_nLastColumnPixelNTSC = (bits >> 14) & 3; + g_nLastColumnPixelNTSC = (bits >> 14) & 1; } } updateVideoScannerHorzEOL(); @@ -1256,12 +1257,10 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores uint16_t aux = hi >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3); uint16_t bits = (main << 7) | (aux & 0x7f); updatePixels( bits ); - g_nLastColumnPixelNTSC = (bits >> 14) & 3; - + g_nLastColumnPixelNTSC = (bits >> 14) & 1; } } updateVideoScannerHorzEOL(); - } } @@ -1273,7 +1272,7 @@ void updateScreenSingleHires40 (long cycles6502) g_pFuncUpdateTextScreen( cycles6502 ); return; } - + for (; cycles6502 > 0; --cycles6502) { uint16_t addr = updateVideoScannerAddressHGR(); @@ -1393,8 +1392,10 @@ void updateScreenText80 (long cycles6502) if ((0 == g_nVideoCharSet) && 0x40 == (a & 0xC0)) // Flash only if mousetext not active aux ^= g_nTextFlashMask; - uint16_t bits = (main << 7) | aux; + uint16_t bits = (main << 7) | (aux & 0x7f); + bits = (bits << 1) | g_nLastColumnPixelNTSC; // GH#555: Align TEXT80 chars with DHGR updatePixels( bits ); + g_nLastColumnPixelNTSC = (bits >> 14) & 1; } } updateVideoScannerHorzEOL(); @@ -1628,7 +1629,11 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit updateMonochromeTables( 0xFF, 0xFF, 0xFF ); for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++) - g_pScanLines[y] = (bgra_t*)(g_pFramebufferbits + sizeof(bgra_t) * GetFrameBufferWidth() * ((GetFrameBufferHeight() - 1) - y - GetFrameBufferBorderHeight()) + (sizeof(bgra_t) * GetFrameBufferBorderWidth())); + { + uint32_t offset = sizeof(bgra_t) * GetFrameBufferWidth() * ((GetFrameBufferHeight() - 1) - y - GetFrameBufferBorderHeight()) + (sizeof(bgra_t) * GetFrameBufferBorderWidth()); + offset -= sizeof(bgra_t); // GH#555: Start 1 RGBA pixel before frame to account for g_nLastColumnPixelNTSC + g_pScanLines[y] = (bgra_t*) (g_pFramebufferbits + offset); + } g_pVideoAddress = g_pScanLines[0]; From 9fff2070c4de54f8d46523448534dde6e26bc122 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 26 May 2018 16:45:25 +0100 Subject: [PATCH 009/128] 1.27.4: Bump version & update History.txt --- bin/History.txt | 12 ++++++++++-- resource/Applewin.rc | 8 ++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index b2ba1d1d..f121102d 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -9,11 +9,19 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth -1.27.3.0 - 14 Apr 2018 +1.27.4.0 - 26 May 2018 ---------------------- +. [Bug #555] Fix for showing 559th DHGR vertical column. + - But now an HGR HCOLOR=2 vertical line at column 0 is only 1 DHGR pixel wide. + - Fix TEXT80 to be aligned with DHGR. + - Fix FLASH in TEXT80 (the inverse aux-memory char would overwrite the main-memory char). +. [Change #554] Help: Added a new help page about AppleWin's SSC emulation. +. [Change #522] SSC: ZLINK not starting unless DCD is set. + - DCD state is now a mirror of DSR unless -dcd switch is used. + - Removed -dsr,-dtr switches, so -modem is now an alias for -dcd. . [Bug #308] SSC: For TCP mode, support DSR, DCD & CTS status bits. . SSC: Now DTR must also be set to enable interrupts (in addition to the respective Tx/Rx interrupt bit). -. SSC: When reading the Status register, throttle calls to GetCommModemStatus() to a maximum of once every 8ms. +. SSC: Change DIPSW1's baud rate to 9600 (was 19200). 1.27.2.0 - 12 Apr 2018 diff --git a/resource/Applewin.rc b/resource/Applewin.rc index a2058600..cdd1c6b2 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,3,0 - PRODUCTVERSION 1,27,3,0 + FILEVERSION 1,27,4,0 + PRODUCTVERSION 1,27,4,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 3, 0" + VALUE "FileVersion", "1, 27, 4, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 3, 0" + VALUE "ProductVersion", "1, 27, 4, 0" END END BLOCK "VarFileInfo" From 20cd8913f5d3817dfd1efd273adeb40e3af15a06 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 26 May 2018 18:04:13 +0100 Subject: [PATCH 010/128] For #556: Suppress the Windows Default Beep (ie. Ding) whenever ALT+ is pressed. --- source/Frame.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/Frame.cpp b/source/Frame.cpp index f2cb3e3f..c5019cc4 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1736,6 +1736,7 @@ LRESULT CALLBACK FrameWndProc ( if ((wparam == VK_F10) || (wparam == VK_MENU)) // VK_MENU == ALT Key return 0; + break; case WM_SYSKEYUP: @@ -1748,6 +1749,9 @@ LRESULT CALLBACK FrameWndProc ( PostMessage(window,WM_KEYUP,wparam,lparam); break; + case WM_MENUCHAR: // GH#556 - Suppress the Windows Default Beep (ie. Ding) whenever ALT+ is pressed + return (MNC_CLOSE << 16) | (wparam & 0xffff); + case WM_USER_BENCHMARK: { UpdateWindow(window); ResetMachineState(); From 19b90800cf2351f759af771fe05c0ad94330b525 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 27 May 2018 10:56:35 +0100 Subject: [PATCH 011/128] Add hook filter for system keys (eg. ALT+TAB, ALT+ESC, CTRL+ESC) - #145, #556 --- AppleWinExpress2008.sln | 6 ++ HookFilter/HookFilter.cpp | 41 ++++++++ HookFilter/HookFilter.vcproj | 181 +++++++++++++++++++++++++++++++++++ help/card-ssc.html | 4 +- source/Applewin.cpp | 38 ++++++++ 5 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 HookFilter/HookFilter.cpp create mode 100644 HookFilter/HookFilter.vcproj diff --git a/AppleWinExpress2008.sln b/AppleWinExpress2008.sln index aa8e1d14..0c04ea20 100644 --- a/AppleWinExpress2008.sln +++ b/AppleWinExpress2008.sln @@ -20,6 +20,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "libyaml\win32\yaml2 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestDebugger", "test\TestDebugger\TestDebugger.vcproj", "{0AE28CF0-15B0-4DDF-B6D2-4562D8E456BB}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HookFilter", "HookFilter\HookFilter.vcproj", "{AA5854AD-2BC7-4EFD-9790-349ADB35E35A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -50,6 +52,10 @@ Global {0AE28CF0-15B0-4DDF-B6D2-4562D8E456BB}.Debug|Win32.Build.0 = Debug|Win32 {0AE28CF0-15B0-4DDF-B6D2-4562D8E456BB}.Release|Win32.ActiveCfg = Release|Win32 {0AE28CF0-15B0-4DDF-B6D2-4562D8E456BB}.Release|Win32.Build.0 = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug|Win32.Build.0 = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release|Win32.ActiveCfg = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp new file mode 100644 index 00000000..c7cc3841 --- /dev/null +++ b/HookFilter/HookFilter.cpp @@ -0,0 +1,41 @@ +#include + +// https://stackoverflow.com/questions/2490577/suppress-task-switch-keys-winkey-alt-tab-alt-esc-ctrl-esc-using-low-level-k + +// NB. __stdcall (or WINAPI) and extern "C": +// . symbol is decorated as _@bytes +// . so use the #pragma to create an undecorated alias for our symbol +extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( + _In_ int nCode, + _In_ WPARAM wParam, + _In_ LPARAM lParam +) +{ + #pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) + + if (nCode >= 0) + { + bool suppress = false; + + PKBDLLHOOKSTRUCT pKbdLlHookStruct = (PKBDLLHOOKSTRUCT) lParam; + + // Suppress alt-tab. + if (pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) + suppress = true; + + // Suppress alt-escape. + if (pKbdLlHookStruct->vkCode == VK_ESCAPE && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) + suppress = true; + + // Suppress ctrl-escape. + bool ControlDown = (GetKeyState(VK_CONTROL) & 0x8000) != 0; + if (pKbdLlHookStruct->vkCode == VK_ESCAPE && ControlDown) + suppress = true; + + // Suppress keys by returning 1. + if (suppress) + return 1; + } + + return CallNextHookEx(0/*parameter is ignored*/, nCode, wParam, lParam); +} diff --git a/HookFilter/HookFilter.vcproj b/HookFilter/HookFilter.vcproj new file mode 100644 index 00000000..df4e8951 --- /dev/null +++ b/HookFilter/HookFilter.vcproj @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/help/card-ssc.html b/help/card-ssc.html index 4c6ee7a8..c2c4471b 100644 --- a/help/card-ssc.html +++ b/help/card-ssc.html @@ -37,7 +37,7 @@
        • For the TCP mode it doesn't matter what baud rate, stop-bit, byte size and parity are set to.
          • It always uses an unthrottled data-rate of 8-bit bytes (no stop-bit, no parity). -
          • When there's an active TCP connection, then the 6551's Status register has DCD,DSR bits clear (active low), and DIPSW2 has CTS bit clear (active low). When there's no TCP connection, then all these bits are set (inactive). +
          • When there's an active TCP connection, then the 6551's Status register has DCD,DSR bits clear (active low), and DIPSW2 has CTS bit clear (active low). When there's no TCP connection, then all these bits are set (inactive).
        • The TCP mode can expose buggy Rx interrupt handling code where the 6551's Status register is read more than once in the Interrupt Service Routine (ISR).
            @@ -58,7 +58,7 @@
          • 6551 ACIA Status register's error bits: overrun, framing and parity (these are all hardcoded to 0).
          • 6551 ACIA Status register's DCD bit (Data Carrier Detect). This is just set the same as DSR.
              -
            • NB. Use command line -dcd to force AppleWin to use the state of the MS_RLSD_ON bit from GetCommModemStatus(). +
            • NB. For COM mode, use command line -dcd to force AppleWin to use the state of the MS_RLSD_ON bit from GetCommModemStatus().
          • NMOS 6551 ACIA CTS bug: transmission of an already-started frame will stop immediately when CTS is taken false, the byte will be lost, and the TxD line will go to marking.
              diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 7505d533..f54adca0 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1012,6 +1012,40 @@ static void InsertHardDisks(LPSTR szImageName_harddisk[NUM_HARDDISKS], bool& bBo //--------------------------------------------------------------------------- +static HINSTANCE g_hinstDLL = 0; +static HHOOK g_hhook = 0; + +void HookFilterForKeyboard() +{ + g_hinstDLL = LoadLibrary(TEXT("AppleWinHookFilter.dll")); + HOOKPROC hkprcLowLevelKeyboardProc = (HOOKPROC) GetProcAddress(g_hinstDLL, "LowLevelKeyboardProc"); + + g_hhook = SetWindowsHookEx( + WH_KEYBOARD_LL, + hkprcLowLevelKeyboardProc, + g_hinstDLL, + 0); + + if (g_hhook == NULL) + { + std::string msg("Failed to install hook filter for system keys"); + + DWORD dwErr = GetLastError(); + MessageBox(GetDesktopWindow(), msg.c_str(), "Warning", MB_ICONASTERISK | MB_OK); // NB. g_hFrameWindow is not yet valid + + msg += "\n"; + LogFileOutput(msg.c_str()); + } +} + +void UnhookFilterForKeyboard() +{ + UnhookWindowsHookEx(g_hhook); + FreeLibrary(g_hinstDLL); +} + +//--------------------------------------------------------------------------- + int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { bool bShutdown = false; @@ -1310,6 +1344,8 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) DiskInitialize(); LogFileOutput("Init: DiskInitialize()\n"); + HookFilterForKeyboard(); + // do @@ -1475,6 +1511,8 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) } while (g_bRestart); + UnhookFilterForKeyboard(); + if (bChangedDisplayResolution) ChangeDisplaySettings(NULL, 0); // restore default From 6b53adde5586d15a1e15456d7b00ae11c09a6efe Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 28 May 2018 17:27:38 +0100 Subject: [PATCH 012/128] SysKey hook filter: . Also suppress ALT+SPACE . PostMessage to AppleWin message-pump for WM_KEYDOWN, WM_KEYUP for these special key combos . Add special any-key-down (AKD) handling for these special key combos --- HookFilter/HookFilter.cpp | 43 +++++++++++++---- HookFilter/HookFilter.vcproj | 2 +- source/Applewin.cpp | 94 ++++++++++++++++++++---------------- source/Frame.cpp | 3 ++ source/Keyboard.cpp | 55 +++++++++++++++++++++ source/Keyboard.h | 2 + 6 files changed, 147 insertions(+), 52 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index c7cc3841..67a18d48 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -2,40 +2,65 @@ // https://stackoverflow.com/questions/2490577/suppress-task-switch-keys-winkey-alt-tab-alt-esc-ctrl-esc-using-low-level-k +static HWND g_hFrameWindow = (HWND)0; + // NB. __stdcall (or WINAPI) and extern "C": // . symbol is decorated as _@bytes // . so use the #pragma to create an undecorated alias for our symbol extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( _In_ int nCode, _In_ WPARAM wParam, - _In_ LPARAM lParam -) + _In_ LPARAM lParam) { #pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) - if (nCode >= 0) + if (nCode == HC_ACTION) { bool suppress = false; PKBDLLHOOKSTRUCT pKbdLlHookStruct = (PKBDLLHOOKSTRUCT) lParam; + UINT newMsg = pKbdLlHookStruct->flags & LLKHF_UP ? WM_KEYUP : WM_KEYDOWN; + LPARAM newlParam = newMsg == WM_KEYUP ? 3<<30 : 0; // b31:transition state, b30:previous key state - // Suppress alt-tab. - if (pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) + // Note about PostMessage() and use of VkKeyScan(): + // . Convert the ascii code to virtual key code, so that the message pump can do TranslateMessage() + // . NB. From MSDN for "WM_KEYDOWN" && "WM_KEYUP" : "Applications must pass wParam to TranslateMessage without altering it at all." + + // Suppress alt-tab + if (pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) + { + PostMessage(g_hFrameWindow, newMsg, LOBYTE(VkKeyScan(0x09)), newlParam); suppress = true; + } - // Suppress alt-escape. - if (pKbdLlHookStruct->vkCode == VK_ESCAPE && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) + // Suppress alt-escape + if (pKbdLlHookStruct->vkCode == VK_ESCAPE && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) + { + PostMessage(g_hFrameWindow, newMsg, LOBYTE(VkKeyScan(0x1B)), newlParam); suppress = true; + } - // Suppress ctrl-escape. + // Suppress alt-space + if (pKbdLlHookStruct->vkCode == VK_SPACE && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) + { + PostMessage(g_hFrameWindow, newMsg, LOBYTE(VkKeyScan(0x20)), newlParam); + suppress = true; + } + + // Suppress ctrl-escape bool ControlDown = (GetKeyState(VK_CONTROL) & 0x8000) != 0; if (pKbdLlHookStruct->vkCode == VK_ESCAPE && ControlDown) suppress = true; - // Suppress keys by returning 1. + // Suppress keys by returning 1 if (suppress) return 1; } return CallNextHookEx(0/*parameter is ignored*/, nCode, wParam, lParam); } + +extern "C" __declspec(dllexport) void __cdecl RegisterHWND(HWND hWnd) +{ + g_hFrameWindow = hWnd; +} diff --git a/HookFilter/HookFilter.vcproj b/HookFilter/HookFilter.vcproj index df4e8951..61bb8edb 100644 --- a/HookFilter/HookFilter.vcproj +++ b/HookFilter/HookFilter.vcproj @@ -2,7 +2,7 @@ = VK_F1) && (wparam <= VK_F8) && (buttondown == -1)) @@ -1399,6 +1400,8 @@ LRESULT CALLBACK FrameWndProc ( break; case WM_KEYUP: + KeybSpecialKeyup(wparam); + // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1)) { diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 53a91cfb..3261f52e 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -389,6 +389,58 @@ static char ClipboardCurrChar(bool bIncPtr) //=========================================================================== +// For AKD (Any Key Down), need special handling for the hooked key combos(*), as GetKeyState() doesn't detect the keys as being down. +// (*) ALT+TAB, ALT+ESCAPE, ALT+SPACE + +static enum {AKD_TAB=0, AKD_ESCAPE, AKD_SPACE}; +static bool g_specialAKD[3] = {false,false,false}; + +void KeybSpecialKeydown(DWORD wparam) +{ + switch (wparam) + { + case VK_TAB: + g_specialAKD[AKD_TAB] = true; + break; + case VK_ESCAPE: + g_specialAKD[AKD_ESCAPE] = true; + break; + case VK_SPACE: + g_specialAKD[AKD_SPACE] = true; + break; + }; +} + +void KeybSpecialKeyup(DWORD wparam) +{ + switch (wparam) + { + case VK_TAB: + g_specialAKD[AKD_TAB] = false; + break; + case VK_ESCAPE: + g_specialAKD[AKD_ESCAPE] = false; + break; + case VK_SPACE: + g_specialAKD[AKD_SPACE] = false; + break; + }; +} + +static bool IsSpecialAKD(int lastvirtkey) +{ + if (VK_TAB == lastvirtkey) + return g_specialAKD[AKD_TAB]; + else if (VK_ESCAPE == lastvirtkey) + return g_specialAKD[AKD_ESCAPE]; + else if (VK_SPACE == lastvirtkey) + return g_specialAKD[AKD_SPACE]; + + return false; +} + +//=========================================================================== + BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) { LogFileTimeUntilFirstKeyRead(); @@ -428,6 +480,9 @@ BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG) keywaiting = 0; + if (IsSpecialAKD(lastvirtkey)) + return keycode | 0x80; + return keycode | ((GetKeyState(lastvirtkey) < 0) ? 0x80 : 0); } diff --git a/source/Keyboard.h b/source/Keyboard.h index dfe9c20c..de3bcb31 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -14,6 +14,8 @@ BYTE KeybGetKeycode (); void KeybQueueKeypress (int,BOOL); void KeybToggleCapsLock (); void KeybToggleP8ACapsLock (); +void KeybSpecialKeydown(DWORD wparam); +void KeybSpecialKeyup(DWORD wparam); void KeybSetSnapshot_v1(const BYTE LastKey); void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); From 0d4be07e7edef2b3de89ec80f2420c64e1a6ddd7 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 28 May 2018 22:13:54 +0100 Subject: [PATCH 013/128] SysKey hook filter: . Fix for GetKeyState() not detecting the special keys as being up (so AKD was erroneously reporting the key still down). . eg. Whilst pressing TAB, press LEFT ALT, then release TAB. --- source/Frame.cpp | 11 +++++++++-- source/Keyboard.cpp | 44 +++++++++++++++----------------------------- source/Keyboard.h | 3 +-- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index aa454042..8b84d581 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1260,7 +1260,7 @@ LRESULT CALLBACK FrameWndProc ( case WM_KEYDOWN: KeybUpdateCtrlShiftStatus(); - KeybSpecialKeydown(wparam); + KeybSpecialKeyTransition(WM_KEYDOWN, wparam); // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == -1)) @@ -1400,7 +1400,14 @@ LRESULT CALLBACK FrameWndProc ( break; case WM_KEYUP: - KeybSpecialKeyup(wparam); + KeybSpecialKeyTransition(WM_KEYUP, wparam); + + if (wparam == VK_ESCAPE || wparam == VK_SPACE || wparam == VK_TAB) + { + char str[40]; + sprintf(str, "WM_KEYUP: %d\n", wparam); + OutputDebugString(str); + } // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1)) diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 3261f52e..ebc180ad 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -390,53 +390,39 @@ static char ClipboardCurrChar(bool bIncPtr) //=========================================================================== // For AKD (Any Key Down), need special handling for the hooked key combos(*), as GetKeyState() doesn't detect the keys as being down. +// . And equally GetKeyState() doesn't detect the keys as being up: eg. Whilst pressing TAB, press LEFT ALT, then release TAB. // (*) ALT+TAB, ALT+ESCAPE, ALT+SPACE static enum {AKD_TAB=0, AKD_ESCAPE, AKD_SPACE}; static bool g_specialAKD[3] = {false,false,false}; -void KeybSpecialKeydown(DWORD wparam) +void KeybSpecialKeyTransition(UINT message, WPARAM wparam) { + _ASSERT(message == WM_KEYUP || message == WM_KEYDOWN); + bool bState = message == WM_KEYDOWN; + switch (wparam) { case VK_TAB: - g_specialAKD[AKD_TAB] = true; + g_specialAKD[AKD_TAB] = bState; break; case VK_ESCAPE: - g_specialAKD[AKD_ESCAPE] = true; + g_specialAKD[AKD_ESCAPE] = bState; break; case VK_SPACE: - g_specialAKD[AKD_SPACE] = true; + g_specialAKD[AKD_SPACE] = bState; break; }; } -void KeybSpecialKeyup(DWORD wparam) -{ - switch (wparam) - { - case VK_TAB: - g_specialAKD[AKD_TAB] = false; - break; - case VK_ESCAPE: - g_specialAKD[AKD_ESCAPE] = false; - break; - case VK_SPACE: - g_specialAKD[AKD_SPACE] = false; - break; - }; -} - -static bool IsSpecialAKD(int lastvirtkey) +static void GetKeyStateOfSpecialAKD(int lastvirtkey, bool& bState) { if (VK_TAB == lastvirtkey) - return g_specialAKD[AKD_TAB]; + bState = g_specialAKD[AKD_TAB]; else if (VK_ESCAPE == lastvirtkey) - return g_specialAKD[AKD_ESCAPE]; + bState = g_specialAKD[AKD_ESCAPE]; else if (VK_SPACE == lastvirtkey) - return g_specialAKD[AKD_SPACE]; - - return false; + bState = g_specialAKD[AKD_SPACE]; } //=========================================================================== @@ -480,10 +466,10 @@ BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG) keywaiting = 0; - if (IsSpecialAKD(lastvirtkey)) - return keycode | 0x80; + bool bState = GetKeyState(lastvirtkey) < 0; + GetKeyStateOfSpecialAKD(lastvirtkey, bState); - return keycode | ((GetKeyState(lastvirtkey) < 0) ? 0x80 : 0); + return keycode | (bState ? 0x80 : 0); } //=========================================================================== diff --git a/source/Keyboard.h b/source/Keyboard.h index de3bcb31..e0b54c55 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -14,8 +14,7 @@ BYTE KeybGetKeycode (); void KeybQueueKeypress (int,BOOL); void KeybToggleCapsLock (); void KeybToggleP8ACapsLock (); -void KeybSpecialKeydown(DWORD wparam); -void KeybSpecialKeyup(DWORD wparam); +void KeybSpecialKeyTransition(UINT message, WPARAM wparam); void KeybSetSnapshot_v1(const BYTE LastKey); void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); From a07407c6f85d385e3a53280afde372db7f1f9fac Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 28 May 2018 22:36:00 +0100 Subject: [PATCH 014/128] Suppress AKD support for II and II+ models. (Fixed #116) --- source/Frame.cpp | 7 ------- source/Keyboard.cpp | 5 +++++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 8b84d581..b212b29d 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1402,13 +1402,6 @@ LRESULT CALLBACK FrameWndProc ( case WM_KEYUP: KeybSpecialKeyTransition(WM_KEYUP, wparam); - if (wparam == VK_ESCAPE || wparam == VK_SPACE || wparam == VK_TAB) - { - char str[40]; - sprintf(str, "WM_KEYUP: %d\n", wparam); - OutputDebugString(str); - } - // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1)) { diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index ebc180ad..c1a90e0d 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -466,6 +466,11 @@ BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG) keywaiting = 0; + if (IS_APPLE2) // Include Pravets machines too? + return keycode; + + // AKD + bool bState = GetKeyState(lastvirtkey) < 0; GetKeyStateOfSpecialAKD(lastvirtkey, bState); From 1583ad25212ef49565c4d293e0411070e398f480 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 29 May 2018 21:54:46 +0100 Subject: [PATCH 015/128] VS2008 sln: add dependency on HookFilter.vcproj --- AppleWinExpress2008.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/AppleWinExpress2008.sln b/AppleWinExpress2008.sln index 0c04ea20..f23ecfcf 100644 --- a/AppleWinExpress2008.sln +++ b/AppleWinExpress2008.sln @@ -6,6 +6,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Applewin", "AppleWinExpress {5CE8051A-3F0C-4C39-B1C0-3338E48BA60F} = {5CE8051A-3F0C-4C39-B1C0-3338E48BA60F} {7935B998-C713-42AE-8F6D-9FF9080A1B1B} = {7935B998-C713-42AE-8F6D-9FF9080A1B1B} {2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2} = {2CC8CA9F-E37E-41A4-BFAD-77E54EB783A2} + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} = {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} {709278B8-C583-4BD8-90DE-4E4F35A3BD8B} = {709278B8-C583-4BD8-90DE-4E4F35A3BD8B} {0AE28CF0-15B0-4DDF-B6D2-4562D8E456BB} = {0AE28CF0-15B0-4DDF-B6D2-4562D8E456BB} EndProjectSection From 9fed8d0cf5ac6b628a9f1042d7543e27098fadcf Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 29 May 2018 22:42:40 +0100 Subject: [PATCH 016/128] Added VS2015 support for HookFilter DLL --- AppleWinExpress2015.sln | 14 ++- HookFilter/HookFilter-vs2015.vcxproj | 97 ++++++++++++++++++++ HookFilter/HookFilter-vs2015.vcxproj.filters | 14 +++ 3 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 HookFilter/HookFilter-vs2015.vcxproj create mode 100644 HookFilter/HookFilter-vs2015.vcxproj.filters diff --git a/AppleWinExpress2015.sln b/AppleWinExpress2015.sln index ab925ed9..803daee0 100644 --- a/AppleWinExpress2015.sln +++ b/AppleWinExpress2015.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppleWin", "AppleWinExpress2015.vcxproj", "{0A960136-A00A-4D4B-805F-664D9950D2CA}" ProjectSection(ProjectDependencies) = postProject @@ -19,6 +19,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "libyaml\win32\yaml2 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCPU6502", "test\TestCPU6502\TestCPU6502-vs2015.vcxproj", "{CF5A49BF-62A5-41BB-B10C-F34D556A7A45}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HookFilter", "HookFilter\HookFilter-vs2015.vcxproj", "{AA5854AD-2BC7-4EFD-9790-349ADB35E35A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug NoDX|Win32 = Debug NoDX|Win32 @@ -67,6 +69,14 @@ Global {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release NoDX|Win32.Build.0 = Release|Win32 {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.ActiveCfg = Release|Win32 {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.Build.0 = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug|Win32.Build.0 = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release NoDX|Win32.Build.0 = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release|Win32.ActiveCfg = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/HookFilter/HookFilter-vs2015.vcxproj b/HookFilter/HookFilter-vs2015.vcxproj new file mode 100644 index 00000000..7e32a2c8 --- /dev/null +++ b/HookFilter/HookFilter-vs2015.vcxproj @@ -0,0 +1,97 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + HookFilter + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} + HookFilter + Win32Proj + + + + DynamicLibrary + v140 + Unicode + true + + + DynamicLibrary + v140 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>14.0.25420.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;HOOKFILTER_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + + + true + Windows + MachineX86 + + + + + + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;HOOKFILTER_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + + + + + + + \ No newline at end of file diff --git a/HookFilter/HookFilter-vs2015.vcxproj.filters b/HookFilter/HookFilter-vs2015.vcxproj.filters new file mode 100644 index 00000000..a87fdcc3 --- /dev/null +++ b/HookFilter/HookFilter-vs2015.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file From 539f5db40ac40329f9fa0238785fdb3292b9ca82 Mon Sep 17 00:00:00 2001 From: tomcw Date: Wed, 30 May 2018 22:38:10 +0100 Subject: [PATCH 017/128] Fix for //e keyboard's AKD. (Fixes #330) --- source/Frame.cpp | 31 +++++++++------- source/Keyboard.cpp | 90 +++++++++++++++++++++++++++++++++++++-------- source/Keyboard.h | 1 + 3 files changed, 92 insertions(+), 30 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index b212b29d..e647b962 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1262,6 +1262,9 @@ LRESULT CALLBACK FrameWndProc ( KeybUpdateCtrlShiftStatus(); KeybSpecialKeyTransition(WM_KEYDOWN, wparam); + if ((HIWORD(lparam) & KF_REPEAT) == 0) + KeybAnyKeyDown(WM_KEYDOWN, wparam); + // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == -1)) { @@ -1320,7 +1323,18 @@ LRESULT CALLBACK FrameWndProc ( Config_Save_Video(); } - else if ((wparam == VK_F11) && (GetKeyState(VK_CONTROL) >= 0)) // Save state (F11) + else if (wparam == VK_F10) + { + if (g_Apple2Type == A2TYPE_PRAVETS8A && !g_bCtrlKey) + { + KeybToggleP8ACapsLock (); // F10: Toggles P8 Capslock + } + else + { + SetUsingCursor(FALSE); // Ctrl+F10 + } + } + else if (wparam == VK_F11 && !g_bCtrlKey) // Save state (F11) { SoundCore_SetFade(FADE_OUT); if(sg_PropertySheet.SaveStateSelectImage(window, true)) @@ -1329,7 +1343,7 @@ LRESULT CALLBACK FrameWndProc ( } SoundCore_SetFade(FADE_IN); } - else if (wparam == VK_F12) // Load state (F12 or Ctrl+F12) + else if (wparam == VK_F12) // Load state (F12 or Ctrl+F12) { SoundCore_SetFade(FADE_OUT); if(sg_PropertySheet.SaveStateSelectImage(window, false)) @@ -1385,22 +1399,11 @@ LRESULT CALLBACK FrameWndProc ( { DebuggerProcessKey(wparam); // Debugger already active, re-direct key to debugger } - - if (wparam == VK_F10) - { - if ((g_Apple2Type == A2TYPE_PRAVETS8A) && (GetKeyState(VK_CONTROL) >= 0)) - { - KeybToggleP8ACapsLock ();//Toggles P8 Capslock - } - else - { - SetUsingCursor(FALSE); - } - } break; case WM_KEYUP: KeybSpecialKeyTransition(WM_KEYUP, wparam); + KeybAnyKeyDown(WM_KEYUP, wparam); // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1)) diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index c1a90e0d..8be5bea6 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -119,7 +119,7 @@ BYTE KeybGetKeycode () // Used by MemCheckPaging() & VideoCheckMode() //=========================================================================== void KeybQueueKeypress (int key, BOOL bASCII) { - if (bASCII == ASCII) + if (bASCII == ASCII) // WM_CHAR { if (g_bFreshReset && key == VK_CANCEL) // OLD HACK: 0x03 { @@ -274,9 +274,10 @@ void KeybQueueKeypress (int key, BOOL bASCII) keycode = key; } } + lastvirtkey = LOBYTE(VkKeyScan(key)); } - else //(bASCII != ASCII) + else //(bASCII != ASCII) // WM_KEYDOWN { // Note: VK_CANCEL is Control-Break if ((key == VK_CANCEL) && (GetKeyState(VK_CONTROL) < 0)) @@ -389,12 +390,12 @@ static char ClipboardCurrChar(bool bIncPtr) //=========================================================================== -// For AKD (Any Key Down), need special handling for the hooked key combos(*), as GetKeyState() doesn't detect the keys as being down. -// . And equally GetKeyState() doesn't detect the keys as being up: eg. Whilst pressing TAB, press LEFT ALT, then release TAB. +// For AKD (Any Key Down), need special handling for the hooked key combos(*), as GetKeyState() doesn't detect the keys as being up/down. +// . EG. Whilst pressing TAB, press LEFT ALT, then release TAB. // (*) ALT+TAB, ALT+ESCAPE, ALT+SPACE -static enum {AKD_TAB=0, AKD_ESCAPE, AKD_SPACE}; -static bool g_specialAKD[3] = {false,false,false}; +static enum {AKD_TAB=0, AKD_ESCAPE, AKD_SPACE, AKD_RETURN}; +static bool g_specialAKD[4] = {false,false,false,false}; void KeybSpecialKeyTransition(UINT message, WPARAM wparam) { @@ -412,17 +413,75 @@ void KeybSpecialKeyTransition(UINT message, WPARAM wparam) case VK_SPACE: g_specialAKD[AKD_SPACE] = bState; break; + case VK_RETURN: // Treat as special too, as get a WM_KEYUP after using RETURN to OK the Config/Load-State dialogs! + g_specialAKD[AKD_RETURN] = bState; + break; }; } -static void GetKeyStateOfSpecialAKD(int lastvirtkey, bool& bState) +static void GetKeyStateOfSpecialAKD(bool& bState) { - if (VK_TAB == lastvirtkey) - bState = g_specialAKD[AKD_TAB]; - else if (VK_ESCAPE == lastvirtkey) - bState = g_specialAKD[AKD_ESCAPE]; - else if (VK_SPACE == lastvirtkey) - bState = g_specialAKD[AKD_SPACE]; + if ( g_specialAKD[AKD_TAB] || g_specialAKD[AKD_ESCAPE] || g_specialAKD[AKD_SPACE] || g_specialAKD[AKD_RETURN] ) + bState = true; +} + +//=========================================================================== + +static int g_AKDRefCount = 0; + +void KeybAnyKeyDown(UINT message, WPARAM wparam) +{ + if (IS_APPLE2) // Include Pravets machines too? + return; // No AKD support + + if (wparam == VK_TAB || wparam == VK_ESCAPE || wparam == VK_SPACE || wparam == VK_RETURN) + return; // Could be from hook-filter, so ignore and handle via KeybSpecialKeyTransition() + + const int value = message == WM_KEYDOWN ? 1 : -1; + bool bDoRefCount = false; + + if (wparam == VK_BACK || + wparam == VK_TAB || + wparam == VK_RETURN || + wparam == VK_ESCAPE || + wparam == VK_SPACE || + (wparam >= VK_LEFT && wparam <= VK_DOWN) || + wparam == VK_DELETE || + (wparam >= '0' && wparam <= '9') || + (wparam >= 'A' && wparam <= 'Z')) + { + bDoRefCount = true; + } + else if (wparam >= VK_NUMPAD0 && wparam <= VK_NUMPAD9) + { + bDoRefCount = true; + } + else if (wparam >= VK_MULTIPLY && wparam <= VK_DIVIDE) + { + bDoRefCount = true; + } + else if (wparam >= VK_OEM_1 && wparam <= VK_OEM_3) // 7 in total + { + bDoRefCount = true; + } + else if (wparam >= VK_OEM_4 && wparam <= VK_OEM_8) // 5 in total + { + bDoRefCount = true; + } + else if (wparam == VK_OEM_102) + { + bDoRefCount = true; + } + + if (bDoRefCount) + { + g_AKDRefCount += value; + if (g_AKDRefCount < 0) + { + _ASSERT(0); + g_AKDRefCount = 0; + } + } } //=========================================================================== @@ -471,9 +530,8 @@ BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG) // AKD - bool bState = GetKeyState(lastvirtkey) < 0; - GetKeyStateOfSpecialAKD(lastvirtkey, bState); - + bool bState = g_AKDRefCount > 0; + GetKeyStateOfSpecialAKD(bState); return keycode | (bState ? 0x80 : 0); } diff --git a/source/Keyboard.h b/source/Keyboard.h index e0b54c55..698150f8 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -15,6 +15,7 @@ void KeybQueueKeypress (int,BOOL); void KeybToggleCapsLock (); void KeybToggleP8ACapsLock (); void KeybSpecialKeyTransition(UINT message, WPARAM wparam); +void KeybAnyKeyDown(UINT message, WPARAM wparam); void KeybSetSnapshot_v1(const BYTE LastKey); void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); From fdd6a622dc9d0ff92340d3d1d3323c279e6558a6 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 2 Jun 2018 22:26:29 +0100 Subject: [PATCH 018/128] Simplified AKD support --- source/Frame.cpp | 29 ++++++----- source/Keyboard.cpp | 114 ++++++++++++-------------------------------- source/Keyboard.h | 1 - source/StdAfx.h | 1 + 4 files changed, 47 insertions(+), 98 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index e647b962..6a6f0c98 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1260,10 +1260,6 @@ LRESULT CALLBACK FrameWndProc ( case WM_KEYDOWN: KeybUpdateCtrlShiftStatus(); - KeybSpecialKeyTransition(WM_KEYDOWN, wparam); - - if ((HIWORD(lparam) & KF_REPEAT) == 0) - KeybAnyKeyDown(WM_KEYDOWN, wparam); // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == -1)) @@ -1389,11 +1385,18 @@ LRESULT CALLBACK FrameWndProc ( // Note about Alt Gr (Right-Alt): // . WM_KEYDOWN[Left-Control], then: // . WM_KEYDOWN[Right-Alt] - BOOL extended = ((lparam & 0x01000000) != 0); + BOOL extended = (HIWORD(lparam) & KF_EXTENDED) != 0; BOOL down = 1; - BOOL autorep = ((lparam & 0x40000000) != 0); - if ((!JoyProcessKey((int)wparam,extended,down,autorep)) && (g_nAppMode != MODE_LOGO)) - KeybQueueKeypress((int)wparam,NOT_ASCII); + BOOL autorep = (HIWORD(lparam) & KF_REPEAT) != 0; + BOOL IsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); + + if (!IsJoyKey && (g_nAppMode != MODE_LOGO)) + { + KeybQueueKeypress((int)wparam, NOT_ASCII); + + if ((HIWORD(lparam) & KF_REPEAT) == 0) + KeybAnyKeyDown(WM_KEYDOWN, wparam); + } } else if (g_nAppMode == MODE_DEBUG) { @@ -1402,9 +1405,6 @@ LRESULT CALLBACK FrameWndProc ( break; case WM_KEYUP: - KeybSpecialKeyTransition(WM_KEYUP, wparam); - KeybAnyKeyDown(WM_KEYUP, wparam); - // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1)) { @@ -1417,10 +1417,13 @@ LRESULT CALLBACK FrameWndProc ( } else { - BOOL extended = ((lparam & 0x01000000) != 0); + BOOL extended = (HIWORD(lparam) & KF_EXTENDED) != 0; BOOL down = 0; BOOL autorep = 0; - JoyProcessKey((int)wparam,extended,down,autorep); + BOOL bIsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); + + if (!bIsJoyKey) + KeybAnyKeyDown(WM_KEYUP, wparam); } break; diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 8be5bea6..ce02585b 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -390,55 +390,17 @@ static char ClipboardCurrChar(bool bIncPtr) //=========================================================================== -// For AKD (Any Key Down), need special handling for the hooked key combos(*), as GetKeyState() doesn't detect the keys as being up/down. -// . EG. Whilst pressing TAB, press LEFT ALT, then release TAB. -// (*) ALT+TAB, ALT+ESCAPE, ALT+SPACE - -static enum {AKD_TAB=0, AKD_ESCAPE, AKD_SPACE, AKD_RETURN}; -static bool g_specialAKD[4] = {false,false,false,false}; - -void KeybSpecialKeyTransition(UINT message, WPARAM wparam) -{ - _ASSERT(message == WM_KEYUP || message == WM_KEYDOWN); - bool bState = message == WM_KEYDOWN; - - switch (wparam) - { - case VK_TAB: - g_specialAKD[AKD_TAB] = bState; - break; - case VK_ESCAPE: - g_specialAKD[AKD_ESCAPE] = bState; - break; - case VK_SPACE: - g_specialAKD[AKD_SPACE] = bState; - break; - case VK_RETURN: // Treat as special too, as get a WM_KEYUP after using RETURN to OK the Config/Load-State dialogs! - g_specialAKD[AKD_RETURN] = bState; - break; - }; -} - -static void GetKeyStateOfSpecialAKD(bool& bState) -{ - if ( g_specialAKD[AKD_TAB] || g_specialAKD[AKD_ESCAPE] || g_specialAKD[AKD_SPACE] || g_specialAKD[AKD_RETURN] ) - bState = true; -} - -//=========================================================================== - -static int g_AKDRefCount = 0; +static uint64_t g_AKDFlags[4] = {0,0,0,0}; +// NB. Don't need to be concerned about if numpad/cursors are used for joystick, +// since parent calls JoyProcessKey() just before this. void KeybAnyKeyDown(UINT message, WPARAM wparam) { - if (IS_APPLE2) // Include Pravets machines too? - return; // No AKD support - - if (wparam == VK_TAB || wparam == VK_ESCAPE || wparam == VK_SPACE || wparam == VK_RETURN) - return; // Could be from hook-filter, so ignore and handle via KeybSpecialKeyTransition() - - const int value = message == WM_KEYDOWN ? 1 : -1; - bool bDoRefCount = false; + if (wparam > 255) + { + _ASSERT(0); + return; + } if (wparam == VK_BACK || wparam == VK_TAB || @@ -448,52 +410,38 @@ void KeybAnyKeyDown(UINT message, WPARAM wparam) (wparam >= VK_LEFT && wparam <= VK_DOWN) || wparam == VK_DELETE || (wparam >= '0' && wparam <= '9') || - (wparam >= 'A' && wparam <= 'Z')) + (wparam >= 'A' && wparam <= 'Z') || + (wparam >= VK_NUMPAD0 && wparam <= VK_NUMPAD9) || + (wparam >= VK_MULTIPLY && wparam <= VK_DIVIDE) || + (wparam >= VK_OEM_1 && wparam <= VK_OEM_3) || // 7 in total + (wparam >= VK_OEM_4 && wparam <= VK_OEM_8) || // 5 in total + (wparam == VK_OEM_102)) { - bDoRefCount = true; - } - else if (wparam >= VK_NUMPAD0 && wparam <= VK_NUMPAD9) - { - bDoRefCount = true; - } - else if (wparam >= VK_MULTIPLY && wparam <= VK_DIVIDE) - { - bDoRefCount = true; - } - else if (wparam >= VK_OEM_1 && wparam <= VK_OEM_3) // 7 in total - { - bDoRefCount = true; - } - else if (wparam >= VK_OEM_4 && wparam <= VK_OEM_8) // 5 in total - { - bDoRefCount = true; - } - else if (wparam == VK_OEM_102) - { - bDoRefCount = true; - } + UINT offset = wparam >> 6; + UINT bit = wparam & 0x3f; - if (bDoRefCount) - { - g_AKDRefCount += value; - if (g_AKDRefCount < 0) - { - _ASSERT(0); - g_AKDRefCount = 0; - } + if (message == WM_KEYDOWN) + g_AKDFlags[offset] |= (1LL< 0; - GetKeyStateOfSpecialAKD(bState); - return keycode | (bState ? 0x80 : 0); + return keycode | (IsAKD() ? 0x80 : 0); } //=========================================================================== diff --git a/source/Keyboard.h b/source/Keyboard.h index 698150f8..5b7dd009 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -14,7 +14,6 @@ BYTE KeybGetKeycode (); void KeybQueueKeypress (int,BOOL); void KeybToggleCapsLock (); void KeybToggleP8ACapsLock (); -void KeybSpecialKeyTransition(UINT message, WPARAM wparam); void KeybAnyKeyDown(UINT message, WPARAM wparam); void KeybSetSnapshot_v1(const BYTE LastKey); void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); diff --git a/source/StdAfx.h b/source/StdAfx.h index 80418ad5..f8dc4d5c 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -31,6 +31,7 @@ typedef UINT8 uint8_t; typedef UINT16 uint16_t; typedef UINT32 uint32_t; +typedef UINT64 uint64_t; #endif #include From 7de5914251001bdfeab8b98a16226e0e15e803b7 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 5 Jun 2018 22:15:23 +0100 Subject: [PATCH 019/128] Added VS2013 and VS2017 support for HookFilter DLL --- AppleWinExpress2013.sln | 15 ++- AppleWinExpress2017.sln | 13 ++- HookFilter/HookFilter-vs2013.vcxproj | 97 ++++++++++++++++++++ HookFilter/HookFilter-vs2013.vcxproj.filters | 14 +++ HookFilter/HookFilter-vs2017.vcxproj | 97 ++++++++++++++++++++ HookFilter/HookFilter-vs2017.vcxproj.filters | 14 +++ HookFilter/HookFilter.cpp | 2 - 7 files changed, 247 insertions(+), 5 deletions(-) create mode 100644 HookFilter/HookFilter-vs2013.vcxproj create mode 100644 HookFilter/HookFilter-vs2013.vcxproj.filters create mode 100644 HookFilter/HookFilter-vs2017.vcxproj create mode 100644 HookFilter/HookFilter-vs2017.vcxproj.filters diff --git a/AppleWinExpress2013.sln b/AppleWinExpress2013.sln index 10dc5eb9..948c6c7d 100644 --- a/AppleWinExpress2013.sln +++ b/AppleWinExpress2013.sln @@ -1,10 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio Express 2013 for Windows Desktop +VisualStudioVersion = 12.0.30723.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppleWin", "AppleWinExpress2013.vcxproj", "{0A960136-A00A-4D4B-805F-664D9950D2CA}" ProjectSection(ProjectDependencies) = postProject + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} = {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} = {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} {0212E0DF-06DA-4080-BD1D-F3B01599F70F} = {0212E0DF-06DA-4080-BD1D-F3B01599F70F} {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} = {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} @@ -19,6 +20,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "libyaml\win32\yaml2 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCPU6502", "test\TestCPU6502\TestCPU6502-vs2013.vcxproj", "{CF5A49BF-62A5-41BB-B10C-F34D556A7A45}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HookFilter", "HookFilter\HookFilter-vs2013.vcxproj", "{AA5854AD-2BC7-4EFD-9790-349ADB35E35A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug NoDX|Win32 = Debug NoDX|Win32 @@ -67,6 +70,14 @@ Global {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release NoDX|Win32.Build.0 = Release|Win32 {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.ActiveCfg = Release|Win32 {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.Build.0 = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug|Win32.Build.0 = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release NoDX|Win32.Build.0 = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release|Win32.ActiveCfg = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/AppleWinExpress2017.sln b/AppleWinExpress2017.sln index a3e4d20f..c88cee92 100644 --- a/AppleWinExpress2017.sln +++ b/AppleWinExpress2017.sln @@ -1,10 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 +VisualStudioVersion = 15.0.26430.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppleWin", "AppleWinExpress2017.vcxproj", "{0A960136-A00A-4D4B-805F-664D9950D2CA}" ProjectSection(ProjectDependencies) = postProject + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} = {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} = {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} {0212E0DF-06DA-4080-BD1D-F3B01599F70F} = {0212E0DF-06DA-4080-BD1D-F3B01599F70F} {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} = {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} @@ -19,6 +20,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "libyaml\win32\yaml2 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCPU6502", "test\TestCPU6502\TestCPU6502-vs2017.vcxproj", "{CF5A49BF-62A5-41BB-B10C-F34D556A7A45}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HookFilter", "HookFilter\HookFilter-vs2017.vcxproj", "{AA5854AD-2BC7-4EFD-9790-349ADB35E35A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug NoDX|Win32 = Debug NoDX|Win32 @@ -67,6 +70,14 @@ Global {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release NoDX|Win32.Build.0 = Release|Win32 {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.ActiveCfg = Release|Win32 {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}.Release|Win32.Build.0 = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug NoDX|Win32.Build.0 = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Debug|Win32.Build.0 = Debug|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release NoDX|Win32.ActiveCfg = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release NoDX|Win32.Build.0 = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release|Win32.ActiveCfg = Release|Win32 + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/HookFilter/HookFilter-vs2013.vcxproj b/HookFilter/HookFilter-vs2013.vcxproj new file mode 100644 index 00000000..fcfb9fd7 --- /dev/null +++ b/HookFilter/HookFilter-vs2013.vcxproj @@ -0,0 +1,97 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + HookFilter + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} + HookFilter + Win32Proj + + + + DynamicLibrary + v120 + Unicode + true + + + DynamicLibrary + v120 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;HOOKFILTER_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + + + true + Windows + MachineX86 + + + + + + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;HOOKFILTER_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + + + + + + + \ No newline at end of file diff --git a/HookFilter/HookFilter-vs2013.vcxproj.filters b/HookFilter/HookFilter-vs2013.vcxproj.filters new file mode 100644 index 00000000..a87fdcc3 --- /dev/null +++ b/HookFilter/HookFilter-vs2013.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/HookFilter/HookFilter-vs2017.vcxproj b/HookFilter/HookFilter-vs2017.vcxproj new file mode 100644 index 00000000..28acb546 --- /dev/null +++ b/HookFilter/HookFilter-vs2017.vcxproj @@ -0,0 +1,97 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + HookFilter + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} + HookFilter + Win32Proj + + + + DynamicLibrary + v141 + Unicode + true + + + DynamicLibrary + v141 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>15.0.26419.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;HOOKFILTER_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + EditAndContinue + + + true + Windows + MachineX86 + + + + + + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;HOOKFILTER_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + + + + + + + \ No newline at end of file diff --git a/HookFilter/HookFilter-vs2017.vcxproj.filters b/HookFilter/HookFilter-vs2017.vcxproj.filters new file mode 100644 index 00000000..a87fdcc3 --- /dev/null +++ b/HookFilter/HookFilter-vs2017.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index 67a18d48..0ec04004 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -1,7 +1,5 @@ #include -// https://stackoverflow.com/questions/2490577/suppress-task-switch-keys-winkey-alt-tab-alt-esc-ctrl-esc-using-low-level-k - static HWND g_hFrameWindow = (HWND)0; // NB. __stdcall (or WINAPI) and extern "C": From e0da17ed96cdbcf60241b98ce7068dc9898f6160 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 10 Jun 2018 17:01:44 +0100 Subject: [PATCH 020/128] Removed all VS2012 proj/slns (#559) --- AppleWinExpress2012.sln | 50 -- AppleWinExpress2012.vcxproj | 424 ----------------- AppleWinExpress2012.vcxproj.filters | 659 -------------------------- source/NTSC.cpp | 2 +- zip_lib/zip_lib2012.vcxproj | 96 ---- zip_lib/zip_lib2012.vcxproj.filters | 46 -- zlib/zlib-Express2012.vcxproj | 106 ----- zlib/zlib-Express2012.vcxproj.filters | 82 ---- 8 files changed, 1 insertion(+), 1464 deletions(-) delete mode 100644 AppleWinExpress2012.sln delete mode 100644 AppleWinExpress2012.vcxproj delete mode 100644 AppleWinExpress2012.vcxproj.filters delete mode 100644 zip_lib/zip_lib2012.vcxproj delete mode 100644 zip_lib/zip_lib2012.vcxproj.filters delete mode 100644 zlib/zlib-Express2012.vcxproj delete mode 100644 zlib/zlib-Express2012.vcxproj.filters diff --git a/AppleWinExpress2012.sln b/AppleWinExpress2012.sln deleted file mode 100644 index 49cd5e65..00000000 --- a/AppleWinExpress2012.sln +++ /dev/null @@ -1,50 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2012 for Windows Desktop -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppleWin", "AppleWinExpress2012.vcxproj", "{0A960136-A00A-4D4B-805F-664D9950D2CA}" - ProjectSection(ProjectDependencies) = postProject - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} = {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E} = {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zip_lib", "zip_lib\zip_lib2012.vcxproj", "{509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib-Express2012.vcxproj", "{9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug NoDX|Win32 = Debug NoDX|Win32 - Debug|Win32 = Debug|Win32 - Release NoDX|Win32 = Release NoDX|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0A960136-A00A-4D4B-805F-664D9950D2CA}.Debug NoDX|Win32.ActiveCfg = Debug NoDX|Win32 - {0A960136-A00A-4D4B-805F-664D9950D2CA}.Debug NoDX|Win32.Build.0 = Debug NoDX|Win32 - {0A960136-A00A-4D4B-805F-664D9950D2CA}.Debug|Win32.ActiveCfg = Debug|Win32 - {0A960136-A00A-4D4B-805F-664D9950D2CA}.Debug|Win32.Build.0 = Debug|Win32 - {0A960136-A00A-4D4B-805F-664D9950D2CA}.Release NoDX|Win32.ActiveCfg = Release NoDX|Win32 - {0A960136-A00A-4D4B-805F-664D9950D2CA}.Release NoDX|Win32.Build.0 = Release NoDX|Win32 - {0A960136-A00A-4D4B-805F-664D9950D2CA}.Release|Win32.ActiveCfg = Release|Win32 - {0A960136-A00A-4D4B-805F-664D9950D2CA}.Release|Win32.Build.0 = Release|Win32 - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Debug NoDX|Win32.Build.0 = Debug|Win32 - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Debug|Win32.ActiveCfg = Debug|Win32 - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Debug|Win32.Build.0 = Debug|Win32 - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Release NoDX|Win32.ActiveCfg = Release|Win32 - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Release NoDX|Win32.Build.0 = Release|Win32 - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Release|Win32.ActiveCfg = Release|Win32 - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}.Release|Win32.Build.0 = Release|Win32 - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Debug NoDX|Win32.ActiveCfg = Debug|Win32 - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Debug NoDX|Win32.Build.0 = Debug|Win32 - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Debug|Win32.ActiveCfg = Debug|Win32 - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Debug|Win32.Build.0 = Debug|Win32 - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release NoDX|Win32.ActiveCfg = Release|Win32 - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release NoDX|Win32.Build.0 = Release|Win32 - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release|Win32.ActiveCfg = Release|Win32 - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/AppleWinExpress2012.vcxproj b/AppleWinExpress2012.vcxproj deleted file mode 100644 index 42ba5edb..00000000 --- a/AppleWinExpress2012.vcxproj +++ /dev/null @@ -1,424 +0,0 @@ - - - - - Debug NoDX - Win32 - - - Debug - Win32 - - - Release NoDX - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - {509739e7-0af3-4c09-a1a9-f0b1bc31b39d} - - - {9b32a6e7-1237-4f36-8903-a3fd51df9c4e} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {0A960136-A00A-4D4B-805F-664D9950D2CA} - Win32Proj - AppleWinExpress2012 - AppleWin - - - - Application - true - v110 - MultiByte - - - Application - true - v110 - MultiByte - - - Application - false - v110 - false - MultiByte - - - Application - false - v110 - false - MultiByte - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) - true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) - MultiThreadedDebug - - - Windows - true - htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) - "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) - true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) - MultiThreadedDebug - - - Windows - true - htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) - "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) - true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) - MultiThreaded - Speed - - - Windows - true - true - true - htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) - true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) - MultiThreaded - Speed - - - Windows - true - true - true - htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - "type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'" - - - - - - \ No newline at end of file diff --git a/AppleWinExpress2012.vcxproj.filters b/AppleWinExpress2012.vcxproj.filters deleted file mode 100644 index 81d4fde5..00000000 --- a/AppleWinExpress2012.vcxproj.filters +++ /dev/null @@ -1,659 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {a9a09086-bbce-46ea-8b29-f18a8df8732b} - - - {d1228537-59c3-4a6c-92fd-d7ba9d4efab7} - - - {d614ba59-527b-4acb-842e-7b61ca7f694f} - - - {2e94f8a1-5598-4bed-8365-add09bca1f56} - - - {71ec7de0-6ba1-4de1-9bc8-bdc3597e62cd} - - - {2c27fcf6-cf59-4359-9e15-2de64af1a94f} - - - {9b13bfc1-31ab-4f55-bb69-b8620ebdc2be} - - - {15b450e4-f89f-4d80-9c44-48b32f33f3e3} - - - {9bcc8097-f610-4843-bd76-a313aa54fbb0} - - - {f688ce36-1417-440c-b844-f2180a0017a9} - - - {4cecf5fc-1fe3-425f-907a-b62a6d046d45} - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files\_Headers - - - Source Files\_Headers - - - Source Files\_Headers - - - Source Files\_Headers - - - Source Files - - - Source Files - - - Source Files\CommonVICE - - - Source Files\CommonVICE - - - Source Files\CommonVICE - - - Source Files\CommonVICE - - - Source Files\CommonVICE - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\CPU - - - Source Files\CPU - - - Source Files\CPU - - - Source Files\CPU - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Disk - - - Source Files\Disk - - - Source Files\Disk - - - Source Files\Disk - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Z80VICE - - - Source Files\Z80VICE - - - Source Files\Z80VICE - - - Source Files\Z80VICE - - - Source Files\Video - - - Source Files\Video - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Resource Files - - - Source Files\Disk - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Model - - - - - Docs - - - Docs - - - Docs - - - Docs - - - Docs - - - Docs - - - Docs - - - - - Source Files - - - Source Files - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\Configuration - - - Source Files\CPU - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Debugger - - - Source Files\Disk - - - Source Files\Disk - - - Source Files\Disk - - - Source Files\Disk - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Emulator - - - Source Files\Z80VICE - - - Source Files\Z80VICE - - - Source Files\Z80VICE - - - Source Files\Video - - - Source Files\Video - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Uthernet - - - Source Files\Model - - - - - Source Files\CPU - - - Source Files\CPU - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 42d35096..a167b811 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1631,7 +1631,7 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++) { uint32_t offset = sizeof(bgra_t) * GetFrameBufferWidth() * ((GetFrameBufferHeight() - 1) - y - GetFrameBufferBorderHeight()) + (sizeof(bgra_t) * GetFrameBufferBorderWidth()); - offset -= sizeof(bgra_t); // GH#555: Start 1 RGBA pixel before frame to account for g_nLastColumnPixelNTSC +// offset -= sizeof(bgra_t); // GH#555: Start 1 RGBA pixel before frame to account for g_nLastColumnPixelNTSC g_pScanLines[y] = (bgra_t*) (g_pFramebufferbits + offset); } diff --git a/zip_lib/zip_lib2012.vcxproj b/zip_lib/zip_lib2012.vcxproj deleted file mode 100644 index 77b67814..00000000 --- a/zip_lib/zip_lib2012.vcxproj +++ /dev/null @@ -1,96 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - - - - {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} - Win32Proj - zip_lib - zip_lib - - - - StaticLibrary - true - v110 - MultiByte - - - StaticLibrary - false - v110 - true - MultiByte - - - - - - - - - - - - - - - NotUsing - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - ..\zlib;%(AdditionalIncludeDirectories) - MultiThreadedDebug - - - Windows - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - ..\zlib;%(AdditionalIncludeDirectories) - MultiThreaded - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/zip_lib/zip_lib2012.vcxproj.filters b/zip_lib/zip_lib2012.vcxproj.filters deleted file mode 100644 index c7a6d9c7..00000000 --- a/zip_lib/zip_lib2012.vcxproj.filters +++ /dev/null @@ -1,46 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/zlib/zlib-Express2012.vcxproj b/zlib/zlib-Express2012.vcxproj deleted file mode 100644 index 6678d4dd..00000000 --- a/zlib/zlib-Express2012.vcxproj +++ /dev/null @@ -1,106 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {9B32A6E7-1237-4F36-8903-A3FD51DF9C4E} - Win32Proj - zlib - zlib - - - - StaticLibrary - true - v110 - MultiByte - - - StaticLibrary - false - v110 - true - MultiByte - - - - - - - - - - - - - - - NotUsing - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - MultiThreadedDebug - - - Windows - true - - - - - Level3 - NotUsing - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - MultiThreaded - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/zlib/zlib-Express2012.vcxproj.filters b/zlib/zlib-Express2012.vcxproj.filters deleted file mode 100644 index 5cdde106..00000000 --- a/zlib/zlib-Express2012.vcxproj.filters +++ /dev/null @@ -1,82 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file From d2a34dfae051da2cc629cb4ad37df9caf9c7626b Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 10 Jun 2018 17:08:32 +0100 Subject: [PATCH 021/128] Removed all VS2005 proj/slns (#559) --- ApplewinExpress2005.sln | 36 -- ApplewinExpress2005.vcproj | 970 ----------------------------------- zip_lib/zip_lib2005.vcproj | 205 -------- zlib/zlib-Express2005.vcproj | 251 --------- 4 files changed, 1462 deletions(-) delete mode 100644 ApplewinExpress2005.sln delete mode 100644 ApplewinExpress2005.vcproj delete mode 100644 zip_lib/zip_lib2005.vcproj delete mode 100644 zlib/zlib-Express2005.vcproj diff --git a/ApplewinExpress2005.sln b/ApplewinExpress2005.sln deleted file mode 100644 index efb869d5..00000000 --- a/ApplewinExpress2005.sln +++ /dev/null @@ -1,36 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual C++ Express 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Applewin", "ApplewinExpress2005.vcproj", "{1DA0C491-B5F4-4EC8-B1D2-CF6BE635DADC}" - ProjectSection(ProjectDependencies) = postProject - {7935B998-C713-42AE-8F6D-9FF9080A1B1B} = {7935B998-C713-42AE-8F6D-9FF9080A1B1B} - {709278B8-C583-4BD8-90DE-4E4F35A3BD8B} = {709278B8-C583-4BD8-90DE-4E4F35A3BD8B} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib-Express2005.vcproj", "{7935B998-C713-42AE-8F6D-9FF9080A1B1B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zip_lib", "zip_lib\zip_lib2005.vcproj", "{709278B8-C583-4BD8-90DE-4E4F35A3BD8B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1DA0C491-B5F4-4EC8-B1D2-CF6BE635DADC}.Debug|Win32.ActiveCfg = Debug|Win32 - {1DA0C491-B5F4-4EC8-B1D2-CF6BE635DADC}.Debug|Win32.Build.0 = Debug|Win32 - {1DA0C491-B5F4-4EC8-B1D2-CF6BE635DADC}.Release|Win32.ActiveCfg = Release|Win32 - {1DA0C491-B5F4-4EC8-B1D2-CF6BE635DADC}.Release|Win32.Build.0 = Release|Win32 - {7935B998-C713-42AE-8F6D-9FF9080A1B1B}.Debug|Win32.ActiveCfg = Debug|Win32 - {7935B998-C713-42AE-8F6D-9FF9080A1B1B}.Debug|Win32.Build.0 = Debug|Win32 - {7935B998-C713-42AE-8F6D-9FF9080A1B1B}.Release|Win32.ActiveCfg = Release|Win32 - {7935B998-C713-42AE-8F6D-9FF9080A1B1B}.Release|Win32.Build.0 = Release|Win32 - {709278B8-C583-4BD8-90DE-4E4F35A3BD8B}.Debug|Win32.ActiveCfg = Debug|Win32 - {709278B8-C583-4BD8-90DE-4E4F35A3BD8B}.Debug|Win32.Build.0 = Debug|Win32 - {709278B8-C583-4BD8-90DE-4E4F35A3BD8B}.Release|Win32.ActiveCfg = Release|Win32 - {709278B8-C583-4BD8-90DE-4E4F35A3BD8B}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/ApplewinExpress2005.vcproj b/ApplewinExpress2005.vcproj deleted file mode 100644 index 10e6908f..00000000 --- a/ApplewinExpress2005.vcproj +++ /dev/null @@ -1,970 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/zip_lib/zip_lib2005.vcproj b/zip_lib/zip_lib2005.vcproj deleted file mode 100644 index 6058b37c..00000000 --- a/zip_lib/zip_lib2005.vcproj +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/zlib/zlib-Express2005.vcproj b/zlib/zlib-Express2005.vcproj deleted file mode 100644 index 8cbd2679..00000000 --- a/zlib/zlib-Express2005.vcproj +++ /dev/null @@ -1,251 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 4a0e93fe28dfc63b03b146cf7dbb52e253747883 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 10 Jun 2018 18:14:34 +0100 Subject: [PATCH 022/128] Added new -alt-enter cmd-line switch to allow configuration of Alt+Enter behaviour (#556) --- help/CommandLine.html | 7 ++++++- help/keyboard.html | 2 +- source/Applewin.cpp | 8 ++++++++ source/Frame.cpp | 20 +++++++++++++++----- source/Frame.h | 2 ++ 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/help/CommandLine.html b/help/CommandLine.html index 106d71c6..0d48ca57 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -68,8 +68,13 @@

              -dcd
              For the SSC's 6551's Status register's DCD bit, use this switch to force AppleWin to use the state of the MS_RLSD_ON bit from GetCommModemStatus().

              + -alt-enter=<toggle-full-screen|open-apple-enter>
              + Define the behavior of Alt+Enter: +
                +
              • Either: Toggle between windowed and full screen video modes (default). +
              • Or: Allow the emulated Apple II to read the Enter key state when Alt (Open Apple key) is pressed. +
              -

              Debug arguments:

              diff --git a/help/keyboard.html b/help/keyboard.html index 527e0658..5e6de04d 100644 --- a/help/keyboard.html +++ b/help/keyboard.html @@ -73,7 +73,7 @@

              Ctrl+PrintScrn:
              Copy the text screen (auto detect 40/80 columns) to the clipboard.

              Alt+Enter:
              - Toggle between windowed and full screen video modes. (NB. Will conflict with emulation when doing Open Apple + Enter.)

              + Default: Toggle between windowed and full screen video modes. (NB. Will conflict with emulation and prevent Open Apple + Enter from being readable. Use the Command Line switch to allow Open Apple + Enter to be readable.)

              Function Keys F1-F8:
              These PC function keys correspond to buttons on the toolbar.

              Function Key F2 + Ctrl:
              diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 512cc541..188ab1b7 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1257,6 +1257,14 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { sg_SSC.SupportDCD(true); } + else if (strcmp(lpCmdLine, "-alt-enter=toggle-full-screen") == 0) // GH#556 + { + SetAltEnterToggleFullScreen(true); + } + else if (strcmp(lpCmdLine, "-alt-enter=open-apple-enter") == 0) // GH#556 + { + SetAltEnterToggleFullScreen(false); + } else // unsupported { LogFileOutput("Unsupported arg: %s\n", lpCmdLine); diff --git a/source/Frame.cpp b/source/Frame.cpp index 6a6f0c98..ee031b02 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -175,6 +175,15 @@ void ScreenWindowResize(const bool bCtrlKey); void FrameResizeWindow(int nNewScale); +// ========================================================================== + +static bool g_bAltEnter_ToggleFullScreen = true; // Default for ALT+ENTER is to toggle between windowed and full-screen modes + +void SetAltEnterToggleFullScreen(bool mode) +{ + g_bAltEnter_ToggleFullScreen = mode; +} + // ========================================================================== // Display construction: @@ -1733,15 +1742,15 @@ LRESULT CALLBACK FrameWndProc ( } break; - case WM_SYSKEYDOWN: + case WM_SYSKEYDOWN: // ALT + any key; or F10 KeybUpdateCtrlShiftStatus(); // http://msdn.microsoft.com/en-us/library/windows/desktop/gg153546(v=vs.85).aspx // v1.25.0: Alt-Return Alt-Enter toggle fullscreen - if (g_bAltKey && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU + if (g_bAltEnter_ToggleFullScreen && g_bAltKey && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU return 0; // NOP -- eat key - else - PostMessage(window,WM_KEYDOWN,wparam,lparam); + + PostMessage(window,WM_KEYDOWN,wparam,lparam); if ((wparam == VK_F10) || (wparam == VK_MENU)) // VK_MENU == ALT Key return 0; @@ -1752,10 +1761,11 @@ LRESULT CALLBACK FrameWndProc ( KeybUpdateCtrlShiftStatus(); // v1.25.0: Alt-Return Alt-Enter toggle fullscreen - if (g_bAltKey && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU + if (g_bAltEnter_ToggleFullScreen && g_bAltKey && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU ScreenWindowResize(false); else PostMessage(window,WM_KEYUP,wparam,lparam); + break; case WM_MENUCHAR: // GH#556 - Suppress the Windows Default Beep (ie. Ding) whenever ALT+ is pressed diff --git a/source/Frame.h b/source/Frame.h index 0528bfe5..672b95e9 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -61,3 +61,5 @@ UINT GetFrameBufferHeight(void); UINT Get3DBorderWidth(void); UINT Get3DBorderHeight(void); + + void SetAltEnterToggleFullScreen(bool mode); From 734bc4cee2b8610fd539d12dcca79a725985b118 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 12 Jun 2018 21:50:27 +0100 Subject: [PATCH 023/128] AKD: Support both Return and Enter (and other extended keys). (#330) --- source/Frame.cpp | 10 +++++----- source/Keyboard.cpp | 19 ++++++++++++++----- source/Keyboard.h | 2 +- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index ee031b02..245245bf 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1394,7 +1394,7 @@ LRESULT CALLBACK FrameWndProc ( // Note about Alt Gr (Right-Alt): // . WM_KEYDOWN[Left-Control], then: // . WM_KEYDOWN[Right-Alt] - BOOL extended = (HIWORD(lparam) & KF_EXTENDED) != 0; + bool extended = (HIWORD(lparam) & KF_EXTENDED) != 0; BOOL down = 1; BOOL autorep = (HIWORD(lparam) & KF_REPEAT) != 0; BOOL IsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); @@ -1403,8 +1403,8 @@ LRESULT CALLBACK FrameWndProc ( { KeybQueueKeypress((int)wparam, NOT_ASCII); - if ((HIWORD(lparam) & KF_REPEAT) == 0) - KeybAnyKeyDown(WM_KEYDOWN, wparam); + if (!autorep) + KeybAnyKeyDown(WM_KEYDOWN, wparam, extended); } } else if (g_nAppMode == MODE_DEBUG) @@ -1426,13 +1426,13 @@ LRESULT CALLBACK FrameWndProc ( } else { - BOOL extended = (HIWORD(lparam) & KF_EXTENDED) != 0; + bool extended = (HIWORD(lparam) & KF_EXTENDED) != 0; BOOL down = 0; BOOL autorep = 0; BOOL bIsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); if (!bIsJoyKey) - KeybAnyKeyDown(WM_KEYUP, wparam); + KeybAnyKeyDown(WM_KEYUP, wparam, extended); } break; diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index ce02585b..70146809 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -390,11 +390,13 @@ static char ClipboardCurrChar(bool bIncPtr) //=========================================================================== -static uint64_t g_AKDFlags[4] = {0,0,0,0}; +const UINT kAKDNumElements = 256/64; +static uint64_t g_AKDFlags[2][kAKDNumElements] = { {0,0,0,0}, // normal + {0,0,0,0}}; // extended // NB. Don't need to be concerned about if numpad/cursors are used for joystick, // since parent calls JoyProcessKey() just before this. -void KeybAnyKeyDown(UINT message, WPARAM wparam) +void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended) { if (wparam > 255) { @@ -419,17 +421,24 @@ void KeybAnyKeyDown(UINT message, WPARAM wparam) { UINT offset = wparam >> 6; UINT bit = wparam & 0x3f; + UINT idx = !bIsExtended ? 0 : 1; if (message == WM_KEYDOWN) - g_AKDFlags[offset] |= (1LL< Date: Sat, 16 Jun 2018 10:24:05 +0100 Subject: [PATCH 024/128] Hook system keys: (#556) . added -no-hook-system-key to prevent hooking system keys . updated help . HookFilter.dll: changed to directly send virtual key code --- HookFilter/HookFilter.cpp | 10 +++------- help/CommandLine.html | 2 ++ source/Applewin.cpp | 37 ++++++++++++++++++++++++++----------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index 0ec04004..fcf3bf33 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -20,28 +20,24 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( UINT newMsg = pKbdLlHookStruct->flags & LLKHF_UP ? WM_KEYUP : WM_KEYDOWN; LPARAM newlParam = newMsg == WM_KEYUP ? 3<<30 : 0; // b31:transition state, b30:previous key state - // Note about PostMessage() and use of VkKeyScan(): - // . Convert the ascii code to virtual key code, so that the message pump can do TranslateMessage() - // . NB. From MSDN for "WM_KEYDOWN" && "WM_KEYUP" : "Applications must pass wParam to TranslateMessage without altering it at all." - // Suppress alt-tab if (pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) { - PostMessage(g_hFrameWindow, newMsg, LOBYTE(VkKeyScan(0x09)), newlParam); + PostMessage(g_hFrameWindow, newMsg, VK_TAB, newlParam); suppress = true; } // Suppress alt-escape if (pKbdLlHookStruct->vkCode == VK_ESCAPE && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) { - PostMessage(g_hFrameWindow, newMsg, LOBYTE(VkKeyScan(0x1B)), newlParam); + PostMessage(g_hFrameWindow, newMsg, VK_ESCAPE, newlParam); suppress = true; } // Suppress alt-space if (pKbdLlHookStruct->vkCode == VK_SPACE && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) { - PostMessage(g_hFrameWindow, newMsg, LOBYTE(VkKeyScan(0x20)), newlParam); + PostMessage(g_hFrameWindow, newMsg, VK_SPACE, newlParam); suppress = true; } diff --git a/help/CommandLine.html b/help/CommandLine.html index 0d48ca57..f8c17778 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -42,6 +42,8 @@ Enable the dialog box to display the last file saved to

              -no-printscreen-key
              Prevent the PrintScreen key from being registered

              + -no-hook-system-key
              + Prevent certain system key combinations from being hooked (to prevent the emulator from trapping ALT+ESC, ALT+SPACE, ALT+TAB and CTRL+ESC). This means that the equivalent Open Apple+<key> combinations won't work within the emulator.

              -use-real-printer
              Enables Advanced configuration control to allow dumping to a real printer

              -noreg
              diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 188ab1b7..de24d066 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -78,6 +78,8 @@ TCHAR g_sProgramDir[MAX_PATH] = TEXT(""); // Directory of where AppleWin exe TCHAR g_sDebugDir [MAX_PATH] = TEXT(""); // TODO: Not currently used TCHAR g_sScreenShotDir[MAX_PATH] = TEXT(""); // TODO: Not currently used bool g_bCapturePrintScreenKey = true; +static bool g_bHookSystemKey = true; + TCHAR g_sCurrentDir[MAX_PATH] = TEXT(""); // Also Starting Dir. Debugger uses this when load/save bool g_bRestart = false; bool g_bRestartFullScreen = false; @@ -871,7 +873,7 @@ static HINSTANCE g_hinstDLL = 0; static HHOOK g_hhook = 0; // Pre: g_hFrameWindow must be valid -void HookFilterForKeyboard() +bool HookFilterForKeyboard() { g_hinstDLL = LoadLibrary(TEXT("HookFilter.dll")); @@ -890,16 +892,17 @@ void HookFilterForKeyboard() g_hinstDLL, 0); - if (g_hhook == 0 || g_hFrameWindow == 0) - { - std::string msg("Failed to install hook filter for system keys"); + if (g_hhook != 0 && g_hFrameWindow != 0) + return true; - DWORD dwErr = GetLastError(); - MessageBox(GetDesktopWindow(), msg.c_str(), "Warning", MB_ICONASTERISK | MB_OK); + std::string msg("Failed to install hook filter for system keys"); - msg += "\n"; - LogFileOutput(msg.c_str()); - } + DWORD dwErr = GetLastError(); + MessageBox(GetDesktopWindow(), msg.c_str(), "Warning", MB_ICONASTERISK | MB_OK); + + msg += "\n"; + LogFileOutput(msg.c_str()); + return false; } void UnhookFilterForKeyboard() @@ -1227,6 +1230,10 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { g_bShowPrintScreenWarningDialog = false; } + else if (strcmp(lpCmdLine, "-no-hook-system-key") == 0) // Don't hook the System keys (eg. Left-ALT+ESC/SPACE/TAB) GH#556 + { + g_bHookSystemKey = false; + } else if (strcmp(lpCmdLine, "-spkr-inc") == 0) { lpCmdLine = GetCurrArg(lpNextArg); @@ -1419,7 +1426,11 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) LogFileOutput("Main: RegisterHotKeys()\n"); } - HookFilterForKeyboard(); // needs valid g_hFrameWindow (for message pump) + if (g_bHookSystemKey) + { + if (HookFilterForKeyboard()) // needs valid g_hFrameWindow (for message pump) + LogFileOutput("Main: HookFilterForKeyboard()\n"); + } // Need to test if it's safe to call ResetMachineState(). In the meantime, just call DiskReset(): DiskReset(); // Switch from a booting A][+ to a non-autostart A][, so need to turn off floppy motor @@ -1527,7 +1538,11 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) DSUninit(); LogFileOutput("Main: DSUninit()\n"); - UnhookFilterForKeyboard(); + if (g_bHookSystemKey) + { + UnhookFilterForKeyboard(); + LogFileOutput("Main: UnhookFilterForKeyboard()\n"); + } } while (g_bRestart); From 6ad262128273c111df3def1acdbfea326e0a5cf5 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 16 Jun 2018 11:36:43 +0100 Subject: [PATCH 025/128] Fixed save-state not saving last key & update history.txt --- bin/History.txt | 9 +++++++++ source/Keyboard.cpp | 9 +++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index f121102d..ccf66a23 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -9,6 +9,15 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.27.5.0 - dd mmm 2018 +---------------------- +. [Bug #556] Allow system key combinations to be read: Open Apple (left ALT) + ESC/SPACE/TAB. + - Also fixes #145, #198, #448. + - Support new command line switches: -no-hook-system-key, -alt-enter= + - Fix for save-state which wasn't correctly saving last key. +. [Bug #330] Any Key Down (AKD) wasn't working for the multi-key case. + + 1.27.4.0 - 26 May 2018 ---------------------- . [Bug #555] Fix for showing 559th DHGR vertical column. diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 70146809..14341ec4 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -51,11 +51,8 @@ static bool g_bCapsLock = true; //Caps lock key for Apple2 and Lat/Cyr lock for static bool g_bP8CapsLock = true; //Caps lock key of Pravets 8A/C static int lastvirtkey = 0; // Current PC keycode static BYTE keycode = 0; // Current Apple keycode - static BOOL keywaiting = 0; -static BYTE g_nLastKey = 0x00; - // // ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- // @@ -513,7 +510,7 @@ void KeybToggleP8ACapsLock () void KeybSetSnapshot_v1(const BYTE LastKey) { - g_nLastKey = LastKey; + keycode = LastKey; } // @@ -529,7 +526,7 @@ static std::string KeybGetSnapshotStructName(void) void KeybSaveSnapshot(YamlSaveHelper& yamlSaveHelper) { YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", KeybGetSnapshotStructName().c_str()); - yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_LASTKEY, g_nLastKey); + yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_LASTKEY, keycode); } void KeybLoadSnapshot(YamlLoadHelper& yamlLoadHelper) @@ -537,7 +534,7 @@ void KeybLoadSnapshot(YamlLoadHelper& yamlLoadHelper) if (!yamlLoadHelper.GetSubMap(KeybGetSnapshotStructName())) return; - g_nLastKey = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTKEY); + keycode = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTKEY); yamlLoadHelper.PopMap(); } From 7f478fa36cc32b5abf93e343d4fbc5138d5af883 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 17 Jun 2018 18:47:57 +0100 Subject: [PATCH 026/128] Mockingboard: Reading 6522's IER now returns 0x80|IER. (Fixes #567) --- source/Mockingboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp index 6af5d49d..96cc0ee5 100644 --- a/source/Mockingboard.cpp +++ b/source/Mockingboard.cpp @@ -549,7 +549,7 @@ static BYTE SY6522_Read(BYTE nDevice, BYTE nReg) nValue = pMB->sy6522.IFR; break; case 0x0e: // IER - nValue = 0x80; // Datasheet says this is 0x80|IER + nValue = 0x80 | pMB->sy6522.IER; // GH#567 break; case 0x0f: // ORA_NO_HS nValue = pMB->sy6522.ORA; From 9bc7feb37e34635c980195c02877435f807a9cb9 Mon Sep 17 00:00:00 2001 From: tomcw Date: Wed, 20 Jun 2018 22:12:19 +0100 Subject: [PATCH 027/128] Mockingboard: Better support for stop/starting 6522's IER.TIMERx (#567) --- source/Mockingboard.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp index 96cc0ee5..49e8bd23 100644 --- a/source/Mockingboard.cpp +++ b/source/Mockingboard.cpp @@ -480,11 +480,11 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue) pMB->sy6522.IER |= nValue; UpdateIFR(pMB, 0); - // Check if active timer changed from non-interrupt (polling IFR) to interrupt: - if ((pMB->sy6522.IER & IxR_TIMER1) && pMB->bTimer1Active) + // Check if a timer interrupt has been enabled (regardless of if there's an active timer or not): GH#567 + if (pMB->sy6522.IER & IxR_TIMER1) StartTimer1(pMB); - if ((pMB->sy6522.IER & IxR_TIMER2) && pMB->bTimer2Active) + if (pMB->sy6522.IER & IxR_TIMER2) StartTimer2(pMB); } break; From 47ec7f435542d26d5802c79d165784af25b362b7 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 23 Jun 2018 17:50:23 +0100 Subject: [PATCH 028/128] Reverted ad12a8e: video rendering from screen position -1: so now DHGR vertical column 559 is hidden again (see #555). Changed HGR rendering, such that that last video byte (at hpos=64) clears g_nLastColumnPixelNTSC so that the end-of-line off-screen pixel is zero (see #555). --- source/NTSC.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index a167b811..ec480f67 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1291,6 +1291,14 @@ void updateScreenSingleHires40 (long cycles6502) if (m & 0x80) bits = (bits << 1) | g_nLastColumnPixelNTSC; updatePixels( bits ); + + // For last hpos && bit6=1: (GH#555) + // * if bit7=0 (no shift) then clear g_nLastColumnPixelNTSC to prevent a 3rd 14M (aka DHGR) pixel being drawn + // . even though this is off-screen, it still has an on-screen affect (making the green dot more white on the screen edge). + // * if bit7=1 (half-dot shift) then also clear g_nLastColumnPixelNTSC + // . not sure if this is correct though + if (g_nVideoClockHorz == (VIDEO_SCANNER_MAX_HORZ-1)) + g_nLastColumnPixelNTSC = 0; } } updateVideoScannerHorzEOL(); @@ -1631,7 +1639,7 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++) { uint32_t offset = sizeof(bgra_t) * GetFrameBufferWidth() * ((GetFrameBufferHeight() - 1) - y - GetFrameBufferBorderHeight()) + (sizeof(bgra_t) * GetFrameBufferBorderWidth()); -// offset -= sizeof(bgra_t); // GH#555: Start 1 RGBA pixel before frame to account for g_nLastColumnPixelNTSC +// offset -= sizeof(bgra_t); // GH#555: Start 1 RGBA pixel before frame to account for g_nLastColumnPixelNTSC // TC: revert as lose half an HGR pixel on left-edge g_pScanLines[y] = (bgra_t*) (g_pFramebufferbits + offset); } From 5f87cc0f7cfe72c794b8bada6361e7de12685d64 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 24 Jun 2018 10:19:27 +0100 Subject: [PATCH 029/128] 1.27.5: Bump version & update History.txt --- bin/History.txt | 5 ++++- resource/Applewin.rc | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index ccf66a23..4c2ec95e 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -9,12 +9,15 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth -1.27.5.0 - dd mmm 2018 +1.27.5.0 - 24 Jun 2018 ---------------------- +. [Bug #567] Fixed Mockingboard/6522: Reading the 6522's IER now returns 0x80|IER. . [Bug #556] Allow system key combinations to be read: Open Apple (left ALT) + ESC/SPACE/TAB. - Also fixes #145, #198, #448. - Support new command line switches: -no-hook-system-key, -alt-enter= - Fix for save-state which wasn't correctly saving last key. +. [Bug #555] Reverted 1.27.4's "Fix for showing 559th DHGR vertical column". + - So 559th DHGR vertical column remains hidden (this is still a bug). . [Bug #330] Any Key Down (AKD) wasn't working for the multi-key case. diff --git a/resource/Applewin.rc b/resource/Applewin.rc index cdd1c6b2..c207be7c 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,4,0 - PRODUCTVERSION 1,27,4,0 + FILEVERSION 1,27,5,0 + PRODUCTVERSION 1,27,5,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 4, 0" + VALUE "FileVersion", "1, 27, 5, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 4, 0" + VALUE "ProductVersion", "1, 27, 5, 0" END END BLOCK "VarFileInfo" From 9cacf8d90df019c73d76446349f5fa4372918b47 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 30 Jun 2018 14:30:30 +0100 Subject: [PATCH 030/128] Small refactor for reading $C01x soft switch status flags Prevent Apple II from reading $C01x/$C07F soft switch status flags --- source/Keyboard.cpp | 6 ++-- source/Keyboard.h | 6 ++-- source/Memory.cpp | 71 ++++++++++++++++----------------------------- source/Memory.h | 1 - source/Video.cpp | 28 ------------------ source/Video.h | 4 --- 6 files changed, 30 insertions(+), 86 deletions(-) diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 14341ec4..b9734da3 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -108,7 +108,7 @@ void KeybUpdateCtrlShiftStatus() } //=========================================================================== -BYTE KeybGetKeycode () // Used by MemCheckPaging() & VideoCheckMode() +BYTE KeybGetKeycode () // Used by IORead_C01x() and TapeRead() for Pravets8A { return keycode; } @@ -440,7 +440,7 @@ static bool IsAKD(void) //=========================================================================== -BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) +BYTE KeybReadData (void) { LogFileTimeUntilFirstKeyRead(); @@ -462,7 +462,7 @@ BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) //=========================================================================== -BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG) +BYTE KeybReadFlag (void) { if (g_bPasteFromClipboard) ClipboardInit(); diff --git a/source/Keyboard.h b/source/Keyboard.h index d6236b56..c5518620 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -15,14 +15,12 @@ void KeybQueueKeypress (int,BOOL); void KeybToggleCapsLock (); void KeybToggleP8ACapsLock (); void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended); +BYTE KeybReadData (void); +BYTE KeybReadFlag (void); void KeybSetSnapshot_v1(const BYTE LastKey); void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); -BYTE __stdcall KeybReadData (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); -BYTE __stdcall KeybReadFlag (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); -BYTE __stdcall KbdAllow8Bit (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); //For Pravets A/C only - extern bool g_bShiftKey; extern bool g_bCtrlKey; extern bool g_bAltKey; diff --git a/source/Memory.cpp b/source/Memory.cpp index a0bb58da..d7537bc3 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -209,7 +209,7 @@ BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYT static BYTE __stdcall IORead_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles) { - return KeybReadData(pc, addr, bWrite, d, nExecutedCycles); + return KeybReadData(); } static BYTE __stdcall IOWrite_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles) @@ -224,32 +224,36 @@ static BYTE __stdcall IOWrite_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON static BYTE __stdcall IORead_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles) { + if (IS_APPLE2) // Include Pravets machines too? + return KeybReadFlag(); + + bool res = false; switch (addr & 0xf) { - case 0x0: return KeybReadFlag(pc, addr, bWrite, d, nExecutedCycles); - case 0x1: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0x2: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0x3: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0x4: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0x5: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0x6: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0x7: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0x8: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0x9: return VideoCheckVbl(nExecutedCycles); - case 0xA: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles); - case 0xB: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles); - case 0xC: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0xD: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles); - case 0xE: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles); - case 0xF: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles); + case 0x0: return KeybReadFlag(); + case 0x1: res = SW_BANK2 ? true : false; break; + case 0x2: res = SW_HIGHRAM ? true : false; break; + case 0x3: res = SW_AUXREAD ? true : false; break; + case 0x4: res = SW_AUXWRITE ? true : false; break; + case 0x5: res = SW_INTCXROM ? true : false; break; + case 0x6: res = SW_ALTZP ? true : false; break; + case 0x7: res = SW_SLOTC3ROM ? true : false; break; + case 0x8: res = SW_80STORE ? true : false; break; + case 0x9: res = VideoGetVblBar(nExecutedCycles); break; + case 0xA: res = VideoGetSWTEXT(); break; + case 0xB: res = VideoGetSWMIXED(); break; + case 0xC: res = SW_PAGE2 ? true : false; break; + case 0xD: res = VideoGetSWHIRES(); break; + case 0xE: res = VideoGetSWAltCharSet(); break; + case 0xF: res = VideoGetSW80COL(); break; } - return 0; + return KeybGetKeycode() | (res ? 0x80 : 0); } static BYTE __stdcall IOWrite_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles) { - return KeybReadFlag(pc, addr, bWrite, d, nExecutedCycles); + return KeybReadFlag(); } //------------------------------------- @@ -344,8 +348,6 @@ static BYTE __stdcall IOWrite_C05x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON static BYTE __stdcall IORead_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles) { - static byte CurrentKestroke = 0; - CurrentKestroke = KeybGetKeycode(); switch (addr & 0x7) // address bit 4 is ignored (UTAIIe:7-5) { //In Pravets8A/C if SETMODE (8bit character encoding) is enabled, bit6 in $C060 is 0; Else it is 1 @@ -399,7 +401,7 @@ static BYTE __stdcall IORead_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG case 0xC: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); case 0xD: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); case 0xE: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); - case 0xF: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles); + case 0xF: return MemReadFloatingBus(VideoGetSWDHIRES(), nExecutedCycles); } return 0; @@ -1016,29 +1018,6 @@ static void UpdatePaging(BOOL initialize) //=========================================================================== -// TODO: >= Apple2e only? -BYTE __stdcall MemCheckPaging(WORD, WORD address, BYTE, BYTE, ULONG) -{ - address &= 0xFF; - BOOL result = 0; - switch (address) - { - case 0x11: result = SW_BANK2; break; - case 0x12: result = SW_HIGHRAM; break; - case 0x13: result = SW_AUXREAD; break; - case 0x14: result = SW_AUXWRITE; break; - case 0x15: result = SW_INTCXROM; break; - case 0x16: result = SW_ALTZP; break; - case 0x17: result = SW_SLOTC3ROM; break; - case 0x18: result = SW_80STORE; break; - case 0x1C: result = SW_PAGE2; break; - case 0x1D: result = SW_HIRES; break; - } - return KeybGetKeycode() | (result ? 0x80 : 0); -} - -//=========================================================================== - void MemDestroy() { VirtualFree(memaux ,0,MEM_RELEASE); @@ -1648,7 +1627,7 @@ BYTE MemReadFloatingBus(const ULONG uExecutedCycles) BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles) { BYTE r = MemReadFloatingBus(uExecutedCycles); - return (r & ~0x80) | ((highbit) ? 0x80 : 0); + return (r & ~0x80) | (highbit ? 0x80 : 0); } //=========================================================================== diff --git a/source/Memory.h b/source/Memory.h index 9b75730b..191a5b26 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -99,5 +99,4 @@ bool MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT version); BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); -BYTE __stdcall MemCheckPaging (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); BYTE __stdcall MemSetPaging(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); diff --git a/source/Video.cpp b/source/Video.cpp index da2dd2a8..4ce1b145 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -338,34 +338,6 @@ void VideoBenchmark () { MB_ICONINFORMATION | MB_SETFOREGROUND); } -//=========================================================================== -BYTE VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) -{ - address &= 0xFF; - if (address == 0x7F) - return MemReadFloatingBus(SW_DHIRES != 0, uExecutedCycles); - else { - BOOL result = 0; - switch (address) { - case 0x1A: result = SW_TEXT; break; - case 0x1B: result = SW_MIXED; break; - case 0x1D: result = SW_HIRES; break; - case 0x1E: result = g_nAltCharSetOffset; break; - case 0x1F: result = SW_80COL; break; - case 0x7F: result = SW_DHIRES; break; - } - return KeybGetKeycode() | (result ? 0x80 : 0); - } -} - -//=========================================================================== -BYTE VideoCheckVbl ( ULONG uExecutedCycles ) -{ - bool bVblBar = VideoGetVblBar(uExecutedCycles); - BYTE r = KeybGetKeycode(); - return (r & ~0x80) | (bVblBar ? 0x80 : 0); - } - // This is called from PageConfig //=========================================================================== void VideoChooseMonochromeColor () diff --git a/source/Video.h b/source/Video.h index dbae4172..1e133a11 100644 --- a/source/Video.h +++ b/source/Video.h @@ -197,10 +197,6 @@ enum VideoScreenShot_e void Video_TakeScreenShot( VideoScreenShot_e iScreenShotType ); void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel ); - -// Win32/MSVC: __stdcall -BYTE VideoCheckMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); -BYTE VideoCheckVbl ( ULONG uExecutedCycles ); BYTE VideoSetMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); void Config_Load_Video(void); From 881e51874b9723f0280792c78f2217e4ed37f2bf Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 30 Jun 2018 18:21:28 +0100 Subject: [PATCH 031/128] Fix for other apps having sluggish key response - fixes #569 --- source/Applewin.cpp | 2 +- source/Memory.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index de24d066..356a869c 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -435,7 +435,7 @@ void EnterMessageLoop(void) else if (g_nAppMode == MODE_PAUSED) Sleep(1); // Stop process hogging CPU - 1ms, as need to fade-out speaker sound buffer else if (g_nAppMode == MODE_LOGO) - Sleep(100); // Stop process hogging CPU + Sleep(1); // Stop process hogging CPU (NB. don't delay for too long otherwise key input can be slow in other apps - GH#569) } } } diff --git a/source/Memory.cpp b/source/Memory.cpp index d7537bc3..79357f8d 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1831,6 +1831,7 @@ _done_saturn: UpdatePaging(0); // Initialize=0 } + // Replicate 80STORE, PAGE2 and HIRES to video sub-system if ((address <= 1) || ((address >= 0x54) && (address <= 0x57))) return VideoSetMode(programcounter,address,write,value,nExecutedCycles); From c457241229c8249f5582a6cff76fae23f99bfa81 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 15 Jul 2018 15:38:37 +0100 Subject: [PATCH 032/128] Keyboard: . When in MODE_LOGO, don't pass WM_CHAR to Apple II keyboard (now consistent with WM_KEYDOWN) . Small refactor for Apple II keyboard's WM_KEYDOWN handler Move code for log init & done to Log.cpp --- source/Applewin.cpp | 14 ++------------ source/Frame.cpp | 6 ++++-- source/Keyboard.cpp | 29 +++++++++++++++++++---------- source/Log.cpp | 25 +++++++++++++++++++++++++ source/Log.h | 6 ++++-- 5 files changed, 54 insertions(+), 26 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 356a869c..dc1c9315 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1077,12 +1077,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (((strcmp(lpCmdLine, "-l") == 0) || (strcmp(lpCmdLine, "-log") == 0)) && (g_fh == NULL)) { - g_fh = fopen("AppleWin.log", "a+t"); // Open log file (append & text mode) - setvbuf(g_fh, NULL, _IONBF, 0); // No buffering (so implicit fflush after every fprintf) - CHAR aDateStr[80], aTimeStr[80]; - GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aDateStr, sizeof(aDateStr)); - GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aTimeStr, sizeof(aTimeStr)); - fprintf(g_fh, "*** Logging started: %s %s\n", aDateStr, aTimeStr); + LogInit(); } else if (strcmp(lpCmdLine, "-noreg") == 0) { @@ -1559,12 +1554,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) tfe_shutdown(); LogFileOutput("Exit: tfe_shutdown()\n"); - if (g_fh) - { - fprintf(g_fh,"*** Logging ended\n\n"); - fclose(g_fh); - g_fh = NULL; - } + LogDone(); RiffFinishWriteFile(); diff --git a/source/Frame.cpp b/source/Frame.cpp index 245245bf..3b4803b5 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1098,7 +1098,8 @@ LRESULT CALLBACK FrameWndProc ( { if( !g_bDebuggerEatKey ) { - KeybQueueKeypress((int)wparam, ASCII); + if (g_nAppMode != MODE_LOGO) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard + KeybQueueKeypress((int)wparam, ASCII); } else { @@ -1399,7 +1400,8 @@ LRESULT CALLBACK FrameWndProc ( BOOL autorep = (HIWORD(lparam) & KF_REPEAT) != 0; BOOL IsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); - if (!IsJoyKey && (g_nAppMode != MODE_LOGO)) + if (!IsJoyKey && + (g_nAppMode != MODE_LOGO)) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard { KeybQueueKeypress((int)wparam, NOT_ASCII); diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index b9734da3..bd1bb24a 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -37,8 +37,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Video.h" // Needed by TK3000 //e, to refresh the frame at each |Mode| change static BYTE asciicode[2][10] = { - {0x08,0x0D,0x15,0x2F,0x00,0x00,0x00,0x00,0x00,0x00}, - {0x08,0x0B,0x15,0x0A,0x00,0x00,0x00,0x00,0x00,0x7F} + // VK_LEFT/UP/RIGHT/DOWN/SELECT, VK_PRINT/EXECUTE/SNAPSHOT/INSERT/DELETE + {0x08,0x0D,0x15,0x2F,0x00, 0x00,0x00,0x00,0x00,0x00}, // Apple II + {0x08,0x0B,0x15,0x0A,0x00, 0x00,0x00,0x00,0x00,0x7F} // Apple //e }; // Convert PC arrow keys to Apple keycodes bool g_bShiftKey = false; @@ -49,7 +50,6 @@ static bool g_bTK3KModeKey = false; //TK3000 //e |Mode| key static bool g_bCapsLock = true; //Caps lock key for Apple2 and Lat/Cyr lock for Pravets8 static bool g_bP8CapsLock = true; //Caps lock key of Pravets 8A/C -static int lastvirtkey = 0; // Current PC keycode static BYTE keycode = 0; // Current Apple keycode static BOOL keywaiting = 0; @@ -102,7 +102,7 @@ bool KeybGetShiftStatus () //=========================================================================== void KeybUpdateCtrlShiftStatus() { - g_bShiftKey = (GetKeyState( VK_SHIFT ) & KF_UP) ? true : false; // 0x8000 KF_UP + g_bShiftKey = (GetKeyState( VK_SHIFT ) & KF_UP) ? true : false; g_bCtrlKey = (GetKeyState( VK_CONTROL) & KF_UP) ? true : false; g_bAltKey = (GetKeyState( VK_MENU ) & KF_UP) ? true : false; } @@ -271,8 +271,6 @@ void KeybQueueKeypress (int key, BOOL bASCII) keycode = key; } } - - lastvirtkey = LOBYTE(VkKeyScan(key)); } else //(bASCII != ASCII) // WM_KEYDOWN { @@ -299,13 +297,24 @@ void KeybQueueKeypress (int key, BOOL bASCII) FrameRefreshStatus(DRAW_LEDS); // TODO: Implement |Mode| LED in the UI; make it appear only when in TK3000 mode VideoRedrawScreen(); // TODO: Still need to implement page mode switching and 'whatnot' } + return; } - if (!((key >= VK_LEFT) && (key <= VK_DELETE) && asciicode[IS_APPLE2 ? 0 : 1][key - VK_LEFT])) + if (key >= VK_LEFT && key <= VK_DELETE) + { + BYTE n = asciicode[IS_APPLE2 ? 0 : 1][key - VK_LEFT]; // Convert to Apple arrow keycode + if (!n) + return; + keycode = n; + } + else if ((GetKeyState( VK_RMENU ) & KF_UP)) // Right ALT + { + // + } + else + { return; - - keycode = asciicode[IS_APPLE2 ? 0 : 1][key - VK_LEFT]; // Convert to Apple arrow keycode - lastvirtkey = key; + } } keywaiting = 1; diff --git a/source/Log.cpp b/source/Log.cpp index 3c8753be..15f9dade 100644 --- a/source/Log.cpp +++ b/source/Log.cpp @@ -32,6 +32,31 @@ FILE* g_fh = NULL; //--------------------------------------------------------------------------- +void LogInit(void) +{ + if (g_fh) + return; + + g_fh = fopen("AppleWin.log", "a+t"); // Open log file (append & text mode) + setvbuf(g_fh, NULL, _IONBF, 0); // No buffering (so implicit fflush after every fprintf) + CHAR aDateStr[80], aTimeStr[80]; + GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aDateStr, sizeof(aDateStr)); + GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aTimeStr, sizeof(aTimeStr)); + fprintf(g_fh, "*** Logging started: %s %s\n", aDateStr, aTimeStr); +} + +void LogDone(void) +{ + if (!g_fh) + return; + + fprintf(g_fh,"*** Logging ended\n\n"); + fclose(g_fh); + g_fh = NULL; +} + +//--------------------------------------------------------------------------- + void LogOutput(LPCTSTR format, ...) { TCHAR output[256]; diff --git a/source/Log.h b/source/Log.h index d97224de..d952e69a 100644 --- a/source/Log.h +++ b/source/Log.h @@ -10,5 +10,7 @@ extern FILE* g_fh; // Filehandle for log file -extern void LogOutput(LPCTSTR format, ...); -extern void LogFileOutput(LPCTSTR format, ...); +void LogInit(void); +void LogDone(void); +void LogOutput(LPCTSTR format, ...); +void LogFileOutput(LPCTSTR format, ...); From 97b07eaee40ba9c774ae12a4e5e7af82f79259ef Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 15 Jul 2018 21:00:01 +0100 Subject: [PATCH 033/128] Keyboard hook filter: . Created a dedicated thread with message loop (#570) HookFilter dll: Only call GetKeyState() if keycode is ESC (instead of every time) DebuggerCursorUpdate(): reduce sleep from 10ms to 1ms --- HookFilter/HookFilter.cpp | 9 +++-- source/Applewin.cpp | 73 ++++++++++++++++++++++++++++++++++++--- source/Debugger/Debug.cpp | 2 +- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index fcf3bf33..d7e9602d 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -42,9 +42,12 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( } // Suppress ctrl-escape - bool ControlDown = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - if (pKbdLlHookStruct->vkCode == VK_ESCAPE && ControlDown) - suppress = true; + if (pKbdLlHookStruct->vkCode == VK_ESCAPE) + { + bool ControlDown = (GetKeyState(VK_CONTROL) & 0x8000) != 0; + if (ControlDown) + suppress = true; + } // Suppress keys by returning 1 if (suppress) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index dc1c9315..9c64d904 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -872,8 +872,11 @@ static void RegisterHotKeys(void) static HINSTANCE g_hinstDLL = 0; static HHOOK g_hhook = 0; +static HANDLE g_hHookThread = NULL; +static DWORD g_HookThreadId = 0; + // Pre: g_hFrameWindow must be valid -bool HookFilterForKeyboard() +static bool HookFilterForKeyboard() { g_hinstDLL = LoadLibrary(TEXT("HookFilter.dll")); @@ -905,12 +908,74 @@ bool HookFilterForKeyboard() return false; } -void UnhookFilterForKeyboard() +static void UnhookFilterForKeyboard() { UnhookWindowsHookEx(g_hhook); FreeLibrary(g_hinstDLL); } +static DWORD WINAPI HookThread(LPVOID lpParameter) +{ + if (!HookFilterForKeyboard()) + return -1; + + MSG msg; + while(GetMessage(&msg, NULL, 0, 0) > 0) + { + if (msg.message == WM_QUIT) + break; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + UnhookFilterForKeyboard(); + return 0; +} + +static bool InitHookThread() +{ + g_hHookThread = CreateThread(NULL, // lpThreadAttributes + 0, // dwStackSize + (LPTHREAD_START_ROUTINE) HookThread, + 0, // lpParameter + 0, // dwCreationFlags : 0 = Run immediately + &g_HookThreadId); // lpThreadId + if (g_hHookThread == NULL) + return false; + + return true; +} + +static void UninitHookThread() +{ + if (g_hHookThread) + { + if (!PostThreadMessage(g_HookThreadId, WM_QUIT, 0, 0)) + { + _ASSERT(0); + return; + } + + do + { + DWORD dwExitCode; + if (GetExitCodeThread(g_hHookThread, &dwExitCode)) + { + if(dwExitCode == STILL_ACTIVE) + Sleep(10); + else + break; + } + } + while(1); + + CloseHandle(g_hHookThread); + g_hHookThread = NULL; + g_HookThreadId = 0; + } +} + //=========================================================================== LPSTR GetCurrArg(LPSTR lpCmdLine) @@ -1423,7 +1488,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (g_bHookSystemKey) { - if (HookFilterForKeyboard()) // needs valid g_hFrameWindow (for message pump) + if (InitHookThread()) // needs valid g_hFrameWindow (for message pump) LogFileOutput("Main: HookFilterForKeyboard()\n"); } @@ -1535,7 +1600,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (g_bHookSystemKey) { - UnhookFilterForKeyboard(); + UninitHookThread(); LogFileOutput("Main: UnhookFilterForKeyboard()\n"); } } diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index c57f55ae..404b570a 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -9680,7 +9680,7 @@ void DebuggerCursorUpdate() } else { - Sleep(10); // Stop process hogging CPU + Sleep(1); // Stop process hogging CPU } } From 5e13bef808d62b5186fd8aad2df54e949df9f126 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 23 Jul 2018 22:14:54 +0100 Subject: [PATCH 034/128] VS2015: Add missing Hook Filter dependency --- AppleWinExpress2015.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/AppleWinExpress2015.sln b/AppleWinExpress2015.sln index 803daee0..19114355 100644 --- a/AppleWinExpress2015.sln +++ b/AppleWinExpress2015.sln @@ -5,6 +5,7 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppleWin", "AppleWinExpress2015.vcxproj", "{0A960136-A00A-4D4B-805F-664D9950D2CA}" ProjectSection(ProjectDependencies) = postProject + {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} = {AA5854AD-2BC7-4EFD-9790-349ADB35E35A} {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} = {CF5A49BF-62A5-41BB-B10C-F34D556A7A45} {0212E0DF-06DA-4080-BD1D-F3B01599F70F} = {0212E0DF-06DA-4080-BD1D-F3B01599F70F} {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} = {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} From 1afa2490c54ba69015162ce690f84f09b8538146 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 23 Jul 2018 22:27:33 +0100 Subject: [PATCH 035/128] Keyboard: Refactor for GetKeyState() --- source/Debugger/Debug.cpp | 4 ++-- source/Frame.h | 3 --- source/Keyboard.cpp | 11 ++++++----- source/Keyboard.h | 4 +++- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 404b570a..b38f40d8 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -780,7 +780,7 @@ Update_t CmdBenchmarkStop (int nArgs) DWORD currtime = GetTickCount(); while ((extbench = GetTickCount()) != currtime) ; // intentional busy-waiting - KeybQueueKeypress(TEXT(' '),1); + KeybQueueKeypress(TEXT(' ') ,ASCII); return UPDATE_ALL; // 0; } @@ -2096,7 +2096,7 @@ Update_t CmdUnassemble (int nArgs) Update_t CmdKey (int nArgs) { KeybQueueKeypress( - nArgs ? g_aArgs[1].nValue ? g_aArgs[1].nValue : g_aArgs[1].sArg[0] : TEXT(' '), 1); // FIXME!!! + nArgs ? g_aArgs[1].nValue ? g_aArgs[1].nValue : g_aArgs[1].sArg[0] : TEXT(' '), ASCII); // FIXME!!! return UPDATE_CONSOLE_DISPLAY; } diff --git a/source/Frame.h b/source/Frame.h index 672b95e9..f5cace2d 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -3,9 +3,6 @@ // 1.19.0.0 Hard Disk Status/Indicator Light #define HD_LED 1 - // Keyboard -- keystroke type - enum {NOT_ASCII=0, ASCII}; - // Win32 extern HWND g_hFrameWindow; diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index bd1bb24a..c890c4e2 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -102,9 +102,9 @@ bool KeybGetShiftStatus () //=========================================================================== void KeybUpdateCtrlShiftStatus() { - g_bShiftKey = (GetKeyState( VK_SHIFT ) & KF_UP) ? true : false; - g_bCtrlKey = (GetKeyState( VK_CONTROL) & KF_UP) ? true : false; - g_bAltKey = (GetKeyState( VK_MENU ) & KF_UP) ? true : false; + g_bShiftKey = (GetKeyState( VK_SHIFT ) < 0) ? true : false; // L or R shift + g_bCtrlKey = (GetKeyState( VK_CONTROL) < 0) ? true : false; // L or R ctrl + g_bAltKey = (GetKeyState( VK_MENU ) < 0) ? true : false; // L or R alt } //=========================================================================== @@ -114,7 +114,7 @@ BYTE KeybGetKeycode () // Used by IORead_C01x() and TapeRead() for Pravets8A } //=========================================================================== -void KeybQueueKeypress (int key, BOOL bASCII) +void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII) { if (bASCII == ASCII) // WM_CHAR { @@ -307,9 +307,10 @@ void KeybQueueKeypress (int key, BOOL bASCII) return; keycode = n; } - else if ((GetKeyState( VK_RMENU ) & KF_UP)) // Right ALT + else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) { // + return; } else { diff --git a/source/Keyboard.h b/source/Keyboard.h index c5518620..802903fc 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -1,5 +1,7 @@ #pragma once +enum Keystroke_e {NOT_ASCII=0, ASCII}; + void ClipboardInitiatePaste(); void KeybReset(); @@ -11,7 +13,7 @@ bool KeybGetShiftStatus(); bool KeybGetCapsAllowed(); //For Pravets8A/C only void KeybUpdateCtrlShiftStatus(); BYTE KeybGetKeycode (); -void KeybQueueKeypress (int,BOOL); +void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII); void KeybToggleCapsLock (); void KeybToggleP8ACapsLock (); void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended); From 6ed354714e2ecdc1f3beb7e3b00794925c1ded85 Mon Sep 17 00:00:00 2001 From: TomCh Date: Fri, 27 Jul 2018 21:55:53 +0100 Subject: [PATCH 036/128] Support ClosedApple+key with Alt Gr when combined with a regular keyboard key: . When Alt Gr is pressed, then manually post WM_CHAR message on receiving a WM_KEYDOWN (manually translate and account for shift/control/caps-lock) . Hook filter: suppress Alt Gr's (ie. RMENU's) fake LCONTROL messages Also: . Hook filter: allow Ctrl+Shift+Esc (for Task Manager) . Keyboard: refactor only use accessor functions to get the Alt/Control/Shift state --- HookFilter/HookFilter.cpp | 16 +++++++- source/Debugger/Debug.cpp | 8 ++-- source/Frame.cpp | 45 ++++++++++++--------- source/Keyboard.cpp | 83 ++++++++++++++++++++++++++------------- source/Keyboard.h | 7 +--- 5 files changed, 101 insertions(+), 58 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index d7e9602d..e21ee760 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -20,6 +20,18 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( UINT newMsg = pKbdLlHookStruct->flags & LLKHF_UP ? WM_KEYUP : WM_KEYDOWN; LPARAM newlParam = newMsg == WM_KEYUP ? 3<<30 : 0; // b31:transition state, b30:previous key state + // + + // NB. Alt Gr (Right-Alt): this normally send 2 WM_KEYDOWN messages for: VK_LCONTROL, then VK_RMENU + // Keyboard scanCodes: LCONTROL=0x1D, LCONTROL_from_RMENU=0x21D + // . For: Microsoft PS/2/Win7-64, VAIO laptop/Win7-64, Microsoft USB/Win10-64 + // NB. WM_KEYDOWN also includes a 9/10-bit? scanCode: LCONTROL=0x1D, RCONTROL=0x11D, RMENU=0x1D(not 0x21D) + // . Can't suppress in app, since scanCode is not >= 0x200 + if (pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) + { + suppress = true; + } + // Suppress alt-tab if (pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) { @@ -44,8 +56,8 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( // Suppress ctrl-escape if (pKbdLlHookStruct->vkCode == VK_ESCAPE) { - bool ControlDown = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - if (ControlDown) + // But don't suppress CTRL+SHIFT+ESC + if (GetKeyState(VK_CONTROL) < 0 && GetKeyState(VK_SHIFT) >= 0) suppress = true; } diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index b38f40d8..8f2b6a64 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -9709,11 +9709,11 @@ void DebuggerMouseClick( int x, int y ) if (g_nAppMode != MODE_DEBUG) return; - // NOTE: KeybUpdateCtrlShiftStatus() should be called before + KeybUpdateCtrlShiftStatus(); int iAltCtrlShift = 0; - iAltCtrlShift |= (g_bAltKey & 1) << 0; - iAltCtrlShift |= (g_bCtrlKey & 1) << 1; - iAltCtrlShift |= (g_bShiftKey & 1) << 2; + iAltCtrlShift |= KeybGetAltStatus() ? 1<<0 : 0; + iAltCtrlShift |= KeybGetCtrlStatus() ? 1<<1 : 0; + iAltCtrlShift |= KeybGetShiftStatus() ? 1<<2 : 0; // GH#462 disasm click # if (iAltCtrlShift != g_bConfigDisasmClick) diff --git a/source/Frame.cpp b/source/Frame.cpp index 3b4803b5..7a6a255d 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -57,6 +57,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Debugger/Debug.h" //#define ENABLE_MENU 0 +#define DEBUG_KEY_MESSAGES 0 // 3D border around the 560x384 Apple II display #define VIEWPORTX 5 @@ -1096,15 +1097,16 @@ LRESULT CALLBACK FrameWndProc ( case WM_CHAR: if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING) || (g_nAppMode == MODE_LOGO)) { - if( !g_bDebuggerEatKey ) + if (!g_bDebuggerEatKey) { +#if DEBUG_KEY_MESSAGES + LogOutput("WM_CHAR: %08X\n", wparam); +#endif if (g_nAppMode != MODE_LOGO) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard - KeybQueueKeypress((int)wparam, ASCII); - } - else - { - g_bDebuggerEatKey = false; + KeybQueueKeypress(wparam, ASCII); } + + g_bDebuggerEatKey = false; } else if (g_nAppMode == MODE_DEBUG) { @@ -1290,19 +1292,19 @@ LRESULT CALLBACK FrameWndProc ( // CTRL+SHIFT+F9 Toggle 50% Scan Lines // ALT+F9 Can't use Alt-F9 as Alt is Open-Apple = Joystick Button #1 - if ( !g_bCtrlKey && !g_bShiftKey ) // F9 + if ( !KeybGetCtrlStatus() && !KeybGetShiftStatus() ) // F9 { g_eVideoType++; if (g_eVideoType >= NUM_VIDEO_MODES) g_eVideoType = 0; } - else if ( !g_bCtrlKey && g_bShiftKey ) // SHIFT+F9 + else if ( !KeybGetCtrlStatus() && KeybGetShiftStatus() ) // SHIFT+F9 { if (g_eVideoType <= 0) g_eVideoType = NUM_VIDEO_MODES; g_eVideoType--; } - else if ( g_bCtrlKey && g_bShiftKey ) // CTRL+SHIFT+F9 + else if ( KeybGetCtrlStatus() && KeybGetShiftStatus() ) // CTRL+SHIFT+F9 { g_uHalfScanLines = !g_uHalfScanLines; } @@ -1331,7 +1333,7 @@ LRESULT CALLBACK FrameWndProc ( } else if (wparam == VK_F10) { - if (g_Apple2Type == A2TYPE_PRAVETS8A && !g_bCtrlKey) + if (g_Apple2Type == A2TYPE_PRAVETS8A && !KeybGetCtrlStatus()) { KeybToggleP8ACapsLock (); // F10: Toggles P8 Capslock } @@ -1340,7 +1342,7 @@ LRESULT CALLBACK FrameWndProc ( SetUsingCursor(FALSE); // Ctrl+F10 } } - else if (wparam == VK_F11 && !g_bCtrlKey) // Save state (F11) + else if (wparam == VK_F11 && !KeybGetCtrlStatus()) // Save state (F11) { SoundCore_SetFade(FADE_OUT); if(sg_PropertySheet.SaveStateSelectImage(window, true)) @@ -1392,18 +1394,20 @@ LRESULT CALLBACK FrameWndProc ( } else if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_LOGO) || (g_nAppMode == MODE_STEPPING)) { - // Note about Alt Gr (Right-Alt): - // . WM_KEYDOWN[Left-Control], then: - // . WM_KEYDOWN[Right-Alt] + // NB. Alt Gr (Right-Alt): this normally send 2 WM_KEYDOWN messages for: VK_LCONTROL, then VK_RMENU + // . NB. The keyboard hook filter now suppresses VK_LCONTROL bool extended = (HIWORD(lparam) & KF_EXTENDED) != 0; BOOL down = 1; BOOL autorep = (HIWORD(lparam) & KF_REPEAT) != 0; BOOL IsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); +#if DEBUG_KEY_MESSAGES + LogOutput("WM_KEYDOWN: %08X (scanCode=%04X)\n", wparam, (lparam>>16)&0xfff); +#endif if (!IsJoyKey && (g_nAppMode != MODE_LOGO)) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard { - KeybQueueKeypress((int)wparam, NOT_ASCII); + KeybQueueKeypress(wparam, NOT_ASCII); if (!autorep) KeybAnyKeyDown(WM_KEYDOWN, wparam, extended); @@ -1433,6 +1437,9 @@ LRESULT CALLBACK FrameWndProc ( BOOL autorep = 0; BOOL bIsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); +#if DEBUG_KEY_MESSAGES + LogOutput("WM_KEYUP: %08X\n", wparam); +#endif if (!bIsJoyKey) KeybAnyKeyDown(WM_KEYUP, wparam, extended); } @@ -1749,7 +1756,7 @@ LRESULT CALLBACK FrameWndProc ( // http://msdn.microsoft.com/en-us/library/windows/desktop/gg153546(v=vs.85).aspx // v1.25.0: Alt-Return Alt-Enter toggle fullscreen - if (g_bAltEnter_ToggleFullScreen && g_bAltKey && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU + if (g_bAltEnter_ToggleFullScreen && KeybGetAltStatus() && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU return 0; // NOP -- eat key PostMessage(window,WM_KEYDOWN,wparam,lparam); @@ -1763,7 +1770,7 @@ LRESULT CALLBACK FrameWndProc ( KeybUpdateCtrlShiftStatus(); // v1.25.0: Alt-Return Alt-Enter toggle fullscreen - if (g_bAltEnter_ToggleFullScreen && g_bAltKey && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU + if (g_bAltEnter_ToggleFullScreen && KeybGetAltStatus() && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU ScreenWindowResize(false); else PostMessage(window,WM_KEYUP,wparam,lparam); @@ -1946,7 +1953,7 @@ static void ProcessButtonClick(int button, bool bFromButtonUI /*=false*/) case BTN_RUN: KeybUpdateCtrlShiftStatus(); - if( g_bCtrlKey ) + if( KeybGetCtrlStatus() ) { CtrlReset(); if (g_nAppMode == MODE_DEBUG) @@ -1990,7 +1997,7 @@ static void ProcessButtonClick(int button, bool bFromButtonUI /*=false*/) case BTN_FULLSCR: KeybUpdateCtrlShiftStatus(); - ScreenWindowResize(g_bCtrlKey); + ScreenWindowResize( KeybGetCtrlStatus() ); break; case BTN_DEBUG: diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index c890c4e2..c23190e6 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Tape.h" #include "YamlHelper.h" #include "Video.h" // Needed by TK3000 //e, to refresh the frame at each |Mode| change +#include "Log.h" static BYTE asciicode[2][10] = { // VK_LEFT/UP/RIGHT/DOWN/SELECT, VK_PRINT/EXECUTE/SNAPSHOT/INSERT/DELETE @@ -65,36 +66,31 @@ void KeybReset() } //=========================================================================== -bool KeybGetAltStatus () -{ - return g_bAltKey; -} - -//=========================================================================== -bool KeybGetCapsStatus () +bool KeybGetCapsStatus() { return g_bCapsLock; } + //=========================================================================== bool KeybGetP8CapsStatus() { return g_bP8CapsLock; } + //=========================================================================== -/* -bool KeybGetCapsAllowed() //For Pravets 8A/C only +bool KeybGetAltStatus() { - return g_CapsLockAllowed; + return g_bAltKey; } -*/ + //=========================================================================== -bool KeybGetCtrlStatus () +bool KeybGetCtrlStatus() { return g_bCtrlKey; } //=========================================================================== -bool KeybGetShiftStatus () +bool KeybGetShiftStatus() { return g_bShiftKey; } @@ -102,9 +98,9 @@ bool KeybGetShiftStatus () //=========================================================================== void KeybUpdateCtrlShiftStatus() { - g_bShiftKey = (GetKeyState( VK_SHIFT ) < 0) ? true : false; // L or R shift - g_bCtrlKey = (GetKeyState( VK_CONTROL) < 0) ? true : false; // L or R ctrl g_bAltKey = (GetKeyState( VK_MENU ) < 0) ? true : false; // L or R alt + g_bCtrlKey = (GetKeyState( VK_CONTROL) < 0) ? true : false; // L or R ctrl + g_bShiftKey = (GetKeyState( VK_SHIFT ) < 0) ? true : false; // L or R shift } //=========================================================================== @@ -114,7 +110,10 @@ BYTE KeybGetKeycode () // Used by IORead_C01x() and TapeRead() for Pravets8A } //=========================================================================== -void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII) + +bool IsVirtualKeyAnAppleIIKey(WPARAM wparam); + +void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII) { if (bASCII == ASCII) // WM_CHAR { @@ -205,7 +204,7 @@ void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII) } else //i.e. latin letters { - if (GetCapsLockAllowed() == false) + if (GetCapsLockAllowed() == false) { if (key == '{') keycode = '['; if (key == '}') keycode = ']'; @@ -309,7 +308,27 @@ void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII) } else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) { - // + if (IsVirtualKeyAnAppleIIKey(key)) + { + // When Alt Gr is down, then WM_CHAR is not posted - so fix this. + // NB. Still get WM_KEYDOWN/WM_KEYUP for the virtual key, so AKD works. + WPARAM newKey = key; + + // Translate if shift or ctrl is down + if (key >= 'A' && key <= 'Z') + { + if ( (GetKeyState(VK_SHIFT) >= 0) && !g_bCapsLock ) + newKey += 'a' - 'A'; // convert to lowercase key + else if (GetKeyState(VK_CONTROL) < 0) + { + LogOutput("L-Control=%d, R-Control=%d\n", GetKeyState(VK_LCONTROL), GetKeyState(VK_RCONTROL)); + newKey -= 'A' - 1; // convert to control-key + } + } + + PostMessage(g_hFrameWindow, WM_CHAR, newKey, 0); + } + return; } else @@ -401,16 +420,8 @@ const UINT kAKDNumElements = 256/64; static uint64_t g_AKDFlags[2][kAKDNumElements] = { {0,0,0,0}, // normal {0,0,0,0}}; // extended -// NB. Don't need to be concerned about if numpad/cursors are used for joystick, -// since parent calls JoyProcessKey() just before this. -void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended) +static bool IsVirtualKeyAnAppleIIKey(WPARAM wparam) { - if (wparam > 255) - { - _ASSERT(0); - return; - } - if (wparam == VK_BACK || wparam == VK_TAB || wparam == VK_RETURN || @@ -425,6 +436,24 @@ void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended) (wparam >= VK_OEM_1 && wparam <= VK_OEM_3) || // 7 in total (wparam >= VK_OEM_4 && wparam <= VK_OEM_8) || // 5 in total (wparam == VK_OEM_102)) + { + return true; + } + + return false; +} + +// NB. Don't need to be concerned about if numpad/cursors are used for joystick, +// since parent calls JoyProcessKey() just before this. +void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended) +{ + if (wparam > 255) + { + _ASSERT(0); + return; + } + + if (IsVirtualKeyAnAppleIIKey(wparam)) { UINT offset = wparam >> 6; UINT bit = wparam & 0x3f; diff --git a/source/Keyboard.h b/source/Keyboard.h index 802903fc..65920f39 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -5,12 +5,11 @@ enum Keystroke_e {NOT_ASCII=0, ASCII}; void ClipboardInitiatePaste(); void KeybReset(); -bool KeybGetAltStatus(); bool KeybGetCapsStatus(); bool KeybGetP8CapsStatus(); +bool KeybGetAltStatus(); bool KeybGetCtrlStatus(); bool KeybGetShiftStatus(); -bool KeybGetCapsAllowed(); //For Pravets8A/C only void KeybUpdateCtrlShiftStatus(); BYTE KeybGetKeycode (); void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII); @@ -22,7 +21,3 @@ BYTE KeybReadFlag (void); void KeybSetSnapshot_v1(const BYTE LastKey); void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); - -extern bool g_bShiftKey; -extern bool g_bCtrlKey; -extern bool g_bAltKey; From a4f225555fa68fd7ac619b215998c18f43d37ef3 Mon Sep 17 00:00:00 2001 From: tomcw Date: Fri, 27 Jul 2018 22:05:59 +0100 Subject: [PATCH 037/128] Keyboard: added comment for GH558 and removed some debug logging --- HookFilter/HookFilter.cpp | 2 +- source/Keyboard.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index e21ee760..6a4525d9 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -27,7 +27,7 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( // . For: Microsoft PS/2/Win7-64, VAIO laptop/Win7-64, Microsoft USB/Win10-64 // NB. WM_KEYDOWN also includes a 9/10-bit? scanCode: LCONTROL=0x1D, RCONTROL=0x11D, RMENU=0x1D(not 0x21D) // . Can't suppress in app, since scanCode is not >= 0x200 - if (pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) + if (pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) // GH#558 { suppress = true; } diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index c23190e6..7ad5af59 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -306,7 +306,7 @@ void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII) return; keycode = n; } - else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) + else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) - GH#558 { if (IsVirtualKeyAnAppleIIKey(key)) { @@ -320,10 +320,7 @@ void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII) if ( (GetKeyState(VK_SHIFT) >= 0) && !g_bCapsLock ) newKey += 'a' - 'A'; // convert to lowercase key else if (GetKeyState(VK_CONTROL) < 0) - { - LogOutput("L-Control=%d, R-Control=%d\n", GetKeyState(VK_LCONTROL), GetKeyState(VK_RCONTROL)); newKey -= 'A' - 1; // convert to control-key - } } PostMessage(g_hFrameWindow, WM_CHAR, newKey, 0); From b069614a2569d7e92e87627c03943fffd05ce3b4 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 28 Jul 2018 10:44:12 +0100 Subject: [PATCH 038/128] 1.27.6: Bump version & update History.txt --- bin/History.txt | 5 +++++ resource/Applewin.rc | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 4c2ec95e..9bbe234a 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -8,6 +8,11 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.27.6.0 - 28 Jul 2018 +---------------------- +. [Bug #570] Fixed lag when repeat-stepping in debugger. +. [Bug #558] Fixed ClosedApple + not working (when using right ALT key). + 1.27.5.0 - 24 Jun 2018 ---------------------- diff --git a/resource/Applewin.rc b/resource/Applewin.rc index c207be7c..a71c4458 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,5,0 - PRODUCTVERSION 1,27,5,0 + FILEVERSION 1,27,6,0 + PRODUCTVERSION 1,27,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 5, 0" + VALUE "FileVersion", "1, 27, 6, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 5, 0" + VALUE "ProductVersion", "1, 27, 6, 0" END END BLOCK "VarFileInfo" From 140d505fe96ff36223cd24afaab53b8cf9a6041d Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 29 Jul 2018 22:34:09 +0100 Subject: [PATCH 039/128] Keyboard: . reverted default so that ALT+TAB is not hooked (#556) . reverted default so that ALT GR's fake LCONTROL is not hooked (#558) . added new switches: -hook-alt-tab and -hook-altgr-control to support hooking these key combo's (#556) --- HookFilter/HookFilter.cpp | 10 +++++++--- source/Applewin.cpp | 19 +++++++++++++++++-- source/Applewin.h | 1 + source/Keyboard.cpp | 2 +- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index 6a4525d9..fe3a045d 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -1,6 +1,8 @@ #include static HWND g_hFrameWindow = (HWND)0; +static bool g_bHookAltTab = false; +static bool g_bHookAltGrControl = false; // NB. __stdcall (or WINAPI) and extern "C": // . symbol is decorated as _@bytes @@ -27,13 +29,13 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( // . For: Microsoft PS/2/Win7-64, VAIO laptop/Win7-64, Microsoft USB/Win10-64 // NB. WM_KEYDOWN also includes a 9/10-bit? scanCode: LCONTROL=0x1D, RCONTROL=0x11D, RMENU=0x1D(not 0x21D) // . Can't suppress in app, since scanCode is not >= 0x200 - if (pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) // GH#558 + if (g_bHookAltGrControl && pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) // GH#558 { suppress = true; } // Suppress alt-tab - if (pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) + if (g_bHookAltTab && pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) { PostMessage(g_hFrameWindow, newMsg, VK_TAB, newlParam); suppress = true; @@ -69,7 +71,9 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( return CallNextHookEx(0/*parameter is ignored*/, nCode, wParam, lParam); } -extern "C" __declspec(dllexport) void __cdecl RegisterHWND(HWND hWnd) +extern "C" __declspec(dllexport) void __cdecl RegisterHWND(HWND hWnd, bool bHookAltTab, bool bHookAltGrControl) { g_hFrameWindow = hWnd; + g_bHookAltTab = bHookAltTab; + g_bHookAltGrControl = bHookAltGrControl; } diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 9c64d904..46cfbda8 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -79,6 +79,8 @@ TCHAR g_sDebugDir [MAX_PATH] = TEXT(""); // TODO: Not currently used TCHAR g_sScreenShotDir[MAX_PATH] = TEXT(""); // TODO: Not currently used bool g_bCapturePrintScreenKey = true; static bool g_bHookSystemKey = true; +static bool g_bHookAltTab = false; +static bool g_bHookAltGrControl = false; TCHAR g_sCurrentDir[MAX_PATH] = TEXT(""); // Also Starting Dir. Debugger uses this when load/save bool g_bRestart = false; @@ -171,6 +173,11 @@ void SetLoadedSaveStateFlag(const bool bFlag) g_bLoadedSaveState = bFlag; } +bool GetHookAltGrControl(void) +{ + return g_bHookAltGrControl; +} + static void ResetToLogoMode(void) { g_nAppMode = MODE_LOGO; @@ -882,10 +889,10 @@ static bool HookFilterForKeyboard() _ASSERT(g_hFrameWindow); - typedef void (*RegisterHWNDProc)(HWND); + typedef void (*RegisterHWNDProc)(HWND, bool, bool); RegisterHWNDProc RegisterHWND = (RegisterHWNDProc) GetProcAddress(g_hinstDLL, "RegisterHWND"); if (RegisterHWND) - RegisterHWND(g_hFrameWindow); + RegisterHWND(g_hFrameWindow, g_bHookAltTab, g_bHookAltGrControl); HOOKPROC hkprcLowLevelKeyboardProc = (HOOKPROC) GetProcAddress(g_hinstDLL, "LowLevelKeyboardProc"); @@ -1294,6 +1301,14 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { g_bHookSystemKey = false; } + else if (strcmp(lpCmdLine, "-hook-alt-tab") == 0) // GH#556 + { + g_bHookAltTab = true; + } + else if (strcmp(lpCmdLine, "-hook-altgr-control") == 0) // GH#556 + { + g_bHookAltGrControl = true; + } else if (strcmp(lpCmdLine, "-spkr-inc") == 0) { lpCmdLine = GetCurrArg(lpNextArg); diff --git a/source/Applewin.h b/source/Applewin.h index 43a6937b..a3732ecc 100644 --- a/source/Applewin.h +++ b/source/Applewin.h @@ -30,6 +30,7 @@ extern HINSTANCE g_hInstance; extern AppMode_e g_nAppMode; bool GetLoadedSaveStateFlag(void); void SetLoadedSaveStateFlag(const bool bFlag); +bool GetHookAltGrControl(void); extern TCHAR g_sProgramDir[MAX_PATH]; extern TCHAR g_sCurrentDir[MAX_PATH]; diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 7ad5af59..c28afd46 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -319,7 +319,7 @@ void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII) { if ( (GetKeyState(VK_SHIFT) >= 0) && !g_bCapsLock ) newKey += 'a' - 'A'; // convert to lowercase key - else if (GetKeyState(VK_CONTROL) < 0) + else if (GetHookAltGrControl() && GetKeyState(VK_CONTROL) < 0) newKey -= 'A' - 1; // convert to control-key } From 898f30f08a8710abaa29529c9ce937a1f515d88f Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 31 Jul 2018 18:06:53 +0100 Subject: [PATCH 040/128] Fixed save-state on exit not working if there was a VM restart (eg. config h/w change). Fixes #564 --- source/Frame.cpp | 4 +++- source/SaveState.cpp | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 7a6a255d..4afb1e82 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1092,6 +1092,7 @@ LRESULT CALLBACK FrameWndProc ( g_TimerIDEvent_100msec = 0; } LogFileOutput("WM_CLOSE (done)\n"); + // Exit via DefWindowProc(), which does the default action for WM_CLOSE, which is to call DestroyWindow(), posting WM_DESTROY break; case WM_CHAR: @@ -1175,7 +1176,8 @@ LRESULT CALLBACK FrameWndProc ( case WM_DESTROY: LogFileOutput("WM_DESTROY\n"); DragAcceptFiles(window,0); - Snapshot_Shutdown(); + if (!g_bRestart) // GH#564: Only save-state on shutdown (not on a restart) + Snapshot_Shutdown(); DebugDestroy(); if (!g_bRestart) { DiskDestroy(); diff --git a/source/SaveState.cpp b/source/SaveState.cpp index d067a381..ff2c7a96 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -637,17 +637,19 @@ void Snapshot_Startup() Snapshot_LoadState(); - bDone = true; + bDone = true; // Prevents a g_bRestart from loading an old save-state } void Snapshot_Shutdown() { static bool bDone = false; + _ASSERT(!bDone); + _ASSERT(!g_bRestart); if(!g_bSaveStateOnExit || bDone) return; Snapshot_SaveState(); - bDone = true; + bDone = true; // Debug flag: should only be called once, and never on a g_bRestart } From e4bd6162c50760239f74148bd90fb3c066247b87 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 31 Jul 2018 18:17:42 +0100 Subject: [PATCH 041/128] Refactor: move code for WM_CLOSE next to WM_DESTROY, and WM_KEYDOWN next to WM_CHAR --- source/Frame.cpp | 91 +++++++++++++++++++++----------------------- source/SaveState.cpp | 2 +- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 4afb1e82..b58379c0 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1095,25 +1095,29 @@ LRESULT CALLBACK FrameWndProc ( // Exit via DefWindowProc(), which does the default action for WM_CLOSE, which is to call DestroyWindow(), posting WM_DESTROY break; - case WM_CHAR: - if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING) || (g_nAppMode == MODE_LOGO)) - { - if (!g_bDebuggerEatKey) - { -#if DEBUG_KEY_MESSAGES - LogOutput("WM_CHAR: %08X\n", wparam); -#endif - if (g_nAppMode != MODE_LOGO) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard - KeybQueueKeypress(wparam, ASCII); - } - - g_bDebuggerEatKey = false; - } - else if (g_nAppMode == MODE_DEBUG) - { - DebuggerInputConsoleChar((TCHAR)wparam); - } - break; + case WM_DESTROY: + LogFileOutput("WM_DESTROY\n"); + DragAcceptFiles(window,0); + if (!g_bRestart) // GH#564: Only save-state on shutdown (not on a restart) + Snapshot_Shutdown(); + DebugDestroy(); + if (!g_bRestart) { + DiskDestroy(); + ImageDestroy(); + HD_Destroy(); + } + PrintDestroy(); + sg_SSC.CommDestroy(); + CpuDestroy(); + MemDestroy(); + SpkrDestroy(); + VideoDestroy(); + MB_Destroy(); + DeleteGdiObjects(); + DIMouse::DirectInputUninit(window); // NB. do before window is destroyed + PostQuitMessage(0); // Post WM_QUIT message to the thread's message queue + LogFileOutput("WM_DESTROY (done)\n"); + break; case WM_CREATE: LogFileOutput("WM_CREATE\n"); @@ -1173,30 +1177,6 @@ LRESULT CALLBACK FrameWndProc ( break; } - case WM_DESTROY: - LogFileOutput("WM_DESTROY\n"); - DragAcceptFiles(window,0); - if (!g_bRestart) // GH#564: Only save-state on shutdown (not on a restart) - Snapshot_Shutdown(); - DebugDestroy(); - if (!g_bRestart) { - DiskDestroy(); - ImageDestroy(); - HD_Destroy(); - } - PrintDestroy(); - sg_SSC.CommDestroy(); - CpuDestroy(); - MemDestroy(); - SpkrDestroy(); - VideoDestroy(); - MB_Destroy(); - DeleteGdiObjects(); - DIMouse::DirectInputUninit(window); // NB. do before window is destroyed - PostQuitMessage(0); // Post WM_QUIT message to the thread's message queue - LogFileOutput("WM_DESTROY (done)\n"); - break; - case WM_DISPLAYCHANGE: VideoReinitialize(); break; @@ -1421,6 +1401,26 @@ LRESULT CALLBACK FrameWndProc ( } break; + case WM_CHAR: + if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING) || (g_nAppMode == MODE_LOGO)) + { + if (!g_bDebuggerEatKey) + { +#if DEBUG_KEY_MESSAGES + LogOutput("WM_CHAR: %08X\n", wparam); +#endif + if (g_nAppMode != MODE_LOGO) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard + KeybQueueKeypress(wparam, ASCII); + } + + g_bDebuggerEatKey = false; + } + else if (g_nAppMode == MODE_DEBUG) + { + DebuggerInputConsoleChar((TCHAR)wparam); + } + break; + case WM_KEYUP: // Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1)) @@ -1795,10 +1795,7 @@ LRESULT CALLBACK FrameWndProc ( } case WM_USER_RESTART: - // . Changed Apple computer type (][+ or //e) - // . Changed slot configuration - // . Changed disk speed (normal or enhanced) - // . Changed Freeze F8 rom setting + // Changed h/w config, eg. Apple computer type (][+ or //e), slot configuration, etc. g_bRestart = true; PostMessage(window,WM_CLOSE,0,0); break; diff --git a/source/SaveState.cpp b/source/SaveState.cpp index ff2c7a96..4870e9d6 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -651,5 +651,5 @@ void Snapshot_Shutdown() Snapshot_SaveState(); - bDone = true; // Debug flag: should only be called once, and never on a g_bRestart + bDone = true; // Debug flag: this func should only be called once, and never on a g_bRestart } From 5e02eaee531032cfd9ff5c1f77a269303d26de14 Mon Sep 17 00:00:00 2001 From: tomcw Date: Thu, 2 Aug 2018 22:37:20 +0100 Subject: [PATCH 042/128] Use VideoGetScannerAddress() to generate the NTSC video lookup tables --- source/Memory.cpp | 1 - source/NTSC.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++--- source/Video.cpp | 6 +-- 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index 79357f8d..70e308ea 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1618,7 +1618,6 @@ void MemReset() BYTE MemReadFloatingBus(const ULONG uExecutedCycles) { -// return mem[ VideoGetScannerAddress(NULL, uExecutedCycles) ]; // NG: ANSI STORY (End Credits) - repro by running from "Turn the disk over" return mem[ NTSC_VideoGetScannerAddress(uExecutedCycles) ]; // OK: This does the 2-cycle adjust for ANSI STORY (End Credits) } diff --git a/source/NTSC.cpp b/source/NTSC.cpp index ec480f67..72f045a4 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -136,7 +136,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static const UINT g_kFrameBufferWidth = GetFrameBufferWidth(); - static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; + static unsigned short (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0; typedef void (*UpdateScreenFunc_t)(long); static UpdateScreenFunc_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY]; @@ -199,7 +199,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define SIGNAL_1 0.7465656072f // Tables - static unsigned g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] = + static unsigned short g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ]; + + static unsigned short g_kClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] = { 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80, 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80, @@ -224,7 +226,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80 }; - static unsigned g_aClockVertOffsetsTXT[33] = + static unsigned short g_aClockVertOffsetsTXT[33]; + + static unsigned short g_kClockVertOffsetsTXT[33] = { 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, @@ -234,7 +238,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x380 }; - static unsigned APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = + static unsigned short APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ]; + + static unsigned short kAPPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = { {0x1068,0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F, 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077, @@ -282,7 +288,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F} }; - static unsigned APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = + static unsigned short APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ]; + + static unsigned short kAPPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = { {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, @@ -776,7 +784,7 @@ INLINE uint16_t updateVideoScannerAddressTXT() //=========================================================================== INLINE uint16_t updateVideoScannerAddressHGR() { - // BUG? g_pHorzClockOffset + // NB. Not a bug: For both A2 and //e then use APPLE_IIE_HORZ_CLOCK_OFFSET - see VideoGetScannerAddress() where only TEXT mode adds $1000 return (g_aClockVertOffsetsHGR[g_nVideoClockVert ] + APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000)); } @@ -1629,9 +1637,12 @@ _mono: } //=========================================================================== +void GenerateVideoTables( void ); + void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit { make_csbits(); + GenerateVideoTables(); initPixelDoubleMasks(); initChromaPhaseTables(); updateMonochromeTables( 0xFF, 0xFF, 0xFF ); @@ -1826,3 +1837,73 @@ bool NTSC_GetColorBurst( void ) { return (g_nColorBurstPixels < 2) ? false : true; } + +//=========================================================================== +void GenerateVideoTables( void ) +{ + eApple2Type currentApple2Type = GetApple2Type(); + + g_uVideoMode = VF_HIRES; + for (UINT i=0, cycle=VIDEO_SCANNER_HORZ_START; i<256; i++, cycle+=VIDEO_SCANNER_MAX_HORZ) + { + if (i % 64 == 0) cycle=VIDEO_SCANNER_HORZ_START; // repeat every 64th scanline + g_aClockVertOffsetsHGR[i] = VideoGetScannerAddress(NULL, cycle) - 0x2000; + _ASSERT(g_aClockVertOffsetsHGR[i] == g_kClockVertOffsetsHGR[i]); + } + + // Repeat last 6 entries for scanlines [256...261] + const UINT kLine256 = 64 - (VIDEO_SCANNER_MAX_VERT - 256); + for (UINT i=256, cycle=kLine256*VIDEO_SCANNER_MAX_HORZ+VIDEO_SCANNER_HORZ_START; i Date: Sun, 5 Aug 2018 22:19:51 +0100 Subject: [PATCH 043/128] Improve VideoGetScannerAddress() to generate NTSC tables; and check tables with all video cycles --- source/NTSC.cpp | 147 ++++++++++++++++++++++++++++------------------- source/Video.cpp | 40 +++++++++---- source/Video.h | 4 +- 3 files changed, 121 insertions(+), 70 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 72f045a4..b97b5b6b 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Includes #include "StdAfx.h" #include "Applewin.h" - #include "CPU.h" + #include "CPU.h" // CpuGetCyclesThisVideoFrame() #include "Frame.h" // FRAMEBUFFER_W FRAMEBUFFER_H #include "Memory.h" // MemGetMainPtr() MemGetBankPtr() #include "Video.h" // g_pFramebufferbits @@ -41,9 +41,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "ntsc_rgb.h" #endif - //LPBYTE MemGetMainPtr(const WORD); - //LPBYTE MemGetBankPtr(const UINT nBank); - // Defines #define HGR_TEST_PATTERN 0 @@ -199,8 +196,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define SIGNAL_1 0.7465656072f // Tables - static unsigned short g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ]; + // Video scanner tables are now runtime-generated using UTAIIe logic + static unsigned short g_aClockVertOffsetsHGR[VIDEO_SCANNER_MAX_VERT]; + static unsigned short g_aClockVertOffsetsTXT[33]; + static unsigned short APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ]; + static unsigned short APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ]; +#ifdef _DEBUG static unsigned short g_kClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] = { 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80, @@ -226,8 +228,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80 }; - static unsigned short g_aClockVertOffsetsTXT[33]; - static unsigned short g_kClockVertOffsetsTXT[33] = { 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, @@ -238,8 +238,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x380 }; - static unsigned short APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ]; - static unsigned short kAPPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = { {0x1068,0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F, @@ -288,8 +286,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F} }; - static unsigned short APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ]; - static unsigned short kAPPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] = { {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, @@ -337,6 +333,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F} }; +#endif /* http://www.kreativekorp.com/miscpages/a2info/munafo.shtml @@ -397,11 +394,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static csbits_t csbits; // charset, optionally followed by alt charset // Prototypes - // prototype from CPU.h - //unsigned char CpuRead(unsigned short addr, unsigned long uExecutedCycles); - // prototypes from Memory.h - //unsigned char * MemGetAuxPtr (unsigned short); - //unsigned char * MemGetMainPtr (unsigned short); INLINE float clampZeroOne( const float & x ); INLINE uint8_t getCharSetBits( const int iChar ); INLINE uint16_t getLoResBits( uint8_t iByte ); @@ -419,8 +411,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA INLINE void updatePixels( uint16_t bits ); INLINE void updateVideoScannerHorzEOL(); INLINE void updateVideoScannerAddress(); - INLINE uint16_t updateVideoScannerAddressTXT(); - INLINE uint16_t updateVideoScannerAddressHGR(); + INLINE uint16_t getVideoScannerAddressTXT(); + INLINE uint16_t getVideoScannerAddressHGR(); static void initChromaPhaseTables(); static real initFilterChroma (real z); @@ -775,16 +767,16 @@ inline void updateVideoScannerAddress() } //=========================================================================== -INLINE uint16_t updateVideoScannerAddressTXT() +INLINE uint16_t getVideoScannerAddressTXT() { return (g_aClockVertOffsetsTXT[g_nVideoClockVert/8] + g_pHorzClockOffset [g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nTextPage * 0x400)); } //=========================================================================== -INLINE uint16_t updateVideoScannerAddressHGR() +INLINE uint16_t getVideoScannerAddressHGR() { - // NB. Not a bug: For both A2 and //e then use APPLE_IIE_HORZ_CLOCK_OFFSET - see VideoGetScannerAddress() where only TEXT mode adds $1000 + // NB. For both A2 and //e use APPLE_IIE_HORZ_CLOCK_OFFSET - see VideoGetScannerAddress() where only TEXT mode adds $1000 return (g_aClockVertOffsetsHGR[g_nVideoClockVert ] + APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000)); } @@ -1142,7 +1134,7 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0 for (; cycles6502 > 0; --cycles6502) { - uint16_t addr = updateVideoScannerAddressHGR(); + uint16_t addr = getVideoScannerAddressHGR(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1173,7 +1165,7 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires for (; cycles6502 > 0; --cycles6502) { - uint16_t addr = updateVideoScannerAddressHGR(); + uint16_t addr = getVideoScannerAddressHGR(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1210,7 +1202,7 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores for (; cycles6502 > 0; --cycles6502) { - uint16_t addr = updateVideoScannerAddressTXT(); + uint16_t addr = getVideoScannerAddressTXT(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1242,7 +1234,7 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores for (; cycles6502 > 0; --cycles6502) { - uint16_t addr = updateVideoScannerAddressTXT(); + uint16_t addr = getVideoScannerAddressTXT(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1283,7 +1275,7 @@ void updateScreenSingleHires40 (long cycles6502) for (; cycles6502 > 0; --cycles6502) { - uint16_t addr = updateVideoScannerAddressHGR(); + uint16_t addr = getVideoScannerAddressHGR(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1324,7 +1316,7 @@ void updateScreenSingleLores40 (long cycles6502) for (; cycles6502 > 0; --cycles6502) { - uint16_t addr = updateVideoScannerAddressTXT(); + uint16_t addr = getVideoScannerAddressTXT(); if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { @@ -1350,7 +1342,7 @@ void updateScreenText40 (long cycles6502) { for (; cycles6502 > 0; --cycles6502) { - uint16_t addr = updateVideoScannerAddressTXT(); + uint16_t addr = getVideoScannerAddressTXT(); if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) { @@ -1382,7 +1374,7 @@ void updateScreenText80 (long cycles6502) { for (; cycles6502 > 0; --cycles6502) { - uint16_t addr = updateVideoScannerAddressTXT(); + uint16_t addr = getVideoScannerAddressTXT(); if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG)) { @@ -1477,9 +1469,9 @@ uint16_t NTSC_VideoGetScannerAddress ( const ULONG uExecutedCycles ) uint16_t addr; bool bHires = (g_uVideoMode & VF_HIRES) && !(g_uVideoMode & VF_TEXT); // SW_HIRES && !SW_TEXT if( bHires ) - addr = updateVideoScannerAddressHGR(); + addr = getVideoScannerAddressHGR(); else - addr = updateVideoScannerAddressTXT(); + addr = getVideoScannerAddressTXT(); g_nVideoClockVert = currVideoClockVert; g_nVideoClockHorz = currVideoClockHorz; @@ -1839,55 +1831,93 @@ bool NTSC_GetColorBurst( void ) } //=========================================================================== -void GenerateVideoTables( void ) + +static bool CheckVideoTables2( eApple2Type type, uint32_t mode ) +{ + SetApple2Type(type); + NTSC_VideoInitAppleType(); + + g_uVideoMode = mode; + + g_dwCyclesThisFrame = 0; + g_nVideoClockHorz = g_nVideoClockVert = 0; + + for (DWORD cycles=0; cycles= kVPresetLine)) // check for previous vertical state preset + if (nVLine >= kVPresetLine) // check for previous vertical state preset { nVState -= nScanLines; // compensate for preset } @@ -835,6 +850,8 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, DWORD nCycles) nAddress |= h_1 << 1; // a1 nAddress |= h_2 << 2; // a2 nAddress |= nSum << 3; // a3 - a6 + g_PartialH = nAddress; + nAddress |= v_0 << 7; // a7 nAddress |= v_1 << 8; // a8 nAddress |= v_2 << 9; // a9 @@ -849,6 +866,8 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, DWORD nCycles) nAddress |= v_A << 10; // a10 nAddress |= v_B << 11; // a11 nAddress |= v_C << 12; // a12 + g_PartialV = nAddress - g_PartialH; + nAddress |= p2a << 13; // a13 nAddress |= p2b << 14; // a14 } @@ -856,24 +875,23 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, DWORD nCycles) { // N: insert text-only address bits // - nAddress |= p2a << 10; // a10 - nAddress |= p2b << 11; // a11 + g_PartialV = nAddress - g_PartialH; // Apple ][ (not //e) and HBL? // if (IS_APPLE2 && // Apple II only (UTAIIe:I-4,#5) !h_5 && (!h_4 || !h_3)) // HBL (UTAIIe:8-10,F8.5) { - nAddress |= 1 << 12; // Y: a12 (add $1000 to address!) + nAddress |= 1 << 12; // Y: a12 (add $1000 to address!) + g_PartialH |= 1 << 12; } - } - // update VBL' state - // - if (pbVblBar_OUT != NULL) - { - *pbVblBar_OUT = !v_4 || !v_3; // VBL' = (v_4 & v_3)' (UTAIIe:5-10,#3) + nAddress |= p2a << 10; // a10 + nAddress |= p2b << 11; // a11 } + + // VBL' = v_4' | v_3' = (v_4 & v_3)' (UTAIIe:5-10,#3) + return static_cast(nAddress); } diff --git a/source/Video.h b/source/Video.h index 1e133a11..3bacb655 100644 --- a/source/Video.h +++ b/source/Video.h @@ -169,7 +169,9 @@ void VideoRedrawScreen (void); void VideoRefreshScreen (uint32_t uRedrawWholeScreenVideoMode = 0, bool bRedrawWholeScreen = false); void VideoReinitialize (); void VideoResetState (); -WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles); +WORD VideoGetScannerAddressPartialV(DWORD nCycles); +WORD VideoGetScannerAddressPartialH(DWORD nCycles); +WORD VideoGetScannerAddress(DWORD nCycles); bool VideoGetVblBar(DWORD uExecutedCycles); bool VideoGetSW80COL(void); From bd7a96ce6e25877a2f30015b231520700f693df5 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 6 Aug 2018 19:06:28 +0100 Subject: [PATCH 044/128] Small refactor of VideoGetScannerAddress() --- source/NTSC.cpp | 8 ++-- source/Video.cpp | 113 +++++++++++++++++++++-------------------------- source/Video.h | 5 +-- 3 files changed, 57 insertions(+), 69 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index b97b5b6b..29dd332c 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1886,7 +1886,7 @@ static void GenerateVideoTables( void ) g_uVideoMode = VF_HIRES; for (UINT i=0, cycle=VIDEO_SCANNER_HORZ_START; i= kVPresetLine) // check for previous vertical state preset { - nVState -= nScanLines; // compensate for preset + nVState -= kScanLines; // compensate for preset } int v_A = (nVState >> 0) & 1; // get vertical state bits int v_B = (nVState >> 1) & 1; @@ -835,9 +820,9 @@ WORD VideoGetScannerAddress(DWORD nCycles) // calculate scanning memory address // - if (nHires && SW_MIXED && v_4 && v_2) // HIRES TIME signal (UTAIIe:5-7,P3) + if (bHires && SW_MIXED && v_4 && v_2) // HIRES TIME signal (UTAIIe:5-7,P3) { - nHires = 0; // address is in text memory for mixed hires + bHires = false; // address is in text memory for mixed hires } int nAddend0 = 0x0D; // 1 1 0 1 @@ -845,54 +830,58 @@ WORD VideoGetScannerAddress(DWORD nCycles) int nAddend2 = (v_4 << 3) | (v_3 << 2) | (v_4 << 1) | (v_3 << 0); int nSum = (nAddend0 + nAddend1 + nAddend2) & 0x0F; // SUM (UTAIIe:5-9) - int nAddress = 0; // build address from video scanner equations (UTAIIe:5-8,T5.1) - nAddress |= h_0 << 0; // a0 - nAddress |= h_1 << 1; // a1 - nAddress |= h_2 << 2; // a2 - nAddress |= nSum << 3; // a3 - a6 - g_PartialH = nAddress; + WORD nAddressH = 0; // build address from video scanner equations (UTAIIe:5-8,T5.1) + nAddressH |= h_0 << 0; // a0 + nAddressH |= h_1 << 1; // a1 + nAddressH |= h_2 << 2; // a2 + nAddressH |= nSum << 3; // a3 - a6 + if (!bHires) + { + // Apple ][ (not //e) and HBL? + // + if (IS_APPLE2 && // Apple II only (UTAIIe:I-4,#5) + !h_5 && (!h_4 || !h_3)) // HBL (UTAIIe:8-10,F8.5) + { + nAddressH |= 1 << 12; // Y: a12 (add $1000 to address!) + } + } - nAddress |= v_0 << 7; // a7 - nAddress |= v_1 << 8; // a8 - nAddress |= v_2 << 9; // a9 + WORD nAddressV = 0; + nAddressV |= v_0 << 7; // a7 + nAddressV |= v_1 << 8; // a8 + nAddressV |= v_2 << 9; // a9 - int p2a = !(nPage2 && !n80Store); - int p2b = nPage2 && !n80Store; + int p2a = !(bPage2 && !b80Store) ? 1 : 0; + int p2b = (bPage2 && !b80Store) ? 1 : 0; - if (nHires) // hires? + WORD nAddressP = 0; // Page bits + if (bHires) // hires? { // Y: insert hires-only address bits // - nAddress |= v_A << 10; // a10 - nAddress |= v_B << 11; // a11 - nAddress |= v_C << 12; // a12 - g_PartialV = nAddress - g_PartialH; - - nAddress |= p2a << 13; // a13 - nAddress |= p2b << 14; // a14 + nAddressV |= v_A << 10; // a10 + nAddressV |= v_B << 11; // a11 + nAddressV |= v_C << 12; // a12 + nAddressP |= p2a << 13; // a13 + nAddressP |= p2b << 14; // a14 } else { // N: insert text-only address bits // - g_PartialV = nAddress - g_PartialH; - - // Apple ][ (not //e) and HBL? - // - if (IS_APPLE2 && // Apple II only (UTAIIe:I-4,#5) - !h_5 && (!h_4 || !h_3)) // HBL (UTAIIe:8-10,F8.5) - { - nAddress |= 1 << 12; // Y: a12 (add $1000 to address!) - g_PartialH |= 1 << 12; - } - - nAddress |= p2a << 10; // a10 - nAddress |= p2b << 11; // a11 + nAddressP |= p2a << 10; // a10 + nAddressP |= p2b << 11; // a11 } // VBL' = v_4' | v_3' = (v_4 & v_3)' (UTAIIe:5-10,#3) - return static_cast(nAddress); + if (videoScannerAddr == VS_PartialAddrH) + return nAddressH; + + if (videoScannerAddr == VS_PartialAddrV) + return nAddressV; + + return nAddressP | nAddressV | nAddressH; } //=========================================================================== @@ -903,7 +892,7 @@ bool VideoGetVblBar(const DWORD uExecutedCycles) int nCycles = CpuGetCyclesThisVideoFrame(uExecutedCycles); // calculate video parameters according to display standard - const int kScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines; + const int kScanLines = g_bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines; const int kScanCycles = kScanLines * kHClocks; nCycles %= kScanCycles; diff --git a/source/Video.h b/source/Video.h index 3bacb655..bd064502 100644 --- a/source/Video.h +++ b/source/Video.h @@ -169,9 +169,8 @@ void VideoRedrawScreen (void); void VideoRefreshScreen (uint32_t uRedrawWholeScreenVideoMode = 0, bool bRedrawWholeScreen = false); void VideoReinitialize (); void VideoResetState (); -WORD VideoGetScannerAddressPartialV(DWORD nCycles); -WORD VideoGetScannerAddressPartialH(DWORD nCycles); -WORD VideoGetScannerAddress(DWORD nCycles); +enum VideoScanner_e {VS_FullAddr, VS_PartialAddrV, VS_PartialAddrH}; +WORD VideoGetScannerAddress(DWORD nCycles, VideoScanner_e videoScannerAddr = VS_FullAddr); bool VideoGetVblBar(DWORD uExecutedCycles); bool VideoGetSW80COL(void); From 74c0ca2cdec41f04d08a0be59eeb82a138bb4a59 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 6 Aug 2018 21:40:20 +0100 Subject: [PATCH 045/128] 1.27.7: Bump version & update History.txt & update docs for new switches --- bin/History.txt | 9 +++++++++ help/CommandLine.html | 9 ++++++++- help/keyboard.html | 2 +- help/savestate.html | 4 +++- resource/Applewin.rc | 8 ++++---- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 9bbe234a..5ae99a94 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -8,6 +8,15 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.27.7.0 - 6 Aug 2018 +--------------------- +. [Bug #564] Fixed 'Save State on Exit' not working correctly when there's a Configuration change to the hardware. +. [Bug #556] Reverted default so that ALT+TAB is not hooked (#556) + - Support new command line switch: -hook-alt-tab to support hooking ALT+TAB. +. [Bug #558] Reverted default so that ALT GR's fake LEFT CONTROL is not hooked (#558) + - Support new command line switch: -hook-altgr-control to suppess ALR GR's fake LEFT CONTROL. + + 1.27.6.0 - 28 Jul 2018 ---------------------- . [Bug #570] Fixed lag when repeat-stepping in debugger. diff --git a/help/CommandLine.html b/help/CommandLine.html index f8c17778..73b56862 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -43,7 +43,14 @@ -no-printscreen-key
              Prevent the PrintScreen key from being registered

              -no-hook-system-key
              - Prevent certain system key combinations from being hooked (to prevent the emulator from trapping ALT+ESC, ALT+SPACE, ALT+TAB and CTRL+ESC). This means that the equivalent Open Apple+<key> combinations won't work within the emulator.

              + Prevent certain system key combinations from being hooked (to prevent the emulator from trapping ALT+ESC, ALT+SPACE, ALT+TAB and CTRL+ESC). This means that the equivalent Open Apple+<key> combinations won't work within the emulator.
              + NB. This switch takes precedence over -hook-alt-tab and -hook-altgr-control.

              + -hook-alt-tab
              + By default the emulator doesn't hook ALT+TAB. Use this to allow Open Apple+TAB to be readable by the emulated machine.

              + -hook-altgr-control
              + By default the emulator doesn't suppress ALT GR's (Right Alt's) fake LEFT CONTROL. Use this to suppress this fake LEFT CONTROL to allow Closed Apple+CTRL+<key> to be readable by the emulated machine.
              + NB. Suppressing this fake LEFT CONTROL seems to prevent international keyboards from being able to type certain keys. +

              -use-real-printer
              Enables Advanced configuration control to allow dumping to a real printer

              -noreg
              diff --git a/help/keyboard.html b/help/keyboard.html index 5e6de04d..a228e2f1 100644 --- a/help/keyboard.html +++ b/help/keyboard.html @@ -29,7 +29,7 @@ The Solid Apple key was introduced on the Apple //e and later renamed to the Option key. This key is emulated with the PC's Right Alt - key, which is in the same position as the Solid Apple key on the original //e. + key (or Alt Gr key), which is in the same position as the Solid Apple key on the original //e.

              Numeric Keypad:
              The numeric keypad, introduced on the Extended Keyboard //e, is emulated diff --git a/help/savestate.html b/help/savestate.html index 87847144..ff5595f5 100644 --- a/help/savestate.html +++ b/help/savestate.html @@ -13,7 +13,8 @@

              The complete1 Apple //e state can be saved to a PC file at any time. This can be useful for continuity across AppleWin sessions or to help with games that don't have a save option.

              -

              This is controlled by the AppleWin Configuration tab labelled Advanced.

              +

              The state can optionally be automatically saved on AppleWin exit, and (automatically) restored on AppleWin restart.

              +

              This is all controlled by the AppleWin Configuration tab labeled Advanced.

              Details:

              The entire Apple //e state is saved to a human-readable (.yaml) file.

              1 @@ -28,6 +29,7 @@

            • Mouse card
            • CP/M SoftCard
            • Parallel Printer card
            • +
            • Super Serial card
            The following are not yet persisted to the file:
              diff --git a/resource/Applewin.rc b/resource/Applewin.rc index a71c4458..d93fa74e 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,6,0 - PRODUCTVERSION 1,27,6,0 + FILEVERSION 1,27,7,0 + PRODUCTVERSION 1,27,7,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 6, 0" + VALUE "FileVersion", "1, 27, 7, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 6, 0" + VALUE "ProductVersion", "1, 27, 7, 0" END END BLOCK "VarFileInfo" From 396c55d8a3ac36d85a4f8c8d9e10504f1375ea27 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 12 Aug 2018 12:48:08 +0100 Subject: [PATCH 046/128] Coverity: tackled a few CIDs (#470) --- source/Applewin.cpp | 2 ++ source/DiskImageHelper.cpp | 70 ++++++++++++++++++++++---------------- source/ParallelPrinter.cpp | 19 +++++++++-- source/SerialComms.cpp | 1 + 4 files changed, 60 insertions(+), 32 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 46cfbda8..5fa5dce3 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1399,6 +1399,8 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) unsigned long fix_minor = g_AppleWinVersion[3] = pFixedFileInfo->dwFileVersionLS & 0xffff; sprintf(VERSIONSTRING, "%d.%d.%d.%d", major, minor, fix, fix_minor); // potential buffer overflow } + + delete [] pVerInfoBlock; } LogFileOutput("AppleWin version: %s\n", VERSIONSTRING); diff --git a/source/DiskImageHelper.cpp b/source/DiskImageHelper.cpp index 5aa50d5d..f1c1a4e1 100644 --- a/source/DiskImageHelper.cpp +++ b/source/DiskImageHelper.cpp @@ -1214,41 +1214,53 @@ ImageError_e CImageHelperBase::CheckZipFile(LPCTSTR pszImageFilename, ImageInfo* return eIMAGE_ERROR_UNABLE_TO_OPEN_ZIP; unz_global_info global_info; - int nRes = unzGetGlobalInfo(hZipFile, &global_info); - if (nRes != UNZ_OK) - return eIMAGE_ERROR_ZIP; - - nRes = unzGoToFirstFile(hZipFile); // Only support 1st file in zip archive for now - if (nRes != UNZ_OK) - return eIMAGE_ERROR_ZIP; - unz_file_info file_info; char szFilename[MAX_PATH]; memset(szFilename, 0, sizeof(szFilename)); - nRes = unzGetCurrentFileInfo(hZipFile, &file_info, szFilename, MAX_PATH, NULL, 0, NULL, 0); - if (nRes != UNZ_OK) - return eIMAGE_ERROR_ZIP; + int nRes = 0, nLen = 0; - const UINT uFileSize = file_info.uncompressed_size; - if (uFileSize > GetMaxImageSize()) - return eIMAGE_ERROR_BAD_SIZE; - - pImageInfo->pImageBuffer = new BYTE[uFileSize]; - - nRes = unzOpenCurrentFile(hZipFile); - if (nRes != UNZ_OK) - return eIMAGE_ERROR_ZIP; - - int nLen = unzReadCurrentFile(hZipFile, pImageInfo->pImageBuffer, uFileSize); - if (nLen < 0) + try { - unzCloseCurrentFile(hZipFile); // Must CloseCurrentFile before Close - return eIMAGE_ERROR_UNSUPPORTED; - } + nRes = unzGetGlobalInfo(hZipFile, &global_info); + if (nRes != UNZ_OK) + throw eIMAGE_ERROR_ZIP; - nRes = unzCloseCurrentFile(hZipFile); - if (nRes != UNZ_OK) - return eIMAGE_ERROR_ZIP; + nRes = unzGoToFirstFile(hZipFile); // Only support 1st file in zip archive for now + if (nRes != UNZ_OK) + throw eIMAGE_ERROR_ZIP; + + nRes = unzGetCurrentFileInfo(hZipFile, &file_info, szFilename, MAX_PATH, NULL, 0, NULL, 0); + if (nRes != UNZ_OK) + throw eIMAGE_ERROR_ZIP; + + const UINT uFileSize = file_info.uncompressed_size; + if (uFileSize > GetMaxImageSize()) + throw eIMAGE_ERROR_BAD_SIZE; + + pImageInfo->pImageBuffer = new BYTE[uFileSize]; + + nRes = unzOpenCurrentFile(hZipFile); + if (nRes != UNZ_OK) + throw eIMAGE_ERROR_ZIP; + + nLen = unzReadCurrentFile(hZipFile, pImageInfo->pImageBuffer, uFileSize); + if (nLen < 0) + { + unzCloseCurrentFile(hZipFile); // Must CloseCurrentFile before Close + throw eIMAGE_ERROR_UNSUPPORTED; + } + + nRes = unzCloseCurrentFile(hZipFile); + if (nRes != UNZ_OK) + throw eIMAGE_ERROR_ZIP; + } + catch (ImageError_e error) + { + if (hZipFile) + unzClose(hZipFile); + + return error; + } nRes = unzClose(hZipFile); hZipFile = NULL; diff --git a/source/ParallelPrinter.cpp b/source/ParallelPrinter.cpp index 1c6db6bd..0916b083 100644 --- a/source/ParallelPrinter.cpp +++ b/source/ParallelPrinter.cpp @@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Applewin.h" +#include "Frame.h" // g_hFrameWindow #include "Memory.h" #include "ParallelPrinter.h" #include "Registry.h" @@ -234,14 +235,26 @@ char* Printer_GetFilename() void Printer_SetFilename(char* prtFilename) { - if(*prtFilename) + if (*prtFilename) + { strcpy(g_szPrintFilename, (const char *) prtFilename); + } else //No registry entry is available { _tcsncpy(g_szPrintFilename, g_sProgramDir, MAX_PATH); g_szPrintFilename[MAX_PATH - 1] = 0; - _tcsncat(g_szPrintFilename, _T(DEFAULT_PRINT_FILENAME), MAX_PATH); - RegSaveString(TEXT("Configuration"),REGVALUE_PRINTER_FILENAME,1,g_szPrintFilename); + + // NB. _tcsncat_s() terminates program if buffer is too small! So continue to use manual buffer check & _tcsncat() + + int nLen = sizeof(g_szPrintFilename) - strlen(g_szPrintFilename) - (sizeof(DEFAULT_PRINT_FILENAME)-1) - 1; + if (nLen < 0) + { + MessageBox(g_hFrameWindow, "Printer - SetFilename(): folder too deep", "Warning", MB_ICONWARNING | MB_OK); + return; + } + + _tcsncat(g_szPrintFilename, DEFAULT_PRINT_FILENAME, sizeof(DEFAULT_PRINT_FILENAME)-1); + RegSaveString(REG_CONFIG, REGVALUE_PRINTER_FILENAME, 1, g_szPrintFilename); } } diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp index 77302924..ac410d19 100644 --- a/source/SerialComms.cpp +++ b/source/SerialComms.cpp @@ -216,6 +216,7 @@ bool CSuperSerialCard::CheckComm() // have socket so attempt to bind it SOCKADDR_IN saAddress; + memset(&saAddress, 0, sizeof(SOCKADDR_IN)); saAddress.sin_family = AF_INET; saAddress.sin_port = htons(TCP_SERIAL_PORT); // TODO: get from registry / GUI saAddress.sin_addr.s_addr = htonl(INADDR_ANY); From 7d100a349bfcb4627cecad7660c5b977f96f5a56 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 9 Sep 2018 13:56:55 +0100 Subject: [PATCH 047/128] NTSC: Merge-squash from 'GH555-1-pixel' branch for the 1 pixel shift for 14M video modes (#555) --- source/Frame.cpp | 3 +- source/Frame.h | 1 - source/NTSC.cpp | 199 +++++++++++++++++++++++++++++++++++++++++++---- source/NTSC.h | 5 +- source/Video.cpp | 8 +- 5 files changed, 189 insertions(+), 27 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index b58379c0..eb4d5470 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Memory.h" #include "Mockingboard.h" #include "MouseInterface.h" +#include "NTSC.h" #include "ParallelPrinter.h" #include "Pravets.h" #include "Registry.h" @@ -199,7 +200,7 @@ void SetAltEnterToggleFullScreen(bool mode) UINT GetFrameBufferBorderlessWidth(void) { - static const UINT uFrameBufferBorderlessW = 560; // 560 = Double Hi-Res + static const UINT uFrameBufferBorderlessW = NTSC_GetFrameBufferBorderlessWidth(); // 560 = Double Hi-Res, +1 for GH#555 return uFrameBufferBorderlessW; } diff --git a/source/Frame.h b/source/Frame.h index f5cace2d..c072520b 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -3,7 +3,6 @@ // 1.19.0.0 Hard Disk Status/Indicator Light #define HD_LED 1 - // Win32 extern HWND g_hFrameWindow; extern int g_nViewportCX; diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 29dd332c..f47bd337 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -23,13 +23,23 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Applewin.h" #include "CPU.h" // CpuGetCyclesThisVideoFrame() - #include "Frame.h" // FRAMEBUFFER_W FRAMEBUFFER_H + #include "Frame.h" #include "Memory.h" // MemGetMainPtr() MemGetBankPtr() #include "Video.h" // g_pFramebufferbits #include "NTSC.h" #include "NTSC_CharSet.h" + +// GH#555: Extend the 14M video modes by 1 pixel +// . 14M (DHGR,DGR,80COL) are shifted right by 1 pixel, so zero out the left-most visible pixel. +// . 7M (all other modes) are not shift right by 1 pixel, so zero out the right-most visible pixel. +// NB. This 1 pixel shift is a workaround for the 14M video modes that actually start 7x 14M pixels to the left on *real h/w*. +// . 7x 14M pixels early + 1x 14M pixel shifted right = 2 complete color phase rotations. +// . ie. the 14M colors are correct, but being 1 pixel out is the closest we can get the 7M and 14M video modes to overlap. +// . The alternative is to render the 14M correctly 7 pixels early, but have 7-pixel borders left (for 7M modes) or right (for 14M modes). +#define EXTEND_14M_VIDEO_BY_1_PIXEL 1 + #define NTSC_REMOVE_WHITE_RINGING 1 // 0 = theoritical dimmed white has chroma, 1 = pure white without chroma tinting #define NTSC_REMOVE_BLACK_GHOSTING 1 // 1 = remove black smear/smudges carrying over #define NTSC_REMOVE_GRAY_CHROMA 1 // 1 = remove all chroma in gray1 and gray2 @@ -120,6 +130,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // "There are exactly 17030 (65 x 262) 6502 cycles in every television scan of an American Apple." #define VIDEO_SCANNER_MAX_HORZ 65 // TODO: use Video.cpp: kHClocks #define VIDEO_SCANNER_MAX_VERT 262 // TODO: use Video.cpp: kNTSCScanLines + static const int VIDEO_SCANNER_6502_CYCLES = VIDEO_SCANNER_MAX_HORZ * VIDEO_SCANNER_MAX_VERT; #define VIDEO_SCANNER_HORZ_COLORBURST_BEG 12 #define VIDEO_SCANNER_HORZ_COLORBURST_END 16 @@ -440,6 +451,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA static void updateScreenText40 ( long cycles6502 ); static void updateScreenText80 ( long cycles6502 ); +//=========================================================================== +// NB. This func only exists so that EXTEND_14M_VIDEO_BY_1_PIXEL only needs to exist in this cpp file! +UINT NTSC_GetFrameBufferBorderlessWidth(void) +{ +#if !EXTEND_14M_VIDEO_BY_1_PIXEL + return 560; // 560 = Double Hi-Res +#else + return 561; // 560 = Double Hi-Res, +1 for GH#555 +#endif +} + //=========================================================================== static void set_csbits() { @@ -657,13 +679,19 @@ inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTa } #endif +//=========================================================================== +inline bool GetColorBurst( void ) +{ + return g_nColorBurstPixels >= 2; +} + //=========================================================================== // NB. g_nLastColumnPixelNTSC = bits.b13 will be superseded by these parent funcs which use bits.b14: // . updateScreenDoubleHires80(), updateScreenDoubleLores80(), updateScreenText80() inline void updatePixels( uint16_t bits ) { - if (g_nColorBurstPixels < 2) + if (!GetColorBurst()) { /* #1 of 7 */ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1; @@ -716,27 +744,70 @@ inline void updatePixels( uint16_t bits ) } //=========================================================================== + +#if !EXTEND_14M_VIDEO_BY_1_PIXEL +// NOTE: This writes out-of-bounds for a 560x384 framebuffer inline void updateVideoScannerHorzEOL() { if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) { if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) { - //VIDEO_DRAW_ENDLINE(); - if (g_nColorBurstPixels < 2) + if (!GetColorBurst()) { - // NOTE: This writes out-of-bounds for a 560x384 framebuffer + // Only for: VF_TEXT && !VF_MIXED (ie. full 24-row TEXT40 or TEXT80) g_pFuncUpdateBnWPixel(g_nLastColumnPixelNTSC); g_pFuncUpdateBnWPixel(0); g_pFuncUpdateBnWPixel(0); - g_pFuncUpdateBnWPixel(0); } else { - // NOTE: This writes out-of-bounds for a 560x384 framebuffer g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); g_pFuncUpdateHuePixel(0); g_pFuncUpdateHuePixel(0); + } + } + + g_nVideoClockHorz = 0; + + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) + { + g_nVideoClockVert = 0; + + updateFlashRate(); + } + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + updateVideoScannerAddress(); + } + } +} +#endif + +//------------------------------------- + +#if EXTEND_14M_VIDEO_BY_1_PIXEL +// NB. Only needed for video modes that are 14M and shift the color phase, ie: +// . updateScreenDoubleHires80(), updateScreenDoubleLores80(), updateScreenText80() +// NOTE: This writes out-of-bounds for a 560x384 framebuffer +inline void updateVideoScannerHorzEOL_14M() +{ + if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) + { + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if (!GetColorBurst()) + { + // Only for: VF_TEXT && !VF_MIXED (ie. full 24-row TEXT40 or TEXT80) + g_pFuncUpdateBnWPixel(g_nLastColumnPixelNTSC); // 14M: Output a 561st dot + g_pFuncUpdateBnWPixel(0); + g_pFuncUpdateBnWPixel(0); + } + else + { + g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); // 14M: Output a 561st dot + g_pFuncUpdateHuePixel(0); g_pFuncUpdateHuePixel(0); } } @@ -757,10 +828,63 @@ inline void updateVideoScannerHorzEOL() } } +//----------------- + +// NOTE: This writes out-of-bounds for a 560x384 framebuffer +inline void updateVideoScannerHorzEOL() +{ + if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz) + { + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + if ( !GetColorBurst() || // Only for: VF_TEXT && !VF_MIXED (ie. full 24-row TEXT40 or TEXT80) + (g_eVideoType == VT_MONO_CUSTOM) || (g_eVideoType == VT_MONO_AMBER) || (g_eVideoType == VT_MONO_GREEN) || (g_eVideoType == VT_MONO_WHITE) ) + { + g_pFuncUpdateBnWPixel(0); + g_pFuncUpdateBnWPixel(0); + + // 7M: Stop outputting video after 560 dots + *(UINT32*)&g_pVideoAddress[0] = 0; + *(UINT32*)&g_pVideoAddress[g_kFrameBufferWidth] = 0; + } + else + { + g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); + g_pFuncUpdateHuePixel(0); + + // 7M: Stop outputting video after 560 dots + *(UINT32*)&g_pVideoAddress[0] = 0; + *(UINT32*)&g_pVideoAddress[g_kFrameBufferWidth] = 0; + } + } + + g_nVideoClockHorz = 0; + + if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT) + { + g_nVideoClockVert = 0; + + updateFlashRate(); + } + + if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) + { + updateVideoScannerAddress(); + } + } +} +#endif + //=========================================================================== inline void updateVideoScannerAddress() { - g_pVideoAddress = g_nVideoClockVert> 14) & 1; + +#if EXTEND_14M_VIDEO_BY_1_PIXEL + zeroPixel0_14M(); +#endif } } +#if EXTEND_14M_VIDEO_BY_1_PIXEL + updateVideoScannerHorzEOL_14M(); +#else updateVideoScannerHorzEOL(); +#endif } } @@ -1217,6 +1375,7 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores uint16_t lo = getLoResBits( m ); uint16_t bits = g_aPixelDoubleMaskHGR[(0xFF & lo >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits updatePixels( bits ); + // NB. No zeroPixel0_14M(), since no color phase shift (or use of g_nLastColumnPixelNTSC) } } updateVideoScannerHorzEOL(); @@ -1258,9 +1417,18 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores uint16_t bits = (main << 7) | (aux & 0x7f); updatePixels( bits ); g_nLastColumnPixelNTSC = (bits >> 14) & 1; + +#if EXTEND_14M_VIDEO_BY_1_PIXEL + zeroPixel0_14M(); +#endif } } +#if EXTEND_14M_VIDEO_BY_1_PIXEL + updateVideoScannerHorzEOL_14M(); +#else updateVideoScannerHorzEOL(); +#endif + } } @@ -1404,9 +1572,18 @@ void updateScreenText80 (long cycles6502) bits = (bits << 1) | g_nLastColumnPixelNTSC; // GH#555: Align TEXT80 chars with DHGR updatePixels( bits ); g_nLastColumnPixelNTSC = (bits >> 14) & 1; + +#if EXTEND_14M_VIDEO_BY_1_PIXEL + zeroPixel0_14M(); +#endif } } +#if EXTEND_14M_VIDEO_BY_1_PIXEL + updateVideoScannerHorzEOL_14M(); +#else updateVideoScannerHorzEOL(); +#endif + } } @@ -1824,12 +2001,6 @@ void NTSC_VideoRedrawWholeScreen( void ) #endif } -//=========================================================================== -bool NTSC_GetColorBurst( void ) -{ - return (g_nColorBurstPixels < 2) ? false : true; -} - //=========================================================================== static bool CheckVideoTables2( eApple2Type type, uint32_t mode ) diff --git a/source/NTSC.h b/source/NTSC.h index 50ea29d1..d81f283b 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -1,6 +1,3 @@ -// Constants - const int VIDEO_SCANNER_6502_CYCLES = 17030; - // Globals (Public) extern uint16_t g_nVideoClockVert; extern uint16_t g_nVideoClockHorz; @@ -19,4 +16,4 @@ extern void NTSC_VideoInitChroma(); extern void NTSC_VideoUpdateCycles( long cycles6502 ); extern void NTSC_VideoRedrawWholeScreen( void ); - extern bool NTSC_GetColorBurst( void ); + extern UINT NTSC_GetFrameBufferBorderlessWidth( void ); diff --git a/source/Video.cpp b/source/Video.cpp index c5808efa..d5663f3b 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -567,6 +567,7 @@ void VideoRedrawScreen (void) //=========================================================================== // TC: Hacky-fix for GH#341 - better to draw to the correct position in the framebuffer to start with! (in NTSC.cpp) +// . NB. Now the dx is corrected in NTSC.cpp, updateVideoScannerAddress() static void VideoFrameBufferAdjust(int& xSrc, int& ySrc, bool bInvertY=false) { int dx=0, dy=0; @@ -574,15 +575,8 @@ static void VideoFrameBufferAdjust(int& xSrc, int& ySrc, bool bInvertY=false) if (g_eVideoType == VT_MONO_TV || g_eVideoType == VT_COLOR_TV) { // Adjust the src locations for the NTSC video modes - dx = 2; dy = -1; } - else if (g_eVideoType == VT_COLOR_MONITOR) - { - //if ((g_uVideoMode & VF_TEXT) == 0) // NB. Not sufficient, eg. ANSI STORY... - if ( NTSC_GetColorBurst() == true ) // ANSI STORY (end credits): split DGR/TEXT80/DGR on scanline - dx = 2; - } if (bInvertY) dy =- dy; From 39f91c552c1848a893ec2fd1b204ead7993927eb Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 9 Sep 2018 15:41:04 +0100 Subject: [PATCH 048/128] NTSC (#555) . For the 14M video modes (DHGR,DGR,80COL), start rendering 1x 14M pixel early to account for these video modes being shifted right by 1 pixel . Revert the display width back to 560 by disabling EXTEND_14M_VIDEO_BY_1_PIXEL --- source/NTSC.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index f47bd337..007ea275 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -38,7 +38,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // . 7x 14M pixels early + 1x 14M pixel shifted right = 2 complete color phase rotations. // . ie. the 14M colors are correct, but being 1 pixel out is the closest we can get the 7M and 14M video modes to overlap. // . The alternative is to render the 14M correctly 7 pixels early, but have 7-pixel borders left (for 7M modes) or right (for 14M modes). -#define EXTEND_14M_VIDEO_BY_1_PIXEL 1 +#define EXTEND_14M_VIDEO_BY_1_PIXEL 0 #define NTSC_REMOVE_WHITE_RINGING 1 // 0 = theoritical dimmed white has chroma, 1 = pure white without chroma tinting #define NTSC_REMOVE_BLACK_GHOSTING 1 // 1 = remove black smear/smudges carrying over @@ -878,12 +878,25 @@ inline void updateVideoScannerHorzEOL() //=========================================================================== inline void updateVideoScannerAddress() { - g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY ? g_pScanLines[2*g_nVideoClockVert] : g_pScanLines[0]; + g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY ? g_pScanLines[2*g_nVideoClockVert] : g_pScanLines[0]; // Adjust, as these video styles have 2x 14M pixels of pre-render // NB. For VT_COLOR_MONITOR, also check color-burst so that TEXT and MIXED(HGR+TEXT) render the TEXT at the same offset (GH#341) if (g_eVideoType == VT_MONO_TV || g_eVideoType == VT_COLOR_TV || (g_eVideoType == VT_COLOR_MONITOR && GetColorBurst())) - g_pVideoAddress = (bgra_t*) ((UINT32*)g_pVideoAddress - 2); + g_pVideoAddress -= 2; + + // GH#555: For the 14M video modes (DHGR,DGR,80COL), start rendering 1x 14M pixel early to account for these video modes being shifted right by 1 pixel + // NB. This 1 pixel shift right is a workaround for the 14M video modes that actually start 7x 14M pixels to the left on *real h/w*. + // . 7x 14M pixels early + 1x 14M pixel shifted right = 2 complete color phase rotations. + // . ie. the 14M colors are correct, but being 1 pixel out is the closest we can get the 7M and 14M video modes to overlap. + // . The alternative is to render the 14M correctly 7 pixels early, but have 7-pixel borders left (for 7M modes) or right (for 14M modes). + if ((g_pFuncUpdateGraphicsScreen == updateScreenDoubleHires80) || + (g_pFuncUpdateGraphicsScreen == updateScreenDoubleLores80) || + (g_pFuncUpdateGraphicsScreen == updateScreenText80) || + (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && g_pFuncUpdateTextScreen == updateScreenText80)) + { + g_pVideoAddress -= 1; + } g_nColorPhaseNTSC = INITIAL_COLOR_PHASE; g_nLastColumnPixelNTSC = 0; @@ -1819,7 +1832,6 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++) { uint32_t offset = sizeof(bgra_t) * GetFrameBufferWidth() * ((GetFrameBufferHeight() - 1) - y - GetFrameBufferBorderHeight()) + (sizeof(bgra_t) * GetFrameBufferBorderWidth()); -// offset -= sizeof(bgra_t); // GH#555: Start 1 RGBA pixel before frame to account for g_nLastColumnPixelNTSC // TC: revert as lose half an HGR pixel on left-edge g_pScanLines[y] = (bgra_t*) (g_pFramebufferbits + offset); } From 18622cb11357014886842e30c26f38d6588ee6d7 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 9 Sep 2018 15:50:55 +0100 Subject: [PATCH 049/128] 1.27.8: Bump version & update History.txt --- bin/History.txt | 5 +++++ resource/Applewin.rc | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 5ae99a94..7eaeeef0 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -8,6 +8,11 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.27.8.0 - 9 Sep 2018 +--------------------- +. [Bug #555] Fix for showing 559th DHGR/DGR/TEXT80 vertical column (retaining 560-pixel display width). + + 1.27.7.0 - 6 Aug 2018 --------------------- . [Bug #564] Fixed 'Save State on Exit' not working correctly when there's a Configuration change to the hardware. diff --git a/resource/Applewin.rc b/resource/Applewin.rc index d93fa74e..88b11363 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,7,0 - PRODUCTVERSION 1,27,7,0 + FILEVERSION 1,27,8,0 + PRODUCTVERSION 1,27,8,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 7, 0" + VALUE "FileVersion", "1, 27, 8, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 7, 0" + VALUE "ProductVersion", "1, 27, 8, 0" END END BLOCK "VarFileInfo" From a15e5a47f60c988c9ef0c60e35fb59235cccdc6f Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 10 Sep 2018 21:28:08 +0100 Subject: [PATCH 050/128] MemGetAuxPtr(): Refactor & added comment about video scanner fetching aux from the 1st 64K aux bank (#520) --- source/Memory.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index 70e308ea..f53719aa 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1095,11 +1095,14 @@ LPBYTE MemGetAuxPtr(const WORD offset) : memaux+offset; #ifdef RAMWORKS - if ( ((SW_PAGE2 && SW_80STORE) || VideoGetSW80COL()) && - ( ( ((offset & 0xFF00)>=0x0400) && - ((offset & 0xFF00)<=0x0700) ) || - ( SW_HIRES && ((offset & 0xFF00)>=0x2000) && - ((offset & 0xFF00)<=0x3F00) ) ) ) { + // Video scanner (for 14M video modes) always fetches from 1st 64K aux bank (UTAIIe ref?) + if (((SW_PAGE2 && SW_80STORE) || VideoGetSW80COL()) && + ( + ( ((offset & 0xFF00)>=0x0400) && ((offset & 0xFF00)<=0x0700) ) || + ( SW_HIRES && ((offset & 0xFF00)>=0x2000) && ((offset & 0xFF00)<=0x3F00) ) + ) + ) + { lpMem = (memshadow[(offset >> 8)] == (RWpages[0]+(offset & 0xFF00))) ? mem+offset : RWpages[0]+offset; From a2d05ca3861eccfa7c4cadbfc0bc51291b7cc754 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 16 Sep 2018 22:02:35 +0100 Subject: [PATCH 051/128] mem(cache): provide more details about how the mem(cache) and associated variables work, eg. when reading/writing to the same or different memory banks --- source/Memory.cpp | 94 +++++++++++++++++++++++++++++++++++------------ source/NTSC.cpp | 2 +- 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index f53719aa..4313cae6 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -79,7 +79,7 @@ MEMORY MANAGEMENT SOFT SWITCHES $C000 W 80STOREOFF Allow page2 to switch video page1 page2 $C001 W 80STOREON Allow page2 to switch main & aux video memory $C002 W RAMRDOFF Read enable main memory from $0200-$BFFF - $C003 W RAMDRON Read enable aux memory from $0200-$BFFF + $C003 W RAMRDON Read enable aux memory from $0200-$BFFF $C004 W RAMWRTOFF Write enable main memory from $0200-$BFFF $C005 W RAMWRTON Write enable aux memory from $0200-$BFFF $C006 W INTCXROMOFF Enable slot ROM from $C100-$C7FF (but $C800-$CFFF depends on INTC8ROM) @@ -129,29 +129,44 @@ SOFT SWITCH STATUS FLAGS // Notes // ----- // -// mem -// - a copy of the memimage ptr -// // memimage // - 64KB +// +// mem +// (a pointer to memimage 64KB) +// - a 64KB r/w memory cache // - reflects the current readable memory in the 6502's 64K address space // . excludes $Cxxx I/O memory // . could be a mix of RAM/ROM, main/aux, etc +// - may also reflect the current writeable memory (on a 256-page granularity) if the write page addr == read page addr +// . for this case, the memdirty flag(s) are valid +// . when writes instead occur to backing-store, then memdirty flag(s) can be ignored // // memmain, memaux -// - physical contiguous 64KB RAM for main & aux respectively +// - physical contiguous 64KB "backing-store" for main & aux respectively +// - NB. 4K bank1 BSR is at $C000-$CFFF // // memwrite -// - 1 ptr entry per 256-byte page +// - 1 pointer entry per 256-byte page // - used to write to a page +// - if RD & WR point to the same 256-byte RAM page, then memwrite will point to the page in 'mem' +// . ie. when SW_AUXREAD==SW_AUXWRITE, or 4K-BSR is r/w, or 8K BSR is r/w, or SW_80STORE=1 +// . So 'mem' remains correct for both r&w operations, but the physical 64K mem block becomes stale +// - if RD & WR point to different 256-byte pages, then memwrite will point to the page in the physical 64K mem block +// . writes will still set the dirty flag (but can be ignored) +// . UpdatePaging() ignores this, as it only copies back to the physical 64K mem block when memshadow changes (for that 256-byte page) // // memdirty // - 1 byte entry per 256-byte page // - set when a write occurs to a 256-byte page +// - indicates that 'mem' (ie. the cache) is out-of-sync with the "physical" 64K backing-store memory +// - NB. a page's dirty flag is only useful(valid) when 'mem' is used for both read & write for the corresponding page +// When they differ, then writes go directly to the backing-store. +// . In this case, the dirty flag will just force a memcpy() to the same address in backing-store. // // memshadow -// - 1 ptr entry per 256-byte page -// - reflects how 'mem' is setup +// - 1 pointer entry per 256-byte page +// - reflects how 'mem' is setup for read operations (at a 256-byte granularity) // . EG: if ALTZP=1, then: // . mem will have copies of memaux's ZP & stack // . memshadow[0] = &memaux[0x0000] @@ -817,19 +832,6 @@ static bool IsCardInSlot(const UINT uSlot) //=========================================================================== -static void BackMainImage(void) -{ - for (UINT loop = 0; loop < 256; loop++) - { - if (memshadow[loop] && ((*(memdirty+loop) & 1) || (loop <= 1))) - CopyMemory(memshadow[loop], memimage+(loop << 8), 256); - - *(memdirty+loop) &= ~1; - } -} - -//=========================================================================== - DWORD GetMemMode(void) { return memmode; @@ -925,7 +927,7 @@ static void UpdatePaging(BOOL initialize) for (loop = 0xC0; loop < 0xC8; loop++) { - memdirty[loop] = 0; // ROM can't be dirty + memdirty[loop] = 0; // mem(cache) can't be dirty for ROM (but STA $Csnn will set the dirty flag) const UINT uSlotOffset = (loop & 0x0f) * 0x100; if (loop == 0xC3) memshadow[loop] = (SW_SLOTC3ROM && !SW_INTCXROM) ? pCxRomPeripheral+uSlotOffset // C300..C3FF - Slot 3 ROM (all 0x00's) @@ -937,7 +939,7 @@ static void UpdatePaging(BOOL initialize) for (loop = 0xC8; loop < 0xD0; loop++) { - memdirty[loop] = 0; // ROM can't be dirty (but STA $CFFF will set the dirty flag) + memdirty[loop] = 0; // mem(cache) can't be dirty for ROM (but STA $Cnnn will set the dirty flag) const UINT uRomOffset = (loop & 0x0f) * 0x100; memshadow[loop] = (!SW_INTCXROM && !INTC8ROM) ? pCxRomPeripheral+uRomOffset // C800..CFFF - Peripheral ROM (GH#486) : pCxRomInternal+uRomOffset; // C800..CFFF - Internal ROM @@ -1070,6 +1072,19 @@ bool MemCheckINTCXROM() //=========================================================================== +static void BackMainImage(void) +{ + for (UINT loop = 0; loop < 256; loop++) + { + if (memshadow[loop] && ((*(memdirty+loop) & 1) || (loop <= 1))) + CopyMemory(memshadow[loop], mem+(loop << 8), 256); + + *(memdirty+loop) &= ~1; + } +} + +//=========================================================================== + static LPBYTE MemGetPtrBANK1(const WORD offset, const LPBYTE pMemBase) { if ((offset & 0xF000) != 0xC000) // Requesting RAM at physical addr $Cxxx (ie. 4K RAM BANK1) @@ -1114,6 +1129,34 @@ LPBYTE MemGetAuxPtr(const WORD offset) //------------------------------------- +// if memshadow == memmain +// so RD memmain +// case: RD == WR +// so RD(mem),WR(mem) +// so 64K memmain could be incorrect +// *therefore mem is correct +// case: RD != WR +// so RD(mem),WR(memaux) +// doesn't matter since RD != WR, then it's guaranteed that memaux is correct +// *therefore either mem or memmain is correct +// else ; memshadow != memmain +// so RD memaux (or ROM) +// case: RD == WR +// so RD(mem),WR(mem) +// so 64K memaux could be incorrect +// *therefore memmain is correct +// case: RD != WR +// so RD(mem),WR(memmain) +// doesn't matter since RD != WR, then it's guaranteed that memmain is correct +// *therefore memmain is correct +// +// *OR* +// +// Is the mem(cache) setup to read (via memshadow) from memmain? +// . if yes, then return the mem(cache) address as writes (via memwrite) may've made the mem(cache) dirty. +// . if no, then return memmain, as the mem(cache) isn't involved in memmain (any writes will go directly to this backing-store). +// + LPBYTE MemGetMainPtr(const WORD offset) { LPBYTE lpMem = MemGetPtrBANK1(offset, memmain); @@ -1127,6 +1170,9 @@ LPBYTE MemGetMainPtr(const WORD offset) //=========================================================================== +// Used by: +// . Savestate: MemSaveSnapshotMemory(), MemLoadSnapshotAux() +// . Debugger : CmdMemorySave(), CmdMemoryLoad() LPBYTE MemGetBankPtr(const UINT nBank) { BackMainImage(); // Flush any dirty pages to back-buffer @@ -1784,7 +1830,7 @@ _done_saturn: // IT DOES SO. // // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour. - // - although any date-race is probably a bug in the 6502 code too. + // - although any data-race is probably a bug in the 6502 code too. if ((address >= 4) && (address <= 5) && ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) { modechanging = 1; diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 007ea275..ae0b1503 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Applewin.h" #include "CPU.h" // CpuGetCyclesThisVideoFrame() #include "Frame.h" - #include "Memory.h" // MemGetMainPtr() MemGetBankPtr() + #include "Memory.h" // MemGetMainPtr() MemGetAuxPtr() #include "Video.h" // g_pFramebufferbits #include "NTSC.h" From 53d1d04988530b4a634b54acd84cfc93ec74ae53 Mon Sep 17 00:00:00 2001 From: TomCh Date: Tue, 2 Oct 2018 22:08:54 +0100 Subject: [PATCH 052/128] DiskII: Support partial nibble reads for very close disk latch reads (#586) Support partial reads for sequential accesses of 6 or less cycles. - And 31 or less cycles when in "Disk Access Speed" = "Authentic Speed" Save-state support for partial read cycle (Disk][ unit v3) Added boot-time logging for Phasor1.dsk (ProDOS 1.1.1) --- source/Applewin.cpp | 7 +++++-- source/Disk.cpp | 31 ++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 5fa5dce3..6ec6a619 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -129,13 +129,16 @@ void LogFileTimeUntilFirstKeyReadReset(void) } // Log the time from emulation restart/reboot until the first key read: BIT $C000 -// . NB. AZTEC.DSK does prior LDY $C000 reads, but the BIT $C000 is at the "Press any key" message +// . AZTEC.DSK (DOS 3.3) does prior LDY $C000 reads, but the BIT $C000 is at the "Press any key" message +// . Phasor1.dsk / ProDOS 1.1.1: PC=E797: B1 50: LDA ($50),Y / "Select an Option:" message void LogFileTimeUntilFirstKeyRead(void) { if (!g_fh || bLogKeyReadDone) return; - if (mem[regs.pc-3] != 0x2C) // bit $c000 + if ( (mem[regs.pc-3] != 0x2C) // AZTEC: bit $c000 + && !((regs.pc-2) == 0xE797 && mem[regs.pc-2] == 0xB1 && mem[regs.pc-1] == 0x50) // Phasor1: lda ($50),y + ) return; DWORD dwTime = GetTickCount() - dwLogKeyReadTickStart; diff --git a/source/Disk.cpp b/source/Disk.cpp index f81002a9..d3998ae7 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -86,6 +86,7 @@ static WORD phases = 0; // state bits for stepper magnet phases 0 - 3 static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry static UINT g_uSlot = 0; static unsigned __int64 g_uDiskLastCycle = 0; +static unsigned __int64 g_uDiskLastReadLatchCycle = 0; static FormatTrack g_formatTrack; static bool IsDriveValid( const int iDrive ); @@ -895,7 +896,23 @@ static void __stdcall DiskReadWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULO // but Sherwood Forest sets shift mode and reads with the drive off, so don't check for now if (!floppywritemode) { + const ULONG nReadCycleDiff = (ULONG) (g_nCumulativeCycles - g_uDiskLastReadLatchCycle); + + // Support partial nibble read if disk reads are very close: (GH#582) + // . 6 cycles (1st->2nd read) for DOS 3.3 / $BD34: "read with delays to see if disk is spinning." (Beneath Apple DOS) + // . 6 cycles (1st->2nd read) for Curse of the Azure Bonds (loop to see if disk is spinning) + // . 31 cycles is the max for a partial 8-bit nibble + const ULONG kReadAccessThreshold = enhancedisk ? 6 : 31; + + if (nReadCycleDiff <= kReadAccessThreshold) + { + UINT invalidBits = 8 - (nReadCycleDiff / 4); // 4 cycles per bit-cell + floppylatch = *(pFloppy->trackimage + pFloppy->byte) >> invalidBits; + return; // Early return so don't update: g_uDiskLastReadLatchCycle & pFloppy->byte + } + floppylatch = *(pFloppy->trackimage + pFloppy->byte); + g_uDiskLastReadLatchCycle = g_nCumulativeCycles; #if LOG_DISK_NIBBLES_READ #if LOG_DISK_NIBBLES_USE_RUNTIME_VAR @@ -959,6 +976,10 @@ void DiskReset(const bool bIsPowerCycle/*=false*/) if (bIsPowerCycle) // GH#460 { + // NB. This doesn't affect the drive head (ie. drive's track position) + // . The initial machine start-up state is track=0, but after a power-cycle the track could be any value. + // . (For DiskII firmware, this results in a subtle extra latch read in this latter case, for the track!=0 case) + g_aFloppyDrive[DRIVE_1].spinning = 0; g_aFloppyDrive[DRIVE_1].writelight = 0; g_aFloppyDrive[DRIVE_2].spinning = 0; @@ -1363,7 +1384,8 @@ int DiskSetSnapshot_v1(const SS_CARD_DISK2* const pSS) // Unit version history: // 2: Added: Format Track state & DiskLastCycle -static const UINT kUNIT_VERSION = 2; +// 3: Added: DiskLastReadLatchCycle +static const UINT kUNIT_VERSION = 3; #define SS_YAML_VALUE_CARD_DISK2 "Disk][" @@ -1375,6 +1397,7 @@ static const UINT kUNIT_VERSION = 2; #define SS_YAML_KEY_FLOPPY_MOTOR_ON "Floppy Motor On" #define SS_YAML_KEY_FLOPPY_WRITE_MODE "Floppy Write Mode" #define SS_YAML_KEY_LAST_CYCLE "Last Cycle" +#define SS_YAML_KEY_LAST_READ_LATCH_CYCLE "Last Read Latch Cycle" #define SS_YAML_KEY_DISK2UNIT "Unit" #define SS_YAML_KEY_FILENAME "Filename" @@ -1429,6 +1452,7 @@ void DiskSaveSnapshot(class YamlSaveHelper& yamlSaveHelper) yamlSaveHelper.SaveBool(SS_YAML_KEY_FLOPPY_MOTOR_ON, floppymotoron == TRUE); yamlSaveHelper.SaveBool(SS_YAML_KEY_FLOPPY_WRITE_MODE, floppywritemode == TRUE); yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_LAST_CYCLE, g_uDiskLastCycle); // v2 + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_LAST_READ_LATCH_CYCLE, g_uDiskLastReadLatchCycle); // v3 g_formatTrack.SaveSnapshot(yamlSaveHelper); // v2 DiskSaveSnapshotDisk2Unit(yamlSaveHelper, DRIVE_1); @@ -1534,6 +1558,11 @@ bool DiskLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT vers g_formatTrack.LoadSnapshot(yamlLoadHelper); } + if (version >= 3) + { + g_uDiskLastReadLatchCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_LAST_READ_LATCH_CYCLE); + } + // Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1 for(UINT i=0; i Date: Tue, 2 Oct 2018 22:21:11 +0100 Subject: [PATCH 053/128] 1.27.9: Bump version & update History.txt --- bin/History.txt | 6 ++++++ resource/Applewin.rc | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 7eaeeef0..152f821a 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -8,6 +8,12 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.27.9.0 - 2 Oct 2018 +--------------------- +. [Bug #582] Support for partial disk II latch reads when accesses are very close. + - Fixes Curse of the Azure Bonds & Pool of Radiance (saving characters and creating disks). + + 1.27.8.0 - 9 Sep 2018 --------------------- . [Bug #555] Fix for showing 559th DHGR/DGR/TEXT80 vertical column (retaining 560-pixel display width). diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 88b11363..8d985736 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,8,0 - PRODUCTVERSION 1,27,8,0 + FILEVERSION 1,27,9,0 + PRODUCTVERSION 1,27,9,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 8, 0" + VALUE "FileVersion", "1, 27, 9, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 8, 0" + VALUE "ProductVersion", "1, 27, 9, 0" END END BLOCK "VarFileInfo" From 91a6227da1625bedc0fbb021e14cbacc293c23a9 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 13 Oct 2018 22:35:55 +0100 Subject: [PATCH 054/128] Debugger: Fixed disasm of branch targets <000 missing leading zeros. (Fixes #587) --- source/Debugger/Debugger_Display.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index eaf033dc..63a34037 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -1493,7 +1493,7 @@ int GetDisassemblyLine ( WORD nBaseAddress, DisasmLine_t & line_ ) if (! (bDisasmFormatFlags & DISASM_FORMAT_SYMBOL)) { - pTarget = FormatAddress( nTarget, nOpbyte ); + pTarget = FormatAddress( nTarget, (iOpmode != AM_R) ? nOpbyte : 3 ); // GH#587: For Bcc opcodes, pretend it's a 3-byte opcode to print a 16-bit target addr } // sprintf( sTarget, g_aOpmodes[ iOpmode ]._sFormat, pTarget ); From 46274d4d1c45fc28ac7701ddb61e9515c5f9dcfd Mon Sep 17 00:00:00 2001 From: TomCh Date: Fri, 26 Oct 2018 11:23:30 -0700 Subject: [PATCH 055/128] Apple II: Language Card and Saturn support for slot-0 (PR #589) Support for #408: * added slot-0 LC and Saturn 128K for Apple II and II+ * added save-state support - for slot-0 LC/Saturn, save the LC state in the slot-0 card, not the //e MMU; and switch to a new Apple2 unit ver2 * added g_Slot0, g_SlotAux * added new LanguageCard.cpp/h to project and moved Saturn code into these new files. * updated VS2013,2015,2017 projects --- AppleWinExpress2008.vcproj | 8 + AppleWinExpress2013.vcxproj | 2 + AppleWinExpress2013.vcxproj.filters | 6 + AppleWinExpress2015.vcxproj | 2 + AppleWinExpress2015.vcxproj.filters | 6 + AppleWinExpress2017.vcxproj | 2 + AppleWinExpress2017.vcxproj.filters | 6 + source/Applewin.cpp | 56 ++-- source/Applewin.h | 2 + source/Common.h | 10 +- source/Configuration/PageAdvanced.cpp | 4 +- source/Debugger/Debugger_Display.cpp | 7 +- source/LanguageCard.cpp | 376 ++++++++++++++++++++++++++ source/LanguageCard.h | 83 ++++++ source/Memory.cpp | 376 +++++++++++++++++--------- source/Memory.h | 30 +- source/SaveState.cpp | 27 +- source/SaveState_Structs_common.h | 8 +- 18 files changed, 824 insertions(+), 187 deletions(-) create mode 100644 source/LanguageCard.cpp create mode 100644 source/LanguageCard.h diff --git a/AppleWinExpress2008.vcproj b/AppleWinExpress2008.vcproj index 92fe61ea..1b926246 100644 --- a/AppleWinExpress2008.vcproj +++ b/AppleWinExpress2008.vcproj @@ -625,6 +625,14 @@ RelativePath=".\source\Keyboard.h" > + + + + diff --git a/AppleWinExpress2013.vcxproj b/AppleWinExpress2013.vcxproj index 63aa1764..9b32be34 100644 --- a/AppleWinExpress2013.vcxproj +++ b/AppleWinExpress2013.vcxproj @@ -71,6 +71,7 @@ + @@ -154,6 +155,7 @@ + diff --git a/AppleWinExpress2013.vcxproj.filters b/AppleWinExpress2013.vcxproj.filters index d1376eee..80023974 100644 --- a/AppleWinExpress2013.vcxproj.filters +++ b/AppleWinExpress2013.vcxproj.filters @@ -76,6 +76,9 @@ Source Files\Emulator + + Source Files\Emulator + Source Files\Emulator @@ -312,6 +315,9 @@ Source Files\Emulator + + Source Files\Emulator + Source Files\Emulator diff --git a/AppleWinExpress2015.vcxproj b/AppleWinExpress2015.vcxproj index 4467abb4..329910e4 100644 --- a/AppleWinExpress2015.vcxproj +++ b/AppleWinExpress2015.vcxproj @@ -71,6 +71,7 @@ + @@ -154,6 +155,7 @@ + diff --git a/AppleWinExpress2015.vcxproj.filters b/AppleWinExpress2015.vcxproj.filters index d1376eee..80023974 100644 --- a/AppleWinExpress2015.vcxproj.filters +++ b/AppleWinExpress2015.vcxproj.filters @@ -76,6 +76,9 @@ Source Files\Emulator + + Source Files\Emulator + Source Files\Emulator @@ -312,6 +315,9 @@ Source Files\Emulator + + Source Files\Emulator + Source Files\Emulator diff --git a/AppleWinExpress2017.vcxproj b/AppleWinExpress2017.vcxproj index c1e10c1e..ce3cf6b1 100644 --- a/AppleWinExpress2017.vcxproj +++ b/AppleWinExpress2017.vcxproj @@ -71,6 +71,7 @@ + @@ -154,6 +155,7 @@ + diff --git a/AppleWinExpress2017.vcxproj.filters b/AppleWinExpress2017.vcxproj.filters index baba23fc..d9a1afb6 100644 --- a/AppleWinExpress2017.vcxproj.filters +++ b/AppleWinExpress2017.vcxproj.filters @@ -76,6 +76,9 @@ Source Files\Emulator + + Source Files\Emulator + Source Files\Emulator @@ -312,6 +315,9 @@ Source Files\Emulator + + Source Files\Emulator + Source Files\Emulator diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 6ec6a619..cb785c33 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Frame.h" #include "Harddisk.h" #include "Joystick.h" +#include "LanguageCard.h" #include "Log.h" #include "Memory.h" #include "Mockingboard.h" @@ -102,8 +103,10 @@ IPropertySheet& sg_PropertySheet = * new CPropertySheet; CSuperSerialCard sg_SSC; CMouseInterface sg_Mouse; -SS_CARDTYPE g_Slot4 = CT_Empty; -SS_CARDTYPE g_Slot5 = CT_Empty; +SS_CARDTYPE g_Slot0 = CT_LanguageCard; // Just for Apple II or II+ or similar clones +SS_CARDTYPE g_Slot4 = CT_Empty; +SS_CARDTYPE g_Slot5 = CT_Empty; +SS_CARDTYPE g_SlotAux = CT_Extended80Col; // For Apple //e and above HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $F800..$FFFF static bool g_bCustomRomF8Failed = false; // Set if custom ROM file failed @@ -1145,6 +1148,8 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) LPSTR szImageName_harddisk[NUM_HARDDISKS] = {NULL,NULL}; LPSTR szSnapshotName = NULL; const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput + UINT uRamWorksExPages = 0; + UINT uSaturnBanks = 0; while (*lpCmdLine) { @@ -1249,37 +1254,30 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) #ifdef RAMWORKS else if (strcmp(lpCmdLine, "-r") == 0) // RamWorks size [1..127] { - g_eMemType = MEM_TYPE_RAMWORKS; - lpCmdLine = GetCurrArg(lpNextArg); lpNextArg = GetNextArg(lpNextArg); - g_uMaxExPages = atoi(lpCmdLine); - if (g_uMaxExPages > kMaxExMemoryBanks) - g_uMaxExPages = kMaxExMemoryBanks; + uRamWorksExPages = atoi(lpCmdLine); + if (uRamWorksExPages > kMaxExMemoryBanks) + uRamWorksExPages = kMaxExMemoryBanks; else - if (g_uMaxExPages < 1) - g_uMaxExPages = 1; + if (uRamWorksExPages < 1) + uRamWorksExPages = 1; } #endif -#ifdef SATURN else if (strcmp(lpCmdLine, "-saturn") == 0) // 64 = Saturn 64K (4 banks), 128 = Saturn 128K (8 banks) { - g_eMemType = MEM_TYPE_SATURN; - lpCmdLine = GetCurrArg(lpNextArg); lpNextArg = GetNextArg(lpNextArg); - // " The boards consist of 16K banks of memory - // (4 banks for the 64K board, - // 8 banks for the 128K), accessed one at a time" - g_uSaturnTotalBanks = atoi(lpCmdLine) / 16; // number of 16K Banks [1..8] - if (g_uSaturnTotalBanks > 8) - g_uSaturnTotalBanks = 8; + // "The boards consist of 16K banks of memory (4 banks for the 64K board, 8 banks for the 128K), accessed one at a time" - Ref: "64K/128K RAM BOARD", Saturn Systems, Ch.1 Introduction(pg-5) + uSaturnBanks = atoi(lpCmdLine) / 16; // number of 16K Banks [1..8] + if (uSaturnBanks > Saturn128K::kMaxSaturnBanks) + uSaturnBanks = Saturn128K::kMaxSaturnBanks; else - if (g_uSaturnTotalBanks < 1) - g_uSaturnTotalBanks = 1; + if (uSaturnBanks < 1) + uSaturnBanks = 1; + } -#endif else if (strcmp(lpCmdLine, "-f8rom") == 0) // Use custom 2K ROM at [$F800..$FFFF] { lpCmdLine = GetCurrArg(lpNextArg); @@ -1459,6 +1457,22 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) LoadConfiguration(); LogFileOutput("Main: LoadConfiguration()\n"); + // Apply the memory expansion switches after loading the Apple II machine type +#ifdef RAMWORKS + if (uRamWorksExPages) + { + SetRamWorksMemorySize(uRamWorksExPages); + SetExpansionMemType(CT_RamWorksIII); + uRamWorksExPages = 0; // Don't reapply after a restart + } +#endif + if (uSaturnBanks) + { + SetSaturnMemorySize(uSaturnBanks); // Set number of banks before constructing Saturn card + SetExpansionMemType(CT_Saturn128K); + uSaturnBanks = 0; // Don't reapply after a restart + } + DebugInitialize(); LogFileOutput("Main: DebugInitialize()\n"); diff --git a/source/Applewin.h b/source/Applewin.h index a3732ecc..894cae02 100644 --- a/source/Applewin.h +++ b/source/Applewin.h @@ -49,8 +49,10 @@ extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (s extern bool g_bDisableDirectSoundMockingboard; // Cmd line switch: don't init MB support extern int g_nMemoryClearType; // Cmd line switch: use specific MIP (Memory Initialization Pattern) +extern SS_CARDTYPE g_Slot0; // LC or Saturn in slot0 extern SS_CARDTYPE g_Slot4; // Mockingboard, Z80, Mouse in slot4 extern SS_CARDTYPE g_Slot5; // Mockingboard, Z80, in slot5 +extern SS_CARDTYPE g_SlotAux; extern HANDLE g_hCustomRomF8; // NULL if no custom rom diff --git a/source/Common.h b/source/Common.h index c78af713..0bdfa9e4 100644 --- a/source/Common.h +++ b/source/Common.h @@ -20,7 +20,6 @@ const DWORD dwClksPerFrame = uCyclesPerLine * uLinesPerFrame; // 17030 #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define RAMWORKS // 8MB RamWorks III support -//#define SATURN // SATURN 128K // Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample // Assume base freqs are 44.1KHz & 48KHz @@ -112,6 +111,7 @@ enum AppMode_e #define REGVALUE_CUSTOM_SPEED "Custom Speed" #define REGVALUE_EMULATION_SPEED "Emulation Speed" #define REGVALUE_WINDOW_SCALE "Window Scale" +#define REGVALUE_SLOT0 "Slot 0" #define REGVALUE_SLOT1 "Slot 1" #define REGVALUE_SLOT2 "Slot 2" #define REGVALUE_SLOT3 "Slot 3" @@ -193,7 +193,7 @@ enum eApple2Type { A2TYPE_MAX }; -inline bool IsApple2(eApple2Type type) +inline bool IsApple2Plus(eApple2Type type) // Apple ][,][+ { return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0; } @@ -203,6 +203,12 @@ inline bool IsClone(eApple2Type type) return (type & APPLECLONE_MASK) != 0; } +inline bool IsApple2PlusOrClone(eApple2Type type) // Apple ][,][+ or clone ][,][+ +{ + return ((type & (APPLE2E_MASK|APPLE2C_MASK)) == 0) + || (type & APPLECLONE_MASK) && !(type & A2TYPE_CLONE_A2E); +} + extern eApple2Type g_Apple2Type; inline bool IsOriginal2E(void) { diff --git a/source/Configuration/PageAdvanced.cpp b/source/Configuration/PageAdvanced.cpp index d7ed2d7a..5d63b6bd 100644 --- a/source/Configuration/PageAdvanced.cpp +++ b/source/Configuration/PageAdvanced.cpp @@ -259,8 +259,8 @@ int CPageAdvanced::GetCloneMenuItem(void) void CPageAdvanced::InitFreezeDlgButton(HWND hWnd) { - const bool bIsApple2 = IsApple2( m_PropertySheetHelper.GetConfigNew().m_Apple2Type ); - EnableWindow(GetDlgItem(hWnd, IDC_THE_FREEZES_F8_ROM_FW), bIsApple2 ? TRUE : FALSE); + const bool bIsApple2Plus = IsApple2Plus( m_PropertySheetHelper.GetConfigNew().m_Apple2Type ); + EnableWindow(GetDlgItem(hWnd, IDC_THE_FREEZES_F8_ROM_FW), bIsApple2Plus ? TRUE : FALSE); const UINT CheckTheFreezesRom = m_PropertySheetHelper.GetConfigNew().m_bEnableTheFreezesF8Rom ? BST_CHECKED : BST_UNCHECKED; CheckDlgButton(hWnd, IDC_THE_FREEZES_F8_ROM_FW, CheckTheFreezesRom); diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 63a34037..937eccf3 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../Applewin.h" #include "../CPU.h" #include "../Frame.h" +#include "../LanguageCard.h" #include "../Memory.h" #include "../Mockingboard.h" #include "../Video.h" @@ -2891,11 +2892,9 @@ void _DrawSoftSwitchLanguageCardBank( RECT & rect, int iBankDisplay, int bg_defa int iActiveBank = -1; char sText[ 4 ] = "?"; // Default to RAMWORKS #ifdef RAMWORKS - if (g_eMemType == MEM_TYPE_RAMWORKS) { sText[0] = 'r'; iActiveBank = g_uActiveBank; } // RAMWORKS + if (GetCurrentExpansionMemType() == CT_RamWorksIII) { sText[0] = 'r'; iActiveBank = GetRamWorksActiveBank(); } // RAMWORKS #endif -#ifdef SATURN - if (g_eMemType == MEM_TYPE_SATURN ) { sText[0] = 's'; iActiveBank = g_uSaturnActiveBank; } // SATURN 64K 128K -#endif // SATURN + if (GetCurrentExpansionMemType() == CT_Saturn128K) { sText[0] = 's'; iActiveBank = GetLanguageCard()->GetActiveBank(); } // SATURN 64K 128K if (iActiveBank >= 0) { diff --git a/source/LanguageCard.cpp b/source/LanguageCard.cpp new file mode 100644 index 00000000..44c6413f --- /dev/null +++ b/source/LanguageCard.cpp @@ -0,0 +1,376 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 1994-1996, Michael O'Brien +Copyright (C) 1999-2001, Oliver Schmidt +Copyright (C) 2002-2005, Tom Charlesworth +Copyright (C) 2006-2018, Tom Charlesworth, Michael Pohoreski, Nick Westgate + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Language Card and Saturn 128K emulation + * + * Author: various + */ + +#include "StdAfx.h" + +#include "Applewin.h" +#include "LanguageCard.h" +#include "Log.h" +#include "Memory.h" +#include "YamlHelper.h" + + +const UINT LanguageCardUnit::kMemModeInitialState = MF_BANK2 | MF_WRITERAM; // !INTCXROM + +LanguageCardUnit::LanguageCardUnit(void) : + m_uLastRamWrite(0), + m_type(CT_LanguageCardIIe) +{ + SetMemMainLanguageCard(NULL, true); +} + +DWORD LanguageCardUnit::SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write) +{ + memmode &= ~(MF_BANK2 | MF_HIGHRAM); + + if (!(address & 8)) + memmode |= MF_BANK2; + + if (((address & 2) >> 1) == (address & 1)) + memmode |= MF_HIGHRAM; + + if (address & 1) // GH#392 + { + if (!write && GetLastRamWrite()) + { + memmode |= MF_WRITERAM; // UTAIIe:5-23 + } + } + else + { + memmode &= ~MF_WRITERAM; // UTAIIe:5-23 + } + + SetLastRamWrite( ((address & 1) && !write) ); // UTAIIe:5-23 + + return memmode; +} + +//------------------------------------- + +LanguageCardSlot0::LanguageCardSlot0(void) +{ + m_type = CT_LanguageCard; + m_pMemory = (LPBYTE) VirtualAlloc(NULL, kMemBankSize, MEM_COMMIT, PAGE_READWRITE); + SetMemMainLanguageCard(m_pMemory); +} + +LanguageCardSlot0::~LanguageCardSlot0(void) +{ + VirtualFree(m_pMemory, 0, MEM_RELEASE); + m_pMemory = NULL; +} + +// + +static const UINT kUNIT_LANGUAGECARD_VER = 1; +static const UINT kSLOT_LANGUAGECARD = 0; + +#define SS_YAML_VALUE_CARD_LANGUAGECARD "Language Card" + +#define SS_YAML_KEY_MEMORYMODE "Memory Mode" +#define SS_YAML_KEY_LASTRAMWRITE "Last RAM Write" + +std::string LanguageCardSlot0::GetSnapshotMemStructName(void) +{ + static const std::string name("Memory Bank"); + return name; +} + +std::string LanguageCardSlot0::GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_LANGUAGECARD); + return name; +} + +void LanguageCardSlot0::SaveLCState(YamlSaveHelper& yamlSaveHelper) +{ + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, GetMemMode() & (MF_WRITERAM|MF_HIGHRAM|MF_BANK2)); + yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, GetLastRamWrite() ? 1 : 0); +} + +void LanguageCardSlot0::LoadLCState(YamlLoadHelper& yamlLoadHelper) +{ + DWORD memMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) & MF_LANGCARD_MASK; + BOOL lastRamWrite = yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE; + SetMemMode( (GetMemMode() & ~MF_LANGCARD_MASK) | memMode ); + SetLastRamWrite(lastRamWrite); +} + +void LanguageCardSlot0::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + if (!IsApple2PlusOrClone(GetApple2Type())) + { + _ASSERT(0); + LogFileOutput("Warning: Save-state attempted to save %s for //e or above\n", GetSnapshotCardName().c_str()); + return; // No Language Card support for //e and above + } + + YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), kSLOT_LANGUAGECARD, kUNIT_LANGUAGECARD_VER); + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + SaveLCState(yamlSaveHelper); + + { + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", GetSnapshotMemStructName().c_str()); + yamlSaveHelper.SaveMemory(m_pMemory, kMemBankSize); + } +} + +bool LanguageCardSlot0::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != kSLOT_LANGUAGECARD) + throw std::string("Card: wrong slot"); + + if (version != kUNIT_LANGUAGECARD_VER) + throw std::string("Card: wrong version"); + + // "State" + LoadLCState(yamlLoadHelper); + + if (!m_pMemory) + { + m_pMemory = (LPBYTE) VirtualAlloc(NULL, kMemBankSize, MEM_COMMIT, PAGE_READWRITE); + if (!m_pMemory) + throw std::string("Card: mem alloc failed"); + } + + if (!yamlLoadHelper.GetSubMap(GetSnapshotMemStructName())) + throw std::string("Memory: Missing map name: " + GetSnapshotMemStructName()); + + yamlLoadHelper.LoadMemory(m_pMemory, kMemBankSize); + + yamlLoadHelper.PopMap(); + + // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2() + + return true; +} + +//------------------------------------- + +Saturn128K::Saturn128K(UINT banks) +{ + m_type = CT_Saturn128K; + m_uSaturnTotalBanks = (banks == 0) ? kMaxSaturnBanks : banks; + m_uSaturnActiveBank = 0; + + for (UINT i=0; i> 1) & 4 + | (address >> 0) & 3; + + if (m_uSaturnActiveBank >= m_uSaturnTotalBanks) + { + // EG. Run RAMTEST128K tests on a Saturn 64K card + // TODO: Saturn::UpdatePaging() should deal with this case: + // . Technically read floating-bus, write to nothing + // . But the mem cache doesn't support floating-bus reads from non-I/O space + m_uSaturnActiveBank = m_uSaturnTotalBanks-1; // FIXME: just prevent crash for now! + } + + SetMemMainLanguageCard( m_aSaturnBanks[ m_uSaturnActiveBank ] ); + + modechanging = 1; + } + else + { + memmode &= ~(MF_BANK2 | MF_HIGHRAM); + + if (!(address & 8)) + memmode |= MF_BANK2; + + if (((address & 2) >> 1) == (address & 1)) + memmode |= MF_HIGHRAM; + + if (address & 1 && GetLastRamWrite()) // Saturn differs from Apple's 16K LC: any access (LC is read-only) + memmode |= MF_WRITERAM; + else + memmode &= ~MF_WRITERAM; + + SetLastRamWrite(address & 1); // Saturn differs from Apple's 16K LC: any access (LC is read-only) + } + + return memmode; +} + +// + +static const UINT kUNIT_SATURN_VER = 1; +static const UINT kSLOT_SATURN = 0; + +#define SS_YAML_VALUE_CARD_SATURN128 "Saturn 128" + +#define SS_YAML_KEY_NUM_SATURN_BANKS "Num Saturn Banks" +#define SS_YAML_KEY_ACTIVE_SATURN_BANK "Active Saturn Bank" + +std::string Saturn128K::GetSnapshotMemStructName(void) +{ + static const std::string name("Memory Bank"); + return name; +} + +std::string Saturn128K::GetSnapshotCardName(void) +{ + static const std::string name(SS_YAML_VALUE_CARD_SATURN128); + return name; +} + +void Saturn128K::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + if (!IsApple2PlusOrClone(GetApple2Type())) + { + _ASSERT(0); + LogFileOutput("Warning: Save-state attempted to save %s for //e or above\n", GetSnapshotCardName().c_str()); + return; // No Saturn support for //e and above + } + + YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), kSLOT_SATURN, kUNIT_SATURN_VER); + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + SaveLCState(yamlSaveHelper); + + yamlSaveHelper.Save("%s: 0x%02X # [1..8] 4=64K, 8=128K card\n", SS_YAML_KEY_NUM_SATURN_BANKS, m_uSaturnTotalBanks); + yamlSaveHelper.Save("%s: 0x%02X # [0..7]\n", SS_YAML_KEY_ACTIVE_SATURN_BANK, m_uSaturnActiveBank); + + for(UINT uBank = 0; uBank < m_uSaturnTotalBanks; uBank++) + { + LPBYTE pMemBase = m_aSaturnBanks[uBank]; + YamlSaveHelper::Label state(yamlSaveHelper, "%s%02X:\n", GetSnapshotMemStructName().c_str(), uBank); + yamlSaveHelper.SaveMemory(pMemBase, kMemBankSize); + } +} + +bool Saturn128K::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) +{ + if (slot != kSLOT_SATURN) // fixme + throw std::string("Card: wrong slot"); + + if (version != kUNIT_SATURN_VER) + throw std::string("Card: wrong version"); + + // "State" + LoadLCState(yamlLoadHelper); + + UINT numBanks = yamlLoadHelper.LoadUint(SS_YAML_KEY_NUM_SATURN_BANKS); + UINT activeBank = yamlLoadHelper.LoadUint(SS_YAML_KEY_ACTIVE_SATURN_BANK); + + if (numBanks < 1 || numBanks > kMaxSaturnBanks || activeBank >= numBanks) + throw std::string(SS_YAML_KEY_UNIT ": Bad Saturn card state"); + + m_uSaturnTotalBanks = numBanks; + m_uSaturnActiveBank = activeBank; + + // + + for(UINT uBank = 0; uBank < m_uSaturnTotalBanks; uBank++) + { + LPBYTE pBank = m_aSaturnBanks[uBank]; + if (!pBank) + { + pBank = m_aSaturnBanks[uBank] = (LPBYTE) VirtualAlloc(NULL, kMemBankSize, MEM_COMMIT, PAGE_READWRITE); + if (!pBank) + throw std::string("Card: mem alloc failed"); + } + + // "Memory Bankxx" + char szBank[3]; + sprintf(szBank, "%02X", uBank); + std::string memName = GetSnapshotMemStructName() + szBank; + + if (!yamlLoadHelper.GetSubMap(memName)) + throw std::string("Memory: Missing map name: " + memName); + + yamlLoadHelper.LoadMemory(pBank, kMemBankSize); + + yamlLoadHelper.PopMap(); + } + + SetMemMainLanguageCard( m_aSaturnBanks[ m_uSaturnActiveBank ] ); + + // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2() + + return true; +} diff --git a/source/LanguageCard.h b/source/LanguageCard.h new file mode 100644 index 00000000..c3654dfe --- /dev/null +++ b/source/LanguageCard.h @@ -0,0 +1,83 @@ +#pragma once + +// +// Language Card (base unit) for Apple //e and above +// + +class LanguageCardUnit +{ +public: + LanguageCardUnit(void); + virtual ~LanguageCardUnit(void) {} + + virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write); + virtual void SetMemorySize(UINT banks) {} // No-op for //e and slot-0 16K LC + virtual UINT GetActiveBank(void) { return 0; } // Always 0 as only 1x 16K bank + virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) { _ASSERT(0); } // Not used for //e + virtual bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version) { _ASSERT(0); return false; } // Not used for //e + + BOOL GetLastRamWrite(void) { return m_uLastRamWrite; } + void SetLastRamWrite(BOOL count) { m_uLastRamWrite = count; } + SS_CARDTYPE GetMemoryType(void) { return m_type; } + + static const UINT kMemModeInitialState; + +protected: + SS_CARDTYPE m_type; + +private: + UINT m_uLastRamWrite; +}; + +// +// Language Card (slot-0) for Apple II or II+ +// + +class LanguageCardSlot0 : public LanguageCardUnit +{ +public: + LanguageCardSlot0(void); + virtual ~LanguageCardSlot0(void); + + virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); + virtual bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + + static const UINT kMemBankSize = 16*1024; + static std::string GetSnapshotCardName(void); + +protected: + void SaveLCState(class YamlSaveHelper& yamlSaveHelper); + void LoadLCState(class YamlLoadHelper& yamlLoadHelper); + +private: + std::string GetSnapshotMemStructName(void); + + LPBYTE m_pMemory; +}; + +// +// Saturn 128K +// + +class Saturn128K : public LanguageCardSlot0 +{ +public: + Saturn128K(UINT banks); + virtual ~Saturn128K(void); + + virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write); + virtual void SetMemorySize(UINT banks); + virtual UINT GetActiveBank(void); + virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); + virtual bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + + static const UINT kMaxSaturnBanks = 8; // 8 * 16K = 128K + static std::string GetSnapshotCardName(void); + +private: + std::string GetSnapshotMemStructName(void); + + UINT m_uSaturnTotalBanks; // Will be > 0 if Saturn card is installed + UINT m_uSaturnActiveBank; // Saturn 128K Language Card Bank 0 .. 7 + LPBYTE m_aSaturnBanks[kMaxSaturnBanks]; +}; diff --git a/source/Memory.cpp b/source/Memory.cpp index 4313cae6..a154114b 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Harddisk.h" #include "Joystick.h" #include "Keyboard.h" +#include "LanguageCard.h" #include "Log.h" #include "Memory.h" #include "Mockingboard.h" @@ -180,8 +181,6 @@ iofunction IORead[256]; iofunction IOWrite[256]; static LPVOID SlotParameters[NUM_SLOTS]; -static BOOL g_bLastWriteRam = 0; - LPBYTE mem = NULL; // @@ -197,31 +196,153 @@ static LPBYTE memimage = NULL; static LPBYTE pCxRomInternal = NULL; static LPBYTE pCxRomPeripheral = NULL; -static const DWORD kMemModeInitialState = MF_BANK2 | MF_WRITERAM; // !INTCXROM -static DWORD memmode = kMemModeInitialState; +static LPBYTE g_pMemMainLanguageCard = NULL; + +static DWORD memmode = LanguageCardUnit::kMemModeInitialState; static BOOL modechanging = 0; // An Optimisation: means delay calling UpdatePaging() for 1 instruction -static BOOL Pravets8charmode = 0; static CNoSlotClock g_NoSlotClock; +static LanguageCardUnit* g_pLanguageCard = NULL; // For all Apple II, //e and above #ifdef RAMWORKS -UINT g_uMaxExPages = 1; // user requested ram pages (default to 1 aux bank: so total = 128KB) -UINT g_uActiveBank = 0; // 0 = aux 64K for: //e extended 80 Col card, or //c -- ALSO RAMWORKS +static UINT g_uMaxExPages = 1; // user requested ram pages (default to 1 aux bank: so total = 128KB) +static UINT g_uActiveBank = 0; // 0 = aux 64K for: //e extended 80 Col card, or //c -- ALSO RAMWORKS static LPBYTE RWpages[kMaxExMemoryBanks]; // pointers to RW memory banks #endif -#ifdef SATURN -UINT g_uSaturnTotalBanks = 0; // Will be > 0 if Saturn card is "installed" -UINT g_uSaturnActiveBank = 0; // Saturn 128K Language Card Bank 0 .. 7 -static LPBYTE g_aSaturnPages[8]; -#endif // SATURN - -MemoryType_e g_eMemType = MEM_TYPE_NATIVE; // 0 = Native memory, 1=RAMWORKS, 2 = SATURN - BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); //============================================================================= +static SS_CARDTYPE g_MemTypeAppleIIPlus = CT_LanguageCard; // Keep a copy so it's not lost if machine type changes, eg: A][ -> A//e -> A][ +static SS_CARDTYPE g_MemTypeAppleIIe = CT_Extended80Col; // Keep a copy so it's not lost if machine type changes, eg: A//e -> A][ -> A//e +static UINT g_uSaturnBanksFromCmdLine = 0; + +// Called from MemLoadSnapshot() +static void ResetDefaultMachineMemTypes(void) +{ + g_MemTypeAppleIIPlus = CT_LanguageCard; + g_MemTypeAppleIIe = CT_Extended80Col; +} + +// Called from MemInitialize(), MemLoadSnapshot() +void SetExpansionMemTypeDefault(void) +{ + SS_CARDTYPE defaultType = IsApple2PlusOrClone(GetApple2Type()) ? g_MemTypeAppleIIPlus : g_MemTypeAppleIIe; + SetExpansionMemType(defaultType); +} + +// Called from SetExpansionMemTypeDefault(), MemLoadSnapshotAux(), SaveState.cpp_ParseSlots(), cmd-line switch +void SetExpansionMemType(const SS_CARDTYPE type) +{ + SS_CARDTYPE newSlot0Card; + SS_CARDTYPE newSlotAuxCard; + + // Set defaults: + if (IsApple2PlusOrClone(GetApple2Type())) + { + newSlot0Card = CT_LanguageCard; + newSlotAuxCard = CT_Empty; + } + else // Apple //e or above + { + newSlot0Card = CT_Empty; // NB. No slot0 for //e + newSlotAuxCard = CT_Extended80Col; + } + + if (type == CT_Saturn128K) + { + g_MemTypeAppleIIPlus = type; + if (IsApple2PlusOrClone(GetApple2Type())) + newSlot0Card = CT_Saturn128K; + else + newSlot0Card = CT_Empty; // NB. No slot0 for //e + } + else if (type == CT_RamWorksIII) + { + g_MemTypeAppleIIe = type; + if (IsApple2PlusOrClone(GetApple2Type())) + newSlotAuxCard = CT_Empty; // NB. No aux slot for ][ or ][+ + else + newSlotAuxCard = CT_RamWorksIII; + } + + if (IsApple2PlusOrClone(GetApple2Type())) + { + delete g_pLanguageCard; + g_pLanguageCard = NULL; + + if (newSlot0Card == CT_Saturn128K) + g_pLanguageCard = new Saturn128K(g_uSaturnBanksFromCmdLine); + else // newSlot0Card == CT_LanguageCard + g_pLanguageCard = new LanguageCardSlot0; + } + else + { + delete g_pLanguageCard; + g_pLanguageCard = new LanguageCardUnit; + } + + _ASSERT(g_pMemMainLanguageCard); + + g_Slot0 = newSlot0Card; + g_SlotAux = newSlotAuxCard; +} + +SS_CARDTYPE GetCurrentExpansionMemType(void) +{ + if (IsApple2PlusOrClone(GetApple2Type())) + return g_Slot0; + else + return g_SlotAux; +} + +// + +void SetRamWorksMemorySize(UINT pages) +{ + g_uMaxExPages = pages; +} + +UINT GetRamWorksActiveBank(void) +{ + return g_uActiveBank; +} + +void SetSaturnMemorySize(UINT banks) +{ + g_uSaturnBanksFromCmdLine = banks; +} + +// + +static BOOL GetLastRamWrite(void) +{ + return g_pLanguageCard->GetLastRamWrite(); +} + +static void SetLastRamWrite(BOOL count) +{ + g_pLanguageCard->SetLastRamWrite(count); +} + +// + +void SetMemMainLanguageCard(LPBYTE ptr, bool bMemMain /*=false*/) +{ + if (bMemMain) + g_pMemMainLanguageCard = memmain+0xC000; + else + g_pMemMainLanguageCard = ptr; +} + +LanguageCardUnit* GetLanguageCard(void) +{ + return g_pLanguageCard; +} + +//============================================================================= + static BYTE __stdcall IORead_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles) { return KeybReadData(); @@ -837,7 +958,7 @@ DWORD GetMemMode(void) return memmode; } -static void SetMemMode(const DWORD uNewMemMode) +void SetMemMode(DWORD uNewMemMode) { #if defined(_DEBUG) && 0 static DWORD dwOldDiff = 0; @@ -881,8 +1002,8 @@ void MemResetPaging() static void ResetPaging(BOOL initialize) { - g_bLastWriteRam = 0; - SetMemMode(kMemModeInitialState); + SetLastRamWrite(0); + SetMemMode(LanguageCardUnit::kMemModeInitialState); UpdatePaging(initialize); } @@ -949,24 +1070,24 @@ static void UpdatePaging(BOOL initialize) { int bankoffset = (SW_BANK2 ? 0 : 0x1000); memshadow[loop] = SW_HIGHRAM ? SW_ALTZP ? memaux+(loop << 8)-bankoffset - : memmain+(loop << 8)-bankoffset - : memrom+((loop-0xD0) * 0x100); + : g_pMemMainLanguageCard+((loop-0xC0)<<8)-bankoffset + : memrom+((loop-0xD0) * 0x100); memwrite[loop] = SW_WRITERAM ? SW_HIGHRAM ? mem+(loop << 8) : SW_ALTZP ? memaux+(loop << 8)-bankoffset - : memmain+(loop << 8)-bankoffset + : g_pMemMainLanguageCard+((loop-0xC0)<<8)-bankoffset : NULL; } for (loop = 0xE0; loop < 0x100; loop++) { memshadow[loop] = SW_HIGHRAM ? SW_ALTZP ? memaux+(loop << 8) - : memmain+(loop << 8) + : g_pMemMainLanguageCard+((loop-0xC0)<<8) : memrom+((loop-0xD0) * 0x100); memwrite[loop] = SW_WRITERAM ? SW_HIGHRAM ? mem+(loop << 8) : SW_ALTZP ? memaux+(loop << 8) - : memmain+(loop << 8) + : g_pMemMainLanguageCard+((loop-0xC0)<<8) : NULL; } @@ -1043,6 +1164,9 @@ void MemDestroy() RWpages[0]=NULL; #endif + delete g_pLanguageCard; + g_pLanguageCard = NULL; + memaux = NULL; memmain = NULL; memdirty = NULL; @@ -1054,6 +1178,8 @@ void MemDestroy() mem = NULL; + g_pMemMainLanguageCard = NULL; + ZeroMemory(memwrite, sizeof(memwrite)); ZeroMemory(memshadow,sizeof(memshadow)); } @@ -1285,20 +1411,27 @@ void MemInitialize() // this happens when running under valgrind memimage = (LPBYTE)newloc; -#ifdef RAMWORKS - // allocate memory for RAMWorks III - up to 8MB - g_uActiveBank = 0; - RWpages[g_uActiveBank] = memaux; + // - UINT i = 1; - while ((i < g_uMaxExPages) && (RWpages[i] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE))) - i++; + RWpages[0] = memaux; + + SetExpansionMemTypeDefault(); + +#ifdef RAMWORKS + if (GetCurrentExpansionMemType() == CT_RamWorksIII) + { + // allocate memory for RAMWorks III - up to 8MB + g_uActiveBank = 0; + + UINT i = 1; + while ((i < g_uMaxExPages) && (RWpages[i] = (LPBYTE) VirtualAlloc(NULL, _6502_MEM_END+1, MEM_COMMIT, PAGE_READWRITE))) + i++; + while (i < kMaxExMemoryBanks) + RWpages[i++] = NULL; + } #endif -#ifdef SATURN - for( UINT iPage = 0; iPage < g_uSaturnTotalBanks; iPage++ ) - g_aSaturnPages[ iPage ] = (LPBYTE) VirtualAlloc( NULL, 1024 * 16,MEM_COMMIT,PAGE_READWRITE); // Saturn Pages are 16K / bank, Max 8 Banks/Card -#endif // SATURN + // MemInitializeROM(); MemInitializeCustomF8ROM(); @@ -1723,69 +1856,7 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE // DETERMINE THE NEW MEMORY PAGING MODE. if ((address >= 0x80) && (address <= 0x8F)) { - SetMemMode(memmode & ~(MF_BANK2 | MF_HIGHRAM)); - -#ifdef SATURN -/* - Bin Addr. - $C0N0 4K Bank A, RAM read, Write protect - $C0N1 4K Bank A, ROM read, Write enabled - $C0N2 4K Bank A, ROM read, Write protect - $C0N3 4K Bank A, RAM read, Write enabled - 0100 $C0N4 select 16K Bank 1 - 0101 $C0N5 select 16K Bank 2 - 0110 $C0N6 select 16K Bank 3 - 0111 $C0N7 select 16K Bank 4 - $C0N8 4K Bank B, RAM read, Write protect - $C0N9 4K Bank B, ROM read, Write enabled - $C0NA 4K Bank B, ROM read, Write protect - $C0NB 4K Bank B, RAM read, Write enabled - 1100 $C0NC select 16K Bank 5 - 1101 $C0ND select 16K Bank 6 - 1110 $C0NE select 16K Bank 7 - 1111 $C0NF select 16K Bank 8 -*/ - if (g_uSaturnTotalBanks) - { - if ((address & 7) > 3) - { - g_uSaturnActiveBank = 0 // Saturn 128K Language Card Bank 0 .. 7 - | (address >> 1) & 4 - | (address >> 0) & 3 - ; - - // TODO: Update paging() - - goto _done_saturn; - } - - // Fall into 16K IO switches - } - -#endif // SATURN - { - // Apple 16K Language Card - if (!(address & 8)) - SetMemMode(memmode | MF_BANK2); - - // C081 C089 Read ROM, Write enable - // C082 C08A Read ROM, Write protect - if (((address & 2) >> 1) == (address & 1)) - SetMemMode(memmode | MF_HIGHRAM); - - if (address & 1) // GH#392 - { - if (!write && g_bLastWriteRam) - { - SetMemMode(memmode | MF_WRITERAM); // UTAIIe:5-23 - } - } - else - { - SetMemMode(memmode & ~(MF_WRITERAM)); // UTAIIe:5-23 - } - } - g_bLastWriteRam = (address & 1) && (!write); // UTAIIe:5-23 + SetMemMode( g_pLanguageCard->SetPaging(address, memmode, modechanging, write ? true : false) ); } else if (!IS_APPLE2) { @@ -1814,33 +1885,32 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE { g_uActiveBank = value; memaux = RWpages[g_uActiveBank]; - UpdatePaging(0); // Initialize=0 + UpdatePaging(FALSE); // Initialize=FALSE } break; #endif } } -#ifdef SATURN -_done_saturn: -#endif // SATURN - - // IF THE EMULATED PROGRAM HAS JUST UPDATE THE MEMORY WRITE MODE AND IS - // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL - // IT DOES SO. - // - // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour. - // - although any data-race is probably a bug in the 6502 code too. - if ((address >= 4) && (address <= 5) && - ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) { - modechanging = 1; - return write ? 0 : MemReadFloatingBus(1, nExecutedCycles); - } - if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) && - (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) || - ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) { - modechanging = 1; - return write ? 0 : MemReadFloatingBus(1, nExecutedCycles); + if (GetCurrentExpansionMemType() != CT_Saturn128K) // TODO: Not sure this optimisation is valid for Saturn, so skip it for now + { + // IF THE EMULATED PROGRAM HAS JUST UPDATE THE MEMORY WRITE MODE AND IS + // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL + // IT DOES SO. + // + // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour. + // - although any data-race is probably a bug in the 6502 code too. + if ((address >= 4) && (address <= 5) && + ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) { + modechanging = 1; + return write ? 0 : MemReadFloatingBus(1, nExecutedCycles); + } + if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) && + (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) || + ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) { + modechanging = 1; + return write ? 0 : MemReadFloatingBus(1, nExecutedCycles); + } } // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND @@ -1903,7 +1973,7 @@ LPVOID MemGetSlotParameters(UINT uSlot) void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux) { SetMemMode(MemMode ^ MF_INTCXROM); // Convert from SLOTCXROM to INTCXROM - g_bLastWriteRam = LastWriteRam; + SetLastRamWrite(LastWriteRam); memcpy(memmain, pMemMain, nMemMainSize); memcpy(memaux, pMemAux, nMemAuxSize); @@ -1918,8 +1988,6 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* // -#define UNIT_AUXSLOT_VER 1 - #define SS_YAML_KEY_MEMORYMODE "Memory Mode" #define SS_YAML_KEY_LASTRAMWRITE "Last RAM Write" #define SS_YAML_KEY_IOSELECT "IO_SELECT" @@ -1927,6 +1995,10 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* #define SS_YAML_KEY_EXPANSIONROMTYPE "Expansion ROM Type" #define SS_YAML_KEY_PERIPHERALROMSLOT "Peripheral ROM Slot" +// + +static const UINT kUNIT_AUXSLOT_VER = 1; + #define SS_YAML_VALUE_CARD_80COL "80 Column" #define SS_YAML_VALUE_CARD_EXTENDED80COL "Extended 80 Column" #define SS_YAML_VALUE_CARD_RAMWORKSIII "RamWorksIII" @@ -1958,19 +2030,19 @@ static std::string MemGetSnapshotAuxMemStructName(void) return name; } -static void MemSaveSnapshotMemory(YamlSaveHelper& yamlSaveHelper, bool bIsMainMem, UINT bank=0) +static void MemSaveSnapshotMemory(YamlSaveHelper& yamlSaveHelper, bool bIsMainMem, UINT bank=0, UINT size=64*1024) { LPBYTE pMemBase = MemGetBankPtr(bank); if (bIsMainMem) { YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotMainMemStructName().c_str()); - yamlSaveHelper.SaveMemory(pMemBase, 64*1024); + yamlSaveHelper.SaveMemory(pMemBase, size); } else { YamlSaveHelper::Label state(yamlSaveHelper, "%s%02X:\n", MemGetSnapshotAuxMemStructName().c_str(), bank-1); - yamlSaveHelper.SaveMemory(pMemBase, 64*1024); + yamlSaveHelper.SaveMemory(pMemBase, size); } } @@ -1979,29 +2051,56 @@ void MemSaveSnapshot(YamlSaveHelper& yamlSaveHelper) // Scope so that "Memory" & "Main Memory" are at same indent level { YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", MemGetSnapshotStructName().c_str()); - yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, memmode ^ MF_INTCXROM); // Convert from INTCXROM to SLOTCXROM - yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, g_bLastWriteRam ? 1 : 0); + DWORD saveMemMode = memmode; + if (IsApple2PlusOrClone(GetApple2Type())) + saveMemMode &= ~MF_LANGCARD_MASK; // For II,II+: clear LC bits - set later by slot-0 LC or Saturn + yamlSaveHelper.SaveHexUint32(SS_YAML_KEY_MEMORYMODE, saveMemMode); + if (!IsApple2PlusOrClone(GetApple2Type())) // NB. This is set later for II,II+ by slot-0 LC or Saturn + yamlSaveHelper.SaveUint(SS_YAML_KEY_LASTRAMWRITE, GetLastRamWrite() ? 1 : 0); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IOSELECT, IO_SELECT); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_IOSELECT_INT, INTC8ROM ? 1 : 0); yamlSaveHelper.SaveUint(SS_YAML_KEY_EXPANSIONROMTYPE, (UINT) g_eExpansionRomType); yamlSaveHelper.SaveUint(SS_YAML_KEY_PERIPHERALROMSLOT, g_uPeripheralRomSlot); } - MemSaveSnapshotMemory(yamlSaveHelper, true); + if (IsApple2PlusOrClone(GetApple2Type())) + MemSaveSnapshotMemory(yamlSaveHelper, true, 0, 48*1024); // NB. Language Card/Saturn provides the remaining 16K (or multiple) bank(s) + else + MemSaveSnapshotMemory(yamlSaveHelper, true); } -bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) { if (!yamlLoadHelper.GetSubMap(MemGetSnapshotStructName())) return false; - SetMemMode( yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) ^ MF_INTCXROM ); // Convert from SLOTCXROM to INTCXROM - g_bLastWriteRam = yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE; + // Create default LC type for AppleII machine (do prior to loading saved LC state) + ResetDefaultMachineMemTypes(); + SetExpansionMemTypeDefault(); + + // + IO_SELECT = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_IOSELECT); INTC8ROM = yamlLoadHelper.LoadUint(SS_YAML_KEY_IOSELECT_INT) ? true : false; g_eExpansionRomType = (eExpansionRomType) yamlLoadHelper.LoadUint(SS_YAML_KEY_EXPANSIONROMTYPE); g_uPeripheralRomSlot = yamlLoadHelper.LoadUint(SS_YAML_KEY_PERIPHERALROMSLOT); + if (version == 1) + { + SetMemMode( yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) ^ MF_INTCXROM ); // Convert from SLOTCXROM to INTCXROM + SetLastRamWrite( yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE ); + } + else + { + UINT uMemMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE); + if (IsApple2PlusOrClone(GetApple2Type())) + uMemMode &= ~MF_LANGCARD_MASK; // For II,II+: clear LC bits - set later by slot-0 LC or Saturn + SetMemMode(uMemMode); + + if (!IsApple2PlusOrClone(GetApple2Type())) + SetLastRamWrite( yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE ); // NB. This is set later for II,II+ by slot-0 LC or Saturn + } + yamlLoadHelper.PopMap(); // @@ -2009,7 +2108,9 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper) if (!yamlLoadHelper.GetSubMap( MemGetSnapshotMainMemStructName() )) throw std::string("Card: Expected key: ") + MemGetSnapshotMainMemStructName(); + memset(memmain, 0, _6502_MEM_END+1); // Clear it, as high 16K may not be in the save-state (eg. the case of Saturn replacing LC) yamlLoadHelper.LoadMemory(memmain, _6502_MEM_END+1); + memcpy(g_pMemMainLanguageCard, memmain+0xC000, LanguageCardSlot0::kMemBankSize); memset(memdirty, 0, 0x100); yamlLoadHelper.PopMap(); @@ -2024,6 +2125,7 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper) return true; } +// TODO: Switch from checking 'g_uMaxExPages == n' to using g_SlotAux void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper) { if (IS_APPLE2) @@ -2036,7 +2138,7 @@ void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper) _ASSERT(g_uMaxExPages == 1); } - yamlSaveHelper.UnitHdr(MemGetSnapshotUnitAuxSlotName(), UNIT_AUXSLOT_VER); + yamlSaveHelper.UnitHdr(MemGetSnapshotUnitAuxSlotName(), kUNIT_AUXSLOT_VER); YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); std::string card = g_uMaxExPages == 0 ? SS_YAML_VALUE_CARD_80COL : // todo: support empty slot @@ -2054,32 +2156,37 @@ void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper) bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version) { - if (version != UNIT_AUXSLOT_VER) + if (version != kUNIT_AUXSLOT_VER) throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Version mismatch"); // "State" UINT numAuxBanks = yamlLoadHelper.LoadUint(SS_YAML_KEY_NUMAUXBANKS); UINT activeAuxBank = yamlLoadHelper.LoadUint(SS_YAML_KEY_ACTIVEAUXBANK); + SS_CARDTYPE type = CT_Empty; std::string card = yamlLoadHelper.LoadString(SS_YAML_KEY_CARD); if (card == SS_YAML_VALUE_CARD_80COL) { + type = CT_80Col; if (numAuxBanks != 0 || activeAuxBank != 0) throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); } else if (card == SS_YAML_VALUE_CARD_EXTENDED80COL) { + type = CT_Extended80Col; if (numAuxBanks != 1 || activeAuxBank != 0) throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); } else if (card == SS_YAML_VALUE_CARD_RAMWORKSIII) { + type = CT_RamWorksIII; if (numAuxBanks < 2 || numAuxBanks > 0x7F || (activeAuxBank+1) > numAuxBanks) throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Bad aux slot card state"); } else { // todo: support empty slot + type = CT_Empty; throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Unknown card: " + card); } @@ -2093,7 +2200,7 @@ bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version) LPBYTE pBank = MemGetBankPtr(uBank); if (!pBank) { - pBank = RWpages[uBank-1] = (LPBYTE) VirtualAlloc(NULL,_6502_MEM_END+1,MEM_COMMIT,PAGE_READWRITE); + pBank = RWpages[uBank-1] = (LPBYTE) VirtualAlloc(NULL, _6502_MEM_END+1, MEM_COMMIT, PAGE_READWRITE); if (!pBank) throw std::string("Card: mem alloc failed"); } @@ -2111,6 +2218,9 @@ bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version) yamlLoadHelper.PopMap(); } + g_Slot0 = CT_Empty; + g_SlotAux = type; + memaux = RWpages[g_uActiveBank]; // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2() diff --git a/source/Memory.h b/source/Memory.h index 191a5b26..ff81ddab 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -13,6 +13,8 @@ #define MF_INTCXROM 0x00000200 #define MF_WRITERAM 0x00000400 // Language Card RAM is Write Enabled #define MF_IMAGEMASK 0x000003F7 +#define MF_LANGCARD_MASK (MF_WRITERAM|MF_HIGHRAM|MF_BANK2) + enum { @@ -39,18 +41,8 @@ enum MemoryInitPattern_e , NUM_MIP }; -enum MemoryType_e -{ - MEM_TYPE_NATIVE = 0, - MEM_TYPE_RAMWORKS = 1, - MEM_TYPE_SATURN = 2, - NUM_MEM_TYPE = 3 -}; - typedef BYTE (__stdcall *iofunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE nWriteValue, ULONG nExecutedCycles); -extern MemoryType_e g_eMemType; - extern iofunction IORead[256]; extern iofunction IOWrite[256]; extern LPBYTE memwrite[0x100]; @@ -63,11 +55,6 @@ extern UINT g_uMaxExPages; // user requested ram pages (from cmd line) extern UINT g_uActiveBank; #endif -#ifdef SATURN -extern UINT g_uSaturnTotalBanks; -extern UINT g_uSaturnActiveBank; // Saturn 128K Language Card Bank 0 .. 7 -#endif // SATURN - void RegisterIoHandler(UINT uSlot, iofunction IOReadC0, iofunction IOWriteC0, iofunction IOReadCx, iofunction IOWriteCx, LPVOID lpSlotParameter, BYTE* pExpansionRom); void MemDestroy (); @@ -78,6 +65,7 @@ LPBYTE MemGetMainPtr(const WORD); LPBYTE MemGetBankPtr(const UINT nBank); LPBYTE MemGetCxRomPeripheral(); DWORD GetMemMode(void); +void SetMemMode(DWORD memmode); bool MemIsAddrCodeMemory(const USHORT addr); void MemInitialize (); void MemInitializeROM(void); @@ -93,10 +81,20 @@ LPVOID MemGetSlotParameters (UINT uSlot); void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux); std::string MemGetSnapshotUnitAuxSlotName(void); void MemSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); -bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); +bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version); void MemSaveSnapshotAux(class YamlSaveHelper& yamlSaveHelper); bool MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT version); BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); BYTE __stdcall MemSetPaging(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); + +enum SS_CARDTYPE; +void SetExpansionMemType(const SS_CARDTYPE type); +SS_CARDTYPE GetCurrentExpansionMemType(void); + +void SetRamWorksMemorySize(UINT pages); +UINT GetRamWorksActiveBank(void); +void SetSaturnMemorySize(UINT banks); +void SetMemMainLanguageCard(LPBYTE ptr, bool bMemMain=false); +class LanguageCardUnit* GetLanguageCard(void); diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 4870e9d6..c248b81b 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Frame.h" #include "Joystick.h" #include "Keyboard.h" +#include "LanguageCard.h" #include "Memory.h" #include "Mockingboard.h" #include "MouseInterface.h" @@ -64,7 +65,7 @@ static YamlHelper yamlHelper; #define SS_FILE_VER 2 -#define UNIT_APPLE2_VER 1 +#define UNIT_APPLE2_VER 2 #define UNIT_SLOTS_VER 1 //----------------------------------------------------------------------------- @@ -323,7 +324,7 @@ static UINT ParseFileHdr(void) static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version) { - if (version != UNIT_APPLE2_VER) + if (version == 0 || version > UNIT_APPLE2_VER) throw std::string(SS_YAML_KEY_UNIT ": Apple2: Version mismatch"); std::string model = yamlLoadHelper.LoadString(SS_YAML_KEY_MODEL); @@ -337,7 +338,7 @@ static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version) KeybLoadSnapshot(yamlLoadHelper); SpkrLoadSnapshot(yamlLoadHelper); VideoLoadSnapshot(yamlLoadHelper); - MemLoadSnapshot(yamlLoadHelper); + MemLoadSnapshot(yamlLoadHelper, version); // g_Apple2Type may've changed: so redraw frame (title, buttons, leds, etc) VideoReinitialize(); // g_CharsetType changed @@ -358,7 +359,8 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version) break; // done all slots const int slot = strtoul(scalar.c_str(), NULL, 10); // NB. aux slot supported as a different "unit" - if (slot < 1 || slot > 7) + // NB. slot-0 only supported for Apple II or II+ (or similar clones) + if (slot < 0 || slot > 7) throw std::string("Slots: Invalid slot #: ") + scalar; yamlLoadHelper.GetSubMap(scalar); @@ -414,6 +416,18 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version) m_ConfigNew.m_bEnableHDD = true; type = CT_GenericHDD; } + else if (card == LanguageCardSlot0::GetSnapshotCardName()) + { + type = CT_LanguageCard; + SetExpansionMemType(type); + bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, version); + } + else if (card == Saturn128K::GetSnapshotCardName()) + { + type = CT_Saturn128K; + SetExpansionMemType(type); + bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, version); + } else { bIsCardSupported = false; @@ -477,6 +491,7 @@ static void Snapshot_LoadState_v2(void) // CConfigNeedingRestart ConfigOld; + //ConfigOld.m_Slot[0] = CT_LanguageCard; // fixme: II/II+=LC, //e=empty ConfigOld.m_Slot[1] = CT_GenericPrinter; // fixme ConfigOld.m_Slot[2] = CT_SSC; // fixme //ConfigOld.m_Slot[3] = CT_Uthernet; // todo @@ -489,7 +504,6 @@ static void Snapshot_LoadState_v2(void) m_ConfigNew.m_SlotAux = CT_Empty; m_ConfigNew.m_bEnableHDD = false; //m_ConfigNew.m_bEnableTheFreezesF8Rom = ?; // todo: when support saving config - //m_ConfigNew.m_bEnhanceDisk = ?; // todo: when support saving config MemReset(); PravetsReset(); @@ -591,6 +605,9 @@ void Snapshot_SaveState(void) yamlSaveHelper.UnitHdr(GetSnapshotUnitSlotsName(), UNIT_SLOTS_VER); YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + if (IsApple2PlusOrClone(GetApple2Type())) + GetLanguageCard()->SaveSnapshot(yamlSaveHelper); // Language Card or Saturn 128K + Printer_SaveSnapshot(yamlSaveHelper); sg_SSC.SaveSnapshot(yamlSaveHelper); diff --git a/source/SaveState_Structs_common.h b/source/SaveState_Structs_common.h index 2ba29f81..8a44ce8f 100644 --- a/source/SaveState_Structs_common.h +++ b/source/SaveState_Structs_common.h @@ -46,9 +46,6 @@ enum SS_UNIT_TYPE const UINT nMemMainSize = 64*1024; const UINT nMemAuxSize = 64*1024; -const UINT kSLOT_LANG = 0; -const UINT kSLOT_AUX = 8; - struct SS_CARD_HDR { SS_UNIT_HDR UnitHdr; @@ -70,10 +67,13 @@ enum SS_CARDTYPE CT_Phasor, // Soundcard CT_Echo, // Soundcard CT_SAM, // Soundcard: Software Automated Mouth - CT_80Col, // 80 column card (no memory) + CT_80Col, // 80 column card (1K) CT_Extended80Col, // Extended 80-col card (64K) CT_RamWorksIII, // RamWorksIII (up to 8MB) CT_Uthernet, + CT_LanguageCard, // Apple][ or ][+ in slot-0 + CT_LanguageCardIIe, // Apple//e LC instance (not a card) + CT_Saturn128K, // Saturn 128K (but may be populated with less RAM, in multiples of 16K) }; ///////////////////////////////////////////////////////////////////////////////// From 9e1170ca9eb54785c386bdf27c8131dd8e007567 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 27 Oct 2018 18:16:32 +0100 Subject: [PATCH 056/128] LC: Added more comments when loading save-state memory v1 for II or II+ --- source/Memory.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index a154114b..3996bee5 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -2108,9 +2108,15 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) if (!yamlLoadHelper.GetSubMap( MemGetSnapshotMainMemStructName() )) throw std::string("Card: Expected key: ") + MemGetSnapshotMainMemStructName(); - memset(memmain, 0, _6502_MEM_END+1); // Clear it, as high 16K may not be in the save-state (eg. the case of Saturn replacing LC) + memset(memmain+0xC000, 0, LanguageCardSlot0::kMemBankSize); // Clear it, as high 16K may not be in the save-state's "Main Memory" (eg. the case of II+ Saturn replacing //e LC) + yamlLoadHelper.LoadMemory(memmain, _6502_MEM_END+1); - memcpy(g_pMemMainLanguageCard, memmain+0xC000, LanguageCardSlot0::kMemBankSize); + if (version == 1 && IsApple2PlusOrClone(GetApple2Type())) + { + // v1 for II/II+ doesn't have a dedicated slot-0 LC, instead the 16K is stored as the top 16K of memmain + memcpy(g_pMemMainLanguageCard, memmain+0xC000, LanguageCardSlot0::kMemBankSize); + memset(memmain+0xC000, 0, LanguageCardSlot0::kMemBankSize); + } memset(memdirty, 0, 0x100); yamlLoadHelper.PopMap(); From 034337cb2857ce79469ee770d334e089602c1f2e Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 27 Oct 2018 18:48:47 +0100 Subject: [PATCH 057/128] Saturn: Change cmd-line to -s0 --- source/Applewin.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index cb785c33..5dddcdf8 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1264,19 +1264,16 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) uRamWorksExPages = 1; } #endif - else if (strcmp(lpCmdLine, "-saturn") == 0) // 64 = Saturn 64K (4 banks), 128 = Saturn 128K (8 banks) + else if (strcmp(lpCmdLine, "-s0") == 0) { lpCmdLine = GetCurrArg(lpNextArg); lpNextArg = GetNextArg(lpNextArg); // "The boards consist of 16K banks of memory (4 banks for the 64K board, 8 banks for the 128K), accessed one at a time" - Ref: "64K/128K RAM BOARD", Saturn Systems, Ch.1 Introduction(pg-5) - uSaturnBanks = atoi(lpCmdLine) / 16; // number of 16K Banks [1..8] - if (uSaturnBanks > Saturn128K::kMaxSaturnBanks) + if (strcmp(lpCmdLine, "saturn") == 0 || strcmp(lpCmdLine, "saturn128") == 0) uSaturnBanks = Saturn128K::kMaxSaturnBanks; - else - if (uSaturnBanks < 1) - uSaturnBanks = 1; - + else if (strcmp(lpCmdLine, "saturn64") == 0) + uSaturnBanks = Saturn128K::kMaxSaturnBanks/2; } else if (strcmp(lpCmdLine, "-f8rom") == 0) // Use custom 2K ROM at [$F800..$FFFF] { From c90eb07f179808e34e8edc970ac25eb81345d3fa Mon Sep 17 00:00:00 2001 From: tomcw Date: Wed, 31 Oct 2018 22:04:42 +0000 Subject: [PATCH 058/128] Saturn: Updated help docs --- help/CommandLine.html | 7 +++++-- help/dbg-screen-layout.html | 1 + help/savestate.html | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/help/CommandLine.html b/help/CommandLine.html index 73b56862..650318d3 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -19,14 +19,17 @@ Start with hard disk 1 plugged-in (and auto power-on the Apple II). NB. Hard disk controller card gets enabled.

              -h2 <pathname>
              Start with hard disk 2 plugged-in. NB. Hard disk controller card gets enabled.

              + -s0 <saturn|saturn64|saturn128>
              + Insert a Saturn 64K or Saturn 128K card into slot 0 in Apple II or Apple II+ machines (or similar clone).
              + Where -s0 saturn is an alias for -s0 saturn128.

              -s7 empty
              Remove the hard disk controller card from slot 7.
              Useful to allow a floppy disk to boot from slot 6, drive 1. Use in combination with -d1.

              -r <number of pages>
              - Emulate a RAMworks III card with 1 to 127 pages (each page is 64K, giving a max of 8MB)

              + Emulate a RAMworks III card with 1 to 127 pages (each page is 64K, giving a max of 8MB) in the auxiliary slot in an Apple //e machine.

              -load-state <savestate>
              Load a save-state file
              - NB. This takes precedent over the -d1,d2,h1,h2,s7 and -r switches.

              + NB. This takes precedent over the -d1,d2,h1,h2,s0,s7 and -r switches.

              -f
              Start in full-screen mode

              -fs-height=<best|nnnn>
              diff --git a/help/dbg-screen-layout.html b/help/dbg-screen-layout.html index dd83acd8..f3dc010e 100644 --- a/help/dbg-screen-layout.html +++ b/help/dbg-screen-layout.html @@ -46,6 +46,7 @@
            • If 'W' is inverse: RAM is write enabled.
            • If 'W' is not inverse: RAM is write protected.
            • 'rNN' will appear if a RAMworks 64K bank is active. +
            • 'sNN' will appear if a Saturn 16K bank is active.

          diff --git a/help/savestate.html b/help/savestate.html index ff5595f5..c98e7a32 100644 --- a/help/savestate.html +++ b/help/savestate.html @@ -21,6 +21,7 @@ The following are persisted to the file:
          • Apple model: ][, ][+, //e, Enhanced //e or clone (eg. Pravets)
          • +
          • Apple ]['s slot-0 language card: 16K Language Card, Saturn 64K or Saturn 128K
          • Apple //e's auxiliary card: 80 Column, Extended 80 Column or RamWorks III
          • Disk][ (even during r/w operation)
          • Hard disk (even during r/w operation)
          • From 09ab12d0b6f291a41845b3ab57df074d9ca67b6d Mon Sep 17 00:00:00 2001 From: tomcw Date: Thu, 1 Nov 2018 21:14:16 +0000 Subject: [PATCH 059/128] Save-state: Keyboard - save 'Key Waiting' flag. (Fixes #591) --- source/Keyboard.cpp | 7 ++++++- source/Keyboard.h | 2 +- source/SaveState.cpp | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index c28afd46..9fa5bdfe 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -552,6 +552,7 @@ void KeybSetSnapshot_v1(const BYTE LastKey) // #define SS_YAML_KEY_LASTKEY "Last Key" +#define SS_YAML_KEY_KEYWAITING "Key Waiting" static std::string KeybGetSnapshotStructName(void) { @@ -563,14 +564,18 @@ void KeybSaveSnapshot(YamlSaveHelper& yamlSaveHelper) { YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", KeybGetSnapshotStructName().c_str()); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_LASTKEY, keycode); + yamlSaveHelper.SaveBool(SS_YAML_KEY_KEYWAITING, keywaiting ? true : false); } -void KeybLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +void KeybLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) { if (!yamlLoadHelper.GetSubMap(KeybGetSnapshotStructName())) return; keycode = (BYTE) yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTKEY); + if (version == 2) + keywaiting = (BOOL) yamlLoadHelper.LoadBool(SS_YAML_KEY_KEYWAITING); + yamlLoadHelper.PopMap(); } diff --git a/source/Keyboard.h b/source/Keyboard.h index 65920f39..28b520b9 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -20,4 +20,4 @@ BYTE KeybReadData (void); BYTE KeybReadFlag (void); void KeybSetSnapshot_v1(const BYTE LastKey); void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); -void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); +void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version); diff --git a/source/SaveState.cpp b/source/SaveState.cpp index c248b81b..e7c36fad 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -335,7 +335,7 @@ static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version) m_ConfigNew.m_CpuType = GetMainCpu(); JoyLoadSnapshot(yamlLoadHelper); - KeybLoadSnapshot(yamlLoadHelper); + KeybLoadSnapshot(yamlLoadHelper, version); SpkrLoadSnapshot(yamlLoadHelper); VideoLoadSnapshot(yamlLoadHelper); MemLoadSnapshot(yamlLoadHelper, version); From 13c393624bd83280836d30babbbfe2549ab0b5f9 Mon Sep 17 00:00:00 2001 From: TomCh Date: Sun, 4 Nov 2018 15:07:46 +0000 Subject: [PATCH 060/128] Apple II original: default to 48K (ie. no Language Card) (PR #592) Added support for #590: * Changed Apple II original to default to no LC * Added new cmd-line switch: -s0 * Changed so when LC is in slot-0, it now use Apple II+'s F8 (auto-start) ROM --- source/Applewin.cpp | 10 ++++- source/Common.h | 5 +++ source/LanguageCard.cpp | 5 +++ source/LanguageCard.h | 3 +- source/Memory.cpp | 83 ++++++++++++++++++++++++++++++++--------- source/SaveState.cpp | 2 +- 6 files changed, 88 insertions(+), 20 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 5dddcdf8..cb01a4b1 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1142,6 +1142,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) bool bSetFullScreen = false; bool bBoot = false; bool bChangedDisplayResolution = false; + bool bSlot0LanguageCard = false; bool bSlot7Empty = false; UINT bestWidth = 0, bestHeight = 0; LPSTR szImageName_drive[NUM_DRIVES] = {NULL,NULL}; @@ -1269,11 +1270,12 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) lpCmdLine = GetCurrArg(lpNextArg); lpNextArg = GetNextArg(lpNextArg); - // "The boards consist of 16K banks of memory (4 banks for the 64K board, 8 banks for the 128K), accessed one at a time" - Ref: "64K/128K RAM BOARD", Saturn Systems, Ch.1 Introduction(pg-5) if (strcmp(lpCmdLine, "saturn") == 0 || strcmp(lpCmdLine, "saturn128") == 0) uSaturnBanks = Saturn128K::kMaxSaturnBanks; else if (strcmp(lpCmdLine, "saturn64") == 0) uSaturnBanks = Saturn128K::kMaxSaturnBanks/2; + else if (strcmp(lpCmdLine, "languagecard") == 0 || strcmp(lpCmdLine, "lc") == 0) + bSlot0LanguageCard = true; } else if (strcmp(lpCmdLine, "-f8rom") == 0) // Use custom 2K ROM at [$F800..$FFFF] { @@ -1470,6 +1472,12 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) uSaturnBanks = 0; // Don't reapply after a restart } + if (bSlot0LanguageCard) + { + SetExpansionMemType(CT_LanguageCard); + bSlot0LanguageCard = false; // Don't reapply after a restart + } + DebugInitialize(); LogFileOutput("Main: DebugInitialize()\n"); diff --git a/source/Common.h b/source/Common.h index 0bdfa9e4..c8572e96 100644 --- a/source/Common.h +++ b/source/Common.h @@ -193,6 +193,11 @@ enum eApple2Type { A2TYPE_MAX }; +inline bool IsApple2Original(eApple2Type type) // Apple ][ +{ + return type == A2TYPE_APPLE2; +} + inline bool IsApple2Plus(eApple2Type type) // Apple ][,][+ { return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0; diff --git a/source/LanguageCard.cpp b/source/LanguageCard.cpp index 44c6413f..2c61139c 100644 --- a/source/LanguageCard.cpp +++ b/source/LanguageCard.cpp @@ -44,6 +44,11 @@ LanguageCardUnit::LanguageCardUnit(void) : SetMemMainLanguageCard(NULL, true); } +LanguageCardUnit::~LanguageCardUnit(void) +{ + SetMemMainLanguageCard(NULL); +} + DWORD LanguageCardUnit::SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write) { memmode &= ~(MF_BANK2 | MF_HIGHRAM); diff --git a/source/LanguageCard.h b/source/LanguageCard.h index c3654dfe..7134b1d5 100644 --- a/source/LanguageCard.h +++ b/source/LanguageCard.h @@ -8,7 +8,7 @@ class LanguageCardUnit { public: LanguageCardUnit(void); - virtual ~LanguageCardUnit(void) {} + virtual ~LanguageCardUnit(void); virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write); virtual void SetMemorySize(UINT banks) {} // No-op for //e and slot-0 16K LC @@ -71,6 +71,7 @@ public: virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); virtual bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + // "The boards consist of 16K banks of memory (4 banks for the 64K board, 8 banks for the 128K), accessed one at a time" - Ref: "64K/128K RAM BOARD", Saturn Systems, Ch.1 Introduction(pg-5) static const UINT kMaxSaturnBanks = 8; // 8 * 16K = 128K static std::string GetSnapshotCardName(void); diff --git a/source/Memory.cpp b/source/Memory.cpp index 3996bee5..52efdbe1 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -214,6 +214,9 @@ BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYT //============================================================================= +// Default memory types on a VM restart +// - can be overwritten by cmd-line or loading a save-state +static SS_CARDTYPE g_MemTypeAppleII = CT_Empty; static SS_CARDTYPE g_MemTypeAppleIIPlus = CT_LanguageCard; // Keep a copy so it's not lost if machine type changes, eg: A][ -> A//e -> A][ static SS_CARDTYPE g_MemTypeAppleIIe = CT_Extended80Col; // Keep a copy so it's not lost if machine type changes, eg: A//e -> A][ -> A//e static UINT g_uSaturnBanksFromCmdLine = 0; @@ -221,14 +224,18 @@ static UINT g_uSaturnBanksFromCmdLine = 0; // Called from MemLoadSnapshot() static void ResetDefaultMachineMemTypes(void) { + g_MemTypeAppleII = CT_Empty; g_MemTypeAppleIIPlus = CT_LanguageCard; g_MemTypeAppleIIe = CT_Extended80Col; } // Called from MemInitialize(), MemLoadSnapshot() -void SetExpansionMemTypeDefault(void) +static void SetExpansionMemTypeDefault(void) { - SS_CARDTYPE defaultType = IsApple2PlusOrClone(GetApple2Type()) ? g_MemTypeAppleIIPlus : g_MemTypeAppleIIe; + SS_CARDTYPE defaultType = IsApple2Original(GetApple2Type()) ? g_MemTypeAppleII + : IsApple2PlusOrClone(GetApple2Type()) ? g_MemTypeAppleIIPlus + : g_MemTypeAppleIIe; + SetExpansionMemType(defaultType); } @@ -239,7 +246,12 @@ void SetExpansionMemType(const SS_CARDTYPE type) SS_CARDTYPE newSlotAuxCard; // Set defaults: - if (IsApple2PlusOrClone(GetApple2Type())) + if (IsApple2Original(GetApple2Type())) + { + newSlot0Card = CT_Empty; + newSlotAuxCard = CT_Empty; + } + else if (IsApple2PlusOrClone(GetApple2Type())) { newSlot0Card = CT_LanguageCard; newSlotAuxCard = CT_Empty; @@ -250,11 +262,12 @@ void SetExpansionMemType(const SS_CARDTYPE type) newSlotAuxCard = CT_Extended80Col; } - if (type == CT_Saturn128K) + if (type == CT_LanguageCard || type == CT_Saturn128K) { + g_MemTypeAppleII = type; g_MemTypeAppleIIPlus = type; if (IsApple2PlusOrClone(GetApple2Type())) - newSlot0Card = CT_Saturn128K; + newSlot0Card = type; else newSlot0Card = CT_Empty; // NB. No slot0 for //e } @@ -264,18 +277,19 @@ void SetExpansionMemType(const SS_CARDTYPE type) if (IsApple2PlusOrClone(GetApple2Type())) newSlotAuxCard = CT_Empty; // NB. No aux slot for ][ or ][+ else - newSlotAuxCard = CT_RamWorksIII; + newSlotAuxCard = type; } if (IsApple2PlusOrClone(GetApple2Type())) { delete g_pLanguageCard; - g_pLanguageCard = NULL; if (newSlot0Card == CT_Saturn128K) g_pLanguageCard = new Saturn128K(g_uSaturnBanksFromCmdLine); - else // newSlot0Card == CT_LanguageCard + else if (newSlot0Card == CT_LanguageCard) g_pLanguageCard = new LanguageCardSlot0; + else + g_pLanguageCard = NULL; } else { @@ -283,8 +297,6 @@ void SetExpansionMemType(const SS_CARDTYPE type) g_pLanguageCard = new LanguageCardUnit; } - _ASSERT(g_pMemMainLanguageCard); - g_Slot0 = newSlot0Card; g_SlotAux = newSlotAuxCard; } @@ -318,12 +330,15 @@ void SetSaturnMemorySize(UINT banks) static BOOL GetLastRamWrite(void) { - return g_pLanguageCard->GetLastRamWrite(); + if (g_pLanguageCard) + return g_pLanguageCard->GetLastRamWrite(); + return 0; } static void SetLastRamWrite(BOOL count) { - g_pLanguageCard->SetLastRamWrite(count); + if (g_pLanguageCard) + g_pLanguageCard->SetLastRamWrite(count); } // @@ -338,6 +353,7 @@ void SetMemMainLanguageCard(LPBYTE ptr, bool bMemMain /*=false*/) LanguageCardUnit* GetLanguageCard(void) { + _ASSERT(g_pLanguageCard); return g_pLanguageCard; } @@ -1003,7 +1019,12 @@ void MemResetPaging() static void ResetPaging(BOOL initialize) { SetLastRamWrite(0); - SetMemMode(LanguageCardUnit::kMemModeInitialState); + + if (IsApple2PlusOrClone(GetApple2Type()) && g_Slot0 == CT_Empty) + SetMemMode(0); + else + SetMemMode(LanguageCardUnit::kMemModeInitialState); + UpdatePaging(initialize); } @@ -1178,8 +1199,6 @@ void MemDestroy() mem = NULL; - g_pMemMainLanguageCard = NULL; - ZeroMemory(memwrite, sizeof(memwrite)); ZeroMemory(memshadow,sizeof(memshadow)); } @@ -1519,6 +1538,36 @@ void MemInitializeROM(void) void MemInitializeCustomF8ROM(void) { const UINT F8RomSize = 0x800; + const UINT F8RomOffset = Apple2RomSize-F8RomSize; + + if (IsApple2Original(GetApple2Type()) && g_Slot0 == CT_LanguageCard) + { + try + { + HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_APPLE2_PLUS_ROM), "ROM"); + if (hResInfo == NULL) + throw false; + + DWORD dwResSize = SizeofResource(NULL, hResInfo); + if(dwResSize != Apple2RomSize) + throw false; + + HGLOBAL hResData = LoadResource(NULL, hResInfo); + if(hResData == NULL) + throw false; + + BYTE* pData = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource + if (pData == NULL) + throw false; + + memcpy(memrom+F8RomOffset, pData+F8RomOffset, F8RomSize); + } + catch (bool) + { + MessageBox( g_hFrameWindow, "Failed to read F8 (auto-start) ROM for language card in original Apple][", TEXT("AppleWin Error"), MB_OK ); + } + } + if (g_hCustomRomF8 != INVALID_HANDLE_VALUE) { BYTE OldRom[Apple2RomSize]; // NB. 12KB on stack @@ -1526,7 +1575,7 @@ void MemInitializeCustomF8ROM(void) SetFilePointer(g_hCustomRomF8, 0, NULL, FILE_BEGIN); DWORD uNumBytesRead; - BOOL bRes = ReadFile(g_hCustomRomF8, memrom+Apple2RomSize-F8RomSize, F8RomSize, &uNumBytesRead, NULL); + BOOL bRes = ReadFile(g_hCustomRomF8, memrom+F8RomOffset, F8RomSize, &uNumBytesRead, NULL); if (uNumBytesRead != F8RomSize) { memcpy(memrom, OldRom, Apple2RomSize); // ROM at $D000...$FFFF @@ -1854,7 +1903,7 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE #endif // DETERMINE THE NEW MEMORY PAGING MODE. - if ((address >= 0x80) && (address <= 0x8F)) + if (g_Slot0 != CT_Empty && (address >= 0x80 && address <= 0x8F)) { SetMemMode( g_pLanguageCard->SetPaging(address, memmode, modechanging, write ? true : false) ); } diff --git a/source/SaveState.cpp b/source/SaveState.cpp index e7c36fad..c61cabf5 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -605,7 +605,7 @@ void Snapshot_SaveState(void) yamlSaveHelper.UnitHdr(GetSnapshotUnitSlotsName(), UNIT_SLOTS_VER); YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); - if (IsApple2PlusOrClone(GetApple2Type())) + if (g_Slot0 != CT_Empty && IsApple2PlusOrClone(GetApple2Type())) GetLanguageCard()->SaveSnapshot(yamlSaveHelper); // Language Card or Saturn 128K Printer_SaveSnapshot(yamlSaveHelper); From f4ccc6929b5039a7068ad63d9f3d101d89fe7b50 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 4 Nov 2018 15:39:14 +0000 Subject: [PATCH 061/128] Help docs: updated for 48K Apple II and LC cmd-line switch --- help/CommandLine.html | 3 +++ help/cfg-config.html | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/help/CommandLine.html b/help/CommandLine.html index 650318d3..9b3ff70f 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -22,6 +22,9 @@ -s0 <saturn|saturn64|saturn128>
            Insert a Saturn 64K or Saturn 128K card into slot 0 in Apple II or Apple II+ machines (or similar clone).
            Where -s0 saturn is an alias for -s0 saturn128.

            + -s0 <languagecard|lc>
            + Insert an Apple 16K Language Card into slot 0 in Apple II and use the F8 auto-start ROM.
            + NB. The Apple II+ already defaults to having a Language Card, so this switch is not required.

            -s7 empty
            Remove the hard disk controller card from slot 7.
            Useful to allow a floppy disk to boot from slot 6, drive 1. Use in combination with -d1.

            diff --git a/help/cfg-config.html b/help/cfg-config.html index e8e027cf..5a6a036d 100644 --- a/help/cfg-config.html +++ b/help/cfg-config.html @@ -16,8 +16,8 @@ the predecessors of the Apple //e: the Apple ][ and Apple ][+. Besides running with a different Apple system ROM, some differences are discussed below.
              -
            • Apple ][ : Non-autobooting, 64K machine, no lower-case, no 80-column, 6502 CPU -
            • Apple ][+ : Autobooting version of the Apple ][ +
            • Apple ][ : 48K non-autostarting, Integer BASIC, no lower-case, no 80-column, 6502 CPU +
            • Apple ][+ : 64K autostarting, Applesoft BASIC version of the Apple ][
            • Apple //e : 128K machine, lower-case, 80-column, 6502 CPU
            • Enhanced Apple //e : 128K machine, lower-case, 80-column, 65C02 CPU
            • Clone (specific model selectable from Advanced page)
            • From 155547f847c9215c855099cf9935cc4f63515de2 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 4 Nov 2018 16:35:25 +0000 Subject: [PATCH 062/128] 1.27.10: Bump version & update History.txt --- bin/History.txt | 14 ++++++++++++++ resource/Applewin.rc | 8 ++++---- source/Memory.cpp | 5 +++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 152f821a..37886844 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -8,6 +8,20 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth + +1.27.10.0 - 4 Nov 2018 +---------------------- +. [Change #590] Apple II original: default to 48K (so no LC installed in slot-0). + - Added new command line switch: -s0 + ('lc' is an alias for 'languagecard') + - When LC is in slot-0, it now use the Apple II+'s F8 (auto-start) ROM +. [Change #408] Support Saturn 64K and 128K cards in slot-0. + - Added new command line switch: -s0 + ('saturn' is an alias for 'saturn128') +. [Bug #591] Save-state wasn't preserving the 'key-waiting' flag. +. [Bug #587] Debugger: disassembly for branch targets < $1000 were missing the leading '0'. + + 1.27.9.0 - 2 Oct 2018 --------------------- . [Bug #582] Support for partial disk II latch reads when accesses are very close. diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 8d985736..3a4d3378 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,9,0 - PRODUCTVERSION 1,27,9,0 + FILEVERSION 1,27,10,0 + PRODUCTVERSION 1,27,10,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 9, 0" + VALUE "FileVersion", "1, 27, 10, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 9, 0" + VALUE "ProductVersion", "1, 27, 10, 0" END END BLOCK "VarFileInfo" diff --git a/source/Memory.cpp b/source/Memory.cpp index 52efdbe1..42dcc991 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -2021,6 +2021,11 @@ LPVOID MemGetSlotParameters(UINT uSlot) void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux) { + // Create default LC type for AppleII machine (do prior to loading saved LC state) + ResetDefaultMachineMemTypes(); + g_MemTypeAppleII = CT_LanguageCard; // SSv1 doesn't save machine type - so if current machine is Apple II then give it 64K + LC + SetExpansionMemTypeDefault(); + SetMemMode(MemMode ^ MF_INTCXROM); // Convert from SLOTCXROM to INTCXROM SetLastRamWrite(LastWriteRam); From 325bc23d08395c2846fb5b4b98e3a6cf6d15c828 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 4 Nov 2018 17:29:22 +0000 Subject: [PATCH 063/128] Fix for LC when //e (broken 13c3936) --- source/Common.h | 5 ++--- source/Memory.cpp | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/Common.h b/source/Common.h index c8572e96..6dcf7756 100644 --- a/source/Common.h +++ b/source/Common.h @@ -200,7 +200,7 @@ inline bool IsApple2Original(eApple2Type type) // Apple ][ inline bool IsApple2Plus(eApple2Type type) // Apple ][,][+ { - return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0; + return ((type & (APPLE2E_MASK|APPLE2C_MASK)) == 0) && !(type & APPLECLONE_MASK); } inline bool IsClone(eApple2Type type) @@ -210,8 +210,7 @@ inline bool IsClone(eApple2Type type) inline bool IsApple2PlusOrClone(eApple2Type type) // Apple ][,][+ or clone ][,][+ { - return ((type & (APPLE2E_MASK|APPLE2C_MASK)) == 0) - || (type & APPLECLONE_MASK) && !(type & A2TYPE_CLONE_A2E); + return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0; } extern eApple2Type g_Apple2Type; diff --git a/source/Memory.cpp b/source/Memory.cpp index 42dcc991..cc43c55e 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1903,9 +1903,10 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE #endif // DETERMINE THE NEW MEMORY PAGING MODE. - if (g_Slot0 != CT_Empty && (address >= 0x80 && address <= 0x8F)) + if (address >= 0x80 && address <= 0x8F) { - SetMemMode( g_pLanguageCard->SetPaging(address, memmode, modechanging, write ? true : false) ); + if (!IS_APPLE2 || (IsApple2PlusOrClone(GetApple2Type()) && g_Slot0 != CT_Empty)) + SetMemMode( g_pLanguageCard->SetPaging(address, memmode, modechanging, write ? true : false) ); } else if (!IS_APPLE2) { From 3bf94eca9ddf48813f7cd9809c7d6e7f6283d33d Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 4 Nov 2018 20:04:38 +0000 Subject: [PATCH 064/128] Fix for save-state v1: original Apple II needs a LC --- source/Memory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/Memory.cpp b/source/Memory.cpp index cc43c55e..958a805a 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -2131,6 +2131,8 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) // Create default LC type for AppleII machine (do prior to loading saved LC state) ResetDefaultMachineMemTypes(); + if (version == 1) + g_MemTypeAppleII = CT_LanguageCard; // version=1: original Apple II always had a LC SetExpansionMemTypeDefault(); // From f9b7d9326ec5f448f3858c9820bc258822cb2297 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 6 Nov 2018 19:12:10 +0000 Subject: [PATCH 065/128] Fixed Coverity 'High Impact Outstanding' issues: CIDs in main code: 1446691 1446688 (false positive) 1446672 (false positive) 1446643 1446642 1446641 1446635 (false positive) CIDs in debugger: 1472410 1446728 (false positive) 1446684 1446673 1472409 1446693 1446692 1446726 1446687 1446685 1446683 --- source/Applewin.cpp | 4 +++ source/Debugger/Debug.cpp | 25 ++++++++++++------- source/Debugger/Debugger_DisassemblerData.cpp | 7 +++++- source/Debugger/Debugger_Display.cpp | 5 ++-- source/Debugger/Debugger_Parser.cpp | 6 ++--- source/DiskImageHelper.cpp | 1 + source/Memory.cpp | 1 + source/ParallelPrinter.cpp | 1 + source/SerialComms.cpp | 1 + 9 files changed, 36 insertions(+), 15 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index cb01a4b1..46ea2718 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1281,6 +1281,10 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { lpCmdLine = GetCurrArg(lpNextArg); lpNextArg = GetNextArg(lpNextArg); + + if (g_hCustomRomF8 != INVALID_HANDLE_VALUE) // Stop resource leak if -f8rom is specified twice! + CloseHandle(g_hCustomRomF8); + g_hCustomRomF8 = CreateFile(lpCmdLine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800)) g_bCustomRomF8Failed = true; diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 8f2b6a64..233ec4fa 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -3639,7 +3639,7 @@ Update_t CmdFlagClear (int nArgs) { int iFlag = (g_iCommand - CMD_FLAG_CLR_C); - if (g_iCommand == CMD_FLAG_CLEAR) + if (g_iCommand == CMD_FLAG_CLEAR) // Undocumented: "cl f f ... f", eg: "se n v c" (TODO: Conflicts with monitor command #L -> 000CL) { int iArg = nArgs; while (iArg) @@ -3648,9 +3648,10 @@ Update_t CmdFlagClear (int nArgs) while (iFlag < _6502_NUM_FLAGS) { // if (g_aFlagNames[iFlag] == g_aArgs[iArg].sArg[0]) - if (g_aBreakpointSource[ BP_SRC_FLAG_N + iFlag ][0] == g_aArgs[iArg].sArg[0]) + if (g_aBreakpointSource[ BP_SRC_FLAG_N - iFlag ][0] == toupper(g_aArgs[iArg].sArg[0])) { - regs.ps &= ~(1 << iFlag); + regs.ps &= ~(1 << (7-iFlag)); + break; } iFlag++; } @@ -3670,7 +3671,7 @@ Update_t CmdFlagSet (int nArgs) { int iFlag = (g_iCommand - CMD_FLAG_SET_C); - if (g_iCommand == CMD_FLAG_SET) + if (g_iCommand == CMD_FLAG_SET) // Undocumented: "se f f ... f", eg: "se n v c" { int iArg = nArgs; while (iArg) @@ -3679,9 +3680,10 @@ Update_t CmdFlagSet (int nArgs) while (iFlag < _6502_NUM_FLAGS) { // if (g_aFlagNames[iFlag] == g_aArgs[iArg].sArg[0]) - if (g_aBreakpointSource[ BP_SRC_FLAG_N + iFlag ][0] == g_aArgs[iArg].sArg[0]) + if (g_aBreakpointSource[ BP_SRC_FLAG_N - iFlag ][0] == toupper(g_aArgs[iArg].sArg[0])) { - regs.ps |= (1 << iFlag); + regs.ps |= (1 << (7-iFlag)); + break; } iFlag++; } @@ -4151,8 +4153,12 @@ Update_t CmdConfigSetDebugDir (int nArgs) { _tcsncpy( sPath, g_sCurrentDir, 2 ); // Prefix with drive letter & colon sPath[2] = 0; + _tcscat( sPath, g_aArgs[1].sArg ); + } + else + { + _tcscpy( sPath, g_aArgs[1].sArg ); } - _tcscat( sPath, g_aArgs[1].sArg ); } else // Relative { @@ -6454,7 +6460,8 @@ Update_t CmdOutputRun (int nArgs) // if (g_aArgs[1].bType & TYPE_QUOTED_2) - _tcscpy( sMiniFileName, pFileName ); + _tcsncpy( sMiniFileName, pFileName, sizeof(sMiniFileName) ); + sMiniFileName[sizeof(sMiniFileName)-1] = 0; // _tcscat( sMiniFileName, ".aws" ); // HACK: MAGIC STRING if (pFileName[0] == '\\' || pFileName[1] == ':') // NB. Any prefix quote has already been stripped @@ -7616,7 +7623,7 @@ Update_t CmdZeroPagePointer (int nArgs) // int nPtrNum = g_aArgs[0].sArg[1] - '0'; // HACK: hard-coded to command length int iZP = g_iCommand - CMD_ZEROPAGE_POINTER_0; - if( (iZP < 0) || (iZP > MAX_ZEROPAGE_POINTERS) ) + if( (iZP < 0) || (iZP >= MAX_ZEROPAGE_POINTERS) ) return Help_Arg_1( g_iCommand ); if (nArgs == 0) diff --git a/source/Debugger/Debugger_DisassemblerData.cpp b/source/Debugger/Debugger_DisassemblerData.cpp index c36a5618..0eded8e1 100644 --- a/source/Debugger/Debugger_DisassemblerData.cpp +++ b/source/Debugger/Debugger_DisassemblerData.cpp @@ -81,16 +81,21 @@ WORD _CmdDefineByteRange(int nArgs,int iArg,DisasmData_t & tData_) // tData_.nArraySize = 0; char *pSymbolName = ""; - char aSymbolName[ 32 ]; + char aSymbolName[ MAX_SYMBOLS_LEN+1 ]; SymbolTable_Index_e eSymbolTable = SYMBOLS_ASSEMBLY; bool bAutoDefineName = false; // 2.7.0.34 if( nArgs > 1 ) { if( g_aArgs[ 2 ].eToken == TOKEN_COLON ) // 2.7.0.31 Bug fix: DB range, i.e. DB 174E:174F + { bAutoDefineName = true; + } else + { pSymbolName = g_aArgs[ 1 ].sArg; + pSymbolName[MAX_SYMBOLS_LEN] = 0; // truncate to max symbol length + } } else { diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 937eccf3..3a171829 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -1792,7 +1792,8 @@ void FormatDisassemblyLine( const DisasmLine_t & line, char * sDisassembly, cons if (line.bTargetImmediate) { strcat( sDisassembly, "#" ); - strcpy( sTarget, line.sTarget ); // sTarget + strncpy( sTarget, line.sTarget, sizeof(sTarget) ); + sTarget[sizeof(sTarget)-1] = 0; } else sprintf( sTarget, g_aOpmodes[ line.iOpmode ].m_sFormat, line.nTarget ); @@ -2460,7 +2461,7 @@ void DrawMemory ( int line, int iMemDump ) char sText[ MAX_MEM_VIEW_TXT * 2 ]; char sData[ MAX_MEM_VIEW_TXT * 2 ]; - char sType [ 4 ] = "Mem"; + char sType [ 6 ] = "Mem"; char sAddress[ 8 ] = ""; int iForeground = FG_INFO_OPCODE; diff --git a/source/Debugger/Debugger_Parser.cpp b/source/Debugger/Debugger_Parser.cpp index f28a4b8d..dbbfb664 100644 --- a/source/Debugger/Debugger_Parser.cpp +++ b/source/Debugger/Debugger_Parser.cpp @@ -127,7 +127,7 @@ int _Arg_Shift( int iSrc, int iEnd, int iDst ) { if (iDst < 0) return ARG_SYNTAX_ERROR; - if (iDst > MAX_ARGS) + if (iDst >= MAX_ARGS) return ARG_SYNTAX_ERROR; int nArgs = (iEnd - iSrc); @@ -151,10 +151,10 @@ int _Args_Insert( int iSrc, int iEnd, int nLen ) iSrc += nLen; int iDst = iEnd + nLen; - if (iDst > MAX_ARGS) + if (iDst >= MAX_ARGS) return ARG_SYNTAX_ERROR; - if (iSrc > MAX_ARGS) + if (iSrc >= MAX_ARGS) return ARG_SYNTAX_ERROR; while (nLen--) diff --git a/source/DiskImageHelper.cpp b/source/DiskImageHelper.cpp index f1c1a4e1..48ba633d 100644 --- a/source/DiskImageHelper.cpp +++ b/source/DiskImageHelper.cpp @@ -1268,6 +1268,7 @@ ImageError_e CImageHelperBase::CheckZipFile(LPCTSTR pszImageFilename, ImageInfo* return eIMAGE_ERROR_ZIP; strncpy(pImageInfo->szFilenameInZip, szFilename, MAX_PATH); + pImageInfo->szFilenameInZip[MAX_PATH-1] = 0; memcpy(&pImageInfo->zipFileInfo.tmz_date, &file_info.tmu_date, sizeof(file_info.tmu_date)); pImageInfo->zipFileInfo.dosDate = file_info.dosDate; pImageInfo->zipFileInfo.internal_fa = file_info.internal_fa; diff --git a/source/Memory.cpp b/source/Memory.cpp index 958a805a..4c164140 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1580,6 +1580,7 @@ void MemInitializeCustomF8ROM(void) { memcpy(memrom, OldRom, Apple2RomSize); // ROM at $D000...$FFFF bRes = FALSE; + // NB. Keep g_hCustomRomF8 handle open - so that any next restart can load it again } if (!bRes) diff --git a/source/ParallelPrinter.cpp b/source/ParallelPrinter.cpp index 0916b083..a12c0171 100644 --- a/source/ParallelPrinter.cpp +++ b/source/ParallelPrinter.cpp @@ -315,6 +315,7 @@ bool Printer_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT inactivity = yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); g_PrinterIdleLimit = yamlLoadHelper.LoadUint(SS_YAML_KEY_IDLELIMIT); strncpy(g_szPrintFilename, yamlLoadHelper.LoadString(SS_YAML_KEY_FILENAME).c_str(), sizeof(g_szPrintFilename)); + g_szPrintFilename[sizeof(g_szPrintFilename)-1] = 0; if (yamlLoadHelper.LoadBool(SS_YAML_KEY_FILEOPEN)) { diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp index ac410d19..f512d942 100644 --- a/source/SerialComms.cpp +++ b/source/SerialComms.cpp @@ -1316,6 +1316,7 @@ char* CSuperSerialCard::GetSerialPortChoices() void CSuperSerialCard::SetSerialPortName(const char* pSerialPortName) { strncpy(m_ayCurrentSerialPortName, pSerialPortName, SIZEOF_SERIALCHOICE_ITEM); + m_ayCurrentSerialPortName[SIZEOF_SERIALCHOICE_ITEM-1] = 0; // Init m_aySerialPortChoices, so that we have choices to show if serial is active when we 1st open Config dialog GetSerialPortChoices(); From 42c58f54e74e5729eed03de638006b267ef3979f Mon Sep 17 00:00:00 2001 From: TomCh Date: Fri, 9 Nov 2018 20:51:51 +0000 Subject: [PATCH 066/128] Refactor Language Card (#593) * Refactor Language Card: . MemSetPaging() now not used for $C080-C08F accesses. - Instead LC registers its own I/O handler like all other slot 1-7 cards. . Saturn uses base LC's 16K for bank0 * Move all 'modechanging = 0' to UpdatePaging() --- source/LanguageCard.cpp | 119 ++++++++++++++++++++++++++++++---------- source/LanguageCard.h | 13 +++-- source/Memory.cpp | 74 +++++++++++++------------ source/Memory.h | 2 + source/SaveState.cpp | 6 +- 5 files changed, 144 insertions(+), 70 deletions(-) diff --git a/source/LanguageCard.cpp b/source/LanguageCard.cpp index 2c61139c..2ae13fc3 100644 --- a/source/LanguageCard.cpp +++ b/source/LanguageCard.cpp @@ -49,19 +49,28 @@ LanguageCardUnit::~LanguageCardUnit(void) SetMemMainLanguageCard(NULL); } -DWORD LanguageCardUnit::SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write) +void LanguageCardUnit::InitializeIO(void) { + RegisterIoHandler(kSlot0, &LanguageCardUnit::IO, &LanguageCardUnit::IO, NULL, NULL, this, NULL); +} + +BYTE __stdcall LanguageCardUnit::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles) +{ + LanguageCardUnit* pLC = (LanguageCardUnit*) MemGetSlotParameters(kSlot0); + + DWORD memmode = GetMemMode(); + DWORD lastmemmode = memmode; memmode &= ~(MF_BANK2 | MF_HIGHRAM); - if (!(address & 8)) + if (!(uAddr & 8)) memmode |= MF_BANK2; - if (((address & 2) >> 1) == (address & 1)) + if (((uAddr & 2) >> 1) == (uAddr & 1)) memmode |= MF_HIGHRAM; - if (address & 1) // GH#392 + if (uAddr & 1) // GH#392 { - if (!write && GetLastRamWrite()) + if (!bWrite && pLC->GetLastRamWrite()) { memmode |= MF_WRITERAM; // UTAIIe:5-23 } @@ -71,9 +80,36 @@ DWORD LanguageCardUnit::SetPaging(WORD address, DWORD memmode, BOOL& modechangin memmode &= ~MF_WRITERAM; // UTAIIe:5-23 } - SetLastRamWrite( ((address & 1) && !write) ); // UTAIIe:5-23 + pLC->SetLastRamWrite( ((uAddr & 1) && !bWrite) ); // UTAIIe:5-23 + SetMemMode(memmode); - return memmode; + // + + if (IS_APPLE2E) + { + // IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS + // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL + // IT DOES SO. + // + // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour. + // - although any data-race is probably a bug in the 6502 code too. + if ((PC < 0xC000) && + (((*(LPDWORD)(mem+PC) & 0x00FFFEFF) == 0x00C0048D) || // Next: STA $C004 or STA $C005 + ((*(LPDWORD)(mem+PC) & 0x00FFFEFF) == 0x00C0028D))) // Next: STA $C002 or STA $C003 + { + SetModeChanging(1); + return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles); + } + } + + // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND + // WRITE TABLES. + if (lastmemmode != memmode) + { + MemUpdatePaging(0); // Initialize=0 + } + + return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles); } //------------------------------------- @@ -94,7 +130,7 @@ LanguageCardSlot0::~LanguageCardSlot0(void) // static const UINT kUNIT_LANGUAGECARD_VER = 1; -static const UINT kSLOT_LANGUAGECARD = 0; +static const UINT kSLOT_LANGUAGECARD = LanguageCardUnit::kSlot0; #define SS_YAML_VALUE_CARD_LANGUAGECARD "Language Card" @@ -188,7 +224,9 @@ Saturn128K::Saturn128K(UINT banks) for (UINT i=0; im_uSaturnTotalBanks); + if (!pLC->m_uSaturnTotalBanks) + return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles); + + bool bBankChanged = false; + DWORD memmode=0, lastmemmode=0; + + if (uAddr & (1<<2)) { - m_uSaturnActiveBank = 0 // Saturn 128K Language Card Bank 0 .. 7 - | (address >> 1) & 4 - | (address >> 0) & 3; + pLC->m_uSaturnActiveBank = 0 // Saturn 128K Language Card Bank 0 .. 7 + | (uAddr >> 1) & 4 + | (uAddr >> 0) & 3; - if (m_uSaturnActiveBank >= m_uSaturnTotalBanks) + if (pLC->m_uSaturnActiveBank >= pLC->m_uSaturnTotalBanks) { // EG. Run RAMTEST128K tests on a Saturn 64K card // TODO: Saturn::UpdatePaging() should deal with this case: // . Technically read floating-bus, write to nothing // . But the mem cache doesn't support floating-bus reads from non-I/O space - m_uSaturnActiveBank = m_uSaturnTotalBanks-1; // FIXME: just prevent crash for now! + pLC->m_uSaturnActiveBank = pLC->m_uSaturnTotalBanks-1; // FIXME: just prevent crash for now! } - SetMemMainLanguageCard( m_aSaturnBanks[ m_uSaturnActiveBank ] ); - - modechanging = 1; + SetMemMainLanguageCard( pLC->m_aSaturnBanks[ pLC->m_uSaturnActiveBank ] ); + bBankChanged = true; } else { + memmode = GetMemMode(); + lastmemmode = memmode; memmode &= ~(MF_BANK2 | MF_HIGHRAM); - if (!(address & 8)) + if (!(uAddr & 8)) memmode |= MF_BANK2; - if (((address & 2) >> 1) == (address & 1)) + if (((uAddr & 2) >> 1) == (uAddr & 1)) memmode |= MF_HIGHRAM; - if (address & 1 && GetLastRamWrite()) // Saturn differs from Apple's 16K LC: any access (LC is read-only) + if (uAddr & 1 && pLC->GetLastRamWrite())// Saturn differs from Apple's 16K LC: any access (LC is read-only) memmode |= MF_WRITERAM; else memmode &= ~MF_WRITERAM; - SetLastRamWrite(address & 1); // Saturn differs from Apple's 16K LC: any access (LC is read-only) + pLC->SetLastRamWrite(uAddr & 1); // Saturn differs from Apple's 16K LC: any access (LC is read-only) + SetMemMode(memmode); } - return memmode; + // NB. Unlike LC, no need to check if next opcode is STA $C002-5, as Saturn is not for //e + + // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND + // WRITE TABLES. + if ((lastmemmode != memmode) || bBankChanged) + { + MemUpdatePaging(0); // Initialize=0 + } + + return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles); } // static const UINT kUNIT_SATURN_VER = 1; -static const UINT kSLOT_SATURN = 0; +static const UINT kSLOT_SATURN = LanguageCardUnit::kSlot0; #define SS_YAML_VALUE_CARD_SATURN128 "Saturn 128" diff --git a/source/LanguageCard.h b/source/LanguageCard.h index 7134b1d5..f7cfaaa5 100644 --- a/source/LanguageCard.h +++ b/source/LanguageCard.h @@ -10,7 +10,7 @@ public: LanguageCardUnit(void); virtual ~LanguageCardUnit(void); - virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write); + virtual void InitializeIO(void); virtual void SetMemorySize(UINT banks) {} // No-op for //e and slot-0 16K LC virtual UINT GetActiveBank(void) { return 0; } // Always 0 as only 1x 16K bank virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) { _ASSERT(0); } // Not used for //e @@ -20,7 +20,10 @@ public: void SetLastRamWrite(BOOL count) { m_uLastRamWrite = count; } SS_CARDTYPE GetMemoryType(void) { return m_type; } + static BYTE __stdcall IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles); + static const UINT kMemModeInitialState; + static const UINT kSlot0 = 0; protected: SS_CARDTYPE m_type; @@ -49,10 +52,10 @@ protected: void SaveLCState(class YamlSaveHelper& yamlSaveHelper); void LoadLCState(class YamlLoadHelper& yamlLoadHelper); + LPBYTE m_pMemory; + private: std::string GetSnapshotMemStructName(void); - - LPBYTE m_pMemory; }; // @@ -65,12 +68,14 @@ public: Saturn128K(UINT banks); virtual ~Saturn128K(void); - virtual DWORD SetPaging(WORD address, DWORD memmode, BOOL& modechanging, bool write); + virtual void InitializeIO(void); virtual void SetMemorySize(UINT banks); virtual UINT GetActiveBank(void); virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); virtual bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version); + static BYTE __stdcall IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nExecutedCycles); + // "The boards consist of 16K banks of memory (4 banks for the 64K board, 8 banks for the 128K), accessed one at a time" - Ref: "64K/128K RAM BOARD", Saturn Systems, Ch.1 Introduction(pg-5) static const UINT kMaxSaturnBanks = 8; // 8 * 16K = 128K static std::string GetSnapshotCardName(void); diff --git a/source/Memory.cpp b/source/Memory.cpp index 4c164140..da8caa25 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -229,7 +229,7 @@ static void ResetDefaultMachineMemTypes(void) g_MemTypeAppleIIe = CT_Extended80Col; } -// Called from MemInitialize(), MemLoadSnapshot() +// Called from MemInitialize(), MemLoadSnapshot(), MemSetSnapshot_v1() static void SetExpansionMemTypeDefault(void) { SS_CARDTYPE defaultType = IsApple2Original(GetApple2Type()) ? g_MemTypeAppleII @@ -280,25 +280,28 @@ void SetExpansionMemType(const SS_CARDTYPE type) newSlotAuxCard = type; } + g_Slot0 = newSlot0Card; + g_SlotAux = newSlotAuxCard; +} + +void CreateLanguageCard(void) +{ + delete g_pLanguageCard; + g_pLanguageCard = NULL; + if (IsApple2PlusOrClone(GetApple2Type())) { - delete g_pLanguageCard; - - if (newSlot0Card == CT_Saturn128K) + if (g_Slot0 == CT_Saturn128K) g_pLanguageCard = new Saturn128K(g_uSaturnBanksFromCmdLine); - else if (newSlot0Card == CT_LanguageCard) + else if (g_Slot0 == CT_LanguageCard) g_pLanguageCard = new LanguageCardSlot0; else g_pLanguageCard = NULL; } else { - delete g_pLanguageCard; g_pLanguageCard = new LanguageCardUnit; } - - g_Slot0 = newSlot0Card; - g_SlotAux = newSlotAuxCard; } SS_CARDTYPE GetCurrentExpansionMemType(void) @@ -969,6 +972,11 @@ static bool IsCardInSlot(const UINT uSlot) //=========================================================================== +void SetModeChanging(BOOL value) +{ + modechanging = value; +} + DWORD GetMemMode(void) { return memmode; @@ -1037,6 +1045,8 @@ void MemUpdatePaging(BOOL initialize) static void UpdatePaging(BOOL initialize) { + modechanging = 0; + // SAVE THE CURRENT PAGING SHADOW TABLE LPBYTE oldshadow[256]; if (!initialize) @@ -1437,7 +1447,7 @@ void MemInitialize() SetExpansionMemTypeDefault(); #ifdef RAMWORKS - if (GetCurrentExpansionMemType() == CT_RamWorksIII) + if (g_SlotAux == CT_RamWorksIII) { // allocate memory for RAMWorks III - up to 8MB g_uActiveBank = 0; @@ -1452,6 +1462,8 @@ void MemInitialize() // + CreateLanguageCard(); + MemInitializeROM(); MemInitializeCustomF8ROM(); MemInitializeIO(); @@ -1580,9 +1592,10 @@ void MemInitializeCustomF8ROM(void) { memcpy(memrom, OldRom, Apple2RomSize); // ROM at $D000...$FFFF bRes = FALSE; - // NB. Keep g_hCustomRomF8 handle open - so that any next restart can load it again } + // NB. If succeeded, then keep g_hCustomRomF8 handle open - so that any next restart can load it again + if (!bRes) { MessageBox( g_hFrameWindow, "Failed to read custom F8 rom", TEXT("AppleWin Error"), MB_OK ); @@ -1616,8 +1629,10 @@ void MemInitializeIO(void) { InitIoHandlers(); - const UINT uSlot = 0; - RegisterIoHandler(uSlot, MemSetPaging, MemSetPaging, NULL, NULL, NULL, NULL); + if (g_pLanguageCard) + g_pLanguageCard->InitializeIO(); + else + RegisterIoHandler(LanguageCardUnit::kSlot0, IO_Null, IO_Null, NULL, NULL, NULL, NULL); // TODO: Cleanup peripheral setup!!! PrintLoadRom(pCxRomPeripheral, 1); // $C100 : Parallel printer f/w @@ -1904,12 +1919,7 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE #endif // DETERMINE THE NEW MEMORY PAGING MODE. - if (address >= 0x80 && address <= 0x8F) - { - if (!IS_APPLE2 || (IsApple2PlusOrClone(GetApple2Type()) && g_Slot0 != CT_Empty)) - SetMemMode( g_pLanguageCard->SetPaging(address, memmode, modechanging, write ? true : false) ); - } - else if (!IS_APPLE2) + if (!IS_APPLE2) { switch (address) { @@ -1943,24 +1953,19 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE } } - if (GetCurrentExpansionMemType() != CT_Saturn128K) // TODO: Not sure this optimisation is valid for Saturn, so skip it for now + if (IS_APPLE2E) { - // IF THE EMULATED PROGRAM HAS JUST UPDATE THE MEMORY WRITE MODE AND IS + // IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL // IT DOES SO. // // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour. // - although any data-race is probably a bug in the 6502 code too. if ((address >= 4) && (address <= 5) && - ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) { + ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) // Next: STA $C002 or STA $C003 + { modechanging = 1; - return write ? 0 : MemReadFloatingBus(1, nExecutedCycles); - } - if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) && - (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) || - ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) { - modechanging = 1; - return write ? 0 : MemReadFloatingBus(1, nExecutedCycles); + return 0; // For $C004 & $C005: entry to this func is always via a write to $C004 or $C005 } } @@ -1968,8 +1973,6 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE // WRITE TABLES. if ((lastmemmode != memmode) || modechanging) { - modechanging = 0; - // NB. Must check MF_SLOTC3ROM too, as IoHandlerCardsIn() depends on both MF_INTCXROM|MF_SLOTC3ROM if ((lastmemmode & (MF_INTCXROM|MF_SLOTC3ROM)) != (memmode & (MF_INTCXROM|MF_SLOTC3ROM))) { @@ -2027,6 +2030,7 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* ResetDefaultMachineMemTypes(); g_MemTypeAppleII = CT_LanguageCard; // SSv1 doesn't save machine type - so if current machine is Apple II then give it 64K + LC SetExpansionMemTypeDefault(); + CreateLanguageCard(); // Create LC here, as for SSv1 there is no slot-0 state SetMemMode(MemMode ^ MF_INTCXROM); // Convert from SLOTCXROM to INTCXROM SetLastRamWrite(LastWriteRam); @@ -2037,7 +2041,6 @@ void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* // - modechanging = 0; // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v1() UpdatePaging(1); // Initialize=1 } @@ -2133,8 +2136,12 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) // Create default LC type for AppleII machine (do prior to loading saved LC state) ResetDefaultMachineMemTypes(); if (version == 1) - g_MemTypeAppleII = CT_LanguageCard; // version=1: original Apple II always had a LC + g_MemTypeAppleII = CT_LanguageCard; // version=1: original Apple II always has a LC + else + g_MemTypeAppleIIPlus = CT_Empty; // version=2+: Apple II/II+ initially start with slot-0 empty SetExpansionMemTypeDefault(); + CreateLanguageCard(); // Create default LC now for: (a) //e which has no slot-0 LC (so this is final) + // (b) II/II+ which get re-created later if slot-0 has a card // @@ -2181,7 +2188,6 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) // - modechanging = 0; // NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v2() UpdatePaging(1); // Initialize=1 (Still needed, even with call to MemUpdatePaging() - why?) // TC-TODO: At this point, the cards haven't been loaded, so the card's expansion ROM is unknown - so pointless(?) calling this now diff --git a/source/Memory.h b/source/Memory.h index ff81ddab..6538ae01 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -66,6 +66,7 @@ LPBYTE MemGetBankPtr(const UINT nBank); LPBYTE MemGetCxRomPeripheral(); DWORD GetMemMode(void); void SetMemMode(DWORD memmode); +void SetModeChanging(BOOL value); bool MemIsAddrCodeMemory(const USHORT addr); void MemInitialize (); void MemInitializeROM(void); @@ -92,6 +93,7 @@ BYTE __stdcall MemSetPaging(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExec enum SS_CARDTYPE; void SetExpansionMemType(const SS_CARDTYPE type); SS_CARDTYPE GetCurrentExpansionMemType(void); +void CreateLanguageCard(void); void SetRamWorksMemorySize(UINT pages); UINT GetRamWorksActiveBank(void); diff --git a/source/SaveState.cpp b/source/SaveState.cpp index c61cabf5..ca2fed79 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -371,7 +371,6 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version) if (!yamlLoadHelper.GetSubMap(std::string(SS_YAML_KEY_STATE))) throw std::string(SS_YAML_KEY_UNIT ": Expected sub-map name: " SS_YAML_KEY_STATE); - bool bIsCardSupported = true; SS_CARDTYPE type = CT_Empty; bool bRes = false; @@ -420,21 +419,22 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT version) { type = CT_LanguageCard; SetExpansionMemType(type); + CreateLanguageCard(); bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, version); } else if (card == Saturn128K::GetSnapshotCardName()) { type = CT_Saturn128K; SetExpansionMemType(type); + CreateLanguageCard(); bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, version); } else { - bIsCardSupported = false; throw std::string("Slots: Unknown card: " + card); // todo: don't throw - just ignore & continue } - if (bRes && bIsCardSupported) + if (bRes) { m_ConfigNew.m_Slot[slot] = type; } From 6fb5b3b0e8c511251d4a18b6cb4141b2f0764e16 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 10 Nov 2018 10:30:19 +0000 Subject: [PATCH 067/128] Refactor: consolidate 'modechanging' optimisations into a single function --- source/LanguageCard.cpp | 18 ++------------ source/Memory.cpp | 53 +++++++++++++++++++++++++---------------- source/Memory.h | 2 +- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/source/LanguageCard.cpp b/source/LanguageCard.cpp index 2ae13fc3..24d3c64e 100644 --- a/source/LanguageCard.cpp +++ b/source/LanguageCard.cpp @@ -85,22 +85,8 @@ BYTE __stdcall LanguageCardUnit::IO(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValu // - if (IS_APPLE2E) - { - // IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS - // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL - // IT DOES SO. - // - // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour. - // - although any data-race is probably a bug in the 6502 code too. - if ((PC < 0xC000) && - (((*(LPDWORD)(mem+PC) & 0x00FFFEFF) == 0x00C0048D) || // Next: STA $C004 or STA $C005 - ((*(LPDWORD)(mem+PC) & 0x00FFFEFF) == 0x00C0028D))) // Next: STA $C002 or STA $C003 - { - SetModeChanging(1); - return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles); - } - } + if (MemOptimizeForModeChanging(PC, uAddr)) + return bWrite ? 0 : MemReadFloatingBus(nExecutedCycles); // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND // WRITE TABLES. diff --git a/source/Memory.cpp b/source/Memory.cpp index da8caa25..0799589e 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -972,11 +972,6 @@ static bool IsCardInSlot(const UINT uSlot) //=========================================================================== -void SetModeChanging(BOOL value) -{ - modechanging = value; -} - DWORD GetMemMode(void) { return memmode; @@ -1953,21 +1948,8 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE } } - if (IS_APPLE2E) - { - // IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS - // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL - // IT DOES SO. - // - // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour. - // - although any data-race is probably a bug in the 6502 code too. - if ((address >= 4) && (address <= 5) && - ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) // Next: STA $C002 or STA $C003 - { - modechanging = 1; - return 0; // For $C004 & $C005: entry to this func is always via a write to $C004 or $C005 - } - } + if (MemOptimizeForModeChanging(programcounter, address)) + return write ? 0 : MemReadFloatingBus(nExecutedCycles); // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND // WRITE TABLES. @@ -2012,6 +1994,37 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE //=========================================================================== +bool MemOptimizeForModeChanging(WORD programcounter, WORD address) +{ + if (IS_APPLE2E) + { + // IF THE EMULATED PROGRAM HAS JUST UPDATED THE MEMORY WRITE MODE AND IS + // ABOUT TO UPDATE THE MEMORY READ MODE, HOLD OFF ON ANY PROCESSING UNTIL + // IT DOES SO. + // + // NB. A 6502 interrupt occurring between these memory write & read updates could lead to incorrect behaviour. + // - although any data-race is probably a bug in the 6502 code too. + if ((address >= 4) && (address <= 5) && // Now: RAMWRTOFF or RAMWRTON + ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) // Next: STA $C002(RAMRDOFF) or STA $C003(RAMRDON) + { + modechanging = 1; + return true; + } + + if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) && // Now: LC + (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) || // Next: STA $C004(RAMWRTOFF) or STA $C005(RAMWRTON) + ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) // or STA $C002(RAMRDOFF) or STA $C003(RAMRDON) + { + modechanging = 1; + return true; + } + } + + return false; +} + +//=========================================================================== + LPVOID MemGetSlotParameters(UINT uSlot) { _ASSERT(uSlot < NUM_SLOTS); diff --git a/source/Memory.h b/source/Memory.h index 6538ae01..7ae9c469 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -66,7 +66,7 @@ LPBYTE MemGetBankPtr(const UINT nBank); LPBYTE MemGetCxRomPeripheral(); DWORD GetMemMode(void); void SetMemMode(DWORD memmode); -void SetModeChanging(BOOL value); +bool MemOptimizeForModeChanging(WORD programcounter, WORD address); bool MemIsAddrCodeMemory(const USHORT addr); void MemInitialize (); void MemInitializeROM(void); From 14e0bb7b71080ad8945d0cfa5490f22afce102cb Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 10 Nov 2018 15:55:20 +0000 Subject: [PATCH 068/128] Added new switch: '-no-hook-alt' - used to prevent left/right ALT from emulating open/closed apple keys (#583) --- source/Applewin.cpp | 4 ++++ source/Frame.cpp | 10 +++++----- source/Joystick.cpp | 14 +++++++++++++- source/Joystick.h | 3 ++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 46ea2718..f0e787b8 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1313,6 +1313,10 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { g_bHookAltGrControl = true; } + else if (strcmp(lpCmdLine, "-no-hook-alt") == 0) // GH#583 + { + JoySetHookAltKeys(false); + } else if (strcmp(lpCmdLine, "-spkr-inc") == 0) { lpCmdLine = GetCurrArg(lpNextArg); diff --git a/source/Frame.cpp b/source/Frame.cpp index eb4d5470..26841a44 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1378,10 +1378,10 @@ LRESULT CALLBACK FrameWndProc ( else if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_LOGO) || (g_nAppMode == MODE_STEPPING)) { // NB. Alt Gr (Right-Alt): this normally send 2 WM_KEYDOWN messages for: VK_LCONTROL, then VK_RMENU - // . NB. The keyboard hook filter now suppresses VK_LCONTROL + // . NB. The keyboard hook filter will suppress VK_LCONTROL (if -hook-altgr-control is passed on the cmd-line) bool extended = (HIWORD(lparam) & KF_EXTENDED) != 0; - BOOL down = 1; - BOOL autorep = (HIWORD(lparam) & KF_REPEAT) != 0; + bool down = true; + bool autorep = (HIWORD(lparam) & KF_REPEAT) != 0; BOOL IsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); #if DEBUG_KEY_MESSAGES @@ -1436,8 +1436,8 @@ LRESULT CALLBACK FrameWndProc ( else { bool extended = (HIWORD(lparam) & KF_EXTENDED) != 0; - BOOL down = 0; - BOOL autorep = 0; + bool down = false; + bool autorep = false; BOOL bIsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); #if DEBUG_KEY_MESSAGES diff --git a/source/Joystick.cpp b/source/Joystick.cpp index bdcecfc7..01e61733 100644 --- a/source/Joystick.cpp +++ b/source/Joystick.cpp @@ -111,6 +111,15 @@ static UINT g_bJoyportEnabled = 0; // Set to use Joyport to drive the 3 button i static UINT g_uJoyportActiveStick = 0; static UINT g_uJoyportReadMode = JOYPORT_LEFTRIGHT; +static bool g_bHookAltKeys = true; + +//=========================================================================== + +void JoySetHookAltKeys(bool hook) +{ + g_bHookAltKeys = hook; +} + //=========================================================================== void CheckJoystick0() { @@ -296,7 +305,7 @@ void JoyInitialize() #define SUPPORT_CURSOR_KEYS -BOOL JoyProcessKey(int virtkey, BOOL extended, BOOL down, BOOL autorep) +BOOL JoyProcessKey(int virtkey, bool extended, bool down, bool autorep) { static struct { @@ -314,6 +323,9 @@ BOOL JoyProcessKey(int virtkey, BOOL extended, BOOL down, BOOL autorep) return 0; } + if (!g_bHookAltKeys && virtkey == VK_MENU) // GH#583 + return 0; + // BOOL keychange = 0; diff --git a/source/Joystick.h b/source/Joystick.h index 8d22876f..2e69d1ce 100644 --- a/source/Joystick.h +++ b/source/Joystick.h @@ -8,7 +8,7 @@ enum JOY1CHOICE {J1C_DISABLED=0, J1C_JOYSTICK2, J1C_KEYBD_CURSORS, J1C_KEYBD_NUM enum {JOYSTICK_MODE_FLOATING=0, JOYSTICK_MODE_CENTERING}; // Joystick centering control void JoyInitialize(); -BOOL JoyProcessKey(int,BOOL,BOOL,BOOL); +BOOL JoyProcessKey(int,bool,bool,bool); void JoyReset(); void JoySetButton(eBUTTON,eBUTTONSTATE); BOOL JoySetEmulationType(HWND,DWORD,int, const bool bMousecardActive); @@ -24,6 +24,7 @@ DWORD JoyGetJoyType(UINT num); void JoySetTrim(short nValue, bool bAxisX); short JoyGetTrim(bool bAxisX); void JoyportControl(const UINT uControl); +void JoySetHookAltKeys(bool hook); void JoySetSnapshot_v1(const unsigned __int64 JoyCntrResetCycle); void JoySaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void JoyLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); From aa59c718470d84287da8cf854de663287fc624ea Mon Sep 17 00:00:00 2001 From: TomCh Date: Sat, 17 Nov 2018 16:29:17 +0000 Subject: [PATCH 069/128] Add support for PAL/European or custom 8K video ROMs (#596) Added new cmd-line switch: -videorom to replace the video ROM for the Enhanced //e. - Support video ROM sizes of 4K, 8K and 16K (top 8K only). - NB. The rocker switch is set to European video ROM. F10 (for //e or Enhanced //e models) emulates the PAL //e's rocker switch (under the keyboard) to toggle between European or US video ROM. Other: - Fixed debugger's view of the AltCharSet soft-switch (it was showing the opposite state). --- resource/Applewin.rc | 8 +-- source/Applewin.cpp | 20 +++++- source/Debugger/Debugger_Display.cpp | 2 +- source/Frame.cpp | 21 ++++-- source/NTSC.cpp | 2 +- source/NTSC_CharSet.cpp | 100 ++++++++++++++++++++++++++- source/NTSC_CharSet.h | 3 +- source/Video.cpp | 63 ++++++++++++++++- source/Video.h | 9 ++- 9 files changed, 208 insertions(+), 20 deletions(-) diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 3a4d3378..3262496d 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,10,0 - PRODUCTVERSION 1,27,10,0 + FILEVERSION 1,27,11,0 + PRODUCTVERSION 1,27,11,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 10, 0" + VALUE "FileVersion", "1, 27, 11, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 10, 0" + VALUE "ProductVersion", "1, 27, 11, 0" END END BLOCK "VarFileInfo" diff --git a/source/Applewin.cpp b/source/Applewin.cpp index f0e787b8..9d2fb161 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1289,6 +1289,22 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800)) g_bCustomRomF8Failed = true; } + else if (strcmp(lpCmdLine, "-videorom") == 0) // Use 4K,8K or 16K video ROM for Enhanced //e + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + + if (!ReadVideoRomFile(lpCmdLine)) + { + std::string msg = "Failed to load video rom (not found or not exactly 4/8/16KiB)"; + LogFileOutput("%s", msg.c_str()); + MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); + } + else + { + SetVideoRomRockerSwitch(true); // Use PAL char set + } + } else if (strcmp(lpCmdLine, "-printscreen") == 0) // Turn on display of the last filename print screen was saved to { g_bDisplayPrintScreenFileName = true; @@ -1553,7 +1569,9 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (g_bCustomRomF8Failed) { - MessageBox(g_hFrameWindow, "Failed to load custom F8 rom (not found or not exactly 2KB)", TEXT("AppleWin Error"), MB_OK); + std::string msg = "Failed to load custom F8 rom (not found or not exactly 2KiB)"; + LogFileOutput("%s", msg.c_str()); + MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); bShutdown = true; } diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 3a171829..b9a8a62a 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -3089,7 +3089,7 @@ void DrawSoftSwitches( int iSoftSwitch ) _DrawSoftSwitch( rect, 0xC00C, bSet, "Col", "40", "80", NULL, bgMemory ); // C00E = off, C00F = on - bSet = VideoGetSWAltCharSet(); + bSet = !VideoGetSWAltCharSet(); _DrawSoftSwitch( rect, 0xC00E, bSet, NULL, "ASC", "MOUS", NULL, bgMemory ); // ASCII/MouseText #if SOFTSWITCH_LANGCARD diff --git a/source/Frame.cpp b/source/Frame.cpp index 26841a44..de139893 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1316,14 +1316,19 @@ LRESULT CALLBACK FrameWndProc ( } else if (wparam == VK_F10) { - if (g_Apple2Type == A2TYPE_PRAVETS8A && !KeybGetCtrlStatus()) - { - KeybToggleP8ACapsLock (); // F10: Toggles P8 Capslock - } - else + if (KeybGetCtrlStatus()) { SetUsingCursor(FALSE); // Ctrl+F10 } + else if (g_Apple2Type == A2TYPE_APPLE2E || g_Apple2Type == A2TYPE_APPLE2EENHANCED) + { + SetVideoRomRockerSwitch( !GetVideoRomRockerSwitch() ); // F10: toggle rocker switch + NTSC_VideoInitAppleType(); + } + else if (g_Apple2Type == A2TYPE_PRAVETS8A) + { + KeybToggleP8ACapsLock (); // F10: Toggles Pravets8A Capslock + } } else if (wparam == VK_F11 && !KeybGetCtrlStatus()) // Save state (F11) { @@ -1758,7 +1763,6 @@ LRESULT CALLBACK FrameWndProc ( KeybUpdateCtrlShiftStatus(); // http://msdn.microsoft.com/en-us/library/windows/desktop/gg153546(v=vs.85).aspx - // v1.25.0: Alt-Return Alt-Enter toggle fullscreen if (g_bAltEnter_ToggleFullScreen && KeybGetAltStatus() && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU return 0; // NOP -- eat key @@ -1772,7 +1776,10 @@ LRESULT CALLBACK FrameWndProc ( case WM_SYSKEYUP: KeybUpdateCtrlShiftStatus(); - // v1.25.0: Alt-Return Alt-Enter toggle fullscreen + // F10: no WM_KEYUP handler for VK_F10. Don't allow WM_KEYUP to pass to default handler which will show the app window's "menu" (and lose focus) + if (wparam == VK_F10) + return 0; + if (g_bAltEnter_ToggleFullScreen && KeybGetAltStatus() && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU ScreenWindowResize(false); else diff --git a/source/NTSC.cpp b/source/NTSC.cpp index ae0b1503..088626dc 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -471,7 +471,7 @@ static void set_csbits() case A2TYPE_APPLE2: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break; case A2TYPE_APPLE2PLUS: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break; case A2TYPE_APPLE2E: csbits = &csbits_2e[0]; break; - case A2TYPE_APPLE2EENHANCED:csbits = &csbits_enhanced2e[0]; break; + case A2TYPE_APPLE2EENHANCED:csbits = GetEnhanced2e_csbits(); break; case A2TYPE_PRAVETS82: csbits = &csbits_pravets82[0]; g_nVideoCharSet = 0; break; // Apple ][ clone case A2TYPE_PRAVETS8M: csbits = &csbits_pravets8M[0]; g_nVideoCharSet = 0; break; // Apple ][ clone case A2TYPE_PRAVETS8A: csbits = &csbits_pravets8C[0]; break; // Apple //e clone diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp index 4fa37822..88d1250f 100644 --- a/source/NTSC_CharSet.cpp +++ b/source/NTSC_CharSet.cpp @@ -21,10 +21,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "StdAfx.h" #include "Applewin.h" +#include "Video.h" #include "NTSC_CharSet.h" -unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e +unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM) +static unsigned char csbits_enhanced2e_pal[2][256][8]; // PAL Enhanced //e (2764 8K video ROM - top 4K) via rocker switch under keyboard unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext) unsigned char csbits_a2[1][256][8]; // ][ and ][+ unsigned char csbits_pravets82[1][256][8]; // Pravets 82 @@ -86,6 +88,91 @@ static void get_csbits(csbits_t csbits, const char* resourceName, const UINT cy0 delete [] pBuffer; } +//------------------------------------- + +// ROM address (RA): +// ----------------- +// . RA10,..,RA3;SEGC,SEGB,SEGA => [2^8][2^3] => 256 chars of 8 lines (total = 2KiB) +// . VID7,..,VID0 is the 8-bit video character (eg. from TEXT/$400 memory) +// +// UTAIIe:8-13, Table 8.2: +// +// ALTCHRSET | RA10 | RA9 +//------------------------------------------ +// 0 | VID7 + VID6.FLASH | VID6.VID7 +// 1 | VID7 | VID6 +// +// FLASH toggles every 16 VBLs, so alternates between selecting NORMAL control/special and INVERSE control/special +// + +void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom) +{ + int RA = 0; // rom address + int i = 0; + + // regular char set + + for (; i<64; i++, RA+=8) // [00..3F] INVERSE / [40..7F] FLASH + { + for (int y=0; y<8; y++) + { + csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..." + csbits[0][i+64][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-14 (Table 8.3) we use FLASH=0, so RA=00ccccccsss + } + } + + RA = (1<<10 | 0<<9); // UTAIIe:8-14 (Table 8.3) + + for (i=128; i<256; i++, RA+=8) // [80..BF] NORMAL + { + for (int y=0; y<8; y++) + { + csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..." + } + } + + RA = (1<<10 | 1<<9); // UTAIIe:8-14 (Table 8.3) + + for (i=192; i<256; i++, RA+=8) // [C0..FF] NORMAL + { + for (int y=0; y<8; y++) + { + csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..." + } + } + + // alt char set + + RA = 0; + + for (i=0; i<256; i++, RA+=8) // [00..7F] INVERSE / [80..FF] NORMAL + { + for (int y=0; y<8; y++) + { + csbits[1][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..." + } + } +} + +void userVideoRom(void) +{ + const BYTE* pVideoRom; + UINT size = GetVideoRom(pVideoRom); // 4K or 8K + if (!size) + return; + + if (size == kVideoRomSize4K) + { + userVideoRom4K(&csbits_enhanced2e[0], pVideoRom); + return; + } + + userVideoRom4K(&csbits_enhanced2e_pal[0], pVideoRom); + userVideoRom4K(&csbits_enhanced2e[0], &pVideoRom[4*1024]); +} + +//------------------------------------- + void make_csbits(void) { get_csbits(&csbits_enhanced2e[0], TEXT("CHARSET40"), 0); // Enhanced //e: Alt char set off @@ -99,4 +186,15 @@ void make_csbits(void) // Original //e is just Enhanced //e with the 32 mousetext chars [0x40..0x5F] replaced by the non-alt charset chars [0x40..0x5F] memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e)); memcpy(&csbits_2e[1][64], &csbits_2e[0][64], 32*8); + + // Try to use any user-provided video ROM for Enhanced //e + userVideoRom(); +} + +csbits_t GetEnhanced2e_csbits(void) +{ + if (IsVideoRom4K()) + return csbits_enhanced2e; + + return GetVideoRomRockerSwitch() == false ? csbits_enhanced2e : csbits_enhanced2e_pal; } diff --git a/source/NTSC_CharSet.h b/source/NTSC_CharSet.h index 3f549059..465a2b51 100644 --- a/source/NTSC_CharSet.h +++ b/source/NTSC_CharSet.h @@ -2,7 +2,7 @@ typedef unsigned char (*csbits_t)[256][8]; -extern unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e +extern unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM) extern unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext) extern unsigned char csbits_a2[1][256][8]; // ][ and ][+ extern unsigned char csbits_pravets82[1][256][8]; // Pravets 82 @@ -10,3 +10,4 @@ extern unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M extern unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C void make_csbits(void); +csbits_t GetEnhanced2e_csbits(void); diff --git a/source/Video.cpp b/source/Video.cpp index d5663f3b..3d593218 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -647,7 +647,7 @@ void VideoResetState () //=========================================================================== -BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) +BYTE VideoSetMode(WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) { address &= 0xFF; @@ -1141,6 +1141,65 @@ static void Video_SaveScreenShot( const char *pScreenShotFileName, const VideoSc } } + +//=========================================================================== + +static const UINT kVideoRomSize8K = kVideoRomSize4K*2; +static const UINT kVideoRomSize16K = kVideoRomSize8K*2; +static const UINT kVideoRomSizeMax = kVideoRomSize16K; +static BYTE g_videoRom[kVideoRomSizeMax]; +static UINT g_videoRomSize = 0; +static bool g_videoRomRockerSwitch = false; + +bool ReadVideoRomFile(const char* pRomFile) +{ + g_videoRomSize = 0; + + HANDLE h = CreateFile(pRomFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + if (h == INVALID_HANDLE_VALUE) + return false; + + const ULONG size = GetFileSize(h, NULL); + if (size == kVideoRomSize4K || size == kVideoRomSize8K || size == kVideoRomSize16K) + { + DWORD bytesRead; + if (ReadFile(h, g_videoRom, size, &bytesRead, NULL) && bytesRead == size) + g_videoRomSize = size; + } + + if (g_videoRomSize == kVideoRomSize16K) + { + // Use top 8K (assume bottom 8K is all 0xFF's) + memcpy(&g_videoRom[0], &g_videoRom[kVideoRomSize8K], kVideoRomSize8K); + g_videoRomSize = kVideoRomSize8K; + } + + CloseHandle(h); + + return g_videoRomSize != 0; +} + +UINT GetVideoRom(const BYTE*& pVideoRom) +{ + pVideoRom = &g_videoRom[0]; + return g_videoRomSize; +} + +bool GetVideoRomRockerSwitch(void) +{ + return g_videoRomRockerSwitch; +} + +void SetVideoRomRockerSwitch(bool state) +{ + g_videoRomRockerSwitch = state; +} + +bool IsVideoRom4K(void) +{ + return g_videoRomSize == 0 || g_videoRomSize == kVideoRomSize4K; +} + //=========================================================================== void Config_Load_Video() @@ -1160,8 +1219,6 @@ void Config_Save_Video() REGSAVE(TEXT(REGVALUE_VIDEO_MONO_COLOR ),g_nMonochromeRGB); } -// ____________________________________________________________________ - //=========================================================================== static void videoCreateDIBSection() { diff --git a/source/Video.h b/source/Video.h index bd064502..301b503b 100644 --- a/source/Video.h +++ b/source/Video.h @@ -198,7 +198,14 @@ enum VideoScreenShot_e void Video_TakeScreenShot( VideoScreenShot_e iScreenShotType ); void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel ); -BYTE VideoSetMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); +BYTE VideoSetMode(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); + +const UINT kVideoRomSize4K = 4*1024; +bool ReadVideoRomFile(const char* pRomFile); +UINT GetVideoRom(const BYTE*& pVideoRom); +bool GetVideoRomRockerSwitch(void); +void SetVideoRomRockerSwitch(bool state); +bool IsVideoRom4K(void); void Config_Load_Video(void); void Config_Save_Video(void); From 6bf729922572ac4e4a19cb7b43ec7cf660f422df Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 17 Nov 2018 17:02:09 +0000 Subject: [PATCH 070/128] 1.27.12: Bump version & update History.txt + help --- bin/History.txt | 14 ++++++++++++++ help/CommandLine.html | 4 ++++ help/keyboard.html | 9 +++++---- resource/Applewin.rc | 8 ++++---- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 37886844..7dd8b0c0 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -9,6 +9,20 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.27.12.0 - 17 Nov 2018 +----------------------- +. [Change #574] Add support for PAL/European or custom 8K video ROMs: + - Added new command line switch: -videorom + - Replaces the video ROM for the Enhanced //e. + - Support video ROM sizes of 4K, 8K and 16K (top 8K only). + - NB. The rocker switch is set to the European video ROM position. + - F10 (for //e or Enhanced //e models) emulates the PAL //e's rocker switch (under the keyboard). + - Use to toggle between European or US video ROM. +. [Change #583] Added new switch: '-no-hook-alt': + - Used to prevent left/right ALT from emulating Open/Solid Apple keys. + - For European keyboards where AltGr is needed to type keys like '[',']'. + + 1.27.10.0 - 4 Nov 2018 ---------------------- . [Change #590] Apple II original: default to 48K (so no LC installed in slot-0). diff --git a/help/CommandLine.html b/help/CommandLine.html index 9b3ff70f..0eb15a2d 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -44,6 +44,8 @@ NB. This changes the display resolution (and restores on exit).

              -f8rom <rom-file>
              Use custom 2K ROM at [$F800..$FFFF]. <rom-file> must be 2048 bytes long

              + -videorom <file>
              + Use an alternate European or custom 4K, 8K or 16K video ROM.

              -printscreen
              Enable the dialog box to display the last file saved to

              -no-printscreen-key
              @@ -51,6 +53,8 @@ -no-hook-system-key
              Prevent certain system key combinations from being hooked (to prevent the emulator from trapping ALT+ESC, ALT+SPACE, ALT+TAB and CTRL+ESC). This means that the equivalent Open Apple+<key> combinations won't work within the emulator.
              NB. This switch takes precedence over -hook-alt-tab and -hook-altgr-control.

              + -no-hook-alt
              + Prevent the left and right ALT keys from being hooked (eg. to prevent emulation of Open/Solid Apple keys via the ALT keys).

              -hook-alt-tab
              By default the emulator doesn't hook ALT+TAB. Use this to allow Open Apple+TAB to be readable by the emulated machine.

              -hook-altgr-control
              diff --git a/help/keyboard.html b/help/keyboard.html index a228e2f1..10314837 100644 --- a/help/keyboard.html +++ b/help/keyboard.html @@ -86,10 +86,11 @@ through the configuration dialog.
              NB. Use Shift+F9 to reverse-cycle the display modes.

              Function Key F9 + Ctrl + Shift:
              This PC function key combo will toggle 50% scanline mode

              -

              Function Key F10 (or Ctrl+left mouse button):
              - This PC function key will stop emulating an Apple joystick with the PC's mouse.
              - In Pravets 8A emulation mode it servers as Caps Lock and Ctrl+F10 shall - be used to stop emulating an Apple joystick with the PC's mouse.

              +

              Function Key F10:
              + In //e or Enhanced //e emulation mode it will emulate the rocker switch for European video ROM selection. Use the Command Line switch to use an alternate European video ROM file.
              + In Pravets 8A emulation mode it servers as Caps Lock.

              +

              Function Key F10 + Ctrl (or Ctrl+left mouse button):
              + This PC function key combo will stop emulating an Apple joystick with the PC's mouse.

              Function Keys F11-F12:
              These PC function keys correspond to saving/loading a save-state file.

              diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 3262496d..9c20dd50 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,11,0 - PRODUCTVERSION 1,27,11,0 + FILEVERSION 1,27,12,0 + PRODUCTVERSION 1,27,12,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +271,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 11, 0" + VALUE "FileVersion", "1, 27, 12, 0" VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 11, 0" + VALUE "ProductVersion", "1, 27, 12, 0" END END BLOCK "VarFileInfo" From af899fa90acfd3ec2fde24146f9e7f2946c8c967 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 19 Nov 2018 22:15:04 +0000 Subject: [PATCH 071/128] Added support for Apple II/II+ 2K video ROMs (fixes #205) --- source/Applewin.cpp | 4 +-- source/NTSC_CharSet.cpp | 55 ++++++++++++++++++++++++++++++++++++++--- source/Video.cpp | 4 +-- source/Video.h | 3 ++- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 9d2fb161..411a0ec8 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1289,14 +1289,14 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800)) g_bCustomRomF8Failed = true; } - else if (strcmp(lpCmdLine, "-videorom") == 0) // Use 4K,8K or 16K video ROM for Enhanced //e + else if (strcmp(lpCmdLine, "-videorom") == 0) // Use 2K (for II/II+). Use 4K,8K or 16K video ROM (for Enhanced //e) { lpCmdLine = GetCurrArg(lpNextArg); lpNextArg = GetNextArg(lpNextArg); if (!ReadVideoRomFile(lpCmdLine)) { - std::string msg = "Failed to load video rom (not found or not exactly 4/8/16KiB)"; + std::string msg = "Failed to load video rom (not found or not exactly 2/4/8/16KiB)"; LogFileOutput("%s", msg.c_str()); MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); } diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp index 88d1250f..a150f26b 100644 --- a/source/NTSC_CharSet.cpp +++ b/source/NTSC_CharSet.cpp @@ -154,11 +154,11 @@ void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom) } } -void userVideoRom(void) +void userVideoRomForIIe(void) { const BYTE* pVideoRom; - UINT size = GetVideoRom(pVideoRom); // 4K or 8K - if (!size) + UINT size = GetVideoRom(pVideoRom); // 2K or 4K or 8K + if (size < kVideoRomSize4K) return; if (size == kVideoRomSize4K) @@ -173,6 +173,50 @@ void userVideoRom(void) //------------------------------------- +void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom) +{ + int RA = 0; // rom address + + for (int i=0; i<256; i++, RA+=8) + { + for (int y=0; y<8; y++) + { + BYTE d=0; + BYTE n = pVideoRom[RA+y]; + + // UTAII:8-30 "Bit 7 of your EPROM fonts will control flashing in the lower 1024 bytes of the EPROM" + // UTAII:8-31 "If you leave O7 (EPROM Output7) reset in these patterns, the resulting characters will be inversions..." + if (!(n & 0x80) && RA < 1024) + n = n ^ 0x7f; + n &= 0x7f; + + // UTAII:8-30 "TEXT ROM pattern is ... reversed" + for (BYTE j=0; j<7; j++) + { + if (n & 1) + d |= 1; + d <<= 1; + n >>= 1; + } + + d >>= 1; // Undo the last left shift + csbits[0][i][y] = d; + } + } +} + +void userVideoRomForIIPlus(void) +{ + const BYTE* pVideoRom; + UINT size = GetVideoRom(pVideoRom); // 2K or 4K or 8K + if (size != kVideoRomSize2K) + return; + + userVideoRom2K(&csbits_a2[0], pVideoRom); +} + +//------------------------------------- + void make_csbits(void) { get_csbits(&csbits_enhanced2e[0], TEXT("CHARSET40"), 0); // Enhanced //e: Alt char set off @@ -188,7 +232,10 @@ void make_csbits(void) memcpy(&csbits_2e[1][64], &csbits_2e[0][64], 32*8); // Try to use any user-provided video ROM for Enhanced //e - userVideoRom(); + userVideoRomForIIe(); + + // Try to use any user-provided video ROM for II/II+ + userVideoRomForIIPlus(); } csbits_t GetEnhanced2e_csbits(void) diff --git a/source/Video.cpp b/source/Video.cpp index 3d593218..c26b56e6 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -1160,7 +1160,7 @@ bool ReadVideoRomFile(const char* pRomFile) return false; const ULONG size = GetFileSize(h, NULL); - if (size == kVideoRomSize4K || size == kVideoRomSize8K || size == kVideoRomSize16K) + if (size == kVideoRomSize2K || size == kVideoRomSize4K || size == kVideoRomSize8K || size == kVideoRomSize16K) { DWORD bytesRead; if (ReadFile(h, g_videoRom, size, &bytesRead, NULL) && bytesRead == size) @@ -1197,7 +1197,7 @@ void SetVideoRomRockerSwitch(bool state) bool IsVideoRom4K(void) { - return g_videoRomSize == 0 || g_videoRomSize == kVideoRomSize4K; + return g_videoRomSize <= kVideoRomSize4K; } //=========================================================================== diff --git a/source/Video.h b/source/Video.h index 301b503b..2ab5d360 100644 --- a/source/Video.h +++ b/source/Video.h @@ -200,7 +200,8 @@ void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int n BYTE VideoSetMode(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); -const UINT kVideoRomSize4K = 4*1024; +const UINT kVideoRomSize2K = 1024*2; +const UINT kVideoRomSize4K = kVideoRomSize2K*2; bool ReadVideoRomFile(const char* pRomFile); UINT GetVideoRom(const BYTE*& pVideoRom); bool GetVideoRomRockerSwitch(void); From cbd41333c944bc427745feacc3c0563fcd0b29f4 Mon Sep 17 00:00:00 2001 From: tomcw Date: Wed, 21 Nov 2018 21:21:54 +0000 Subject: [PATCH 072/128] 2K ROM: refactor --- source/NTSC_CharSet.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp index a150f26b..a5d6c906 100644 --- a/source/NTSC_CharSet.cpp +++ b/source/NTSC_CharSet.cpp @@ -181,25 +181,18 @@ void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom) { for (int y=0; y<8; y++) { - BYTE d=0; BYTE n = pVideoRom[RA+y]; // UTAII:8-30 "Bit 7 of your EPROM fonts will control flashing in the lower 1024 bytes of the EPROM" // UTAII:8-31 "If you leave O7 (EPROM Output7) reset in these patterns, the resulting characters will be inversions..." if (!(n & 0x80) && RA < 1024) n = n ^ 0x7f; - n &= 0x7f; // UTAII:8-30 "TEXT ROM pattern is ... reversed" - for (BYTE j=0; j<7; j++) - { - if (n & 1) - d |= 1; - d <<= 1; - n >>= 1; - } + BYTE d = 0; + for (BYTE j=0; j<7; j++, n >>= 1) // Just bits [0..6] + d = (d << 1) | (n & 1); - d >>= 1; // Undo the last left shift csbits[0][i][y] = d; } } From 5504d280c7d1606c1cf64d26f6f06a200b5ca40c Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 3 Dec 2018 17:38:52 +0000 Subject: [PATCH 073/128] When drive is off then data register holds its present state. (Fixes #599) NB. Drive off = motor off && stopped spinning after 1 sec delay. --- source/Disk.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/source/Disk.cpp b/source/Disk.cpp index d3998ae7..06cb34dc 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -892,10 +892,14 @@ static void __stdcall DiskReadWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULO } } - // Should really test for drive off - after 1 second drive off delay (UTAIIe page 9-13) - // but Sherwood Forest sets shift mode and reads with the drive off, so don't check for now if (!floppywritemode) { + // Don't change latch if drive off after 1 second drive-off delay (UTAIIe page 9-13) + // "DRIVES OFF forces the data register to hold its present state." (UTAIIe page 9-12) + // Note: Sherwood Forest sets shift mode and reads with the drive off. + if (!pDrive->spinning) // GH#599 + return; + const ULONG nReadCycleDiff = (ULONG) (g_nCumulativeCycles - g_uDiskLastReadLatchCycle); // Support partial nibble read if disk reads are very close: (GH#582) @@ -954,10 +958,8 @@ static void __stdcall DiskReadWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULO if (++pFloppy->byte >= pFloppy->nibbles) pFloppy->byte = 0; - // Feature Request #201 Show track status - // https://github.com/AppleWin/AppleWin/issues/201 - // NB. Prevent flooding of forcing UI to redraw!!! - if( ((pFloppy->byte) & 0xFF) == 0 ) + // Show track status (GH#201) - NB. Prevent flooding of forcing UI to redraw!!! + if ((pFloppy->byte & 0xFF) == 0) FrameDrawDiskStatus( (HDC)0 ); } @@ -1052,11 +1054,16 @@ bool DiskSelect(const int iDrive) static void __stdcall DiskLoadWriteProtect(WORD, WORD, BYTE write, BYTE value, ULONG) { /* floppyloadmode = 1; */ + + // Don't change latch if drive off after 1 second drive-off delay (UTAIIe page 9-13) + // "DRIVES OFF forces the data register to hold its present state." (UTAIIe page 9-12) + // Note: Gemstone Warrior sets load mode with the drive off. + if (g_aFloppyDrive[currdrive].spinning) // GH#599 + return; + if (!write) { // Notes: - // . Should really test for drive off - after 1 second drive off delay (UTAIIe page 9-13) - // but Gemstone Warrior sets load mode with the drive off, so don't check for now // . Phase 1 on also forces write protect in the Disk II drive (UTAIIe page 9-7) but we don't implement that // . write mode doesn't prevent reading write protect (GH#537): // "If for some reason the above write protect check were entered with the READ/WRITE switch in WRITE, From 5ddff0d688e29e5d32b5ea025ca62dc1e158fe4c Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 3 Dec 2018 21:36:54 +0000 Subject: [PATCH 074/128] DiskII: read write protect - fix spinning test --- source/Disk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Disk.cpp b/source/Disk.cpp index 06cb34dc..b07f16ab 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -1058,7 +1058,7 @@ static void __stdcall DiskLoadWriteProtect(WORD, WORD, BYTE write, BYTE value, U // Don't change latch if drive off after 1 second drive-off delay (UTAIIe page 9-13) // "DRIVES OFF forces the data register to hold its present state." (UTAIIe page 9-12) // Note: Gemstone Warrior sets load mode with the drive off. - if (g_aFloppyDrive[currdrive].spinning) // GH#599 + if (!g_aFloppyDrive[currdrive].spinning) // GH#599 return; if (!write) From 54fffdf25a978c33faf4e62557b0d67d125bc912 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 8 Dec 2018 13:29:48 +0000 Subject: [PATCH 075/128] 1.27.13: Bump version & update History.txt + help --- AppleWinExpress2008.vcproj | 4 ++++ bin/History.txt | 9 ++++++++- help/CommandLine.html | 14 ++++++++------ help/dbg-screen-layout.html | 4 ++-- help/savestate.html | 3 +++ resource/Applewin.rc | 9 +++++---- resource/version.h | 5 +++++ source/Applewin.cpp | 4 ++-- 8 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 resource/version.h diff --git a/AppleWinExpress2008.vcproj b/AppleWinExpress2008.vcproj index 1b926246..ccc80c1f 100644 --- a/AppleWinExpress2008.vcproj +++ b/AppleWinExpress2008.vcproj @@ -1285,6 +1285,10 @@ RelativePath=".\resource\TKClock.rom" >
              + + diff --git a/bin/History.txt b/bin/History.txt index 7dd8b0c0..f4a9a2a7 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -8,10 +8,17 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.27.13.0 - 8 Dec 2018 +---------------------- +. [Bug #599] Fix for Ultima V not loading in Authentic Speed mode (regression introduced at 1.27.9.0). +. [Change #205] Added support for Apple II/II+ custom 2K video ROMs. + - Extended command line switch: -videorom + - If the ROM sizs is 2K, then it replaces the video ROM for the Apple II/II+. + 1.27.12.0 - 17 Nov 2018 ----------------------- -. [Change #574] Add support for PAL/European or custom 8K video ROMs: +. [Change #574] Added support for PAL/European or custom 8K video ROMs: - Added new command line switch: -videorom - Replaces the video ROM for the Enhanced //e. - Support video ROM sizes of 4K, 8K and 16K (top 8K only). diff --git a/help/CommandLine.html b/help/CommandLine.html index 0eb15a2d..1d265e69 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -20,16 +20,16 @@ -h2 <pathname>
              Start with hard disk 2 plugged-in. NB. Hard disk controller card gets enabled.

              -s0 <saturn|saturn64|saturn128>
              - Insert a Saturn 64K or Saturn 128K card into slot 0 in Apple II or Apple II+ machines (or similar clone).
              + Insert a Saturn 64K or Saturn 128K card into slot 0 in the Apple II or II+ machines (or similar clone).
              Where -s0 saturn is an alias for -s0 saturn128.

              -s0 <languagecard|lc>
              - Insert an Apple 16K Language Card into slot 0 in Apple II and use the F8 auto-start ROM.
              + Insert an Apple 16K Language Card into slot 0 in the original Apple II and use the F8 auto-start ROM.
              NB. The Apple II+ already defaults to having a Language Card, so this switch is not required.

              -s7 empty
              Remove the hard disk controller card from slot 7.
              Useful to allow a floppy disk to boot from slot 6, drive 1. Use in combination with -d1.

              -r <number of pages>
              - Emulate a RAMworks III card with 1 to 127 pages (each page is 64K, giving a max of 8MB) in the auxiliary slot in an Apple //e machine.

              + Emulate a RamWorks III card with 1 to 127 pages (each page is 64K, giving a max of 8MB) in the auxiliary slot in an Apple //e machine.

              -load-state <savestate>
              Load a save-state file
              NB. This takes precedent over the -d1,d2,h1,h2,s0,s7 and -r switches.

              @@ -42,10 +42,12 @@
            • nnnn: select a specific resolution with height=nnnn pixels
            NB. This changes the display resolution (and restores on exit).

            - -f8rom <rom-file>
            - Use custom 2K ROM at [$F800..$FFFF]. <rom-file> must be 2048 bytes long

            + -f8rom <file>
            + Use custom 2K ROM for any Apple II machine at [$F800..$FFFF]. <file> must be 2048 bytes long

            -videorom <file>
            - Use an alternate European or custom 4K, 8K or 16K video ROM.

            + Use an alternate custom 2K video ROM for Apple II or II+ machines (but not clones).
            + Use an alternate European or custom 4K, 8K or 16K (top 8K only) video ROM for the Enhanced //e.
            + NB. There's currently no support for using an alternate video ROM for the original Apple //e or clones.

            -printscreen
            Enable the dialog box to display the last file saved to

            -no-printscreen-key
            diff --git a/help/dbg-screen-layout.html b/help/dbg-screen-layout.html index f3dc010e..e46abe6f 100644 --- a/help/dbg-screen-layout.html +++ b/help/dbg-screen-layout.html @@ -38,14 +38,14 @@
          • 0C: $C00C - Col40/80 (inverse indicates state of 80COL)
          • 0E: $C00E - ASC/MOUS (inverse indicates state of ALTCHARSET)
          • 80: $C080-C087: B2/M R/W (Language Card Bank2) -
          • 88: $C088-C08F: B1/M rNN (Language Card Bank1 and RAMworks 64K bank number) +
          • 88: $C088-C08F: B1/M rNN (Language Card Bank1 and RamWorks 64K bank number)
            • 'B2' or 'B1' is inverse when that LC bank is enabled.
            • If 'M' is inverse: ROM is active for reading.
            • If 'M' is not inverse: LC2 or LC1 RAM is active.
            • If 'W' is inverse: RAM is write enabled.
            • If 'W' is not inverse: RAM is write protected. -
            • 'rNN' will appear if a RAMworks 64K bank is active. +
            • 'rNN' will appear if a RamWorks 64K bank is active.
            • 'sNN' will appear if a Saturn 16K bank is active.
          diff --git a/help/savestate.html b/help/savestate.html index c98e7a32..6cbef20b 100644 --- a/help/savestate.html +++ b/help/savestate.html @@ -37,6 +37,9 @@
        • Uthernet card
        • SAM card
        • No-Slot clock (there's nothing to persist)
        • +
        • Using The Freeze's F8 ROM
        • +
        • Alternate F8 ROM
        • +
        • Alternate video ROM

        Note: Only the file names of the disk images are stored in the .yaml file (not the full path). This allows you to move your disk image around or distribute them. diff --git a/resource/Applewin.rc b/resource/Applewin.rc index 9c20dd50..ffcc230e 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -1,6 +1,7 @@ // Microsoft Visual C++ generated resource script. // #include "resource.h" +#include "version.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -252,8 +253,8 @@ DISK_ICON ICON "DISK.ICO" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,27,12,0 - PRODUCTVERSION 1,27,12,0 + FILEVERSION APPLEWIN_VERSION + PRODUCTVERSION APPLEWIN_VERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -271,12 +272,12 @@ BEGIN VALUE "Comments", "https://github.com/AppleWin" VALUE "CompanyName", "AppleWin" VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 27, 12, 0" + VALUE "FileVersion", APPLEWIN_VERSION_STR VALUE "InternalName", "APPLEWIN" VALUE "LegalCopyright", " 1994-2018 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, 27, 12, 0" + VALUE "ProductVersion", APPLEWIN_VERSION_STR END END BLOCK "VarFileInfo" diff --git a/resource/version.h b/resource/version.h new file mode 100644 index 00000000..ba6ac1b3 --- /dev/null +++ b/resource/version.h @@ -0,0 +1,5 @@ +#define APPLEWIN_VERSION 1,27,13,0 + +#define xstr(a) str(a) +#define str(a) #a +#define APPLEWIN_VERSION_STR xstr(APPLEWIN_VERSION) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 411a0ec8..a63fbb39 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1296,7 +1296,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (!ReadVideoRomFile(lpCmdLine)) { - std::string msg = "Failed to load video rom (not found or not exactly 2/4/8/16KiB)"; + std::string msg = "Failed to load video rom (not found or not exactly 2/4/8/16KiB)\n"; LogFileOutput("%s", msg.c_str()); MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); } @@ -1569,7 +1569,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (g_bCustomRomF8Failed) { - std::string msg = "Failed to load custom F8 rom (not found or not exactly 2KiB)"; + std::string msg = "Failed to load custom F8 rom (not found or not exactly 2KiB)\n"; LogFileOutput("%s", msg.c_str()); MessageBox(g_hFrameWindow, msg.c_str(), TEXT("AppleWin Error"), MB_OK); bShutdown = true; From 7e2f53b62cde2e4e8af2cc592dbd3545e4fa39a6 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 8 Dec 2018 13:36:52 +0000 Subject: [PATCH 076/128] History.txt: fixed typo --- bin/History.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/History.txt b/bin/History.txt index f4a9a2a7..58c2d73d 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -13,7 +13,7 @@ Tom Charlesworth . [Bug #599] Fix for Ultima V not loading in Authentic Speed mode (regression introduced at 1.27.9.0). . [Change #205] Added support for Apple II/II+ custom 2K video ROMs. - Extended command line switch: -videorom - - If the ROM sizs is 2K, then it replaces the video ROM for the Apple II/II+. + - If the ROM size is 2K, then it replaces the video ROM for the Apple II/II+. 1.27.12.0 - 17 Nov 2018 From d0f03fc90c71dfa5ed498bc1fa2aec567afa0297 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 9 Dec 2018 10:05:46 +0000 Subject: [PATCH 077/128] Removed CTRL+F10 functionality to reveal mouse cursor (fixes #597) --- help/keyboard.html | 9 ++++----- source/Frame.cpp | 6 +----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/help/keyboard.html b/help/keyboard.html index 10314837..26d75449 100644 --- a/help/keyboard.html +++ b/help/keyboard.html @@ -74,6 +74,8 @@ Copy the text screen (auto detect 40/80 columns) to the clipboard.

        Alt+Enter:
        Default: Toggle between windowed and full screen video modes. (NB. Will conflict with emulation and prevent Open Apple + Enter from being readable. Use the Command Line switch to allow Open Apple + Enter to be readable.)

        +

        Ctrl+Left Mouse Button:
        + This will show the Windows mouse cursor when emulating an Apple joystick with the PC's mouse or using a Mouse card.

        Function Keys F1-F8:
        These PC function keys correspond to buttons on the toolbar.

        Function Key F2 + Ctrl:
        @@ -89,9 +91,6 @@

        Function Key F10:
        In //e or Enhanced //e emulation mode it will emulate the rocker switch for European video ROM selection. Use the Command Line switch to use an alternate European video ROM file.
        In Pravets 8A emulation mode it servers as Caps Lock.

        -

        Function Key F10 + Ctrl (or Ctrl+left mouse button):
        - This PC function key combo will stop emulating an Apple joystick with the PC's mouse.
        -

        Function Keys F11-F12:
        - These PC function keys correspond to saving/loading a save-state - file.

        +

        Function Keys F11-F12:
        + These PC function keys correspond to saving/loading a save-state file.

        \ No newline at end of file diff --git a/source/Frame.cpp b/source/Frame.cpp index de139893..b1312d94 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1316,11 +1316,7 @@ LRESULT CALLBACK FrameWndProc ( } else if (wparam == VK_F10) { - if (KeybGetCtrlStatus()) - { - SetUsingCursor(FALSE); // Ctrl+F10 - } - else if (g_Apple2Type == A2TYPE_APPLE2E || g_Apple2Type == A2TYPE_APPLE2EENHANCED) + if (g_Apple2Type == A2TYPE_APPLE2E || g_Apple2Type == A2TYPE_APPLE2EENHANCED) { SetVideoRomRockerSwitch( !GetVideoRomRockerSwitch() ); // F10: toggle rocker switch NTSC_VideoInitAppleType(); From b17f880e6d9b423ac154b1869d35dacd6453d147 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 9 Dec 2018 11:48:22 +0000 Subject: [PATCH 078/128] HDD: Added a swap HDD function to the Config->Disk UI (#585) --- help/cfg-disk.html | 34 ++++++++---------- help/ddi-harddisk.html | 8 ++--- help/img/disk.png | Bin 34265 -> 35119 bytes resource/Applewin.rc | 1 + resource/resource.h | 1 + source/Configuration/PageDisk.cpp | 56 +++++++++++++++++++++--------- source/Configuration/PageDisk.h | 2 ++ source/Harddisk.cpp | 12 +++++++ source/Harddisk.h | 1 + 9 files changed, 74 insertions(+), 41 deletions(-) diff --git a/help/cfg-disk.html b/help/cfg-disk.html index 96dc370c..67df107c 100644 --- a/help/cfg-disk.html +++ b/help/cfg-disk.html @@ -1,23 +1,13 @@ - - - - - Disk Settings - - - -

        Disk Settings

        - -
        Disk settings +

        Floppy Controller Settings:

        Disk Access Speed:
        Here you can choose the speed at which the system can access @@ -26,14 +16,14 @@ By default, you would want "Enhanced Speed" so that data can be accessed as fast as possible. However, it is also possible that certain programs might depend on the "Authentic Speed" to function properly. This is the speed at which the real hardware -would access data from your drives.

        - +would access data from your drives. +

        Disk 1/2 drop-down menus:
        - These menus allow you to select floppy disk images (.dsk files) to 'insert' into the -emulated floppy drives 1 and 2. This can also be done during emulation by using the toolbar or using the F3/F4 keys. Diskettes can be swapped by pressing F5 during emulation. You can also eject images from this menu.

        +emulated floppy drives 1 and 2. This can also be done during emulation by using the toolbar or using the F3/F4 keys. Diskettes can be swapped by pressing F5 during emulation. You can also eject images from this menu. +

        Hard disk Controller Settings:

        @@ -42,16 +32,20 @@ A hard disk controller (or interface) card can be plugged in to slot 7 by checki See Hard disk Images for more details.

        +

        Swap:
        +Swap the hard disk images.
        +WARNING! If done during image access this could result in undefined behavior (eg. Apple II program crash) or data corruption on the image. +

        +

        HDD 1/2 drop-down menus:
        - These menus allow you to select hard disk images (eg. .hdv files) to -connect to the emulated hard disk controller card. You can also unplug images from this menu.

        - - -Path to CiderPress:
        +connect to the emulated hard disk controller card. You can also unplug images from this menu. +

        +

        Path to CiderPress:
        Use this to specify where CiderPress is installed.
        The right mouse button context menu on either of the drive icons allows you to open CiderPress with the image in the drive. +

        diff --git a/help/ddi-harddisk.html b/help/ddi-harddisk.html index a1d579ed..046583de 100644 --- a/help/ddi-harddisk.html +++ b/help/ddi-harddisk.html @@ -3,7 +3,7 @@ - Transferring Disk Images + Hard Disk Images @@ -20,8 +20,9 @@ Just check Enable hard disk controller in slot 7.

        There is provision to connect two hard disks to this card. -This is done by using .hdv files on your PC. +This is done by using .hdv or 800KB .2mg files on your PC. Each hard disk can have a maximum capacity of 32MB.

        +NB. The hard disk controller supports both fixed-disk types (up to 32MB) and 3.5" floppy types (800KB).

        On booting, the Apple will always attempt to @@ -33,9 +34,6 @@ interface card in it).

        To boot a floppy disk with the hard disk card enabled, either hold down the Open-Apple key during an Apple II restart or issue PR#6 from an AppleSoft prompt.

        -

        You can download sample .hdv -images from Asimov (eg. ftp://public.asimov.net/pub/apple_II/images/utility/misc/hardpc.zip).

        -

        Warnings:

        + -rgb-card-invert-bit7
        + Force the RGB card (in "Color (RGB Monitor)" video mode) to invert bit7 in MIX mode. Enables the correct rendering for Dragon Wars.

        Debug arguments:

        -l or -log
        - Enable logging. Creates an AppleWin.log file

        + Enable logging. Creates an AppleWin.log file.

        -m
        - Disable DirectSound support

        + Disable DirectSound support.

        -no-printscreen-dlg
        - Suppress the warning message-box if AppleWin fails to capture the PrintScreen key

        + Suppress the warning message-box if AppleWin fails to capture the PrintScreen key.

        + -screenshot-and-exit
        + For testing. Use in combination with -load-state.

        diff --git a/resource/version.h b/resource/version.h index ec8ebb7a..4b56dec7 100644 --- a/resource/version.h +++ b/resource/version.h @@ -1,4 +1,4 @@ -#define APPLEWIN_VERSION 1,28,4,0 +#define APPLEWIN_VERSION 1,28,5,0 #define xstr(a) str(a) #define str(a) #a diff --git a/source/Applewin.cpp b/source/Applewin.cpp index a69a138a..4cf53765 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -53,6 +53,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Speech.h" #endif #include "Video.h" +#include "RGBMonitor.h" #include "NTSC.h" #include "Configuration/About.h" @@ -1416,6 +1417,10 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { newVideoStyleDisableMask = VS_COLOR_VERTICAL_BLEND; } + else if (strcmp(lpCmdLine, "-rgb-card-invert-bit7") == 0) // GH#633 + { + RGB_SetInvertBit7(true); + } else if (strcmp(lpCmdLine, "-screenshot-and-exit") == 0) // GH#616: For testing - Use in combination with -load-state { szScreenshotFilename = GetCurrArg(lpNextArg); diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 186e3ba5..fe7b7c82 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -1378,7 +1378,7 @@ void updateScreenDoubleHires80Simplified (long cycles6502 ) // wsUpdateVideoDblH uint8_t a = *MemGetAuxPtr(addr); uint8_t m = *MemGetMainPtr(addr); - if (RGB_IsMixMode() && !MemGetAnnunciator(2)) // AN2 inverts high bit? (GH#633) + if (RGB_IsMixModeInvertBit7()) // Invert high bit? (GH#633) { a ^= 0x80; m ^= 0x80; diff --git a/source/RGBMonitor.cpp b/source/RGBMonitor.cpp index 93a8a0db..3312b3a6 100644 --- a/source/RGBMonitor.cpp +++ b/source/RGBMonitor.cpp @@ -739,6 +739,7 @@ static UINT g_rgbFlags = 0; static UINT g_rgbMode = 0; static WORD g_rgbPrevAN3Addr = 0; static bool g_rgbSet80COL = false; +static bool g_rgbInvertBit7 = false; // Video7 RGB card: // . Clock in the !80COL state to define the 2 flags: F2, F1 @@ -801,6 +802,11 @@ bool RGB_Is560Mode(void) // Extended 80-Column Text/AppleColor Card's Mode 1 return g_rgbMode == 3; } +bool RGB_IsMixModeInvertBit7(void) +{ + return RGB_IsMixMode() && g_rgbInvertBit7; +} + void RGB_ResetState(void) { g_rgbFlags = 0; @@ -808,6 +814,11 @@ void RGB_ResetState(void) g_rgbPrevAN3Addr = 0; } +void RGB_SetInvertBit7(bool state) +{ + g_rgbInvertBit7 = state; +} + //=========================================================================== #define SS_YAML_KEY_RGB_CARD "AppleColor RGB Adaptor" @@ -817,6 +828,7 @@ void RGB_ResetState(void) #define SS_YAML_KEY_RGB_MODE "RGB mode" #define SS_YAML_KEY_RGB_PREVIOUS_AN3 "Previous AN3" #define SS_YAML_KEY_RGB_80COL_CHANGED "80COL changed" +#define SS_YAML_KEY_RGB_INVERT_BIT7 "Invert bit7" void RGB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper) { @@ -826,6 +838,7 @@ void RGB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper) yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_RGB_MODE, g_rgbMode); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_RGB_PREVIOUS_AN3, g_rgbPrevAN3Addr); yamlSaveHelper.SaveBool(SS_YAML_KEY_RGB_80COL_CHANGED, g_rgbSet80COL); + yamlSaveHelper.SaveBool(SS_YAML_KEY_RGB_INVERT_BIT7, g_rgbInvertBit7); } void RGB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT cardVersion) @@ -838,7 +851,10 @@ void RGB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT cardVersion) g_rgbPrevAN3Addr = yamlLoadHelper.LoadUint(SS_YAML_KEY_RGB_PREVIOUS_AN3); if (cardVersion >= 3) + { g_rgbSet80COL = yamlLoadHelper.LoadBool(SS_YAML_KEY_RGB_80COL_CHANGED); + g_rgbInvertBit7 = yamlLoadHelper.LoadBool(SS_YAML_KEY_RGB_INVERT_BIT7); + } yamlLoadHelper.PopMap(); } diff --git a/source/RGBMonitor.h b/source/RGBMonitor.h index b6b26ab7..14cb72c0 100644 --- a/source/RGBMonitor.h +++ b/source/RGBMonitor.h @@ -13,7 +13,9 @@ bool RGB_Is140Mode(void); bool RGB_Is160Mode(void); bool RGB_IsMixMode(void); bool RGB_Is560Mode(void); +bool RGB_IsMixModeInvertBit7(void); void RGB_ResetState(void); +void RGB_SetInvertBit7(bool state); void RGB_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void RGB_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT cardVersion); From adcfb9ef3d346ca22de09b5b367bf63257c3b826 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 6 Apr 2019 18:23:42 +0100 Subject: [PATCH 126/128] Fix reads to $C07X to return floating bus (broke at 7c95c0f6c4) --- source/Joystick.cpp | 4 +--- source/Joystick.h | 2 +- source/Memory.cpp | 10 +++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/source/Joystick.cpp b/source/Joystick.cpp index 30e77c23..a7edb82a 100644 --- a/source/Joystick.cpp +++ b/source/Joystick.cpp @@ -643,7 +643,7 @@ void JoyReset() } //=========================================================================== -BYTE __stdcall JoyResetPosition(WORD, WORD, BYTE, BYTE, ULONG nExecutedCycles) +void JoyResetPosition(ULONG nExecutedCycles) { CpuCalcCycles(nExecutedCycles); g_nJoyCntrResetCycle = g_nCumulativeCycles; @@ -652,8 +652,6 @@ BYTE __stdcall JoyResetPosition(WORD, WORD, BYTE, BYTE, ULONG nExecutedCycles) CheckJoystick0(); if((joyinfo[joytype[1]] == DEVICE_JOYSTICK) || (joyinfo[joytype[1]] == DEVICE_JOYSTICK_THUMBSTICK2)) CheckJoystick1(); - - return MemReadFloatingBus(nExecutedCycles); } //=========================================================================== diff --git a/source/Joystick.h b/source/Joystick.h index 09f322c9..668d650a 100644 --- a/source/Joystick.h +++ b/source/Joystick.h @@ -30,4 +30,4 @@ void JoyLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); BYTE __stdcall JoyReadPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); -BYTE __stdcall JoyResetPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); +void JoyResetPosition(ULONG nExecutedCycles); diff --git a/source/Memory.cpp b/source/Memory.cpp index 5c551104..5457e991 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -552,12 +552,12 @@ static BYTE __stdcall IOWrite_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON static BYTE __stdcall IORead_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles) { - // Apple//e TRM, pg-258: "Reading or writing any address in the range $C070-$C07F also triggers the paddle time and resets the VBLINT(*)." (*) //c only! - JoyResetPosition(pc, addr, bWrite, d, nExecutedCycles); //$C07X Analog input reset + // Apple//e TRM, pg-258: "Reading or writing any address in the range $C070-$C07F also triggers the paddle timer and resets the VBLINT(*)." (*) //c only! + JoyResetPosition(nExecutedCycles); //$C07X Analog input reset switch (addr & 0xf) { - case 0x0: break; + case 0x0: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); case 0x1: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); case 0x2: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); case 0x3: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); @@ -582,8 +582,8 @@ static BYTE __stdcall IORead_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG static BYTE __stdcall IOWrite_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles) { - // Apple//e TRM, pg-258: "Reading or writing any address in the range $C070-$C07F also triggers the paddle time and resets the VBLINT(*)." (*) //c only! - JoyResetPosition(pc, addr, bWrite, d, nExecutedCycles); //$C07X Analog input reset + // Apple//e TRM, pg-258: "Reading or writing any address in the range $C070-$C07F also triggers the paddle timer and resets the VBLINT(*)." (*) //c only! + JoyResetPosition(nExecutedCycles); //$C07X Analog input reset switch (addr & 0xf) { From 4db23c10dc980d8251d3e67f689cb5dd0984e7cc Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 6 Apr 2019 18:56:00 +0100 Subject: [PATCH 127/128] Fixed typo & inconsistency in $C070 write statement --- bin/History.txt | 2 +- source/Memory.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 4578fb44..899d480e 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -13,7 +13,7 @@ Tom Charlesworth --------------------- . [Change #631] Improvements for the RGB AppleColor card: - Relax the video-mode precondition to just ignore if VF_MIXED (previously required HIRES on) for Apple II Desktop. - - Changing from DHGR B&W mode to HGR remains in B&W (color burst if off). + - Changing from DHGR B&W mode to HGR remains in B&W (color burst is off). - For '50% scan lines', don't blend in NTSC B&W mode, as this was inconsistent with the RGB colour rendering. . [Change #633] Improvements for the RGB AppleColor card: - Improved the video-mode precondition to ignore if 80COL ($C00C/D) occurs before DHIRESON ($C05F) for Renegade. diff --git a/source/Memory.cpp b/source/Memory.cpp index 5457e991..b91a7c58 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -587,7 +587,7 @@ static BYTE __stdcall IOWrite_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON switch (addr & 0xf) { - case 0x0: break; + case 0x0: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); #ifdef RAMWORKS case 0x1: return MemSetPaging(pc, addr, bWrite, d, nExecutedCycles); // extended memory card set page case 0x2: return IO_Null(pc, addr, bWrite, d, nExecutedCycles); From 78c9d893577eac2c0d11e976ef673668dd928706 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 7 Apr 2019 08:55:55 +0100 Subject: [PATCH 128/128] Help-troubleshooting: Added new item about issue with AltGr on international keyboards --- help/Troubleshooting.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/help/Troubleshooting.html b/help/Troubleshooting.html index 30130c11..91f4be35 100644 --- a/help/Troubleshooting.html +++ b/help/Troubleshooting.html @@ -27,5 +27,23 @@
    + + When using a non-US (or UK) keyboard, certain keys can't be typed. +
      +
    • AltGr (or right Alt) needs to be used to type certain keys, eg: +
        +
      • '@' is AltGr+2 (for a Canadian-French keyboard).
      • +
      • '[' is AltGr+é (for an Italian keyboard).
      • +
      +
    • Some games or productivity software have an action based on the Open Apple (Alt) or Solid Apple (AltGr) keys, eg: +
        +
      • Lode Runner uses CTRL+@ to increase the lives.
      • +
      • AppleLogo // and AppleWorks 5.1 have problems when using an Italian keyboard.
      • +
      +
    • This dual function for AltGr (to both type a key and emulate Solid Apple) can cause problems such that the key (eg. '@') can never be typed. +
    • The workaround is to use the `-no-hook-alt` command line switch and configure Joystick 1 = "Keyboard (numpad)"; and then use the '0' and '.' keys for Open/Solid Apple. +
    • +
    +