mirror of
https://github.com/AppleWin/AppleWin.git
synced 2026-04-21 23:16:39 +00:00
Add a Debugger breakpoint card (PR #1441)
. For AppleWin-Test regression tests for debugger breakpoints
This commit is contained in:
@@ -27,6 +27,7 @@ enum SS_CARDTYPE
|
||||
CT_Uthernet2,
|
||||
CT_MegaAudio, // Soundcard
|
||||
CT_SDMusic, // Soundcard
|
||||
CT_BreakpointCard,
|
||||
};
|
||||
|
||||
enum SLOTS { SLOT0=0, SLOT1, SLOT2, SLOT3, SLOT4, SLOT5, SLOT6, SLOT7, NUM_SLOTS, SLOT_AUX, GAME_IO_CONNECTOR };
|
||||
|
||||
@@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "CardManager.h"
|
||||
#include "Registry.h"
|
||||
|
||||
#include "BreakpointCard.h"
|
||||
#include "Disk.h"
|
||||
#include "FourPlay.h"
|
||||
#include "Harddisk.h"
|
||||
@@ -132,7 +133,9 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
|
||||
m_slot[slot] = new Saturn128K(slot, Saturn128K::kMaxSaturnBanks);
|
||||
}
|
||||
break;
|
||||
|
||||
case CT_BreakpointCard:
|
||||
m_slot[slot] = new BreakpointCard(slot);
|
||||
break;
|
||||
default:
|
||||
_ASSERT(0);
|
||||
break;
|
||||
|
||||
@@ -223,6 +223,10 @@ bool ProcessCmdLine(LPSTR lpCmdLine)
|
||||
g_cmdLine.slotInsert[slot] = CT_SDMusic;
|
||||
g_cmdLine.supportExtraMBCardTypes = true;
|
||||
}
|
||||
else if (strcmp(lpCmdLine, "breakpointcard") == 0)
|
||||
{
|
||||
g_cmdLine.slotInsert[slot] = CT_BreakpointCard;
|
||||
}
|
||||
else if (strcmp(lpCmdLine, "6522a-bad") == 0)
|
||||
{
|
||||
g_cmdLine.slotInfo[slot].useBad6522A = true;
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@ enum AppMode_e
|
||||
#define PATH_SEPARATOR '/'
|
||||
#endif
|
||||
|
||||
enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE};
|
||||
enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE, IS_BREAKPOINTCARD};
|
||||
|
||||
//
|
||||
#define APPLE2P_MASK 0x01
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
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-2025, 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
|
||||
*/
|
||||
/*
|
||||
Breakpoint card
|
||||
---------------
|
||||
|
||||
For debugger breakpoint regression tests.
|
||||
|
||||
C0n0 (R) : Status
|
||||
b7: BP match
|
||||
b6: BP mismatch
|
||||
b1: FIFO full
|
||||
b0: FIFO empty
|
||||
C0n1 (R) : Cmd: Reset
|
||||
Flush FIFO
|
||||
NB. don't change intercept mode
|
||||
C0n2 (R) : Cmd: Intercept BP by card
|
||||
C0n3 (R) : Cmd: Intercept BP by debugger
|
||||
C0nX (R) : ID byte $0X (except when X=0)
|
||||
|
||||
C0nX (W) : FIFO
|
||||
FIFO is 32 x 6 bytes deep
|
||||
where: 6-byte BP-set = {type.b, addrStart.w, addrEnd.w, access.b}
|
||||
|
||||
Any r/w clears the IRQ
|
||||
RESET clears the IRQ, flushes FIFO and sets: Intercept BP by card
|
||||
|
||||
Operation:
|
||||
. Cmd:Reset flushes FIFO & sets Status.empty=1 (all other bits are zero)
|
||||
. Cmd:Intercept BP by card
|
||||
. Write FIFO with multiple BP-sets for test code
|
||||
- these are the expected BP hit results
|
||||
. Status.full=1 after writing 32 BP-sets
|
||||
. Execute test code
|
||||
. AppleWin debugger:
|
||||
- Cmd:Intercept BP by card: when active, then debugger doesn't break on BP match
|
||||
- Instead debugger hands off BP to Breakpoint card (only 'bp' & 'bpm[r|w]')
|
||||
. Remove BP-set from front of FIFO
|
||||
- Check if it matches/mismatches and set status accordingly
|
||||
. Delay 1 cycle & assert IRQ
|
||||
. CPU vectors to IRQ handler
|
||||
. Reading Status clears IRQ
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "CardManager.h"
|
||||
#include "Core.h"
|
||||
#include "CPU.h"
|
||||
#include "Debug.h"
|
||||
#include "BreakpointCard.h"
|
||||
#include "Memory.h"
|
||||
|
||||
BreakpointCard::BreakpointCard(UINT slot) :
|
||||
Card(CT_BreakpointCard, slot),
|
||||
m_syncEvent(slot, 0, SyncEventCallback) // use slot# as "unique" id for Disk2InterfaceCards
|
||||
{
|
||||
Reset(true);
|
||||
}
|
||||
|
||||
BreakpointCard::~BreakpointCard()
|
||||
{
|
||||
if (m_syncEvent.m_active)
|
||||
g_SynchronousEventMgr.Remove(m_syncEvent.m_id);
|
||||
}
|
||||
|
||||
void BreakpointCard::Reset(const bool powerCycle)
|
||||
{
|
||||
m_interceptBPByCard = false;
|
||||
InterceptBreakpoints(m_slot, nullptr);
|
||||
ResetState();
|
||||
if (!powerCycle) // if called by ctor: CriticalSection not created yet
|
||||
CpuIrqDeassert(IS_BREAKPOINTCARD);
|
||||
}
|
||||
|
||||
void BreakpointCard::InitializeIO(LPBYTE pCxRomPeripheral)
|
||||
{
|
||||
RegisterIoHandler(m_slot, &BreakpointCard::IORead, &BreakpointCard::IOWrite, IO_Null, IO_Null, this, NULL);
|
||||
}
|
||||
|
||||
BYTE __stdcall BreakpointCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
|
||||
{
|
||||
const UINT slot = ((addr & 0xff) >> 4) - 8;
|
||||
BreakpointCard* pCard = (BreakpointCard*)MemGetSlotParameters(slot);
|
||||
|
||||
CpuIrqDeassert(IS_BREAKPOINTCARD);
|
||||
|
||||
const BYTE reg = addr & 0xf;
|
||||
if (reg == 0)
|
||||
{
|
||||
uint8_t otherStatus = pCard->m_BP_FIFO.empty() ? kEmpty : 0;
|
||||
return pCard->m_status | otherStatus;
|
||||
}
|
||||
else if (reg == 1) // Cmd: Reset
|
||||
{
|
||||
pCard->ResetState();
|
||||
}
|
||||
else if (reg == 2) // Cmd: Intercept BP by card
|
||||
{
|
||||
pCard->m_interceptBPByCard = true;
|
||||
InterceptBreakpoints(slot, BreakpointCard::CbFunction);
|
||||
}
|
||||
else if (reg == 3) // Cmd: Intercept BP by debugger
|
||||
{
|
||||
pCard->m_interceptBPByCard = false;
|
||||
InterceptBreakpoints(slot, nullptr);
|
||||
}
|
||||
|
||||
return addr & 0x0f; // ID bytes [$01-$0F]
|
||||
}
|
||||
|
||||
BYTE __stdcall BreakpointCard::IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
|
||||
{
|
||||
const UINT slot = ((addr & 0xff) >> 4) - 8;
|
||||
BreakpointCard* pCard = (BreakpointCard*)MemGetSlotParameters(slot);
|
||||
|
||||
CpuIrqDeassert(IS_BREAKPOINTCARD);
|
||||
|
||||
pCard->m_BPSet[pCard->m_BPSetIdx++] = value;
|
||||
|
||||
if (pCard->m_BPSetIdx == kNumParams)
|
||||
{
|
||||
pCard->m_BPSetIdx = 0;
|
||||
|
||||
if (!(pCard->m_status & kFull))
|
||||
{
|
||||
INTERCEPTBREAKPOINT bpSet;
|
||||
bpSet.type = pCard->m_BPSet[0];
|
||||
bpSet.addrStart = (pCard->m_BPSet[2] << 8) | pCard->m_BPSet[1];
|
||||
bpSet.addrEnd = (pCard->m_BPSet[4] << 8) | pCard->m_BPSet[3];
|
||||
bpSet.access = pCard->m_BPSet[5];
|
||||
|
||||
pCard->m_BP_FIFO.push(bpSet);
|
||||
}
|
||||
|
||||
if (pCard->m_BP_FIFO.size() == kFIFO_SIZE)
|
||||
pCard->m_status |= kFull;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BreakpointCard::CbFunction(uint8_t slot, INTERCEPTBREAKPOINT interceptBreakpoint)
|
||||
{
|
||||
BreakpointCard* pCard = (BreakpointCard*)MemGetSlotParameters(slot);
|
||||
|
||||
pCard->m_deferred = interceptBreakpoint;
|
||||
|
||||
// Defer processing the breakpoint by 1 opcode (ie. 1 cycle), otherwise this happens:
|
||||
// . BP occurs at <addr>, but opcode hasn't executed yet
|
||||
// . Breakpoint card aserts IRQ, and IRQ is taken by 6502
|
||||
// . 6502 executes ISR, and returns to <addr>
|
||||
// . BP occurs at <addr>...
|
||||
|
||||
pCard->m_syncEvent.m_cyclesRemaining = 1; // Next opcode
|
||||
g_SynchronousEventMgr.Insert(&pCard->m_syncEvent);
|
||||
}
|
||||
|
||||
int BreakpointCard::SyncEventCallback(int id, int cycles, ULONG uExecutedCycles)
|
||||
{
|
||||
BreakpointCard& card = dynamic_cast<BreakpointCard&>(GetCardMgr().GetRef(id));
|
||||
card.Deferred(card.m_deferred.type, card.m_deferred.addrStart, card.m_deferred.addrEnd, card.m_deferred.access);
|
||||
return 0; // Don't repeat event
|
||||
}
|
||||
|
||||
void BreakpointCard::Deferred(uint8_t type, uint16_t addrStart, uint16_t addrEnd, uint8_t access)
|
||||
{
|
||||
m_status &= ~(kMatch | kMismatch);
|
||||
|
||||
CpuIrqAssert(IS_BREAKPOINTCARD);
|
||||
|
||||
if (m_BP_FIFO.empty())
|
||||
{
|
||||
m_status |= kMismatch;
|
||||
return;
|
||||
}
|
||||
|
||||
const INTERCEPTBREAKPOINT bpSet = m_BP_FIFO.front();
|
||||
m_BP_FIFO.pop();
|
||||
m_status &= ~kFull;
|
||||
|
||||
if (bpSet.type != type)
|
||||
{
|
||||
m_status |= kMismatch;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case BPTYPE_PC:
|
||||
case BPTYPE_MEM:
|
||||
if ((bpSet.addrStart != addrStart) || (bpSet.access != access))
|
||||
{
|
||||
m_status |= kMismatch;
|
||||
break;
|
||||
}
|
||||
m_status |= kMatch;
|
||||
break;
|
||||
case BPTYPE_DMA:
|
||||
{
|
||||
bool validAddr = ((addrStart >= bpSet.addrStart && addrStart < bpSet.addrEnd) ||
|
||||
(bpSet.addrStart >= addrStart && bpSet.addrStart < addrEnd));
|
||||
if (!validAddr || (bpSet.access != access))
|
||||
{
|
||||
m_status |= kMismatch;
|
||||
break;
|
||||
}
|
||||
m_status |= kMatch;
|
||||
}
|
||||
break;
|
||||
case BPTYPE_UNKNOWN:
|
||||
default:
|
||||
m_status |= kMismatch;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include "Card.h"
|
||||
#include "Interface.h"
|
||||
#include "SynchronousEventManager.h"
|
||||
|
||||
enum BreakType_t { BPTYPE_UNKNOWN, BPTYPE_PC, BPTYPE_MEM, BPTYPE_DMA };
|
||||
enum BreakAccess_t { BPACCESS_R, BPACCESS_W, BPACCESS_RW };
|
||||
|
||||
struct INTERCEPTBREAKPOINT
|
||||
{
|
||||
INTERCEPTBREAKPOINT()
|
||||
{
|
||||
type = BPTYPE_UNKNOWN;
|
||||
addrStart = 0x0000;
|
||||
addrEnd = 0x0000;
|
||||
access = BPACCESS_R;
|
||||
}
|
||||
|
||||
void Set(uint8_t type_, uint16_t addrStart_, uint8_t access_)
|
||||
{
|
||||
type = type_;
|
||||
addrStart = addrStart_;
|
||||
access = access_;
|
||||
}
|
||||
|
||||
void SetDMA(uint16_t addrStart_, uint16_t addrEnd_, uint8_t access_)
|
||||
{
|
||||
type = BPTYPE_DMA;
|
||||
addrStart = addrStart_;
|
||||
addrEnd = addrEnd_;
|
||||
access = access_;
|
||||
}
|
||||
|
||||
uint8_t type;
|
||||
uint16_t addrStart;
|
||||
uint16_t addrEnd;
|
||||
uint8_t access;
|
||||
};
|
||||
|
||||
|
||||
class BreakpointCard : public Card
|
||||
{
|
||||
public:
|
||||
BreakpointCard(UINT slot);
|
||||
virtual ~BreakpointCard(void);
|
||||
|
||||
void ResetState()
|
||||
{
|
||||
m_BPSetIdx = 0;
|
||||
m_status = 0;
|
||||
while (!m_BP_FIFO.empty())
|
||||
m_BP_FIFO.pop();
|
||||
}
|
||||
|
||||
virtual void Destroy(void) {}
|
||||
virtual void Reset(const bool powerCycle);
|
||||
virtual void Update(const ULONG nExecutedCycles) {}
|
||||
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||
|
||||
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
||||
static BYTE __stdcall IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
||||
|
||||
static void CbFunction(uint8_t slot, INTERCEPTBREAKPOINT interceptBreakpoint);
|
||||
|
||||
virtual void SaveSnapshot(YamlSaveHelper& yamlSaveHelper) {}
|
||||
virtual bool LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) { return false; }
|
||||
|
||||
private:
|
||||
static int SyncEventCallback(int id, int cycles, ULONG uExecutedCycles);
|
||||
void Deferred(uint8_t type, uint16_t addrStart, uint16_t addrEnd, uint8_t access);
|
||||
|
||||
static const uint8_t kMatch = 1 << 7;
|
||||
static const uint8_t kMismatch = 1 << 6;
|
||||
static const uint8_t kFull = 1 << 1;
|
||||
static const uint8_t kEmpty = 1 << 0;
|
||||
uint8_t m_status;
|
||||
|
||||
bool m_interceptBPByCard;
|
||||
|
||||
static const uint8_t kNumParams = 6; // sizeof(packed(INTERCEPTBREAKPOINT))
|
||||
BYTE m_BPSet[kNumParams];
|
||||
BYTE m_BPSetIdx;
|
||||
|
||||
static const uint8_t kFIFO_SIZE = 32; // needs to be big enough for each test's set of BPs
|
||||
std::queue<INTERCEPTBREAKPOINT> m_BP_FIFO;
|
||||
|
||||
INTERCEPTBREAKPOINT m_deferred;
|
||||
SyncEvent m_syncEvent;
|
||||
};
|
||||
@@ -87,6 +87,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
static int g_bDebugBreakpointHit = 0; // See: BreakpointHit_t
|
||||
static Breakpoint_t *g_pDebugBreakpointHit = nullptr;
|
||||
|
||||
static WORD g_nBreakMemoryAddr = 0;
|
||||
static std::string g_sBreakMemoryFullPrefixAddr;
|
||||
static int g_breakpointHitID = -1;
|
||||
|
||||
@@ -363,6 +364,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
static std::string g_sAutoRunScriptFilename("DebuggerAutoRun.txt");
|
||||
|
||||
static uint8_t g_interceptBreakpointsSlot = 0;
|
||||
static CBFUNCTION g_InterceptBreakpointsCB = nullptr;
|
||||
|
||||
// Private ________________________________________________________________________________________
|
||||
|
||||
|
||||
@@ -1429,6 +1433,7 @@ int CheckBreakpointsIO ()
|
||||
{
|
||||
if (_CheckBreakpointValue( pBP, nAddress ))
|
||||
{
|
||||
g_nBreakMemoryAddr = (WORD)nAddress; // last BP hit
|
||||
g_sBreakMemoryFullPrefixAddr = GetFullPrefixAddrForBreakpoint(pBP->addrPrefix, (WORD)nAddress, DEVICE_e::DEV_MEMORY, false); // string is last BP hit
|
||||
BYTE opcode = ReadByteFromMemory(regs.pc);
|
||||
|
||||
@@ -9103,6 +9108,7 @@ void DebugContinueStepping (const bool bCallerWillUpdateDisplay/*=false*/)
|
||||
{
|
||||
std::string stopReason = "Unknown!";
|
||||
bool skipStopReason = false;
|
||||
INTERCEPTBREAKPOINT interceptBreakpoint;
|
||||
|
||||
if (regs.pc == g_nDebugStepUntil)
|
||||
stopReason = StrFormat( CHC_DEFAULT "Register " CHC_REGS "PC" CHC_DEFAULT " matches '" CHC_INFO "Go until" CHC_DEFAULT "' address $" CHC_ADDRESS "%04X", g_nDebugStepUntil);
|
||||
@@ -9120,14 +9126,25 @@ void DebugContinueStepping (const bool bCallerWillUpdateDisplay/*=false*/)
|
||||
g_aBreakpointSource[ g_pDebugBreakpointHit->eSource ],
|
||||
CHC_DEFAULT
|
||||
);
|
||||
if (g_pDebugBreakpointHit->eSource == BP_SRC_REG_PC)
|
||||
interceptBreakpoint.Set(BPTYPE_PC, regs.pc, BPACCESS_R);
|
||||
}
|
||||
}
|
||||
else if (g_bDebugBreakpointHit & BP_HIT_MEM)
|
||||
{
|
||||
stopReason = StrFormat("Memory access at %s", g_sBreakMemoryFullPrefixAddr.c_str());
|
||||
interceptBreakpoint.Set(BPTYPE_MEM, g_nBreakMemoryAddr, BPACCESS_RW);
|
||||
}
|
||||
else if (g_bDebugBreakpointHit & BP_HIT_MEMW)
|
||||
{
|
||||
stopReason = StrFormat("Write access at %s", g_sBreakMemoryFullPrefixAddr.c_str());
|
||||
interceptBreakpoint.Set(BPTYPE_MEM, g_nBreakMemoryAddr, BPACCESS_W);
|
||||
}
|
||||
else if (g_bDebugBreakpointHit & BP_HIT_MEMR)
|
||||
{
|
||||
stopReason = StrFormat("Read access at %s", g_sBreakMemoryFullPrefixAddr.c_str());
|
||||
interceptBreakpoint.Set(BPTYPE_MEM, g_nBreakMemoryAddr, BPACCESS_R);
|
||||
}
|
||||
else if (g_bDebugBreakpointHit & BP_HIT_PC_READ_FLOATING_BUS_OR_IO_MEM)
|
||||
stopReason = "PC reads from floating bus or I/O memory";
|
||||
else if (g_bDebugBreakpointHit & BP_HIT_INTERRUPT)
|
||||
@@ -9144,6 +9161,9 @@ void DebugContinueStepping (const bool bCallerWillUpdateDisplay/*=false*/)
|
||||
|
||||
if (!skipStopReason)
|
||||
{
|
||||
if (g_InterceptBreakpointsCB != nullptr)
|
||||
g_InterceptBreakpointsCB(g_interceptBreakpointsSlot, interceptBreakpoint);
|
||||
|
||||
std::string hitId = GetBreakpointHitIdString(g_breakpointHitID);
|
||||
ConsolePrintFormat(CHC_INFO "Stop reason: %s " CHC_DEFAULT "%s", hitId.c_str(), stopReason.c_str());
|
||||
g_breakpointHitID = -1;
|
||||
@@ -9160,12 +9180,22 @@ void DebugContinueStepping (const bool bCallerWillUpdateDisplay/*=false*/)
|
||||
stopReason = StrFormat("HDD DMA from memory " CHC_ARG_SEP "$" CHC_ADDRESS "%04X" CHC_ARG_SEP "-" CHC_ADDRESS "%04X", g_DebugBreakOnDMA[i].memoryAddr, g_DebugBreakOnDMA[i].memoryAddrEnd);
|
||||
std::string hitId = GetBreakpointHitIdString(g_DebugBreakOnDMA[i].BPid);
|
||||
ConsolePrintFormat(CHC_INFO "Stop reason: %s " CHC_DEFAULT "%s", hitId.c_str(), stopReason.c_str());
|
||||
|
||||
if (g_InterceptBreakpointsCB != nullptr)
|
||||
{
|
||||
const uint8_t access = (nDebugBreakpointHit & BP_DMA_FROM_MEM) ? BPACCESS_R : BPACCESS_W;
|
||||
interceptBreakpoint.SetDMA(g_DebugBreakOnDMA[i].memoryAddr, g_DebugBreakOnDMA[i].memoryAddrEnd, access);
|
||||
g_InterceptBreakpointsCB(g_interceptBreakpointsSlot, interceptBreakpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleUpdate();
|
||||
|
||||
g_nDebugSteps = 0;
|
||||
//
|
||||
|
||||
if (g_InterceptBreakpointsCB == nullptr)
|
||||
g_nDebugSteps = 0;
|
||||
}
|
||||
|
||||
if (g_nDebugSteps > 0)
|
||||
@@ -9286,6 +9316,7 @@ void DebugInitialize ()
|
||||
WindowUpdateConsoleDisplayedSize();
|
||||
|
||||
// CLEAR THE BREAKPOINT AND WATCH TABLES
|
||||
g_nBreakMemoryAddr = 0;
|
||||
g_breakpointHitID = -1;
|
||||
for (int i = 0; i < MAX_BREAKPOINTS; i++)
|
||||
g_aBreakpoints[i].Clear();
|
||||
@@ -10126,3 +10157,11 @@ void DebugSetAutoRunScript (std::string& sAutoRunScriptFilename)
|
||||
{
|
||||
g_sAutoRunScriptFilename = sAutoRunScriptFilename;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void InterceptBreakpoints(uint8_t slot, CBFUNCTION cbfunction)
|
||||
{
|
||||
g_interceptBreakpointsSlot = slot;
|
||||
g_InterceptBreakpointsCB = cbfunction;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Debugger_Display.h"
|
||||
#include "Debugger_Symbols.h"
|
||||
#include "Util_MemoryTextFile.h"
|
||||
#include "BreakpointCard.h"
|
||||
|
||||
// Globals __________________________________________________________________
|
||||
|
||||
@@ -191,3 +192,6 @@
|
||||
|
||||
void ClearTempBreakpoints();
|
||||
void DebugSetAutoRunScript(std::string& sAutoRunScriptFilename);
|
||||
|
||||
typedef void(*CBFUNCTION)(uint8_t slot, INTERCEPTBREAKPOINT interceptBreakpoint);
|
||||
void InterceptBreakpoints(uint8_t slot, CBFUNCTION cbfunction);
|
||||
|
||||
Reference in New Issue
Block a user