diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 020e2e6b..b4020ba5 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -114,6 +114,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA "M", // Mem RW "M", // Mem READ_ONLY "M", // Mem WRITE_ONLY + // Watches + "M", // Memory + "V", // Video Scanner // TODO: M0 ram bank 0, M1 aux ram ? }; @@ -6655,7 +6658,7 @@ Update_t CmdWatch (int nArgs) //=========================================================================== Update_t CmdWatchAdd (int nArgs) { - // WA [adddress] + // WA [address] // WA # address if (! nArgs) { @@ -6673,6 +6676,18 @@ Update_t CmdWatchAdd (int nArgs) bool bAdded = false; for (; iArg <= nArgs; iArg++ ) { + if (g_aArgs[iArg].eToken == TOKEN_ALPHANUMERIC && g_aArgs[iArg].sArg[0] == 'v') // 'video' ? + { + g_aWatches[iWatch].bSet = true; + g_aWatches[iWatch].bEnabled = true; + g_aWatches[iWatch].eSource = BP_SRC_VIDEO_SCANNER; + g_aWatches[iWatch].nAddress = 0xDEAD; + bAdded = true; + g_nWatches++; + iWatch++; + continue; + } + WORD nAddress = g_aArgs[iArg].nValue; // Make sure address isn't an IO address @@ -6698,6 +6713,7 @@ Update_t CmdWatchAdd (int nArgs) { g_aWatches[iWatch].bSet = true; g_aWatches[iWatch].bEnabled = true; + g_aWatches[iWatch].eSource = BP_SRC_MEMORY; g_aWatches[iWatch].nAddress = (WORD) nAddress; bAdded = true; g_nWatches++; diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 74fea238..a6184a71 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -2767,7 +2767,7 @@ void DrawWatches (int line) #if DEBUG_FORCE_DISPLAY // Watch if (true) #else - if (g_aWatches[iWatch].bEnabled) + if (g_aWatches[iWatch].bEnabled && g_aWatches[iWatch].eSource == BP_SRC_MEMORY) #endif { RECT rect2 = rect; @@ -2779,40 +2779,32 @@ void DrawWatches (int line) DebuggerSetColorFG( DebuggerGetColor( FG_INFO_BULLET )); PrintTextCursorX( StrFormat( "%X ", iWatch ).c_str(), rect2 ); -// DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); -// PrintTextCursorX( ".", rect2 ); - DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_ADDRESS )); PrintTextCursorX( WordToHexStr( g_aWatches[iWatch].nAddress ).c_str(), rect2 ); DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); PrintTextCursorX( ":", rect2 ); - BYTE nTarget8 = 0; + // - nTarget8 = (unsigned)*(LPBYTE)(mem+g_aWatches[iWatch].nAddress); + BYTE nTargetL = *(LPBYTE)(mem + g_aWatches[iWatch].nAddress); DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); - PrintTextCursorX( ByteToHexStr( nTarget8 ).c_str(), rect2 ); + PrintTextCursorX( ByteToHexStr( nTargetL ).c_str(), rect2 ); - nTarget8 = (unsigned)*(LPBYTE)(mem+g_aWatches[iWatch].nAddress + 1); + BYTE nTargetH = *(LPBYTE)(mem + ((g_aWatches[iWatch].nAddress + 1) & 0xffff)); DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); - PrintTextCursorX( ByteToHexStr( nTarget8 ).c_str(), rect2 ); + PrintTextCursorX( ByteToHexStr( nTargetH ).c_str(), rect2 ); DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); PrintTextCursorX( "(", rect2 ); - WORD nTarget16 = (unsigned)*(LPWORD)(mem+g_aWatches[iWatch].nAddress); + WORD nTarget16 = (((WORD)nTargetH) << 8) | ((WORD)nTargetL); DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); PrintTextCursorX( WordToHexStr( nTarget16 ).c_str(), rect2 ); DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); -// PrintTextCursorX( ":", rect2 ); PrintTextCursorX( ")", rect2 ); -// BYTE nValue8 = *(LPBYTE)(mem + nTarget16); -// DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); -// PrintTextCursorX( ByteToHexStr( nValue8 ).c_str(), rect2 ); - rect.top += g_nFontHeight; rect.bottom += g_nFontHeight; @@ -2836,6 +2828,54 @@ void DrawWatches (int line) PrintTextCursorX( ByteToHexStr( nValue8 ).c_str(), rect2 ); } } + else if (g_aWatches[iWatch].bEnabled && g_aWatches[iWatch].eSource == BP_SRC_VIDEO_SCANNER) + { + uint32_t data; + int dataSize; + g_aWatches[iWatch].nAddress = NTSC_GetScannerAddressAndData(data, dataSize); + + RECT rect2 = rect; + + DebuggerSetColorBG(DebuggerGetColor(BG_INFO_WATCH)); + DebuggerSetColorFG(DebuggerGetColor(FG_INFO_TITLE)); + PrintTextCursorX("W", rect2); + + DebuggerSetColorFG(DebuggerGetColor(FG_INFO_BULLET)); + PrintTextCursorX(StrFormat("%X ", iWatch).c_str(), rect2); + + DebuggerSetColorFG(DebuggerGetColor(FG_DISASM_ADDRESS)); + PrintTextCursorX(WordToHexStr(g_aWatches[iWatch].nAddress).c_str(), rect2); + + DebuggerSetColorFG(DebuggerGetColor(FG_INFO_OPERATOR)); + PrintTextCursorX(":", rect2); + + DebuggerSetColorFG(DebuggerGetColor(FG_INFO_OPCODE)); + if (dataSize == 1) + { + PrintTextCursorX(ByteToHexStr(data).c_str(), rect2); + } + else if (dataSize == 2) + { + PrintTextCursorX("a:", rect2); + PrintTextCursorX(ByteToHexStr(data>>8).c_str(), rect2); + PrintTextCursorX(" m:", rect2); + PrintTextCursorX(ByteToHexStr(data).c_str(), rect2); + } + else + { + _ASSERT(dataSize == 4); + PrintTextCursorX(DWordToHexStr(data).c_str(), rect2); + } + + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; + } + else + { + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; + } + rect.top += g_nFontHeight; rect.bottom += g_nFontHeight; } diff --git a/source/Debugger/Debugger_Types.h b/source/Debugger/Debugger_Types.h index b52110ed..d42a570d 100644 --- a/source/Debugger/Debugger_Types.h +++ b/source/Debugger/Debugger_Types.h @@ -184,6 +184,9 @@ BP_SRC_MEM_READ_ONLY, BP_SRC_MEM_WRITE_ONLY, + BP_SRC_MEMORY, // For watches + BP_SRC_VIDEO_SCANNER, // For watches + NUM_BREAKPOINT_SOURCES }; @@ -516,7 +519,7 @@ , CMD_VIEW_DHGR2 , CMD_VIEW_SHR // Watch - , CMD_WATCH // TODO: Deprecated ? + , CMD_WATCH , CMD_WATCH_ADD , CMD_WATCH_CLEAR , CMD_WATCH_DISABLE diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 29d35ba3..9c646de5 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -869,6 +869,16 @@ INLINE uint16_t getVideoScannerAddressHGR() return nAddress; } +//=========================================================================== +INLINE uint16_t getVideoScannerAddressSHR() +{ + // 2 pixels per byte in 320-pixel mode = 160 bytes/scanline + // 4 pixels per byte in 640-pixel mode = 160 bytes/scanline + const UINT kBytesPerScanline = 160; + const UINT kBytesPerCycle = 4; + return 0x2000 + kBytesPerScanline * g_nVideoClockVert + kBytesPerCycle * (g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START); +} + // Non-Inline _________________________________________________________ // Build the 4 phase chroma lookup table @@ -1822,14 +1832,10 @@ void updateScreenSHR(long cycles6502) { for (; cycles6502 > 0; --cycles6502) { - // 2 pixels per byte in 320-pixel mode = 160 bytes/scanline - // 4 pixels per byte in 640-pixel mode = 160 bytes/scanline - const UINT kBytesPerScanline = 160; - const UINT kBytesPerCycle = 4; - uint16_t addr = 0x2000 + kBytesPerScanline * g_nVideoClockVert + kBytesPerCycle * (g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START); - if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY_IIGS) { + uint16_t addr = getVideoScannerAddressSHR(); + if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START) { uint32_t* pAux = (uint32_t*) MemGetAuxPtr(addr); // 8 pixels (320 mode) / 16 pixels (640 mode) @@ -1947,6 +1953,8 @@ void NTSC_SetVideoTextMode( int cols ) //=========================================================================== void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ ) { + g_uNewVideoModeFlags = uVideoModeFlags; + if (uVideoModeFlags & VF_SHR) { g_pFuncUpdateGraphicsScreen = updateScreenSHR; @@ -1965,7 +1973,6 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ ) // (GH#670) NB. if g_bFullSpeed then NTSC_VideoUpdateCycles() won't be called on the next 6502 opcode. // - Instead it's called when !g_bFullSpeed (eg. drive motor off), then the stale g_uNewVideoModeFlags will get used for NTSC_SetVideoMode()! g_bDelayVideoMode = true; - g_uNewVideoModeFlags = uVideoModeFlags; return; } @@ -2711,3 +2718,84 @@ bool NTSC_IsVisible(void) { return (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START); } + +// For debugger +uint16_t NTSC_GetScannerAddressAndData(uint32_t& data, int& dataSize) +{ + uint16_t addr = 0; + + if (g_uNewVideoModeFlags & VF_SHR) + { + addr = getVideoScannerAddressSHR(); + uint32_t* pAux = (uint32_t*)MemGetAuxPtr(addr); // 8 pixels (320 mode) / 16 pixels (640 mode) + data = pAux[0]; + dataSize = 4; + return addr; + } + + // + + if ( (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED) || + (g_uNewVideoModeFlags & VF_TEXT) || + !(g_uNewVideoModeFlags & VF_HIRES) ) + { + addr = getVideoScannerAddressTXT(); + } + else + { + addr = getVideoScannerAddressHGR(); + } + + // Copy logic from NTSC_SetVideoMode() + if (g_uNewVideoModeFlags & VF_TEXT) + { + if (g_uNewVideoModeFlags & VF_80COL) + dataSize = 2; + else + dataSize = 1; + } + else if (g_uNewVideoModeFlags & VF_HIRES) + { + if (g_uNewVideoModeFlags & VF_DHIRES) + { + if (g_uNewVideoModeFlags & VF_80COL) + dataSize = 2; + else + dataSize = 1; + } + else + { + dataSize = 1; + } + } + else + { + if (g_uNewVideoModeFlags & VF_DHIRES) + { + if (g_uNewVideoModeFlags & VF_80COL) + dataSize = 2; + else + dataSize = 1; + } + else + { + dataSize = 1; + } + } + + // Extra logic for MIXED mode + if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && (g_uNewVideoModeFlags & VF_80COL)) + dataSize = 2; + + + data = 0; + if (dataSize == 2) + { + uint8_t* pAux = MemGetAuxPtr(addr); + data = pAux[0] << 8; + } + uint8_t* pMain = MemGetMainPtr(addr); + data |= pMain[0]; + + return addr; +} diff --git a/source/NTSC.h b/source/NTSC.h index 5e5771fa..6e64ea1b 100644 --- a/source/NTSC.h +++ b/source/NTSC.h @@ -29,3 +29,4 @@ UINT NTSC_GetCyclesPerLine(void); UINT NTSC_GetVideoLines(void); UINT NTSC_GetCyclesUntilVBlank(int cycles); bool NTSC_IsVisible(void); +uint16_t NTSC_GetScannerAddressAndData(uint32_t& data, int& dataSize); diff --git a/source/StrFormat.h b/source/StrFormat.h index b20ed91c..befb7d5b 100644 --- a/source/StrFormat.h +++ b/source/StrFormat.h @@ -75,4 +75,12 @@ inline std::string WordToHexStr(uint16_t n) return s; } +inline std::string DWordToHexStr(uint32_t n) +{ + std::string s; + StrAppendWordAsHex(s, n >> 16); + StrAppendWordAsHex(s, n); + return s; +} + } // namespace