From eed3182befe27fa1e539a49c083264c70b3fe117 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 25 May 2020 20:21:36 +0100 Subject: [PATCH 01/15] Fixed cmd line regressions: (#790) . -s7-empty-on-exit wasn't being recognised . -d1, -d2 weren't saving the 'Last Disk Image 1/2' & 'Starting Directory' --- source/Applewin.cpp | 24 ++++++++++-------------- source/CardManager.cpp | 4 ++-- source/Disk.cpp | 7 ++++--- source/Disk.h | 2 +- source/MouseInterface.cpp | 1 + source/SerialComms.cpp | 7 +++---- source/SerialComms.h | 2 +- 7 files changed, 22 insertions(+), 25 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 39d2b079..50544668 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1211,11 +1211,9 @@ static void InsertHardDisks(LPSTR szImageName_harddisk[NUM_HARDDISKS], bool& bBo HD_SetEnabled(true); DWORD dwTmp; - if (REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp)) - { - if (!dwTmp) - REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 1); // Config: HDD Enabled - } + BOOL res = REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp); + if (!res || !dwTmp) + REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 1); // Config: HDD Enabled // @@ -1244,11 +1242,9 @@ static void UnplugHardDiskControllerCard(void) HD_SetEnabled(false); DWORD dwTmp; - if (REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp)) - { - if (dwTmp) - REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 0); // Config: HDD Disabled - } + BOOL res = REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp); + if (!res || dwTmp) + REGSAVE(TEXT(REGVALUE_HDD_ENABLED), 0); // Config: HDD Disabled } static bool CheckOldAppleWinVersion(void) @@ -1504,15 +1500,15 @@ static bool ProcessCmdLine(LPSTR lpCmdLine) g_cmdLine.szImageName_drive[slot][drive] = lpCmdLine; } } + else if (strcmp(lpCmdLine, "-s7-empty-on-exit") == 0) + { + g_cmdLine.bSlot7EmptyOnExit = true; + } else { LogFileOutput("Unsupported arg: %s\n", lpCmdLine); } } - else if (strcmp(lpCmdLine, "-s7-empty-on-exit") == 0) - { - g_cmdLine.bSlot7EmptyOnExit = true; - } else if (strcmp(lpCmdLine, "-load-state") == 0) { lpCmdLine = GetCurrArg(lpNextArg); diff --git a/source/CardManager.cpp b/source/CardManager.cpp index f5b17f27..9e0a96f6 100644 --- a/source/CardManager.cpp +++ b/source/CardManager.cpp @@ -46,12 +46,12 @@ void CardManager::Insert(UINT slot, SS_CARDTYPE type) switch (type) { case CT_Disk2: - m_slot[slot] = new Disk2InterfaceCard; + m_slot[slot] = new Disk2InterfaceCard(slot); break; case CT_SSC: _ASSERT(m_pSSC == NULL); if (m_pSSC) break; // Only support one SSC - m_slot[slot] = m_pSSC = new CSuperSerialCard; + m_slot[slot] = m_pSSC = new CSuperSerialCard(slot); break; case CT_MockingboardC: m_slot[slot] = new DummyCard(type); diff --git a/source/Disk.cpp b/source/Disk.cpp index b0ddb704..1df0ea2e 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -53,14 +53,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // . if false && I/O ReadWrite($C0EC) && drive is spinning, then advance the track buffer's nibble index (to simulate spinning). // Also m_enhanceDisk is persisted to the save-state, so it's an attribute of the DiskII interface card. -Disk2InterfaceCard::Disk2InterfaceCard(void) : - Card(CT_Disk2) +Disk2InterfaceCard::Disk2InterfaceCard(UINT slot) : + Card(CT_Disk2), + m_slot(slot) { ResetSwitches(); m_floppyLatch = 0; m_saveDiskImage = true; // Save the DiskImage name to Registry - m_slot = 0; m_diskLastCycle = 0; m_diskLastReadLatchCycle = 0; m_enhanceDisk = true; @@ -1770,6 +1770,7 @@ void Disk2InterfaceCard::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot) // . Patching the firmware breaks the ADC checksum used by "The CIA Files" (Tricky Dick) // . In this case we can patch to compensate for an ADC or EOR checksum but not both (nickw) + _ASSERT(m_slot == uSlot); RegisterIoHandler(uSlot, &Disk2InterfaceCard::IORead, &Disk2InterfaceCard::IOWrite, NULL, NULL, this, NULL); m_slot = uSlot; diff --git a/source/Disk.h b/source/Disk.h index f61f8bf7..b3070e1f 100644 --- a/source/Disk.h +++ b/source/Disk.h @@ -120,7 +120,7 @@ public: class Disk2InterfaceCard : public Card { public: - Disk2InterfaceCard(void); + Disk2InterfaceCard(UINT slot); virtual ~Disk2InterfaceCard(void); virtual void Init(void) {}; diff --git a/source/MouseInterface.cpp b/source/MouseInterface.cpp index 41782b6f..3f15dda2 100644 --- a/source/MouseInterface.cpp +++ b/source/MouseInterface.cpp @@ -181,6 +181,7 @@ void CMouseInterface::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot) { // m_bActive = true; m_bEnabled = true; + _ASSERT(m_uSlot == uSlot); SetSlotRom(); // Pre: m_bActive == true RegisterIoHandler(uSlot, &CMouseInterface::IORead, &CMouseInterface::IOWrite, NULL, NULL, this, NULL); } diff --git a/source/SerialComms.cpp b/source/SerialComms.cpp index a47f72f3..b07d18ab 100644 --- a/source/SerialComms.cpp +++ b/source/SerialComms.cpp @@ -64,9 +64,9 @@ SSC_DIPSW CSuperSerialCard::m_DIPSWDefault = //=========================================================================== -CSuperSerialCard::CSuperSerialCard() : +CSuperSerialCard::CSuperSerialCard(UINT slot) : Card(CT_SSC), - m_uSlot(0), + m_uSlot(slot), m_aySerialPortChoices(NULL), m_uTCPChoiceItemIdx(0), m_bCfgSupportDCD(false), @@ -957,10 +957,9 @@ void CSuperSerialCard::CommInitialize(LPBYTE pCxRomPeripheral, UINT uSlot) if(pData == NULL) return; + _ASSERT(m_uSlot == uSlot); memcpy(pCxRomPeripheral + uSlot*256, pData+SSC_SLOT_FW_OFFSET, SSC_SLOT_FW_SIZE); - m_uSlot = uSlot; - // Expansion ROM if (m_pExpansionRom == NULL) { diff --git a/source/SerialComms.h b/source/SerialComms.h index 318182cb..d2a244d2 100644 --- a/source/SerialComms.h +++ b/source/SerialComms.h @@ -25,7 +25,7 @@ typedef struct class CSuperSerialCard : public Card { public: - CSuperSerialCard(); + CSuperSerialCard(UINT slot); virtual ~CSuperSerialCard(); virtual void Init(void) {}; From b132b0d0a8810ac9dbf1ad1d93b945ffea334f30 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 26 May 2020 21:37:56 +0100 Subject: [PATCH 02/15] Added cmd line switch: -power-on --- help/CommandLine.html | 7 +++++-- source/Applewin.cpp | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/help/CommandLine.html b/help/CommandLine.html index ec9bb067..e1d97152 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -55,7 +55,7 @@ -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.

-load-state <savestate>
- Load a save-state file
+ Load a save-state file (and auto power-on the Apple II).
NB. This takes precedent over the -d1, -d2, -d#s#, -h1, -h2, s0-7, -model and -r switches.

-f
Start in full-screen mode

@@ -138,7 +138,10 @@ -50hz
Support 50Hz(PAL) video refresh rate and PAL 1.016MHz base CPU clock.

-60hz
- Support 60Hz(NTSC) video refresh rate and NTSC 1.020MHz base CPU clock (default).
+ Support 60Hz(NTSC) video refresh rate and NTSC 1.020MHz base CPU clock (default).

+ -power-on
+ Force a power-on.
+ Use to auto power-on when not using -d1, -h1 or -load-state.

Debug arguments: diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 50544668..f5f1b05c 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1769,6 +1769,10 @@ static bool ProcessCmdLine(LPSTR lpCmdLine) { g_cmdLine.newVideoRefreshRate = VR_60HZ; } + else if (strcmp(lpCmdLine, "-power-on") == 0) + { + g_cmdLine.bBoot = true; + } else // unsupported { LogFileOutput("Unsupported arg: %s\n", lpCmdLine); From fa047974ec3813eb7b8eaf6586feb7d050c7bd77 Mon Sep 17 00:00:00 2001 From: tomcw Date: Thu, 28 May 2020 21:41:15 +0100 Subject: [PATCH 03/15] Fixed cmd line '-s7 empty' so that 'Harddisk Enable' is updated in Registry/conf.ini file . this matches -s7-empty-on-exit and the -d1,-d2,-h1,-h2 switches --- source/Applewin.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index f5f1b05c..69011212 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1964,6 +1964,8 @@ static void RepeatInitialization(void) LogFileOutput("Main: FrameCreateWindow() - post\n"); // Allow the 4 hardcoded slots to be configurated as empty + // TODO: this state should be reflected in the Registry/conf.ini (just as bSlotEmpty[7] is) + // TODO: support bSlotEmpty[] for slots: 0,4,5 if (g_cmdLine.bSlotEmpty[SLOT1]) g_CardMgr.Remove(SLOT1); if (g_cmdLine.bSlotEmpty[SLOT2]) @@ -1998,7 +2000,7 @@ static void RepeatInitialization(void) g_cmdLine.szImageName_harddisk[HARDDISK_1] = g_cmdLine.szImageName_harddisk[HARDDISK_2] = NULL; // Don't insert on a restart if (g_cmdLine.bSlotEmpty[7]) - HD_SetEnabled(false); + UnplugHardDiskControllerCard(); } MemInitialize(); From 4f340fa2647e9d3b8a9b2823c0485953b92d339b Mon Sep 17 00:00:00 2001 From: tomcw Date: Fri, 29 May 2020 21:58:53 +0100 Subject: [PATCH 04/15] Revert previous fa04797: . again '-s7 empty' doesn't persist this state to Registry/conf.ini . consistent with other '-sn empty' cmds --- source/Applewin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 69011212..bb225c74 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1964,7 +1964,7 @@ static void RepeatInitialization(void) LogFileOutput("Main: FrameCreateWindow() - post\n"); // Allow the 4 hardcoded slots to be configurated as empty - // TODO: this state should be reflected in the Registry/conf.ini (just as bSlotEmpty[7] is) + // NB. this state is not persisted to the Registry/conf.ini (just as '-s7 empty' isn't) // TODO: support bSlotEmpty[] for slots: 0,4,5 if (g_cmdLine.bSlotEmpty[SLOT1]) g_CardMgr.Remove(SLOT1); @@ -2000,7 +2000,7 @@ static void RepeatInitialization(void) g_cmdLine.szImageName_harddisk[HARDDISK_1] = g_cmdLine.szImageName_harddisk[HARDDISK_2] = NULL; // Don't insert on a restart if (g_cmdLine.bSlotEmpty[7]) - UnplugHardDiskControllerCard(); + HD_SetEnabled(false); // Disable HDD controller, but don't persist this to Registry/conf.ini (consistent with other '-sn empty' cmds) } MemInitialize(); From 037c3383033485762a7a19126e2e89d99534122f Mon Sep 17 00:00:00 2001 From: TomCh Date: Sat, 30 May 2020 14:12:36 +0100 Subject: [PATCH 05/15] Debugger: Extend 'tf' command to add cycles for trace (#783) (PR #793) Also don't call DrawFlags(), speeding up tracing by 10 times. Authored-by: Nick Westgate --- source/Debugger/Debug.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index cb69665a..44fdc73c 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -8160,7 +8160,17 @@ void OutputTraceLine () char sDisassembly[ CONSOLE_WIDTH ]; // DrawDisassemblyLine( 0,regs.pc, sDisassembly); // Get Disasm String FormatDisassemblyLine( line, sDisassembly, CONSOLE_WIDTH ); - char sFlags[ _6502_NUM_FLAGS + 1 ]; DrawFlags( 0, regs.ps, sFlags ); // Get Flags String + char sFlags[] = "........"; + WORD nRegFlags = regs.ps; + int nFlag = _6502_NUM_FLAGS; + while (nFlag--) + { + int iFlag = (_6502_NUM_FLAGS - nFlag - 1); + bool bSet = (nRegFlags & 1); + if (bSet) + sFlags[nFlag] = g_aBreakpointSource[BP_SRC_FLAG_C + iFlag][0]; + nRegFlags >>= 1; + } if (!g_hTraceFile) return; @@ -8178,8 +8188,8 @@ void OutputTraceLine () else { fprintf( g_hTraceFile, -// "00 00 00 0000 -------- 0000:90 90 90 NOP" - "A: X: Y: SP: Flags Addr:Opcode Mnemonic\n"); +// "00000000 00 00 00 0000 -------- 0000:90 90 90 NOP" + "Cycles A: X: Y: SP: Flags Addr:Opcode Mnemonic\n"); } } @@ -8214,8 +8224,10 @@ void OutputTraceLine () } else { + const UINT cycles = (UINT)g_nCumulativeCycles; fprintf( g_hTraceFile, - "%02X %02X %02X %04X %s %s\n", + "%08X %02X %02X %02X %04X %s %s\n", + cycles, (unsigned)regs.a, (unsigned)regs.x, (unsigned)regs.y, From f801655b234d50e70d5795b07bcec1f33d93810e Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 30 May 2020 14:41:14 +0100 Subject: [PATCH 06/15] Debugger: DrawFlags() - refactored to remove unused 3rd param --- source/Debugger/Debugger_Display.cpp | 16 ++-------------- source/Debugger/Debugger_Display.h | 2 -- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index fbd99901..b3bd9064 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -2340,9 +2340,8 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress ) } -// Optionally copy the flags to pText_ //=========================================================================== -void DrawFlags ( int line, WORD nRegFlags, LPTSTR pFlagNames_) +static void DrawFlags ( int line, WORD nRegFlags ) { if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) return; @@ -2431,19 +2430,8 @@ void DrawFlags ( int line, WORD nRegFlags, LPTSTR pFlagNames_) rect.top -= g_nFontHeight; rect.bottom -= g_nFontHeight; - if (pFlagNames_) - { - if (!bSet) - sFlagNames[nFlag] = '.'; - else - sFlagNames[nFlag] = g_aBreakpointSource[ BP_SRC_FLAG_C + iFlag ][0]; - } - nRegFlags >>= 1; } - - if (pFlagNames_) - strcpy(pFlagNames_,sFlagNames); } //=========================================================================== @@ -2732,7 +2720,7 @@ void DrawRegisters ( int line ) DrawRegister( line++, sReg[ BP_SRC_REG_X ] , 1, regs.x , PARAM_REG_X ); DrawRegister( line++, sReg[ BP_SRC_REG_Y ] , 1, regs.y , PARAM_REG_Y ); DrawRegister( line++, sReg[ BP_SRC_REG_PC] , 2, regs.pc, PARAM_REG_PC ); - DrawFlags ( line , regs.ps, NULL); + DrawFlags ( line , regs.ps); line += 2; DrawRegister( line++, sReg[ BP_SRC_REG_S ] , 2, regs.sp, PARAM_REG_SP ); } diff --git a/source/Debugger/Debugger_Display.h b/source/Debugger/Debugger_Display.h index fb4deedd..3e5a9435 100644 --- a/source/Debugger/Debugger_Display.h +++ b/source/Debugger/Debugger_Display.h @@ -81,8 +81,6 @@ void FormatOpcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ ); void FormatNopcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ ); - void DrawFlags ( int line, WORD nRegFlags, LPTSTR pFlagNames_); - // extern HDC GetDebuggerMemDC(void); From a332e58f1a0974d56eb05aa3ed9b1192b9284d50 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 31 May 2020 16:11:43 +0100 Subject: [PATCH 07/15] Help: Debugger: added new section on Bookmarks --- help/Table of Contents.hhc | 4 + help/dbg-bookmarks.html | 127 ++++++++++++++++++++++ help/dbg-toc-intro.html | 1 + help/img/debugger-bookmarks-annotated.png | Bin 0 -> 24696 bytes help/resources/debugger-bookmarks.png | Bin 0 -> 24015 bytes 5 files changed, 132 insertions(+) create mode 100644 help/dbg-bookmarks.html create mode 100644 help/img/debugger-bookmarks-annotated.png create mode 100644 help/resources/debugger-bookmarks.png diff --git a/help/Table of Contents.hhc b/help/Table of Contents.hhc index ebbb292e..0df195af 100644 --- a/help/Table of Contents.hhc +++ b/help/Table of Contents.hhc @@ -195,6 +195,10 @@ +

  • + + +
  • diff --git a/help/dbg-bookmarks.html b/help/dbg-bookmarks.html new file mode 100644 index 00000000..d8573931 --- /dev/null +++ b/help/dbg-bookmarks.html @@ -0,0 +1,127 @@ + + + + AppleWin Debugger Tutorial + + + +

    Bookmarks

    +

    Bookmarks allow you to "tag" an address and consequently jump back to them.
    + They appear as a number with a circle around them between address and opcodes are listed (where the : separator is). +

    + + + +
    +

    Notes:

    +
      +
    • Set a bookmark a the current disassembly cursor, use Ctrl-Shift-#, ie: +
        +
      • NB. Ctrl-Shift-0 can't be used, as it's not recognised by Windows +
      • Ctrl-Shift-1 set bookmark 1 +
      • Ctrl-Shift-2 set bookmark 2 +
      • ... +
      • Ctrl-Shift-9 set bookmark 9 +
      +
    • + +
      + +
    • To jump to a existing bookmark, if it exists, press Ctrl-#, ie: +
        +
      • Ctrl-0 to jump to bookmark 0 +
      • Ctrl-1 to jump to bookmark 1 +
      • Ctrl-2 to jump to bookmark 2 +
      • ... +
      • Ctrl-9 to jump to bookmark 9 +
      +
    • + +
      + +
    • NB. +
        +
      • Bookmarks can appear in any order that you set - not just contiguous. +
      • An address can only have ONE bookmark assigned to it. If you try setting a new bookmark over an existing one, the old one will become free for use. +
      +
    • +
    + +

    +

    + +

    Commands to manipulate bookmarks:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Command

    +
    +

    Description

    +
    +

    help bookmarks

    +
    +

    Lists all bookmark related commands

    +
    +

    help bma

    +
    +

    Lists specific help about the bma command

    +
    +

    bma <address|label>

    +
    +

    Add a bookmark at an address or label

    +
    +

    bmc #

    +
    +

    Clear a specific bookmarks, for example 'bmc 1' clears bookmark 1

    +
    +

    bmc *

    +
    +

    Clears all bookmarks

    +
    +

    bml

    +
    +

    Lists all boommarks

    +
    +

    bmsave

    +
    +

    Not implemented yet

    +
    + + diff --git a/help/dbg-toc-intro.html b/help/dbg-toc-intro.html index 95ea6c03..f7837741 100644 --- a/help/dbg-toc-intro.html +++ b/help/dbg-toc-intro.html @@ -27,6 +27,7 @@
  • Calculator
  • Windows
  • Breakpoints +
  • Bookmarks
  • Configuration
    • Colors diff --git a/help/img/debugger-bookmarks-annotated.png b/help/img/debugger-bookmarks-annotated.png new file mode 100644 index 0000000000000000000000000000000000000000..fa1d0a1c3f0fcff1a9c7367705110db2dcd1cf34 GIT binary patch literal 24696 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 sVoGgm0O`PAcU3ytGdH8#MhwMP&2eHtwp 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 literal 0 HcmV?d00001 diff --git a/help/resources/debugger-bookmarks.png b/help/resources/debugger-bookmarks.png new file mode 100644 index 0000000000000000000000000000000000000000..e27249cc34e9bc7ac10a860ee8ace3ab67a5d1e6 GIT binary patch literal 24015 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

      7A zg2B(+%ys$uRy{8_hQt~B8=->iC7hDU!^)6gS-uINVS^Ong6i>n(R2)tt3S$7E7e9I zKi_+3X@g48hzEoTk#rR%z-B>5Ti%B%ET6^sre;O9pU=sjd_{W#t8~t7_E9Q``;tdu zfjn%II~4!bOp7j2otZhPaTQcf-*P7Q4RAiqWvWaehQqw$C+5Y!%!`l;$3(NLI9{#q zP+Wj$!`6d(2T^b^lU)Zu3fORC#)&^B6YW`~Xl721BTI=3P!>T1>LP+yrIcF&>Q~jy`pLRx{N~8n||iWGAw?4)R|!Olc|R7Y@N0mx~#{ z4rCaqcy|$&RDHqb<1lXbNA%zB1B|{sN6?+cXspKHY0q6yg_(fN3LT7@Y?!zEX>3*nPz`hE&~>u7*;xt@SE+f!=_wYXxUh@!}BBy;G4*YsAb1>&SKPc@=V9^tEyR(adXSapC4Y_RH z48BYY3nd?82R+0X{;X)7xxxDmPA1N>ILXO$H~iY{h4XZ>2VO^Nr>;}_Y$bXB+u}(x zS6ov%W+ru5SWEVTjCohxft?3c6k#6KW$w`Sj~o|wPL`C7GyIG&84GwSX&^aS5v`{r zI@xwc>ZgjYKQO*T)Hw2!VPTxPB0U2JIF;dbi>Q5^Pp|7h_CwNx_iX%lVW2((>uP)n z3)U6X@xmuuodVyp*uGcU!R4lKe!~7I_)NwV4R4-FR~is9NU zLoedO88C<)QJj3ecSqi2${utkeSpT&#c_KIlO#6ubhI<{CufMC8{*>oPSN67o08#y z$VWNlI(+5hiai346hpN6dp&A@ne4TcuwnQjJ71P$8tYkNBH2&c4EE?4o^x3<;Q3(A}fBHvJ1$8oX zK|fZqxVn?Ru8!a`+EYK}VNHxCKay_x?p8Z4$La<4(d;xB2h#}W0%pDX$`4l;T`3`5 zAtbB0C9yK!9SJ!_L-#CCR+vO<@^1tsfGKa}LIE*|UCaPZZU-%JRr1`hOQ3XrCn9Q* zDQrEyTnYQAJQV{+A+g4xYXvE`DB<{L_|4!P;-{65T=Twa( zIkId8j?`r-@%djyD6|h=0zM<T$g-0+3IQ`CO|6ED8Z literal 0 HcmV?d00001 From 105d0d77d86d7bbbdc725fa9b017bf063011b749 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 31 May 2020 16:39:50 +0100 Subject: [PATCH 08/15] 1.29.13.0: Updated version and History.txt --- bin/History.txt | 18 +++++++++++++++--- resource/version.h | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index dbb696eb..8ab500cd 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -9,6 +9,18 @@ https://github.com/AppleWin/AppleWin/issues/new Tom Charlesworth +1.29.13.0 - 31 May 2020 +----------------------- +. [Bug #790] Fixed regression for -d1,-d2 & -s7-empty-on-exit (introduced at 1.29.7.0). +. [Change #787] Debugger: Extended 'cycles part' command to do timings relative to a user-specified base. +. [Change #783] Debugger: Extended 'tf' command to include cycle count. +. [Change #720] Debugger: Added more symbols to APPLE2E.SYM. + - NB. LC ($C08n) symbols are now correct for the LC, so 'LDA $C08C,X' will disassemble as 'LDA LCRAMIN1_,X' + instead of 'LDA DATASTROBE,X'. So now perhaps less helpful when stepping Disk II code. +. [PR #785] Debugger: Improvements to Bookmarks. + - AppleWin.chm: Added debugger help about Bookmarks. + + 1.29.12.0 - 26 Apr 2020 ----------------------- . [PR #757] Allow use of an INI-file for configuration instead of the Registry (fixes #709). @@ -23,10 +35,10 @@ Tom Charlesworth 1.29.11.0 - 27 Mar 2020 ----------------------- -. [Bug #771] Added new command line switch to load custom ROM: -rom . +. [Change #771] Added new command line switch to load custom ROM: -rom . - Supports 12KiB (at $D000) and 16KiB (at $C000) rom files. . [Bug #765] Lancaster (Total Replay) hangs when starting second game. -. [Bug #734] DiskII controller card: support 13-sector firmware. +. [Change #734] DiskII controller card: support 13-sector firmware. - The card auto-selects the firmware based on the .woz (v2 or higher) image properties. - Only change the firmware at reset/reboot to avoid changing whilst running in $C6xx space! - Fixes 'The Best of MUSE' & 'MicroChess 2.0' (#732) @@ -54,7 +66,7 @@ Tom Charlesworth . [Bug #748] DiskII: data latch returns a rand() value when no disk is in drive. . [Bug #746] Debugger: correctly repaint Apple II screen when showing it from debugger. . [Bug #745] WOZ: Support for large tracks. -. [Bug #743] Added new command line switches: +. [Change #743] Added new command line switches: -left-alt-control-buttons : left-ctrl=button0, left-alt=button1 -right-alt-control-buttons : right-alt=button0, right-ctrl=button1 -swap-buttons : for swapping buttons 0 & 1 diff --git a/resource/version.h b/resource/version.h index a5cc76d0..c4ec4790 100644 --- a/resource/version.h +++ b/resource/version.h @@ -1,4 +1,4 @@ -#define APPLEWIN_VERSION 1,29,12,0 +#define APPLEWIN_VERSION 1,29,13,0 #define xstr(a) str(a) #define str(a) #a From f238be27e8e8d24c0ef4bf487826f5d4da326fcb Mon Sep 17 00:00:00 2001 From: tomcw Date: Wed, 3 Jun 2020 20:26:06 +0100 Subject: [PATCH 09/15] Use SetCursor() to busy when loading state file. (Fixes #781) Fixed typos in dbg-bookmarks.html. --- bin/History.txt | 1 + help/dbg-bookmarks.html | 6 +++--- source/SaveState.cpp | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 8ab500cd..ac548195 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -19,6 +19,7 @@ Tom Charlesworth instead of 'LDA DATASTROBE,X'. So now perhaps less helpful when stepping Disk II code. . [PR #785] Debugger: Improvements to Bookmarks. - AppleWin.chm: Added debugger help about Bookmarks. +. Fixed occasional speaker clicks in full-speed mode. 1.29.12.0 - 26 Apr 2020 diff --git a/help/dbg-bookmarks.html b/help/dbg-bookmarks.html index d8573931..6ddd81e5 100644 --- a/help/dbg-bookmarks.html +++ b/help/dbg-bookmarks.html @@ -7,7 +7,7 @@

      Bookmarks

      Bookmarks allow you to "tag" an address and consequently jump back to them.
      - They appear as a number with a circle around them between address and opcodes are listed (where the : separator is). + They appear as a number with a circle around them between where address and opcodes are listed (where the : separator is).

      @@ -15,7 +15,7 @@

      Notes:

        -
      • Set a bookmark a the current disassembly cursor, use Ctrl-Shift-#, ie: +
      • Set a bookmark at the current disassembly cursor, use Ctrl-Shift-#, ie:
        • NB. Ctrl-Shift-0 can't be used, as it's not recognised by Windows
        • Ctrl-Shift-1 set bookmark 1 @@ -27,7 +27,7 @@
          -
        • To jump to a existing bookmark, if it exists, press Ctrl-#, ie: +
        • To jump to an existing bookmark, if it exists, press Ctrl-#, ie:
          • Ctrl-0 to jump to bookmark 0
          • Ctrl-1 to jump to bookmark 1 diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 7d1de8a2..0e1dc5f3 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -371,6 +371,7 @@ static void ParseUnit(void) static void Snapshot_LoadState_v2(void) { bool restart = false; // Only need to restart if any VM state has change + HCURSOR oldcursor = SetCursor(LoadCursor(0,IDC_WAIT)); try { @@ -474,6 +475,7 @@ static void Snapshot_LoadState_v2(void) PostMessage(g_hFrameWindow, WM_USER_RESTART, 0, 0); // Power-cycle VM (undoing all the new state just loaded) } + SetCursor(oldcursor); yamlHelper.FinaliseParser(); } From 41203f5d2d6f841087965034f5e7b3a9c44caddf Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 6 Jun 2020 16:32:58 +0100 Subject: [PATCH 10/15] Fixes for image loading switches (-d1,-d2,-h1,-h2,-s5d1,-s5d2): . support relative paths (#663) . updated the current directory with the path for each loaded image (#663) & saving state (#691) . added a new switch -current-dir --- source/Applewin.cpp | 53 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index bb225c74..4076f944 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -82,6 +82,7 @@ AppMode_e g_nAppMode = MODE_LOGO; static bool g_bLoadedSaveState = false; static bool g_bSysClkOK = false; +std::string g_sStartDir; // NB. AppleWin.exe maybe relative to this! (GH#663) std::string g_sProgramDir; // Directory of where AppleWin executable resides std::string g_sDebugDir; // TODO: Not currently used std::string g_sScreenShotDir; // TODO: Not currently used @@ -541,7 +542,8 @@ void EnterMessageLoop(void) } //=========================================================================== -void GetProgramDirectory(void) + +static void GetProgramDirectory(void) { TCHAR programDir[MAX_PATH]; GetModuleFileName((HINSTANCE)0, programDir, MAX_PATH); @@ -1141,19 +1143,27 @@ static std::string GetFullPath(LPCSTR szFileName) } else { - // Rel pathname - char szCWD[_MAX_PATH] = {0}; - if (!GetCurrentDirectory(sizeof(szCWD), szCWD)) - return ""; - - strPathName = szCWD; - strPathName.append("\\"); + // Rel pathname (GH#663) + strPathName = g_sStartDir; strPathName.append(szFileName); } return strPathName; } +static void SetCurrentDir(std::string pathname) +{ + // Due to the order HDDs/disks are inserted, then s7 insertions take priority over s6 & s5; and d2 takes priority over d1: + // . if -s6[dN] and -hN are specified, then g_sCurrentDir will be set to the HDD image's path + // . if -s5[dN] and -s6[dN] are specified, then g_sCurrentDir will be set to the s6 image's path + // . if -[sN]d1 and -[sN]d2 are specified, then g_sCurrentDir will be set to the d2 image's path + // This is purely dependent on the current order of InsertFloppyDisks() & InsertHardDisks() - ie. very brittle! + // . better to use -current-dir to be explicit + std::size_t found = pathname.find_last_of("\\"); + std::string path = pathname.substr(0, found); + SetCurrentImageDir(path); +} + static bool DoDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName) { Disk2InterfaceCard& disk2Card = dynamic_cast(g_CardMgr.GetRef(slot)); @@ -1162,7 +1172,10 @@ static bool DoDiskInsert(const UINT slot, const int nDrive, LPCSTR szFileName) if (strPathName.empty()) return false; ImageError_e Error = disk2Card.InsertDisk(nDrive, strPathName.c_str(), IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); - return Error == eIMAGE_ERROR_NONE; + bool res = (Error == eIMAGE_ERROR_NONE); + if (res) + SetCurrentDir(strPathName); + return res; } static bool DoHardDiskInsert(const int nDrive, LPCSTR szFileName) @@ -1171,7 +1184,10 @@ static bool DoHardDiskInsert(const int nDrive, LPCSTR szFileName) if (strPathName.empty()) return false; BOOL bRes = HD_Insert(nDrive, strPathName.c_str()); - return bRes ? true : false; + bool res = (bRes == TRUE); + if (res) + SetCurrentDir(strPathName); + return res; } static void InsertFloppyDisks(const UINT slot, LPSTR szImageName_drive[NUM_DRIVES], bool& bBoot) @@ -1349,15 +1365,22 @@ struct CmdLine VideoRefreshRate_e newVideoRefreshRate; double clockMultiplier; eApple2Type model; + std::string strCurrentDir; }; static CmdLine g_cmdLine; int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) { + char startDir[_MAX_PATH]; + GetCurrentDirectory(sizeof(startDir), startDir); + g_sStartDir = startDir; + if (*(g_sStartDir.end()-1) != '\\') g_sStartDir += '\\'; + if (!ProcessCmdLine(lpCmdLine)) return 0; + LogFileOutput("g_sStartDir = %s\n", g_sStartDir.c_str()); GetAppleWinVersion(); OneTimeInitialization(passinstance); @@ -1773,6 +1796,12 @@ static bool ProcessCmdLine(LPSTR lpCmdLine) { g_cmdLine.bBoot = true; } + else if (strcmp(lpCmdLine, "-current-dir") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_cmdLine.strCurrentDir = lpCmdLine; + } else // unsupported { LogFileOutput("Unsupported arg: %s\n", lpCmdLine); @@ -2003,6 +2032,10 @@ static void RepeatInitialization(void) HD_SetEnabled(false); // Disable HDD controller, but don't persist this to Registry/conf.ini (consistent with other '-sn empty' cmds) } + // Set *after* InsertFloppyDisks() & InsertHardDisks(), which both update g_sCurrentDir + if (!g_cmdLine.strCurrentDir.empty()) + SetCurrentImageDir(g_cmdLine.strCurrentDir); + MemInitialize(); LogFileOutput("Main: MemInitialize()\n"); From 80eb33012fee3918d5c39e1d2677ac3f171172ea Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 7 Jun 2020 18:25:34 +0100 Subject: [PATCH 11/15] Fixed an edge case when switching from IIe to II+, and the Mockingboard wasn't visible in memory. . Due to INTCXROM still being set and it not being excluded when in II+ mode. . Fix is to reinit memmode on restart and only check INTCXROM if IIe or above. --- source/Common.h | 7 ++++++- source/Memory.cpp | 10 ++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/source/Common.h b/source/Common.h index 6a9b5cc6..f2c6516b 100644 --- a/source/Common.h +++ b/source/Common.h @@ -161,7 +161,7 @@ enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE}; #define APPLECLONE_MASK 0x100 #define IS_APPLE2 ((g_Apple2Type & (APPLE2E_MASK|APPLE2C_MASK)) == 0) -#define IS_APPLE2E() (g_Apple2Type & APPLE2E_MASK) +//#define IS_APPLE2E() (g_Apple2Type & APPLE2E_MASK) // unused #define IS_APPLE2C() (g_Apple2Type & APPLE2C_MASK) #define IS_CLONE() (g_Apple2Type & APPLECLONE_MASK) @@ -218,6 +218,11 @@ inline bool IsApple2PlusOrClone(eApple2Type type) // Apple ][,][+,][J-Plus or cl return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0; } +inline bool IsAppleIIeOrAbove(eApple2Type type) // Apple //e,Enhanced//e,//c or clone //e,Enhanced//e +{ + return !IsApple2PlusOrClone(type); +} + extern eApple2Type g_Apple2Type; inline bool IsEnhancedIIE(void) { diff --git a/source/Memory.cpp b/source/Memory.cpp index b65dd0e8..4c513f64 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1499,6 +1499,12 @@ void MemInitialize() CreateLanguageCard(); + // Reinit memmode on a restart (eg. h/w config changes) + if (IsApple2PlusOrClone(GetApple2Type()) && g_CardMgr.QuerySlot(SLOT0) == CT_Empty) + SetMemMode(0); + else + SetMemMode(LanguageCardUnit::kMemModeInitialState); + MemInitializeROM(); MemInitializeCustomROM(); MemInitializeCustomF8ROM(); @@ -1768,7 +1774,7 @@ void MemInitializeIO(void) // Finally remove the cards' ROMs at $Csnn if internal ROM is enabled // . required when restoring saved-state - if (SW_INTCXROM) + if (IsAppleIIeOrAbove(GetApple2Type()) && SW_INTCXROM) IoHandlerCardsOut(); } @@ -2092,7 +2098,7 @@ BYTE __stdcall MemSetPaging(WORD programcounter, WORD address, BYTE write, BYTE bool MemOptimizeForModeChanging(WORD programcounter, WORD address) { - if (IS_APPLE2E()) + if (IsAppleIIeOrAbove(GetApple2Type())) { // 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 From 6d85c1b6bdac59253297d633905c4a096bf5259e Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 8 Jun 2020 21:11:12 +0100 Subject: [PATCH 12/15] NSC: Reset NSC on power-cycle. (Fixes #751) --- source/Frame.cpp | 2 +- source/Memory.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 40fdd55c..f33ed21d 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -2297,7 +2297,7 @@ void ResetMachineState () HD_Reset(); g_bFullSpeed = 0; // Might've hit reset in middle of InternalCpuExecute() - so beep may get (partially) muted - MemReset(); // calls CpuInitialize() + MemReset(); // calls CpuInitialize(), CNoSlotClock.Reset() PravetsReset(); if (g_CardMgr.QuerySlot(SLOT6) == CT_Disk2) dynamic_cast(g_CardMgr.GetRef(SLOT6)).Boot(); diff --git a/source/Memory.cpp b/source/Memory.cpp index 4c513f64..48b71c28 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1801,7 +1801,7 @@ inline DWORD getRandomTime() //=========================================================================== // Called by: -// . MemInitialize() +// . MemInitialize() eg. on AppleWin start & restart (eg. h/w config changes) // . ResetMachineState() eg. Power-cycle ('Apple-Go' button) // . Snapshot_LoadState_v2() void MemReset() @@ -1956,6 +1956,8 @@ void MemReset() //Sets Caps Lock = false (Pravets 8A/C only) z80_reset(); // NB. Also called above in CpuInitialize() + + g_NoSlotClock.Reset(); // NB. Power-cycle, but not RESET signal } //=========================================================================== From f491bb19cdabc679cb71eb7ec2b1637b4e40b320 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 8 Jun 2020 22:06:17 +0100 Subject: [PATCH 13/15] Improved fix for 80eb330 . During init: only need to call IoHandlerCardsOut() when loading save-state . MemInitialize() -> MemReset() -> ResetPaging() which always inits memmode --- source/Memory.cpp | 22 +++++++--------------- source/Memory.h | 2 +- source/SaveState.cpp | 4 ++-- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index 48b71c28..05075352 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1499,12 +1499,6 @@ void MemInitialize() CreateLanguageCard(); - // Reinit memmode on a restart (eg. h/w config changes) - if (IsApple2PlusOrClone(GetApple2Type()) && g_CardMgr.QuerySlot(SLOT0) == CT_Empty) - SetMemMode(0); - else - SetMemMode(LanguageCardUnit::kMemModeInitialState); - MemInitializeROM(); MemInitializeCustomROM(); MemInitializeCustomF8ROM(); @@ -1769,19 +1763,17 @@ void MemInitializeIO(void) if (g_CardMgr.QuerySlot(SLOT7) == CT_GenericHDD) HD_Load_Rom(pCxRomPeripheral, SLOT7); // $C700 : HDD f/w - - // - - // Finally remove the cards' ROMs at $Csnn if internal ROM is enabled - // . required when restoring saved-state - if (IsAppleIIeOrAbove(GetApple2Type()) && SW_INTCXROM) - IoHandlerCardsOut(); } // Called by: // . Snapshot_LoadState_v2() -void MemInitializeCardExpansionRomFromSnapshot(void) +void MemInitializeCardSlotAndExpansionRomFromSnapshot(void) { + // Remove all the cards' ROMs at $Csnn if internal ROM is enabled + if (IsAppleIIeOrAbove(GetApple2Type()) && SW_INTCXROM) + IoHandlerCardsOut(); + + // Potentially init a card's expansion ROM const UINT uSlot = g_uPeripheralRomSlot; if (ExpansionRom[uSlot] == NULL) @@ -1948,7 +1940,7 @@ void MemReset() mem = memimage; // INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE - ResetPaging(1); // Initialize=1 + ResetPaging(TRUE); // Initialize=1, init memmode // INITIALIZE & RESET THE CPU // . Do this after ROM has been copied back to mem[], so that PC is correctly init'ed from 6502's reset vector diff --git a/source/Memory.h b/source/Memory.h index 5f91647f..6226b996 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -74,7 +74,7 @@ void MemInitializeROM(void); void MemInitializeCustomROM(void); void MemInitializeCustomF8ROM(void); void MemInitializeIO(void); -void MemInitializeCardExpansionRomFromSnapshot(void); +void MemInitializeCardSlotAndExpansionRomFromSnapshot(void); BYTE MemReadFloatingBus(const ULONG uExecutedCycles); BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles); void MemReset (); diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 0e1dc5f3..8a070e60 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -400,7 +400,7 @@ static void Snapshot_LoadState_v2(void) m_ConfigNew.m_bEnableHDD = false; //m_ConfigNew.m_bEnableTheFreezesF8Rom = ?; // todo: when support saving config - MemReset(); // Also calls CpuInitialize() + MemReset(); // Also calls CpuInitialize(), CNoSlotClock.Reset() PravetsReset(); if (g_CardMgr.IsSSCInstalled()) @@ -455,7 +455,7 @@ static void Snapshot_LoadState_v2(void) MemInitializeCustomROM(); MemInitializeCustomF8ROM(); MemInitializeIO(); - MemInitializeCardExpansionRomFromSnapshot(); + MemInitializeCardSlotAndExpansionRomFromSnapshot(); MemUpdatePaging(TRUE); From c9ef6ecee1449824ef31fefc71e8e7c9afc88799 Mon Sep 17 00:00:00 2001 From: tomcw Date: Wed, 10 Jun 2020 20:56:00 +0100 Subject: [PATCH 14/15] NoSlotClock: . added to save-state (v6) via a new unit type 'Miscellaneous' . added cmd line switch '-no-nsc' to configure AppleII without an NSC --- source/Applewin.cpp | 9 +++++++++ source/Memory.cpp | 45 +++++++++++++++++++++++++++++++++++++----- source/Memory.h | 5 +++++ source/NoSlotClock.cpp | 40 +++++++++++++++++++++++++++++++++++++ source/NoSlotClock.h | 4 ++++ source/SaveState.cpp | 30 ++++++++++++++++++++++++++-- 6 files changed, 126 insertions(+), 7 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 4076f944..82d5c611 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1318,6 +1318,7 @@ struct CmdLine bSlot0LanguageCard = false; bSlot7EmptyOnExit = false; bSwapButtons0and1 = false; + bRemoveNoSlotClock = false; bestWidth = 0; bestHeight = 0; szImageName_harddisk[HARDDISK_1] = NULL; @@ -1350,6 +1351,7 @@ struct CmdLine bool bSlotEmpty[NUM_SLOTS]; bool bSlot7EmptyOnExit; bool bSwapButtons0and1; + bool bRemoveNoSlotClock; SS_CARDTYPE slotInsert[NUM_SLOTS]; UINT bestWidth; UINT bestHeight; @@ -1802,6 +1804,10 @@ static bool ProcessCmdLine(LPSTR lpCmdLine) lpNextArg = GetNextArg(lpNextArg); g_cmdLine.strCurrentDir = lpCmdLine; } + else if (strcmp(lpCmdLine, "-no-nsc") == 0) + { + g_cmdLine.bRemoveNoSlotClock = true; + } else // unsupported { LogFileOutput("Unsupported arg: %s\n", lpCmdLine); @@ -2036,6 +2042,9 @@ static void RepeatInitialization(void) if (!g_cmdLine.strCurrentDir.empty()) SetCurrentImageDir(g_cmdLine.strCurrentDir); + if (g_cmdLine.bRemoveNoSlotClock) + MemRemoveNoSlotClock(); + MemInitialize(); LogFileOutput("Main: MemInitialize()\n"); diff --git a/source/Memory.cpp b/source/Memory.cpp index 05075352..5a5a7db1 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -210,7 +210,7 @@ static LPBYTE g_pMemMainLanguageCard = NULL; static DWORD memmode = LanguageCardUnit::kMemModeInitialState; static BOOL modechanging = 0; // An Optimisation: means delay calling UpdatePaging() for 1 instruction -static CNoSlotClock g_NoSlotClock; +static CNoSlotClock* g_NoSlotClock = new CNoSlotClock; static LanguageCardUnit* g_pLanguageCard = NULL; // For all Apple II, //e and above #ifdef RAMWORKS @@ -832,17 +832,17 @@ static BYTE __stdcall IO_Cxxx(WORD programcounter, WORD address, BYTE write, BYT } } - if (IsPotentialNoSlotClockAccess(address)) + if (g_NoSlotClock && IsPotentialNoSlotClockAccess(address)) { if (!write) { int data = 0; - if (g_NoSlotClock.Read(address, data)) + if (g_NoSlotClock->Read(address, data)) return (BYTE) data; } else { - g_NoSlotClock.Write(address); + g_NoSlotClock->Write(address); return 0; } } @@ -1949,7 +1949,8 @@ void MemReset() z80_reset(); // NB. Also called above in CpuInitialize() - g_NoSlotClock.Reset(); // NB. Power-cycle, but not RESET signal + if (g_NoSlotClock) + g_NoSlotClock->Reset(); // NB. Power-cycle, but not RESET signal } //=========================================================================== @@ -2136,6 +2137,26 @@ bool MemGetAnnunciator(UINT annunciator) //=========================================================================== +bool MemHasNoSlotClock(void) +{ + return g_NoSlotClock != NULL; +} + +void MemInsertNoSlotClock(void) +{ + if (!MemHasNoSlotClock()) + g_NoSlotClock = new CNoSlotClock; + g_NoSlotClock->Reset(); +} + +void MemRemoveNoSlotClock(void) +{ + delete g_NoSlotClock; + g_NoSlotClock = NULL; +} + +//=========================================================================== + // NB. Don't need to save 'modechanging', as this is just an optimisation to save calling UpdatePaging() twice. // . If we were to save the state when 'modechanging' is set, then on restoring the state, the 6502 code will immediately update the read memory mode. // . This will work correctly. @@ -2452,3 +2473,17 @@ bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT unitVersion) return true; } + +void NoSlotClockSaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + if (g_NoSlotClock) + g_NoSlotClock->SaveSnapshot(yamlSaveHelper); +} + +void NoSlotClockLoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!g_NoSlotClock) + g_NoSlotClock = new CNoSlotClock; + + g_NoSlotClock->LoadSnapshot(yamlLoadHelper); +} diff --git a/source/Memory.h b/source/Memory.h index 6226b996..2e65ba18 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -82,11 +82,16 @@ void MemResetPaging (); void MemUpdatePaging(BOOL initialize); LPVOID MemGetSlotParameters (UINT uSlot); bool MemGetAnnunciator(UINT annunciator); +bool MemHasNoSlotClock(void); +void MemInsertNoSlotClock(void); +void MemRemoveNoSlotClock(void); std::string MemGetSnapshotUnitAuxSlotName(void); void MemSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT unitVersion); void MemSaveSnapshotAux(class YamlSaveHelper& yamlSaveHelper); bool MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT unitVersion); +void NoSlotClockSaveSnapshot(YamlSaveHelper& yamlSaveHelper); +void NoSlotClockLoadSnapshot(YamlLoadHelper& yamlLoadHelper); BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); diff --git a/source/NoSlotClock.cpp b/source/NoSlotClock.cpp index c25e06c2..25a330e2 100644 --- a/source/NoSlotClock.cpp +++ b/source/NoSlotClock.cpp @@ -41,6 +41,7 @@ All the other drivers and utilities available to me don't define the DOW mapping #include "StdAfx.h" #include "NoSlotClock.h" +#include "YamlHelper.h" CNoSlotClock::CNoSlotClock() : @@ -166,6 +167,45 @@ void CNoSlotClock::PopulateClockRegister() m_ClockRegister.WriteNibble(year / 10); } +#define SS_YAML_KEY_CLOCK_REGISTER_ENABLED "Clock Register Enabled" +#define SS_YAML_KEY_WRITE_ENABLED "Write Enabled" +#define SS_YAML_KEY_CLOCK_REGISTER_MASK "Clock Register Mask" +#define SS_YAML_KEY_CLOCK_REGISTER "Clock Register" +#define SS_YAML_KEY_COMPARISON_REGISTER_MASK "Comparison Register Mask" +#define SS_YAML_KEY_COMPARISON_REGISTER "Comparison Register" + +std::string CNoSlotClock::GetSnapshotStructName(void) +{ + static const std::string name("No Slot Clock"); + return name; +} + +void CNoSlotClock::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) +{ + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", GetSnapshotStructName().c_str()); + yamlSaveHelper.SaveBool(SS_YAML_KEY_CLOCK_REGISTER_ENABLED, m_bClockRegisterEnabled); + yamlSaveHelper.SaveBool(SS_YAML_KEY_WRITE_ENABLED, m_bWriteEnabled); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_CLOCK_REGISTER_MASK, m_ClockRegister.m_Mask); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_CLOCK_REGISTER, m_ClockRegister.m_Register); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_COMPARISON_REGISTER_MASK, m_ComparisonRegister.m_Mask); + yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_COMPARISON_REGISTER, m_ComparisonRegister.m_Register); +} + +void CNoSlotClock::LoadSnapshot(YamlLoadHelper& yamlLoadHelper) +{ + if (!yamlLoadHelper.GetSubMap(GetSnapshotStructName())) + return; + + m_bClockRegisterEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_CLOCK_REGISTER_ENABLED); + m_bWriteEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_WRITE_ENABLED); + m_ClockRegister.m_Mask = yamlLoadHelper.LoadUint64(SS_YAML_KEY_CLOCK_REGISTER_MASK); + m_ClockRegister.m_Register = yamlLoadHelper.LoadUint64(SS_YAML_KEY_CLOCK_REGISTER); + m_ComparisonRegister.m_Mask = yamlLoadHelper.LoadUint64(SS_YAML_KEY_COMPARISON_REGISTER_MASK); + m_ComparisonRegister.m_Register = yamlLoadHelper.LoadUint64(SS_YAML_KEY_COMPARISON_REGISTER); + + yamlLoadHelper.PopMap(); +} + CNoSlotClock::RingRegister64::RingRegister64() { Reset(); diff --git a/source/NoSlotClock.h b/source/NoSlotClock.h index 68706bb0..f2f773ad 100644 --- a/source/NoSlotClock.h +++ b/source/NoSlotClock.h @@ -57,6 +57,9 @@ public: bool ClockRead(int& data); void ClockWrite(int address); + void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); + void LoadSnapshot(class YamlLoadHelper& yamlLoadHelper); + bool m_bClockRegisterEnabled; bool m_bWriteEnabled; RingRegister64 m_ClockRegister; @@ -64,6 +67,7 @@ public: private: void PopulateClockRegister(); + std::string GetSnapshotStructName(void); static const UINT64 kClockInitSequence = 0x5CA33AC55CA33AC5; }; diff --git a/source/SaveState.cpp b/source/SaveState.cpp index 8a070e60..4bd044f7 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -71,10 +71,13 @@ static YamlHelper yamlHelper; // v3: Extended: memory (added 'AnnunciatorN') // v4: Extended: video (added 'Video Refresh Rate') // v5: Extended: cpu (added 'Defer IRQ By 1 Opcode') -#define UNIT_APPLE2_VER 5 +// v6: Added 'Unit Miscellaneous' for NoSlotClock(NSC) +#define UNIT_APPLE2_VER 6 #define UNIT_SLOTS_VER 1 +#define UNIT_MISC_VER 1 + //----------------------------------------------------------------------------- void Snapshot_SetFilename(const std::string & strPathname) @@ -134,6 +137,12 @@ static std::string GetSnapshotUnitSlotsName(void) return name; } +static std::string GetSnapshotUnitMiscName(void) +{ + static const std::string name("Miscellaneous"); + return name; +} + #define SS_YAML_KEY_MODEL "Model" #define SS_YAML_VALUE_APPLE2 "Apple][" @@ -353,6 +362,9 @@ static void ParseUnit(void) if (unit == GetSnapshotUnitApple2Name()) { ParseUnitApple2(yamlLoadHelper, unitVersion); + + if (unitVersion < 6) MemInsertNoSlotClock(); // NSC always inserted + else MemRemoveNoSlotClock(); // NSC only add if there's a misc unit } else if (unit == MemGetSnapshotUnitAuxSlotName()) { @@ -362,6 +374,11 @@ static void ParseUnit(void) { ParseSlots(yamlLoadHelper, unitVersion); } + else if (unit == GetSnapshotUnitMiscName()) + { + // NB. could extend for other misc devices - see how ParseSlots() calls GetMapNextSlotNumber() + NoSlotClockLoadSnapshot(yamlLoadHelper); + } else { throw std::string(SS_YAML_KEY_UNIT ": Unknown type: " ) + unit; @@ -400,7 +417,7 @@ static void Snapshot_LoadState_v2(void) m_ConfigNew.m_bEnableHDD = false; //m_ConfigNew.m_bEnableTheFreezesF8Rom = ?; // todo: when support saving config - MemReset(); // Also calls CpuInitialize(), CNoSlotClock.Reset() + MemReset(); // Also calls CpuInitialize() PravetsReset(); if (g_CardMgr.IsSSCInstalled()) @@ -570,6 +587,15 @@ void Snapshot_SaveState(void) if (g_CardMgr.QuerySlot(SLOT7) == CT_GenericHDD) HD_SaveSnapshot(yamlSaveHelper); } + + // Miscellaneous + if (MemHasNoSlotClock()) + { + yamlSaveHelper.UnitHdr(GetSnapshotUnitMiscName(), UNIT_MISC_VER); + YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE); + + NoSlotClockSaveSnapshot(yamlSaveHelper); + } } catch(std::string szMessage) { From e5ccf26d4fed3d671f9c1ff1fc6000a78ce7c69e Mon Sep 17 00:00:00 2001 From: tomcw Date: Wed, 10 Jun 2020 21:45:19 +0100 Subject: [PATCH 15/15] Help: updated about NSC in save-state, and -no-nsc switch --- help/CommandLine.html | 2 ++ help/clock.html | 2 +- help/savestate.html | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/help/CommandLine.html b/help/CommandLine.html index e1d97152..d1bd62fd 100644 --- a/help/CommandLine.html +++ b/help/CommandLine.html @@ -52,6 +52,8 @@ Useful to allow a floppy disk to boot from slot 6, drive 1. Use in combination with -d1.

            -s7-empty-on-exit
            Remove the hard disk controller card from slot 7 on AppleWin exit.

            + -no-nsc
            + Remove the No-Slot clock (NSC).

            -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.

            -load-state <savestate>
            diff --git a/help/clock.html b/help/clock.html index 48d27d14..ef734563 100644 --- a/help/clock.html +++ b/help/clock.html @@ -12,7 +12,7 @@

            Clock:

            AppleWin emulates a No-Slot clock (aka NSC).

            This is a chip (a Dallas SmartWatch DS1216) that sits under one of the 28-pin ROM chips in the Apple II.
            - No hardware configuration is required: this chip is always present, but won't interfere with emulation when not in use. + No hardware configuration is required: this chip is always present (unless -no-nsc is used), but won't interfere with emulation when not in use.

            It requires a software driver to be installed (for DOS and ProDOS). This driver then emulates the Thunderclock card.

            Here's a summary of NSC/ROM chip locations and which drivers work:

            diff --git a/help/savestate.html b/help/savestate.html index 33ad53a4..00dd9848 100644 --- a/help/savestate.html +++ b/help/savestate.html @@ -31,12 +31,12 @@
          • CP/M SoftCard
          • Parallel Printer card
          • Super Serial card
          • +
          • No-Slot clock
          The following are not yet persisted to the file:
          • Uthernet card
          • SAM card
          • -
          • No-Slot clock (there's nothing to persist)
          • Using The Freeze's F8 ROM
          • Alternate F8 ROM
          • Alternate ROM