From c7f515015bafd17d08790e216ce0c9ed31b59abd Mon Sep 17 00:00:00 2001 From: Andrea Date: Wed, 17 Mar 2021 20:32:19 +0000 Subject: [PATCH] Debugger: Separate disassembler functions from display (PR #933) Makes it easier to use them in different environments. --- AppleWinExpress2008.vcproj | 8 + AppleWinExpress2019.vcxproj | 2 + AppleWinExpress2019.vcxproj.filters | 6 + source/Debugger/Debug.cpp | 140 ----- source/Debugger/Debug.h | 10 +- source/Debugger/Debugger_Disassembler.cpp | 723 ++++++++++++++++++++++ source/Debugger/Debugger_Disassembler.h | 26 + source/Debugger/Debugger_Display.cpp | 595 +----------------- source/Debugger/Debugger_Display.h | 16 - source/Debugger/Debugger_Symbols.h | 8 +- source/Debugger/Debugger_Types.h | 5 + 11 files changed, 779 insertions(+), 760 deletions(-) create mode 100644 source/Debugger/Debugger_Disassembler.cpp create mode 100644 source/Debugger/Debugger_Disassembler.h diff --git a/AppleWinExpress2008.vcproj b/AppleWinExpress2008.vcproj index 4a980880..c145816c 100644 --- a/AppleWinExpress2008.vcproj +++ b/AppleWinExpress2008.vcproj @@ -329,6 +329,14 @@ RelativePath=".\source\Debugger\Debugger_Console.h" > + + + + diff --git a/AppleWinExpress2019.vcxproj b/AppleWinExpress2019.vcxproj index 9ee9b430..c01f5177 100644 --- a/AppleWinExpress2019.vcxproj +++ b/AppleWinExpress2019.vcxproj @@ -61,6 +61,7 @@ + @@ -153,6 +154,7 @@ + diff --git a/AppleWinExpress2019.vcxproj.filters b/AppleWinExpress2019.vcxproj.filters index c96a2ed8..dddf397c 100644 --- a/AppleWinExpress2019.vcxproj.filters +++ b/AppleWinExpress2019.vcxproj.filters @@ -220,6 +220,9 @@ Source Files\Windows + + Source Files\Debugger + @@ -522,6 +525,9 @@ Source Files\Windows + + Source Files\Debugger + diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 47188308..1f350eaa 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -361,21 +361,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Update_t _CmdWindowViewCommon (int iNewWindow); // Utility - char FormatCharTxtCtrl ( const BYTE b, bool *pWasCtrl_ ); - char FormatCharTxtAsci ( const BYTE b, bool *pWasAsci_ ); - char FormatCharTxtHigh ( const BYTE b, bool *pWasHi_ ); - char FormatChar4Font ( const BYTE b, bool *pWasHi_, bool *pWasLo_ ); - void _CursorMoveDownAligned( int nDelta ); void _CursorMoveUpAligned( int nDelta ); - void DisasmCalcTopFromCurAddress( bool bUpdateTop = true ); - void DisasmCalcCurFromTopAddress(); - void DisasmCalcBotFromTopAddress(); - void DisasmCalcTopBotAddress (); - WORD DisasmCalcAddressFromLines( WORD iAddress, int nLines ); - - // DebugVideoMode _____________________________________________________________ // Fix for GH#345 @@ -2957,133 +2945,6 @@ Update_t CmdConfigGetFont (int nArgs) // Cursor _________________________________________________________________________________________ -// Given an Address, and Line to display it on -// Calculate the address of the top and bottom lines -// @param bUpdateCur -// true = Update Cur based on Top -// false = Update Top & Bot based on Cur -//=========================================================================== -void DisasmCalcTopFromCurAddress( bool bUpdateTop ) -{ - int nLen = ((g_nDisasmWinHeight - g_nDisasmCurLine) * 3); // max 3 opcodes/instruction, is our search window - - // Look for a start address that when disassembled, - // will have the cursor on the specified line and address - int iTop = g_nDisasmCurAddress - nLen; - int iCur = g_nDisasmCurAddress; - - g_bDisasmCurBad = false; - - bool bFound = false; - while (iTop <= iCur) - { - WORD iAddress = iTop; -// int iOpcode; - int iOpmode; - int nOpbytes; - - for( int iLine = 0; iLine <= nLen; iLine++ ) // min 1 opcode/instruction - { -// a. - _6502_GetOpmodeOpbyte( iAddress, iOpmode, nOpbytes ); -// b. -// _6502_GetOpcodeOpmodeOpbyte( iOpcode, iOpmode, nOpbytes ); - - if (iLine == g_nDisasmCurLine) // && (iAddress == g_nDisasmCurAddress)) - { - if (iAddress == g_nDisasmCurAddress) -// b. -// && (iOpmode != AM_1) && -// && (iOpmode != AM_2) && -// && (iOpmode != AM_3) && -// && _6502_IsOpcodeValid( iOpcode)) - { - g_nDisasmTopAddress = iTop; - bFound = true; - break; - } - } - - // .20 Fixed: DisasmCalcTopFromCurAddress() - //if ((eMode >= AM_1) && (eMode <= AM_3)) -#if 0 // _DEBUG - TCHAR sText[ CONSOLE_WIDTH ]; - wsprintf( sText, "%04X : %d bytes\n", iAddress, nOpbytes ); - OutputDebugString( sText ); -#endif - iAddress += nOpbytes; - } - if (bFound) - { - break; - } - iTop++; - } - - if (! bFound) - { - // Well, we're up the creek. - // There is no (valid) solution! - // Basically, there is no address, that when disassembled, - // will put our Address on the cursor Line! - // So, like typical game programming, when we don't like the solution, change the problem! -// if (bUpdateTop) - g_nDisasmTopAddress = g_nDisasmCurAddress; - - g_bDisasmCurBad = true; // Bad Disassembler, no opcode for you! - - // We reall should move the cursor line to the top for one instruction. - // Moving the cursor line around is not really a good idea, since we're breaking consistency paradigm for the user. - // g_nDisasmCurLine = 0; -#if 0 // _DEBUG - TCHAR sText[ CONSOLE_WIDTH * 2 ]; - sprintf( sText, TEXT("DisasmCalcTopFromCurAddress()\n" - "\tTop: %04X\n" - "\tLen: %04X\n" - "\tMissed: %04X"), - g_nDisasmCurAddress - nLen, nLen, g_nDisasmCurAddress ); - GetFrame().FrameMessageBox( sText, "ERROR", MB_OK ); -#endif - } -} - - -//=========================================================================== -WORD DisasmCalcAddressFromLines( WORD iAddress, int nLines ) -{ - while (nLines-- > 0) - { - int iOpmode; - int nOpbytes; - _6502_GetOpmodeOpbyte( iAddress, iOpmode, nOpbytes ); - iAddress += nOpbytes; - } - return iAddress; -} - - -//=========================================================================== -void DisasmCalcCurFromTopAddress() -{ - g_nDisasmCurAddress = DisasmCalcAddressFromLines( g_nDisasmTopAddress, g_nDisasmCurLine ); -} - - -//=========================================================================== -void DisasmCalcBotFromTopAddress( ) -{ - g_nDisasmBotAddress = DisasmCalcAddressFromLines( g_nDisasmTopAddress, g_nDisasmWinHeight ); -} - - -//=========================================================================== -void DisasmCalcTopBotAddress () -{ - DisasmCalcTopFromCurAddress(); - DisasmCalcBotFromTopAddress(); -} - - //=========================================================================== Update_t CmdCursorFollowTarget ( int nArgs ) { @@ -8859,7 +8720,6 @@ void DebugInitialize () memset( g_aZeroPagePointers, 0, MAX_ZEROPAGE_POINTERS * sizeof(ZeroPagePointers_t)); // Load Main, Applesoft, and User Symbols - extern bool g_bSymbolsDisplayMissingFile; g_bSymbolsDisplayMissingFile = false; g_iCommand = CMD_SYMBOLS_ROM; diff --git a/source/Debugger/Debug.h b/source/Debugger/Debug.h index 29e963bd..ef5a89c5 100644 --- a/source/Debugger/Debug.h +++ b/source/Debugger/Debug.h @@ -5,6 +5,7 @@ #include "Debugger_Types.h" #include "Debugger_DisassemblerData.h" +#include "Debugger_Disassembler.h" #include "Debugger_Range.h" #include "Debugger_Parser.h" #include "Debugger_Console.h" @@ -145,15 +146,6 @@ // Source Level Debugging int FindSourceLine( WORD nAddress ); - const char* FormatAddress( WORD nAddress, int nBytes ); - -// Symbol Table / Memory - bool FindAddressFromSymbol( const char* pSymbol, WORD * pAddress_ = NULL, int * iTable_ = NULL ); - WORD GetAddressFromSymbol( const char* symbol); // HACK: returns 0 if symbol not found - void SymbolUpdate( SymbolTable_Index_e eSymbolTable, const char *pSymbolName, WORD nAddrss, bool bRemoveSymbol, bool bUpdateSymbol ); - - const char* FindSymbolFromAddress( WORD nAdress, int * iTable_ = NULL ); - const char* GetSymbol( WORD nAddress, int nBytes); // Memory size_t Util_GetTextScreen( char* &pText_ ); diff --git a/source/Debugger/Debugger_Disassembler.cpp b/source/Debugger/Debugger_Disassembler.cpp new file mode 100644 index 00000000..8ad19d6f --- /dev/null +++ b/source/Debugger/Debugger_Disassembler.cpp @@ -0,0 +1,723 @@ +#include "StdAfx.h" + +#include "Debug.h" + +#include "../Memory.h" + +//=========================================================================== +const char* FormatAddress(WORD nAddress, int nBytes) +{ + // There is no symbol for this nAddress + static TCHAR sSymbol[8] = TEXT(""); + switch (nBytes) + { + case 2: wsprintf(sSymbol, TEXT("$%02X"), (unsigned)nAddress); break; + case 3: wsprintf(sSymbol, TEXT("$%04X"), (unsigned)nAddress); break; + // TODO: FIXME: Can we get called with nBytes == 16 ?? + default: sSymbol[0] = 0; break; // clear since is static + } + return sSymbol; +} + +//=========================================================================== +char* FormatCharCopy(char* pDst, const char* pSrc, const int nLen) +{ + for (int i = 0; i < nLen; i++) + *pDst++ = FormatCharTxtCtrl(*pSrc++); + return pDst; +} + +//=========================================================================== +char FormatCharTxtAsci(const BYTE b, bool* pWasAsci_) +{ + if (pWasAsci_) + *pWasAsci_ = false; + + char c = (b & 0x7F); + if (b <= 0x7F) + { + if (pWasAsci_) + { + *pWasAsci_ = true; + } + } + return c; +} + +// Note: FormatCharTxtCtrl() and RemapChar() +//=========================================================================== +char FormatCharTxtCtrl(const BYTE b, bool* pWasCtrl_) +{ + if (pWasCtrl_) + *pWasCtrl_ = false; + + char c = (b & 0x7F); // .32 Changed: Lo now maps High Ascii to printable chars. i.e. ML1 D0D0 + if (b < 0x20) // SPACE + { + if (pWasCtrl_) + { + *pWasCtrl_ = true; + } + c = b + '@'; // map ctrl chars to visible + } + return c; +} + +//=========================================================================== +char FormatCharTxtHigh(const BYTE b, bool* pWasHi_) +{ + if (pWasHi_) + *pWasHi_ = false; + + char c = b; + if (b > 0x7F) + { + if (pWasHi_) + { + *pWasHi_ = true; + } + c = (b & 0x7F); + } + return c; +} + + +//=========================================================================== +char FormatChar4Font(const BYTE b, bool* pWasHi_, bool* pWasLo_) +{ + // Most Windows Fonts don't have (printable) glyphs for control chars + BYTE b1 = FormatCharTxtHigh(b, pWasHi_); + BYTE b2 = FormatCharTxtCtrl(b1, pWasLo_); + return b2; +} + + + +// Disassembly + /* + // Thought about moving MouseText to another location, say high bit, 'A' + 0x80 + // But would like to keep compatibility with existing CHARSET40 + // Since we should be able to display all apple chars 0x00 .. 0xFF with minimal processing + // Use CONSOLE_COLOR_ESCAPE_CHAR to shift to mouse text + * Apple Font + K Mouse Text Up Arror + H Mouse Text Left Arrow + J Mouse Text Down Arrow + * Wingdings + \xE1 Up Arrow + \xE2 Down Arrow + * Webdings // M$ Font + \x35 Up Arrow + \x33 Left Arrow (\x71 recycl is too small to make out details) + \x36 Down Arrow + * Symols + \xAD Up Arrow + \xAF Down Arrow + * ??? + \x18 Up + \x19 Down + */ +#if USE_APPLE_FONT +const char* g_sConfigBranchIndicatorUp[NUM_DISASM_BRANCH_TYPES + 1] = { " ", "^", "\x8B" }; // "`K" 0x4B +const char* g_sConfigBranchIndicatorEqual[NUM_DISASM_BRANCH_TYPES + 1] = { " ", "=", "\x88" }; // "`H" 0x48 +const char* g_sConfigBranchIndicatorDown[NUM_DISASM_BRANCH_TYPES + 1] = { " ", "v", "\x8A" }; // "`J" 0x4A +#else +const char* g_sConfigBranchIndicatorUp[NUM_DISASM_BRANCH_TYPES + 1] = { " ", "^", "\x35" }; +const char* g_sConfigBranchIndicatorEqual[NUM_DISASM_BRANCH_TYPES + 1] = { " ", "=", "\x33" }; +char* g_sConfigBranchIndicatorDown[NUM_DISASM_BRANCH_TYPES + 1] = { " ", "v", "\x36" }; +#endif + +// Disassembly ____________________________________________________________________________________ + +void GetTargets_IgnoreDirectJSRJMP(const BYTE iOpcode, int& nTargetPointer) +{ + if (iOpcode == OPCODE_JSR || iOpcode == OPCODE_JMP_A) + nTargetPointer = NO_6502_TARGET; +} + + +// Get the data needed to disassemble one line of opcodes. Fills in the DisasmLine info. +// Disassembly formatting flags returned +// @parama sTargetValue_ indirect/indexed final value +//=========================================================================== +int GetDisassemblyLine(WORD nBaseAddress, DisasmLine_t& line_) +// char *sAddress_, char *sOpCodes_, +// char *sTarget_, char *sTargetOffset_, int & nTargetOffset_, +// char *sTargetPointer_, char *sTargetValue_, +// char *sImmediate_, char & nImmediate_, char *sBranch_ ) +{ + line_.Clear(); + + int iOpcode; + int iOpmode; + int nOpbyte; + + iOpcode = _6502_GetOpmodeOpbyte(nBaseAddress, iOpmode, nOpbyte, &line_.pDisasmData); + const DisasmData_t* pData = line_.pDisasmData; // Disassembly_IsDataAddress( nBaseAddress ); + + line_.iOpcode = iOpcode; + line_.iOpmode = iOpmode; + line_.nOpbyte = nOpbyte; + +#if _DEBUG + // if (iLine != 41) + // return nOpbytes; +#endif + + if (iOpmode == AM_M) + line_.bTargetImmediate = true; + + if ((iOpmode >= AM_IZX) && (iOpmode <= AM_NA)) + line_.bTargetIndirect = true; // () + + if ((iOpmode >= AM_IZX) && (iOpmode <= AM_NZY)) + line_.bTargetIndexed = true; // () + + if (((iOpmode >= AM_A) && (iOpmode <= AM_ZY)) || line_.bTargetIndirect) + line_.bTargetValue = true; // #$ + + if ((iOpmode == AM_AX) || (iOpmode == AM_ZX) || (iOpmode == AM_IZX) || (iOpmode == AM_IAX)) + line_.bTargetX = true; // ,X + + if ((iOpmode == AM_AY) || (iOpmode == AM_ZY) || (iOpmode == AM_NZY)) + line_.bTargetY = true; // ,Y + + unsigned int nMinBytesLen = (MAX_OPCODES * (2 + g_bConfigDisasmOpcodeSpaces)); // 2 char for byte (or 3 with space) + + int bDisasmFormatFlags = 0; + + // Composite string that has the symbol or target nAddress + WORD nTarget = 0; + + if ((iOpmode != AM_IMPLIED) && + (iOpmode != AM_1) && + (iOpmode != AM_2) && + (iOpmode != AM_3)) + { + // Assume target address starts after the opcode ... + // BUT in the Assembler Directive / Data Disassembler case for define addr/word + // the opcode literally IS the target address! + if (pData) + { + nTarget = pData->nTargetAddress; + } + else { + nTarget = mem[(nBaseAddress + 1) & 0xFFFF] | (mem[(nBaseAddress + 2) & 0xFFFF] << 8); + if (nOpbyte == 2) + nTarget &= 0xFF; + } + + if (iOpmode == AM_R) // Relative + { + line_.bTargetRelative = true; + + nTarget = nBaseAddress + 2 + (int)(signed char)nTarget; + + line_.nTarget = nTarget; + sprintf(line_.sTargetValue, "%04X", nTarget & 0xFFFF); + + // Always show branch indicators + bDisasmFormatFlags |= DISASM_FORMAT_BRANCH; + + if (nTarget < nBaseAddress) + { + sprintf(line_.sBranch, "%s", g_sConfigBranchIndicatorUp[g_iConfigDisasmBranchType]); + } + else + if (nTarget > nBaseAddress) + { + sprintf(line_.sBranch, "%s", g_sConfigBranchIndicatorDown[g_iConfigDisasmBranchType]); + } + else + { + sprintf(line_.sBranch, "%s", g_sConfigBranchIndicatorEqual[g_iConfigDisasmBranchType]); + } + } + // intentional re-test AM_R ... + +// if ((iOpmode >= AM_A) && (iOpmode <= AM_NA)) + if ((iOpmode == AM_A) || // Absolute + (iOpmode == AM_Z) || // Zeropage + (iOpmode == AM_AX) || // Absolute, X + (iOpmode == AM_AY) || // Absolute, Y + (iOpmode == AM_ZX) || // Zeropage, X + (iOpmode == AM_ZY) || // Zeropage, Y + (iOpmode == AM_R) || // Relative + (iOpmode == AM_IZX) || // Indexed (Zeropage Indirect, X) + (iOpmode == AM_IAX) || // Indexed (Absolute Indirect, X) + (iOpmode == AM_NZY) || // Indirect (Zeropage) Index, Y + (iOpmode == AM_NZ) || // Indirect (Zeropage) + (iOpmode == AM_NA)) //(Indirect Absolute) + { + line_.nTarget = nTarget; + + const char* pTarget = NULL; + const char* pSymbol = 0; + + pSymbol = FindSymbolFromAddress(nTarget); + + // Data Assembler + if (pData && (!pData->bSymbolLookup)) + pSymbol = 0; + + // Try exact match first + if (pSymbol) + { + bDisasmFormatFlags |= DISASM_FORMAT_SYMBOL; + pTarget = pSymbol; + } + + if (!(bDisasmFormatFlags & DISASM_FORMAT_SYMBOL)) + { + pSymbol = FindSymbolFromAddress(nTarget - 1); + if (pSymbol) + { + bDisasmFormatFlags |= DISASM_FORMAT_SYMBOL; + bDisasmFormatFlags |= DISASM_FORMAT_OFFSET; + pTarget = pSymbol; + line_.nTargetOffset = +1; // U FA82 LDA $3F1 BREAK-1 + } + } + + // Old Offset search: (Search +1 First) nTarget-1, (Search -1 Second) nTarget+1 + // Problem: U D038 shows as A.TRACE+1 + // New Offset search: (Search -1 First) nTarget+1, (Search +1 Second) nTarget+1 + // Problem: U D834, D87E shows as P.MUL-1, instead of P.ADD+1 + // 2.6.2.31 Fixed: address table was bailing on first possible match. U D000 -> da STOP+1, instead of END-1 + // 2.7.0.0: Try to match nTarget-1, nTarget+1, AND if we have both matches + // Then we need to decide which one to show. If we have pData then pick this one. + // TODO: Do we need to let the user decide which one they want searched first? + // nFirstTarget = g_bDebugConfig_DisasmMatchSymbolOffsetMinus1First ? nTarget-1 : nTarget+1; + // nSecondTarget = g_bDebugConfig_DisasmMatchSymbolOffsetMinus1First ? nTarget+1 : nTarget-1; + if (!(bDisasmFormatFlags & DISASM_FORMAT_SYMBOL) || pData) + { + pSymbol = FindSymbolFromAddress(nTarget + 1); + if (pSymbol) + { + bDisasmFormatFlags |= DISASM_FORMAT_SYMBOL; + bDisasmFormatFlags |= DISASM_FORMAT_OFFSET; + pTarget = pSymbol; + line_.nTargetOffset = -1; // U FA82 LDA $3F3 BREAK+1 + } + } + + if (!(bDisasmFormatFlags & DISASM_FORMAT_SYMBOL)) + { + pTarget = FormatAddress(nTarget, (iOpmode != AM_R) ? nOpbyte : 3); // GH#587: For Bcc opcodes, pretend it's a 3-byte opcode to print a 16-bit target addr + } + + // sprintf( sTarget, g_aOpmodes[ iOpmode ]._sFormat, pTarget ); + if (bDisasmFormatFlags & DISASM_FORMAT_OFFSET) + { + int nAbsTargetOffset = (line_.nTargetOffset > 0) ? line_.nTargetOffset : -line_.nTargetOffset; + sprintf(line_.sTargetOffset, "%d", nAbsTargetOffset); + } + sprintf(line_.sTarget, "%s", pTarget); + + + // Indirect / Indexed + int nTargetPartial; + int nTargetPartial2; + int nTargetPointer; + WORD nTargetValue = 0; // de-ref + _6502_GetTargets(nBaseAddress, &nTargetPartial, &nTargetPartial2, &nTargetPointer, NULL); + GetTargets_IgnoreDirectJSRJMP(iOpcode, nTargetPointer); // For *direct* JSR/JMP, don't show 'addr16:byte char' + + if (nTargetPointer != NO_6502_TARGET) + { + bDisasmFormatFlags |= DISASM_FORMAT_TARGET_POINTER; + + nTargetValue = *(mem + nTargetPointer) | (*(mem + ((nTargetPointer + 1) & 0xffff)) << 8); + + // if (((iOpmode >= AM_A) && (iOpmode <= AM_NZ)) && (iOpmode != AM_R)) + // sprintf( sTargetValue_, "%04X", nTargetValue ); // & 0xFFFF + + if (g_iConfigDisasmTargets & DISASM_TARGET_ADDR) + sprintf(line_.sTargetPointer, "%04X", nTargetPointer & 0xFFFF); + + if (iOpcode != OPCODE_JMP_NA && iOpcode != OPCODE_JMP_IAX) + { + bDisasmFormatFlags |= DISASM_FORMAT_TARGET_VALUE; + if (g_iConfigDisasmTargets & DISASM_TARGET_VAL) + sprintf(line_.sTargetValue, "%02X", nTargetValue & 0xFF); + + bDisasmFormatFlags |= DISASM_FORMAT_CHAR; + line_.nImmediate = (BYTE)nTargetValue; + + unsigned _char = FormatCharTxtCtrl(FormatCharTxtHigh(line_.nImmediate, NULL), NULL); + sprintf(line_.sImmediate, "%c", _char); + + // if (ConsoleColorIsEscapeMeta( nImmediate_ )) +#if OLD_CONSOLE_COLOR + if (ConsoleColorIsEscapeMeta(_char)) + sprintf(line_.sImmediate, "%c%c", _char, _char); + else + sprintf(line_.sImmediate, "%c", _char); +#endif + } + + // if (iOpmode == AM_NA ) // Indirect Absolute + // sprintf( sTargetValue_, "%04X", nTargetPointer & 0xFFFF ); + // else + // // sprintf( sTargetValue_, "%02X", nTargetValue & 0xFF ); + // sprintf( sTargetValue_, "%04X:%02X", nTargetPointer & 0xFFFF, nTargetValue & 0xFF ); + } + } + else + if (iOpmode == AM_M) + { + // sprintf( sTarget, g_aOpmodes[ iOpmode ]._sFormat, (unsigned)nTarget ); + sprintf(line_.sTarget, "%02X", (unsigned)nTarget); + + if (iOpmode == AM_M) + { + bDisasmFormatFlags |= DISASM_FORMAT_CHAR; + line_.nImmediate = (BYTE)nTarget; + unsigned _char = FormatCharTxtCtrl(FormatCharTxtHigh(line_.nImmediate, NULL), NULL); + + sprintf(line_.sImmediate, "%c", _char); +#if OLD_CONSOLE_COLOR + if (ConsoleColorIsEscapeMeta(_char)) + sprintf(line_.sImmediate, "%c%c", _char, _char); + else + sprintf(line_.sImmediate, "%c", _char); +#endif + } + } + } + + sprintf(line_.sAddress, "%04X", nBaseAddress); + + // Opcode Bytes + FormatOpcodeBytes(nBaseAddress, line_); + + // Data Disassembler + if (pData) + { + line_.iNoptype = pData->eElementType; + line_.iNopcode = pData->iDirective; + strcpy(line_.sMnemonic, g_aAssemblerDirectives[line_.iNopcode].m_pMnemonic); + + FormatNopcodeBytes(nBaseAddress, line_); + } + else { // Regular 6502/65C02 opcode -> mnemonic + strcpy(line_.sMnemonic, g_aOpcodes[line_.iOpcode].sMnemonic); + } + + int nSpaces = strlen(line_.sOpCodes); + while (nSpaces < (int)nMinBytesLen) + { + strcat(line_.sOpCodes, " "); + nSpaces++; + } + + return bDisasmFormatFlags; +} + +//=========================================================================== +void FormatOpcodeBytes(WORD nBaseAddress, DisasmLine_t& line_) +{ + int nOpbyte = line_.nOpbyte; + + char* pDst = line_.sOpCodes; + int nMaxOpBytes = nOpbyte; + if (nMaxOpBytes > MAX_OPCODES) // 2.8.0.0 fix // TODO: FIX: show max 8 bytes for HEX + nMaxOpBytes = MAX_OPCODES; + + for (int iByte = 0; iByte < nMaxOpBytes; iByte++) + { + BYTE nMem = mem[(nBaseAddress + iByte) & 0xFFFF]; + sprintf(pDst, "%02X", nMem); // sBytes+strlen(sBytes) + pDst += 2; + + // TODO: If Disassembly_IsDataAddress() don't show spaces... + if (g_bConfigDisasmOpcodeSpaces) + { + strcat(pDst, " "); + pDst++; // 2.5.3.3 fix + } + } +} + +// Formats Target string with bytes,words, string, etc... +//=========================================================================== +void FormatNopcodeBytes(WORD nBaseAddress, DisasmLine_t& line_) +{ + char* pDst = line_.sTarget; + const char* pSrc = 0; + DWORD nStartAddress = line_.pDisasmData->nStartAddress; + DWORD nEndAddress = line_.pDisasmData->nEndAddress; + // int nDataLen = nEndAddress - nStartAddress + 1 ; + int nDisplayLen = nEndAddress - nBaseAddress + 1; // *inclusive* KEEP IN SYNC: _CmdDefineByteRange() CmdDisasmDataList() _6502_GetOpmodeOpbyte() FormatNopcodeBytes() + int len = nDisplayLen; + + for (int iByte = 0; iByte < line_.nOpbyte; ) + { + BYTE nTarget8 = *(LPBYTE)(mem + nBaseAddress + iByte); + WORD nTarget16 = *(LPWORD)(mem + nBaseAddress + iByte); + + switch (line_.iNoptype) + { + case NOP_BYTE_1: + case NOP_BYTE_2: + case NOP_BYTE_4: + case NOP_BYTE_8: + sprintf(pDst, "%02X", nTarget8); // sBytes+strlen(sBytes) + pDst += 2; + iByte++; + if (line_.iNoptype == NOP_BYTE_1) + if (iByte < line_.nOpbyte) + { + *pDst++ = ','; + } + break; + case NOP_WORD_1: + case NOP_WORD_2: + case NOP_WORD_4: + sprintf(pDst, "%04X", nTarget16); // sBytes+strlen(sBytes) + pDst += 4; + iByte += 2; + if (iByte < line_.nOpbyte) + { + *pDst++ = ','; + } + break; + case NOP_ADDRESS: + // Nothing to do, already handled :-) + iByte += 2; + break; + case NOP_STRING_APPLESOFT: + iByte = line_.nOpbyte; + strncpy(pDst, (const char*)(mem + nBaseAddress), iByte); + pDst += iByte; + *pDst = 0; + case NOP_STRING_APPLE: + iByte = line_.nOpbyte; // handle all bytes of text + pSrc = (const char*)mem + nStartAddress; + + if (len > (MAX_IMMEDIATE_LEN - 2)) // does "text" fit? + { + if (len > MAX_IMMEDIATE_LEN) // no; need extra characters for ellipsis? + len = (MAX_IMMEDIATE_LEN - 3); // ellipsis = true + + // DISPLAY: text_longer_18... + FormatCharCopy(pDst, pSrc, len); // BUG: #251 v2.8.0.7: ASC #:# with null byte doesn't mark up properly + + if (nDisplayLen > len) // ellipsis + { + *pDst++ = '.'; + *pDst++ = '.'; + *pDst++ = '.'; + } + } + else { // DISPLAY: "max_18_char" + *pDst++ = '"'; + pDst = FormatCharCopy(pDst, pSrc, len); // BUG: #251 v2.8.0.7: ASC #:# with null byte doesn't mark up properly + *pDst++ = '"'; + } + + *pDst = 0; + break; + default: +#if _DEBUG // Unhandled data disassembly! + int* FATAL = 0; + *FATAL = 0xDEADC0DE; +#endif + iByte++; + break; + } + } +} + +//=========================================================================== +void FormatDisassemblyLine(const DisasmLine_t& line, char* sDisassembly, const int nBufferSize) +{ + //> Address Seperator Opcodes Label Mnemonic Target [Immediate] [Branch] + // + // Data Disassembler + // Label Directive [Immediate] + const char* pMnemonic = g_aOpcodes[line.iOpcode].sMnemonic; + + sprintf(sDisassembly, "%s:%s %s " + , line.sAddress + , line.sOpCodes + , pMnemonic + ); + + /* + if (line.bTargetIndexed || line.bTargetIndirect) + { + strcat( sDisassembly, "(" ); + } + + if (line.bTargetImmediate) + strcat( sDisassembly, "#$" ); + + if (line.bTargetValue) + strcat( sDisassembly, line.sTarget ); + + if (line.bTargetIndirect) + { + if (line.bTargetX) + strcat( sDisassembly, ", X" ); + if (line.bTargetY) + strcat( sDisassembly, ", Y" ); + } + + if (line.bTargetIndexed || line.bTargetIndirect) + { + strcat( sDisassembly, ")" ); + } + + if (line.bTargetIndirect) + { + if (line.bTargetY) + strcat( sDisassembly, ", Y" ); + } + */ + char sTarget[32]; + + if (line.bTargetValue || line.bTargetRelative || line.bTargetImmediate) + { + if (line.bTargetRelative) + strcpy(sTarget, line.sTargetValue); + else + if (line.bTargetImmediate) + { + strcat(sDisassembly, "#"); + strncpy(sTarget, line.sTarget, sizeof(sTarget)); + sTarget[sizeof(sTarget) - 1] = 0; + } + else + sprintf(sTarget, g_aOpmodes[line.iOpmode].m_sFormat, line.nTarget); + + strcat(sDisassembly, "$"); + strcat(sDisassembly, sTarget); + } +} + +// Given an Address, and Line to display it on +// Calculate the address of the top and bottom lines +// @param bUpdateCur +// true = Update Cur based on Top +// false = Update Top & Bot based on Cur +//=========================================================================== +void DisasmCalcTopFromCurAddress(bool bUpdateTop) +{ + int nLen = ((g_nDisasmWinHeight - g_nDisasmCurLine) * 3); // max 3 opcodes/instruction, is our search window + + // Look for a start address that when disassembled, + // will have the cursor on the specified line and address + int iTop = g_nDisasmCurAddress - nLen; + int iCur = g_nDisasmCurAddress; + + g_bDisasmCurBad = false; + + bool bFound = false; + while (iTop <= iCur) + { + WORD iAddress = iTop; + // int iOpcode; + int iOpmode; + int nOpbytes; + + for (int iLine = 0; iLine <= nLen; iLine++) // min 1 opcode/instruction + { + // a. + _6502_GetOpmodeOpbyte(iAddress, iOpmode, nOpbytes); + // b. + // _6502_GetOpcodeOpmodeOpbyte( iOpcode, iOpmode, nOpbytes ); + + if (iLine == g_nDisasmCurLine) // && (iAddress == g_nDisasmCurAddress)) + { + if (iAddress == g_nDisasmCurAddress) + // b. + // && (iOpmode != AM_1) && + // && (iOpmode != AM_2) && + // && (iOpmode != AM_3) && + // && _6502_IsOpcodeValid( iOpcode)) + { + g_nDisasmTopAddress = iTop; + bFound = true; + break; + } + } + + // .20 Fixed: DisasmCalcTopFromCurAddress() + //if ((eMode >= AM_1) && (eMode <= AM_3)) +#if 0 // _DEBUG + TCHAR sText[CONSOLE_WIDTH]; + wsprintf(sText, "%04X : %d bytes\n", iAddress, nOpbytes); + OutputDebugString(sText); +#endif + iAddress += nOpbytes; + } + if (bFound) + { + break; + } + iTop++; + } + + if (!bFound) + { + // Well, we're up the creek. + // There is no (valid) solution! + // Basically, there is no address, that when disassembled, + // will put our Address on the cursor Line! + // So, like typical game programming, when we don't like the solution, change the problem! +// if (bUpdateTop) + g_nDisasmTopAddress = g_nDisasmCurAddress; + + g_bDisasmCurBad = true; // Bad Disassembler, no opcode for you! + + // We reall should move the cursor line to the top for one instruction. + // Moving the cursor line around is not really a good idea, since we're breaking consistency paradigm for the user. + // g_nDisasmCurLine = 0; +#if 0 // _DEBUG + TCHAR sText[CONSOLE_WIDTH * 2]; + sprintf(sText, TEXT("DisasmCalcTopFromCurAddress()\n" + "\tTop: %04X\n" + "\tLen: %04X\n" + "\tMissed: %04X"), + g_nDisasmCurAddress - nLen, nLen, g_nDisasmCurAddress); + GetFrame().FrameMessageBox(sText, "ERROR", MB_OK); +#endif + } +} + + +//=========================================================================== +WORD DisasmCalcAddressFromLines(WORD iAddress, int nLines) +{ + while (nLines-- > 0) + { + int iOpmode; + int nOpbytes; + _6502_GetOpmodeOpbyte(iAddress, iOpmode, nOpbytes); + iAddress += nOpbytes; + } + return iAddress; +} + + +//=========================================================================== +void DisasmCalcCurFromTopAddress() +{ + g_nDisasmCurAddress = DisasmCalcAddressFromLines(g_nDisasmTopAddress, g_nDisasmCurLine); +} + + +//=========================================================================== +void DisasmCalcBotFromTopAddress() +{ + g_nDisasmBotAddress = DisasmCalcAddressFromLines(g_nDisasmTopAddress, g_nDisasmWinHeight); +} + + +//=========================================================================== +void DisasmCalcTopBotAddress() +{ + DisasmCalcTopFromCurAddress(); + DisasmCalcBotFromTopAddress(); +} diff --git a/source/Debugger/Debugger_Disassembler.h b/source/Debugger/Debugger_Disassembler.h new file mode 100644 index 00000000..6915a730 --- /dev/null +++ b/source/Debugger/Debugger_Disassembler.h @@ -0,0 +1,26 @@ +#pragma once + +int GetDisassemblyLine(const WORD nOffset, DisasmLine_t& line_); +// , int iOpcode, int iOpmode, int nOpbytes +// char *sAddress_, char *sOpCodes_, +// char *sTarget_, char *sTargetOffset_, int & nTargetOffset_, char *sTargetValue_, +// char * sImmediate_, char & nImmediate_, char *sBranch_ ); +void FormatDisassemblyLine(const DisasmLine_t& line, char* sDisassembly_, const int nBufferSize); +void FormatOpcodeBytes(WORD nBaseAddress, DisasmLine_t& line_); +void FormatNopcodeBytes(WORD nBaseAddress, DisasmLine_t& line_); + +const char* FormatAddress(WORD nAddress, int nBytes); +char* FormatCharCopy(char* pDst, const char* pSrc, const int nLen); + +char FormatCharTxtAsci(const BYTE b, bool* pWasAsci_ = NULL); +char FormatCharTxtCtrl(const BYTE b, bool* pWasCtrl_ = NULL); +char FormatCharTxtHigh(const BYTE b, bool* pWasHi_ = NULL); +char FormatChar4Font(const BYTE b, bool* pWasHi_, bool* pWasLo_); + +void GetTargets_IgnoreDirectJSRJMP(const BYTE iOpcode, int& nTargetPointer); + +void DisasmCalcTopFromCurAddress(bool bUpdateTop = true); +void DisasmCalcCurFromTopAddress(); +void DisasmCalcBotFromTopAddress(); +void DisasmCalcTopBotAddress(); +WORD DisasmCalcAddressFromLines(WORD iAddress, int nLines); diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index 60571c12..f7c919f5 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Debug.h" #include "Debugger_Display.h" +#include "Debugger_Disassembler.h" #include "../Core.h" #include "../Interface.h" @@ -115,40 +116,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA RGB( 80, 192, 255 ) // Lite Blue }; -// Disassembly - /* - // Thought about moving MouseText to another location, say high bit, 'A' + 0x80 - // But would like to keep compatibility with existing CHARSET40 - // Since we should be able to display all apple chars 0x00 .. 0xFF with minimal processing - // Use CONSOLE_COLOR_ESCAPE_CHAR to shift to mouse text - * Apple Font - K Mouse Text Up Arror - H Mouse Text Left Arrow - J Mouse Text Down Arrow - * Wingdings - \xE1 Up Arrow - \xE2 Down Arrow - * Webdings // M$ Font - \x35 Up Arrow - \x33 Left Arrow (\x71 recycl is too small to make out details) - \x36 Down Arrow - * Symols - \xAD Up Arrow - \xAF Down Arrow - * ??? - \x18 Up - \x19 Down - */ -#if USE_APPLE_FONT - const char * g_sConfigBranchIndicatorUp [ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "^", "\x8B" }; // "`K" 0x4B - const char * g_sConfigBranchIndicatorEqual[ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "=", "\x88" }; // "`H" 0x48 - const char * g_sConfigBranchIndicatorDown [ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "v", "\x8A" }; // "`J" 0x4A -#else - const char * g_sConfigBranchIndicatorUp [ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "^", "\x35" }; - const char * g_sConfigBranchIndicatorEqual[ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "=", "\x33" }; - char * g_sConfigBranchIndicatorDown [ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "v", "\x36" }; -#endif - // Drawing // Width const int DISPLAY_WIDTH = 560; @@ -229,12 +196,6 @@ static char ColorizeSpecialChar( char * sText, BYTE nData, const MemoryView_e iV void DrawWindowBottom ( Update_t bUpdate, int iWindow ); - char* FormatCharCopy( char *pDst, const char *pSrc, const int nLen ); - char FormatCharTxtAsci( const BYTE b, bool * pWasAsci_ = NULL ); - char FormatCharTxtCtrl( const BYTE b, bool * pWasCtrl_ = NULL ); - char FormatCharTxtHigh( const BYTE b, bool *pWasHi_ = NULL ); - char FormatChar4Font ( const BYTE b, bool *pWasHi_, bool *pWasLo_ ); - void DrawRegister(int line, LPCTSTR name, int bytes, WORD value, int iSource = 0); @@ -947,78 +908,6 @@ int PrintTextCursorY ( const char * pText, RECT & rRect ) } -//=========================================================================== -char* FormatCharCopy( char *pDst, const char *pSrc, const int nLen ) -{ - for( int i = 0; i < nLen; i++ ) - *pDst++ = FormatCharTxtCtrl( *pSrc++ ); - return pDst; -} - -//=========================================================================== -char FormatCharTxtAsci ( const BYTE b, bool * pWasAsci_ ) -{ - if (pWasAsci_) - *pWasAsci_ = false; - - char c = (b & 0x7F); - if (b <= 0x7F) - { - if (pWasAsci_) - { - *pWasAsci_ = true; - } - } - return c; -} - -// Note: FormatCharTxtCtrl() and RemapChar() -//=========================================================================== -char FormatCharTxtCtrl ( const BYTE b, bool * pWasCtrl_ ) -{ - if (pWasCtrl_) - *pWasCtrl_ = false; - - char c = (b & 0x7F); // .32 Changed: Lo now maps High Ascii to printable chars. i.e. ML1 D0D0 - if (b < 0x20) // SPACE - { - if (pWasCtrl_) - { - *pWasCtrl_ = true; - } - c = b + '@'; // map ctrl chars to visible - } - return c; -} - -//=========================================================================== -char FormatCharTxtHigh ( const BYTE b, bool *pWasHi_ ) -{ - if (pWasHi_) - *pWasHi_ = false; - - char c = b; - if (b > 0x7F) - { - if (pWasHi_) - { - *pWasHi_ = true; - } - c = (b & 0x7F); - } - return c; -} - - -//=========================================================================== -char FormatChar4Font ( const BYTE b, bool *pWasHi_, bool *pWasLo_ ) -{ - // Most Windows Fonts don't have (printable) glyphs for control chars - BYTE b1 = FormatCharTxtHigh( b , pWasHi_ ); - BYTE b2 = FormatCharTxtCtrl( b1, pWasLo_ ); - return b2; -} - @@ -1429,488 +1318,6 @@ void DrawConsoleInput () } -// Disassembly ____________________________________________________________________________________ - -void GetTargets_IgnoreDirectJSRJMP(const BYTE iOpcode, int& nTargetPointer) -{ - if (iOpcode == OPCODE_JSR || iOpcode == OPCODE_JMP_A) - nTargetPointer = NO_6502_TARGET; -} - -// Get the data needed to disassemble one line of opcodes. Fills in the DisasmLine info. -// Disassembly formatting flags returned -// @parama sTargetValue_ indirect/indexed final value -//=========================================================================== -int GetDisassemblyLine ( WORD nBaseAddress, DisasmLine_t & line_ ) -// char *sAddress_, char *sOpCodes_, -// char *sTarget_, char *sTargetOffset_, int & nTargetOffset_, -// char *sTargetPointer_, char *sTargetValue_, -// char *sImmediate_, char & nImmediate_, char *sBranch_ ) -{ - line_.Clear(); - - int iOpcode; - int iOpmode; - int nOpbyte; - - iOpcode = _6502_GetOpmodeOpbyte( nBaseAddress, iOpmode, nOpbyte, &line_.pDisasmData ); - const DisasmData_t* pData = line_.pDisasmData; // Disassembly_IsDataAddress( nBaseAddress ); - - line_.iOpcode = iOpcode; - line_.iOpmode = iOpmode; - line_.nOpbyte = nOpbyte; - -#if _DEBUG -// if (iLine != 41) -// return nOpbytes; -#endif - - if (iOpmode == AM_M) - line_.bTargetImmediate = true; - - if ((iOpmode >= AM_IZX) && (iOpmode <= AM_NA)) - line_.bTargetIndirect = true; // () - - if ((iOpmode >= AM_IZX) && (iOpmode <= AM_NZY)) - line_.bTargetIndexed = true; // () - - if (((iOpmode >= AM_A) && (iOpmode <= AM_ZY)) || line_.bTargetIndirect) - line_.bTargetValue = true; // #$ - - if ((iOpmode == AM_AX) || (iOpmode == AM_ZX) || (iOpmode == AM_IZX) || (iOpmode == AM_IAX)) - line_.bTargetX = true; // ,X - - if ((iOpmode == AM_AY) || (iOpmode == AM_ZY) || (iOpmode == AM_NZY)) - line_.bTargetY = true; // ,Y - - unsigned int nMinBytesLen = (MAX_OPCODES * (2 + g_bConfigDisasmOpcodeSpaces)); // 2 char for byte (or 3 with space) - - int bDisasmFormatFlags = 0; - - // Composite string that has the symbol or target nAddress - WORD nTarget = 0; - - if ((iOpmode != AM_IMPLIED) && - (iOpmode != AM_1) && - (iOpmode != AM_2) && - (iOpmode != AM_3)) - { - // Assume target address starts after the opcode ... - // BUT in the Assembler Directive / Data Disassembler case for define addr/word - // the opcode literally IS the target address! - if( pData ) - { - nTarget = pData->nTargetAddress; - } else { - nTarget = mem[(nBaseAddress+1)&0xFFFF] | (mem[(nBaseAddress+2)&0xFFFF]<<8); - if (nOpbyte == 2) - nTarget &= 0xFF; - } - - if (iOpmode == AM_R) // Relative - { - line_.bTargetRelative = true; - - nTarget = nBaseAddress+2+(int)(signed char)nTarget; - - line_.nTarget = nTarget; - sprintf( line_.sTargetValue, "%04X", nTarget & 0xFFFF ); - - // Always show branch indicators - bDisasmFormatFlags |= DISASM_FORMAT_BRANCH; - - if (nTarget < nBaseAddress) - { - sprintf( line_.sBranch, "%s", g_sConfigBranchIndicatorUp[ g_iConfigDisasmBranchType ] ); - } - else - if (nTarget > nBaseAddress) - { - sprintf( line_.sBranch, "%s", g_sConfigBranchIndicatorDown[ g_iConfigDisasmBranchType ] ); - } - else - { - sprintf( line_.sBranch, "%s", g_sConfigBranchIndicatorEqual[ g_iConfigDisasmBranchType ] ); - } - } - // intentional re-test AM_R ... - -// if ((iOpmode >= AM_A) && (iOpmode <= AM_NA)) - if ((iOpmode == AM_A ) || // Absolute - (iOpmode == AM_Z ) || // Zeropage - (iOpmode == AM_AX ) || // Absolute, X - (iOpmode == AM_AY ) || // Absolute, Y - (iOpmode == AM_ZX ) || // Zeropage, X - (iOpmode == AM_ZY ) || // Zeropage, Y - (iOpmode == AM_R ) || // Relative - (iOpmode == AM_IZX) || // Indexed (Zeropage Indirect, X) - (iOpmode == AM_IAX) || // Indexed (Absolute Indirect, X) - (iOpmode == AM_NZY) || // Indirect (Zeropage) Index, Y - (iOpmode == AM_NZ ) || // Indirect (Zeropage) - (iOpmode == AM_NA )) //(Indirect Absolute) - { - line_.nTarget = nTarget; - - const char* pTarget = NULL; - const char* pSymbol = 0; - - pSymbol = FindSymbolFromAddress( nTarget ); - - // Data Assembler - if (pData && (!pData->bSymbolLookup)) - pSymbol = 0; - - // Try exact match first - if (pSymbol) - { - bDisasmFormatFlags |= DISASM_FORMAT_SYMBOL; - pTarget = pSymbol; - } - - if (! (bDisasmFormatFlags & DISASM_FORMAT_SYMBOL)) - { - pSymbol = FindSymbolFromAddress( nTarget - 1 ); - if (pSymbol) - { - bDisasmFormatFlags |= DISASM_FORMAT_SYMBOL; - bDisasmFormatFlags |= DISASM_FORMAT_OFFSET; - pTarget = pSymbol; - line_.nTargetOffset = +1; // U FA82 LDA $3F1 BREAK-1 - } - } - - // Old Offset search: (Search +1 First) nTarget-1, (Search -1 Second) nTarget+1 - // Problem: U D038 shows as A.TRACE+1 - // New Offset search: (Search -1 First) nTarget+1, (Search +1 Second) nTarget+1 - // Problem: U D834, D87E shows as P.MUL-1, instead of P.ADD+1 - // 2.6.2.31 Fixed: address table was bailing on first possible match. U D000 -> da STOP+1, instead of END-1 - // 2.7.0.0: Try to match nTarget-1, nTarget+1, AND if we have both matches - // Then we need to decide which one to show. If we have pData then pick this one. - // TODO: Do we need to let the user decide which one they want searched first? - // nFirstTarget = g_bDebugConfig_DisasmMatchSymbolOffsetMinus1First ? nTarget-1 : nTarget+1; - // nSecondTarget = g_bDebugConfig_DisasmMatchSymbolOffsetMinus1First ? nTarget+1 : nTarget-1; - if (! (bDisasmFormatFlags & DISASM_FORMAT_SYMBOL) || pData) - { - pSymbol = FindSymbolFromAddress( nTarget + 1 ); - if (pSymbol) - { - bDisasmFormatFlags |= DISASM_FORMAT_SYMBOL; - bDisasmFormatFlags |= DISASM_FORMAT_OFFSET; - pTarget = pSymbol; - line_.nTargetOffset = -1; // U FA82 LDA $3F3 BREAK+1 - } - } - - if (! (bDisasmFormatFlags & DISASM_FORMAT_SYMBOL)) - { - pTarget = FormatAddress( nTarget, (iOpmode != AM_R) ? nOpbyte : 3 ); // GH#587: For Bcc opcodes, pretend it's a 3-byte opcode to print a 16-bit target addr - } - -// sprintf( sTarget, g_aOpmodes[ iOpmode ]._sFormat, pTarget ); - if (bDisasmFormatFlags & DISASM_FORMAT_OFFSET) - { - int nAbsTargetOffset = (line_.nTargetOffset > 0) ? line_.nTargetOffset : - line_.nTargetOffset; - sprintf( line_.sTargetOffset, "%d", nAbsTargetOffset ); - } - sprintf( line_.sTarget, "%s", pTarget ); - - - // Indirect / Indexed - int nTargetPartial; - int nTargetPartial2; - int nTargetPointer; - WORD nTargetValue = 0; // de-ref - _6502_GetTargets( nBaseAddress, &nTargetPartial, &nTargetPartial2, &nTargetPointer, NULL ); - GetTargets_IgnoreDirectJSRJMP(iOpcode, nTargetPointer); // For *direct* JSR/JMP, don't show 'addr16:byte char' - - if (nTargetPointer != NO_6502_TARGET) - { - bDisasmFormatFlags |= DISASM_FORMAT_TARGET_POINTER; - - nTargetValue = *(mem + nTargetPointer) | (*(mem + ((nTargetPointer + 1) & 0xffff)) << 8); - -// if (((iOpmode >= AM_A) && (iOpmode <= AM_NZ)) && (iOpmode != AM_R)) -// sprintf( sTargetValue_, "%04X", nTargetValue ); // & 0xFFFF - - if (g_iConfigDisasmTargets & DISASM_TARGET_ADDR) - sprintf( line_.sTargetPointer, "%04X", nTargetPointer & 0xFFFF ); - - if (iOpcode != OPCODE_JMP_NA && iOpcode != OPCODE_JMP_IAX) - { - bDisasmFormatFlags |= DISASM_FORMAT_TARGET_VALUE; - if (g_iConfigDisasmTargets & DISASM_TARGET_VAL) - sprintf( line_.sTargetValue, "%02X", nTargetValue & 0xFF ); - - bDisasmFormatFlags |= DISASM_FORMAT_CHAR; - line_.nImmediate = (BYTE) nTargetValue; - - unsigned _char = FormatCharTxtCtrl( FormatCharTxtHigh( line_.nImmediate, NULL ), NULL ); - sprintf( line_.sImmediate, "%c", _char ); - -// if (ConsoleColorIsEscapeMeta( nImmediate_ )) -#if OLD_CONSOLE_COLOR - if (ConsoleColorIsEscapeMeta( _char )) - sprintf( line_.sImmediate, "%c%c", _char, _char ); - else - sprintf( line_.sImmediate, "%c", _char ); -#endif - } - -// if (iOpmode == AM_NA ) // Indirect Absolute -// sprintf( sTargetValue_, "%04X", nTargetPointer & 0xFFFF ); -// else -// // sprintf( sTargetValue_, "%02X", nTargetValue & 0xFF ); -// sprintf( sTargetValue_, "%04X:%02X", nTargetPointer & 0xFFFF, nTargetValue & 0xFF ); - } - } - else - if (iOpmode == AM_M) - { -// sprintf( sTarget, g_aOpmodes[ iOpmode ]._sFormat, (unsigned)nTarget ); - sprintf( line_.sTarget, "%02X", (unsigned)nTarget ); - - if (iOpmode == AM_M) - { - bDisasmFormatFlags |= DISASM_FORMAT_CHAR; - line_.nImmediate = (BYTE) nTarget; - unsigned _char = FormatCharTxtCtrl( FormatCharTxtHigh( line_.nImmediate, NULL ), NULL ); - - sprintf( line_.sImmediate, "%c", _char ); -#if OLD_CONSOLE_COLOR - if (ConsoleColorIsEscapeMeta( _char )) - sprintf( line_.sImmediate, "%c%c", _char, _char ); - else - sprintf( line_.sImmediate, "%c", _char ); -#endif - } - } - } - - sprintf( line_.sAddress, "%04X", nBaseAddress ); - - // Opcode Bytes - FormatOpcodeBytes( nBaseAddress, line_ ); - -// Data Disassembler - if( pData ) - { - line_.iNoptype = pData->eElementType; - line_.iNopcode = pData->iDirective; - strcpy( line_.sMnemonic, g_aAssemblerDirectives[ line_.iNopcode ].m_pMnemonic ); - - FormatNopcodeBytes( nBaseAddress, line_ ); - } else { // Regular 6502/65C02 opcode -> mnemonic - strcpy( line_.sMnemonic, g_aOpcodes[ line_.iOpcode ].sMnemonic ); - } - - int nSpaces = strlen( line_.sOpCodes ); - while (nSpaces < (int)nMinBytesLen) - { - strcat( line_.sOpCodes, " " ); - nSpaces++; - } - - return bDisasmFormatFlags; -} - - -//=========================================================================== -const char* FormatAddress( WORD nAddress, int nBytes ) -{ - // There is no symbol for this nAddress - static TCHAR sSymbol[8] = TEXT(""); - switch (nBytes) - { - case 2: wsprintf(sSymbol,TEXT("$%02X"),(unsigned)nAddress); break; - case 3: wsprintf(sSymbol,TEXT("$%04X"),(unsigned)nAddress); break; - // TODO: FIXME: Can we get called with nBytes == 16 ?? - default: sSymbol[0] = 0; break; // clear since is static - } - return sSymbol; -} - - -//=========================================================================== -void FormatOpcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ ) -{ - int nOpbyte = line_.nOpbyte; - - char *pDst = line_.sOpCodes; - int nMaxOpBytes = nOpbyte; - if ( nMaxOpBytes > MAX_OPCODES) // 2.8.0.0 fix // TODO: FIX: show max 8 bytes for HEX - nMaxOpBytes = MAX_OPCODES; - - for( int iByte = 0; iByte < nMaxOpBytes; iByte++ ) - { - BYTE nMem = mem[(nBaseAddress+iByte)&0xFFFF]; - sprintf( pDst, "%02X", nMem ); // sBytes+strlen(sBytes) - pDst += 2; - - // TODO: If Disassembly_IsDataAddress() don't show spaces... - if (g_bConfigDisasmOpcodeSpaces) - { - strcat( pDst, " " ); - pDst++; // 2.5.3.3 fix - } - } -} - -// Formats Target string with bytes,words, string, etc... -//=========================================================================== -void FormatNopcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ ) -{ - char *pDst = line_.sTarget; - const char *pSrc = 0; - DWORD nStartAddress = line_.pDisasmData->nStartAddress; - DWORD nEndAddress = line_.pDisasmData->nEndAddress ; -// int nDataLen = nEndAddress - nStartAddress + 1 ; - int nDisplayLen = nEndAddress - nBaseAddress + 1 ; // *inclusive* KEEP IN SYNC: _CmdDefineByteRange() CmdDisasmDataList() _6502_GetOpmodeOpbyte() FormatNopcodeBytes() - int len = nDisplayLen; - - for( int iByte = 0; iByte < line_.nOpbyte; ) - { - BYTE nTarget8 = *(LPBYTE)(mem + nBaseAddress + iByte); - WORD nTarget16 = *(LPWORD)(mem + nBaseAddress + iByte); - - switch( line_.iNoptype ) - { - case NOP_BYTE_1: - case NOP_BYTE_2: - case NOP_BYTE_4: - case NOP_BYTE_8: - sprintf( pDst, "%02X", nTarget8 ); // sBytes+strlen(sBytes) - pDst += 2; - iByte++; - if( line_.iNoptype == NOP_BYTE_1) - if( iByte < line_.nOpbyte ) - { - *pDst++ = ','; - } - break; - case NOP_WORD_1: - case NOP_WORD_2: - case NOP_WORD_4: - sprintf( pDst, "%04X", nTarget16 ); // sBytes+strlen(sBytes) - pDst += 4; - iByte+= 2; - if( iByte < line_.nOpbyte ) - { - *pDst++ = ','; - } - break; - case NOP_ADDRESS: - // Nothing to do, already handled :-) - iByte += 2; - break; - case NOP_STRING_APPLESOFT: - iByte = line_.nOpbyte; - strncpy( pDst, (const char*)(mem + nBaseAddress), iByte ); - pDst += iByte; - *pDst = 0; - case NOP_STRING_APPLE: - iByte = line_.nOpbyte; // handle all bytes of text - pSrc = (const char*)mem + nStartAddress; - - if (len > (MAX_IMMEDIATE_LEN - 2)) // does "text" fit? - { - if (len > MAX_IMMEDIATE_LEN) // no; need extra characters for ellipsis? - len = (MAX_IMMEDIATE_LEN - 3); // ellipsis = true - - // DISPLAY: text_longer_18... - FormatCharCopy( pDst, pSrc, len ); // BUG: #251 v2.8.0.7: ASC #:# with null byte doesn't mark up properly - - if( nDisplayLen > len ) // ellipsis - { - *pDst++ = '.'; - *pDst++ = '.'; - *pDst++ = '.'; - } - } else { // DISPLAY: "max_18_char" - *pDst++ = '"'; - pDst = FormatCharCopy( pDst, pSrc, len ); // BUG: #251 v2.8.0.7: ASC #:# with null byte doesn't mark up properly - *pDst++ = '"'; - } - - *pDst = 0; - break; - default: -#if _DEBUG // Unhandled data disassembly! - int *FATAL = 0; - *FATAL = 0xDEADC0DE; -#endif - iByte++; - break; - } - } -} - -//=========================================================================== -void FormatDisassemblyLine( const DisasmLine_t & line, char * sDisassembly, const int nBufferSize ) -{ - //> Address Seperator Opcodes Label Mnemonic Target [Immediate] [Branch] - // - // Data Disassembler - // Label Directive [Immediate] - const char * pMnemonic = g_aOpcodes[ line.iOpcode ].sMnemonic; - - sprintf( sDisassembly, "%s:%s %s " - , line.sAddress - , line.sOpCodes - , pMnemonic - ); - -/* - if (line.bTargetIndexed || line.bTargetIndirect) - { - strcat( sDisassembly, "(" ); - } - - if (line.bTargetImmediate) - strcat( sDisassembly, "#$" ); - - if (line.bTargetValue) - strcat( sDisassembly, line.sTarget ); - - if (line.bTargetIndirect) - { - if (line.bTargetX) - strcat( sDisassembly, ", X" ); - if (line.bTargetY) - strcat( sDisassembly, ", Y" ); - } - - if (line.bTargetIndexed || line.bTargetIndirect) - { - strcat( sDisassembly, ")" ); - } - - if (line.bTargetIndirect) - { - if (line.bTargetY) - strcat( sDisassembly, ", Y" ); - } -*/ - char sTarget[ 32 ]; - - if (line.bTargetValue || line.bTargetRelative || line.bTargetImmediate) - { - if (line.bTargetRelative) - strcpy( sTarget, line.sTargetValue ); - else - if (line.bTargetImmediate) - { - strcat( sDisassembly, "#" ); - strncpy( sTarget, line.sTarget, sizeof(sTarget) ); - sTarget[sizeof(sTarget)-1] = 0; - } - else - sprintf( sTarget, g_aOpmodes[ line.iOpmode ].m_sFormat, line.nTarget ); - - strcat( sDisassembly, "$" ); - strcat( sDisassembly, sTarget ); - } -} - //=========================================================================== WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress ) { diff --git a/source/Debugger/Debugger_Display.h b/source/Debugger/Debugger_Display.h index cae4841d..c728834e 100644 --- a/source/Debugger/Debugger_Display.h +++ b/source/Debugger/Debugger_Display.h @@ -1,11 +1,5 @@ #pragma once -// use the new Debugger Font (Apple Font) -#define USE_APPLE_FONT 1 - -// Test Colors & Glyphs -#define DEBUG_APPLE_FONT 0 - // Win32 Debugger Font enum ConsoleFontSize_e @@ -53,16 +47,6 @@ void DrawConsoleLine ( const conchar_t * pText, int y); void DrawConsoleCursor (); - int GetDisassemblyLine( const WORD nOffset, DisasmLine_t & line_ ); -// , int iOpcode, int iOpmode, int nOpbytes -// char *sAddress_, char *sOpCodes_, -// char *sTarget_, char *sTargetOffset_, int & nTargetOffset_, char *sTargetValue_, -// char * sImmediate_, char & nImmediate_, char *sBranch_ ); - WORD DrawDisassemblyLine ( int line, const WORD offset ); - void FormatDisassemblyLine( const DisasmLine_t & line, char *sDisassembly_, const int nBufferSize ); - void FormatOpcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ ); - void FormatNopcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ ); - // extern HDC GetDebuggerMemDC(void); diff --git a/source/Debugger/Debugger_Symbols.h b/source/Debugger/Debugger_Symbols.h index 444b0ea5..0481434b 100644 --- a/source/Debugger/Debugger_Symbols.h +++ b/source/Debugger/Debugger_Symbols.h @@ -1,11 +1,11 @@ // Variables extern SymbolTable_t g_aSymbols[ NUM_SYMBOL_TABLES ]; + extern bool g_bSymbolsDisplayMissingFile; // Prototypes Update_t _CmdSymbolsClear ( SymbolTable_Index_e eSymbolTable ); - Update_t _CmdSymbolsCommon ( int nArgs, SymbolTable_Index_e eSymbolTable ); Update_t _CmdSymbolsListTables (int nArgs, int bSymbolTables ); Update_t _CmdSymbolsUpdate ( int nArgs, int bSymbolTables ); @@ -15,3 +15,9 @@ // SymbolOffset int ParseSymbolTable ( const std::string & pFileName, SymbolTable_Index_e eWhichTableToLoad, int nSymbolOffset = 0 ); + // Symbol Table / Memory + bool FindAddressFromSymbol(const char* pSymbol, WORD* pAddress_ = NULL, int* iTable_ = NULL); + WORD GetAddressFromSymbol(const char* symbol); // HACK: returns 0 if symbol not found + void SymbolUpdate(SymbolTable_Index_e eSymbolTable, const char* pSymbolName, WORD nAddrss, bool bRemoveSymbol, bool bUpdateSymbol); + const char* FindSymbolFromAddress(WORD nAdress, int* iTable_ = NULL); + const char* GetSymbol(WORD nAddress, int nBytes); diff --git a/source/Debugger/Debugger_Types.h b/source/Debugger/Debugger_Types.h index 02722cb5..f163f0f4 100644 --- a/source/Debugger/Debugger_Types.h +++ b/source/Debugger/Debugger_Types.h @@ -1,5 +1,10 @@ #pragma once +// use the new Debugger Font (Apple Font) +#define USE_APPLE_FONT 1 + +// Test Colors & Glyphs +#define DEBUG_APPLE_FONT 0 // Addressing _____________________________________________________________________________________