mirror of
https://github.com/AppleWin/AppleWin.git
synced 2025-01-03 11:30:22 +00:00
When the debugger is active (eg. breakpoints enabled) then trap on HDD r/w's that match the BPM[R|W]. NB. the breakpoint will fire after the whole HDD r/w operation has completed.
This commit is contained in:
parent
a1f6ebe1c9
commit
22065c6325
@ -68,8 +68,20 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
int g_nDebugBreakOnInvalid = 0; // Bit Flags of Invalid Opcode to break on: // iOpcodeType = AM_IMPLIED (BRK), AM_1, AM_2, AM_3
|
||||
int g_iDebugBreakOnOpcode = 0;
|
||||
bool g_bDebugBreakOnInterrupt = false;
|
||||
static int g_iDebugBreakOnDmaToOrFromIoMemory = 0;
|
||||
static WORD g_uDebugBreakOnDmaIoMemoryAddr = 0;
|
||||
|
||||
struct DebugBreakOnDMA
|
||||
{
|
||||
DebugBreakOnDMA() : isToOrFromMemory(0), memoryAddr(0), memoryAddrEnd(0), BPid(0) {}
|
||||
|
||||
int isToOrFromMemory;
|
||||
WORD memoryAddr;
|
||||
WORD memoryAddrEnd;
|
||||
int BPid;
|
||||
};
|
||||
|
||||
static const uint32_t NUM_BREAK_ON_DMA = 3; // A 512-byte block misaligned touching 3 pages
|
||||
static DebugBreakOnDMA g_DebugBreakOnDMA[NUM_BREAK_ON_DMA];
|
||||
static DebugBreakOnDMA g_DebugBreakOnDMAIO;
|
||||
|
||||
static int g_bDebugBreakpointHit = 0; // See: BreakpointHit_t
|
||||
|
||||
@ -1118,7 +1130,7 @@ bool _CheckBreakpointValue( Breakpoint_t *pBP, int nVal )
|
||||
if ((nVal >= pBP->nAddress) && ((UINT)nVal < (pBP->nAddress + pBP->nLength)))
|
||||
bStatus = true;
|
||||
break;
|
||||
case BP_OP_NOT_EQUAL : // Rnage is: (,] (not-inclusive, inclusive)
|
||||
case BP_OP_NOT_EQUAL : // Range is: (,] (not-inclusive, inclusive)
|
||||
if ((nVal < pBP->nAddress) || ((UINT)nVal >= (pBP->nAddress + pBP->nLength)))
|
||||
bStatus = true;
|
||||
break;
|
||||
@ -1137,6 +1149,53 @@ bool _CheckBreakpointValue( Breakpoint_t *pBP, int nVal )
|
||||
return bStatus;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
bool _CheckBreakpointRange(Breakpoint_t* pBP, int nVal, int nSize)
|
||||
{
|
||||
bool bStatus = false;
|
||||
|
||||
int iCmp = pBP->eOperator;
|
||||
switch (iCmp)
|
||||
{
|
||||
case BP_OP_EQUAL: // Range is like C++ STL: [,) (inclusive,not-inclusive)
|
||||
if ( ((nVal >= pBP->nAddress) && ((UINT)nVal < (pBP->nAddress + pBP->nLength))) ||
|
||||
((pBP->nAddress >= nVal) && (pBP->nAddress < ((UINT)nVal + nSize))) )
|
||||
bStatus = true;
|
||||
break;
|
||||
default:
|
||||
_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return bStatus;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
void DebuggerBreakOnDma(WORD nAddress, WORD nSize, bool isDmaToMemory, int iBreakpoint);
|
||||
|
||||
bool DebuggerCheckMemBreakpoints(WORD nAddress, WORD nSize, bool isDmaToMemory)
|
||||
{
|
||||
// NB. Caller handles when (addr+size) wraps on 64K
|
||||
|
||||
for (int iBreakpoint = 0; iBreakpoint < MAX_BREAKPOINTS; iBreakpoint++)
|
||||
{
|
||||
Breakpoint_t* pBP = &g_aBreakpoints[iBreakpoint];
|
||||
if (_BreakpointValid(pBP))
|
||||
{
|
||||
if (pBP->eSource == BP_SRC_MEM_RW || (pBP->eSource == BP_SRC_MEM_READ_ONLY && !isDmaToMemory) || (pBP->eSource == BP_SRC_MEM_WRITE_ONLY && isDmaToMemory))
|
||||
{
|
||||
if (_CheckBreakpointRange(pBP, nAddress, nSize))
|
||||
{
|
||||
DebuggerBreakOnDma(nAddress, nSize, isDmaToMemory, iBreakpoint);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
int CheckBreakpointsIO ()
|
||||
@ -1272,17 +1331,53 @@ void ClearTempBreakpoints ()
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
static int CheckBreakpointsDmaToOrFromIoMemory(void)
|
||||
static int CheckBreakpointsDmaToOrFromIOMemory(void)
|
||||
{
|
||||
int res = g_iDebugBreakOnDmaToOrFromIoMemory;
|
||||
g_iDebugBreakOnDmaToOrFromIoMemory = 0;
|
||||
int res = g_DebugBreakOnDMAIO.isToOrFromMemory;
|
||||
g_DebugBreakOnDMAIO.isToOrFromMemory = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
void DebuggerBreakOnDmaToOrFromIoMemory(WORD addr, bool isDmaToMemory)
|
||||
void DebuggerBreakOnDmaToOrFromIoMemory(WORD nAddress, bool isDmaToMemory)
|
||||
{
|
||||
g_iDebugBreakOnDmaToOrFromIoMemory = isDmaToMemory ? BP_DMA_TO_IO_MEM : BP_DMA_FROM_IO_MEM;
|
||||
g_uDebugBreakOnDmaIoMemoryAddr = addr;
|
||||
g_DebugBreakOnDMAIO.isToOrFromMemory = isDmaToMemory ? BP_DMA_TO_IO_MEM : BP_DMA_FROM_IO_MEM;
|
||||
g_DebugBreakOnDMAIO.memoryAddr = nAddress;
|
||||
}
|
||||
|
||||
static int CheckBreakpointsDmaToOrFromMemory(int idx)
|
||||
{
|
||||
if (idx == -1)
|
||||
{
|
||||
int res = 0;
|
||||
for (int i = 0; i < NUM_BREAK_ON_DMA; i++)
|
||||
res |= g_DebugBreakOnDMA[i].isToOrFromMemory;
|
||||
return res;
|
||||
}
|
||||
|
||||
_ASSERT(idx < NUM_BREAK_ON_DMA);
|
||||
if (idx >= NUM_BREAK_ON_DMA)
|
||||
return 0;
|
||||
|
||||
int res = g_DebugBreakOnDMA[idx].isToOrFromMemory;
|
||||
g_DebugBreakOnDMA[idx].isToOrFromMemory = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void DebuggerBreakOnDma(WORD nAddress, WORD nSize, bool isDmaToMemory, int iBreakpoint)
|
||||
{
|
||||
for (int i = 0; i < NUM_BREAK_ON_DMA; i++)
|
||||
{
|
||||
if (g_DebugBreakOnDMA[i].isToOrFromMemory != 0)
|
||||
continue;
|
||||
|
||||
g_DebugBreakOnDMA[i].isToOrFromMemory = isDmaToMemory ? BP_DMA_TO_MEM : BP_DMA_FROM_MEM;
|
||||
g_DebugBreakOnDMA[i].memoryAddr = nAddress;
|
||||
g_DebugBreakOnDMA[i].memoryAddrEnd = nAddress + nSize - 1;
|
||||
g_DebugBreakOnDMA[i].BPid = iBreakpoint;
|
||||
return;
|
||||
}
|
||||
|
||||
_ASSERT(0);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
@ -8279,12 +8374,13 @@ void DebugContinueStepping(const bool bCallerWillUpdateDisplay/*=false*/)
|
||||
g_bDebugBreakpointHit |= BP_HIT_INTERRUPT;
|
||||
}
|
||||
|
||||
g_bDebugBreakpointHit |= CheckBreakpointsIO() | CheckBreakpointsReg() | CheckBreakpointsDmaToOrFromIoMemory();
|
||||
g_bDebugBreakpointHit |= CheckBreakpointsIO() | CheckBreakpointsReg() | CheckBreakpointsDmaToOrFromIOMemory() | CheckBreakpointsDmaToOrFromMemory(-1);
|
||||
}
|
||||
|
||||
if (regs.pc == g_nDebugStepUntil || g_bDebugBreakpointHit)
|
||||
{
|
||||
std::string stopReason = "Unknown!";
|
||||
bool skipStopReason = false;
|
||||
|
||||
if (regs.pc == g_nDebugStepUntil)
|
||||
stopReason = "PC matches 'Go until' address";
|
||||
@ -8305,11 +8401,28 @@ void DebugContinueStepping(const bool bCallerWillUpdateDisplay/*=false*/)
|
||||
else if (g_bDebugBreakpointHit & BP_HIT_INTERRUPT)
|
||||
stopReason = StrFormat("Interrupt occurred at $%04X", g_LBR);
|
||||
else if (g_bDebugBreakpointHit & BP_DMA_TO_IO_MEM)
|
||||
stopReason = StrFormat("HDD DMA to I/O memory or ROM $%04X", g_uDebugBreakOnDmaIoMemoryAddr);
|
||||
stopReason = StrFormat("HDD DMA to I/O memory or ROM at $%04X", g_DebugBreakOnDMAIO.memoryAddr);
|
||||
else if (g_bDebugBreakpointHit & BP_DMA_FROM_IO_MEM)
|
||||
stopReason = StrFormat("HDD DMA from I/O memory $%04X", g_uDebugBreakOnDmaIoMemoryAddr);
|
||||
stopReason = StrFormat("HDD DMA from I/O memory at $%04X ", g_DebugBreakOnDMAIO.memoryAddr);
|
||||
else if (g_bDebugBreakpointHit & (BP_DMA_FROM_MEM | BP_DMA_TO_MEM))
|
||||
skipStopReason = true;
|
||||
|
||||
if (!skipStopReason)
|
||||
ConsoleBufferPushFormat( "Stop reason: %s", stopReason.c_str() );
|
||||
|
||||
for (int i = 0; i < NUM_BREAK_ON_DMA; i++)
|
||||
{
|
||||
int nDebugBreakpointHit = CheckBreakpointsDmaToOrFromMemory(i);
|
||||
if (nDebugBreakpointHit)
|
||||
{
|
||||
if (nDebugBreakpointHit & BP_DMA_TO_MEM)
|
||||
stopReason = StrFormat("HDD DMA to memory $%04X-%04X (BP#%d)", g_DebugBreakOnDMA[i].memoryAddr, g_DebugBreakOnDMA[i].memoryAddrEnd, g_DebugBreakOnDMA[i].BPid);
|
||||
else if (nDebugBreakpointHit & BP_DMA_FROM_MEM)
|
||||
stopReason = StrFormat("HDD DMA from memory $%04X-%04X (BP#%d)", g_DebugBreakOnDMA[i].memoryAddr, g_DebugBreakOnDMA[i].memoryAddrEnd, g_DebugBreakOnDMA[i].BPid);
|
||||
ConsoleBufferPushFormat("Stop reason: %s", stopReason.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleBufferPushFormat( "Stop reason: %s", stopReason.c_str() );
|
||||
ConsoleUpdate();
|
||||
|
||||
g_nDebugSteps = 0;
|
||||
|
@ -41,6 +41,8 @@
|
||||
, BP_HIT_INTERRUPT = (1 << 7)
|
||||
, BP_DMA_TO_IO_MEM = (1 << 8)
|
||||
, BP_DMA_FROM_IO_MEM = (1 << 9)
|
||||
, BP_DMA_TO_MEM = (1 << 10)
|
||||
, BP_DMA_FROM_MEM = (1 << 11)
|
||||
};
|
||||
|
||||
extern int g_nBreakpoints;
|
||||
@ -183,4 +185,5 @@
|
||||
void DebuggerMouseClick( int x, int y );
|
||||
|
||||
bool IsDebugSteppingAtFullSpeed(void);
|
||||
void DebuggerBreakOnDmaToOrFromIoMemory(WORD addr, bool isDmaToMemory);
|
||||
void DebuggerBreakOnDmaToOrFromIoMemory(WORD nAddress, bool isDmaToMemory);
|
||||
bool DebuggerCheckMemBreakpoints(WORD nAddress, WORD nSize, bool isDmaToMemory);
|
||||
|
@ -520,9 +520,18 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
||||
UINT size = PAGE_SIZE - (dstAddr & 0xff);
|
||||
if (size > remaining) size = remaining; // clip the last memcpy for the unaligned case
|
||||
|
||||
if (g_nAppMode == MODE_STEPPING)
|
||||
{
|
||||
if (DebuggerCheckMemBreakpoints(dstAddr, size, true)) // GH#1103
|
||||
{
|
||||
// BP hit
|
||||
pCard->m_notBusyCycle = 0; // DMA complete
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(page + (dstAddr & 0xff), pSrc, size);
|
||||
pSrc += size;
|
||||
dstAddr += size;
|
||||
dstAddr = (dstAddr + size) & (MEMORY_LENGTH-1); // wraps at 64KiB boundary
|
||||
|
||||
remaining -= size;
|
||||
}
|
||||
@ -545,6 +554,7 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
||||
pHDD->m_status_next = DISK_STATUS_WRITE; // or DISK_STATUS_PROT if we ever enable write-protect on HDD
|
||||
bool bRes = true;
|
||||
const bool bAppendBlocks = (pHDD->m_diskblock * HD_BLOCK_SIZE) >= ImageGetImageSize(pHDD->m_imagehandle);
|
||||
bool breakpointHit = false;
|
||||
|
||||
if (bAppendBlocks)
|
||||
{
|
||||
@ -576,15 +586,28 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pHDD->m_memblock <= (MEMORY_LENGTH - HD_BLOCK_SIZE))
|
||||
UINT size = HD_BLOCK_SIZE;
|
||||
WORD srcAddr = pHDD->m_memblock;
|
||||
BYTE* pDst = pHDD->m_buf;
|
||||
|
||||
if (pHDD->m_memblock > (MEMORY_LENGTH - HD_BLOCK_SIZE)) // wraps at 64KiB boundary (GH#1007)
|
||||
size = MEMORY_LENGTH - pHDD->m_memblock;
|
||||
|
||||
if (g_nAppMode == MODE_STEPPING)
|
||||
breakpointHit = DebuggerCheckMemBreakpoints(srcAddr, size, false);
|
||||
|
||||
memcpy(pDst, mem + srcAddr, size);
|
||||
|
||||
if (HD_BLOCK_SIZE != size)
|
||||
{
|
||||
memcpy(pHDD->m_buf, mem + pHDD->m_memblock, HD_BLOCK_SIZE);
|
||||
}
|
||||
else // wraps on 64KiB boundary (GH#1007)
|
||||
{
|
||||
const UINT size = MEMORY_LENGTH - pHDD->m_memblock;
|
||||
memcpy(pHDD->m_buf, mem + pHDD->m_memblock, size);
|
||||
memcpy(pHDD->m_buf + size, mem, HD_BLOCK_SIZE - size);
|
||||
pDst += size;
|
||||
size = HD_BLOCK_SIZE - size;
|
||||
srcAddr = 0x0000; // wrap around to 0x0000
|
||||
|
||||
if (g_nAppMode == MODE_STEPPING)
|
||||
breakpointHit = DebuggerCheckMemBreakpoints(srcAddr, size, false);
|
||||
|
||||
memcpy(pDst, mem + srcAddr, size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,7 +618,9 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
||||
{
|
||||
pHDD->m_error = 0;
|
||||
r = 0;
|
||||
pCard->m_notBusyCycle = g_nCumulativeCycles + (UINT64)CYCLES_FOR_DMA_RW_BLOCK;
|
||||
|
||||
if (!breakpointHit)
|
||||
pCard->m_notBusyCycle = g_nCumulativeCycles + (UINT64)CYCLES_FOR_DMA_RW_BLOCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user