Files
AppleWin/source/Debugger/Debugger_Range.cpp
TomCh 54f86f0cdc Debugger: support address prefixes for slot, bank, language card & ROM (#1419)
* Minor tidy

* Changes:
. semicolon now Comment EOL
. double fwd-slash now Divide floor
. (single fwd-slash unassigned)

* . fwd-slash now parsed in Range_GetPrefix()
. WIP: 'bp bank/addr'

* Add error msgs

* Extend Breakpoint_t struct

* Update cmd 'bpl' to support displaying prefixes

* Do prefix checks & output error msgs

* Add _CheckBreakpointValueWithPrefix()
. support bank, for BP_OP_EQUAL
Stop reason: include BP id

* WIP: fix BPs (non-BPM)

* Fix cmd 'bpr'

* Stop reason: don't show BP id for BP_HIT_REG (as it already includes it)
Add comment about nArgs from calling funcs
Refactor _CmdBreakpointAddCommonArg(): nArgs

* Stop reason for memory BP: show full prefixed address

* Stop reason: output BP id in consistenct way

* Support ROM prefix filter

* Complete addr prefix logic

* Improve logic

* BP: 'HDD DMA to/from memory' - use common hit id function

* Support rw bank 100

* Support double forward-slash at start of line as a comment

* Refactor: use debugger naming convention for vars

* Changed prefix errors from 'bad' to 'out-of-range'

* DebugInitialize(): Reset g_breakpointHitID

* Refactor: use debugger var naming convention & formatting style

* Switch divide-operator to the underscore char, and allow double-fslash as a comment anywhere on a line

* Update help for debugger calculator

* Update help for debugger breakpoints

* Update help for debugger breakpoints (conditional)

* Fix help:breakpoints.html & fix ArgsGetRegisterVlaue() to do case-insensitive compare

* Fix underscore to be treated as a alphanumeric in a few edge cases

* Revert to using '//' as divide operator

* Help: update debugger Breakpoints & Calculalor pages

* Help: update debugger Calculator (missed one)

* Detabify and align

* Display (1) or (2) prefix for LC1 or LC2 breakpoint

* #1419 Added Aux.1 and Aux.N indicators

* Display (1) or (2) suffix for LC1 or LC2 breakpoint

* Extend cmd 'bpl' to display BP's end addr

* Show both bank and slot together

* Fix spacing for BP with range

* Add: FG_INFO_BP_MEM, FG_INFO_MEM_WRITE, BG_INFO_MEM_BANK_LC, FG_INFO_MEM_BANK_LC colors

* Cleanup

* Add 3x5 mini hex numbers

* Mini hex font to have rounded 0,A,C glyphs

* Display 2 hex Bank now

* Support edge-case for bank 0x100

* Tidy up end red spacer

* Refactor & introduce new struct AddressPrefix_t

* Fix a few bugs:
. bpl: fix end addr
. fix for 'R' and 'W' not coloured for single-byte BPs (eg. bpmr 100)

---------

Co-authored-by: michaelangel007 <michaelangel007@sharedcraft.com>
2025-09-06 02:43:57 -07:00

233 lines
6.2 KiB
C++

/*
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-2010, Tom Charlesworth, Michael Pohoreski
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: Debugger Utility Range
*
* Author: Copyright (C) 2006-2010 Michael Pohoreski
*/
#include "StdAfx.h"
#include "Debug.h"
#include "../CardManager.h"
// Util - Range _______________________________________________________________
//===========================================================================
RangeType_t Range_GetPrefix(const int iArg, AddressPrefix_t* pAP)
{
if ((iArg + 1) >= MAX_ARGS)
return RANGE_NO_PREFIX;
if (g_aArgs[iArg + 1].eToken != TOKEN_FSLASH)
return RANGE_NO_PREFIX;
// Spec: (GH#451)
// [sN/][nn/][L<1|2>/][ROM/]<nnnn>
if (tolower(g_aArgs[iArg].sArg[0]) == 's') // slot
{
int len = strlen(g_aArgs[iArg].sArg);
pAP->nSlot = g_aArgs[iArg].sArg[len - 1] - '0'; // eg. s1 or sl1 or slot1
if (pAP->nSlot > 7)
{
ConsoleDisplayError("Address prefix out-of-range. Use slots 0-7.");
return RANGE_PREFIX_BAD;
}
}
else if (tolower(g_aArgs[iArg].sArg[0]) == 'l') // LC
{
int len = strlen(g_aArgs[iArg].sArg);
pAP->nLangCard = g_aArgs[iArg].sArg[len - 1] - '0'; // eg. l1 or lc1
if (pAP->nLangCard < 1 || pAP->nLangCard > 2)
{
ConsoleDisplayError("Address prefix out-of-range. Use lc 1 or 2.");
return RANGE_PREFIX_BAD;
}
}
else if (tolower(g_aArgs[iArg].sArg[0]) == 'r') // ROM
{
pAP->bIsROM = true;
}
else // bank (RamWorks or Saturn)
{
if (g_aArgs[iArg].nValue > 0x100) // Permit 00-100
{
ConsoleDisplayError("Address prefix out-of-range. Use bank 0-100 (or 0-7 for Saturn).");
return RANGE_PREFIX_BAD;
}
pAP->nBank = g_aArgs[iArg].nValue;
}
return RANGE_PREFIX_OK;
}
//===========================================================================
bool Range_GetAllPrefixes(int& iArg, const int nArg, int& dArgPrefix, AddressPrefix_t* pAP)
{
const int kArgsPerPrefix = 2;
for (int i = iArg; i < nArg; i += kArgsPerPrefix)
{
RangeType_t prefix = Range_GetPrefix(i, pAP);
if (prefix == RANGE_NO_PREFIX)
break;
if (prefix == RANGE_PREFIX_BAD)
return false;
dArgPrefix += kArgsPerPrefix;
iArg += kArgsPerPrefix; // done 1 prefix (2 args)
}
// Got all prefixes, so do some checks:
if (pAP->bIsROM &&
(pAP->nSlot != Breakpoint_t::kSlotInvalid || pAP->nBank != Breakpoint_t::kBankInvalid || pAP->nLangCard != Breakpoint_t::kLangCardInvalid))
{
ConsoleDisplayError("Address prefix bad: 'r/' not permitted with other prefixes.");
return false;
}
if (pAP->nSlot != Breakpoint_t::kSlotInvalid) // Currently setting a slot# means Saturn card
{
if (pAP->nBank != Breakpoint_t::kBankInvalid && pAP->nBank > 7)
{
ConsoleDisplayError("Address prefix bad: Saturn only supports banks 0-7.");
return false;
}
if (GetCardMgr().QuerySlot(pAP->nSlot) != CT_Saturn128K)
{
ConsoleDisplayError("Address prefix bad: No Saturn in slot.");
return false;
}
}
else // No slot# specified, so aux slot (for Extended 80Col or RamWorks card)
{
if (pAP->nBank != Breakpoint_t::kBankInvalid)
{
if (!IsAppleIIeOrAbove(GetApple2Type()))
{
ConsoleDisplayError("Address prefix bad: Aux slot requires //e or above.");
return false;
}
}
}
return true;
}
//===========================================================================
bool Range_CalcEndLen( const RangeType_t eRange
, const WORD & nAddress1, const WORD & nAddress2
, WORD & nAddressEnd_, int & nAddressLen_ )
{
bool bValid = false;
if (eRange == RANGE_HAS_LEN)
{
// BSAVE 2000,0 Len=0 End=n/a
// BSAVE 2000,1 Len=1 End=2000
// 0,FFFF [,)
// End = FFFE = Len-1
// Len = FFFF
nAddressLen_ = nAddress2;
unsigned int nTemp = nAddress1 + nAddressLen_ - 1;
if (nTemp > _6502_MEM_END)
nTemp = _6502_MEM_END;
nAddressEnd_ = nTemp;
bValid = true;
}
else
if (eRange == RANGE_HAS_END)
{
// BSAVE 2000:2000 Len=0, End=n/a
// BSAVE 2000:2001 Len=1, End=2000
// 0:FFFF [,]
// End = FFFF
// Len = 10000 = End+1
nAddressEnd_ = nAddress2;
nAddressLen_ = nAddress2 - nAddress1 + 1;
bValid = true;
}
return bValid;
}
//===========================================================================
RangeType_t Range_Get( WORD & nAddress1_, WORD & nAddress2_, const int iArg/* =1 */)
{
nAddress1_ = g_aArgs[ iArg ].nValue;
if (nAddress1_ > _6502_MEM_END)
nAddress1_ = _6502_MEM_END;
nAddress2_ = 0;
int nTemp = 0;
RangeType_t eRange = RANGE_MISSING_ARG_2;
if ((iArg + 2) >= MAX_ARGS)
return eRange;
if (g_aArgs[ iArg + 1 ].eToken == TOKEN_COMMA)
{
// 0,FFFF [,) // Note the mathematical range
// End = FFFE = Len-1
// Len = FFFF
eRange = RANGE_HAS_LEN;
nTemp = g_aArgs[ iArg + 2 ].nValue;
nAddress2_ = nTemp;
}
else
if (g_aArgs[ iArg + 1 ].eToken == TOKEN_COLON)
{
// 0:FFFF [,] // Note the mathematical range
// End = FFFF
// Len = 10000 = End+1
eRange = RANGE_HAS_END;
nTemp = g_aArgs[ iArg + 2 ].nValue;
// i.e.
// FFFF:D000
// 1 2 Temp
// FFFF D000
// FFFF
// D000
if (nAddress1_ > nTemp)
{
nAddress2_ = nAddress1_;
nAddress1_ = nTemp;
}
else
nAddress2_ = nTemp;
}
// .17 Bug Fix: D000,FFFF -> D000,CFFF (nothing searched!)
// if (nTemp > _6502_MEM_END)
// nTemp = _6502_MEM_END;
return eRange;
}