From b9a2c7cd5f7a26fd343ea55b3c0c2b6810931eaa Mon Sep 17 00:00:00 2001 From: mpohoreski Date: Fri, 11 Jun 2010 15:38:22 +0000 Subject: [PATCH] debugger source cleanup -> moved 'source/debugger' --- AppleWin/source/Debugger/Debug.cpp | 8965 +++++++++++++++++ AppleWin/source/Debugger/Debug.h | 192 + .../source/Debugger/Debugger_Assembler.cpp | 1361 +++ AppleWin/source/Debugger/Debugger_Assembler.h | 180 + AppleWin/source/Debugger/Debugger_Console.cpp | 625 ++ AppleWin/source/Debugger/Debugger_Console.h | 256 + .../Debugger/Debugger_DisassemblerData.cpp | 367 + .../Debugger/Debugger_DisassemblerData.h | 55 + AppleWin/source/Debugger/Debugger_Display.cpp | 3383 +++++++ AppleWin/source/Debugger/Debugger_Display.h | 96 + AppleWin/source/Debugger/Debugger_Help.cpp | 1552 +++ AppleWin/source/Debugger/Debugger_Help.h | 33 + AppleWin/source/Debugger/Debugger_Parser.cpp | 1060 ++ AppleWin/source/Debugger/Debugger_Parser.h | 240 + AppleWin/source/Debugger/Debugger_Range.cpp | 123 + AppleWin/source/Debugger/Debugger_Range.h | 4 + AppleWin/source/Debugger/Debugger_Symbols.cpp | 862 ++ AppleWin/source/Debugger/Debugger_Symbols.h | 17 + AppleWin/source/Debugger/Debugger_Types.h | 1579 +++ 19 files changed, 20950 insertions(+) create mode 100644 AppleWin/source/Debugger/Debug.cpp create mode 100644 AppleWin/source/Debugger/Debug.h create mode 100644 AppleWin/source/Debugger/Debugger_Assembler.cpp create mode 100644 AppleWin/source/Debugger/Debugger_Assembler.h create mode 100644 AppleWin/source/Debugger/Debugger_Console.cpp create mode 100644 AppleWin/source/Debugger/Debugger_Console.h create mode 100644 AppleWin/source/Debugger/Debugger_DisassemblerData.cpp create mode 100644 AppleWin/source/Debugger/Debugger_DisassemblerData.h create mode 100644 AppleWin/source/Debugger/Debugger_Display.cpp create mode 100644 AppleWin/source/Debugger/Debugger_Display.h create mode 100644 AppleWin/source/Debugger/Debugger_Help.cpp create mode 100644 AppleWin/source/Debugger/Debugger_Help.h create mode 100644 AppleWin/source/Debugger/Debugger_Parser.cpp create mode 100644 AppleWin/source/Debugger/Debugger_Parser.h create mode 100644 AppleWin/source/Debugger/Debugger_Range.cpp create mode 100644 AppleWin/source/Debugger/Debugger_Range.h create mode 100644 AppleWin/source/Debugger/Debugger_Symbols.cpp create mode 100644 AppleWin/source/Debugger/Debugger_Symbols.h create mode 100644 AppleWin/source/Debugger/Debugger_Types.h diff --git a/AppleWin/source/Debugger/Debug.cpp b/AppleWin/source/Debugger/Debug.cpp new file mode 100644 index 00000000..1c47103c --- /dev/null +++ b/AppleWin/source/Debugger/Debug.cpp @@ -0,0 +1,8965 @@ +/* +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-2009, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Debugger + * + * Author: Copyright (C) 2006-2009 Michael Pohoreski + */ + +// disable warning C4786: symbol greater than 255 character: +//#pragma warning(disable: 4786) + +#include "StdAfx.h" + +// #define DEBUG_COMMAND_HELP 1 +// #define DEBUG_ASM_HASH 1 +#define ALLOW_INPUT_LOWERCASE 1 + + // See Debugger_Changelong.txt for full details + const int DEBUGGER_VERSION = MAKE_VERSION(2,6,2,0); + + +// Public _________________________________________________________________________________________ + +// All (Global) + bool g_bDebuggerEatKey = false; + +// Bookmarks __________________________________________________________________ +// vector g_aBookmarks; + int g_nBookmarks; + Bookmark_t g_aBookmarks[ MAX_BOOKMARKS ]; + +// Breakpoints ________________________________________________________________ + + // Full-Speed debugging + int g_nDebugOnBreakInvalid = 0; + int g_iDebugOnOpcode = 0; + bool g_bDebugDelayBreakCheck = false; + + int g_nBreakpoints = 0; + Breakpoint_t g_aBreakpoints[ MAX_BREAKPOINTS ]; + + // NOTE: Breakpoint_Source_t and g_aBreakpointSource must match! + const char *g_aBreakpointSource[ NUM_BREAKPOINT_SOURCES ] = + { // Used to be one char, since ArgsCook also uses // TODO/FIXME: Parser use Param[] ? + // Used for both Input & Output! + // Regs + "A", // Reg A + "X", // Reg X + "Y", // Reg Y + // Special + "PC", // Program Counter + "S" , // Stack Pointer + // Flags -- .8 Moved: Flag names from g_aFlagNames[] to "inlined" g_aBreakpointSource[] + "P", // Processor Status + "C", // ---- ---1 Carry + "Z", // ---- --1- Zero + "I", // ---- -1-- Interrupt + "D", // ---- 1--- Decimal + "B", // ---1 ---- Break + "R", // --1- ---- Reserved + "V", // -1-- ---- Overflow + "N", // 1--- ---- Sign + // Misc + "OP", // Opcode/Instruction/Mnemonic + // Memory + "M" // Main + // TODO: M0 ram bank 0, M1 aux ram ? + }; + + // Note: BreakpointOperator_t, _PARAM_BREAKPOINT_, and g_aBreakpointSymbols must match! + const char *g_aBreakpointSymbols[ NUM_BREAKPOINT_OPERATORS ] = + { // Output: Must be 2 chars! + "<=", // LESS_EQAUL + "< ", // LESS_THAN + "= ", // EQUAL + "!=", // NOT_EQUAL +// "! ", // NOT_EQUAL_1 + "> ", // GREATER_THAN + ">=", // GREATER_EQUAL + "? ", // READ // Q. IO Read use 'I'? A. No, since I=Interrupt + "@ ", // WRITE // Q. IO Write use 'O'? A. No, since O=Opcode + "* ", // Read/Write + }; + + +// Commands _______________________________________________________________________________________ + + #define __COMMANDS_VERIFY_TXT__ "\xDE\xAD\xC0\xDE" + #define __PARAMS_VERIFY_TXT__ "\xDE\xAD\xDA\x1A" + + int g_iCommand; // last command (enum) // used for consecuitive commands + + vector g_vPotentialCommands; // global, since TAB-completion also needs + vector g_vSortedCommands; + + // Setting function to NULL, allows g_aCommands arguments to be safely listed here + // Commands should be listed alphabetically per category. + // For the list sorted by category, check Commands_e + // NOTE: Commands_e and g_aCommands[] must be kept in sync! Aliases are listed at the end. + Command_t g_aCommands[] = + { + // Assembler + {TEXT("A") , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" }, + // Disassembler Data + {TEXT("B") , CmdDisasmDataDefByte1 , CMD_DISASM_DATA , "Treat byte [range] as data" }, + {TEXT("X") , CmdDisasmDataDefCode , CMD_DISASM_CODE , "Treat byte [range] as code" }, + {TEXT("DL") , CmdDisasmDataList , CMD_DISASM_LIST , "List all byte ranges treated as data" }, + // without symbol lookup + {TEXT("DB") , CmdDisasmDataDefByte1 , CMD_DEFINE_DATA_BYTE1, "Define byte (array)" }, + {TEXT("DB2") , CmdDisasmDataDefByte2 , CMD_DEFINE_DATA_BYTE2, "Define byte array, display 2 bytes/line" }, + {TEXT("DB4") , CmdDisasmDataDefByte4 , CMD_DEFINE_DATA_BYTE4, "Define byte array, display 4 bytes/line" }, + {TEXT("DB8") , CmdDisasmDataDefByte8 , CMD_DEFINE_DATA_BYTE8, "Define byte array, display 8 bytes/line" }, + {TEXT("DW") , CmdDisasmDataDefWord1 , CMD_DEFINE_DATA_WORD1, "Define address array" }, + {TEXT("DW2") , CmdDisasmDataDefWord2 , CMD_DEFINE_DATA_WORD2, "Define address array, display 2 words/line" }, + {TEXT("DW4") , CmdDisasmDataDefWord4 , CMD_DEFINE_DATA_WORD4, "Define address array, display 4 words/line" }, + {TEXT("DS") , CmdDisasmDataDefString , CMD_DEFINE_DATA_STR , "Define string" }, +// {TEXT("DF") , CmdDisasmDataDefFloat , CMD_DEFINE_DATA_FLOAT, "Define AppleSoft (packed) Float" }, +// {TEXT("DFX") , CmdDisasmDataDefFloatUnpack , CMD_DEFINE_DATA_FLOAT2,"Define AppleSoft (unpacked) Float" }, + // with symbol lookup +// {TEXT("DA<>") , CmdDisasmDataDefAddress8HL , CMD_DEFINE_ADDR_8_HL , "Define split array of addresses, high byte section followed by low byte section" }, +// {TEXT("DA><") , CmdDisasmDataDefAddress8LH , CMD_DEFINE_ADDR_8_LH , "Define split array of addresses, low byte section followed by high byte section" }, +// {TEXT("DA<") , CmdDisasmDataDefAddress8H , CMD_DEFINE_ADDR_BYTE_H , "Define array of high byte addresses" }, +// {TEXT("DB>") , CmdDisasmDataDefAddress8L , CMD_DEFINE_ADDR_BYTE_L , "Define array of low byte addresses" } + {TEXT(".DA") , CmdDisasmDataDefAddress16 , CMD_DEFINE_ADDR_WORD , "Define array of word addresses" }, +// TODO: Rename config cmd: DISASM +// {TEXT("UA") , CmdDisasmDataSmart , CMD_SMART_DISASSEMBLE, "Analyze opcodes to determine if code or data" }, + // CPU (Main) + {TEXT(".") , CmdCursorJumpPC , CMD_CURSOR_JUMP_PC , "Locate the cursor in the disasm window" }, // centered + {TEXT("=") , CmdCursorSetPC , CMD_CURSOR_SET_PC , "Sets the PC to the current instruction" }, + {TEXT("BRK") , CmdBreakInvalid , CMD_BREAK_INVALID , "Enter debugger on BRK or INVALID" }, + {TEXT("BRKOP") , CmdBreakOpcode , CMD_BREAK_OPCODE , "Enter debugger on opcode" }, + {TEXT("G") , CmdGo , CMD_GO , "Run [until PC = address]" }, + {TEXT("IN") , CmdIn , CMD_IN , "Input byte from IO $C0xx" }, + {TEXT("KEY") , CmdKey , CMD_INPUT_KEY , "Feed key into emulator" }, + {TEXT("JSR") , CmdJSR , CMD_JSR , "Call sub-routine" }, + {TEXT("NOP") , CmdNOP , CMD_NOP , "Zap the current instruction with a NOP" }, + {TEXT("OUT") , CmdOut , CMD_OUT , "Output byte to IO $C0xx" }, + {TEXT("PROFILE") , CmdProfile , CMD_PROFILE , "List/Save 6502 profiling" }, + {TEXT("R") , CmdRegisterSet , CMD_REGISTER_SET , "Set register" }, + {TEXT("POP") , CmdStackPop , CMD_STACK_POP }, + {TEXT("PPOP") , CmdStackPopPseudo , CMD_STACK_POP_PSEUDO }, + {TEXT("PUSH") , CmdStackPop , CMD_STACK_PUSH }, +// {TEXT("RTS") , CmdStackReturn , CMD_STACK_RETURN }, + {TEXT("P") , CmdStepOver , CMD_STEP_OVER , "Step current instruction" }, + {TEXT("RTS") , CmdStepOut , CMD_STEP_OUT , "Step out of subroutine" }, + {TEXT("T") , CmdTrace , CMD_TRACE , "Trace current instruction" }, + {TEXT("TF") , CmdTraceFile , CMD_TRACE_FILE , "Save trace to filename" }, + {TEXT("TL") , CmdTraceLine , CMD_TRACE_LINE , "Trace (with cycle counting)" }, + {TEXT("U") , CmdUnassemble , CMD_UNASSEMBLE , "Disassemble instructions" }, +// {TEXT("WAIT") , CmdWait , CMD_WAIT , "Run until + // Bookmarks + {TEXT("BM") , CmdBookmark , CMD_BOOKMARK , "Alias for BMA (Bookmark Add)" }, + {TEXT("BMA") , CmdBookmarkAdd , CMD_BOOKMARK_ADD , "Add/Update addess to bookmark" }, + {TEXT("BMC") , CmdBookmarkClear , CMD_BOOKMARK_CLEAR , "Clear (remove) bookmark" }, + {TEXT("BML") , CmdBookmarkList , CMD_BOOKMARK_LIST , "List all bookmarks" }, + {TEXT("BMG") , CmdBookmarkGoto , CMD_BOOKMARK_GOTO , "Move cursor to bookmark" }, +// {TEXT("BMLOAD") , CmdBookmarkLoad , CMD_BOOKMARK_LOAD , "Load bookmarks" }, + {TEXT("BMSAVE") , CmdBookmarkSave , CMD_BOOKMARK_SAVE , "Save bookmarks" }, + // Breakpoints + {TEXT("BP") , CmdBreakpoint , CMD_BREAKPOINT , "Alias for BPR (Breakpoint Register Add)" }, + {TEXT("BPA") , CmdBreakpointAddSmart, CMD_BREAKPOINT_ADD_SMART , "Add (smart) breakpoint" }, +// {TEXT("BPP") , CmdBreakpointAddFlag , CMD_BREAKPOINT_ADD_FLAG , "Add breakpoint on flags" }, + {TEXT("BPR") , CmdBreakpointAddReg , CMD_BREAKPOINT_ADD_REG , "Add breakpoint on register value" }, // NOTE! Different from SoftICE !!!! + {TEXT("BPX") , CmdBreakpointAddPC , CMD_BREAKPOINT_ADD_PC , "Add breakpoint at current instruction" }, + {TEXT("BPIO") , CmdBreakpointAddIO , CMD_BREAKPOINT_ADD_IO , "Add breakpoint for IO address $C0xx" }, + {TEXT("BPM") , CmdBreakpointAddMem , CMD_BREAKPOINT_ADD_MEM , "Add breakpoint on memory access" }, // SoftICE + + {TEXT("BPC") , CmdBreakpointClear , CMD_BREAKPOINT_CLEAR , "Clear (remove) breakpoint" }, // SoftICE + {TEXT("BPD") , CmdBreakpointDisable , CMD_BREAKPOINT_DISABLE , "Disable breakpoint- it is still in the list, just not active" }, // SoftICE + {TEXT("BPEDIT") , CmdBreakpointEdit , CMD_BREAKPOINT_EDIT , "Edit breakpoint" }, // SoftICE + {TEXT("BPE") , CmdBreakpointEnable , CMD_BREAKPOINT_ENABLE , "(Re)Enable disabled breakpoint" }, // SoftICE + {TEXT("BPL") , CmdBreakpointList , CMD_BREAKPOINT_LIST , "List all breakpoints" }, // SoftICE +// {TEXT("BPLOAD") , CmdBreakpointLoad , CMD_BREAKPOINT_LOAD , "Loads breakpoints" }, + {TEXT("BPSAVE") , CmdBreakpointSave , CMD_BREAKPOINT_SAVE , "Saves breakpoints" }, + // Config + {TEXT("BENCHMARK") , CmdBenchmark , CMD_BENCHMARK , "Benchmark the emulator" }, + {TEXT("BW") , CmdConfigColorMono , CMD_CONFIG_BW , "Sets/Shows RGB for Black & White scheme" }, + {TEXT("COLOR") , CmdConfigColorMono , CMD_CONFIG_COLOR , "Sets/Shows RGB for color scheme" }, +// {TEXT("OPTION") , CmdConfigMenu , CMD_CONFIG_MENU , "Access config options" }, + {TEXT("DISASM") , CmdConfigDisasm , CMD_CONFIG_DISASM , "Sets/Shows disassembly view options." }, + {TEXT("FONT") , CmdConfigFont , CMD_CONFIG_FONT , "Shows current font or sets new one" }, + {TEXT("HCOLOR") , CmdConfigHColor , CMD_CONFIG_HCOLOR , "Sets/Shows colors mapped to Apple HGR" }, + {TEXT("LOAD") , CmdConfigLoad , CMD_CONFIG_LOAD , "Load debugger configuration" }, + {TEXT("MONO") , CmdConfigColorMono , CMD_CONFIG_MONOCHROME , "Sets/Shows RGB for monochrome scheme" }, + {TEXT("SAVE") , CmdConfigSave , CMD_CONFIG_SAVE , "Save debugger configuration" }, + // Cursor + {TEXT("RET") , CmdCursorJumpRetAddr , CMD_CURSOR_JUMP_RET_ADDR , "Sets the cursor to the sub-routine caller" }, + {TEXT( "^") , NULL , CMD_CURSOR_LINE_UP }, // \x2191 = Up Arrow (Unicode) + {TEXT("Shift ^") , NULL , CMD_CURSOR_LINE_UP_1 }, + {TEXT( "v") , NULL , CMD_CURSOR_LINE_DOWN }, // \x2193 = Dn Arrow (Unicode) + {TEXT("Shift v") , NULL , CMD_CURSOR_LINE_DOWN_1 }, + {TEXT("PAGEUP" ) , CmdCursorPageUp , CMD_CURSOR_PAGE_UP , "Scroll up one screen" }, + {TEXT("PAGEUP256") , CmdCursorPageUp256 , CMD_CURSOR_PAGE_UP_256 , "Scroll up 256 bytes" }, // Shift + {TEXT("PAGEUP4K" ) , CmdCursorPageUp4K , CMD_CURSOR_PAGE_UP_4K , "Scroll up 4096 bytes" }, // Ctrl + {TEXT("PAGEDN" ) , CmdCursorPageDown , CMD_CURSOR_PAGE_DOWN , "Scroll down one scren" }, + {TEXT("PAGEDOWN256") , CmdCursorPageDown256 , CMD_CURSOR_PAGE_DOWN_256 , "Scroll down 256 bytes" }, // Shift + {TEXT("PAGEDOWN4K" ) , CmdCursorPageDown4K , CMD_CURSOR_PAGE_DOWN_4K , "Scroll down 4096 bytes" }, // Ctrl + // Disk + {TEXT("DISK") , CmdDisk , CMD_DISK , "Access Disk Drive Functions" }, + // Flags +// {TEXT("FC") , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" }, // NVRBDIZC see AW_CPU.cpp AF_* + {TEXT("CL") , CmdFlag , CMD_FLAG_CLEAR , "Clear specified Flag" }, // NVRBDIZC see AW_CPU.cpp AF_* + + {TEXT("CLC") , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" }, // 0 // Legacy + {TEXT("CLZ") , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" }, // 1 + {TEXT("CLI") , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" }, // 2 + {TEXT("CLD") , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" }, // 3 + {TEXT("CLB") , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("CLR") , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" }, // 5 + {TEXT("CLV") , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" }, // 6 + {TEXT("CLN") , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" }, // 7 + +// {TEXT("FS") , CmdFlag , CMD_FLAG_SET , "Set specified Flag" }, + {TEXT("SE") , CmdFlag , CMD_FLAG_SET , "Set specified Flag" }, + + {TEXT("SEC") , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" }, // 0 + {TEXT("SEZ") , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" }, // 1 + {TEXT("SEI") , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" }, // 2 + {TEXT("SED") , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" }, // 3 + {TEXT("SEB") , CmdFlagSet , CMD_FLAG_SET_B , "Set Flag Break" }, // 4 // Legacy + {TEXT("SER") , CmdFlagSet , CMD_FLAG_SET_R , "Set Flag Reserved" }, // 5 + {TEXT("SEV") , CmdFlagSet , CMD_FLAG_SET_V , "Set Flag Overflow" }, // 6 + {TEXT("SEN") , CmdFlagSet , CMD_FLAG_SET_N , "Set Flag Negative" }, // 7 + // Help + {TEXT("?") , CmdHelpList , CMD_HELP_LIST , "List all available commands" }, + {TEXT("HELP") , CmdHelpSpecific , CMD_HELP_SPECIFIC , "Help on specific command" }, + {TEXT("VERSION") , CmdVersion , CMD_VERSION , "Displays version of emulator/debugger" }, + {TEXT("MOTD") , CmdMOTD , CMD_MOTD }, + // Memory + {TEXT("MC") , CmdMemoryCompare , CMD_MEMORY_COMPARE }, + + {TEXT("D") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" }, // FIXME: Must also work in DATA screen + {TEXT("MD1") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 , "Hex dump in the mini memory area 1" }, + {TEXT("MD2") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 , "Hex dump in the mini memory area 2" }, + {TEXT("M1") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // alias + {TEXT("M2") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_2 }, // alias + + {TEXT("MA1") , CmdMemoryMiniDumpAscii,CMD_MEM_MINI_DUMP_ASCII_1, "ASCII text in mini memory area 1" }, + {TEXT("MA2") , CmdMemoryMiniDumpAscii,CMD_MEM_MINI_DUMP_ASCII_2, "ASCII text in mini memory area 2" }, + {TEXT("MT1") , CmdMemoryMiniDumpApple,CMD_MEM_MINI_DUMP_APPLE_1, "Apple Text in mini memory area 1" }, + {TEXT("MT2") , CmdMemoryMiniDumpApple,CMD_MEM_MINI_DUMP_APPLE_2, "Apple Text in mini memory area 2" }, +// {TEXT("ML1") , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_1, "Text (Ctrl) in mini memory dump area 1" }, +// {TEXT("ML2") , CmdMemoryMiniDumpLow , CMD_MEM_MINI_DUMP_TXT_LO_2, "Text (Ctrl) in mini memory dump area 2" }, +// {TEXT("MH1") , CmdMemoryMiniDumpHigh, CMD_MEM_MINI_DUMP_TXT_HI_1, "Text (High) in mini memory dump area 1" }, +// {TEXT("MH2") , CmdMemoryMiniDumpHigh, CMD_MEM_MINI_DUMP_TXT_HI_2, "Text (High) in mini memory dump area 2" }, + + {TEXT("ME") , CmdMemoryEdit , CMD_MEMORY_EDIT }, // TODO: like Copy ][+ Sector Edit + {TEXT("MEB") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE , "Enter byte" }, + {TEXT("MEW") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD , "Enter word" }, + {TEXT("BLOAD") , CmdMemoryLoad , CMD_MEMORY_LOAD , "Load a region of memory" }, + {TEXT("M") , CmdMemoryMove , CMD_MEMORY_MOVE , "Memory move" }, + {TEXT("BSAVE") , CmdMemorySave , CMD_MEMORY_SAVE , "Save a region of memory" }, + {TEXT("S") , CmdMemorySearch , CMD_MEMORY_SEARCH , "Search memory for text / hex values" }, + {TEXT("@") ,_SearchMemoryDisplay , CMD_MEMORY_FIND_RESULTS , "Display search memory results" }, +// {TEXT("SA") , CmdMemorySearchAscii, CMD_MEMORY_SEARCH_ASCII , "Search ASCII text" }, +// {TEXT("ST") , CmdMemorySearchApple , CMD_MEMORY_SEARCH_APPLE , "Search Apple text (hi-bit)" }, + {TEXT("SH") , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" }, + {TEXT("F") , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" }, + // Output / Scripts + {TEXT("CALC") , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" }, + {TEXT("ECHO") , CmdOutputEcho , CMD_OUTPUT_ECHO , "Echo string to console" }, // or toggle command echoing" + {TEXT("PRINT") , CmdOutputPrint , CMD_OUTPUT_PRINT , "Display string and/or hex values" }, + {TEXT("PRINTF") , CmdOutputPrintf , CMD_OUTPUT_PRINTF , "Display formatted string" }, + {TEXT("RUN") , CmdOutputRun , CMD_OUTPUT_RUN , "Run script file of debugger commands" }, + // Source Level Debugging + {TEXT("SOURCE") , CmdSource , CMD_SOURCE , "Starts/Stops source level debugging" }, + {TEXT("SYNC") , CmdSync , CMD_SYNC , "Syncs the cursor to the source file" }, + // Symbols + {TEXT("SYM") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Lookup symbol or address, or define symbol" }, + + {TEXT("SYMMAIN") , CmdSymbolsCommand , CMD_SYMBOLS_ROM , "Main/ROM symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {TEXT("SYMBASIC") , CmdSymbolsCommand , CMD_SYMBOLS_APPLESOFT , "Applesoft symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {TEXT("SYMASM") , CmdSymbolsCommand , CMD_SYMBOLS_ASSEMBLY , "Assembly symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {TEXT("SYMUSER") , CmdSymbolsCommand , CMD_SYMBOLS_USER_1 , "First user symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {TEXT("SYMUSER2") , CmdSymbolsCommand , CMD_SYMBOLS_USER_2 , "Second User symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {TEXT("SYMSRC") , CmdSymbolsCommand , CMD_SYMBOLS_SRC_1 , "First Source symbol table lookup/menu" }, // CLEAR,LOAD,SAVE + {TEXT("SYMSRC2") , CmdSymbolsCommand , CMD_SYMBOLS_SRC_2 , "Second Source symbol table lookup/menu" }, // CLEAR,LOAD,SAVE +// {TEXT("SYMCLEAR") , CmdSymbolsClear , CMD_SYMBOLS_CLEAR }, // can't use SC = SetCarry + {TEXT("SYMINFO") , CmdSymbolsInfo , CMD_SYMBOLS_INFO , "Display summary of symbols" }, + {TEXT("SYMLIST") , CmdSymbolsList , CMD_SYMBOLS_LIST , "Lookup symbol in main/user/src tables" }, // 'symbolname', can't use param '*' + // Variables +// {TEXT("CLEAR") , CmdVarsClear , CMD_VARIABLES_CLEAR }, +// {TEXT("VAR") , CmdVarsDefine , CMD_VARIABLES_DEFINE }, +// {TEXT("INT8") , CmdVarsDefineInt8 , CMD_VARIABLES_DEFINE_INT8}, +// {TEXT("INT16") , CmdVarsDefineInt16 , CMD_VARIABLES_DEFINE_INT16}, +// {TEXT("VARS") , CmdVarsList , CMD_VARIABLES_LIST }, +// {TEXT("VARSLOAD") , CmdVarsLoad , CMD_VARIABLES_LOAD }, +// {TEXT("VARSSAVE") , CmdVarsSave , CMD_VARIABLES_SAVE }, +// {TEXT("SET") , CmdVarsSet , CMD_VARIABLES_SET }, + // View + {TEXT("TEXT") , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X, "View Text screen (current page)" }, + {TEXT("TEXT1") , CmdViewOutput_Text41 , CMD_VIEW_TEXT41, "View Text screen Page 1" }, + {TEXT("TEXT2") , CmdViewOutput_Text42 , CMD_VIEW_TEXT42, "View Text screen Page 2" }, + {TEXT("TEXT80") , CmdViewOutput_Text8X , CMD_VIEW_TEXT8X, "View 80-col Text screen (current page)" }, + {TEXT("TEXT81") , CmdViewOutput_Text81 , CMD_VIEW_TEXT8X, "View 80-col Text screen Page 1" }, + {TEXT("TEXT82") , CmdViewOutput_Text82 , CMD_VIEW_TEXT8X, "View 80-col Text screen Page 2" }, + {TEXT("GR") , CmdViewOutput_GRX , CMD_VIEW_GRX , "View Lo-Res screen (current page)" }, + {TEXT("GR1") , CmdViewOutput_GR1 , CMD_VIEW_GR1 , "View Lo-Res screen Page 1" }, + {TEXT("GR2") , CmdViewOutput_GR2 , CMD_VIEW_GR2 , "View Lo-Res screen Page 2" }, + {TEXT("DGR") , CmdViewOutput_DGRX , CMD_VIEW_DGRX , "View Double lo-res (current page)" }, + {TEXT("DGR1") , CmdViewOutput_DGR1 , CMD_VIEW_DGR1 , "View Double lo-res Page 1" }, + {TEXT("DGR2") , CmdViewOutput_DGR2 , CMD_VIEW_DGR2 , "View Double lo-res Page 2" }, + {TEXT("HGR") , CmdViewOutput_HGRX , CMD_VIEW_HGRX , "View Hi-res (current page)" }, + {TEXT("HGR1") , CmdViewOutput_HGR1 , CMD_VIEW_HGR1 , "View Hi-res Page 1" }, + {TEXT("HGR2") , CmdViewOutput_HGR2 , CMD_VIEW_HGR2 , "View Hi-res Page 2" }, + {TEXT("DHGR") , CmdViewOutput_DHGRX , CMD_VIEW_DHGRX , "View Double Hi-res (current page)" }, + {TEXT("DHGR1") , CmdViewOutput_DHGR1 , CMD_VIEW_DHGR1 , "View Double Hi-res Page 1" }, + {TEXT("DHGR2") , CmdViewOutput_DHGR2 , CMD_VIEW_DHGR2 , "View Double Hi-res Page 2" }, + // Watch + {TEXT("W") , CmdWatch , CMD_WATCH_ADD , "Alias for WA (Watch Add)" }, + {TEXT("WA") , CmdWatchAdd , CMD_WATCH_ADD , "Add/Update address or symbol to watch" }, + {TEXT("WC") , CmdWatchClear , CMD_WATCH_CLEAR , "Clear (remove) watch" }, + {TEXT("WD") , CmdWatchDisable , CMD_WATCH_DISABLE , "Disable specific watch - it is still in the list, just not active" }, + {TEXT("WE") , CmdWatchEnable , CMD_WATCH_ENABLE , "(Re)Enable disabled watch" }, + {TEXT("WL") , CmdWatchList , CMD_WATCH_LIST , "List all watches" }, +// {TEXT("WLOAD") , CmdWatchLoad , CMD_WATCH_LOAD , "Load Watches" }, // Cant use as param to W + {TEXT("WSAVE") , CmdWatchSave , CMD_WATCH_SAVE , "Save Watches" }, // due to symbol look-up + // Window + {TEXT("WIN") , CmdWindow , CMD_WINDOW , "Show specified debugger window" }, +// TODO: need to rename with data disassembly + {TEXT("CODE") , CmdWindowViewCode , CMD_WINDOW_CODE , "Switch to full code window" }, // Can't use WC = WatchClear + {TEXT("CODE1") , CmdWindowShowCode1 , CMD_WINDOW_CODE_1 , "Show code on top split window" }, + {TEXT("CODE2") , CmdWindowShowCode2 , CMD_WINDOW_CODE_2 , "Show code on bottom split window" }, + {TEXT("CONSOLE") , CmdWindowViewConsole , CMD_WINDOW_CONSOLE , "Switch to full console window" }, +// TODO: need to rename with data disassembly + {TEXT("DATA") , CmdWindowViewData , CMD_WINDOW_DATA , "Switch to full data window" }, + {TEXT("DATA1") , CmdWindowShowCode1 , CMD_WINDOW_CODE_1 , "Show data on top split window" }, + {TEXT("DATA2") , CmdWindowShowData2 , CMD_WINDOW_DATA_2 , "Show data on bottom split window" }, + {TEXT("SOURCE1") , CmdWindowShowSource1 , CMD_WINDOW_SOURCE_1, "Show source on top split screen" }, + {TEXT("SOURCE2") , CmdWindowShowSource2 , CMD_WINDOW_SOURCE_2, "Show source on bottom split screen" }, + + {TEXT("\\") , CmdWindowViewOutput , CMD_WINDOW_OUTPUT , "Display Apple output until key pressed" }, +// {TEXT("INFO") , CmdToggleInfoPanel , CMD_WINDOW_TOGGLE }, +// {TEXT("WINSOURCE") , CmdWindowShowSource , CMD_WINDOW_SOURCE }, +// {TEXT("ZEROPAGE") , CmdWindowShowZeropage, CMD_WINDOW_ZEROPAGE }, + // Zero Page + {TEXT("ZP") , CmdZeroPage , CMD_ZEROPAGE_POINTER , "Alias for ZPA (Zero Page Add)" }, + {TEXT("ZP0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 , "Set/Update/Remove ZP watch 0 " }, + {TEXT("ZP1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 , "Set/Update/Remove ZP watch 1" }, + {TEXT("ZP2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 , "Set/Update/Remove ZP watch 2" }, + {TEXT("ZP3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 , "Set/Update/Remove ZP watch 3" }, + {TEXT("ZP4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 , "Set/Update/Remove ZP watch 4" }, + {TEXT("ZP5") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_5 , "Set/Update/Remove ZP watch 5 " }, + {TEXT("ZP6") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_6 , "Set/Update/Remove ZP watch 6" }, + {TEXT("ZP7") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_7 , "Set/Update/Remove ZP watch 7" }, + {TEXT("ZPA") , CmdZeroPageAdd , CMD_ZEROPAGE_POINTER_ADD , "Add/Update address to zero page pointer"}, + {TEXT("ZPC") , CmdZeroPageClear , CMD_ZEROPAGE_POINTER_CLEAR , "Clear (remove) zero page pointer" }, + {TEXT("ZPD") , CmdZeroPageDisable , CMD_ZEROPAGE_POINTER_DISABLE,"Disable zero page pointer - it is still in the list, just not active" }, + {TEXT("ZPE") , CmdZeroPageEnable , CMD_ZEROPAGE_POINTER_ENABLE, "(Re)Enable disabled zero page pointer" }, + {TEXT("ZPL") , CmdZeroPageList , CMD_ZEROPAGE_POINTER_LIST , "List all zero page pointers" }, +// {TEXT("ZPLOAD") , CmdZeroPageLoad , CMD_ZEROPAGE_POINTER_LOAD , "Load zero page pointers" }, // Cant use as param to ZP + {TEXT("ZPSAVE") , CmdZeroPageSave , CMD_ZEROPAGE_POINTER_SAVE , "Save zero page pointers" }, // due to symbol look-up + +// {TEXT("TIMEDEMO"),CmdTimeDemo, CMD_TIMEDEMO }, // CmdBenchmarkStart(), CmdBenchmarkStop() +// {TEXT("WC"),CmdShowCodeWindow}, // Can't use since WatchClear +// {TEXT("WD"),CmdShowDataWindow}, // + + // Internal Consistency Check + {TEXT(__COMMANDS_VERIFY_TXT__), NULL, NUM_COMMANDS }, + + // Aliasies - Can be in any order + {TEXT("->") , NULL , CMD_CURSOR_JUMP_PC }, + {TEXT("Ctrl ->" ) , NULL , CMD_CURSOR_SET_PC }, + {TEXT("Shift ->") , NULL , CMD_CURSOR_JUMP_PC }, // at top + {TEXT("INPUT") , CmdIn , CMD_IN }, + // Data + // Flags - Clear + {TEXT("RC") , CmdFlagClear , CMD_FLAG_CLR_C , "Clear Flag Carry" }, // 0 // Legacy + {TEXT("RZ") , CmdFlagClear , CMD_FLAG_CLR_Z , "Clear Flag Zero" }, // 1 + {TEXT("RI") , CmdFlagClear , CMD_FLAG_CLR_I , "Clear Flag Interrupts Disabled" }, // 2 + {TEXT("RD") , CmdFlagClear , CMD_FLAG_CLR_D , "Clear Flag Decimal (BCD)" }, // 3 + {TEXT("RB") , CmdFlagClear , CMD_FLAG_CLR_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("RR") , CmdFlagClear , CMD_FLAG_CLR_R , "Clear Flag Reserved" }, // 5 + {TEXT("RV") , CmdFlagClear , CMD_FLAG_CLR_V , "Clear Flag Overflow" }, // 6 + {TEXT("RN") , CmdFlagClear , CMD_FLAG_CLR_N , "Clear Flag Negative (Sign)" }, // 7 + // Flags - Set + {TEXT("SC") , CmdFlagSet , CMD_FLAG_SET_C , "Set Flag Carry" }, // 0 + {TEXT("SZ") , CmdFlagSet , CMD_FLAG_SET_Z , "Set Flag Zero" }, // 1 + {TEXT("SI") , CmdFlagSet , CMD_FLAG_SET_I , "Set Flag Interrupts Disabled" }, // 2 + {TEXT("SD") , CmdFlagSet , CMD_FLAG_SET_D , "Set Flag Decimal (BCD)" }, // 3 + {TEXT("SB") , CmdFlagSet , CMD_FLAG_SET_B , "CLear Flag Break" }, // 4 // Legacy + {TEXT("SR") , CmdFlagSet , CMD_FLAG_SET_R , "Clear Flag Reserved" }, // 5 + {TEXT("SV") , CmdFlagSet , CMD_FLAG_SET_V , "Clear Flag Overflow" }, // 6 + {TEXT("SN") , CmdFlagSet , CMD_FLAG_SET_N , "Clear Flag Negative" }, // 7 + + {TEXT("ME8") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE }, // changed from EB -- bugfix: EB:## ## + {TEXT("ME16") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD }, + {TEXT("MM") , CmdMemoryMove , CMD_MEMORY_MOVE }, + {TEXT("MS") , CmdMemorySearch , CMD_MEMORY_SEARCH }, // CmdMemorySearch + {TEXT("P0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 }, + {TEXT("P1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 }, + {TEXT("P2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 }, + {TEXT("P3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 }, + {TEXT("P4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 }, + {TEXT("REGISTER") , CmdRegisterSet , CMD_REGISTER_SET }, +// {TEXT("RET") , CmdStackReturn , CMD_STACK_RETURN }, + {TEXT("TRACE") , CmdTrace , CMD_TRACE }, + {TEXT("SYMBOLS") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Return " }, +// {TEXT("SYMBOLS1") , CmdSymbolsInfo , CMD_SYMBOLS_1 }, +// {TEXT("SYMBOLS2") , CmdSymbolsInfo , CMD_SYMBOLS_2 }, + + {TEXT("SYM0" ) , CmdSymbolsInfo , CMD_SYMBOLS_ROM }, + {TEXT("SYM1" ) , CmdSymbolsInfo , CMD_SYMBOLS_APPLESOFT }, + {TEXT("SYM2" ) , CmdSymbolsInfo , CMD_SYMBOLS_ASSEMBLY }, + {TEXT("SYM3" ) , CmdSymbolsInfo , CMD_SYMBOLS_USER_1 }, + {TEXT("SYM4" ) , CmdSymbolsInfo , CMD_SYMBOLS_USER_2 }, + {TEXT("SYM5" ) , CmdSymbolsInfo , CMD_SYMBOLS_SRC_1 }, + {TEXT("SYM6" ) , CmdSymbolsInfo , CMD_SYMBOLS_SRC_2 }, + + {TEXT("TEXT40") , CmdViewOutput_Text4X , CMD_VIEW_TEXT4X }, + {TEXT("TEXT41") , CmdViewOutput_Text41 , CMD_VIEW_TEXT41 }, + {TEXT("TEXT42") , CmdViewOutput_Text42 , CMD_VIEW_TEXT42 }, + + {TEXT("WATCH") , CmdWatchAdd , CMD_WATCH_ADD }, + {TEXT("WINDOW") , CmdWindow , CMD_WINDOW }, +// {TEXT("W?") , CmdWatchAdd , CMD_WATCH_ADD }, + {TEXT("ZAP") , CmdNOP , CMD_NOP }, + + // DEPRECATED -- Probably should be removed in a future version + {TEXT("BENCH") , CmdBenchmarkStart , CMD_BENCHMARK }, + {TEXT("EXITBENCH") , CmdBenchmarkStop , CMD_BENCHMARK }, + {TEXT("MDB") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this?? + {TEXT("MEMORY") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this?? +}; + +// static const char g_aFlagNames[_6502_NUM_FLAGS+1] = TEXT("CZIDBRVN");// Reversed since arrays are from left-to-right + + const int NUM_COMMANDS_WITH_ALIASES = sizeof(g_aCommands) / sizeof (Command_t); // Determined at compile-time ;-) + + +// Color ______________________________________________________________________ + + int g_iColorScheme = SCHEME_COLOR; + + // Used when the colors are reset + COLORREF gaColorPalette[ NUM_PALETTE ] = + { + RGB(0,0,0), + // NOTE: See _SetupColorRamp() if you want to programmitically set/change + RGB(255, 0, 0), RGB(223, 0, 0), RGB(191, 0, 0), RGB(159, 0, 0), RGB(127, 0, 0), RGB( 95, 0, 0), RGB( 63, 0, 0), RGB( 31, 0, 0), // 001 // Red + RGB( 0,255, 0), RGB( 0,223, 0), RGB( 0,191, 0), RGB( 0,159, 0), RGB( 0,127, 0), RGB( 0, 95, 0), RGB( 0, 63, 0), RGB( 0, 31, 0), // 010 // Green + RGB(255,255, 0), RGB(223,223, 0), RGB(191,191, 0), RGB(159,159, 0), RGB(127,127, 0), RGB( 95, 95, 0), RGB( 63, 63, 0), RGB( 31, 31, 0), // 011 // Yellow + RGB( 0, 0,255), RGB( 0, 0,223), RGB( 0, 0,191), RGB( 0, 0,159), RGB( 0, 0,127), RGB( 0, 0, 95), RGB( 0, 0, 63), RGB( 0, 0, 31), // 100 // Blue + RGB(255, 0,255), RGB(223, 0,223), RGB(191, 0,191), RGB(159, 0,159), RGB(127, 0,127), RGB( 95, 0, 95), RGB( 63, 0, 63), RGB( 31, 0, 31), // 101 // Magenta + RGB( 0,255,255), RGB( 0,223,223), RGB( 0,191,191), RGB( 0,159,159), RGB( 0,127,127), RGB( 0, 95, 95), RGB( 0, 63, 63), RGB( 0, 31, 31), // 110 // Cyan + RGB(255,255,255), RGB(223,223,223), RGB(191,191,191), RGB(159,159,159), RGB(127,127,127), RGB( 95, 95, 95), RGB( 63, 63, 63), RGB( 31, 31, 31), // 111 // White/Gray + + // Custom Colors + RGB( 80,192,255), // Light Sky Blue // Used for console FG + RGB( 0,128,192), // Darker Sky Blue + RGB( 0, 64,128), // Deep Sky Blue + RGB(255,128, 0), // Orange (Full) + RGB(128, 64, 0), // Orange (Half) + RGB( 0, 0, 0), + RGB( 0, 0, 0), + RGB( 0, 0, 0), + + RGB( 0, 0, 0), + RGB( 0, 0, 0), + RGB( 0, 0, 0), + RGB( 0, 0, 0), + RGB( 0, 0, 0), + RGB( 0, 0, 0), + RGB( 0, 0, 0), + RGB( 0, 0, 0), + }; + + // Index into Palette + int g_aColorIndex[ NUM_DEBUG_COLORS ] = + { + K0, W8, // BG_CONSOLE_OUTPUT FG_CONSOLE_OUTPUT (W8) + + B1, COLOR_CUSTOM_01, // BG_CONSOLE_INPUT FG_CONSOLE_INPUT (W8) + + B2, B3, // BG_DISASM_1 BG_DISASM_2 + + R8, W8, // BG_DISASM_BP_S_C FG_DISASM_BP_S_C + R6, W5, // BG_DISASM_BP_0_C FG_DISASM_BP_0_C + + R7, // FG_DISASM_BP_S_X // Y8 lookes better on Info Cyan // R6 + W5, // FG_DISASM_BP_0_X + + W8, K0, // BG_DISASM_C FG_DISASM_C // B8 -> K0 + Y8, K0, // BG_DISASM_PC_C FG_DISASM_PC_C // K8 -> K0 + Y4, W8, // BG_DISASM_PC_X FG_DISASM_PC_X + + C4, // BG_DISASM_BOOKMARK + W8, // FG_DISASM_BOOKMARK + + W8, // FG_DISASM_ADDRESS + G192, // FG_DISASM_OPERATOR + Y8, // FG_DISASM_OPCODE + W8, // FG_DISASM_MNEMONIC + COLOR_CUSTOM_04, // FG_DISASM_TARGET (or W8) + G8, // FG_DISASM_SYMBOL + C8, // FG_DISASM_CHAR + G8, // FG_DISASM_BRANCH + + C3, // BG_INFO (C4, C2 too dark) + W8, // FG_INFO_TITLE (or W8) + Y7, // FG_INFO_BULLET (W8) + G192, // FG_INFO_OPERATOR + COLOR_CUSTOM_04, // FG_INFO_ADDRESS (was Y8) + Y8, // FG_INFO_OPCODE + COLOR_CUSTOM_01, // FG_INFO_REG (was orange) + + W8, // BG_INFO_INVERSE + C3, // FG_INFO_INVERSE + C5, // BG_INFO_CHAR + W8, // FG_INFO_CHAR_HI + Y8, // FG_INFO_CHAR_LO + + COLOR_CUSTOM_04, // BG_INFO_IO_BYTE + COLOR_CUSTOM_04, // FG_INFO_IO_BYTE + + C2, // BG_DATA_1 + C3, // BG_DATA_2 + Y8, // FG_DATA_BYTE + W8, // FG_DATA_TEXT + + G4, // BG_SYMBOLS_1 + G3, // BG_SYMBOLS_2 + W8, // FG_SYMBOLS_ADDRESS + M8, // FG_SYMBOLS_NAME + + K0, // BG_SOURCE_TITLE + W8, // FG_SOURCE_TITLE + W2, // BG_SOURCE_1 // C2 W2 for "Paper Look" + W3, // BG_SOURCE_2 + W8 // FG_SOURCE + }; + + COLORREF g_aColors[ NUM_COLOR_SCHEMES ][ NUM_DEBUG_COLORS ]; + + COLORREF DebuggerGetColor ( int iColor ); + + +// Cursor (Console Input) _____________________________________________________ + +// char g_aInputCursor[] = "\|/-"; + enum InputCursor + { + CURSOR_INSERT, + CURSOR_OVERSTRIKE, + NUM_INPUT_CURSORS + }; + + const char g_aInputCursor[] = "_\x7F"; // insert over-write + bool g_bInputCursor = false; + int g_iInputCursor = CURSOR_OVERSTRIKE; // which cursor to use + const int g_nInputCursor = sizeof( g_aInputCursor ); + + void DebuggerCursorUpdate(); + char DebuggerCursorGet(); + +// Cursor (Disasm) ____________________________________________________________ + + WORD g_nDisasmTopAddress = 0; + WORD g_nDisasmBotAddress = 0; + WORD g_nDisasmCurAddress = 0; + + bool g_bDisasmCurBad = false; + int g_nDisasmCurLine = 0; // Aligned to Top or Center + int g_iDisasmCurState = CURSOR_NORMAL; + + int g_nDisasmWinHeight = 0; + +// char g_aConfigDisasmAddressColon[] = TEXT(" :"); + + extern const int WINDOW_DATA_BYTES_PER_LINE = 8; + +#if OLD_FONT +// Font + TCHAR g_sFontNameDefault[ MAX_FONT_NAME ] = TEXT("Courier New"); + TCHAR g_sFontNameConsole[ MAX_FONT_NAME ] = TEXT("Courier New"); + TCHAR g_sFontNameDisasm [ MAX_FONT_NAME ] = TEXT("Courier New"); + TCHAR g_sFontNameInfo [ MAX_FONT_NAME ] = TEXT("Courier New"); + TCHAR g_sFontNameBranch [ MAX_FONT_NAME ] = TEXT("Webdings"); + HFONT g_hFontWebDings = (HFONT)0; +#endif + int g_iFontSpacing = FONT_SPACING_CLEAN; + + // TODO: This really needs to be phased out, and use the ConfigFont[] settings +#if USE_APPLE_FONT + int g_nFontHeight = CONSOLE_FONT_HEIGHT; // 13 -> 12 Lucida Console is readable +#else + int g_nFontHeight = 15; // 13 -> 12 Lucida Console is readable +#endif + + const int MIN_DISPLAY_CONSOLE_LINES = 5; // doesn't include ConsoleInput + + int g_nDisasmDisplayLines = 0; + + +// Config _____________________________________________________________________ + +// Config - Disassembly + bool g_bConfigDisasmAddressView = true; + bool g_bConfigDisasmAddressColon = true; + bool g_bConfigDisasmOpcodesView = true; + bool g_bConfigDisasmOpcodeSpaces = true; + int g_iConfigDisasmTargets = DISASM_TARGET_BOTH; + int g_iConfigDisasmBranchType = DISASM_BRANCH_FANCY; + int g_bConfigDisasmImmediateChar = DISASM_IMMED_BOTH; + int g_iConfigDisasmScroll = 3; // favor 3 byte opcodes +// Config - Info + bool g_bConfigInfoTargetPointer = false; + + MemoryTextFile_t g_ConfigState; + +// Display ____________________________________________________________________ + + void UpdateDisplay( Update_t bUpdate ); + + +// Memory _____________________________________________________________________ + + const int _6502_BRANCH_POS = +127; + const int _6502_BRANCH_NEG = -128; + const unsigned int _6502_ZEROPAGE_END = 0x00FF; + const unsigned int _6502_STACK_END = 0x01FF; + const unsigned int _6502_IO_BEGIN = 0xC000; + const unsigned int _6502_IO_END = 0xC0FF; + const unsigned int _6502_MEM_BEGIN = 0x0000; + const unsigned int _6502_MEM_END = 0xFFFF; + + MemoryDump_t g_aMemDump[ NUM_MEM_DUMPS ]; + + // Made global so operator @# can be used with other commands. + MemorySearchResults_t g_vMemorySearchResults; + + +// Parameters _____________________________________________________________________________________ + + // NOTE: Order MUST match Parameters_e[] !!! + Command_t g_aParameters[] = + { +// Breakpoint + {TEXT("<=") , NULL, PARAM_BP_LESS_EQUAL }, + {TEXT("<" ) , NULL, PARAM_BP_LESS_THAN }, + {TEXT("=" ) , NULL, PARAM_BP_EQUAL }, + {TEXT("!=") , NULL, PARAM_BP_NOT_EQUAL }, + {TEXT("!" ) , NULL, PARAM_BP_NOT_EQUAL_1 }, + {TEXT(">" ) , NULL, PARAM_BP_GREATER_THAN }, + {TEXT(">=") , NULL, PARAM_BP_GREATER_EQUAL }, + {TEXT("R") , NULL, PARAM_BP_READ }, + {TEXT("?") , NULL, PARAM_BP_READ }, + {TEXT("W") , NULL, PARAM_BP_WRITE }, + {TEXT("@") , NULL, PARAM_BP_WRITE }, + {TEXT("*") , NULL, PARAM_BP_READ_WRITE }, +// Regs (for PUSH / POP) + {TEXT("A") , NULL, PARAM_REG_A }, + {TEXT("X") , NULL, PARAM_REG_X }, + {TEXT("Y") , NULL, PARAM_REG_Y }, + {TEXT("PC") , NULL, PARAM_REG_PC }, + {TEXT("S") , NULL, PARAM_REG_SP }, +// Flags + {TEXT("P") , NULL, PARAM_FLAGS }, + {TEXT("C") , NULL, PARAM_FLAG_C }, // ---- ---1 Carry + {TEXT("Z") , NULL, PARAM_FLAG_Z }, // ---- --1- Zero + {TEXT("I") , NULL, PARAM_FLAG_I }, // ---- -1-- Interrupt + {TEXT("D") , NULL, PARAM_FLAG_D }, // ---- 1--- Decimal + {TEXT("B") , NULL, PARAM_FLAG_B }, // ---1 ---- Break + {TEXT("R") , NULL, PARAM_FLAG_R }, // --1- ---- Reserved + {TEXT("V") , NULL, PARAM_FLAG_V }, // -1-- ---- Overflow + {TEXT("N") , NULL, PARAM_FLAG_N }, // 1--- ---- Sign +// Disasm + {TEXT("BRANCH") , NULL, PARAM_CONFIG_BRANCH }, + {TEXT("COLON") , NULL, PARAM_CONFIG_COLON }, + {TEXT("OPCODE") , NULL, PARAM_CONFIG_OPCODE }, + {TEXT("POINTER") , NULL, PARAM_CONFIG_POINTER }, + {TEXT("SPACES") , NULL, PARAM_CONFIG_SPACES }, + {TEXT("TARGET") , NULL, PARAM_CONFIG_TARGET }, +// Disk + {TEXT("EJECT") , NULL, PARAM_DISK_EJECT }, + {TEXT("PROTECT") , NULL, PARAM_DISK_PROTECT }, + {TEXT("READ") , NULL, PARAM_DISK_READ }, +// Font (Config) + {TEXT("MODE") , NULL, PARAM_FONT_MODE }, // also INFO, CONSOLE, DISASM (from Window) +// General + {TEXT("FIND") , NULL, PARAM_FIND }, + {TEXT("BRANCH") , NULL, PARAM_BRANCH }, + {"CATEGORY" , NULL, PARAM_CATEGORY }, + {TEXT("CLEAR") , NULL, PARAM_CLEAR }, + {TEXT("LOAD") , NULL, PARAM_LOAD }, + {TEXT("LIST") , NULL, PARAM_LIST }, + {TEXT("OFF") , NULL, PARAM_OFF }, + {TEXT("ON") , NULL, PARAM_ON }, + {TEXT("RESET") , NULL, PARAM_RESET }, + {TEXT("SAVE") , NULL, PARAM_SAVE }, + {TEXT("START") , NULL, PARAM_START }, // benchmark + {TEXT("STOP") , NULL, PARAM_STOP }, // benchmark +// Help Categories + {"*" , NULL, PARAM_WILDSTAR }, + {"BOOKMARKS" , NULL, PARAM_CAT_BOOKMARKS }, + {"BREAKPOINTS" , NULL, PARAM_CAT_BREAKPOINTS }, + {"CONFIG" , NULL, PARAM_CAT_CONFIG }, + {"CPU" , NULL, PARAM_CAT_CPU }, +// {TEXT("EXPRESSION") , + {"FLAGS" , NULL, PARAM_CAT_FLAGS }, + {"HELP" , NULL, PARAM_CAT_HELP }, + {"KEYBOARD" , NULL, PARAM_CAT_KEYBOARD }, + {"MEMORY" , NULL, PARAM_CAT_MEMORY }, // alias // SOURCE [SYMBOLS] [MEMORY] filename + {"OUTPUT" , NULL, PARAM_CAT_OUTPUT }, + {"OPERATORS" , NULL, PARAM_CAT_OPERATORS }, + {"RANGE" , NULL, PARAM_CAT_RANGE }, +// {TEXT("REGISTERS") , NULL, PARAM_CAT_REGISTERS }, + {"SYMBOLS" , NULL, PARAM_CAT_SYMBOLS }, + {"VIEW" , NULL, PARAM_CAT_VIEW }, + {"WATCHES" , NULL, PARAM_CAT_WATCHES }, + {"WINDOW" , NULL, PARAM_CAT_WINDOW }, + {"ZEROPAGE" , NULL, PARAM_CAT_ZEROPAGE }, +// Memory + {TEXT("?") , NULL, PARAM_MEM_SEARCH_WILD }, +// {TEXT("*") , NULL, PARAM_MEM_SEARCH_BYTE }, +// Source level debugging + {TEXT("MEM") , NULL, PARAM_SRC_MEMORY }, + {TEXT("MEMORY") , NULL, PARAM_SRC_MEMORY }, + {TEXT("SYM") , NULL, PARAM_SRC_SYMBOLS }, + {TEXT("SYMBOLS") , NULL, PARAM_SRC_SYMBOLS }, + {TEXT("MERLIN") , NULL, PARAM_SRC_MERLIN }, + {TEXT("ORCA") , NULL, PARAM_SRC_ORCA }, +// View +// {TEXT("VIEW") , NULL, PARAM_SRC_??? }, +// Window Win Cmd WinEffects CmdEffects + {TEXT("CODE") , NULL, PARAM_CODE }, // x x code win only switch to code window +// {TEXT("CODE1") , NULL, PARAM_CODE_1 }, // - x code/data win + {TEXT("CODE2") , NULL, PARAM_CODE_2 }, // - x code/data win + {TEXT("CONSOLE") , NULL, PARAM_CONSOLE }, // x - switch to console window + {TEXT("DATA") , NULL, PARAM_DATA }, // x x data win only switch to data window +// {TEXT("DATA1") , NULL, PARAM_DATA_1 }, // - x code/data win + {TEXT("DATA2") , NULL, PARAM_DATA_2 }, // - x code/data win + {TEXT("DISASM") , NULL, PARAM_DISASM }, // + {TEXT("INFO") , NULL, PARAM_INFO }, // - x code/data Toggles showing/hiding Regs/Stack/BP/Watches/ZP + {TEXT("SOURCE") , NULL, PARAM_SOURCE }, // x x switch to source window + {TEXT("SRC") , NULL, PARAM_SOURCE }, // alias +// {TEXT("SOURCE_1") , NULL, PARAM_SOURCE_1 }, // - x code/data + {TEXT("SOURCE2 ") , NULL, PARAM_SOURCE_2 }, // - x + {TEXT("SYMBOLS") , NULL, PARAM_SYMBOLS }, // x x code/data win switch to symbols window + {TEXT("SYM") , NULL, PARAM_SYMBOLS }, // alias x SOURCE [SYM] [MEM] filename +// {TEXT("SYMBOL1") , NULL, PARAM_SYMBOL_1 }, // - x code/data win + {TEXT("SYMBOL2") , NULL, PARAM_SYMBOL_2 }, // - x code/data win +// Internal Consistency Check + { TEXT( __PARAMS_VERIFY_TXT__), NULL, NUM_PARAMS }, + }; + +// Profile + const int NUM_PROFILE_LINES = NUM_OPCODES + NUM_OPMODES + 16; + + ProfileOpcode_t g_aProfileOpcodes[ NUM_OPCODES ]; + ProfileOpmode_t g_aProfileOpmodes[ NUM_OPMODES ]; + + TCHAR g_FileNameProfile[] = TEXT("Profile.txt"); // changed from .csv to .txt since Excel doesn't give import options. + int g_nProfileLine = 0; + char g_aProfileLine[ NUM_PROFILE_LINES ][ CONSOLE_WIDTH ]; + + void ProfileReset (); + bool ProfileSave (); + void ProfileFormat( bool bSeperateColumns, ProfileFormat_e eFormatMode ); + + char * ProfileLinePeek ( int iLine ); + char * ProfileLinePush (); + void ProfileLineReset (); + + +// Source Level Debugging _________________________________________________________________________ + bool g_bSourceLevelDebugging = false; + bool g_bSourceAddSymbols = false; + bool g_bSourceAddMemory = false; + + char g_aSourceFileName[ MAX_PATH ] = ""; + + MemoryTextFile_t g_AssemblerSourceBuffer; + + int g_iSourceDisplayStart = 0; + int g_nSourceAssembleBytes = 0; + int g_nSourceAssemblySymbols = 0; + + // TODO: Support multiple source filenames + SourceAssembly_t g_aSourceDebug; + + + +// Watches ________________________________________________________________________________________ + int g_nWatches = 0; + Watches_t g_aWatches[ MAX_WATCHES ]; // TODO: use vector ?? + + +// Window _________________________________________________________________________________________ + int g_iWindowLast = WINDOW_CODE; + int g_iWindowThis = WINDOW_CODE; + WindowSplit_t g_aWindowConfig[ NUM_WINDOWS ]; + + +// Zero Page Pointers _____________________________________________________________________________ + int g_nZeroPagePointers = 0; + ZeroPagePointers_t g_aZeroPagePointers[ MAX_ZEROPAGE_POINTERS ]; // TODO: use vector<> ? + + +// TODO: // CONFIG SAVE --> VERSION # + enum DebugConfigVersion_e + { + VERSION_0, + CURRENT_VERSION = VERSION_0 + }; + + +// Misc. __________________________________________________________________________________________ + + char g_sFileNameConfig [] = +#ifdef MSDOS + "AWDEBUGR.CFG"; +#else + "AppleWinDebugger.cfg"; +#endif + + char g_sFileNameTrace [] = "Trace.txt"; + + bool g_bBenchmarking = false; + + BOOL fulldisp = 0; + WORD lastpc = 0; + + BOOL g_bProfiling = 0; + int g_nDebugSteps = 0; + DWORD g_nDebugStepCycles = 0; + int g_nDebugStepStart = 0; + int g_nDebugStepUntil = -1; // HACK: MAGIC # + + int g_nDebugSkipStart = 0; + int g_nDebugSkipLen = 0; + + FILE *g_hTraceFile = NULL; + bool g_bTraceHeader = false; // semaphore, flag header to be printed + + DWORD extbench = 0; + bool g_bDebuggerViewingAppleOutput = false; + + bool g_bIgnoreNextKey = false; + +// Private ________________________________________________________________________________________ + + +// Prototypes _______________________________________________________________ + + static int ParseInput ( LPTSTR pConsoleInput, bool bCook = true ); + static Update_t ExecuteCommand ( int nArgs ); + +// Breakpoints + void _BWZ_List ( const Breakpoint_t * aBreakWatchZero, const int iBWZ ); // bool bZeroBased = true ); + void _BWZ_ListAll ( const Breakpoint_t * aBreakWatchZero, const int nMax ); + +// bool CheckBreakpoint (WORD address, BOOL memory); + bool CheckBreakpointsIO (); + bool CheckBreakpointsReg (); + bool _CmdBreakpointAddReg ( Breakpoint_t *pBP, BreakpointSource_t iSrc, BreakpointOperator_t iCmp, WORD nAddress, int nLen, bool bIsTempBreakpoint ); + int _CmdBreakpointAddCommonArg ( int iArg, int nArg, BreakpointSource_t iSrc, BreakpointOperator_t iCmp, bool bIsTempBreakpoint=false ); + void _BWZ_Clear( Breakpoint_t * aBreakWatchZero, int iSlot ); + +// Config - Colors + static void _ConfigColorsReset ( BYTE *pPalDst = 0 ); + +// Config - Save + bool ConfigSave_BufferToDisk ( char *pFileName, ConfigSave_t eConfigSave ); + void ConfigSave_PrepareHeader ( const Parameters_e eCategory, const Commands_e eCommandClear ); + +// Drawing + static bool DebuggerSetColor ( const int iScheme, const int iColor, const COLORREF nColor ); + static void _CmdColorGet ( const int iScheme, const int iColor ); + +// Font + static void _UpdateWindowFontHeights (int nFontHeight); + +// Source Level Debugging + static bool BufferAssemblyListing ( char * pFileName ); + static bool ParseAssemblyListing ( bool bBytesToMemory, bool bAddSymbols ); + + +// Window + void _WindowJoin (); + void _WindowSplit (Window_e eNewBottomWindow ); + void _WindowLast (); + void _WindowSwitch ( int eNewWindow ); + int WindowGetHeight ( int iWindow ); + void WindowUpdateDisasmSize (); + void WindowUpdateConsoleDisplayedSize (); + void WindowUpdateSizes (); + Update_t _CmdWindowViewFull (int iNewWindow); + 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 ); + bool InternalSingleStep (); + + void DisasmCalcCurFromTopAddress(); + void DisasmCalcBotFromTopAddress(); + void DisasmCalcTopBotAddress (); + WORD DisasmCalcAddressFromLines( WORD iAddress, int nLines ); + + + +//=========================================================================== +LPCTSTR FormatAddress( WORD nAddress, int nBytes ) +{ + // No symbol for this addres -- string with 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; + default: sSymbol[0] = 0; break; // clear since is static + } + return sSymbol; +} + + + + +// Bookmarks __________________________________________________________________ + + +//=========================================================================== +bool _Bookmark_Add( const int iBookmark, const WORD nAddress ) +{ + if (iBookmark < MAX_BOOKMARKS) + { + // g_aBookmarks.push_back( nAddress ); +// g_aBookmarks.at( iBookmark ) = nAddress; + g_aBookmarks[ iBookmark ].nAddress = nAddress; + g_aBookmarks[ iBookmark ].bSet = true; + g_nBookmarks++; + return true; + } + + return false; +} + + +//=========================================================================== +bool _Bookmark_Del( const WORD nAddress ) +{ + bool bDeleted = false; + +// int nSize = g_aBookmarks.size(); + int iBookmark; + for (iBookmark = 0; iBookmark < MAX_BOOKMARKS; iBookmark++ ) + { + if (g_aBookmarks[ iBookmark ].nAddress == nAddress) + { +// g_aBookmarks.at( iBookmark ) = NO_6502_TARGET; + g_aBookmarks[ iBookmark ].bSet = false; + bDeleted = true; + } + } + return bDeleted; +} + +bool Bookmark_Find( const WORD nAddress ) +{ + // Ugh, linear search +// int nSize = g_aBookmarks.size(); + int iBookmark; + for (iBookmark = 0; iBookmark < MAX_BOOKMARKS; iBookmark++ ) + { + if (g_aBookmarks[ iBookmark ].nAddress == nAddress) + { + if (g_aBookmarks[ iBookmark ].bSet) + return true; + } + } + return false; +} + + +//=========================================================================== +bool _Bookmark_Get( const int iBookmark, WORD & nAddress ) +{ +// int nSize = g_aBookmarks.size(); + if (iBookmark >= MAX_BOOKMARKS) + return false; + + if (g_aBookmarks[ iBookmark ].bSet) + { + nAddress = g_aBookmarks[ iBookmark ].nAddress; + return true; + } + + return false; +} + + +//=========================================================================== +void _Bookmark_Reset() +{ +// g_aBookmarks.reserve( MAX_BOOKMARKS ); +// g_aBookmarks.insert( g_aBookma int iBookmark = 0; + int iBookmark = 0; + for (iBookmark = 0; iBookmark < MAX_BOOKMARKS; iBookmark++ ) + { + g_aBookmarks[ iBookmark ].bSet = false; + } +} + + +//=========================================================================== +int _Bookmark_Size() +{ + int g_nBookmarks = 0; + + int iBookmark; + for (iBookmark = 0; iBookmark < MAX_BOOKMARKS; iBookmark++ ) + { + if (g_aBookmarks[ iBookmark ].bSet) + g_nBookmarks++; + } + + return g_nBookmarks; +} + +//=========================================================================== +Update_t CmdBookmark (int nArgs) +{ + return CmdBookmarkAdd( nArgs ); +} + +//=========================================================================== +Update_t CmdBookmarkAdd (int nArgs ) +{ + // BMA [address] + // BMA # address + if (! nArgs) + { + return CmdZeroPageList( 0 ); + } + + int iArg = 1; + int iBookmark = NO_6502_TARGET; + + if (nArgs > 1) + { + iBookmark = g_aArgs[ 1 ].nValue; + iArg++; + } + + bool bAdded = false; + for (; iArg <= nArgs; iArg++ ) + { + WORD nAddress = g_aArgs[ iArg ].nValue; + + if (iBookmark == NO_6502_TARGET) + { + iBookmark = 0; + while ((iBookmark < MAX_BOOKMARKS) && (g_aBookmarks[iBookmark].bSet)) + { + iBookmark++; + } + } + + if ((iBookmark >= MAX_BOOKMARKS) && !bAdded) + { + char sText[ CONSOLE_WIDTH ]; + sprintf( sText, "All bookmarks are currently in use. (Max: %d)", MAX_BOOKMARKS ); + ConsoleDisplayPush( sText ); + return ConsoleUpdate(); + } + + if ((iBookmark < MAX_BOOKMARKS) && (g_nBookmarks < MAX_BOOKMARKS)) + { + g_aBookmarks[iBookmark].bSet = true; + g_aBookmarks[iBookmark].nAddress = nAddress; + bAdded = true; + g_nBookmarks++; + iBookmark++; + } + } + + if (!bAdded) + goto _Help; + + return UPDATE_DISASM | ConsoleUpdate(); + +_Help: + return Help_Arg_1( CMD_BOOKMARK_ADD ); + +} + + + + +//=========================================================================== +Update_t CmdBookmarkClear (int nArgs) +{ + int iBookmark = 0; + + bool bClearAll = false; + + int iArg; + for (iArg = 1; iArg <= nArgs; iArg++ ) + { + if (! _tcscmp(g_aArgs[nArgs].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName)) + { + for (iBookmark = 0; iBookmark < MAX_BOOKMARKS; iBookmark++ ) + { + if (g_aBookmarks[ iBookmark ].bSet) + g_aBookmarks[ iBookmark ].bSet = false; + } + break; + } + + iBookmark = g_aArgs[ iArg ].nValue; + if (g_aBookmarks[ iBookmark ].bSet) + g_aBookmarks[ iBookmark ].bSet = false; + } + + return UPDATE_DISASM; +} + + +//=========================================================================== +Update_t CmdBookmarkGoto ( int nArgs ) +{ + if (! nArgs) + return Help_Arg_1( CMD_BOOKMARK_GOTO ); + + int iBookmark = g_aArgs[ 1 ].nValue; + + WORD nAddress; + if (_Bookmark_Get( iBookmark, nAddress )) + { + g_nDisasmCurAddress = nAddress; + g_nDisasmCurLine = 0; + DisasmCalcTopBotAddress(); + } + + return UPDATE_DISASM; +} + + +//=========================================================================== +Update_t CmdBookmarkList (int nArgs) +{ + if (! g_nBookmarks) + { + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, TEXT(" There are no current bookmarks. (Max: %d)"), MAX_BOOKMARKS ); + ConsoleBufferPush( sText ); + } + else + { + _BWZ_ListAll( g_aBookmarks, MAX_BOOKMARKS ); + } + return ConsoleUpdate(); +} + + +//=========================================================================== +Update_t CmdBookmarkLoad (int nArgs) +{ + char sFilePath[ MAX_PATH ] = ""; + + if (nArgs == 1) + { +// strcpy( sMiniFileName, pFileName ); + // strcat( sMiniFileName, ".aws" ); // HACK: MAGIC STRING + +// _tcscpy(sFileName, g_sCurrentDir); // +// _tcscat(sFileName, sMiniFileName); + } + + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdBookmarkSave (int nArgs) +{ + TCHAR sText[ CONSOLE_WIDTH ]; + + g_ConfigState.Reset(); + + ConfigSave_PrepareHeader( PARAM_CAT_BOOKMARKS, CMD_BOOKMARK_CLEAR ); + + int iBookmark = 0; + while (iBookmark < MAX_BOOKMARKS) + { + if (g_aBookmarks[ iBookmark ].bSet) + { + sprintf( sText, "%s %x %04X\n" + , g_aCommands[ CMD_BOOKMARK_ADD ].m_sName + , iBookmark + , g_aBookmarks[ iBookmark ].nAddress + ); + g_ConfigState.PushLine( sText ); + } + iBookmark++; + } + + if (nArgs) + { + if (! (g_aArgs[ 1 ].bType & TYPE_QUOTED_2)) + return Help_Arg_1( CMD_BOOKMARK_SAVE ); + + if (ConfigSave_BufferToDisk( g_aArgs[ 1 ].sArg, CONFIG_SAVE_FILE_CREATE )) + { + ConsoleBufferPush( TEXT( "Saved." ) ); + return ConsoleUpdate(); + } + } + + return UPDATE_CONSOLE_DISPLAY; +} + + + +//=========================================================================== +BOOL CheckJump (WORD targetaddress) +{ + WORD savedpc = regs.pc; + InternalSingleStep(); + BOOL result = (regs.pc == targetaddress); + regs.pc = savedpc; + return result; +} + + +// Benchmark ______________________________________________________________________________________ + +//=========================================================================== +Update_t CmdBenchmark (int nArgs) +{ + if (g_bBenchmarking) + CmdBenchmarkStart(0); + else + CmdBenchmarkStop(0); + + return UPDATE_ALL; // TODO/FIXME Verify +} + +//=========================================================================== +Update_t CmdBenchmarkStart (int nArgs) +{ + CpuSetupBenchmark(); + g_nDisasmCurAddress = regs.pc; + DisasmCalcTopBotAddress(); + g_bBenchmarking = true; + return UPDATE_ALL; // 1; +} + +//=========================================================================== +Update_t CmdBenchmarkStop (int nArgs) +{ + g_bBenchmarking = false; + DebugEnd(); + g_nAppMode = MODE_RUNNING; + FrameRefreshStatus(DRAW_TITLE); + VideoRedrawScreen(); + DWORD currtime = GetTickCount(); + while ((extbench = GetTickCount()) != currtime) + ; // intentional busy-waiting + KeybQueueKeypress(TEXT(' '),1); + g_bResetTiming = true; + + return UPDATE_ALL; // 0; +} + +//=========================================================================== +Update_t CmdProfile (int nArgs) +{ + if (! nArgs) + { + sprintf( g_aArgs[ 1 ].sArg, g_aParameters[ PARAM_RESET ].m_sName ); + nArgs = 1; + } + + if (nArgs == 1) + { + int iParam; + int nFound = FindParam( g_aArgs[ 1 ].sArg, MATCH_EXACT, iParam, _PARAM_GENERAL_BEGIN, _PARAM_GENERAL_END ); + + if (! nFound) + goto _Help; + + if (iParam == PARAM_RESET) + { + ProfileReset(); + g_bProfiling = 1; + ConsoleBufferPush( TEXT(" Resetting profile data." ) ); + } + else + { + if ((iParam != PARAM_SAVE) && (iParam != PARAM_LIST)) + goto _Help; + + bool bExport = true; + if (iParam == PARAM_LIST) + bExport = false; + + // .csv (Comma Seperated Value) +// ProfileFormat( bExport, bExport ? PROFILE_FORMAT_COMMA : PROFILE_FORMAT_SPACE ); + // .txt (Tab Seperated Value) + ProfileFormat( bExport, bExport ? PROFILE_FORMAT_TAB : PROFILE_FORMAT_SPACE ); + + // Dump to console + if (iParam == PARAM_LIST) + { + + char *pText; + char sText[ CONSOLE_WIDTH ]; + + int nLine = g_nProfileLine; + int iLine; + + for( iLine = 0; iLine < nLine; iLine++ ) + { + pText = ProfileLinePeek( iLine ); + if (pText) + { + TextConvertTabsToSpaces( sText, pText, CONSOLE_WIDTH, 4 ); + // ConsoleBufferPush( sText ); + ConsolePrint( sText ); + } + } + } + + if (iParam == PARAM_SAVE) + { + if (ProfileSave()) + { + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, " Saved: %s", g_FileNameProfile ); + ConsoleBufferPush( sText ); + } + else + ConsoleBufferPush( TEXT(" ERROR: Couldn't save file. (In use?)" ) ); + } + } + } + else + goto _Help; + + return ConsoleUpdate(); // UPDATE_CONSOLE_DISPLAY; + +_Help: + return Help_Arg_1( CMD_PROFILE ); +} + + +// Breakpoints ____________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdBreakInvalid (int nArgs) // Breakpoint IFF Full-speed! +{ + if ((nArgs > 2) || (nArgs == 0)) + goto _Help; + + int iType = 0; // default to BRK + int nActive = 0; + +// if (nArgs == 2) + iType = g_aArgs[ 1 ].nValue; + + // Cases: + // 0. CMD // display + // 1a. CMD # // display + // 1b. CMD ON | OFF //set + // 1c. CMD ? // error + // 2a. CMD # ON | OFF // set + // 2b. CMD # ? // error + TCHAR sText[ CONSOLE_WIDTH ]; + bool bValidParam = true; + + int iParamArg = nArgs; + int iParam; + int nFound = FindParam( g_aArgs[ iParamArg ].sArg, MATCH_EXACT, iParam, _PARAM_GENERAL_BEGIN, _PARAM_GENERAL_END ); + + if (nFound) + { + if (iParam == PARAM_ON) + nActive = 1; + else + if (iParam == PARAM_OFF) + nActive = 0; + else + bValidParam = false; + } + else + bValidParam = false; + + if (nArgs == 1) + { + if (! nFound) // bValidParam) // case 1a or 1c + { + if ((iType < 0) || (iType > AM_3)) + goto _Help; + + if (IsDebugBreakOnInvalid( iType )) + iParam = PARAM_ON; + else + iParam = PARAM_OFF; + } + else // case 1b + { + SetDebugBreakOnInvalid( iType, nActive ); + } + + if (iType == 0) + wsprintf( sText, TEXT("Enter debugger on BRK opcode: %s"), g_aParameters[ iParam ].m_sName ); + else + wsprintf( sText, TEXT("Enter debugger on INVALID %1X opcode: %s"), iType, g_aParameters[ iParam ].m_sName ); + ConsoleBufferPush( sText ); + return ConsoleUpdate(); + } + else + if (nArgs == 2) + { + if (! bValidParam) // case 2b + { + goto _Help; + } + else // case 2a (or not 2b ;-) + { + if ((iType < 0) || (iType > AM_3)) + goto _Help; + + SetDebugBreakOnInvalid( iType, nActive ); + + if (iType == 0) + wsprintf( sText, TEXT("Enter debugger on BRK opcode: %s"), g_aParameters[ iParam ].m_sName ); + else + wsprintf( sText, TEXT("Enter debugger on INVALID %1X opcode: %s"), iType, g_aParameters[ iParam ].m_sName ); + ConsoleBufferPush( sText ); + return ConsoleUpdate(); + } + } + + return UPDATE_CONSOLE_DISPLAY; + +_Help: + return HelpLastCommand(); +} + + +//=========================================================================== +Update_t CmdBreakOpcode (int nArgs) // Breakpoint IFF Full-speed! +{ + TCHAR sText[ CONSOLE_WIDTH ]; + + if (nArgs > 1) + return HelpLastCommand(); + + TCHAR sAction[ CONSOLE_WIDTH ] = TEXT("Current"); // default to display + + if (nArgs == 1) + { + int iOpcode = g_aArgs[ 1] .nValue; + g_iDebugOnOpcode = iOpcode & 0xFF; + + _tcscpy( sAction, TEXT("Setting") ); + + if (iOpcode >= NUM_OPCODES) + { + wsprintf( sText, TEXT("Warning: clamping opcode: %02X"), g_iDebugOnOpcode ); + ConsoleBufferPush( sText ); + return ConsoleUpdate(); + } + } + + if (g_iDebugOnOpcode == 0) + // Show what the current break opcode is + wsprintf( sText, TEXT("%s full speed Break on Opcode: None") + , sAction + , g_iDebugOnOpcode + , g_aOpcodes65C02[ g_iDebugOnOpcode ].sMnemonic + ); + else + // Show what the current break opcode is + wsprintf( sText, TEXT("%s full speed Break on Opcode: %02X %s") + , sAction + , g_iDebugOnOpcode + , g_aOpcodes65C02[ g_iDebugOnOpcode ].sMnemonic + ); + + ConsoleBufferPush( sText ); + return ConsoleUpdate(); +} + + +// bool bBP = g_nBreakpoints && CheckBreakpoint(nOffset,nOffset == regs.pc); +//=========================================================================== +bool GetBreakpointInfo ( WORD nOffset, bool & bBreakpointActive_, bool & bBreakpointEnable_ ) +{ + for (int iBreakpoint = 0; iBreakpoint < MAX_BREAKPOINTS; iBreakpoint++) + { + Breakpoint_t *pBP = &g_aBreakpoints[ iBreakpoint ]; + + if ((pBP->nLength) +// && (pBP->bEnabled) // not bSet + && (nOffset >= pBP->nAddress) && (nOffset < (pBP->nAddress + pBP->nLength))) // [nAddress,nAddress+nLength] + { + bBreakpointActive_ = pBP->bSet; + bBreakpointEnable_ = pBP->bEnabled; + return true; + } + +// if (g_aBreakpoints[iBreakpoint].nLength && g_aBreakpoints[iBreakpoint].bEnabled && +// (g_aBreakpoints[iBreakpoint].nAddress <= targetaddr) && +// (g_aBreakpoints[iBreakpoint].nAddress + g_aBreakpoints[iBreakpoint].nLength > targetaddr)) + } + + bBreakpointActive_ = false; + bBreakpointEnable_ = false; + + return false; +} + + +// Returns true if we should continue checking breakpoint details, else false +//=========================================================================== +bool _BreakpointValid( Breakpoint_t *pBP ) //, BreakpointSource_t iSrc ) +{ + bool bStatus = false; + + if (! pBP->bEnabled) + return bStatus; + +// if (pBP->eSource != iSrc) +// return bStatus; + + if (! pBP->nLength) + return bStatus; + + return true; +} + + +//=========================================================================== +bool _CheckBreakpointValue( Breakpoint_t *pBP, int nVal ) +{ + bool bStatus = false; + + int iCmp = pBP->eOperator; + switch (iCmp) + { + case BP_OP_LESS_EQUAL : + if (nVal <= pBP->nAddress) + bStatus = true; + break; + case BP_OP_LESS_THAN : + if (nVal < pBP->nAddress) + bStatus = true; + break; + case BP_OP_EQUAL : // Range is like C++ STL: [,) (inclusive,not-inclusive) + if ((nVal >= pBP->nAddress) && (nVal < (pBP->nAddress + pBP->nLength))) + bStatus = true; + break; + case BP_OP_NOT_EQUAL : // Rnage is: (,] (not-inclusive, inclusive) + if ((nVal < pBP->nAddress) || (nVal >= (pBP->nAddress + pBP->nLength))) + bStatus = true; + break; + case BP_OP_GREATER_THAN : + if (nVal > pBP->nAddress) + bStatus = true; + break; + case BP_OP_GREATER_EQUAL: + if (nVal >= pBP->nAddress) + bStatus = true; + break; + default: + break; + } + + return bStatus; +} + + +//=========================================================================== +bool CheckBreakpointsIO () +{ + const int NUM_TARGETS = 2; + + int aTarget[ NUM_TARGETS ] = + { + NO_6502_TARGET, + NO_6502_TARGET + }; + int nBytes; + bool bStatus = false; + + int iTarget; + int nAddress; + + _6502_GetTargets( regs.pc, &aTarget[0], &aTarget[1], &nBytes ); + + if (nBytes) + { + for (iTarget = 0; iTarget < NUM_TARGETS; iTarget++ ) + { + nAddress = aTarget[ iTarget ]; + if (nAddress != NO_6502_TARGET) + { + for (int iBreakpoint = 0; iBreakpoint < MAX_BREAKPOINTS; iBreakpoint++) + { + Breakpoint_t *pBP = &g_aBreakpoints[iBreakpoint]; + if (_BreakpointValid( pBP )) + { + if (pBP->eSource == BP_SRC_MEM_1) + { + if (_CheckBreakpointValue( pBP, nAddress )) + { + return true; + } + } + } + } + } + } + } + return bStatus; +} + +// Returns true if a register breakpoint is triggered +//=========================================================================== +bool CheckBreakpointsReg () +{ + bool bStatus = false; + + for (int iBreakpoint = 0; iBreakpoint < MAX_BREAKPOINTS; iBreakpoint++) + { + Breakpoint_t *pBP = &g_aBreakpoints[iBreakpoint]; + + if (! _BreakpointValid( pBP )) + continue; + + switch (pBP->eSource) + { + case BP_SRC_REG_PC: + bStatus = _CheckBreakpointValue( pBP, regs.pc ); + break; + case BP_SRC_REG_A: + bStatus = _CheckBreakpointValue( pBP, regs.a ); + break; + case BP_SRC_REG_X: + bStatus = _CheckBreakpointValue( pBP, regs.x ); + break; + case BP_SRC_REG_Y: + bStatus = _CheckBreakpointValue( pBP, regs.y ); + break; + case BP_SRC_REG_P: + bStatus = _CheckBreakpointValue( pBP, regs.ps ); + break; + case BP_SRC_REG_S: + bStatus = _CheckBreakpointValue( pBP, regs.sp ); + break; + default: + break; + } + + if (bStatus) + { + if (pBP->bTemp) + _BWZ_Clear(pBP, iBreakpoint); + + break; + } + } + + return bStatus; +} + +void ClearTempBreakpoints () +{ + for (int iBreakpoint = 0; iBreakpoint < MAX_BREAKPOINTS; iBreakpoint++) + { + Breakpoint_t *pBP = &g_aBreakpoints[iBreakpoint]; + + if (! _BreakpointValid( pBP )) + continue; + + if (pBP->bTemp) + _BWZ_Clear(pBP, iBreakpoint); + } +} + +//=========================================================================== +Update_t CmdBreakpoint (int nArgs) +{ + return CmdBreakpointAddPC( nArgs ); +} + + +// smart breakpoint +//=========================================================================== +Update_t CmdBreakpointAddSmart (int nArgs) +{ + int nAddress = g_aArgs[1].nValue; + + if (! nArgs) + { + nArgs = 1; + g_aArgs[ nArgs ].nValue = g_nDisasmCurAddress; + } + + if ((nAddress >= _6502_IO_BEGIN) && (nAddress <= _6502_IO_END)) + { + return CmdBreakpointAddIO( nArgs ); + } + else + { + CmdBreakpointAddReg( nArgs ); + CmdBreakpointAddMem( nArgs ); + return UPDATE_BREAKPOINTS; + } + + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdBreakpointAddReg (int nArgs) +{ + if (! nArgs) + { + return Help_Arg_1( CMD_BREAKPOINT_ADD_REG ); + } + + BreakpointSource_t iSrc = BP_SRC_REG_PC; + BreakpointOperator_t iCmp = BP_OP_EQUAL ; + int nLen = 1; + + bool bHaveSrc = false; + bool bHaveCmp = false; + + int iParamSrc; + int iParamCmp; + + int nFound; + bool bAdded = false; + + int iArg = 0; + while (iArg++ < nArgs) + { + char *sArg = g_aArgs[iArg].sArg; + + bHaveSrc = false; + bHaveCmp = false; + + nFound = FindParam( sArg, MATCH_EXACT, iParamSrc, _PARAM_REGS_BEGIN, _PARAM_REGS_END ); + if (nFound) + { + switch (iParamSrc) + { + case PARAM_REG_A : iSrc = BP_SRC_REG_A ; bHaveSrc = true; break; + case PARAM_FLAGS : iSrc = BP_SRC_REG_P ; bHaveSrc = true; break; + case PARAM_REG_X : iSrc = BP_SRC_REG_X ; bHaveSrc = true; break; + case PARAM_REG_Y : iSrc = BP_SRC_REG_Y ; bHaveSrc = true; break; + case PARAM_REG_PC: iSrc = BP_SRC_REG_PC; bHaveSrc = true; break; + case PARAM_REG_SP: iSrc = BP_SRC_REG_S ; bHaveSrc = true; break; + default: + break; + } + } + + nFound = FindParam( sArg, MATCH_EXACT, iParamCmp, _PARAM_BREAKPOINT_BEGIN, _PARAM_BREAKPOINT_END ); + if (nFound) + { + switch (iParamCmp) + { + case PARAM_BP_LESS_EQUAL : iCmp = BP_OP_LESS_EQUAL ; bHaveCmp = true; break; + case PARAM_BP_LESS_THAN : iCmp = BP_OP_LESS_THAN ; bHaveCmp = true; break; + case PARAM_BP_EQUAL : iCmp = BP_OP_EQUAL ; bHaveCmp = true; break; + case PARAM_BP_NOT_EQUAL : iCmp = BP_OP_NOT_EQUAL ; bHaveCmp = true; break; + case PARAM_BP_NOT_EQUAL_1 : iCmp = BP_OP_NOT_EQUAL ; bHaveCmp = true; break; + case PARAM_BP_GREATER_THAN : iCmp = BP_OP_GREATER_THAN ; bHaveCmp = true; break; + case PARAM_BP_GREATER_EQUAL: iCmp = BP_OP_GREATER_EQUAL; bHaveCmp = true; break; + default: + break; + } + } + + if ((! bHaveSrc) && (! bHaveCmp)) + { + int dArgs = _CmdBreakpointAddCommonArg( iArg, nArgs, iSrc, iCmp ); + if (!dArgs) + { + return Help_Arg_1( CMD_BREAKPOINT_ADD_REG ); + } + iArg += dArgs; + } + } + + return UPDATE_ALL; +} + + +//=========================================================================== +bool _CmdBreakpointAddReg( Breakpoint_t *pBP, BreakpointSource_t iSrc, BreakpointOperator_t iCmp, WORD nAddress, int nLen, bool bIsTempBreakpoint ) +{ + bool bStatus = false; + + if (pBP) + { + pBP->eSource = iSrc; + pBP->eOperator = iCmp; + pBP->nAddress = nAddress; + pBP->nLength = nLen; + pBP->bSet = true; + pBP->bEnabled = true; + pBP->bTemp = bIsTempBreakpoint; + bStatus = true; + } + + return bStatus; +} + + +// @return Number of args processed +//=========================================================================== +int _CmdBreakpointAddCommonArg ( int iArg, int nArg, BreakpointSource_t iSrc, BreakpointOperator_t iCmp, bool bIsTempBreakpoint ) +{ + int dArg = 0; + + int iBreakpoint = 0; + Breakpoint_t *pBP = & g_aBreakpoints[ iBreakpoint ]; + + while ((iBreakpoint < MAX_BREAKPOINTS) && g_aBreakpoints[iBreakpoint].bSet) //g_aBreakpoints[iBreakpoint].nLength) + { + iBreakpoint++; + pBP++; + } + + if (iBreakpoint >= MAX_BREAKPOINTS) + { + ConsoleDisplayError(TEXT("All Breakpoints slots are currently in use.")); + return dArg; + } + + if (iArg <= nArg) + { +#if DEBUG_VAL_2 + int nLen = g_aArgs[iArg].nVal2; +#endif + WORD nAddress = 0; + WORD nAddress2 = 0; + WORD nEnd = 0; + int nLen = 0; + + dArg = 1; + RangeType_t eRange = Range_Get( nAddress, nAddress2, iArg); + if ((eRange == RANGE_HAS_END) || + (eRange == RANGE_HAS_LEN)) + { + Range_CalcEndLen( eRange, nAddress, nAddress2, nEnd, nLen ); + dArg = 2; + } + + if ( !nLen) + { + nLen = 1; + } + + if (! _CmdBreakpointAddReg( pBP, iSrc, iCmp, nAddress, nLen, bIsTempBreakpoint )) + { + dArg = 0; + } + g_nBreakpoints++; + } + + return dArg; +} + + +//=========================================================================== +Update_t CmdBreakpointAddPC (int nArgs) +{ + BreakpointSource_t iSrc = BP_SRC_REG_PC; + BreakpointOperator_t iCmp = BP_OP_EQUAL ; + + if (!nArgs) + { + nArgs = 1; +// g_aArgs[1].nValue = regs.pc; + g_aArgs[1].nValue = g_nDisasmCurAddress; + } + + bool bHaveSrc = false; + bool bHaveCmp = false; + +// int iParamSrc; + int iParamCmp; + + int nFound = 0; + bool bAdded = false; + + int iArg = 0; + while (iArg++ < nArgs) + { + char *sArg = g_aArgs[iArg].sArg; + + if (g_aArgs[iArg].bType & TYPE_OPERATOR) + { + nFound = FindParam( sArg, MATCH_EXACT, iParamCmp, _PARAM_BREAKPOINT_BEGIN, _PARAM_BREAKPOINT_END ); + if (nFound) + { + switch (iParamCmp) + { + case PARAM_BP_LESS_EQUAL : iCmp = BP_OP_LESS_EQUAL ; bHaveCmp = true; break; + case PARAM_BP_LESS_THAN : iCmp = BP_OP_LESS_THAN ; bHaveCmp = true; break; + case PARAM_BP_EQUAL : iCmp = BP_OP_EQUAL ; bHaveCmp = true; break; + case PARAM_BP_NOT_EQUAL : iCmp = BP_OP_NOT_EQUAL ; bHaveCmp = true; break; + case PARAM_BP_GREATER_THAN : iCmp = BP_OP_GREATER_THAN ; bHaveCmp = true; break; + case PARAM_BP_GREATER_EQUAL: iCmp = BP_OP_GREATER_EQUAL; bHaveCmp = true; break; + default: + break; + } + } + } + else + { + int dArg = _CmdBreakpointAddCommonArg( iArg, nArgs, iSrc, iCmp ); + if (! dArg) + { + return Help_Arg_1( CMD_BREAKPOINT_ADD_PC ); + } + iArg += dArg; + } + } + + return UPDATE_BREAKPOINTS | UPDATE_CONSOLE_DISPLAY; // 1; +} + + +//=========================================================================== +Update_t CmdBreakpointAddIO (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdBreakpointAddMem (int nArgs) +{ + BreakpointSource_t iSrc = BP_SRC_MEM_1; + BreakpointOperator_t iCmp = BP_OP_EQUAL ; + + bool bAdded = false; + + int iArg = 0; + + while (iArg++ < nArgs) + { + char *sArg = g_aArgs[iArg].sArg; + + if (g_aArgs[iArg].bType & TYPE_OPERATOR) + { + return Help_Arg_1( CMD_BREAKPOINT_ADD_MEM ); + } + else + { + int dArg = _CmdBreakpointAddCommonArg( iArg, nArgs, iSrc, iCmp ); + if (! dArg) + { + return Help_Arg_1( CMD_BREAKPOINT_ADD_MEM ); + } + iArg += dArg; + } + } + + return UPDATE_BREAKPOINTS | UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +void _BWZ_Clear( Breakpoint_t * aBreakWatchZero, int iSlot ) +{ + aBreakWatchZero[ iSlot ].bSet = false; + aBreakWatchZero[ iSlot ].bEnabled = false; + aBreakWatchZero[ iSlot ].nLength = 0; +} + +void _BWZ_RemoveOne( Breakpoint_t *aBreakWatchZero, const int iSlot, int & nTotal ) +{ + if (aBreakWatchZero[iSlot].bSet) + { + _BWZ_Clear( aBreakWatchZero, iSlot ); + nTotal--; + } +} + +void _BWZ_RemoveAll( Breakpoint_t *aBreakWatchZero, const int nMax, int & nTotal ) +{ + for( int iSlot = 0; iSlot < nMax; iSlot++ ) + { + _BWZ_RemoveOne( aBreakWatchZero, iSlot, nTotal ); + } +} + +// called by BreakpointsClear, WatchesClear, ZeroPagePointersClear +//=========================================================================== +void _BWZ_ClearViaArgs( int nArgs, Breakpoint_t * aBreakWatchZero, const int nMax, int & nTotal ) +{ + int iSlot = 0; + + // Clear specified breakpoints + while (nArgs) + { + iSlot = g_aArgs[nArgs].nValue; + + if (! _tcscmp(g_aArgs[nArgs].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName)) + { + _BWZ_RemoveAll( aBreakWatchZero, nMax, nTotal ); + break; + } + else + if ((iSlot >= 0) && (iSlot < nMax)) + { + _BWZ_RemoveOne( aBreakWatchZero, iSlot, nTotal ); + } + + nArgs--; + } +} + +// called by BreakpointsEnable, WatchesEnable, ZeroPagePointersEnable +// called by BreakpointsDisable, WatchesDisable, ZeroPagePointersDisable +void _BWZ_EnableDisableViaArgs( int nArgs, Breakpoint_t * aBreakWatchZero, const int nMax, const bool bEnabled ) +{ + int iSlot = 0; + + // Enable each breakpoint in the list + while (nArgs) + { + iSlot = g_aArgs[nArgs].nValue; + + if (! _tcscmp(g_aArgs[nArgs].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName)) + { + for( ; iSlot < nMax; iSlot++ ) + { + aBreakWatchZero[ iSlot ].bEnabled = bEnabled; + } + } + else + if ((iSlot >= 0) && (iSlot < nMax)) + { + aBreakWatchZero[ iSlot ].bEnabled = bEnabled; + } + + nArgs--; + } +} + +//=========================================================================== +Update_t CmdBreakpointClear (int nArgs) +{ + if (!g_nBreakpoints) + return ConsoleDisplayError(TEXT("There are no breakpoints defined.")); + + if (!nArgs) + { + _BWZ_RemoveAll( g_aBreakpoints, MAX_BREAKPOINTS, g_nBreakpoints ); + } + else + { + _BWZ_ClearViaArgs( nArgs, g_aBreakpoints, MAX_BREAKPOINTS, g_nBreakpoints ); + } + + return UPDATE_DISASM | UPDATE_BREAKPOINTS | UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdBreakpointDisable (int nArgs) +{ + if (! g_nBreakpoints) + return ConsoleDisplayError(TEXT("There are no (PC) Breakpoints defined.")); + + if (! nArgs) + return Help_Arg_1( CMD_BREAKPOINT_DISABLE ); + + _BWZ_EnableDisableViaArgs( nArgs, g_aBreakpoints, MAX_BREAKPOINTS, false ); + + return UPDATE_BREAKPOINTS; +} + +//=========================================================================== +Update_t CmdBreakpointEdit (int nArgs) +{ + return (UPDATE_DISASM | UPDATE_BREAKPOINTS); +} + + +//=========================================================================== +Update_t CmdBreakpointEnable (int nArgs) { + + if (! g_nBreakpoints) + return ConsoleDisplayError(TEXT("There are no (PC) Breakpoints defined.")); + + if (! nArgs) + return Help_Arg_1( CMD_BREAKPOINT_ENABLE ); + + _BWZ_EnableDisableViaArgs( nArgs, g_aBreakpoints, MAX_BREAKPOINTS, true ); + + return UPDATE_BREAKPOINTS; +} + + +void _BWZ_List( const Breakpoint_t * aBreakWatchZero, const int iBWZ ) //, bool bZeroBased ) +{ + static char sText[ CONSOLE_WIDTH ]; + static const char sFlags[] = "-*"; + static char sName[ MAX_SYMBOLS_LEN+1 ]; + + WORD nAddress = aBreakWatchZero[ iBWZ ].nAddress; + LPCTSTR pSymbol = GetSymbol( nAddress, 2 ); + if (! pSymbol) + { + sName[0] = 0; + pSymbol = sName; + } + + sprintf( sText, " #%d %c %04X %s", +// (bZeroBased ? iBWZ + 1 : iBWZ), + iBWZ, + sFlags[ (int) aBreakWatchZero[ iBWZ ].bEnabled ], + aBreakWatchZero[ iBWZ ].nAddress, + pSymbol + ); + ConsoleBufferPush( sText ); +} + +void _BWZ_ListAll( const Breakpoint_t * aBreakWatchZero, const int nMax ) +{ + int iBWZ = 0; + while (iBWZ < MAX_BOOKMARKS) + { + if (aBreakWatchZero[ iBWZ ].bSet) + { + _BWZ_List( aBreakWatchZero, iBWZ ); + } + iBWZ++; + } +} + +//=========================================================================== +Update_t CmdBreakpointList (int nArgs) +{ +// ConsoleBufferPush( ); +// vector vBreakpoints; +// int iBreakpoint = MAX_BREAKPOINTS; +// while (iBreakpoint--) +// { +// if (g_aBreakpoints[iBreakpoint].enabled) +// { +// vBreakpoints.push_back( g_aBreakpoints[iBreakpoint].address ); +// } +// } +// sort( vBreakpoints.begin(), vBreakpoints.end() ); +// iBreakpoint = vBreakPoints.size(); + + if (! g_nBreakpoints) + { + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, TEXT(" There are no current breakpoints. (Max: %d)"), MAX_BREAKPOINTS ); + ConsoleBufferPush( sText ); + } + else + { + _BWZ_ListAll( g_aBreakpoints, MAX_BREAKPOINTS ); + } + return ConsoleUpdate(); +} + +//=========================================================================== +Update_t CmdBreakpointLoad (int nArgs) +{ + return UPDATE_ALL; +} + + +//=========================================================================== +Update_t CmdBreakpointSave (int nArgs) +{ + TCHAR sText[ CONSOLE_WIDTH ]; + + g_ConfigState.Reset(); + + ConfigSave_PrepareHeader( PARAM_CAT_BREAKPOINTS, CMD_BREAKPOINT_CLEAR ); + + int iBreakpoint = 0; + while (iBreakpoint < MAX_BREAKPOINTS) + { + if (g_aBreakpoints[ iBreakpoint ].bSet) + { + sprintf( sText, "%s %x %04X,%04X\n" + , g_aCommands[ CMD_BREAKPOINT_ADD_REG ].m_sName + , iBreakpoint + , g_aBreakpoints[ iBreakpoint ].nAddress + , g_aBreakpoints[ iBreakpoint ].nLength + ); + g_ConfigState.PushLine( sText ); + } + if (! g_aBreakpoints[ iBreakpoint ].bEnabled) + { + sprintf( sText, "%s %x\n" + , g_aCommands[ CMD_BREAKPOINT_DISABLE ].m_sName + , iBreakpoint + ); + g_ConfigState.PushLine( sText ); + } + + iBreakpoint++; + } + + if (nArgs) + { + if (! (g_aArgs[ 1 ].bType & TYPE_QUOTED_2)) + return Help_Arg_1( CMD_BREAKPOINT_SAVE ); + + if (ConfigSave_BufferToDisk( g_aArgs[ 1 ].sArg, CONFIG_SAVE_FILE_CREATE )) + { + ConsoleBufferPush( TEXT( "Saved." ) ); + return ConsoleUpdate(); + } + } + + return UPDATE_CONSOLE_DISPLAY; +} + +// Assembler ______________________________________________________________________________________ + +//=========================================================================== +Update_t _CmdAssemble( WORD nAddress, int iArg, int nArgs ) +{ + bool bHaveLabel = false; + + // if AlphaNumeric + ArgToken_e iTokenSrc = NO_TOKEN; + ParserFindToken( g_pConsoleInput, g_aTokens, NUM_TOKENS, &iTokenSrc ); + + if (iTokenSrc == NO_TOKEN) // is TOKEN_ALPHANUMERIC + if (g_pConsoleInput[0] != CHAR_SPACE) + { + bHaveLabel = true; + + // Symbol + char *pSymbolName = g_aArgs[ iArg ].sArg; // pArg->sArg; + SymbolUpdate( SYMBOLS_ASSEMBLY, pSymbolName, nAddress, false, true ); // bool bRemoveSymbol, bool bUpdateSymbol ) + + iArg++; + } + + bool bStatus = Assemble( iArg, nArgs, nAddress ); + if ( bStatus) + return UPDATE_ALL; + + return UPDATE_CONSOLE_DISPLAY; // UPDATE_NOTHING; +} + + +//=========================================================================== +Update_t CmdAssemble (int nArgs) +{ + if (! g_bAssemblerOpcodesHashed) + { + AssemblerStartup(); + g_bAssemblerOpcodesHashed = true; + } + + // 0 : A + // 1 : A address + // 2+: A address mnemonic... + + if (! nArgs) + { +// return Help_Arg_1( CMD_ASSEMBLE ); + + // Start assembler, continue with last assembled address + AssemblerOn(); + return UPDATE_CONSOLE_DISPLAY; + } + + g_nAssemblerAddress = g_aArgs[1].nValue; + + if (nArgs == 1) + { + int iArg = 1; + + // undocumented ASM * + if ((! _tcscmp( g_aArgs[ iArg ].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName )) || + (! _tcscmp( g_aArgs[ iArg ].sArg, g_aParameters[ PARAM_MEM_SEARCH_WILD ].m_sName )) ) + { + _CmdAssembleHashDump(); + } + + AssemblerOn(); + return UPDATE_CONSOLE_DISPLAY; + +// return Help_Arg_1( CMD_ASSEMBLE ); + } + + if (nArgs > 1) + { + return _CmdAssemble( g_nAssemblerAddress, 2, nArgs ); // disasm, memory, watches, zeropage + } + +// return Help_Arg_1( CMD_ASSEMBLE ); + // g_nAssemblerAddress; // g_aArgs[1].nValue; +// return ConsoleUpdate(); + + return UPDATE_CONSOLE_DISPLAY; +} + +// CPU ____________________________________________________________________________________________ +// CPU Step, Trace ________________________________________________________________________________ + +//=========================================================================== +Update_t CmdGo (int nArgs) +{ + // G StopAddress [SkipAddress,Length] + // Example: + // G C600 FA00,FFFF + // TODO: G addr1,len addr3,len + // TODO: G addr1:addr2 addr3:addr4 + + g_nDebugSteps = -1; + g_nDebugStepCycles = 0; + g_nDebugStepStart = regs.pc; + g_nDebugStepUntil = nArgs ? g_aArgs[1].nValue : -1; + g_nDebugSkipStart = -1; + g_nDebugSkipLen = -1; + + if (nArgs > 4) + return Help_Arg_1( CMD_GO ); + + // G StopAddress [SkipAddress,Len] + // Old 1 2 2 + // G addr addr [, len] + // New 1 2 3 4 + if (nArgs > 1) + { + int iArg = 2; + g_nDebugSkipStart = g_aArgs[ iArg ].nValue; + +#if DEBUG_VAL_2 + WORD nAddress = g_aArgs[ iArg ].nVal2; +#endif + int nLen = 0; + int nEnd = 0; + + if (nArgs > 2) + { + if (g_aArgs[ iArg + 1 ].eToken == TOKEN_COMMA) + { + if (nArgs > 3) + { + nLen = g_aArgs[ iArg + 2 ].nValue; + nEnd = g_nDebugSkipStart + nLen; + if (nEnd > _6502_MEM_END) + nEnd = _6502_MEM_END + 1; + } + else + { + return Help_Arg_1( CMD_GO ); + } + } + else + if (g_aArgs[ iArg+ 1 ].eToken == TOKEN_COLON) + { + nEnd = g_aArgs[ iArg + 2 ].nValue + 1; + } + else + return Help_Arg_1( CMD_GO ); + } + else + return Help_Arg_1( CMD_GO ); + + nLen = nEnd - g_nDebugSkipStart; + if (nLen < 0) + nLen = -nLen; + g_nDebugSkipLen = nLen; + g_nDebugSkipLen &= _6502_MEM_END; + +#if _DEBUG + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, TEXT("Start: %04X,%04X End: %04X Len: %04X"), + g_nDebugSkipStart, g_nDebugSkipLen, nEnd, nLen ); + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); +#endif + } + +// WORD nAddressSymbol = 0; +// bool bFoundSymbol = FindAddressFromSymbol( g_aArgs[1].sArg, & nAddressSymbol ); +// if (bFoundSymbol) +// g_nDebugStepUntil = nAddressSymbol; + +// if (!g_nDebugStepUntil) +// g_nDebugStepUntil = GetAddress(g_aArgs[1].sArg); + + g_bDebuggerEatKey = true; + g_nAppMode = MODE_STEPPING; + FrameRefreshStatus(DRAW_TITLE); + + return UPDATE_CONSOLE_DISPLAY; // TODO: Verify // 0; +} + +//=========================================================================== +Update_t CmdStepOver (int nArgs) +{ + // assert( g_nDisasmCurAddress == regs.pc ); + +// g_nDebugSteps = nArgs ? g_aArgs[1].nValue : 1; + WORD nDebugSteps = nArgs ? g_aArgs[1].nValue : 1; + + while (nDebugSteps -- > 0) + { + int nOpcode = *(mem + regs.pc); // g_nDisasmCurAddress + // int eMode = g_aOpcodes[ nOpcode ].addrmode; + // int nByte = g_aOpmodes[eMode]._nBytes; + // if ((eMode == AM_A) && + + CmdTrace(0); + if (nOpcode == OPCODE_JSR) + { + CmdStepOut(0); + g_nDebugSteps = 0xFFFF; + while (g_nDebugSteps != 0) + DebugContinueStepping(); + } + } + + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdStepOut (int nArgs) +{ + // TODO: "RET" should probably pop the Call stack + // Also see: CmdCursorJumpRetAddr + WORD nAddress; + if (_6502_GetStackReturnAddress( nAddress )) + { + nArgs = _Arg_1( nAddress ); + g_aArgs[1].sArg[0] = 0; + CmdGo( 1 ); + } + + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdTrace (int nArgs) +{ + g_nDebugSteps = nArgs ? g_aArgs[1].nValue : 1; + g_nDebugStepCycles = 0; + g_nDebugStepStart = regs.pc; + g_nDebugStepUntil = -1; + g_nAppMode = MODE_STEPPING; + FrameRefreshStatus(DRAW_TITLE); + DebugContinueStepping(); + + return UPDATE_ALL; // TODO: Verify // 0 +} + +//=========================================================================== +Update_t CmdTraceFile (int nArgs) +{ + char sText[ CONSOLE_WIDTH ] = ""; + + if (g_hTraceFile) + { + fclose( g_hTraceFile ); + g_hTraceFile = NULL; + + sprintf( sText, "Trace stopped." ); + } + else + { + char sFileName[MAX_PATH]; + + if (nArgs) + strcpy( sFileName, g_aArgs[1].sArg ); + else + strcpy( sFileName, g_sFileNameTrace ); + + + char sFilePath[ MAX_PATH ]; + strcpy(sFilePath, g_sCurrentDir); // g_sProgramDir + strcat(sFilePath, sFileName ); + + g_hTraceFile = fopen( sFilePath, "wt" ); + + if (g_hTraceFile) + { + sprintf( sText, "Trace started: %s", sFileName ); + + g_bTraceHeader = true; + } + else + { + sprintf( sText, "Trace ERROR: %s", sFileName ); + } + } + + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); + + return UPDATE_ALL; // TODO: Verify // 0 +} + +//=========================================================================== +Update_t CmdTraceLine (int nArgs) +{ + g_nDebugSteps = nArgs ? g_aArgs[1].nValue : 1; + g_nDebugStepCycles = 1; + g_nDebugStepStart = regs.pc; + g_nDebugStepUntil = -1; + + g_nAppMode = MODE_STEPPING; + FrameRefreshStatus(DRAW_TITLE); + DebugContinueStepping(); + + return UPDATE_ALL; // TODO: Verify // 0 +} + + + + +// Unassemble +//=========================================================================== +Update_t CmdUnassemble (int nArgs) +{ + if (! nArgs) + return Help_Arg_1( CMD_UNASSEMBLE ); + + WORD nAddress = g_aArgs[1].nValue; + g_nDisasmTopAddress = nAddress; + + DisasmCalcCurFromTopAddress(); + DisasmCalcBotFromTopAddress(); + + return UPDATE_DISASM; +} + + +//=========================================================================== +Update_t CmdKey (int nArgs) +{ + KeybQueueKeypress( + nArgs ? g_aArgs[1].nValue ? g_aArgs[1].nValue : g_aArgs[1].sArg[0] : TEXT(' '), 1); // FIXME!!! + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdIn (int nArgs) +{ + if (!nArgs) + return Help_Arg_1( CMD_IN ); + + WORD nAddress = g_aArgs[1].nValue; + + BYTE nPageOffset = nAddress & 0xFF; + IORead[ (nAddress>>4) & 0xF ](regs.pc, nAddress & 0xFF, 0, 0, 0); // g_aArgs[1].nValue + + return UPDATE_CONSOLE_DISPLAY; // TODO: Verify // 1 +} + + +//=========================================================================== +Update_t CmdJSR (int nArgs) +{ + if (! nArgs) + return Help_Arg_1( CMD_JSR ); + + WORD nAddress = g_aArgs[1].nValue & _6502_MEM_END; + + // Mark Stack Page as dirty + *(memdirty+(regs.sp >> 8)) = 1; + + // Push PC onto stack + *(mem + regs.sp) = ((regs.pc >> 8) & 0xFF); + regs.sp--; + + *(mem + regs.sp) = ((regs.pc >> 0) - 1) & 0xFF; + regs.sp--; + + + // Jump to new address + regs.pc = nAddress; + + return UPDATE_ALL; +} + + +//=========================================================================== +Update_t CmdNOP (int nArgs) +{ + int iOpcode; + int iOpmode; + int nOpbytes; + + _6502_GetOpcodeOpmodeOpbyte( iOpcode, iOpmode, nOpbytes ); + + while (nOpbytes--) + { + *(mem+regs.pc + nOpbytes) = 0xEA; + } + + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdOut (int nArgs) +{ +// if ((!nArgs) || +// ((g_aArgs[1].sArg[0] != TEXT('0')) && (!g_aArgs[1].nValue) && (!GetAddress(g_aArgs[1].sArg)))) +// return DisplayHelp(CmdInput); + + if (!nArgs) + Help_Arg_1( CMD_OUT ); + + WORD nAddress = g_aArgs[1].nValue; + + BYTE nPageOffset = nAddress & 0xFF; + IOWrite[ (nAddress>>4) & 0xF ] (regs.pc, nAddress & 0xFF, 1, g_aArgs[2].nValue & 0xFF, 0); + + return UPDATE_CONSOLE_DISPLAY; // TODO: Verify // 1 +} + + +// Color __________________________________________________________________________________________ + +void _ColorPrint( int iColor, COLORREF nColor ) +{ + int R = (nColor >> 0) & 0xFF; + int G = (nColor >> 8) & 0xFF; + int B = (nColor >> 16) & 0xFF; + + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, " Color %01X: %02X %02X %02X", iColor, R, G, B ); // TODO: print name of colors! + ConsoleBufferPush( sText ); +} + +void _CmdColorGet( const int iScheme, const int iColor ) +{ + if (iColor < NUM_DEBUG_COLORS) + { +// COLORREF nColor = g_aColors[ iScheme ][ iColor ]; + DebugColors_e eColor = static_cast( iColor ); + COLORREF nColor = DebuggerGetColor( eColor ); + _ColorPrint( iColor, nColor ); + } + else + { + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, "Color: %d\nOut of range!", iColor ); + MessageBox( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); + } +} + +//=========================================================================== +inline COLORREF DebuggerGetColor( int iColor ) +{ + COLORREF nColor = RGB(0,255,255); // 0xFFFF00; // Hot Pink! -- so we notice errors. Not that there is anything wrong with pink... + + if ((g_iColorScheme < NUM_COLOR_SCHEMES) && (iColor < NUM_DEBUG_COLORS)) + { + nColor = g_aColors[ g_iColorScheme ][ iColor ]; + } + + return nColor; +} + + +bool DebuggerSetColor( const int iScheme, const int iColor, const COLORREF nColor ) +{ + bool bStatus = false; + if ((g_iColorScheme < NUM_COLOR_SCHEMES) && (iColor < NUM_DEBUG_COLORS)) + { + g_aColors[ iScheme ][ iColor ] = nColor; + bStatus = true; + } + + // Propogate to console since it has its own copy of colors + if (iColor == FG_CONSOLE_OUTPUT) + { + COLORREF nConsole = DebuggerGetColor( FG_CONSOLE_OUTPUT ); + g_anConsoleColor[ CONSOLE_COLOR_x ] = nConsole; + } + + return bStatus; +} + +//=========================================================================== +Update_t CmdConfigColorMono (int nArgs) +{ + int iScheme = 0; + + if (g_iCommand == CMD_CONFIG_COLOR) + iScheme = SCHEME_COLOR; + if (g_iCommand == CMD_CONFIG_MONOCHROME) + iScheme = SCHEME_MONO; + if (g_iCommand == CMD_CONFIG_BW) + iScheme = SCHEME_BW; + + if ((iScheme < 0) || (iScheme > NUM_COLOR_SCHEMES)) // sanity check + iScheme = SCHEME_COLOR; + + if (! nArgs) + { + g_iColorScheme = iScheme; + UpdateDisplay( UPDATE_BACKGROUND ); + return UPDATE_ALL; + } + +// if ((nArgs != 1) && (nArgs != 4)) + if (nArgs > 4) + return HelpLastCommand(); + + int iColor = g_aArgs[ 1 ].nValue; + if ((iColor < 0) || iColor >= NUM_DEBUG_COLORS) + return HelpLastCommand(); + + int iParam; + int nFound = FindParam( g_aArgs[ 1 ].sArg, MATCH_EXACT, iParam, _PARAM_GENERAL_BEGIN, _PARAM_GENERAL_END ); + + if (nFound) + { + if (iParam == PARAM_RESET) + { + _ConfigColorsReset(); + ConsoleBufferPush( TEXT(" Resetting colors." ) ); + } + else + if (iParam == PARAM_SAVE) + { + } + else + if (iParam == PARAM_LOAD) + { + } + else + return HelpLastCommand(); + } + else + { + if (nArgs == 1) + { // Dump Color + _CmdColorGet( iScheme, iColor ); + return ConsoleUpdate(); + } + else + if (nArgs == 4) + { // Set Color + int R = g_aArgs[2].nValue & 0xFF; + int G = g_aArgs[3].nValue & 0xFF; + int B = g_aArgs[4].nValue & 0xFF; + COLORREF nColor = RGB(R,G,B); + + DebuggerSetColor( iScheme, iColor, nColor ); + } + else + return HelpLastCommand(); + } + + return UPDATE_ALL; +} + +Update_t CmdConfigHColor (int nArgs) +{ + if ((nArgs != 1) && (nArgs != 4)) + return Help_Arg_1( g_iCommand ); + + int iColor = g_aArgs[ 1 ].nValue; + if ((iColor < 0) || iColor >= NUM_DEBUG_COLORS) + return Help_Arg_1( g_iCommand ); + + if (nArgs == 1) + { // Dump Color +// _CmdColorGet( iScheme, iColor ); +// TODO/FIXME: must export AW_Video.cpp: static LPBITMAPINFO framebufferinfo; +// COLORREF nColor = g_aColors[ iScheme ][ iColor ]; +// _ColorPrint( iColor, nColor ); + return ConsoleUpdate(); + } + else + { // Set Color +// DebuggerSetColor( iScheme, iColor ); + return UPDATE_ALL; + } +} + +// Config _________________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdConfigLoad (int nArgs) +{ + // TODO: CmdConfigRun( gaFileNameConfig ) + +// TCHAR sFileNameConfig[ MAX_PATH ]; + if (! nArgs) + { + + } + +// gDebugConfigName + // DEBUGLOAD file // load debugger setting + return UPDATE_ALL; +} + + +//=========================================================================== +bool ConfigSave_BufferToDisk ( char *pFileName, ConfigSave_t eConfigSave ) +{ + bool bStatus = false; + + char sModeCreate[] = "w+t"; + char sModeAppend[] = "a+t"; + char *pMode = NULL; + if (eConfigSave == CONFIG_SAVE_FILE_CREATE) + pMode = sModeCreate; + else + if (eConfigSave == CONFIG_SAVE_FILE_APPEND) + pMode = sModeAppend; + + char sFileName[ MAX_PATH ]; + + _tcscpy(sFileName, g_sCurrentDir); + _tcscat(sFileName, pFileName ); + + FILE *hFile = fopen( pFileName, pMode ); + + if (hFile) + { + char *pText; + int nLine = g_ConfigState.GetNumLines(); + int iLine; + + for( iLine = 0; iLine < nLine; iLine++ ) + { + pText = g_ConfigState.GetLine( iLine ); + if ( pText ) + { + fputs( pText, hFile ); + } + } + + fclose( hFile ); + bStatus = true; + } + else + { + } + + return bStatus; +} + + +//=========================================================================== +void ConfigSave_PrepareHeader ( const Parameters_e eCategory, const Commands_e eCommandClear ) +{ + char sText[ CONSOLE_WIDTH ]; + + sprintf( sText, "%s %s = %s\n" + , g_aTokens[ TOKEN_COMMENT_EOL ].sToken + , g_aParameters[ PARAM_CATEGORY ].m_sName + , g_aParameters[ eCategory ] + ); + g_ConfigState.PushLine( sText ); + + sprintf( sText, "%s %s\n" + , g_aCommands[ eCommandClear ].m_sName + , g_aParameters[ PARAM_WILDSTAR ].m_sName + ); + g_ConfigState.PushLine( sText ); +} + + +// Save Debugger Settings +//=========================================================================== +Update_t CmdConfigSave (int nArgs) +{ + TCHAR sFilename[ MAX_PATH ]; + _tcscpy( sFilename, g_sProgramDir ); // g_sCurrentDir + _tcscat( sFilename, g_sFileNameConfig ); + +/* + HANDLE hFile = CreateFile( sfilename, + GENERIC_WRITE, + 0, + (LPSECURITY_ATTRIBUTES)NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (hFile != INVALID_HANDLE_VALUE) + { + void *pSrc; + int nLen; + DWORD nPut; + + // FIXME: Shouldn be saving in Text format, not binary! + + int nVersion = CURRENT_VERSION; + pSrc = (void *) &nVersion; + nLen = sizeof( nVersion ); + WriteFile( hFile, pSrc, nLen, &nPut, NULL ); + + pSrc = (void *) & gaColorPalette; + nLen = sizeof( gaColorPalette ); + WriteFile( hFile, pSrc, nLen, &nPut, NULL ); + + pSrc = (void *) & g_aColorIndex; + nLen = sizeof( g_aColorIndex ); + WriteFile( hFile, pSrc, nLen, &nPut, NULL ); + + CloseHandle( hFile ); + } +*/ + // Bookmarks + CmdBookmarkSave( 0 ); + + // Breakpoints + CmdBreakpointSave( 0 ); + + // Watches + CmdWatchSave( 0 ); + + // Zeropage pointers + CmdZeroPageSave( 0 ); + + // Color Palete + + // Color Index +// CmdColorSave( 0 ); + + // UserSymbol + + // History + + return UPDATE_CONSOLE_DISPLAY; +} + + +// Config - Disasm ________________________________________________________________________________ + +//=========================================================================== +Update_t CmdConfigDisasm( int nArgs ) +{ + int iParam = 0; + TCHAR sText[ CONSOLE_WIDTH ]; + + bool bDisplayCurrentSettings = false; + +// if (! _tcscmp( g_aArgs[ 1 ].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName )) + if (! nArgs) + { + bDisplayCurrentSettings = true; + nArgs = PARAM_CONFIG_NUM; + } + else + { + if (nArgs > 2) + return Help_Arg_1( CMD_CONFIG_DISASM ); + } + + for (int iArg = 1; iArg <= nArgs; iArg++ ) + { + if (bDisplayCurrentSettings) + iParam = _PARAM_CONFIG_BEGIN + iArg - 1; + else + if (FindParam( g_aArgs[iArg].sArg, MATCH_FUZZY, iParam )) + { + } + + switch (iParam) + { + case PARAM_CONFIG_BRANCH: + if ((nArgs > 1) && (! bDisplayCurrentSettings)) // set + { + iArg++; + g_iConfigDisasmBranchType = g_aArgs[ iArg ].nValue; + if (g_iConfigDisasmBranchType < 0) + g_iConfigDisasmBranchType = 0; + if (g_iConfigDisasmBranchType >= NUM_DISASM_BRANCH_TYPES) + g_iConfigDisasmBranchType = NUM_DISASM_BRANCH_TYPES - 1; + + } + else // show current setting + { + wsprintf( sText, TEXT( "Branch Type: %d" ), g_iConfigDisasmBranchType ); + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); + } + break; + + case PARAM_CONFIG_COLON: + if ((nArgs > 1) && (! bDisplayCurrentSettings)) // set + { + iArg++; + g_bConfigDisasmAddressColon = (g_aArgs[ iArg ].nValue) ? true : false; + } + else // show current setting + { + int iState = g_bConfigDisasmAddressColon ? PARAM_ON : PARAM_OFF; + wsprintf( sText, TEXT( "Colon: %s" ), g_aParameters[ iState ].m_sName ); + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); + } + break; + + case PARAM_CONFIG_OPCODE: + if ((nArgs > 1) && (! bDisplayCurrentSettings)) // set + { + iArg++; + g_bConfigDisasmOpcodesView = (g_aArgs[ iArg ].nValue) ? true : false; + } + else + { + int iState = g_bConfigDisasmOpcodesView ? PARAM_ON : PARAM_OFF; + wsprintf( sText, TEXT( "Opcodes: %s" ), g_aParameters[ iState ].m_sName ); + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); + } + break; + + case PARAM_CONFIG_POINTER: + if ((nArgs > 1) && (! bDisplayCurrentSettings)) // set + { + iArg++; + g_bConfigInfoTargetPointer = (g_aArgs[ iArg ].nValue) ? true : false; + } + else + { + int iState = g_bConfigInfoTargetPointer ? PARAM_ON : PARAM_OFF; + wsprintf( sText, TEXT( "Info Target Pointer: %s" ), g_aParameters[ iState ].m_sName ); + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); + } + break; + + case PARAM_CONFIG_SPACES: + if ((nArgs > 1) && (! bDisplayCurrentSettings)) // set + { + iArg++; + g_bConfigDisasmOpcodeSpaces = (g_aArgs[ iArg ].nValue) ? true : false; + } + else + { + int iState = g_bConfigDisasmOpcodeSpaces ? PARAM_ON : PARAM_OFF; + wsprintf( sText, TEXT( "Opcode spaces: %s" ), g_aParameters[ iState ].m_sName ); + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); + } + break; + + case PARAM_CONFIG_TARGET: + if ((nArgs > 1) && (! bDisplayCurrentSettings)) // set + { + iArg++; + g_iConfigDisasmTargets = g_aArgs[ iArg ].nValue; + if (g_iConfigDisasmTargets < 0) + g_iConfigDisasmTargets = 0; + if (g_iConfigDisasmTargets >= NUM_DISASM_TARGET_TYPES) + g_iConfigDisasmTargets = NUM_DISASM_TARGET_TYPES - 1; + } + else // show current setting + { + wsprintf( sText, TEXT( "Target: %d" ), g_iConfigDisasmTargets ); + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); + } + break; + + default: + return Help_Arg_1( CMD_CONFIG_DISASM ); // CMD_CONFIG_DISASM_OPCODE ); + } +// } +// else +// return Help_Arg_1( CMD_CONFIG_DISASM ); + } + return UPDATE_CONSOLE_DISPLAY | UPDATE_DISASM; +} + +// Config - Font __________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdConfigFontLoad( int nArgs ) +{ + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdConfigFontSave( int nArgs ) +{ + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdConfigFontMode( int nArgs ) +{ + if (nArgs != 2) + return Help_Arg_1( CMD_CONFIG_FONT ); + + int nMode = g_aArgs[ 2 ].nValue; + + if ((nMode < 0) || (nMode >= NUM_FONT_SPACING)) + return Help_Arg_1( CMD_CONFIG_FONT ); + + g_iFontSpacing = nMode; + _UpdateWindowFontHeights( g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontHeight ); + + return UPDATE_CONSOLE_DISPLAY | UPDATE_DISASM; +} + + +//=========================================================================== +Update_t CmdConfigFont (int nArgs) +{ + int iArg; + + if (! nArgs) + return CmdConfigGetFont( nArgs ); + else + if (nArgs <= 2) // nArgs + { + iArg = 1; + + // FONT * is undocumented, like VERSION * + if ((! _tcscmp( g_aArgs[ iArg ].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName )) || + (! _tcscmp( g_aArgs[ iArg ].sArg, g_aParameters[ PARAM_MEM_SEARCH_WILD ].m_sName )) ) + { + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, "Lines: %d Font Px: %d Line Px: %d" + , g_nDisasmDisplayLines + , g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontHeight + , g_aFontConfig[ FONT_DISASM_DEFAULT ]._nLineHeight ); + ConsoleBufferPush( sText ); + ConsoleBufferToDisplay(); + return UPDATE_CONSOLE_DISPLAY; + } + + int iFound; + int nFound; + + nFound = FindParam( g_aArgs[iArg].sArg, MATCH_EXACT, iFound, _PARAM_GENERAL_BEGIN, _PARAM_GENERAL_END ); + if (nFound) + { + switch( iFound ) + { + case PARAM_LOAD: + return CmdConfigFontLoad( nArgs ); + break; + case PARAM_SAVE: + return CmdConfigFontSave( nArgs ); + break; + // TODO: FONT SIZE # + // TODO: AA {ON|OFF} + default: + break; + } + } + + nFound = FindParam( g_aArgs[iArg].sArg, MATCH_EXACT, iFound, _PARAM_FONT_BEGIN, _PARAM_FONT_END ); + if (nFound) + { + if (iFound == PARAM_FONT_MODE) + return CmdConfigFontMode( nArgs ); + } + + return CmdConfigSetFont( nArgs ); + } + + return Help_Arg_1( CMD_CONFIG_FONT ); +} + + +// Only for FONT_DISASM_DEFAULT ! +//=========================================================================== +void _UpdateWindowFontHeights( int nFontHeight ) +{ + if (nFontHeight) + { + int nConsoleTopY = GetConsoleTopPixels( g_nConsoleDisplayLines ); + + int nHeight = 0; + + if (g_iFontSpacing == FONT_SPACING_CLASSIC) + { + nHeight = nFontHeight + 1; + g_nDisasmDisplayLines = nConsoleTopY / nHeight; + } + else + if (g_iFontSpacing == FONT_SPACING_CLEAN) + { + nHeight = nFontHeight; + g_nDisasmDisplayLines = nConsoleTopY / nHeight; + } + else + if (g_iFontSpacing == FONT_SPACING_COMPRESSED) + { + nHeight = nFontHeight - 1; + g_nDisasmDisplayLines = (nConsoleTopY + nHeight) / nHeight; // Ceil() + } + + g_aFontConfig[ FONT_DISASM_DEFAULT ]._nLineHeight = nHeight; + +// int nHeightOptimal = (nHeight0 + nHeight1) / 2; +// int nLinesOptimal = nConsoleTopY / nHeightOptimal; +// g_nDisasmDisplayLines = nLinesOptimal; + + WindowUpdateSizes(); + } +} + +//=========================================================================== +bool _CmdConfigFont ( int iFont, LPCSTR pFontName, int iPitchFamily, int nFontHeight ) +{ + bool bStatus = false; + HFONT hFont = (HFONT) 0; + FontConfig_t *pFont = NULL; + + if (iFont < NUM_FONTS) + pFont = & g_aFontConfig[ iFont ]; + + if (pFontName) + { +// int nFontHeight = g_nFontHeight - 1; + + int bAntiAlias = (nFontHeight < 14) ? DEFAULT_QUALITY : ANTIALIASED_QUALITY; + + // Try allow new font + hFont = CreateFont( + nFontHeight + , 0 // Width + , 0 // Escapement + , 0 // Orientatin + , FW_MEDIUM // Weight + , 0 // Italic + , 0 // Underline + , 0 // Strike Out + , DEFAULT_CHARSET // OEM_CHARSET + , OUT_DEFAULT_PRECIS + , CLIP_DEFAULT_PRECIS + , bAntiAlias // ANTIALIASED_QUALITY // DEFAULT_QUALITY + , iPitchFamily // HACK: MAGIC #: 4 + , pFontName ); + + if (hFont) + { + if (iFont == FONT_DISASM_DEFAULT) + _UpdateWindowFontHeights( nFontHeight ); + + _tcsncpy( pFont->_sFontName, pFontName, MAX_FONT_NAME-1 ); + pFont->_sFontName[ MAX_FONT_NAME-1 ] = 0; + + HDC hDC = FrameGetDC(); + + TEXTMETRIC tm; + GetTextMetrics(hDC, &tm); + + SIZE size; + TCHAR sText[] = "W"; + int nLen = 1; + + int nFontWidthAvg; + int nFontWidthMax; + +// if (! (tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) // Windows has this bitflag reversed! +// { // Proportional font? +// bool bStop = true; +// } + + // GetCharWidth32() doesn't work with TrueType Fonts + if (GetTextExtentPoint32( hDC, sText, nLen, &size )) + { + nFontWidthAvg = tm.tmAveCharWidth; + nFontWidthMax = size.cx; + } + else + { + // Font Name Avg Max "W" + // Arial 7 8 11 + // Courier 5 32 11 + // Courier New 7 14 + nFontWidthAvg = tm.tmAveCharWidth; + nFontWidthMax = tm.tmMaxCharWidth; + } + + if (! nFontWidthAvg) + { + nFontWidthAvg = 7; + nFontWidthMax = 7; + } + + FrameReleaseDC(); + +// DeleteObject( g_hFontDisasm ); +// g_hFontDisasm = hFont; + pFont->_hFont = hFont; + + pFont->_nFontWidthAvg = nFontWidthAvg; + pFont->_nFontWidthMax = nFontWidthMax; + pFont->_nFontHeight = nFontHeight; + + bStatus = true; + } + } + return bStatus; +} + + +//=========================================================================== +Update_t CmdConfigSetFont (int nArgs) +{ +#if OLD_FONT + HFONT hFont = (HFONT) 0; + TCHAR *pFontName = NULL; + int nHeight = g_nFontHeight; + int iFontTarget = FONT_DISASM_DEFAULT; + int iFontPitch = FIXED_PITCH | FF_MODERN; +// int iFontMode = + bool bHaveTarget = false; + bool bHaveFont = false; + + if (! nArgs) + { // reset to defaut font + pFontName = g_sFontNameDefault; + } + else + if (nArgs <= 3) + { + int iArg = 1; + pFontName = g_aArgs[1].sArg; + + // [DISASM|INFO|CONSOLE] "FontName" [#] + // "FontName" can be either arg 1 or 2 + + int iFound; + int nFound = FindParam( g_aArgs[iArg].sArg, MATCH_EXACT, iFound, _PARAM_WINDOW_BEGIN, _PARAM_WINDOW_END ); + if (nFound) + { + switch( iFound ) + { + case PARAM_DISASM : iFontTarget = FONT_DISASM_DEFAULT; iFontPitch = FIXED_PITCH | FF_MODERN ; bHaveTarget = true; break; + case PARAM_INFO : iFontTarget = FONT_INFO ; iFontPitch = FIXED_PITCH | FF_MODERN ; bHaveTarget = true; break; + case PARAM_CONSOLE: iFontTarget = FONT_CONSOLE ; iFontPitch = DEFAULT_PITCH | FF_DECORATIVE; bHaveTarget = true; break; + default: + if (g_aArgs[2].bType != TOKEN_QUOTE_DOUBLE) + return Help_Arg_1( CMD_CONFIG_FONT ); + break; + } + if (bHaveTarget) + { + pFontName = g_aArgs[2].sArg; + } + } + else + if (nArgs == 2) + { + nHeight = atoi(g_aArgs[2].sArg ); + if ((nHeight < 6) || (nHeight > 36)) + nHeight = g_nFontHeight; + } + } + else + { + return Help_Arg_1( CMD_CONFIG_FONT ); + } + + if (! _CmdConfigFont( iFontTarget, pFontName, iFontPitch, nHeight )) + { + } +#endif + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdConfigGetFont (int nArgs) +{ + if (! nArgs) + { + for (int iFont = 0; iFont < NUM_FONTS; iFont++ ) + { + TCHAR sText[ CONSOLE_WIDTH ] = TEXT(""); + wsprintf( sText, " Font: %-20s A:%2d M:%2d", +// g_sFontNameCustom, g_nFontWidthAvg, g_nFontWidthMax ); + g_aFontConfig[ iFont ]._sFontName, + g_aFontConfig[ iFont ]._nFontWidthAvg, + g_aFontConfig[ iFont ]._nFontWidthMax ); + ConsoleBufferPush( sText ); + } + return ConsoleUpdate(); + } + + return UPDATE_CONSOLE_DISPLAY; +} + + + +// 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 ); + MessageBox( g_hFrameWindow, 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 ) +{ + WORD nAddress = 0; + if (_6502_GetTargetAddress( g_nDisasmCurAddress, nAddress )) + { + g_nDisasmCurAddress = nAddress; + + if (CURSOR_ALIGN_CENTER == nArgs) + { + WindowUpdateDisasmSize(); + } + else + if (CURSOR_ALIGN_TOP == nArgs) + { + g_nDisasmCurLine = 0; + } + DisasmCalcTopBotAddress(); + } + + return UPDATE_ALL; +} + + +//=========================================================================== +Update_t CmdCursorLineDown (int nArgs) +{ + int iOpmode; + int nOpbytes; + _6502_GetOpmodeOpbyte( g_nDisasmCurAddress, iOpmode, nOpbytes ); // g_nDisasmTopAddress + + if (g_iWindowThis == WINDOW_DATA) + { + _CursorMoveDownAligned( WINDOW_DATA_BYTES_PER_LINE ); + DisasmCalcTopBotAddress(); + } + else + if (nArgs) // scroll down by 'n' bytes + { + nOpbytes = nArgs; // HACKL g_aArgs[1].val + + g_nDisasmTopAddress += nOpbytes; + g_nDisasmCurAddress += nOpbytes; + g_nDisasmBotAddress += nOpbytes; + DisasmCalcTopBotAddress(); + } + else + { +#if DEBUG_SCROLL == 6 + // Works except on one case: G FB53, SPACE, DOWN + WORD nTop = g_nDisasmTopAddress; + WORD nCur = g_nDisasmCurAddress + nOpbytes; + if (g_bDisasmCurBad) + { + g_nDisasmCurAddress = nCur; + g_bDisasmCurBad = false; + DisasmCalcTopFromCurAddress(); + return UPDATE_DISASM; + } + + // Adjust Top until nNewCur is at > Cur + do + { + g_nDisasmTopAddress++; + DisasmCalcCurFromTopAddress(); + } while (g_nDisasmCurAddress < nCur); + + DisasmCalcCurFromTopAddress(); + DisasmCalcBotFromTopAddress(); + g_bDisasmCurBad = false; +#endif + g_nDisasmCurAddress += nOpbytes; + + _6502_GetOpmodeOpbyte( g_nDisasmTopAddress, iOpmode, nOpbytes ); + g_nDisasmTopAddress += nOpbytes; + + _6502_GetOpmodeOpbyte( g_nDisasmBotAddress, iOpmode, nOpbytes ); + g_nDisasmBotAddress += nOpbytes; + + if (g_bDisasmCurBad) + { +// MessageBox( NULL, TEXT("Bad Disassembly of opcodes"), TEXT("Debugger"), MB_OK ); + +// g_nDisasmCurAddress = nCur; +// g_bDisasmCurBad = false; +// DisasmCalcTopFromCurAddress(); + DisasmCalcTopBotAddress(); +// return UPDATE_DISASM; + } + g_bDisasmCurBad = false; + } + + // Can't use use + nBytes due to Disasm Singularity +// DisasmCalcTopBotAddress(); + + return UPDATE_DISASM; +} + +// C++ Bug, can't have local structs used in STL containers + struct LookAhead_t + { + int _nAddress; + int _iOpcode; + int _iOpmode; + int _nOpbytes; + }; + +//=========================================================================== +Update_t CmdCursorLineUp (int nArgs) +{ + int nBytes = 1; + + if (g_iWindowThis == WINDOW_DATA) + { + _CursorMoveUpAligned( WINDOW_DATA_BYTES_PER_LINE ); + } + else + if (nArgs) + { + nBytes = nArgs; // HACK: g_aArgs[1].nValue + + g_nDisasmTopAddress--; + DisasmCalcCurFromTopAddress(); + DisasmCalcBotFromTopAddress(); + } + else + { +// if (! g_nDisasmCurLine) +// { +// g_nDisasmCurLine = 1; +// DisasmCalcTopFromCurAddress( false ); + +// g_nDisasmCurLine = 0; +// DisasmCalcCurFromTopAddress(); +// DisasmCalcBotFromTopAddress(); +// return UPDATE_DISASM; +// } + + // SmartLineUp() + // Figure out if we should move up 1, 2, or 3 bytes since we have 2 possible cases: + // + // a) Scroll up by 2 bytes + // xx-2: A9 yy LDA #xx + // xxxx: top + // + // b) Scroll up by 3 bytes + // xx-3: 20 A9 xx JSR $00A9 + // xxxx: top of window + // +#define DEBUG_SCROLL 3 + +#if DEBUG_SCROLL == 1 + WORD nCur = g_nDisasmCurAddress - nBytes; + + // Adjust Top until nNewCur is at > Cur + do + { + g_nDisasmTopAddress--; + DisasmCalcCurFromTopAddress(); + } while (g_nDisasmCurAddress > nCur); +#endif + +#if DEBUG_SCROLL == 2 + WORD nCur = g_nDisasmCurAddress - nBytes; + + int iOpcode; + int iOpmode; + int nOpbytes; + + int aOpBytes[ 4 ]; // index is relative offset from cursor + int nLeastDesiredTopAddress = NO_6502_TARGET; + + do + { + g_nDisasmTopAddress--; + +// _6502_GetOpcodeOpmodeOpbyte( iOpcode, iOpmode, nOpbytes ); + iOpcode = _6502_GetOpmodeOpbyte( g_nDisasmTopAddress, iOpmode, nOpbytes ); + aOpBytes[ 1 ] = nOpbytes; + + // Disasm is kept in sync. Maybe bad opcode, but if no other choices... + if (nOpbytes == 1) + nLeastDesiredTopAddress = g_nDisasmTopAddress; + + if ( (iOpmode == AM_1) + || (iOpmode == AM_2) + || (iOpmode == AM_3) + || ! _6502_IsOpcodeValid( iOpcode) + || (nOpbytes != 1) ) + { + g_nDisasmTopAddress--; + DisasmCalcCurFromTopAddress(); + + iOpcode = _6502_GetOpmodeOpbyte( g_nDisasmTopAddress, iOpmode, nOpbytes ); + aOpBytes[ 2 ] = nOpbytes; + + if ( (iOpmode == AM_1) + || (iOpmode == AM_2) + || (iOpmode == AM_3) + || ! _6502_IsOpcodeValid( iOpcode) + || (nOpbytes != 2) ) + { + g_nDisasmTopAddress--; + DisasmCalcCurFromTopAddress(); + + iOpcode = _6502_GetOpmodeOpbyte( g_nDisasmTopAddress, iOpmode, nOpbytes ); + aOpBytes[ 3 ] = nOpbytes; + + if ( (iOpmode == AM_1) + || (iOpmode == AM_2) + || (iOpmode == AM_3) + || (nOpbytes != 3) ) + g_nDisasmTopAddress--; + DisasmCalcCurFromTopAddress(); + } + } + + DisasmCalcCurFromTopAddress(); + } while (g_nDisasmCurAddress > nCur); +#endif +#if DEBUG_SCROLL == 3 + // Isn't this the new DisasmCalcTopFromCurAddress() ?? + int iOpcode; + int iOpmode; + int nOpbytes; + + const int MAX_LOOK_AHEAD = g_nDisasmWinHeight; + + static vector aTopCandidates; + LookAhead_t tCandidate; + +// if (! aBestTop.capacity() ) + aTopCandidates.reserve( MAX_LOOK_AHEAD ); + aTopCandidates.erase( aTopCandidates.begin(), aTopCandidates.end() ); + + WORD nTop = g_nDisasmTopAddress; + WORD iTop = 0; + WORD nCur = 0; + + do + { + nTop--; + nCur = nTop; + iTop = (g_nDisasmTopAddress - nTop); + + + for (int iLine = 0; iLine < MAX_LOOK_AHEAD; iLine++ ) + { + iOpcode = _6502_GetOpmodeOpbyte( nCur, iOpmode, nOpbytes ); + + // If address on iLine = g_nDisasmCurLine + 1 + if (iLine == (g_nDisasmCurLine + 1)) + { + if (nCur == (g_nDisasmCurAddress)) + { + iOpcode = _6502_GetOpmodeOpbyte( nTop, iOpmode, nOpbytes ); + + tCandidate._nAddress = nTop; + tCandidate._iOpcode = iOpcode; + tCandidate._iOpmode = iOpmode; + tCandidate._nOpbytes = nOpbytes; + + aTopCandidates.push_back( tCandidate ); + } + } + nCur += nOpbytes; + + if (nCur > g_nDisasmCurAddress) + break; + } + } while (iTop < MAX_LOOK_AHEAD); + + int nCandidates = aTopCandidates.size(); + if (nCandidates) + { + int iBest = NO_6502_TARGET; + + int iCandidate = 0; + for ( ; iCandidate < nCandidates; iCandidate++ ) + { + tCandidate = aTopCandidates.at( iCandidate ); + iOpcode = tCandidate._iOpcode; + iOpmode = tCandidate._iOpmode; + + if ( (iOpmode != AM_1) + && (iOpmode != AM_2) + && (iOpmode != AM_3) + && _6502_IsOpcodeValid( iOpcode ) ) + { + if (g_iConfigDisasmScroll == 1) + { + // Favor min opbytes + if (iBest != NO_6502_TARGET) + iBest = iCandidate; + } + else + if (g_iConfigDisasmScroll == 3) + { + // Favor max opbytes + iBest = iCandidate; + } + } + } + + // All were "invalid", pick first choice + if (iBest == NO_6502_TARGET) + iBest = 0; + + tCandidate = aTopCandidates.at( iBest ); + g_nDisasmTopAddress = tCandidate._nAddress; + + DisasmCalcCurFromTopAddress(); + DisasmCalcBotFromTopAddress(); + g_bDisasmCurBad = false; + } + else + { + // Singularity + g_bDisasmCurBad = true; + +// g_nDisasmTopAddress--; + g_nDisasmCurAddress--; +// g_nDisasmBotAddress--; + DisasmCalcTopBotAddress(); + } +#endif + + } + + return UPDATE_DISASM; +} + + +//=========================================================================== +Update_t CmdCursorJumpPC (int nArgs) +{ + // TODO: Allow user to decide if they want next g_aOpcodes at + // 1) Centered (traditionaly), or + // 2) Top of the screen + + // if (UserPrefs.bNextInstructionCentered) + if (CURSOR_ALIGN_CENTER == nArgs) + { + g_nDisasmCurAddress = regs.pc; // (2) + WindowUpdateDisasmSize(); // calc cur line + } + else + if (CURSOR_ALIGN_TOP == nArgs) + { + g_nDisasmCurAddress = regs.pc; // (2) + g_nDisasmCurLine = 0; + } + + DisasmCalcTopBotAddress(); + + return UPDATE_ALL; +} + + +//=========================================================================== +Update_t CmdCursorJumpRetAddr (int nArgs) +{ + WORD nAddress = 0; + if (_6502_GetStackReturnAddress( nAddress )) + { + g_nDisasmCurAddress = nAddress; + + if (CURSOR_ALIGN_CENTER == nArgs) + { + WindowUpdateDisasmSize(); + } + else + if (CURSOR_ALIGN_TOP == nArgs) + { + g_nDisasmCurLine = 0; + } + DisasmCalcTopBotAddress(); + } + + return UPDATE_ALL; +} + + +//=========================================================================== +Update_t CmdCursorRunUntil (int nArgs) +{ + nArgs = _Arg_1( g_nDisasmCurAddress ); + return CmdGo( nArgs ); +} + + +//=========================================================================== +WORD _ClampAddress( int nAddress ) +{ + if (nAddress < 0) + nAddress = 0; + if (nAddress > _6502_MEM_END) + nAddress = _6502_MEM_END; + + return (WORD) nAddress; +} + + +// nDelta must be a power of 2 +//=========================================================================== +void _CursorMoveDownAligned( int nDelta ) +{ + if (g_iWindowThis == WINDOW_DATA) + { + if (g_aMemDump[0].bActive) + { + if (g_aMemDump[0].eDevice == DEV_MEMORY) + { + g_aMemDump[0].nAddress += nDelta; + g_aMemDump[0].nAddress &= _6502_MEM_END; + } + } + } + else + { + int nNewAddress = g_nDisasmTopAddress; // BUGFIX: g_nDisasmCurAddress; + + if ((nNewAddress & (nDelta-1)) == 0) + nNewAddress += nDelta; + else + nNewAddress += (nDelta - (nNewAddress & (nDelta-1))); // .22 Fixed: Shift-PageUp Shift-PageDown Ctrl-PageUp Ctrl-PageDown -> _CursorMoveUpAligned() & _CursorMoveDownAligned() + + g_nDisasmTopAddress = nNewAddress & _6502_MEM_END; // .21 Fixed: _CursorMoveUpAligned() & _CursorMoveDownAligned() not wrapping around past FF00 to 0, and wrapping around past 0 to FF00 + } +} + +// nDelta must be a power of 2 +//=========================================================================== +void _CursorMoveUpAligned( int nDelta ) +{ + if (g_iWindowThis == WINDOW_DATA) + { + if (g_aMemDump[0].bActive) + { + if (g_aMemDump[0].eDevice == DEV_MEMORY) + { + g_aMemDump[0].nAddress -= nDelta; + g_aMemDump[0].nAddress &= _6502_MEM_END; + } + } + } + else + { + int nNewAddress = g_nDisasmTopAddress; // BUGFIX: g_nDisasmCurAddress; + + if ((nNewAddress & (nDelta-1)) == 0) + nNewAddress -= nDelta; + else + nNewAddress -= (nNewAddress & (nDelta-1)); // .22 Fixed: Shift-PageUp Shift-PageDown Ctrl-PageUp Ctrl-PageDown -> _CursorMoveUpAligned() & _CursorMoveDownAligned() + + g_nDisasmTopAddress = nNewAddress & _6502_MEM_END; // .21 Fixed: _CursorMoveUpAligned() & _CursorMoveDownAligned() not wrapping around past FF00 to 0, and wrapping around past 0 to FF00 + } +} + + +//=========================================================================== +Update_t CmdCursorPageDown (int nArgs) +{ + int iLines = 0; // show at least 1 line from previous display + int nLines = WindowGetHeight( g_iWindowThis ); + + if (nLines < 2) + nLines = 2; + + if (g_iWindowThis == WINDOW_DATA) + { + const int nStep = 128; + _CursorMoveDownAligned( nStep ); + } + else + { +// 4 +// while (++iLines < nLines) +// CmdCursorLineDown(nArgs); + +// 5 + nLines -= (g_nDisasmCurLine + 1); + if (nLines < 1) + nLines = 1; + + while (iLines++ < nLines) + { + CmdCursorLineDown( 0 ); // nArgs + } +// 6 + + } + + return UPDATE_DISASM; +} + + +//=========================================================================== +Update_t CmdCursorPageDown256 (int nArgs) +{ + const int nStep = 256; + _CursorMoveDownAligned( nStep ); + return UPDATE_DISASM; +} + +//=========================================================================== +Update_t CmdCursorPageDown4K (int nArgs) +{ + const int nStep = 4096; + _CursorMoveDownAligned( nStep ); + return UPDATE_DISASM; +} + +//=========================================================================== +Update_t CmdCursorPageUp (int nArgs) +{ + int iLines = 0; // show at least 1 line from previous display + int nLines = WindowGetHeight( g_iWindowThis ); + + if (nLines < 2) + nLines = 2; + + if (g_iWindowThis == WINDOW_DATA) + { + const int nStep = 128; + _CursorMoveUpAligned( nStep ); + } + else + { +// while (++iLines < nLines) +// CmdCursorLineUp(nArgs); + nLines -= (g_nDisasmCurLine + 1); + if (nLines < 1) + nLines = 1; + + while (iLines++ < nLines) + { + CmdCursorLineUp( 0 ); // smart line up + // CmdCursorLineUp( -nLines ); + } + } + + return UPDATE_DISASM; +} + +//=========================================================================== +Update_t CmdCursorPageUp256 (int nArgs) +{ + const int nStep = 256; + _CursorMoveUpAligned( nStep ); + return UPDATE_DISASM; +} + +//=========================================================================== +Update_t CmdCursorPageUp4K (int nArgs) +{ + const int nStep = 4096; + _CursorMoveUpAligned( nStep ); + return UPDATE_DISASM; +} + +//=========================================================================== +Update_t CmdCursorSetPC( int nArgs) // TODO rename +{ + regs.pc = nArgs; // HACK: + return UPDATE_DISASM; +} + + +// Flags __________________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdFlagClear (int nArgs) +{ + int iFlag = (g_iCommand - CMD_FLAG_CLR_C); + + if (g_iCommand == CMD_FLAG_CLEAR) + { + int iArg = nArgs; + while (iArg) + { + iFlag = 0; + while (iFlag < _6502_NUM_FLAGS) + { +// if (g_aFlagNames[iFlag] == g_aArgs[iArg].sArg[0]) + if (g_aBreakpointSource[ BP_SRC_FLAG_N + iFlag ][0] == g_aArgs[iArg].sArg[0]) + { + regs.ps &= ~(1 << iFlag); + } + iFlag++; + } + iArg--; + } + } + else + { + regs.ps &= ~(1 << iFlag); + } + + return UPDATE_FLAGS; // 1; +} + +//=========================================================================== +Update_t CmdFlagSet (int nArgs) +{ + int iFlag = (g_iCommand - CMD_FLAG_SET_C); + + if (g_iCommand == CMD_FLAG_SET) + { + int iArg = nArgs; + while (iArg) + { + iFlag = 0; + while (iFlag < _6502_NUM_FLAGS) + { +// if (g_aFlagNames[iFlag] == g_aArgs[iArg].sArg[0]) + if (g_aBreakpointSource[ BP_SRC_FLAG_N + iFlag ][0] == g_aArgs[iArg].sArg[0]) + { + regs.ps |= (1 << iFlag); + } + iFlag++; + } + iArg--; + } + } + else + { + regs.ps |= (1 << iFlag); + } + return UPDATE_FLAGS; // 1; +} + +//=========================================================================== +Update_t CmdFlag (int nArgs) +{ +// if (g_aArgs[0].sArg[0] == g_aParameters[PARAM_FLAG_CLEAR].aName[0] ) // TEXT('R') + if (g_iCommand == CMD_FLAG_CLEAR) + return CmdFlagClear( nArgs ); + else + if (g_iCommand == CMD_FLAG_SET) +// if (g_aArgs[0].sArg[0] == g_aParameters[PARAM_FLAG_SET].aName[0] ) // TEXT('S') + return CmdFlagSet( nArgs ); + + return UPDATE_ALL; // 0; +} + + +// Disk ___________________________________________________________________________________________ +Update_t CmdDisk ( int nArgs) +{ + if (! nArgs) + goto _Help; + + if (nArgs < 2) + goto _Help; + + int iDrive = g_aArgs[ 1 ].nValue; + + if ((iDrive < 1) || (iDrive > 2)) + return HelpLastCommand(); + + iDrive--; + + int iParam = 0; + int nFound = FindParam( g_aArgs[ 2 ].sArg, MATCH_EXACT, iParam, _PARAM_DISK_BEGIN, _PARAM_DISK_END ); + + if (! nFound) + goto _Help; + + if (iParam == PARAM_DISK_EJECT) + { + if (nArgs > 2) + goto _Help; + + DiskEject( iDrive ); + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); + } + else + if (iParam == PARAM_DISK_PROTECT) + { + if (nArgs > 3) + goto _Help; + + bool bProtect = true; + + if (nArgs == 3) + bProtect = g_aArgs[ 3 ].nValue ? true : false; + + DiskSetProtect( iDrive, bProtect ); + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); + } + else + { + if (nArgs != 3) + goto _Help; + + LPCTSTR pDiskName = g_aArgs[ 3 ].sArg; + + // DISK # "Diskname" + DiskInsert( iDrive, pDiskName, IMAGE_FORCE_WRITE_PROTECTED, IMAGE_DONT_CREATE ); + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); + } + + return UPDATE_CONSOLE_DISPLAY; + +_Help: + return HelpLastCommand(); +} + + +// Memory _________________________________________________________________________________________ + + +// TO DO: +// . Add support for dumping Disk][ device +//=========================================================================== +bool MemoryDumpCheck (int nArgs, WORD * pAddress_ ) +{ + if (! nArgs) + return false; + + Arg_t *pArg = &g_aArgs[1]; + WORD nAddress = pArg->nValue; + bool bUpdate = false; + + pArg->eDevice = DEV_MEMORY; // Default + + if(strncmp(g_aArgs[1].sArg, "SY", 2) == 0) // SY6522 + { + nAddress = (g_aArgs[1].sArg[2] - '0') & 3; + pArg->eDevice = DEV_SY6522; + bUpdate = true; + } + else if(strncmp(g_aArgs[1].sArg, "AY", 2) == 0) // AY8910 + { + nAddress = (g_aArgs[1].sArg[2] - '0') & 3; + pArg->eDevice = DEV_AY8910; + bUpdate = true; + } +#ifdef SUPPORT_Z80_EMU + else if(strcmp(g_aArgs[1].sArg, "*AF") == 0) + { + nAddress = *(WORD*)(mem + REG_AF); + bUpdate = true; + } + else if(strcmp(g_aArgs[1].sArg, "*BC") == 0) + { + nAddress = *(WORD*)(mem + REG_BC); + bUpdate = true; + } + else if(strcmp(g_aArgs[1].sArg, "*DE") == 0) + { + nAddress = *(WORD*)(mem + REG_DE); + bUpdate = true; + } + else if(strcmp(g_aArgs[1].sArg, "*HL") == 0) + { + nAddress = *(WORD*)(mem + REG_HL); + bUpdate = true; + } + else if(strcmp(g_aArgs[1].sArg, "*IX") == 0) + { + nAddress = *(WORD*)(mem + REG_IX); + bUpdate = true; + } +#endif + + if (bUpdate) + { + pArg->nValue = nAddress; + sprintf( pArg->sArg, "%04X", nAddress ); + } + + if (pAddress_) + { + *pAddress_ = nAddress; + } + + return true; +} + +//=========================================================================== +Update_t CmdMemoryCompare (int nArgs ) +{ + if (nArgs < 3) + return Help_Arg_1( CMD_MEMORY_COMPARE ); + + WORD nSrcAddr = g_aArgs[1].nValue; + WORD nLenByte = 0; + WORD nDstAddr = g_aArgs[3].nValue; + + WORD nSrcSymAddr; + WORD nDstSymAddr; + + if (!nSrcAddr) + { + nSrcSymAddr = GetAddressFromSymbol( g_aArgs[1].sArg ); + if (nSrcAddr != nSrcSymAddr) + nSrcAddr = nSrcSymAddr; + } + + if (!nDstAddr) + { + nDstSymAddr = GetAddressFromSymbol( g_aArgs[3].sArg ); + if (nDstAddr != nDstSymAddr) + nDstAddr = nDstSymAddr; + } + +// if ((!nSrcAddr) || (!nDstAddr)) +// return Help_Arg_1( CMD_MEMORY_COMPARE ); + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +static Update_t _CmdMemoryDump (int nArgs, int iWhich, int iView ) +{ + WORD nAddress = 0; + + if( ! MemoryDumpCheck(nArgs, & nAddress ) ) + { + return Help_Arg_1( g_iCommand ); + } + + g_aMemDump[iWhich].nAddress = nAddress; + g_aMemDump[iWhich].eDevice = g_aArgs[1].eDevice; + g_aMemDump[iWhich].bActive = true; + g_aMemDump[iWhich].eView = (MemoryView_e) iView; + + return UPDATE_ALL; // TODO: This really needed? Don't think we do any actual ouput +} + +//=========================================================================== +bool _MemoryCheckMiniDump ( int iWhich ) +{ + if ((iWhich < 0) || (iWhich > NUM_MEM_MINI_DUMPS)) + { + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, TEXT(" Only %d memory mini dumps"), NUM_MEM_MINI_DUMPS ); + ConsoleDisplayError( sText ); + return true; + } + return false; +} + +//=========================================================================== +Update_t CmdMemoryMiniDumpHex (int nArgs) +{ + int iWhich = g_iCommand - CMD_MEM_MINI_DUMP_HEX_1; + if (_MemoryCheckMiniDump( iWhich )) + return UPDATE_CONSOLE_DISPLAY; + + return _CmdMemoryDump(nArgs, iWhich, MEM_VIEW_HEX ); +} + +//=========================================================================== +Update_t CmdMemoryMiniDumpAscii (int nArgs) +{ + int iWhich = g_iCommand - CMD_MEM_MINI_DUMP_ASCII_1; + if (_MemoryCheckMiniDump( iWhich )) + return UPDATE_CONSOLE_DISPLAY; + + return _CmdMemoryDump(nArgs, iWhich, MEM_VIEW_ASCII ); +} + +//=========================================================================== +Update_t CmdMemoryMiniDumpApple (int nArgs) +{ + int iWhich = g_iCommand - CMD_MEM_MINI_DUMP_APPLE_1; + if (_MemoryCheckMiniDump( iWhich )) + return UPDATE_CONSOLE_DISPLAY; + + return _CmdMemoryDump(nArgs, iWhich, MEM_VIEW_APPLE ); // MEM_VIEW_TXT_LO ); +} + +//=========================================================================== +//Update_t CmdMemoryMiniDumpLow (int nArgs) +//{ +// int iWhich = g_iCommand - CMD_MEM_MINI_DUMP_TXT_LO_1; +// if (_MemoryCheckMiniDump( iWhich )) +// return UPDATE_CONSOLE_DISPLAY; +// +// return _CmdMemoryDump(nArgs, iWhich, MEM_VIEW_APPLE ); // MEM_VIEW_TXT_LO ); +//} + +//=========================================================================== +//Update_t CmdMemoryMiniDumpHigh (int nArgs) +//{ +// int iWhich = g_iCommand - CMD_MEM_MINI_DUMP_TXT_HI_1; +// if (_MemoryCheckMiniDump( iWhich )) +// return UPDATE_CONSOLE_DISPLAY; +// +// return _CmdMemoryDump(nArgs, iWhich, MEM_VIEW_APPLE ); // MEM_VIEW_TXT_HI ); +//} + +//=========================================================================== +Update_t CmdMemoryEdit (int nArgs) +{ + + return UPDATE_CONSOLE_DISPLAY; +} + +// MEB addr 8_bit_value +//=========================================================================== +Update_t CmdMemoryEnterByte (int nArgs) +{ + if ((nArgs < 2) || + ((g_aArgs[2].sArg[0] != TEXT('0')) && (!g_aArgs[2].nValue))) // arg2 not numeric or not specified + { + Help_Arg_1( CMD_MEMORY_ENTER_WORD ); + } + + WORD nAddress = g_aArgs[1].nValue; + while (nArgs >= 2) + { + WORD nData = g_aArgs[nArgs].nValue; + if( nData > 0xFF) + { + *(mem + nAddress + nArgs - 2) = (BYTE)(nData >> 0); + *(mem + nAddress + nArgs - 1) = (BYTE)(nData >> 8); + } + else + { + *(mem + nAddress+nArgs-2) = (BYTE)nData; + } + *(memdirty+(nAddress >> 8)) = 1; + nArgs--; + } + + return UPDATE_ALL; +} + +// MEW addr 16-bit_vaue +//=========================================================================== +Update_t CmdMemoryEnterWord (int nArgs) +{ + if ((nArgs < 2) || + ((g_aArgs[2].sArg[0] != TEXT('0')) && (!g_aArgs[2].nValue))) // arg2 not numeric or not specified + { + Help_Arg_1( CMD_MEMORY_ENTER_WORD ); + } + + WORD nAddress = g_aArgs[1].nValue; + while (nArgs >= 2) + { + WORD nData = g_aArgs[nArgs].nValue; + + // Little Endian + *(mem + nAddress + nArgs - 2) = (BYTE)(nData >> 0); + *(mem + nAddress + nArgs - 1) = (BYTE)(nData >> 8); + + *(memdirty+(nAddress >> 8)) |= 1; + nArgs--; + } + + return UPDATE_ALL; +} + +//=========================================================================== +void MemMarkDirty( WORD nAddressStart, WORD nAddressEnd ) +{ + for( int iPage = (nAddressStart >> 8); iPage <= (nAddressEnd >> 8); iPage++ ) + { + *(memdirty+iPage) = 1; + } +} + +//=========================================================================== +Update_t CmdMemoryFill (int nArgs) +{ + // F address end value + // F address,len value + // F address:end value + if ((!nArgs) || (nArgs < 3) || (nArgs > 4)) + return Help_Arg_1( CMD_MEMORY_FILL ); + + WORD nAddress2 = 0; + WORD nAddressStart = 0; + WORD nAddressEnd = 0; + int nAddressLen = 0; + BYTE nValue = 0; + + if( nArgs == 3) + { + nAddressStart = g_aArgs[1].nValue; + nAddressEnd = g_aArgs[2].nValue; + nAddressLen = MIN(_6502_MEM_END , nAddressEnd - nAddressStart + 1 ); + } + else + { + RangeType_t eRange; + eRange = Range_Get( nAddressStart, nAddress2, 1 ); + + if (! Range_CalcEndLen( eRange, nAddressStart, nAddress2, nAddressEnd, nAddressLen )) + return Help_Arg_1( CMD_MEMORY_MOVE ); + } +#if DEBUG_VAL_2 + nBytes = MAX(1,g_aArgs[1].nVal2); // TODO: This actually work?? +#endif + + if ((nAddressLen > 0) && (nAddressEnd <= _6502_MEM_END)) + { + MemMarkDirty( nAddressStart, nAddressEnd ); + + nValue = g_aArgs[nArgs].nValue & 0xFF; + while( nAddressStart <= nAddressEnd ) + { + // TODO: Optimize - split into pre_io, and post_io + if ((nAddress2 < _6502_IO_BEGIN) || (nAddress2 > _6502_IO_END)) + { + *(mem + nAddressStart) = nValue; + } + nAddressStart++; + } + } + + return UPDATE_ALL; // UPDATE_CONSOLE_DISPLAY; +} + + +static TCHAR g_sMemoryLoadSaveFileName[ MAX_PATH ] = TEXT(""); + + +//=========================================================================== +Update_t CmdMemoryLoad (int nArgs) +{ + // BLOAD ["Filename"] , addr[, len] + // BLOAD ["Filename"] , addr[: end] + // 1 2 3 4 5 + if (nArgs > 5) + return Help_Arg_1( CMD_MEMORY_LOAD ); + + bool bHaveFileName = false; + int iArgAddress = 3; + + if (g_aArgs[1].bType & TYPE_QUOTED_2) + bHaveFileName = true; + +// if (g_aArgs[2].bType & TOKEN_QUOTE_DOUBLE) +// bHaveFileName = true; + + if (nArgs > 1) + { + if (g_aArgs[1].bType & TYPE_QUOTED_2) + bHaveFileName = true; + + int iArgComma1 = 2; + int iArgAddress = 3; + int iArgComma2 = 4; + int iArgLength = 5; + + if (! bHaveFileName) + { + iArgComma1 = 1; + iArgAddress = 2; + iArgComma2 = 3; + iArgLength = 4; + + if (nArgs > 4) + return Help_Arg_1( CMD_MEMORY_LOAD ); + } + + if (g_aArgs[ iArgComma1 ].eToken != TOKEN_COMMA) + return Help_Arg_1( CMD_MEMORY_SAVE ); + + TCHAR sLoadSaveFilePath[ MAX_PATH ]; + _tcscpy( sLoadSaveFilePath, g_sCurrentDir ); // g_sProgramDir + + WORD nAddressStart; + WORD nAddress2 = 0; + WORD nAddressEnd = 0; + int nAddressLen = 0; + + RangeType_t eRange; + eRange = Range_Get( nAddressStart, nAddress2, iArgAddress ); + if (nArgs > 4) + { + if (eRange == RANGE_MISSING_ARG_2) + { + return Help_Arg_1( CMD_MEMORY_LOAD ); + } + +// if (eRange == RANGE_MISSING_ARG_2) + if (! Range_CalcEndLen( eRange, nAddressStart, nAddress2, nAddressEnd, nAddressLen )) + { + return Help_Arg_1( CMD_MEMORY_SAVE ); + } + } + + BYTE *pMemory = new BYTE [ _6502_MEM_END + 1 ]; // default 64K buffer + BYTE *pDst = mem + nAddressStart; + BYTE *pSrc = pMemory; + + if (bHaveFileName) + { + _tcscpy( g_sMemoryLoadSaveFileName, g_aArgs[ 1 ].sArg ); + } + _tcscat( sLoadSaveFilePath, g_sMemoryLoadSaveFileName ); + + FILE *hFile = fopen( sLoadSaveFilePath, "rb" ); + if (hFile) + { + fseek( hFile, 0, SEEK_END ); + int nFileBytes = ftell( hFile ); + fseek( hFile, 0, SEEK_SET ); + + if (nFileBytes > _6502_MEM_END) + nFileBytes = _6502_MEM_END + 1; // Bank-switched RAMR/ROM is only 16-bit + + // Caller didnt' specify how many bytes to read, default to them all + if (nAddressLen == 0) + { + nAddressLen = nFileBytes; + } + + size_t nRead = fread( pMemory, nAddressLen, 1, hFile ); + if (nRead == 1) // (size_t)nLen) + { + int iByte; + for( iByte = 0; iByte < nAddressLen; iByte++ ) + { + *pDst++ = *pSrc++; + } + ConsoleBufferPush( TEXT( "Loaded." ) ); + } + fclose( hFile ); + } + else + { + ConsoleBufferPush( TEXT( "ERROR: Bad filename" ) ); + TCHAR sPath[ MAX_PATH + 8 ] = "Path: "; + _tcscat( sPath, g_sCurrentDir ); + ConsoleBufferPush( sPath ); + TCHAR sFile[ MAX_PATH + 8 ] = "File: "; + _tcscat( sFile, g_sMemoryLoadSaveFileName ); + ConsoleBufferPush( sFile ); + } + + delete [] pMemory; + } + else + return Help_Arg_1( CMD_MEMORY_LOAD ); + + return ConsoleUpdate(); +} + +// dst src : len +//=========================================================================== +Update_t CmdMemoryMove (int nArgs) +{ + if (nArgs < 3) + return Help_Arg_1( CMD_MEMORY_MOVE ); + + WORD nDst = g_aArgs[1].nValue; +// WORD nSrc = g_aArgs[2].nValue; +// WORD nLen = g_aArgs[3].nValue - nSrc; + WORD nAddress2 = 0; + WORD nAddressStart = 0; + WORD nAddressEnd = 0; + int nAddressLen = 0; + + RangeType_t eRange; + eRange = Range_Get( nAddressStart, nAddress2, 2 ); + +// if (eRange == RANGE_MISSING_ARG_2) + if (! Range_CalcEndLen( eRange, nAddressStart, nAddress2, nAddressEnd, nAddressLen )) + return Help_Arg_1( CMD_MEMORY_MOVE ); + + if ((nAddressLen > 0) && (nAddressEnd <= _6502_MEM_END)) + { + MemMarkDirty( nAddressStart, nAddressEnd ); + +// BYTE *pSrc = mem + nAddressStart; +// BYTE *pDst = mem + nDst; +// BYTE *pEnd = pSrc + nAddressLen; + + while( nAddressStart <= nAddressEnd ) + { + // TODO: Optimize - split into pre_io, and post_io + if ((nDst < _6502_IO_BEGIN) || (nDst > _6502_IO_END)) + { + *(mem + nDst) = *(mem + nAddressStart); + } + nDst++; + nAddressStart++; + } + + return UPDATE_ALL; + } + + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdMemorySave (int nArgs) +{ + // BSAVE ["Filename"] , addr , len + // BSAVE ["Filename"] , addr : end + // 1 2 3 4 5 + static WORD nAddressStart = 0; + WORD nAddress2 = 0; + static WORD nAddressEnd = 0; + static int nAddressLen = 0; + + if (nArgs > 5) + return Help_Arg_1( CMD_MEMORY_SAVE ); + + if (! nArgs) + { + TCHAR sLast[ CONSOLE_WIDTH ] = TEXT(""); + if (nAddressLen) + { + wsprintf( sLast, TEXT("Last saved: $%04X:$%04X, %04X"), + nAddressStart, nAddressEnd, nAddressLen ); + } + else + { + wsprintf( sLast, TEXT( "Last saved: none" ) ); + } + ConsoleBufferPush( sLast ); + } + else + { + bool bHaveFileName = false; + + if (g_aArgs[1].bType & TYPE_QUOTED_2) + bHaveFileName = true; + +// if (g_aArgs[1].bType & TOKEN_QUOTE_DOUBLE) +// bHaveFileName = true; + + int iArgComma1 = 2; + int iArgAddress = 3; + int iArgComma2 = 4; + int iArgLength = 5; + + if (! bHaveFileName) + { + iArgComma1 = 1; + iArgAddress = 2; + iArgComma2 = 3; + iArgLength = 4; + + if (nArgs > 4) + return Help_Arg_1( CMD_MEMORY_SAVE ); + } + +// if ((g_aArgs[ iArgComma1 ].eToken != TOKEN_COMMA) || +// (g_aArgs[ iArgComma2 ].eToken != TOKEN_COLON)) +// return Help_Arg_1( CMD_MEMORY_SAVE ); + + TCHAR sLoadSaveFilePath[ MAX_PATH ]; + _tcscpy( sLoadSaveFilePath, g_sCurrentDir ); // g_sProgramDir + + RangeType_t eRange; + eRange = Range_Get( nAddressStart, nAddress2, iArgAddress ); + +// if (eRange == RANGE_MISSING_ARG_2) + if (! Range_CalcEndLen( eRange, nAddressStart, nAddress2, nAddressEnd, nAddressLen )) + return Help_Arg_1( CMD_MEMORY_SAVE ); + + if ((nAddressLen) && (nAddressEnd <= _6502_MEM_END)) + { + if (! bHaveFileName) + { + sprintf( g_sMemoryLoadSaveFileName, "%04X.%04X.bin", nAddressStart, nAddressLen ); // nAddressEnd ); + } + else + { + _tcscpy( g_sMemoryLoadSaveFileName, g_aArgs[ 1 ].sArg ); + } + _tcscat( sLoadSaveFilePath, g_sMemoryLoadSaveFileName ); + +// if (nArgs == 2) + { + BYTE *pMemory = new BYTE [ nAddressLen ]; + BYTE *pDst = pMemory; + BYTE *pSrc = mem + nAddressStart; + + // memcpy -- copy out of active memory bank + int iByte; + for( iByte = 0; iByte < nAddressLen; iByte++ ) + { + *pDst++ = *pSrc++; + } + + FILE *hFile = fopen( sLoadSaveFilePath, "rb" ); + if (hFile) + { + ConsoleBufferPush( TEXT( "Warning: File already exists. Overwriting." ) ); + fclose( hFile ); + } + + hFile = fopen( sLoadSaveFilePath, "wb" ); + if (hFile) + { + size_t nWrote = fwrite( pMemory, nAddressLen, 1, hFile ); + if (nWrote == 1) // (size_t)nAddressLen) + { + ConsoleBufferPush( TEXT( "Saved." ) ); + } + else + { + ConsoleBufferPush( TEXT( "Error saving." ) ); + } + fclose( hFile ); + } + + delete [] pMemory; + } + } + } + + return ConsoleUpdate(); +} + + +//=========================================================================== +int _SearchMemoryFind( + MemorySearchValues_t vMemorySearchValues, + WORD nAddressStart, + WORD nAddressEnd ) +{ + int nFound = 0; + g_vMemorySearchResults.erase( g_vMemorySearchResults.begin(), g_vMemorySearchResults.end() ); + g_vMemorySearchResults.push_back( NO_6502_TARGET ); + + WORD nAddress; + for( nAddress = nAddressStart; nAddress < nAddressEnd; nAddress++ ) + { + bool bMatchAll = true; + + WORD nAddress2 = nAddress; + + int nMemBlocks = vMemorySearchValues.size(); + for (int iBlock = 0; iBlock < nMemBlocks; iBlock++, nAddress2++ ) + { + MemorySearch_t ms = vMemorySearchValues.at( iBlock ); + ms.m_bFound = false; + + if ((ms.m_iType == MEM_SEARCH_BYTE_EXACT ) || + (ms.m_iType == MEM_SEARCH_NIB_HIGH_EXACT) || + (ms.m_iType == MEM_SEARCH_NIB_LOW_EXACT )) + { + BYTE nTarget = *(mem + nAddress2); + + if (ms.m_iType == MEM_SEARCH_NIB_LOW_EXACT) + nTarget &= 0x0F; + + if (ms.m_iType == MEM_SEARCH_NIB_HIGH_EXACT) + nTarget &= 0xF0; + + if (ms.m_nValue == nTarget) + { // ms.m_nAddress = nAddress2; + ms.m_bFound = true; + continue; + } + else + { + bMatchAll = false; + break; + } + } + else + if (ms.m_iType == MEM_SEARCH_BYTE_1_WILD) + { + // match by definition + } + else + { + // start 2ndary search + // if next block matches, then this block matches (since we are wild) + if ((iBlock + 1) == nMemBlocks) // there is no next block, hence we match + continue; + + MemorySearch_t ms2 = vMemorySearchValues.at( iBlock + 1 ); + + WORD nAddress3 = nAddress2; + for (nAddress3 = nAddress2; nAddress3 < nAddressEnd; nAddress3++ ) + { + if ((ms.m_iType == MEM_SEARCH_BYTE_EXACT ) || + (ms.m_iType == MEM_SEARCH_NIB_HIGH_EXACT) || + (ms.m_iType == MEM_SEARCH_NIB_LOW_EXACT )) + { + BYTE nTarget = *(mem + nAddress3); + + if (ms.m_iType == MEM_SEARCH_NIB_LOW_EXACT) + nTarget &= 0x0F; + + if (ms.m_iType == MEM_SEARCH_NIB_HIGH_EXACT) + nTarget &= 0xF0; + + if (ms.m_nValue == nTarget) + { + nAddress2 = nAddress3; + continue; + } + else + { + bMatchAll = false; + break; + } + } + + } + } + } + + if (bMatchAll) + { + nFound++; + + // Save the search result + g_vMemorySearchResults.push_back( nAddress ); + } + } + + return nFound; +} + + +//=========================================================================== +Update_t _SearchMemoryDisplay (int nArgs) +{ + const UINT nBuf = CONSOLE_WIDTH * 2; + + int nFound = g_vMemorySearchResults.size() - 1; + + int nLen = 0; // temp + int nLineLen = 0; // string length of matches for this line, for word-wrap + + TCHAR sMatches[ nBuf ] = TEXT(""); + TCHAR sResult[ nBuf ]; + TCHAR sText[ nBuf ] = TEXT(""); + + if (nFound > 0) + { + int iFound = 1; + while (iFound <= nFound) + { + WORD nAddress = g_vMemorySearchResults.at( iFound ); + +// sprintf( sText, "%2d:$%04X ", iFound, nAddress ); +// int nLen = _tcslen( sText ); + + sResult[0] = 0; + nLen = 0; + + StringCat( sResult, CHC_COMMAND, nBuf ); + sprintf( sText, "%2d", iFound ); + nLen += StringCat( sResult, sText , nBuf ); + + StringCat( sResult, CHC_DEFAULT, nBuf ); + nLen += StringCat( sResult, ":" , nBuf ); + + StringCat( sResult, CHC_ADDRESS, nBuf ); + sprintf( sText, "$%04X", nAddress ); + nLen += StringCat( sResult, sText, nBuf ); + + // Fit on same line? + if ((nLineLen + nLen) > (g_nConsoleDisplayWidth - 1)) // CONSOLE_WIDTH + { + //ConsoleDisplayPush( sMatches ); + ConsolePrint( sMatches ); + _tcscpy( sMatches, sResult ); + nLineLen = nLen; + } + else + { + StringCat( sMatches, sResult, nBuf ); + nLineLen += nLen; + } + + iFound++; + } + ConsolePrint( sMatches ); + } + +// wsprintf( sMatches, "Total: %d (#$%04X)", nFound, nFound ); +// ConsoleDisplayPush( sMatches ); + sResult[0] = 0; + + StringCat( sResult, CHC_USAGE , nBuf ); + nLen += StringCat( sResult, "Total", nBuf ); + + StringCat( sResult, CHC_DEFAULT, nBuf ); + nLen += StringCat( sResult, ": " , nBuf ); + + StringCat( sResult, CHC_NUM_DEC, nBuf ); + sprintf( sText, "%d ", nFound ); + nLen += StringCat( sResult, sText, nBuf ); + + StringCat( sResult, CHC_ARG_OPT, nBuf ); + nLen += StringCat( sResult, "(" , nBuf ); + + StringCat( sResult, CHC_DEFAULT, nBuf ); + nLen += StringCat( sResult, "#$", nBuf ); + + StringCat( sResult, CHC_NUM_HEX, nBuf ); + sprintf( sText, "%04X", nFound ); + nLen += StringCat( sResult, sText, nBuf ); + + StringCat( sResult, CHC_ARG_OPT, nBuf ); + nLen += StringCat( sResult, ")" , nBuf ); + + ConsolePrint( sResult ); + + // g_vMemorySearchResults is cleared in DebugEnd() + +// return UPDATE_CONSOLE_DISPLAY; + return ConsoleUpdate(); +} + + +//=========================================================================== +Update_t _CmdMemorySearch (int nArgs, bool bTextIsAscii = true ) +{ + WORD nAddressStart = 0; + WORD nAddress2 = 0; + WORD nAddressEnd = 0; + int nAddressLen = 0; + + RangeType_t eRange; + eRange = Range_Get( nAddressStart, nAddress2 ); + +// if (eRange == RANGE_MISSING_ARG_2) + if (! Range_CalcEndLen( eRange, nAddressStart, nAddress2, nAddressEnd, nAddressLen)) + return ConsoleDisplayError( TEXT("Error: Missing address seperator (comma or colon)" ) ); + + int iArgFirstByte = 4; + + // S start,len # + int nMinLen = nArgs - (iArgFirstByte - 1); + + bool bHaveWildCards = false; + int iArg; + + MemorySearchValues_t vMemorySearchValues; + MemorySearch_e tLastType = MEM_SEARCH_BYTE_N_WILD; + + // Get search "string" + Arg_t *pArg = & g_aArgs[ iArgFirstByte ]; + + WORD nTarget; + for (iArg = iArgFirstByte; iArg <= nArgs; iArg++, pArg++ ) + { + MemorySearch_t ms; + + nTarget = pArg->nValue; + ms.m_nValue = nTarget & 0xFF; + ms.m_iType = MEM_SEARCH_BYTE_EXACT; + + if (nTarget > 0xFF) // searching for 16-bit address + { + vMemorySearchValues.push_back( ms ); + ms.m_nValue = (nTarget >> 8); + + tLastType = ms.m_iType; + } + else + { + TCHAR *pByte = pArg->sArg; + + if (pArg->bType & TYPE_QUOTED_1) + { + // Convert string to hex byte(s) + int iChar = 0; + int nChars = pArg->nArgLen; + + if (nChars) + { + ms.m_iType = MEM_SEARCH_BYTE_EXACT; + ms.m_bFound = false; + + while (iChar < nChars) + { + ms.m_nValue = pArg->sArg[ iChar ]; + + // Ascii (Low-Bit) + // Apple (High-Bit) +// if (! bTextIsAscii) // NOTE: Single quote chars is opposite hi-bit !!! +// ms.m_nValue &= 0x7F; +// else + ms.m_nValue |= 0x80; + + // last char is handle in common case below + iChar++; + if (iChar < nChars) + vMemorySearchValues.push_back( ms ); + } + } + } + else + if (pArg->bType & TYPE_QUOTED_2) + { + // Convert string to hex byte(s) + int iChar = 0; + int nChars = pArg->nArgLen; + + if (nChars) + { + ms.m_iType = MEM_SEARCH_BYTE_EXACT; + ms.m_bFound = false; + + while (iChar < nChars) + { + ms.m_nValue = pArg->sArg[ iChar ]; + + // Ascii (Low-Bit) + // Apple (High-Bit) +// if (bTextIsAscii) + ms.m_nValue &= 0x7F; +// else +// ms.m_nValue |= 0x80; + + iChar++; // last char is handle in common case below + if (iChar < nChars) + vMemorySearchValues.push_back( ms ); + } + } + } + else + { + // must be numeric .. make sure not too big + if (pArg->nArgLen > 2) + { + vMemorySearchValues.erase( vMemorySearchValues.begin(), vMemorySearchValues.end() ); + return HelpLastCommand(); + } + + if (pArg->nArgLen == 1) + { + if (pByte[0] == g_aParameters[ PARAM_MEM_SEARCH_WILD ].m_sName[0]) // Hack: hard-coded one char token + { + ms.m_iType = MEM_SEARCH_BYTE_1_WILD; + } + } + else + { + if (pByte[0] == g_aParameters[ PARAM_MEM_SEARCH_WILD ].m_sName[0]) // Hack: hard-coded one char token + { + ms.m_iType = MEM_SEARCH_NIB_LOW_EXACT; + ms.m_nValue = pArg->nValue & 0x0F; + } + + if (pByte[1] == g_aParameters[ PARAM_MEM_SEARCH_WILD ].m_sName[0]) // Hack: hard-coded one char token + { + if (ms.m_iType == MEM_SEARCH_NIB_LOW_EXACT) + { + ms.m_iType = MEM_SEARCH_BYTE_N_WILD; + } + else + { + ms.m_iType = MEM_SEARCH_NIB_HIGH_EXACT; + ms.m_nValue = (pArg->nValue << 4) & 0xF0; + } + } + } + } + } + + // skip over multiple byte_wild, since they are redundent + // xx ?? ?? xx + // ^ + // redundant + if ((tLastType == MEM_SEARCH_BYTE_N_WILD) && (ms.m_iType == MEM_SEARCH_BYTE_N_WILD)) + continue; + + vMemorySearchValues.push_back( ms ); + tLastType = ms.m_iType; + } + + _SearchMemoryFind( vMemorySearchValues, nAddressStart, nAddressEnd ); + vMemorySearchValues.erase( vMemorySearchValues.begin(), vMemorySearchValues.end() ); + + return _SearchMemoryDisplay(); +} + + +//=========================================================================== +Update_t CmdMemorySearch (int nArgs) +{ + // S address,length # [,#] + if (nArgs < 4) + return HelpLastCommand(); + + return _CmdMemorySearch( nArgs, true ); + + return UPDATE_CONSOLE_DISPLAY; +} + + +// Search for ASCII text (no Hi-Bit set) +//=========================================================================== +Update_t CmdMemorySearchAscii (int nArgs) +{ + if (nArgs < 4) + return HelpLastCommand(); + + return _CmdMemorySearch( nArgs, true ); +} + +// Search for Apple text (Hi-Bit set) +//=========================================================================== +Update_t CmdMemorySearchApple (int nArgs) +{ + if (nArgs < 4) + return HelpLastCommand(); + + return _CmdMemorySearch( nArgs, false ); +} + +//=========================================================================== +Update_t CmdMemorySearchHex (int nArgs) +{ + if (nArgs < 4) + return HelpLastCommand(); + + return _CmdMemorySearch( nArgs, true ); +} + + +// Registers ______________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdRegisterSet (int nArgs) +{ + if ((nArgs == 2) && + (g_aArgs[1].sArg[0] == TEXT('P')) && (g_aArgs[2].sArg[0] == TEXT('L'))) //HACK: TODO/FIXME: undocumented hard-coded command?!?! + { + regs.pc = lastpc; + } + else + if (nArgs < 2) // || ((g_aArgs[2].sArg[0] != TEXT('0')) && !g_aArgs[2].nValue)) + { + return Help_Arg_1( CMD_REGISTER_SET ); + } + else + { + TCHAR *pName = g_aArgs[1].sArg; + int iParam; + if (FindParam( pName, MATCH_EXACT, iParam, _PARAM_REGS_BEGIN, _PARAM_REGS_END )) + { + int iArg = 2; + if (g_aArgs[ iArg ].eToken == TOKEN_EQUAL) + iArg++; + + if (iArg > nArgs) + return Help_Arg_1( CMD_REGISTER_SET ); + + BYTE b = (BYTE)(g_aArgs[ iArg ].nValue & 0xFF); + WORD w = (WORD)(g_aArgs[ iArg ].nValue & 0xFFFF); + + switch (iParam) + { + case PARAM_REG_A : regs.a = b; break; + case PARAM_REG_PC: regs.pc = w; g_nDisasmCurAddress = regs.pc; DisasmCalcTopBotAddress(); break; + case PARAM_REG_SP: regs.sp = b | 0x100; break; + case PARAM_REG_X : regs.x = b; break; + case PARAM_REG_Y : regs.y = b; break; + default: return Help_Arg_1( CMD_REGISTER_SET ); + } + } + } + +// g_nDisasmCurAddress = regs.pc; +// DisasmCalcTopBotAddress(); + + return UPDATE_ALL; // 1 +} + + +// Output _________________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdOutputCalc (int nArgs) +{ + const int nBits = 8; + + if (! nArgs) + return Help_Arg_1( CMD_OUTPUT_CALC ); + + WORD nAddress = g_aArgs[1].nValue; + TCHAR sText [ CONSOLE_WIDTH ]; + + bool bHi = false; + bool bLo = false; + char c = FormatChar4Font( (BYTE) nAddress, &bHi, &bLo ); + bool bParen = bHi || bLo; + + int nBit = 0; + int iBit = 0; + for( iBit = 0; iBit < nBits; iBit++ ) + { + bool bSet = (nAddress >> iBit) & 1; + if (bSet) + nBit |= (1 << (iBit * 4)); // 4 bits per hex digit + } + + wsprintf( sText, TEXT("$%04X 0z%08X %5d '%c' "), + nAddress, nBit, nAddress, c ); + + if (bParen) + _tcscat( sText, TEXT("(") ); + + if (bHi & bLo) + _tcscat( sText, TEXT("High Ctrl") ); + else + if (bHi) + _tcscat( sText, TEXT("High") ); + else + if (bLo) + _tcscat( sText, TEXT("Ctrl") ); + + if (bParen) + _tcscat( sText, TEXT(")") ); + + ConsoleBufferPush( sText ); + return ConsoleUpdate(); +} + + +//=========================================================================== +Update_t CmdOutputEcho (int nArgs) +{ + TCHAR sText[ CONSOLE_WIDTH ] = TEXT(""); + + if (g_aArgs[1].bType & TYPE_QUOTED_2) + { + ConsoleDisplayPush( g_aArgs[1].sArg ); + } + else + { + const char *pText = g_pConsoleFirstArg; // ConsoleInputPeek(); + if (pText) + { + ConsoleDisplayPush( pText ); + } + } + + return ConsoleUpdate(); +} + + +enum PrintState_e +{ PS_LITERAL + , PS_TYPE + , PS_ESCAPE + , PS_NEXT_ARG_BIN + , PS_NEXT_ARG_HEX + , PS_NEXT_ARG_DEC + , PS_NEXT_ARG_CHR +}; + +struct PrintFormat_t +{ + int nValue; + int eType; +}; + + +//=========================================================================== +Update_t CmdOutputPrint (int nArgs) +{ + // PRINT "A:",A," X:",X + // Removed: PRINT "A:%d",A," X: %d",X + TCHAR sText[ CONSOLE_WIDTH ] = TEXT(""); + int nLen = 0; + + int nValue; + + if (! nArgs) + goto _Help; + + int iArg; + for (iArg = 1; iArg <= nArgs; iArg++ ) + { + if (g_aArgs[ iArg ].bType & TYPE_QUOTED_2) + { + int iChar; + int nChar = _tcslen( g_aArgs[ iArg ].sArg ); + for( iChar = 0; iChar < nChar; iChar++ ) + { + TCHAR c = g_aArgs[ iArg ].sArg[ iChar ]; + sText[ nLen++ ] = c; + } + + iArg++; +// if (iArg > nArgs) +// goto _Help; + if (iArg <= nArgs) + if (g_aArgs[ iArg ].eToken != TOKEN_COMMA) + goto _Help; + } + else + { + nValue = g_aArgs[ iArg ].nValue; + sprintf( &sText[ nLen ], "%04X", nValue ); + + while (sText[ nLen ]) + nLen++; + + iArg++; + if (iArg <= nArgs) + if (g_aArgs[ iArg ].eToken != TOKEN_COMMA) + goto _Help; + } +#if 0 + sprintf( &sText[ nLen ], "%04X", nValue ); + sprintf( &sText[ nLen ], "%d", nValue ); + sprintf( &sText[ nLen ], "%c", nValue ); +#endif + } + + if (nLen) + ConsoleBufferPush( sText ); + + return ConsoleUpdate(); + +_Help: + return Help_Arg_1( CMD_OUTPUT_PRINT ); +} + + +//=========================================================================== +Update_t CmdOutputPrintf (int nArgs) +{ + // PRINTF "A:%d X:%d",A,X + // PRINTF "Hex:%x Dec:%d Bin:%z",A,A,A + + TCHAR sText[ CONSOLE_WIDTH ] = TEXT(""); + +// vector aValues; +// PrintFormat_t entry; + vector aValues; + Arg_t entry; + int iValue = 0; + int nValue = 0; + + if (! nArgs) + goto _Help; + + int nLen = 0; + + PrintState_e eThis = PS_LITERAL; +// PrintState_e eNext = PS_NEXT_ARG_HEX; // PS_LITERAL; + + int nWidth = 0; + + int iArg; + for (iArg = 1; iArg <= nArgs; iArg++ ) + { + if (g_aArgs[ iArg ].bType & TYPE_QUOTED_2) + continue; + else + if (g_aArgs[ iArg ].eToken == TOKEN_COMMA) + continue; + else + { +// entry.eType = PS_LITERAL; + entry.nValue = g_aArgs[ iArg ].nValue; + aValues.push_back( entry ); +// nValue = g_aArgs[ iArg ].nValue; +// aValues.push_back( nValue ); + } + } + const int nParamValues = (int) aValues.size(); + + for (iArg = 1; iArg <= nArgs; iArg++ ) + { + if (g_aArgs[ iArg ].bType & TYPE_QUOTED_2) + { + int iChar; + int nChar = _tcslen( g_aArgs[ iArg ].sArg ); + for( iChar = 0; iChar < nChar; iChar++ ) + { + TCHAR c = g_aArgs[ iArg ].sArg[ iChar ]; + switch ( eThis ) + { + case PS_LITERAL: + switch( c ) + { + case '\\': + eThis = PS_ESCAPE; + case '%': + eThis = PS_TYPE; + break; + default: + sText[ nLen++ ] = c; + break; + } + break; + case PS_ESCAPE: + switch( c ) + { + case 'n': + case 'r': + eThis = PS_LITERAL; + sText[ nLen++ ] = '\n'; + break; + } + break; + case PS_TYPE: + if (iValue >= nParamValues) + { + wsprintf( sText, TEXT("Error: Missing value arg: %d"), iValue + 1 ); + ConsoleBufferPush( sText ); + return ConsoleUpdate(); + } + switch( c ) + { + case 'X': + case 'x': // PS_NEXT_ARG_HEX + nValue = aValues[ iValue ].nValue; + sprintf( &sText[ nLen ], "%04X", nValue ); + iValue++; + break; + case 'D': + case 'd': // PS_NEXT_ARG_DEC + nValue = aValues[ iValue ].nValue; + sprintf( &sText[ nLen ], "%d", nValue ); + iValue++; + break; + break; + case 'Z': + case 'z': + { + nValue = aValues[ iValue ].nValue; + if (!nWidth) + nWidth = 8; + int nBits = nWidth; + while (nBits-- > 0) + { + if ((nValue >> nBits) & 1) + sText[ nLen++ ] = '1'; + else + sText[ nLen++ ] = '0'; + } + iValue++; + break; + } + case 'c': // PS_NEXT_ARG_CHR; + nValue = aValues[ iValue ].nValue; + sprintf( &sText[ nLen ], "%c", nValue ); + iValue++; + break; + case '%': + default: + sText[ nLen++ ] = c; + break; + } + while (sText[ nLen ]) + nLen++; + eThis = PS_LITERAL; + break; + default: + break; + } + } + } + else + if (g_aArgs[ iArg ].eToken == TOKEN_COMMA) + { + iArg++; + if (iArg > nArgs) + goto _Help; + } + else + goto _Help; + } + + if (nLen) + ConsoleBufferPush( sText ); + + return ConsoleUpdate(); + +_Help: + return Help_Arg_1( CMD_OUTPUT_PRINTF ); +} + + +//=========================================================================== +Update_t CmdOutputRun (int nArgs) +{ + if (! nArgs) + return Help_Arg_1( CMD_OUTPUT_RUN ); + + if (nArgs != 1) + return Help_Arg_1( CMD_OUTPUT_RUN ); + + // Read in script + // could be made global, to cache last run. + // Opens up the possibility of: + // CHEAT [ON | OFF] -> re-run script + // with conditional logic + // IF @ON .... + MemoryTextFile_t script; + + TCHAR * pFileName = g_aArgs[ 1 ].sArg; + + TCHAR sFileName[ MAX_PATH ]; + TCHAR sMiniFileName[ CONSOLE_WIDTH ]; + +// if (g_aArgs[1].bType & TYPE_QUOTED_2) + + _tcscpy( sMiniFileName, pFileName ); +// _tcscat( sMiniFileName, ".aws" ); // HACK: MAGIC STRING + + if (pFileName[0] == '\\' || pFileName[1] == ':') // NB. Any prefix quote has already been stripped + { + // Abs pathname + _tcscpy(sFileName, sMiniFileName); + } + else + { + // Rel pathname + _tcscpy(sFileName, g_sCurrentDir); + _tcscat(sFileName, sMiniFileName); + } + + if (script.Read( sFileName )) + { + int iLine = 0; + int nLine = script.GetNumLines(); + + Update_t bUpdateDisplay = UPDATE_NOTHING; + + for( int iLine = 0; iLine < nLine; iLine++ ) + { + script.GetLine( iLine, g_pConsoleInput, CONSOLE_WIDTH-2 ); + g_nConsoleInputChars = _tcslen( g_pConsoleInput ); + bUpdateDisplay |= DebuggerProcessCommand( false ); + } + } + else + { + char sText[ CONSOLE_WIDTH ]; + sprintf( sText, "%sCouldn't load filename: %s%s" + , CHC_ERROR + , CHC_STRING + , sFileName + ); + ConsolePrint( sText ); + } + + return ConsoleUpdate(); +} + + +// Source Level Debugging _________________________________________________________________________ + +//=========================================================================== +bool BufferAssemblyListing( char *pFileName ) +{ + bool bStatus = false; // true = loaded + + if (! pFileName) + return bStatus; + + g_AssemblerSourceBuffer.Reset(); + g_AssemblerSourceBuffer.Read( pFileName ); + + if (g_AssemblerSourceBuffer.GetNumLines()) + { + g_bSourceLevelDebugging = true; + bStatus = true; + } + + return bStatus; +} + + +//=========================================================================== +int FindSourceLine( WORD nAddress ) +{ + int iAddress = 0; + int iLine = 0; + int iSourceLine = NO_SOURCE_LINE; + +// iterate of +// probably should be sorted by address +// then can do binary search +// iSourceLine = g_aSourceDebug.find( nAddress ); +#if 0 // _DEBUG + { + TCHAR sText[ CONSOLE_WIDTH ]; + for (int i = 0; i < g_vSourceLines.size(); i++ ) + { + wsprintf( sText, "%d: %s\n", i, g_vSourceLines[ i ] ); + OutputDebugString( sText ); + } + } +#endif + + SourceAssembly_t::iterator iSource = g_aSourceDebug.begin(); + while (iSource != g_aSourceDebug.end() ) + { + iAddress = iSource->first; + iLine = iSource->second; + +#if 0 // _DEBUG + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, "%04X -> %d line\n", iAddress, iLine ); + OutputDebugString( sText ); +#endif + + if (iAddress == nAddress) + { + iSourceLine = iLine; + break; + } + + iSource++; + } + // not found + + return iSourceLine; +} + +//=========================================================================== +bool ParseAssemblyListing( bool bBytesToMemory, bool bAddSymbols ) +{ + bool bStatus = false; // true = loaded + + // Assembler source listing file: + // + // xxxx:_b1_[b2]_[b3]__n_[label]_[opcode]_[param] +// char sByte1[ 2 ]; +// char sByte2[ 2 ]; +// char sByte3[ 2 ]; +// char sLineN[ W ]; + char sName[ MAX_SYMBOLS_LEN ]; +// char sAsm [ W ]; +// char sParam[ W ]; + + const int MAX_LINE = 256; + char sLine[ MAX_LINE ]; + char sText[ MAX_LINE ]; +// char sLabel[ MAX_LINE ]; + + g_nSourceAssembleBytes = 0; + g_nSourceAssemblySymbols = 0; + + const DWORD INVALID_ADDRESS = _6502_MEM_END + 1; + + bool bPrevSymbol = false; + bool bFourBytes = false; + BYTE nByte4 = 0; + + int nLines = g_AssemblerSourceBuffer.GetNumLines(); + for( int iLine = 0; iLine < nLines; iLine++ ) + { + g_AssemblerSourceBuffer.GetLine( iLine, sText, MAX_LINE - 1 ); + + DWORD nAddress = INVALID_ADDRESS; + + _tcscpy( sLine, sText ); + char *p = sLine; + p = strstr( sLine, ":" ); + if (p) + { + *p = 0; + // sscanf( sLine, "%s %s %s %s %s %s %s %s", sAddr1, sByte1, sByte2, sByte3, sLineN, sLabel, sAsm, sParam ); + sscanf( sLine, "%X", &nAddress ); + + if (nAddress >= INVALID_ADDRESS) // || (sName[0] == 0) ) + continue; + + if (bBytesToMemory) + { + char *pEnd = p + 1; + char *pStart; + int iByte; + for (iByte = 0; iByte < 4; iByte++ ) // BUG: Some assemblers also put 4 bytes on a line + { + // xx xx xx + // ^ ^ + // | | + // | end + // start + pStart = pEnd + 1; + pEnd = const_cast( SkipUntilWhiteSpace( pStart )); + int nLen = (pEnd - pStart); + if (nLen != 2) + { + break; + } + *pEnd = 0; + if (TextIsHexByte( pStart )) + { + BYTE nByte = TextConvert2CharsToByte( pStart ); + *(mem + ((WORD)nAddress) + iByte ) = nByte; + } + } + g_nSourceAssembleBytes += iByte; + } + + g_aSourceDebug[ (WORD) nAddress ] = iLine; // g_nSourceAssemblyLines; + } + + _tcscpy( sLine, sText ); + if (bAddSymbols) + { + // Add user symbol: symbolname EQU $address + // or user symbol: address: symbolname DFB #bytes + char *pEQU = strstr( sLine, "EQU" ); // EQUal / EQUate + char *pDFB = strstr( sLine, "DFB" ); // DeFine Byte + char *pLabel = NULL; + + if (pEQU) + pLabel = pEQU; + if (pDFB) + pLabel = pDFB; + + if (pLabel) + { + char *pLabelEnd = pLabel - 1; + pLabelEnd = const_cast( SkipWhiteSpaceReverse( pLabelEnd, &sLine[ 0 ] )); + char * pLabelStart = NULL; // SkipWhiteSpaceReverse( pLabelEnd, &sLine[ 0 ] ); + if (pLabelEnd) + { + pLabelStart = const_cast( SkipUntilWhiteSpaceReverse( pLabelEnd, &sLine[ 0 ] )); + pLabelEnd++; + pLabelStart++; + + int nLen = pLabelEnd - pLabelStart; + nLen = MIN( nLen, MAX_SYMBOLS_LEN ); + strncpy( sName, pLabelStart, nLen ); + sName[ nLen ] = 0; + + char *pAddressEQU = strstr( pLabel, "$" ); + char *pAddressDFB = strstr( sLine, ":" ); // Get address from start of line + char *pAddress = NULL; + + if (pAddressEQU) + pAddress = pAddressEQU + 1; + if (pAddressDFB) + { + *pAddressDFB = 0; + pAddress = sLine; + } + + if (pAddress) + { + char *pAddressEnd; + nAddress = (DWORD) strtol( pAddress, &pAddressEnd, 16 ); + g_aSymbols[ SYMBOLS_SRC_2 ][ (WORD) nAddress] = sName; + g_nSourceAssemblySymbols++; + } + } + } + } + } // for + + bStatus = true; + + return bStatus; +} + + +//=========================================================================== +Update_t CmdSource (int nArgs) +{ + if (! nArgs) + { + g_bSourceLevelDebugging = false; + } + else + { + g_bSourceAddMemory = false; + g_bSourceAddSymbols = false; + + for( int iArg = 1; iArg <= nArgs; iArg++ ) + { + TCHAR *pFileName = g_aArgs[ iArg ].sArg; + + int iParam; + bool bFound = FindParam( pFileName, MATCH_EXACT, iParam, _PARAM_SOURCE_BEGIN, _PARAM_SOURCE_END ) > 0 ? true : false; + if (bFound && (iParam == PARAM_SRC_SYMBOLS)) + { + g_bSourceAddSymbols = true; + } + else + if (bFound && (iParam == PARAM_SRC_MEMORY)) + { + g_bSourceAddMemory = true; + } + else + { + TCHAR sFileName[MAX_PATH]; + _tcscpy(sFileName,g_sProgramDir); + _tcscat(sFileName, pFileName); + + const int MAX_MINI_FILENAME = 20; + TCHAR sMiniFileName[ MAX_MINI_FILENAME + 1 ]; + _tcsncpy( sMiniFileName, pFileName, MAX_MINI_FILENAME - 1 ); + sMiniFileName[ MAX_MINI_FILENAME ] = 0; + + + if (BufferAssemblyListing( sFileName )) + { + _tcscpy( g_aSourceFileName, pFileName ); + + if (! ParseAssemblyListing( g_bSourceAddMemory, g_bSourceAddSymbols )) + { + wsprintf( sFileName, "Couldn't load filename: %s", sMiniFileName ); + ConsoleBufferPush( sFileName ); + } + else + { + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sFileName, " Read: %d lines, %d symbols" + , g_AssemblerSourceBuffer.GetNumLines() // g_nSourceAssemblyLines + , g_nSourceAssemblySymbols ); + + if (g_nSourceAssembleBytes) + { + wsprintf( sText, ", %d bytes", g_nSourceAssembleBytes ); + _tcscat( sFileName, sText ); + } + ConsoleBufferPush( sFileName ); + } + } + else + { + wsprintf( sFileName, "Error reading: %s", sMiniFileName ); + ConsoleBufferPush( sFileName ); + } + } + } + return ConsoleUpdate(); + } + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdSync (int nArgs) +{ + // TODO + return UPDATE_CONSOLE_DISPLAY; +} + + +// Stack __________________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdStackPush (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdStackPop (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdStackPopPseudo (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; +} + + +// View ___________________________________________________________________________________________ + +// See: CmdWindowViewOutput (int nArgs) +enum ViewVideoPage_t +{ + VIEW_PAGE_X, // current page + VIEW_PAGE_1, + VIEW_PAGE_2 +}; + +Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ); + +Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ) +{ + g_VideoForceFullRedraw = true; + _Video_Dirty(); + switch( iPage ) + { + case VIEW_PAGE_X: _Video_SetupBanks( g_bVideoDisplayPage2 ); break; // Page Current + case VIEW_PAGE_1: _Video_SetupBanks( false ); break; // Page 1 + case VIEW_PAGE_2: _Video_SetupBanks( true ); break; // Page 2 ! + default: + break; + } + _Video_RedrawScreen( pfUpdate ); + g_bDebuggerViewingAppleOutput = true; + return UPDATE_NOTHING; // intentional +} + +// Text 40 + Update_t CmdViewOutput_Text4X (int nArgs) + { + return _ViewOutput( VIEW_PAGE_X, Update40ColCell ); + } + Update_t CmdViewOutput_Text41 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_1, Update40ColCell ); + } + Update_t CmdViewOutput_Text42 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_2, Update40ColCell ); + } +// Text 80 + Update_t CmdViewOutput_Text8X (int nArgs) + { + return _ViewOutput( VIEW_PAGE_X, Update80ColCell ); + } + Update_t CmdViewOutput_Text81 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_1, Update80ColCell ); + } + Update_t CmdViewOutput_Text82 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_2, Update80ColCell ); + } +// Lo-Res + Update_t CmdViewOutput_GRX (int nArgs) + { + return _ViewOutput( VIEW_PAGE_X, UpdateLoResCell ); + } + Update_t CmdViewOutput_GR1 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_1, UpdateLoResCell ); + } + Update_t CmdViewOutput_GR2 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_2, UpdateLoResCell ); + } +// Double Lo-Res + Update_t CmdViewOutput_DGRX (int nArgs) + { + return _ViewOutput( VIEW_PAGE_X, UpdateDLoResCell ); + } + Update_t CmdViewOutput_DGR1 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_1, UpdateDLoResCell ); + } + Update_t CmdViewOutput_DGR2 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_2, UpdateDLoResCell ); + } +// Hi-Res + Update_t CmdViewOutput_HGRX (int nArgs) + { + return _ViewOutput( VIEW_PAGE_X, UpdateHiResCell ); + } + Update_t CmdViewOutput_HGR1 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_1, UpdateHiResCell ); + } + Update_t CmdViewOutput_HGR2 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_2, UpdateHiResCell ); + } +// Double Hi-Res + Update_t CmdViewOutput_DHGRX (int nArgs) + { + return _ViewOutput( VIEW_PAGE_X, UpdateDHiResCell ); + } + Update_t CmdViewOutput_DHGR1 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_1, UpdateDHiResCell ); + } + Update_t CmdViewOutput_DHGR2 (int nArgs) + { + return _ViewOutput( VIEW_PAGE_2, UpdateDHiResCell ); + } + +// Watches ________________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdWatch (int nArgs) +{ + return CmdWatchAdd( nArgs ); +} + + +//=========================================================================== +Update_t CmdWatchAdd (int nArgs) +{ + // WA [adddress] + // WA # address + if (! nArgs) + { + return CmdWatchList( 0 ); + } + + int iArg = 1; + int iWatch = NO_6502_TARGET; + if (nArgs > 1) + { + iWatch = g_aArgs[ 1 ].nValue; + iArg++; + } + + bool bAdded = false; + for (; iArg <= nArgs; iArg++ ) + { + WORD nAddress = g_aArgs[iArg].nValue; + + // Make sure address isn't an IO address + if ((nAddress >= _6502_IO_BEGIN) && (nAddress <= _6502_IO_END)) + return ConsoleDisplayError(TEXT("You may not watch an I/O location.")); + + if (iWatch == NO_6502_TARGET) + { + iWatch = 0; + while ((iWatch < MAX_ZEROPAGE_POINTERS) && (g_aWatches[iWatch].bSet)) + { + iWatch++; + } + } + + if ((iWatch >= MAX_WATCHES) && !bAdded) + { + char sText[ CONSOLE_WIDTH ]; + sprintf( sText, "All watches are currently in use. (Max: %d)", MAX_WATCHES ); + ConsoleDisplayPush( sText ); + return ConsoleUpdate(); + } + + if ((iWatch < MAX_WATCHES) && (g_nWatches < MAX_WATCHES)) + { + g_aWatches[iWatch].bSet = true; + g_aWatches[iWatch].bEnabled = true; + g_aWatches[iWatch].nAddress = (WORD) nAddress; + bAdded = true; + g_nWatches++; + iWatch++; + } + } + + if (!bAdded) + goto _Help; + + return UPDATE_WATCH; + +_Help: + return Help_Arg_1( CMD_WATCH_ADD ); +} + +//=========================================================================== +Update_t CmdWatchClear (int nArgs) +{ + if (!g_nWatches) + return ConsoleDisplayError(TEXT("There are no watches defined.")); + + if (!nArgs) + return Help_Arg_1( CMD_WATCH_CLEAR ); + + _BWZ_ClearViaArgs( nArgs, g_aWatches, MAX_WATCHES, g_nWatches ); + +// if (! g_nWatches) +// { +// UpdateDisplay(UPDATE_BACKGROUND); // 1 +// return UPDATE_NOTHING; // 0 +// } + + return UPDATE_CONSOLE_DISPLAY | UPDATE_WATCH; // 1 +} + +//=========================================================================== +Update_t CmdWatchDisable (int nArgs) +{ + if (! g_nWatches) + return ConsoleDisplayError(TEXT("There are no watches defined.")); + + if (!nArgs) + return Help_Arg_1( CMD_WATCH_DISABLE ); + + _BWZ_EnableDisableViaArgs( nArgs, g_aWatches, MAX_WATCHES, false ); + + return UPDATE_WATCH; +} + +//=========================================================================== +Update_t CmdWatchEnable (int nArgs) +{ + if (! g_nWatches) + return ConsoleDisplayError(TEXT("There are no watches defined.")); + + if (!nArgs) + return Help_Arg_1( CMD_WATCH_ENABLE ); + + _BWZ_EnableDisableViaArgs( nArgs, g_aWatches, MAX_WATCHES, true ); + + return UPDATE_WATCH; +} + +//=========================================================================== +Update_t CmdWatchList (int nArgs) +{ + if (! g_nWatches) + { + TCHAR sText[ CONSOLE_WIDTH ]; + wsprintf( sText, TEXT(" There are no current watches. (Max: %d)"), MAX_WATCHES ); + ConsoleBufferPush( sText ); + } + else + { + _BWZ_List( g_aWatches, MAX_WATCHES ); + } + return ConsoleUpdate(); +} + +/* +//=========================================================================== +Update_t CmdWatchLoad (int nArgs) +{ + if (!nArgs) + return Help_Arg_1( CMD_WATCH_LOAD ); + + return UPDATE_CONSOLE_DISPLAY; +} +*/ + +//=========================================================================== +Update_t CmdWatchSave (int nArgs) +{ + if (!nArgs) + return Help_Arg_1( CMD_WATCH_SAVE ); + + return UPDATE_CONSOLE_DISPLAY; +} + + +// Window _________________________________________________________________________________________ + +//=========================================================================== +void _WindowJoin () +{ + g_aWindowConfig[ g_iWindowThis ].bSplit = false; +} + +//=========================================================================== +void _WindowSplit ( Window_e eNewBottomWindow ) +{ + g_aWindowConfig[ g_iWindowThis ].bSplit = true; + g_aWindowConfig[ g_iWindowThis ].eBot = eNewBottomWindow; +} + +//=========================================================================== +void _WindowLast () +{ + int eNew = g_iWindowLast; + g_iWindowLast = g_iWindowThis; + g_iWindowThis = eNew; +} + +//=========================================================================== +void _WindowSwitch( int eNewWindow ) +{ + g_iWindowLast = g_iWindowThis; + g_iWindowThis = eNewWindow; +} + +//=========================================================================== +Update_t _CmdWindowViewCommon ( int iNewWindow ) +{ + // Switching to same window, remove split + if (g_iWindowThis == iNewWindow) + { + g_aWindowConfig[ iNewWindow ].bSplit = false; + } + else + { + _WindowSwitch( iNewWindow ); + } + +// WindowUpdateConsoleDisplayedSize(); + WindowUpdateSizes(); + return UPDATE_ALL; +} + +//=========================================================================== +Update_t _CmdWindowViewFull ( int iNewWindow ) +{ + if (g_iWindowThis != iNewWindow) + { + g_aWindowConfig[ iNewWindow ].bSplit = false; + _WindowSwitch( iNewWindow ); + WindowUpdateConsoleDisplayedSize(); + } + return UPDATE_ALL; +} + +//=========================================================================== +void WindowUpdateConsoleDisplayedSize() +{ + g_nConsoleDisplayLines = MIN_DISPLAY_CONSOLE_LINES; +#if USE_APPLE_FONT + g_bConsoleFullWidth = true; + g_nConsoleDisplayWidth = CONSOLE_WIDTH - 1; + + if (g_iWindowThis == WINDOW_CONSOLE) + { + g_nConsoleDisplayLines = MAX_DISPLAY_LINES; + g_nConsoleDisplayWidth = CONSOLE_WIDTH - 1; + g_bConsoleFullWidth = true; + } +#else + g_nConsoleDisplayWidth = (CONSOLE_WIDTH / 2) + 10; + g_bConsoleFullWidth = false; + +// g_bConsoleFullWidth = false; +// g_nConsoleDisplayWidth = CONSOLE_WIDTH - 10; + + if (g_iWindowThis == WINDOW_CONSOLE) + { + g_nConsoleDisplayLines = MAX_DISPLAY_LINES; + g_nConsoleDisplayWidth = CONSOLE_WIDTH - 1; + g_bConsoleFullWidth = true; + } +#endif +} + +//=========================================================================== +int WindowGetHeight( int iWindow ) +{ +// if (iWindow == WINDOW_CODE) + return g_nDisasmWinHeight; +} + +//=========================================================================== +void WindowUpdateDisasmSize() +{ + if (g_aWindowConfig[ g_iWindowThis ].bSplit) + { + g_nDisasmWinHeight = (MAX_DISPLAY_LINES - g_nConsoleDisplayLines) / 2; + } + else + { + g_nDisasmWinHeight = MAX_DISPLAY_LINES - g_nConsoleDisplayLines; + } + g_nDisasmCurLine = MAX(0, (g_nDisasmWinHeight - 1) / 2); +#if _DEBUG +#endif +} + +//=========================================================================== +void WindowUpdateSizes() +{ + WindowUpdateDisasmSize(); + WindowUpdateConsoleDisplayedSize(); +} + + +//=========================================================================== +Update_t CmdWindowCycleNext( int nArgs ) +{ + g_iWindowThis++; + if (g_iWindowThis >= NUM_WINDOWS) + g_iWindowThis = 0; + + WindowUpdateSizes(); + + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdWindowCyclePrev( int nArgs ) +{ + g_iWindowThis--; + if (g_iWindowThis < 0) + g_iWindowThis = NUM_WINDOWS-1; + + WindowUpdateSizes(); + + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdWindowShowCode (int nArgs) +{ + if (g_iWindowThis == WINDOW_CODE) + { + g_aWindowConfig[ g_iWindowThis ].bSplit = false; + g_aWindowConfig[ g_iWindowThis ].eBot = WINDOW_CODE; // not really needed, but SAFE HEX ;-) + } + else + if (g_iWindowThis == WINDOW_DATA) + { + g_aWindowConfig[ g_iWindowThis ].bSplit = true; + g_aWindowConfig[ g_iWindowThis ].eBot = WINDOW_CODE; + } + + WindowUpdateSizes(); + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdWindowShowCode1 (int nArgs) +{ +/* + if ((g_iWindowThis == WINDOW_CODE) || (g_iWindowThis != WINDOW_CODE)) + { + g_aWindowConfig[ g_iWindowThis ].bSplit = true; + g_aWindowConfig[ g_iWindowThis ].eTop = WINDOW_CODE; + + Window_e eWindow = WINDOW_CODE; + if (g_iWindowThis == WINDOW_DATA) + eWindow = WINDOW_DATA; + + g_aWindowConfig[ g_iWindowThis ].eBot = eWindow; + return UPDATE_ALL; + } +*/ + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdWindowShowCode2 (int nArgs) +{ + if ((g_iWindowThis == WINDOW_CODE) || (g_iWindowThis == WINDOW_CODE)) + { + if (g_iWindowThis == WINDOW_CODE) + { + _WindowJoin(); + WindowUpdateDisasmSize(); + } + else + if (g_iWindowThis == WINDOW_DATA) + { + _WindowSplit( WINDOW_CODE ); + WindowUpdateDisasmSize(); + } + return UPDATE_DISASM; + + } + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdWindowShowData (int nArgs) +{ + if (g_iWindowThis == WINDOW_CODE) + { + g_aWindowConfig[ g_iWindowThis ].bSplit = true; + g_aWindowConfig[ g_iWindowThis ].eBot = WINDOW_DATA; + return UPDATE_ALL; + } + else + if (g_iWindowThis == WINDOW_DATA) + { + g_aWindowConfig[ g_iWindowThis ].bSplit = false; + g_aWindowConfig[ g_iWindowThis ].eBot = WINDOW_DATA; // not really needed, but SAFE HEX ;-) + return UPDATE_ALL; + } + + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdWindowShowData1 (int nArgs) +{ +/* + if (g_iWindowThis != PARAM_CODE_1) + { + g_iWindowLast = g_iWindowThis; + g_iWindowThis = PARAM_DATA_1; + return UPDATE_ALL; + } +*/ + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdWindowShowData2 (int nArgs) +{ + if ((g_iWindowThis == WINDOW_CODE) || (g_iWindowThis == WINDOW_CODE)) + { + if (g_iWindowThis == WINDOW_CODE) + { + _WindowJoin(); + } + else + if (g_iWindowThis == WINDOW_DATA) + { + _WindowSplit( WINDOW_DATA ); + } + return UPDATE_DISASM; + + } + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdWindowShowSource (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdWindowShowSource1 (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdWindowShowSource2 (int nArgs) +{ + _WindowSplit( WINDOW_SOURCE ); + WindowUpdateSizes(); + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t CmdWindowViewCode (int nArgs) +{ + return _CmdWindowViewCommon( WINDOW_CODE ); +} + +//=========================================================================== +Update_t CmdWindowViewConsole (int nArgs) +{ + return _CmdWindowViewFull( WINDOW_CONSOLE ); + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdWindowViewData (int nArgs) +{ + return _CmdWindowViewCommon( WINDOW_DATA ); +} + +//=========================================================================== +Update_t CmdWindowViewOutput (int nArgs) +{ + VideoRedrawScreen(); + g_bDebuggerViewingAppleOutput = true; + + return UPDATE_NOTHING; // intentional +} + +//=========================================================================== +Update_t CmdWindowViewSource (int nArgs) +{ + return _CmdWindowViewFull( WINDOW_CONSOLE ); + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdWindowViewSymbols (int nArgs) +{ + return _CmdWindowViewFull( WINDOW_CONSOLE ); + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdWindow (int nArgs) +{ + if (!nArgs) + return Help_Arg_1( CMD_WINDOW ); + + int iParam; + TCHAR *pName = g_aArgs[1].sArg; + int nFound = FindParam( pName, MATCH_EXACT, iParam, _PARAM_WINDOW_BEGIN, _PARAM_WINDOW_END ); + if (nFound) + { + switch (iParam) + { + case PARAM_CODE : return CmdWindowViewCode(0) ; break; + case PARAM_CONSOLE: return CmdWindowViewConsole(0); break; + case PARAM_DATA : return CmdWindowViewData(0) ; break; +// case PARAM_INFO : CmdWindowInfo(); break; + case PARAM_SOURCE : return CmdWindowViewSource(0) ; break; + case PARAM_SYMBOLS: return CmdWindowViewSymbols(0); break; + default: + return Help_Arg_1( CMD_WINDOW ); + break; + } + } + + WindowUpdateConsoleDisplayedSize(); + + return UPDATE_ALL; +} + +//=========================================================================== +Update_t CmdWindowLast (int nArgs) +{ + _WindowLast(); + WindowUpdateConsoleDisplayedSize(); + return UPDATE_ALL; +} + +// ZeroPage _______________________________________________________________________________________ + + +//=========================================================================== +Update_t CmdZeroPage (int nArgs) +{ + // ZP [address] + // ZP # address + return CmdZeroPageAdd( nArgs ); +} + +//=========================================================================== +Update_t CmdZeroPageAdd (int nArgs) +{ + // ZP [address] + // ZP # address [address...] + if (! nArgs) + { + return CmdZeroPageList( 0 ); + } + + int iArg = 1; + int iZP = NO_6502_TARGET; + + if (nArgs > 1) + { + iZP = g_aArgs[ 1 ].nValue; + iArg++; + } + + bool bAdded = false; + for (; iArg <= nArgs; iArg++ ) + { + WORD nAddress = g_aArgs[iArg].nValue; + + if (iZP == NO_6502_TARGET) + { + iZP = 0; + while ((iZP < MAX_ZEROPAGE_POINTERS) && (g_aZeroPagePointers[iZP].bSet)) + { + iZP++; + } + } + + if ((iZP >= MAX_ZEROPAGE_POINTERS) && !bAdded) + { + char sText[ CONSOLE_WIDTH ]; + sprintf( sText, "All zero page pointers are currently in use. (Max: %d)", MAX_ZEROPAGE_POINTERS ); + ConsoleDisplayPush( sText ); + return ConsoleUpdate(); + } + + if ((iZP < MAX_ZEROPAGE_POINTERS) && (g_nZeroPagePointers < MAX_ZEROPAGE_POINTERS)) + { + g_aZeroPagePointers[iZP].bSet = true; + g_aZeroPagePointers[iZP].bEnabled = true; + g_aZeroPagePointers[iZP].nAddress = (BYTE) nAddress; + bAdded = true; + g_nZeroPagePointers++; + iZP++; + } + } + + if (!bAdded) + goto _Help; + + return UPDATE_ZERO_PAGE | ConsoleUpdate(); + +_Help: + return Help_Arg_1( CMD_ZEROPAGE_POINTER_ADD ); + +} + +Update_t _ZeroPage_Error() +{ +// return ConsoleDisplayError( "There are no (ZP) pointers defined." ); + char sText[ CONSOLE_WIDTH ]; + sprintf( sText, " There are no current (ZP) pointers. (Max: %d)", MAX_ZEROPAGE_POINTERS ); +// ConsoleBufferPush( sText ); + return ConsoleDisplayError( sText ); +} + +//=========================================================================== +Update_t CmdZeroPageClear (int nArgs) +{ + if (!g_nBreakpoints) + return _ZeroPage_Error(); + + // CHECK FOR ERRORS + if (!nArgs) + return Help_Arg_1( CMD_ZEROPAGE_POINTER_CLEAR ); + + _BWZ_ClearViaArgs( nArgs, g_aZeroPagePointers, MAX_ZEROPAGE_POINTERS, g_nZeroPagePointers ); + + if (! g_nZeroPagePointers) + { + UpdateDisplay( UPDATE_BACKGROUND ); + return UPDATE_CONSOLE_DISPLAY; + } + + return UPDATE_CONSOLE_DISPLAY | UPDATE_ZERO_PAGE; +} + +//=========================================================================== +Update_t CmdZeroPageDisable (int nArgs) +{ + if (!nArgs) + return Help_Arg_1( CMD_ZEROPAGE_POINTER_DISABLE ); + if (! g_nZeroPagePointers) + return _ZeroPage_Error(); + + _BWZ_EnableDisableViaArgs( nArgs, g_aZeroPagePointers, MAX_ZEROPAGE_POINTERS, false ); + + return UPDATE_ZERO_PAGE; +} + +//=========================================================================== +Update_t CmdZeroPageEnable (int nArgs) +{ + if (! g_nZeroPagePointers) + return _ZeroPage_Error(); + + if (!nArgs) + return Help_Arg_1( CMD_ZEROPAGE_POINTER_ENABLE ); + + _BWZ_EnableDisableViaArgs( nArgs, g_aZeroPagePointers, MAX_ZEROPAGE_POINTERS, true ); + + return UPDATE_ZERO_PAGE; +} + +//=========================================================================== +Update_t CmdZeroPageList (int nArgs) +{ + if (! g_nZeroPagePointers) + { + _ZeroPage_Error(); + } + else + { + _BWZ_ListAll( g_aZeroPagePointers, MAX_ZEROPAGE_POINTERS ); + } + return ConsoleUpdate(); +} + +/* +//=========================================================================== +Update_t CmdZeroPageLoad (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; + +} +*/ + +//=========================================================================== +Update_t CmdZeroPageSave (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdZeroPagePointer (int nArgs) +{ + // p[0..4] : disable + // p[0..4] : enable + + if( (nArgs != 0) && (nArgs != 1) ) + return Help_Arg_1( g_iCommand ); +// return DisplayHelp(CmdZeroPagePointer); + +// int nPtrNum = g_aArgs[0].sArg[1] - '0'; // HACK: hard-coded to command length + int iZP = g_iCommand - CMD_ZEROPAGE_POINTER_0; + + if( (iZP < 0) || (iZP > MAX_ZEROPAGE_POINTERS) ) + return Help_Arg_1( g_iCommand ); + + if (nArgs == 0) + { + g_aZeroPagePointers[iZP].bEnabled = false; + } + else + { + g_aZeroPagePointers[iZP].bSet = true; + g_aZeroPagePointers[iZP].bEnabled = true; + + WORD nAddress = g_aArgs[1].nValue; + g_aZeroPagePointers[iZP].nAddress = (BYTE) nAddress; + } + + return UPDATE_ZERO_PAGE; +} + + +// Command Input __________________________________________________________________________________ + + +// Note: Range is [iParamBegin,iParamEnd], not the usually (STL) expected [iParamBegin,iParamEnd) +//=========================================================================== +int FindParam( LPTSTR pLookupName, Match_e eMatch, int & iParam_, int iParamBegin, int iParamEnd ) +{ + int nFound = 0; + int nLen = _tcslen( pLookupName ); + int iParam = 0; + + if (! nLen) + return nFound; + +#if ALLOW_INPUT_LOWERCASE + eMatch = MATCH_FUZZY; +#endif + + if (eMatch == MATCH_EXACT) + { +// while (iParam < NUM_PARAMS ) + for (iParam = iParamBegin; iParam <= iParamEnd; iParam++ ) + { + TCHAR *pParamName = g_aParameters[iParam].m_sName; + int eCompare = _tcsicmp(pLookupName, pParamName); + if (! eCompare) // exact match? + { + nFound++; + iParam_ = g_aParameters[iParam].iCommand; + break; + } + } + } + else + if (eMatch == MATCH_FUZZY) + { +#if ALLOW_INPUT_LOWERCASE + TCHAR aLookup[ 256 ] = ""; + for( int i = 0; i < nLen; i++ ) + { + aLookup[ i ] = toupper( pLookupName[ i ] ); + } +#endif + for (iParam = iParamBegin; iParam <= iParamEnd; iParam++ ) + { + TCHAR *pParamName = g_aParameters[ iParam ].m_sName; +// _tcsnccmp + +#if ALLOW_INPUT_LOWERCASE + if (! _tcsncmp(aLookup, pParamName ,nLen)) +#else + if (! _tcsncmp(pLookupName, pParamName ,nLen)) +#endif + { + nFound++; + iParam_ = g_aParameters[iParam].iCommand; + + if (!_tcsicmp(pLookupName, pParamName)) // exact match? + { + nFound = 1; // Exact match takes precidence over fuzzy matches + break; + } + } + } + } + return nFound; +} + +//=========================================================================== +int FindCommand( LPTSTR pName, CmdFuncPtr_t & pFunction_, int * iCommand_ ) +{ + g_vPotentialCommands.erase( g_vPotentialCommands.begin(), g_vPotentialCommands.end() ); + + int nFound = 0; + int nLen = _tcslen( pName ); + int iCommand = 0; + + if (! nLen) + return nFound; + + char sCommand[ CONSOLE_WIDTH ]; + strcpy( sCommand, pName ); + _strupr( sCommand ); + + while ((iCommand < NUM_COMMANDS_WITH_ALIASES)) // && (name[0] >= g_aCommands[iCommand].aName[0])) Command no longer in Alphabetical order + { + TCHAR *pCommandName = g_aCommands[iCommand].m_sName; +// int iCmp = strcasecmp( sCommand, pCommandName, nLen ) + if (! _tcsncmp(sCommand, pCommandName, nLen)) + { + pFunction_ = g_aCommands[iCommand].pFunction; + if (pFunction_) + { + g_iCommand = g_aCommands[iCommand].iCommand; + + // Don't push the same comamnd/alias if already on the list + if (find( g_vPotentialCommands.begin(), g_vPotentialCommands.end(), g_iCommand) == g_vPotentialCommands.end()) + { + nFound++; + g_vPotentialCommands.push_back( g_iCommand ); + + if (iCommand_) + *iCommand_ = iCommand; +// !_tcscmp + if (!_tcsicmp(pName, pCommandName)) // exact match? + { + // if (iCommand_) + // *iCommand_ = iCommand; + + nFound = 1; // Exact match takes precidence over fuzzy matches + g_vPotentialCommands.erase( g_vPotentialCommands.begin(), g_vPotentialCommands.end() ); + break; + } + } + } + } + iCommand++; + } + +// if (nFound == 1) +// { +// +// } + + return nFound; +} + +//=========================================================================== +void DisplayAmbigiousCommands( int nFound ) +{ + char sText[ CONSOLE_WIDTH * 2 ]; + sprintf( sText, "Ambiguous %s%d%s Commands:" + , CHC_NUM_DEC + , g_vPotentialCommands.size() + , CHC_DEFAULT + ); + ConsolePrint( sText ); + + int iCommand = 0; + while (iCommand < nFound) + { + char sPotentialCommands[ CONSOLE_WIDTH ]; + sprintf( sPotentialCommands, "%s ", CHC_COMMAND ); + + int iWidth = strlen( sPotentialCommands ); + while ((iCommand < nFound) && (iWidth < g_nConsoleDisplayWidth)) + { + int nCommand = g_vPotentialCommands[ iCommand ]; + char *pName = g_aCommands[ nCommand ].m_sName; + int nLen = strlen( pName ); + + if ((iWidth + nLen) >= (CONSOLE_WIDTH - 1)) + break; + + sprintf( sText, "%s ", pName ); + strcat( sPotentialCommands, sText ); + iWidth += nLen + 1; + iCommand++; + } + ConsolePrint( sPotentialCommands ); + } +} + +bool IsHexDigit( char c ) +{ + if ((c >= '0') && (c <= '9')) + return true; + else + if ((c >= 'A') && (c <= 'F')) + return true; + else + if ((c >= 'a') && (c <= 'f')) + return true; + return false; +} + + +//=========================================================================== +Update_t ExecuteCommand (int nArgs) +{ + Arg_t * pArg = & g_aArgs[ 0 ]; + char * pCommand = & pArg->sArg[0]; + + CmdFuncPtr_t pFunction = NULL; + int nFound = FindCommand( pCommand, pFunction ); + +// int nCookMask = (1 << NUM_TOKENS) - 1; // ArgToken_e used as bit mask! + + + // BUGFIX: commands that are also valid hex addresses + // ####:# [#] + // #<#.#M + int nLen = pArg->nArgLen; + + if ((! nFound) || (nLen < 6)) + { + { + // verify pCommand[ 0 .. (nLen-1) ] are hex digits + bool bIsHex = true; + char *pChar = pCommand; + for (int iChar = 0; iChar < (nLen - 1); iChar++, pChar++ ) + { + bIsHex = IsHexDigit( *pChar ); + if( !bIsHex ) + { + break; + } + } + + if (bIsHex) + { + WORD nAddress = 0; + + // Support old AppleWin GO commands: + // . G -> GO + // . G #### -> GO until $address + // Support Apple Monitor commands: + // . ####G -> JMP $address (exit debugger) + if ((pCommand[nLen-1] == 'G') || + (pCommand[nLen-1] == 'g')) + { + if (nLen == 1) + { + if (nArgs) + { + const int iArg = 1; + ArgsGetValue( &g_aArgs[iArg], &g_aArgs[iArg].nValue ); + _CmdBreakpointAddCommonArg(iArg, nArgs, BP_SRC_REG_PC, BP_OP_EQUAL, true); + } + } + else if (nLen > 1) + { + pCommand[nLen-1] = 0; + ArgsGetValue( pArg, & nAddress ); + + regs.pc = nAddress; + } + + g_nAppMode = MODE_RUNNING; // exit the debugger + + nFound = 1; + g_iCommand = CMD_OUTPUT_ECHO; // hack: don't cook args + } + else + // ####L -> Unassemble $address + if ((pCommand[nLen-1] == 'L') || + (pCommand[nLen-1] == 'l')) + { + pCommand[nLen-1] = 0; + ArgsGetValue( pArg, & nAddress ); + + g_iCommand = CMD_UNASSEMBLE; + + // replace: addrL + // with: comamnd addr + pArg[1] = pArg[0]; + strcpy( pArg->sArg, g_aCommands[ g_iCommand ].m_sName ); + pArg->nArgLen = strlen( pArg->sArg ); + + pArg++; + pArg->nValue = nAddress; + nArgs++; + pFunction = g_aCommands[ g_iCommand ].pFunction; + nFound = 1; + } + else + // address: byte ... + if ((pArg+1)->eToken == TOKEN_COLON) + { + g_iCommand = CMD_MEMORY_ENTER_BYTE; + + // replace: addr : + // with: command addr + pArg[1] = pArg[0]; + + strcpy( pArg->sArg, g_aCommands[ g_iCommand ].m_sName ); + pArg->nArgLen = strlen( pArg->sArg ); + +// nCookMask &= ~ (1 << TOKEN_COLON); +// nArgs++; + + pFunction = g_aCommands[ g_iCommand ].pFunction; + nFound = 1; + } + else + // #<#.#M + if (pArg[1].eToken == TOKEN_LESS_THAN) + { + // Look for period + nLen = pArg[2].nArgLen; + + char *pDst = pArg[0].sArg; + char *pSrc = pArg[2].sArg; + char *pEnd = 0; + + bool bFoundSrc = false; + bool bFoundLen = false; + + pChar = pSrc; + while( *pChar ) + { + if( *pChar == '.' ) + { + if( pEnd ) // only allowed one period + { + pEnd = 0; + break; + } + + *pChar = 0; // ':'; + pEnd = pChar + 1; + bFoundSrc = true; + } else + if( !IsHexDigit( *pChar ) ) + { + break; + } + pChar++; + } + if( pEnd ) { + if( (*pChar == 'M') + || (*pChar == 'm')) + { + *pChar++ = 0; + if( ! *pChar ) + bFoundLen = true; + } + + if( bFoundSrc && bFoundLen ) + { +//ArgsGetValue( pArg, & nAddress ); +//char sText[ CONSOLE_WIDTH ]; +//sprintf( sText, "Dst:%s Src: %s End: %s", pDst, pSrc, pEnd ); +//ConsolePrint( sText ); + g_iCommand = CMD_MEMORY_MOVE; + pFunction = g_aCommands[ g_iCommand ].pFunction; + + strcpy( pArg[4].sArg, pEnd ); + strcpy( pArg[3].sArg, g_aTokens[ TOKEN_COLON ].sToken ); + strcpy( pArg[2].sArg, pSrc ); + strcpy( pArg[1].sArg, pDst ); + strcpy( pArg[0].sArg, g_aCommands[ g_iCommand ].m_sName ); + // pDst moved from arg0 to arg1 ! + pArg[1].bType = TYPE_VALUE; + pArg[2].bType = TYPE_VALUE; + pArg[3].bType = TYPE_OPERATOR; + pArg[4].bType = TYPE_VALUE; + + ArgsGetValue( &pArg[1], &pArg[1].nValue ); + ArgsGetValue( &pArg[2], &pArg[2].nValue ); + pArg[3].eToken = TOKEN_COLON; + ArgsGetValue( &pArg[4], &pArg[4].nValue ); + + nFound = 1; + nArgs = 4; + } + } + } + + // TODO: display memory at address + // addr1 [addr2] -> display byte at address + // MDB memory display byte (is deprecated, so can be re-used) + } + } + } + + if (nFound > 1) + { +// ASSERT (nFound == g_vPotentialCommands.size() ); + DisplayAmbigiousCommands( nFound ); + + return ConsoleUpdate(); +// return ConsoleDisplayError( gaPotentialCommands ); + } + + if (nFound) + { + bool bCook = true; + if (g_iCommand == CMD_OUTPUT_ECHO) + bCook = false; + + int nArgsCooked = nArgs; + if (bCook) + nArgsCooked = ArgsCook( nArgs ); // nCookMask + + if (nArgsCooked == ARG_SYNTAX_ERROR) + return ConsoleDisplayError( "Syntax Error" ); + + if (pFunction) + return pFunction( nArgsCooked ); // Eat them + + return UPDATE_CONSOLE_DISPLAY; + } + else + return ConsoleDisplayError( "Illegal Command" ); +} + + + +// ________________________________________________________________________________________________ + + +//=========================================================================== +bool InternalSingleStep () +{ + static DWORD dwCyclesThisFrame = 0; + + bool bResult = false; + _try + { + BYTE nOpcode = *(mem+regs.pc); + int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode; + + g_aProfileOpcodes[ nOpcode ].m_nCount++; + g_aProfileOpmodes[ nOpmode ].m_nCount++; + + DWORD dwExecutedCycles = CpuExecute(g_nDebugStepCycles); + dwCyclesThisFrame += dwExecutedCycles; + + if (dwCyclesThisFrame >= dwClksPerFrame) + { + dwCyclesThisFrame -= dwClksPerFrame; + } + VideoUpdateVbl( dwCyclesThisFrame ); + + bResult = true; + } + _except (EXCEPTION_EXECUTE_HANDLER) + { + bResult = false; + } + + return bResult; +} + + +//=========================================================================== +void OutputTraceLine () +{ + DisasmLine_t line; + GetDisassemblyLine( regs.pc, line ); + + char sDisassembly[ CONSOLE_WIDTH ]; // DrawDisassemblyLine( 0,regs.pc, sDisassembly); // Get Disasm String + FormatDisassemblyLine( line, sDisassembly, CONSOLE_WIDTH ); + + char sFlags[ _6502_NUM_FLAGS + 1 ]; DrawFlags( 0, regs.ps, sFlags ); // Get Flags String + + if (g_hTraceFile) + { + if (g_bTraceHeader) + { + g_bTraceHeader = false; + + fprintf( g_hTraceFile, +// "00 00 00 0000 -------- 0000:90 90 90 NOP" + "A: X: Y: SP: Flags Addr:Opcode Mnemonic\n" + ); + } + + char sTarget[ 16 ]; + if (line.bTargetValue) + { + sprintf( sTarget, "%s:%s" + , line.sTargetPointer + , line.sTargetValue + ); + } + + fprintf( g_hTraceFile, +// "a=%02x x=%02x y=%02x sp=%03x ps=%s %s\n", + "%02X %02X %02X %04X %s %s\n", + (unsigned)regs.a, + (unsigned)regs.x, + (unsigned)regs.y, + (unsigned)regs.sp, + (char*) sFlags + , sDisassembly + , sTarget + ); + } +} + +//=========================================================================== +int ParseInput ( LPTSTR pConsoleInput, bool bCook ) +{ + int nArg = 0; + + // TODO: need to check for non-quoted command seperator ';', and buffer input + RemoveWhiteSpaceReverse( pConsoleInput ); + + ArgsClear(); + nArg = ArgsGet( pConsoleInput ); // Get the Raw Args + + int iArg; + for( iArg = 0; iArg <= nArg; iArg++ ) + { + g_aArgs[ iArg ] = g_aArgRaw[ iArg ]; + } + + return nArg; +} + +//=========================================================================== +void ParseParameter( ) +{ +} + +// Return address of next line to write to. +//=========================================================================== +char * ProfileLinePeek ( int iLine ) +{ + char *pText = NULL; + + if (iLine < 0) + iLine = 0; + + if (! g_nProfileLine) + pText = & g_aProfileLine[ iLine ][ 0 ]; + + if (iLine <= g_nProfileLine) + pText = & g_aProfileLine[ iLine ][ 0 ]; + + return pText; +} + +//=========================================================================== +char * ProfileLinePush () +{ + if (g_nProfileLine < NUM_PROFILE_LINES) + { + g_nProfileLine++; + } + + return ProfileLinePeek( g_nProfileLine ); +} + +void ProfileLineReset() +{ + g_nProfileLine = 0; +} + + +#define DELIM "%s" +//=========================================================================== +void ProfileFormat( bool bExport, ProfileFormat_e eFormatMode ) +{ + char sSeperator7[ 32 ] = "\t"; + char sSeperator2[ 32 ] = "\t"; + char sSeperator1[ 32 ] = "\t"; + char sOpcode [ 8 ]; // 2 chars for opcode in hex, plus quotes on either side + char sAddress[MAX_OPMODE_NAME]; + + if (eFormatMode == PROFILE_FORMAT_COMMA) + { + sSeperator7[0] = ','; + sSeperator2[0] = ','; + sSeperator1[0] = ','; + } + else + if (eFormatMode == PROFILE_FORMAT_SPACE) + { + sprintf( sSeperator7, " " ); // 7 + sprintf( sSeperator2, " " ); // 2 + sprintf( sSeperator1, " " ); // 1 + } + + ProfileLineReset(); + char *pText = ProfileLinePeek( 0 ); + + int iOpcode; + int iOpmode; + + bool bOpcodeGood = true; + bool bOpmodeGood = true; + + vector< ProfileOpcode_t > vProfileOpcode( &g_aProfileOpcodes[0], &g_aProfileOpcodes[ NUM_OPCODES ] ); + vector< ProfileOpmode_t > vProfileOpmode( &g_aProfileOpmodes[0], &g_aProfileOpmodes[ NUM_OPMODES ] ); + + // sort > + sort( vProfileOpcode.begin(), vProfileOpcode.end(), ProfileOpcode_t() ); + sort( vProfileOpmode.begin(), vProfileOpmode.end(), ProfileOpmode_t() ); + + Profile_t nOpcodeTotal = 0; + Profile_t nOpmodeTotal = 0; + + for (iOpcode = 0; iOpcode < NUM_OPCODES; ++iOpcode ) + { + nOpcodeTotal += vProfileOpcode[ iOpcode ].m_nCount; + } + + for (iOpmode = 0; iOpmode < NUM_OPMODES; ++iOpmode ) + { + nOpmodeTotal += vProfileOpmode[ iOpmode ].m_nCount; + } + + if (nOpcodeTotal < 1.) + { + nOpcodeTotal = 1; + bOpcodeGood = false; + } + + char *pColorOperator = ""; + char *pColorNumber = ""; + char *pColorOpcode = ""; + char *pColorMnemonic = ""; + char *pColorOpmode = ""; + char *pColorTotal = ""; + if (! bExport) + { + pColorOperator = CHC_ARG_SEP; // grey + pColorNumber = CHC_NUM_DEC; // cyan + pColorOpcode = CHC_NUM_HEX; // yellow + pColorMnemonic = CHC_COMMAND; // green + pColorOpmode = CHC_USAGE ; // yellow + pColorTotal = CHC_DEFAULT; // white + } + +// Opcode + if (bExport) // Export = SeperateColumns + sprintf( pText + , "\"Percent\"" DELIM "\"Count\"" DELIM "\"Opcode\"" DELIM "\"Mnemonic\"" DELIM "\"Addressing Mode\"\n" + , sSeperator7, sSeperator2, sSeperator1, sSeperator1 ); + else + sprintf( pText + , "Percent" DELIM "Count" DELIM "Mnemonic" DELIM "Addressing Mode\n" + , sSeperator7, sSeperator2, sSeperator1 ); + + pText = ProfileLinePush(); + + for (iOpcode = 0; iOpcode < NUM_OPCODES; ++iOpcode ) + { + ProfileOpcode_t tProfileOpcode = vProfileOpcode.at( iOpcode ); + + Profile_t nCount = tProfileOpcode.m_nCount; + + // Don't spam with empty data if dumping to the console + if ((! nCount) && (! bExport)) + continue; + + int nOpcode = tProfileOpcode.m_iOpcode; + int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode; + double nPercent = (100. * nCount) / nOpcodeTotal; + + char sOpmode[ MAX_OPMODE_FORMAT ]; + sprintf( sOpmode, g_aOpmodes[ nOpmode ].m_sFormat, 0 ); + + if (bExport) + { + // Excel Bug: Quoted numbers are NOT treated as strings in .csv! WTF? + // @reference: http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q214233 + // + // Workaround: Prefix with (') apostrophe -- this doesn't break HEX2DEC() + // This works properly in Openoffice. + // In Excel, this ONLY works IF you TYPE it in! + // + // Solution: Quote the numbers, but you must select the "TEXT" Column data format for the "Opcode" column. + // We don't use .csv, since you aren't given the Import Dialog in Excel! + sprintf( sOpcode, "\"%02X\"", nOpcode ); // Works with Excel, IF using Import dialog & choose Text. (also works with OpenOffice) +// sprintf( sOpcode, "'%02X", nOpcode ); // SHOULD work with Excel, but only works with OpenOffice. + sprintf( sAddress, "\"%s\"", g_aOpmodes[ nOpmode ].m_sName ); + } + else // not qouted if dumping to console + { + sprintf( sOpcode, "%02X", nOpcode ); + strcpy( sAddress, g_aOpmodes[ nOpmode ].m_sName ); + } + + // BUG: Yeah 100% is off by 1 char. Profiling only one opcode isn't worth fixing this visual alignment bug. + sprintf( pText, + "%s%7.4f%s%%" DELIM "%s%9u" DELIM "%s%s" DELIM "%s%s" DELIM "%s%s\n" + , pColorNumber + , nPercent + , pColorOperator + , sSeperator2 + , pColorNumber + , static_cast(nCount), sSeperator2 + , pColorOpcode + , sOpcode, sSeperator2 + , pColorMnemonic + , g_aOpcodes[ nOpcode ].sMnemonic, sSeperator2 + , pColorOpmode + , sAddress + ); + pText = ProfileLinePush(); + } + + if (! bOpcodeGood) + nOpcodeTotal = 0; + + sprintf( pText + , "Total: " DELIM "%s%9u\n" + , sSeperator2 + , pColorTotal + , static_cast(nOpcodeTotal) ); + pText = ProfileLinePush(); + + sprintf( pText, "\n" ); + pText = ProfileLinePush(); + +// Opmode + // "Percent Count Adressing Mode\n" ); + if (bExport) + // Note: 2 extra dummy columns are inserted to keep Addressing Mode in same column + sprintf( pText + , "\"Percent\"" DELIM "\"Count\"" DELIM DELIM DELIM "\"Addressing Mode\"\n" + , sSeperator7, sSeperator2, sSeperator2, sSeperator2 ); + else + { + sprintf( pText + , "Percent" DELIM "Count" DELIM "Addressing Mode\n" + , sSeperator7, sSeperator2 ); + } + pText = ProfileLinePush(); + + if (nOpmodeTotal < 1) + { + nOpmodeTotal = 1.; + bOpmodeGood = false; + } + + for (iOpmode = 0; iOpmode < NUM_OPMODES; ++iOpmode ) + { + ProfileOpmode_t tProfileOpmode = vProfileOpmode.at( iOpmode ); + Profile_t nCount = tProfileOpmode.m_nCount; + + // Don't spam with empty data if dumping to the console + if ((! nCount) && (! bExport)) + continue; + + int nOpmode = tProfileOpmode.m_iOpmode; + double nPercent = (100. * nCount) / nOpmodeTotal; + + if (bExport) + { + // Note: 2 extra dummy columns are inserted to keep Addressing Mode in same column + sprintf( sAddress, "%s%s\"%s\"", sSeperator1, sSeperator1, g_aOpmodes[ nOpmode ].m_sName ); + } + else // not qouted if dumping to console + { + strcpy( sAddress, g_aOpmodes[ nOpmode ].m_sName ); + } + + // BUG: Yeah 100% is off by 1 char. Profiling only one opcode isn't worth fixing this visual alignment bug. + sprintf( pText + , "%s%7.4f%s%%" DELIM "%s%9u" DELIM "%s%s\n" + , pColorNumber + , nPercent + , pColorOperator + , sSeperator2 + , pColorNumber + , static_cast(nCount), sSeperator2 + , pColorOpmode + , sAddress + ); + pText = ProfileLinePush(); + } + + if (! bOpmodeGood) + nOpmodeTotal = 0; + + sprintf( pText + , "Total: " DELIM "%s%9u\n" + , sSeperator2 + , pColorTotal + , static_cast(nOpmodeTotal) ); + pText = ProfileLinePush(); + + sprintf( pText, "\n" ); + pText = ProfileLinePush(); +} +#undef DELIM + + +//=========================================================================== +void ProfileReset() +{ + int iOpcode; + int iOpmode; + + for (iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ ) + { + g_aProfileOpcodes[ iOpcode ].m_iOpcode = iOpcode; + g_aProfileOpcodes[ iOpcode ].m_nCount = 0; + } + + for (iOpmode = 0; iOpmode < NUM_OPMODES; iOpmode++ ) + { + g_aProfileOpmodes[ iOpmode ].m_iOpmode = iOpmode; + g_aProfileOpmodes[ iOpmode ].m_nCount = 0; + } +} + + +//=========================================================================== +bool ProfileSave() +{ + bool bStatus = false; + + char sFilename[MAX_PATH]; + strcpy( sFilename, g_sProgramDir ); // TODO: Allow user to decide? + strcat( sFilename, g_FileNameProfile ); + + FILE *hFile = fopen( sFilename, "wt" ); + + if (hFile) + { + char *pText; + int nLine = g_nProfileLine; + int iLine; + + for( iLine = 0; iLine < nLine; iLine++ ) + { + pText = ProfileLinePeek( iLine ); + if ( pText ) + { + fputs( pText, hFile ); + } + } + + fclose( hFile ); + bStatus = true; + } + return bStatus; +} + + + +// _____________________________________________________________________________________ +// | | +// | Public Functions | +// | | +// |_____________________________________________________________________________________| + +//=========================================================================== +void DebugBegin () +{ + // This is called every time the emulator is reset. + // And everytime the debugger is entered. + + g_nAppMode = MODE_DEBUG; + FrameRefreshStatus(DRAW_TITLE); + + if (IS_APPLE2 || (g_Apple2Type == A2TYPE_APPLE2E)) + { + g_aOpcodes = & g_aOpcodes6502[ 0 ]; // Apple ][, ][+, //e + g_aOpmodes[ AM_2 ].m_nBytes = 1; + g_aOpmodes[ AM_3 ].m_nBytes = 1; + } + else + { + g_aOpcodes = & g_aOpcodes65C02[ 0 ]; // Enhanced Apple //e + g_aOpmodes[ AM_2 ].m_nBytes = 2; + g_aOpmodes[ AM_3 ].m_nBytes = 3; + } + + g_nDisasmCurAddress = regs.pc; + DisasmCalcTopBotAddress(); + + g_bDebuggerViewingAppleOutput = false; + + UpdateDisplay( UPDATE_ALL ); + +#if DEBUG_APPLE_FONT + int iFG = 7; + int iBG = 4; + +// DebuggerSetColorFG( aColors[ iFG ] ); +// DebuggerSetColorBG( aColors[ iBG ] ); + + int iChar = 0; + int x = 0; + int y = 0; + for (iChar = 0; iChar < 256; iChar++) + { + x = (iChar % 16); + y = (iChar / 16); + + iFG = (x >> 1); // (iChar % 8); + iBG = (y >> 1) & 7; // (iChar / 8) & 7; + DebuggerSetColorFG( aConsoleColors[ iFG ] ); + DebuggerSetColorBG( aConsoleColors[ iBG ] ); + + DebuggerPrintChar( x * (APPLE_FONT_WIDTH / 2), y * (APPLE_FONT_HEIGHT / 2), iChar ); + } +#endif +} + +//=========================================================================== +void DebugContinueStepping () +{ + static unsigned nStepsTaken = 0; + + if (g_nDebugSkipLen > 0) + { + if ((regs.pc >= g_nDebugSkipStart) && (regs.pc < (g_nDebugSkipStart + g_nDebugSkipLen))) + { + // Enter turbo debugger g_nAppMode -- UI not updated, etc. + g_nDebugSteps = -1; + g_nAppMode = MODE_STEPPING; + } + else + { + // Enter normal debugger g_nAppMode -- UI updated every instruction, etc. + g_nDebugSteps = 1; + g_nAppMode = MODE_STEPPING; + } + } + + if (g_nDebugSteps) + { + if (g_hTraceFile) + OutputTraceLine(); + lastpc = regs.pc; + + InternalSingleStep(); + + bool bBreak = CheckBreakpointsIO(); + + if (CheckBreakpointsReg()) + bBreak = true; + + if ((regs.pc == g_nDebugStepUntil) || bBreak) + g_nDebugSteps = 0; + else if (g_nDebugSteps > 0) + g_nDebugSteps--; + } + + if (g_nDebugSteps) + { + if (!((++nStepsTaken) & 0xFFFF)) + { + if (nStepsTaken == 0x10000) + VideoRedrawScreen(); + else + VideoRefreshScreen(); + } + } + else + { + g_nAppMode = MODE_DEBUG; + FrameRefreshStatus(DRAW_TITLE); +// BUG: PageUp, Trace - doesn't center cursor + +// if ((g_nDebugStepStart < regs.pc) && (g_nDebugStepStart+3 >= regs.pc)) + // Still within current disasm "window"? +/* + if ((regs.pc >= g_nDisasmTopAddress) && (regs.pc <= g_nDisasmBotAddress)) + { + int eMode = g_aOpcodes[*(mem+g_nDisasmCurAddress)].addrmode; + int nBytes = g_aOpmodes[ eMode ]._nBytes; + g_nDisasmCurAddress += nBytes; +// g_nDisasmTopAddress += nBytes; +// g_nDisasmBotAddress += nBytes; + } + else +*/ + { + g_nDisasmCurAddress = regs.pc; + } + + DisasmCalcTopBotAddress(); + +// g_nDisasmCurAddress += g_aOpmodes[g_aOpcodes[*(mem+g_nDisasmCurAddress)].addrmode]._nBytes; +// DisasmCalcTopBotAddress(); + + Update_t bUpdate = UPDATE_ALL; +// if (nStepsTaken >= 0x10000) // HACK_MAGIC_NUM +// bUpdate = UPDATE_ALL; + + UpdateDisplay( bUpdate ); // nStepsTaken >= 0x10000); + nStepsTaken = 0; + } +} + +//=========================================================================== +void DebugDestroy () +{ + DebugEnd(); + + for (int iFont = 0; iFont < NUM_FONTS; iFont++ ) + { + DeleteObject( g_aFontConfig[ iFont ]._hFont ); + g_aFontConfig[ iFont ]._hFont = NULL; + } +// DeleteObject(g_hFontDisasm ); +// DeleteObject(g_hFontDebugger); +// DeleteObject(g_hFontWebDings); + + // TODO: Symbols_Clear() + for( int iTable = 0; iTable < NUM_SYMBOL_TABLES; iTable++ ) + { + _CmdSymbolsClear( (SymbolTable_Index_e) iTable ); + } + // TODO: DataDisassembly_Clear() + + SelectObject( g_hFrameDC, GetStockObject(NULL_BRUSH) ); + + DeleteObject( g_hConsoleBrushFG ); + DeleteObject( g_hConsoleBrushBG ); + + DeleteDC( g_hConsoleFontDC ); + DeleteObject( g_hConsoleFontBitmap ); + +// ReleaseDC( g_hFrameWindow, g_hFrameDC ); +} + + +//=========================================================================== +void DebugEnd () +{ + // Stepping ... calls us when key hit?! FrameWndProc() ProcessButtonClick() DebugEnd() + if (g_bProfiling) + { + // See: .csv / .txt note in CmdProfile() + ProfileFormat( true, PROFILE_FORMAT_TAB ); // Export in Excel-ready text format. + ProfileSave(); + } + + if (g_hTraceFile) + { + fclose(g_hTraceFile); + g_hTraceFile = NULL; + } + + g_vMemorySearchResults.erase( g_vMemorySearchResults.begin(), g_vMemorySearchResults.end() ); +} + + +#if _DEBUG +#define DEBUG_COLOR_RAMP 0 +//=========================================================================== +void _SetupColorRamp( const int iPrimary, int & iColor_ ) +{ + TCHAR sRamp[ CONSOLE_WIDTH*2 ] = TEXT(""); +#if DEBUG_COLOR_RAMP + TCHAR sText[ CONSOLE_WIDTH ]; +#endif + + bool bR = (iPrimary & 1) ? true : false; + bool bG = (iPrimary & 2) ? true : false; + bool bB = (iPrimary & 4) ? true : false; + int dStep = 32; + int nLevels = 256 / dStep; + for (int iLevel = nLevels; iLevel > 0; iLevel-- ) + { + int nC = ((iLevel * dStep) - 1); + int nR = bR ? nC : 0; + int nG = bG ? nC : 0; + int nB = bB ? nC : 0; + DWORD nColor = RGB(nR,nG,nB); + gaColorPalette[ iColor_ ] = nColor; +#if DEBUG_COLOR_RAMP + wsprintf( sText, TEXT("RGB(%3d,%3d,%3d), "), nR, nG, nB ); + _tcscat( sRamp, sText ); +#endif + iColor_++; + } +#if DEBUG_COLOR_RAMP + wsprintf( sText, TEXT(" // %d%d%d\n"), bB, bG, bR ); + _tcscat( sRamp, sText ); + OutputDebugString( sRamp ); + sRamp[0] = 0; +#endif +} +#endif // _DEBUG + +// Full Screen uses the palette from g_pFramebufferinfo +// BUT DebutInitialize() is called before VideoInitialize() +// THUS this is called post-initialize to set up the global palette +// +// pPalDst is the first color in the palette that we can stick our custom debug colors in +//=========================================================================== +void Debug_UpdatePalette( BYTE *pPalDst ) +{ + _ConfigColorsReset( pPalDst ); +} + +//=========================================================================== +void _ConfigColorsReset( BYTE *pPalDst ) +{ +// int iColor = 1; // black only has one level, skip it, since black levels same as white levels +// for (int iPrimary = 1; iPrimary < 8; iPrimary++ ) +// { +// _SetupColorRamp( iPrimary, iColor ); +// } + + BYTE *pDst = pPalDst; + + // Setup default colors + int iColor; + for (iColor = 0; iColor < NUM_DEBUG_COLORS; iColor++ ) + { + COLORREF nColor = gaColorPalette[ g_aColorIndex[ iColor ] ]; + + int R = (nColor >> 0) & 0xFF; + int G = (nColor >> 8) & 0xFF; + int B = (nColor >> 16) & 0xFF; + + if( pDst ) + { + *(pDst + 0) = B; + *(pDst + 1) = G; + *(pDst + 2) = R; + *(pDst + 3) = 0; + pDst += 4; + } + + // There are many, many ways of shifting the color domain to the monochrome domain + // NTSC uses 3x3 matrix, could map RGB -> wavelength, etc. + int M = (R + G + B) / 3; // Monochrome component + + int nThreshold = 64; + + int BW; + if (M < nThreshold) + BW = 0; + else + BW = 255; + + COLORREF nMono = RGB(M,M,M); + COLORREF nBW = RGB(BW,BW,BW); + + DebuggerSetColor( SCHEME_COLOR, iColor, nColor ); + DebuggerSetColor( SCHEME_MONO , iColor, nMono ); + DebuggerSetColor( SCHEME_BW , iColor, nBW ); + } +} + + +//=========================================================================== +void DebugInitialize () +{ + AssemblerOff(); // update prompt + +#if _DEBUG + DWORD nError = 0; +#endif + +// g_hDstDC = g_hFrameDC; //GetDC( g_hFrameWindow ); +#if _DEBUG + nError = GetLastError(); +#endif + + // Must select a bitmap into the temp DC ! + HDC hTmpDC = CreateCompatibleDC( g_hFrameDC ); + +#if _DEBUG + nError = GetLastError(); +#endif + + g_hConsoleFontDC = CreateCompatibleDC( g_hFrameDC ); +#if _DEBUG + nError = GetLastError(); +#endif + +#if APPLE_FONT_NEW + // Pre-scaled bitmap + g_hConsoleFontBitmap = LoadBitmap(g_hInstance,TEXT("IDB_DEBUG_FONT_7x8")); + SelectObject( g_hConsoleFontDC, g_hConsoleFontBitmap ); +#else + // Scale at run-time + + // Black = Transparent + // White = Opaque + HBITMAP hTmpBitamp = LoadBitmap(g_hInstance,TEXT("CHARSET40")); +#if _DEBUG + nError = GetLastError(); +#endif + + SelectObject( hTmpDC ,hTmpBitamp); +#if _DEBUG + nError = GetLastError(); +#endif + + g_hConsoleFontBrush = GetStockBrush( WHITE_BRUSH ); + SelectObject(g_hConsoleFontDC, g_hConsoleFontBrush ); + +// SelectObject(hTmpDC, g_hDebugFontBrush ); + +#if _DEBUG + nError = GetLastError(); +#endif + + g_hConsoleFontBitmap = CreateCompatibleBitmap( + hTmpDC, + APPLE_FONT_X_REGIONSIZE/2, APPLE_FONT_Y_REGIONSIZE/2 + ); +#if _DEBUG + nError = GetLastError(); +#endif + SelectObject( g_hConsoleFontDC, g_hConsoleFontBitmap ); + + StretchBlt( + g_hConsoleFontDC, // HDC hdcDest, // handle to destination DC + 0, 0, // int nXOriginDest, int nYOriginDest, // y-coord of destination upper-left corner + APPLE_FONT_X_REGIONSIZE/2, APPLE_FONT_Y_REGIONSIZE/2, // int nWidthDest, int nHeightDest, + hTmpDC, // HDC hdcSrc, // handle to source DC + 0, APPLE_FONT_Y_APPLE_80COL, // int nXOriginSrc, int nYOriginSrc, + APPLE_FONT_X_REGIONSIZE, APPLE_FONT_Y_REGIONSIZE, // int nWidthSrc, int nHeightSrc, + SRCCOPY // DWORD dwRop // raster operation code + ); + + DeleteObject( hTmpBitamp ); + DeleteObject( hTmpDC ); +#endif + +// DeleteDC( g_hFrameDC ); g_hDstDC = NULL; + + ZeroMemory( g_aConsoleDisplay, sizeof( g_aConsoleDisplay ) ); // CONSOLE_WIDTH * CONSOLE_HEIGHT ); + ConsoleInputReset(); + + for( int iWindow = 0; iWindow < NUM_WINDOWS; iWindow++ ) + { + WindowSplit_t *pWindow = & g_aWindowConfig[ iWindow ]; + + pWindow->bSplit = false; + pWindow->eTop = (Window_e) iWindow; + pWindow->eBot = (Window_e) iWindow; + } + + g_iWindowThis = WINDOW_CODE; + g_iWindowLast = WINDOW_CODE; + + WindowUpdateDisasmSize(); + + _ConfigColorsReset(); + + WindowUpdateConsoleDisplayedSize(); + + // CLEAR THE BREAKPOINT AND WATCH TABLES + ZeroMemory( g_aBreakpoints , MAX_BREAKPOINTS * sizeof(Breakpoint_t)); + ZeroMemory( g_aWatches , MAX_WATCHES * sizeof(Watches_t) ); + ZeroMemory( g_aZeroPagePointers, MAX_ZEROPAGE_POINTERS * sizeof(ZeroPagePointers_t)); + + // Load Main, Applesoft, and User Symbols + extern bool g_bSymbolsDisplayMissingFile; + g_bSymbolsDisplayMissingFile = false; + + g_iCommand = CMD_SYMBOLS_ROM; + CmdSymbolsLoad(0); + + g_iCommand = CMD_SYMBOLS_APPLESOFT; + CmdSymbolsLoad(0); + + // ,0x7,0xFF // Treat zero-page as data + // $00 GOWARM JSR ... + // $01 LOC1 DW + // $03 GOSTROUT JSR ... + // $07..$B0 + // $B1 CHRGET + // $C8 + // $C9 RNDSEED DW + // $D0..$FF + + g_iCommand = CMD_SYMBOLS_USER_1; + CmdSymbolsLoad(0); + + g_bSymbolsDisplayMissingFile = true; + +#if OLD_FONT + // CREATE A FONT FOR THE DEBUGGING SCREEN + int nArgs = _Arg_1( g_sFontNameDefault ); +#endif + + for (int iFont = 0; iFont < NUM_FONTS; iFont++ ) + { + g_aFontConfig[ iFont ]._hFont = NULL; +#if USE_APPLE_FONT + g_aFontConfig[ iFont ]._nFontHeight = CONSOLE_FONT_HEIGHT; + g_aFontConfig[ iFont ]._nFontWidthAvg = CONSOLE_FONT_WIDTH; + g_aFontConfig[ iFont ]._nFontWidthMax = CONSOLE_FONT_WIDTH; + g_aFontConfig[ iFont ]._nLineHeight = CONSOLE_FONT_HEIGHT; +#endif + } + +#if OLD_FONT + _CmdConfigFont( FONT_INFO , g_sFontNameInfo , FIXED_PITCH | FF_MODERN , g_nFontHeight ); // DEFAULT_CHARSET + _CmdConfigFont( FONT_CONSOLE , g_sFontNameConsole, FIXED_PITCH | FF_MODERN , g_nFontHeight ); // DEFAULT_CHARSET + _CmdConfigFont( FONT_DISASM_DEFAULT, g_sFontNameDisasm , FIXED_PITCH | FF_MODERN , g_nFontHeight ); // OEM_CHARSET + _CmdConfigFont( FONT_DISASM_BRANCH , g_sFontNameBranch , DEFAULT_PITCH | FF_DECORATIVE, g_nFontHeight+3); // DEFAULT_CHARSET +#endif + _UpdateWindowFontHeights( g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontHeight ); + + int iColor; + + iColor = FG_CONSOLE_OUTPUT; + COLORREF nColor = gaColorPalette[ g_aColorIndex[ iColor ] ]; + g_anConsoleColor[ CONSOLE_COLOR_x ] = nColor; + +/* + g_hFontDebugger = CreateFont( + g_nFontHeight // Height + , 0 // Width + , 0 // Escapement + , 0 // Orientatin + , FW_MEDIUM // Weight + , 0 // Italic + , 0 // Underline + , 0 // Strike Out + , DEFAULT_CHARSET // "OEM_CHARSET" DEFAULT_CHARSET + , OUT_DEFAULT_PRECIS + , CLIP_DEFAULT_PRECIS + , ANTIALIASED_QUALITY // DEFAULT_QUALITY + , FIXED_PITCH | FF_MODERN // HACK: MAGIC #: 4 // FIXED_PITCH + , g_sFontNameDefault ); + + g_hFontWebDings = CreateFont( + g_nFontHeight // Height + , 0 // Width + , 0 // Escapement + , 0 // Orientatin + , FW_MEDIUM // Weight + , 0 // Italic + , 0 // Underline + , 0 // Strike Out + , DEFAULT_CHARSET // ANSI_CHARSET // OEM_CHARSET DEFAULT_CHARSET + , OUT_DEFAULT_PRECIS + , CLIP_DEFAULT_PRECIS + , ANTIALIASED_QUALITY // DEFAULT_QUALITY + , DEFAULT_PITCH | FF_DECORATIVE // FIXED_PITCH | 4 | FF_MODERN + , g_sFontNameBranch ); +*/ +// if (g_hFontWebDings) +#if !USE_APPLE_FONT + if (g_aFontConfig[ FONT_DISASM_BRANCH ]._hFont) + { + g_iConfigDisasmBranchType = DISASM_BRANCH_FANCY; + } + else + { + g_iConfigDisasmBranchType = DISASM_BRANCH_PLAIN; + } +#endif + + // ConsoleInputReset(); already called in DebugInitialize() + TCHAR sText[ CONSOLE_WIDTH ]; + + if (_tcscmp( g_aCommands[ NUM_COMMANDS ].m_sName, TEXT(__COMMANDS_VERIFY_TXT__))) + { + wsprintf( sText, "*** ERROR *** Commands mis-matched!" ); + MessageBox( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); + PostQuitMessage( 1 ); + } + + if (_tcscmp( g_aParameters[ NUM_PARAMS ].m_sName, TEXT(__PARAMS_VERIFY_TXT__))) + { + wsprintf( sText, "*** ERROR *** Parameters mis-matched!" ); + MessageBox( g_hFrameWindow, sText, TEXT("ERROR"), MB_OK ); + PostQuitMessage( 2 ); + } + + // Check all summary help to see if it fits within the console + for (int iCmd = 0; iCmd < NUM_COMMANDS; iCmd++ ) + { + char *pHelp = g_aCommands[ iCmd ].pHelpSummary; + if (pHelp) + { + int nLen = _tcslen( pHelp ) + 2; + if (nLen > (CONSOLE_WIDTH-1)) + { + wsprintf( sText, TEXT("Warning: %s help is %d chars"), + pHelp, nLen ); + ConsoleBufferPush( sText ); + } + } + } + +#if _DEBUG +//g_bConsoleBufferPaused = true; +#endif + + _Bookmark_Reset(); + + CmdMOTD(0); +} + +// wparam = 0x16 +// lparam = 0x002f 0x0001 +// insert = VK_INSERT + +// Add character to the input line +//=========================================================================== +void DebuggerInputConsoleChar( TCHAR ch ) +{ + if ((g_nAppMode == MODE_STEPPING) && (ch == DEBUG_EXIT_KEY)) + { + g_nDebugSteps = 0; // Exit Debugger + ClearTempBreakpoints(); + } + + if (g_nAppMode != MODE_DEBUG) + return; + + if (g_bConsoleBufferPaused) + return; + + if (g_bIgnoreNextKey) + { + g_bIgnoreNextKey = false; + return; + } + + if (ch == CONSOLE_COLOR_ESCAPE_CHAR) + return; + + if (g_nConsoleInputSkip == ch) + return; + + if (ch == CHAR_SPACE) + { + // If don't have console input, don't pass space to the input line + // exception: pass to assembler + if ((! g_nConsoleInputChars) && (! g_bAssemblerInput)) + return; + } + + if (g_nConsoleInputChars > (g_nConsoleDisplayWidth-1)) + return; + + if ((ch >= CHAR_SPACE) && (ch <= 126)) // HACK MAGIC # 32 -> ' ', # 126 + { + if ((ch == TCHAR_QUOTE_DOUBLE) || (ch == TCHAR_QUOTE_SINGLE)) + g_bConsoleInputQuoted = ! g_bConsoleInputQuoted; + + if (!g_bConsoleInputQuoted) + { + // TODO: must fix param matching to ignore case +#if ALLOW_INPUT_LOWERCASE +#else + ch = (TCHAR)CharUpper((LPTSTR)ch); +#endif + } + ConsoleInputChar( ch ); + + DebuggerCursorNext(); + + FrameGetDC(); + DrawConsoleInput(); + FrameReleaseDC(); + } + else + if (ch == 0x16) // HACK: Ctrl-V. WTF!? + { + // Support Clipboard (paste) + if (!IsClipboardFormatAvailable(CF_TEXT)) + return; + + if (!OpenClipboard( g_hFrameWindow )) + return; + + HGLOBAL hClipboard; + LPTSTR pData; + + hClipboard = GetClipboardData(CF_TEXT); + if (hClipboard != NULL) + { + pData = (char*) GlobalLock(hClipboard); + if (pData != NULL) + { + LPTSTR pSrc = pData; + char c; + + while (true) + { + c = *pSrc++; + + if (! c) + break; + + if (c == CHAR_CR) + { +#if WIN32 + // Eat char +#endif +#if MACOSX + #pragma error( "TODO: Mac port - handle CR/LF") +#endif + } + else + if (c == CHAR_LF) + { +#if WIN32 + DebuggerProcessCommand( true ); +#endif +#if MACOSX + #pragma error( "TODO: Mac port - handle CR/LF") +#endif + } + else + { + // If we didn't want verbatim, we could do: + // DebuggerInputConsoleChar( c ); + if ((c >= CHAR_SPACE) && (c <= 126)) // HACK MAGIC # 32 -> ' ', # 126 + ConsoleInputChar( c ); + } + } + GlobalUnlock(hClipboard); + } + } + CloseClipboard(); + + UpdateDisplay( UPDATE_CONSOLE_DISPLAY ); + } +} + + +// Triggered when ENTER is pressed, or via script +//=========================================================================== +Update_t DebuggerProcessCommand ( const bool bEchoConsoleInput ) +{ + Update_t bUpdateDisplay = UPDATE_NOTHING; + + char sText[ CONSOLE_WIDTH ]; + + if (bEchoConsoleInput) + ConsoleDisplayPush( ConsoleInputPeek() ); + + if (g_bAssemblerInput) + { + if (g_nConsoleInputChars) + { + ParseInput( g_pConsoleInput, false ); // Don't cook the args + bUpdateDisplay |= _CmdAssemble( g_nAssemblerAddress, 0, g_nArgRaw ); + } + else + { + AssemblerOff(); + + int nDelayedTargets = AssemblerDelayedTargetsSize(); + if (nDelayedTargets) + { + sprintf( sText, " Asm: %d sym declared, not defined", nDelayedTargets ); + ConsoleDisplayPush( sText ); + bUpdateDisplay |= UPDATE_CONSOLE_DISPLAY; + } + } + ConsoleInputReset(); + bUpdateDisplay |= UPDATE_CONSOLE_DISPLAY | UPDATE_CONSOLE_INPUT; + ConsoleUpdate(); // udpate console, don't pause + } + else + if (g_nConsoleInputChars) + { + // BufferedInputPush( + // Handle Buffered Input + // while ( BufferedInputPeek() ) + int nArgs = ParseInput( g_pConsoleInput ); + if (nArgs == ARG_SYNTAX_ERROR) + { + sprintf( sText, "Syntax error: %s", g_aArgs[0].sArg ); + bUpdateDisplay |= ConsoleDisplayError( sText ); + } + else + { + bUpdateDisplay |= ExecuteCommand( nArgs ); // ParseInput()); + } + + if (!g_bConsoleBufferPaused) + { + ConsoleInputReset(); + } + } + + return bUpdateDisplay; +} + +void ToggleFullScreenConsole() +{ + // Switch to Console Window + if (g_iWindowThis != WINDOW_CONSOLE) + { + CmdWindowViewConsole( 0 ); + } + else // switch back to last window + { + CmdWindowLast( 0 ); + } +} + +//=========================================================================== +void DebuggerProcessKey( int keycode ) +//void DebugProcessCommand (int keycode) +{ + if (g_nAppMode != MODE_DEBUG) + return; + + if (g_bDebuggerViewingAppleOutput) + { + if ((VK_SHIFT == keycode) || (VK_CONTROL == keycode) || (VK_MENU == keycode)) + { + return; + } + + // Normally any key press takes us out of "Viewing Apple Output" g_nAppMode + // VK_F# are already processed, so we can't use them to cycle next video g_nAppMode +// if ((g_nAppMode != MODE_LOGO) && (g_nAppMode != MODE_DEBUG)) + g_bDebuggerViewingAppleOutput = false; + UpdateDisplay( UPDATE_ALL ); // 1 + return; + } + + Update_t bUpdateDisplay = UPDATE_NOTHING; + + // For long output, allow user to read it + if (g_nConsoleBuffer) + { + if ((VK_SPACE == keycode) || (VK_RETURN == keycode) || (VK_TAB == keycode) || (VK_ESCAPE == keycode)) + { + int nLines = MIN( g_nConsoleBuffer, g_nConsoleDisplayLines - 1 ); // was -2 + if (VK_ESCAPE == keycode) // user doesn't want to read all this stu + { + nLines = g_nConsoleBuffer; + } + ConsoleBufferTryUnpause( nLines ); + + // don't really need since 'else if (keycode = VK_BACK)' but better safe then sorry + keycode = 0; // don't single-step + } + + bUpdateDisplay |= UPDATE_CONSOLE_DISPLAY | UPDATE_CONSOLE_INPUT; + ConsoleDisplayPause(); + } + else + // If have console input, don't invoke curmovement + // TODO: Probably should disable all "movement" keys to map them to line editing g_nAppMode + if ((keycode == VK_SPACE) && g_nConsoleInputChars) + return; + else if (keycode == VK_ESCAPE) + { + g_bConsoleInputQuoted = false; + ConsoleInputReset(); + bUpdateDisplay |= UPDATE_CONSOLE_INPUT; + } + else if (keycode == VK_BACK) + { + // Note: Checks prev char if QUTOE - SINGLE or DOUBLE +// ConsoleUpdateCursor( CHAR_SPACE ); + if (! ConsoleInputBackSpace()) + { + // CmdBeep(); + } + bUpdateDisplay |= UPDATE_CONSOLE_INPUT; + } + else if (keycode == VK_RETURN) + { +// ConsoleUpdateCursor( 0 ); + + if (! g_nConsoleInputChars) + { + // bugfix: 2.6.1.35 Fixed: Pressing enter on blank line while in assembler wouldn't exit it. + if( g_bAssemblerInput ) + { + bUpdateDisplay |= DebuggerProcessCommand( false ); + } + else + { + ToggleFullScreenConsole(); + bUpdateDisplay |= UPDATE_ALL; + } + } + else + { + ConsoleScrollEnd(); + bUpdateDisplay |= DebuggerProcessCommand( true ); // copy console input to console output + + // BUGFIX: main disassembly listing doesn't get updated in full screen console + //bUpdateDisplay |= UPDATE_CONSOLE_DISPLAY; + bUpdateDisplay |= UPDATE_ALL; + } + } + else if (( keycode == VK_OEM_3 ) || // US: Tilde ~ (key to the immediate left of numeral 1) + ( keycode == VK_OEM_8 )) // UK: Logical NOT ¬ (key to the immediate left of numeral 1) + { + if (KeybGetCtrlStatus()) + { + ToggleFullScreenConsole(); + bUpdateDisplay |= UPDATE_ALL; + } + else + { + g_nConsoleInputSkip = 0; // VK_OEM_3; // don't pass to DebugProcessChar() + DebuggerInputConsoleChar( '~' ); + } + g_nConsoleInputSkip = '~'; // VK_OEM_3; // don't pass to DebugProcessChar() + } + else + { + switch (keycode) + { + case VK_TAB: + { + if (g_nConsoleInputChars) + { + // TODO: TabCompletionCommand() + // TODO: TabCompletionSymbol() + bUpdateDisplay |= ConsoleInputTabCompletion(); + } + else + if (KeybGetCtrlStatus() && KeybGetShiftStatus()) + bUpdateDisplay |= CmdWindowCyclePrev( 0 ); + else + if (KeybGetCtrlStatus()) + bUpdateDisplay |= CmdWindowCycleNext( 0 ); + else + bUpdateDisplay |= CmdCursorJumpPC( CURSOR_ALIGN_CENTER ); + break; + } + case VK_SPACE: + if (g_bAssemblerInput) + { +// if (g_nConsoleInputChars) +// { +// ParseInput( g_pConsoleInput, false ); // Don't cook the args +// bUpdateDisplay |= _CmdAssemble( g_nAssemblerAddress, 0, g_nArgRaw ); +// } + } + else + { + if (KeybGetShiftStatus()) + bUpdateDisplay |= CmdStepOut(0); + else + if (KeybGetCtrlStatus()) + bUpdateDisplay |= CmdStepOver(0); + else + bUpdateDisplay |= CmdTrace(0); + } + break; + + case VK_HOME: + if (g_iWindowThis == WINDOW_CONSOLE) + { + ConsoleScrollHome(); + } + else + if (g_nConsoleInputChars > 0) + { + if (KeybGetShiftStatus()) + { + bUpdateDisplay |= ConsoleScrollHome(); + } + else + { + // Move cursor to start of console input + } + } + else + { + // If you really want $000 at the top of the screen... + // g_nDisasmTopAddress = _6502_MEM_BEGIN; + // DisasmCalcCurFromTopAddress(); + // DisasmCalcBotFromTopAddress(); + + g_nDisasmCurAddress = _6502_MEM_BEGIN; + DisasmCalcTopBotAddress(); + } + bUpdateDisplay |= UPDATE_DISASM; + break; + + case VK_END: + if (g_iWindowThis == WINDOW_CONSOLE) + { + ConsoleScrollEnd(); + } + else + if (g_nConsoleInputChars > 0) + { + if (KeybGetShiftStatus()) + { + bUpdateDisplay |= ConsoleScrollEnd(); + } + else + { + // Move cursor to end of console input + } + } + else + { + // If you really want $8000 at the top of the screen... + // g_nDisasmTopAddress = (_6502_MEM_END / 2) + 1; + // DisasmCalcCurFromTopAddress(); + // DisasmCalcTopBotAddress(); + + g_nDisasmCurAddress = (_6502_MEM_END / 2) + 1; + DisasmCalcTopBotAddress(); + } + bUpdateDisplay |= UPDATE_DISASM; + break; + + case VK_PRIOR: // VK_PAGE_UP + if (g_iWindowThis == WINDOW_CONSOLE) + { + bUpdateDisplay |= ConsoleScrollPageUp(); + } + else + if (g_nConsoleInputChars > 0) + { + if (KeybGetShiftStatus()) + { + bUpdateDisplay |= ConsoleScrollPageUp(); + } + else + { + // Scroll through console input history + bUpdateDisplay |= ConsoleScrollUp( 3 ); + } + } + else + { + if (KeybGetShiftStatus()) + bUpdateDisplay |= CmdCursorPageUp256(0); + else + if (KeybGetCtrlStatus()) + bUpdateDisplay |= CmdCursorPageUp4K(0); + else + bUpdateDisplay |= CmdCursorPageUp(0); + } + break; + + case VK_NEXT: // VK_PAGE_DN + if (g_iWindowThis == WINDOW_CONSOLE) + { + bUpdateDisplay |= ConsoleScrollPageDn(); + } + else + if (g_nConsoleInputChars > 0) + { + if (KeybGetShiftStatus()) + { + bUpdateDisplay |= ConsoleScrollPageDn(); + } + else + { + // Scroll through console input history + bUpdateDisplay |= ConsoleScrollDn( 3 ); + } + } + else + { + if (KeybGetShiftStatus()) + bUpdateDisplay |= CmdCursorPageDown256(0); + else + if (KeybGetCtrlStatus()) + bUpdateDisplay |= CmdCursorPageDown4K(0); + else + bUpdateDisplay |= CmdCursorPageDown(0); + } + break; + + case VK_UP: + if (g_iWindowThis == WINDOW_CONSOLE) + { + bUpdateDisplay |= ConsoleScrollUp( 1 ); + } + else + if (g_nConsoleInputChars > 0) + { + if (KeybGetShiftStatus()) + { + bUpdateDisplay |= ConsoleScrollUp( 1 ); + } + else + { + // TODO: FIXME: Scroll through console input history + } + } + else + { + // Shift the Top offset up by 1 byte + // i.e. no smart disassembly like LineUp() + // Normally UP moves to the previous "line" which may be multiple bytes. + if (KeybGetShiftStatus()) + bUpdateDisplay |= CmdCursorLineUp(1); + else + bUpdateDisplay |= CmdCursorLineUp(0); // smart disassembly + } + break; + + case VK_DOWN: + if (g_iWindowThis == WINDOW_CONSOLE) + { + bUpdateDisplay |= ConsoleScrollDn( 1 ); + } + else + if (g_nConsoleInputChars > 0) + { + if (KeybGetShiftStatus()) + { + bUpdateDisplay |= ConsoleScrollDn( 1 ); + } + else + { + // TODO: FIXME: Scroll through console input history + } + } + else + { + if (KeybGetCtrlStatus()) + bUpdateDisplay |= CmdCursorRunUntil(0); + else + if (KeybGetShiftStatus()) + // Shift the Offest down by 1 byte + // i.e. no smart disassembly like LineDown() + bUpdateDisplay |= CmdCursorLineDown(1); + else + bUpdateDisplay |= CmdCursorLineDown(0); + } + break; + + case VK_RIGHT: + if (KeybGetCtrlStatus()) + bUpdateDisplay |= CmdCursorSetPC( g_nDisasmCurAddress ); + else + if (KeybGetShiftStatus()) + bUpdateDisplay |= CmdCursorJumpPC( CURSOR_ALIGN_TOP ); + else + if (KeybGetAltStatus()) + bUpdateDisplay |= CmdCursorJumpPC( CURSOR_ALIGN_CENTER ); + else + bUpdateDisplay |= CmdCursorFollowTarget( CURSOR_ALIGN_TOP ); + break; + + case VK_LEFT: + if (KeybGetShiftStatus()) + bUpdateDisplay |= CmdCursorJumpRetAddr( CURSOR_ALIGN_TOP ); // Jump to Caller + else + bUpdateDisplay |= CmdCursorJumpRetAddr( CURSOR_ALIGN_CENTER ); + break; + + default: + if ((keycode >= '0') && (keycode <= '9')) + { + int nArgs = 1; + int iBookmark = keycode - '0'; + if (KeybGetCtrlStatus() && KeybGetShiftStatus()) + { + nArgs = 2; + g_aArgs[ 1 ].nValue = iBookmark; + g_aArgs[ 2 ].nValue = g_nDisasmCurAddress; + bUpdateDisplay |= CmdBookmarkAdd( nArgs ); + g_bIgnoreNextKey = true; + } + else + if (KeybGetCtrlStatus()) + { + nArgs = 1; + g_aArgs[ 1 ].nValue = iBookmark; + bUpdateDisplay |= CmdBookmarkGoto( nArgs ); + g_bIgnoreNextKey = true; + } + } + + break; + } // switch + } + + if (bUpdateDisplay && !g_bDebuggerViewingAppleOutput) // & UPDATE_BACKGROUND) + UpdateDisplay( bUpdateDisplay ); +} + +// Still called from external file +void DebugDisplay( BOOL bDrawBackground ) +{ + Update_t bUpdateFlags = UPDATE_ALL; + +// if (! bDrawBackground) +// bUpdateFlags &= ~UPDATE_BACKGROUND; + + UpdateDisplay( bUpdateFlags ); +} + + +//=========================================================================== +void DebuggerUpdate() +{ + DebuggerCursorUpdate(); +} + + +//=========================================================================== +void DebuggerCursorUpdate() +{ + if (g_nAppMode != MODE_DEBUG) + return; + + const int nUpdatesPerSecond = 4; + const DWORD nUpdateInternal_ms = 1000 / nUpdatesPerSecond; + static DWORD nBeg = GetTickCount(); // timeGetTime(); + DWORD nNow = GetTickCount(); // timeGetTime(); + + if (((nNow - nBeg) >= nUpdateInternal_ms) && !g_bDebuggerViewingAppleOutput) + { + nBeg = nNow; + + DebuggerCursorNext(); + + FrameGetDC(); + DrawConsoleCursor(); + FrameReleaseDC(); + } + else + { + Sleep(10); // Stop process hogging CPU + } +} + + +//=========================================================================== +void DebuggerCursorNext() +{ + g_bInputCursor ^= true; + if (g_bInputCursor) + ConsoleUpdateCursor( g_aInputCursor[ g_iInputCursor ] ); + else + ConsoleUpdateCursor( 0 ); // show char under cursor +} + + +//=========================================================================== +//char DebuggerCursorGet() +//{ +// return g_aInputCursor[ g_iInputCursor ]; +//} + + +//=========================================================================== +void DebuggerMouseClick( int x, int y ) +{ + if (g_nAppMode != MODE_DEBUG) + return; + + int nFontWidth = g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontWidthAvg; + int nFontHeight = g_aFontConfig[ FONT_DISASM_DEFAULT ]._nLineHeight ; + + // do picking + FrameGetDC(); + + int cx = (x - VIEWPORTX) / nFontWidth; + int cy = (y - VIEWPORTY) / nFontHeight; + +#if _DEBUG + char sText[ CONSOLE_WIDTH ]; + sprintf( sText, "x:%d y:%d cx:%d cy:%d", x, y, cx, cy ); + ConsoleDisplayPush( sText ); + DebugDisplay( UPDATE_CONSOLE_DISPLAY ); +#endif + + if (g_iWindowThis == WINDOW_CODE) + { + // Display_AssemblyLine -- need Tabs + + if( g_bConfigDisasmAddressView ) + { + // HACK: hard-coded from DrawDisassemblyLine::aTabs[] !!! + if( cx < 4) // #### + { + g_bConfigDisasmAddressView ^= true; + DebugDisplay( UPDATE_DISASM ); + } + else + if (cx == 4) // : + { + g_bConfigDisasmAddressColon ^= true; + DebugDisplay( UPDATE_DISASM ); + } + else // AD 00 00 + if ((cx > 4) & (cx <= 13)) + { + g_bConfigDisasmOpcodesView ^= true; + DebugDisplay( UPDATE_DISASM ); + } + + } else + { + if( cx == 0 ) // : + { + // Three-way state + // "addr:" + // ":" + // " " + g_bConfigDisasmAddressColon ^= true; + if( g_bConfigDisasmAddressColon ) + { + g_bConfigDisasmAddressView ^= true; + } + DebugDisplay( UPDATE_DISASM ); + } + else + if ((cx > 0) & (cx <= 13)) + { + g_bConfigDisasmOpcodesView ^= true; + DebugDisplay( UPDATE_DISASM ); + } + } + // Click on PC inside reg window? + if ((cx >= 51) && (cx <= 60)) + { + if (cy == 3) + { + CmdCursorJumpPC( CURSOR_ALIGN_CENTER ); + DebugDisplay( UPDATE_DISASM ); + } + else // Click on stack + if( cy > 3) + { + } + } + } + + FrameReleaseDC(); +} diff --git a/AppleWin/source/Debugger/Debug.h b/AppleWin/source/Debugger/Debug.h new file mode 100644 index 00000000..5ccdba70 --- /dev/null +++ b/AppleWin/source/Debugger/Debug.h @@ -0,0 +1,192 @@ +#pragma once + +#include +#include // sort, find +#include +using namespace std; + +#include "Debugger_Types.h" +#include "Debugger_DisassemblerData.h" +#include "Debugger_Range.h" +#include "Debugger_Parser.h" +#include "Debugger_Console.h" +#include "Debugger_Assembler.h" +#include "Debugger_Help.h" +#include "Debugger_Display.h" +#include "Debugger_Symbols.h" +#include "Util_MemoryTextFile.h" + +// Globals __________________________________________________________________ + +// All (Global) + extern bool g_bDebuggerEatKey; + +// Benchmarking + extern DWORD extbench; + +// Bookmarks + extern int g_nBookmarks; + extern Bookmark_t g_aBookmarks[ MAX_BOOKMARKS ]; +// extern vector g_aBookmarks; + +// Breakpoints + extern int g_nBreakpoints; + extern Breakpoint_t g_aBreakpoints[ MAX_BREAKPOINTS ]; + + extern const char *g_aBreakpointSource [ NUM_BREAKPOINT_SOURCES ]; + extern const TCHAR *g_aBreakpointSymbols[ NUM_BREAKPOINT_OPERATORS ]; + + // Full-Speed debugging + extern int g_nDebugOnBreakInvalid; + extern int g_iDebugOnOpcode ; + extern bool g_bDebugDelayBreakCheck; + +// Commands + extern const int NUM_COMMANDS_WITH_ALIASES; // = sizeof(g_aCommands) / sizeof (Command_t); // Determined at compile-time ;-) + extern int g_iCommand; // last command + + extern Command_t g_aCommands[]; + extern Command_t g_aParameters[]; + + class commands_functor_compare + { + public: + bool operator() ( const Command_t & rLHS, const Command_t & rRHS ) const + { + // return true if lhs g_vMemorySearchResults; + +// Source Level Debugging + extern TCHAR g_aSourceFileName[ MAX_PATH ]; + extern MemoryTextFile_t g_AssemblerSourceBuffer; + + extern int g_iSourceDisplayStart ; + extern int g_nSourceAssembleBytes ; + extern int g_nSourceAssemblySymbols; + +// Version + extern const int DEBUGGER_VERSION; + +// Watches + extern int g_nWatches; + extern Watches_t g_aWatches[ MAX_WATCHES ]; + +// Window + extern int g_iWindowLast; + extern int g_iWindowThis; + extern WindowSplit_t g_aWindowConfig[ NUM_WINDOWS ]; + +// Zero Page + extern int g_nZeroPagePointers; + extern ZeroPagePointers_t g_aZeroPagePointers[ MAX_ZEROPAGE_POINTERS ]; // TODO: use vector<> ? + +// Prototypes _______________________________________________________________ + +// Bookmarks + bool Bookmark_Find( const WORD nAddress ); + +// Breakpoints + bool GetBreakpointInfo ( WORD nOffset, bool & bBreakpointActive_, bool & bBreakpointEnable_ ); + + // 0 = Brk, 1 = Invalid1, .. 3 = Invalid 3 + inline bool IsDebugBreakOnInvalid( int iOpcodeType ) + { + bool bActive = (g_nDebugOnBreakInvalid >> iOpcodeType) & 1; + return bActive; + } + + inline void SetDebugBreakOnInvalid( int iOpcodeType, int nValue ) + { + if (iOpcodeType <= AM_3) + { + g_nDebugOnBreakInvalid &= ~ ( 1 << iOpcodeType); + g_nDebugOnBreakInvalid |= ((nValue & 1) << iOpcodeType); + } + } + +// Color + inline COLORREF DebuggerGetColor( int iColor ); + +// Source Level Debugging + int FindSourceLine( WORD nAddress ); + LPCTSTR FormatAddress( WORD nAddress, int nBytes ); + +// Symbol Table / Memory + bool FindAddressFromSymbol( LPCSTR pSymbol, WORD * pAddress_ = NULL, int * iTable_ = NULL ); + WORD GetAddressFromSymbol (LPCTSTR symbol); // HACK: returns 0 if symbol not found + void SymbolUpdate( SymbolTable_Index_e eSymbolTable, char *pSymbolName, WORD nAddrss, bool bRemoveSymbol, bool bUpdateSymbol ); + + LPCTSTR FindSymbolFromAddress (WORD nAdress, int * iTable_ = NULL ); + LPCTSTR GetSymbol (WORD nAddress, int nBytes); + + Update_t DebuggerProcessCommand( const bool bEchoConsoleInput ); + +// Prototypes _______________________________________________________________ + + enum + { + DEBUG_EXIT_KEY = 0x1B, // Escape + DEBUG_TOGGLE_KEY = VK_F1 + BTN_DEBUG + }; + + void DebugBegin (); + void DebugContinueStepping (); + void DebugDestroy (); + void DebugDisplay (BOOL); + void DebugEnd (); + void DebugInitialize (); +// void DebugProcessChar (TCHAR); + void DebuggerInputConsoleChar( TCHAR ch ); +// void DebugProcessCommand (int); + void DebuggerProcessKey( int keycode ); + + void DebuggerUpdate(); + void DebuggerCursorNext(); + + void DebuggerMouseClick( int x, int y ); + \ No newline at end of file diff --git a/AppleWin/source/Debugger/Debugger_Assembler.cpp b/AppleWin/source/Debugger/Debugger_Assembler.cpp new file mode 100644 index 00000000..f4e61cf2 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Assembler.cpp @@ -0,0 +1,1361 @@ +/* +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-2009, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Debugger + * + * Author: Copyright (C) 2006-2009, Michael Pohoreski + */ + +#include "StdAfx.h" + +// Globals __________________________________________________________________ + + +// Addressing _____________________________________________________________________________________ + + AddressingMode_t g_aOpmodes[ NUM_ADDRESSING_MODES ] = + { // Outut, but eventually used for Input when Assembler is working. + {TEXT("") , 1 , "(implied)" }, // (implied) + {TEXT("") , 1 , "n/a 1" }, // INVALID1 + {TEXT("") , 2 , "n/a 2" }, // INVALID2 + {TEXT("") , 3 , "n/a 3" }, // INVALID3 + {TEXT("%02X") , 2 , "Immediate" }, // AM_M // #$%02X -> %02X + {TEXT("%04X") , 3 , "Absolute" }, // AM_A + {TEXT("%02X") , 2 , "Zero Page" }, // AM_Z + {TEXT("%04X,X") , 3 , "Absolute,X" }, // AM_AX // %s,X + {TEXT("%04X,Y") , 3 , "Absolute,Y" }, // AM_AY // %s,Y + {TEXT("%02X,X") , 2 , "Zero Page,X" }, // AM_ZX // %s,X + {TEXT("%02X,Y") , 2 , "Zero Page,Y" }, // AM_ZY // %s,Y + {TEXT("%s") , 2 , "Relative" }, // AM_R + {TEXT("(%02X,X)"), 2 , "(Zero Page),X" }, // AM_IZX // ($%02X,X) -> %s,X + {TEXT("(%04X,X)"), 3 , "(Absolute),X" }, // AM_IAX // ($%04X,X) -> %s,X + {TEXT("(%02X),Y"), 2 , "(Zero Page),Y" }, // AM_NZY // ($%02X),Y + {TEXT("(%02X)") , 2 , "(Zero Page)" }, // AM_NZ // ($%02X) -> $%02X + {TEXT("(%04X)") , 3 , "(Absolute)" } // AM_NA // (%04X) -> %s + }; + + +// Assembler ______________________________________________________________________________________ + + int g_bAssemblerOpcodesHashed = false; + Hash_t g_aOpcodesHash[ NUM_OPCODES ]; // for faster mnemonic lookup, for the assembler + bool g_bAssemblerInput = false; + int g_nAssemblerAddress = 0; + + const Opcodes_t *g_aOpcodes = NULL; // & g_aOpcodes65C02[ 0 ]; + + +// Disassembler Data _____________________________________________________________________________ + + vector g_aDisassemblerData; + + +// Instructions / Opcodes _________________________________________________________________________ + + +// @reference: http://www.6502.org/tutorials/compare_instructions.html +// 10 signed: BPL BGE +// B0 unsigned: BCS BGE + +#define R_ MEM_R +#define _W MEM_W +#define RW MEM_R | MEM_W +#define _S MEM_S +#define im MEM_IM +#define SW MEM_S | MEM_WI +#define SR MEM_S | MEM_RI +const Opcodes_t g_aOpcodes65C02[ NUM_OPCODES ] = +{ + {"BRK", 0 , 0}, {"ORA", AM_IZX, R_}, {"nop", AM_M , im}, {"nop", 0 , 0 }, // 00 .. 03 + {"TSB", AM_Z , _W}, {"ORA", AM_Z , R_}, {"ASL", AM_Z , RW}, {"nop", 0 , 0 }, // 04 .. 07 + {"PHP", 0 , SW}, {"ORA", AM_M , im}, {"ASL", 0 , 0}, {"nop", 0 , 0 }, // 08 .. 0B + {"TSB", AM_A , _W}, {"ORA", AM_A , R_}, {"ASL", AM_A , RW}, {"nop", 0 , 0 }, // 0C .. 0F + {"BPL", AM_R , 0}, {"ORA", AM_NZY, R_}, {"ORA", AM_NZ , R_}, {"nop", 0 , 0 }, // 10 .. 13 + {"TRB", AM_Z , _W}, {"ORA", AM_ZX , R_}, {"ASL", AM_ZX , RW}, {"nop", 0 , 0 }, // 14 .. 17 + {"CLC", 0 , 0}, {"ORA", AM_AY , R_}, {"INC", 0 , 0}, {"nop", 0 , 0 }, // 18 .. 1B + {"TRB", AM_A , _W}, {"ORA", AM_AX , R_}, {"ASL", AM_AX , RW}, {"nop", 0 , 0 }, // 1C .. 1F + + {"JSR", AM_A , SW}, {"AND", AM_IZX, R_}, {"nop", AM_M , im}, {"nop", 0 , 0 }, // 20 .. 23 + {"BIT", AM_Z , R_}, {"AND", AM_Z , R_}, {"ROL", AM_Z , RW}, {"nop", 0 , 0 }, // 24 .. 27 + {"PLP", 0 , SR}, {"AND", AM_M , im}, {"ROL", 0 , 0}, {"nop", 0 , 0 }, // 28 .. 2B + {"BIT", AM_A , R_}, {"AND", AM_A , R_}, {"ROL", AM_A , RW}, {"nop", 0 , 0 }, // 2C .. 2F + {"BMI", AM_R , 0}, {"AND", AM_NZY, R_}, {"AND", AM_NZ , R_}, {"nop", 0 , 0 }, // 30 .. 33 + {"BIT", AM_ZX , R_}, {"AND", AM_ZX , R_}, {"ROL", AM_ZX , RW}, {"nop", 0 , 0 }, // 34 .. 37 + {"SEC", 0 , 0}, {"AND", AM_AY , R_}, {"DEC", 0 , 0}, {"nop", 0 , 0 }, // 38 .. 3B + {"BIT", AM_AX , R_}, {"AND", AM_AX , R_}, {"ROL", AM_AX , RW}, {"nop", 0 , 0 }, // 3C .. 3F + + {"RTI", 0 , 0}, {"EOR", AM_IZX, R_}, {"nop", AM_M , im}, {"nop", 0 , 0 }, // 40 .. 43 + {"nop", AM_Z , 0}, {"EOR", AM_Z , R_}, {"LSR", AM_Z , _W}, {"nop", 0 , 0 }, // 44 .. 47 + {"PHA", 0 , SW}, {"EOR", AM_M , im}, {"LSR", 0 , 0}, {"nop", 0 , 0 }, // 48 .. 4B + {"JMP", AM_A , 0}, {"EOR", AM_A , R_}, {"LSR", AM_A , _W}, {"nop", 0 , 0 }, // 4C .. 4F + {"BVC", AM_R , 0}, {"EOR", AM_NZY, R_}, {"EOR", AM_NZ , R_}, {"nop", 0 , 0 }, // 50 .. 53 + {"nop", AM_ZX , 0}, {"EOR", AM_ZX , R_}, {"LSR", AM_ZX , _W}, {"nop", 0 , 0 }, // 54 .. 57 + {"CLI", 0 , 0}, {"EOR", AM_AY , R_}, {"PHY", 0 , SW}, {"nop", 0 , 0 }, // 58 .. 5B + {"nop", AM_AX , 0}, {"EOR", AM_AX , R_}, {"LSR", AM_AX , RW}, {"nop", 0 , 0 }, // 5C .. 5F + + {"RTS", 0 , SR}, {"ADC", AM_IZX, R_}, {"nop", AM_M , im}, {"nop", 0 , 0 }, // 60 .. 63 + {"STZ", AM_Z , _W}, {"ADC", AM_Z , R_}, {"ROR", AM_Z , RW}, {"nop", 0 , 0 }, // 64 .. 67 + {"PLA", 0 , SR}, {"ADC", AM_M , im}, {"ROR", 0 , 0}, {"nop", 0 , 0 }, // 68 .. 6B + {"JMP", AM_NA , 0}, {"ADC", AM_A , R_}, {"ROR", AM_A , RW}, {"nop", 0 , 0 }, // 6C .. 6F + {"BVS", AM_R , 0}, {"ADC", AM_NZY, R_}, {"ADC", AM_NZ , R_}, {"nop", 0 , 0 }, // 70 .. 73 + {"STZ", AM_ZX , _W}, {"ADC", AM_ZX , R_}, {"ROR", AM_ZX , RW}, {"nop", 0 , 0 }, // 74 .. 77 + {"SEI", 0 , 0}, {"ADC", AM_AY , R_}, {"PLY", 0 , SR}, {"nop", 0 , 0 }, // 78 .. 7B + {"JMP", AM_IAX, 0}, {"ADC", AM_AX , R_}, {"ROR", AM_AX , RW}, {"nop", 0 , 0 }, // 7C .. 7F + + {"BRA", AM_R , 0}, {"STA", AM_IZX, _W}, {"nop", AM_M , im}, {"nop", 0 , 0 }, // 80 .. 83 + {"STY", AM_Z , _W}, {"STA", AM_Z , _W}, {"STX", AM_Z , _W}, {"nop", 0 , 0 }, // 84 .. 87 + {"DEY", 0 , 0}, {"BIT", AM_M , im}, {"TXA", 0 , 0}, {"nop", 0 , 0 }, // 88 .. 8B + {"STY", AM_A , _W}, {"STA", AM_A , _W}, {"STX", AM_A , _W}, {"nop", 0 , 0 }, // 8C .. 8F + {"BCC", AM_R , 0}, {"STA", AM_NZY, _W}, {"STA", AM_NZ , _W}, {"nop", 0 , 0 }, // 90 .. 93 + {"STY", AM_ZX , _W}, {"STA", AM_ZX , _W}, {"STX", AM_ZY , _W}, {"nop", 0 , 0 }, // 94 .. 97 + {"TYA", 0 , 0}, {"STA", AM_AY , _W}, {"TXS", 0 , 0}, {"nop", 0 , 0 }, // 98 .. 9B + {"STZ", AM_A , _W}, {"STA", AM_AX , _W}, {"STZ", AM_AX , _W}, {"nop", 0 , 0 }, // 9C .. 9F + + {"LDY", AM_M , im}, {"LDA", AM_IZX, R_}, {"LDX", AM_M , im}, {"nop", 0 , 0 }, // A0 .. A3 + {"LDY", AM_Z , R_}, {"LDA", AM_Z , R_}, {"LDX", AM_Z , R_}, {"nop", 0 , 0 }, // A4 .. A7 + {"TAY", 0 , 0}, {"LDA", AM_M , im}, {"TAX", 0 , 0 }, {"nop", 0 , 0 }, // A8 .. AB + {"LDY", AM_A , R_}, {"LDA", AM_A , R_}, {"LDX", AM_A , R_}, {"nop", 0 , 0 }, // AC .. AF + {"BCS", AM_R , 0}, {"LDA", AM_NZY, R_}, {"LDA", AM_NZ , R_}, {"nop", 0 , 0 }, // B0 .. B3 + {"LDY", AM_ZX , R_}, {"LDA", AM_ZX , R_}, {"LDX", AM_ZY , R_}, {"nop", 0 , 0 }, // B4 .. B7 + {"CLV", 0 , 0}, {"LDA", AM_AY , R_}, {"TSX", 0 , 0 }, {"nop", 0 , 0 }, // B8 .. BB + {"LDY", AM_AX , R_}, {"LDA", AM_AX , R_}, {"LDX", AM_AY , R_}, {"nop", 0 , 0 }, // BC .. BF + + {"CPY", AM_M , im}, {"CMP", AM_IZX, R_}, {"nop", AM_M , im}, {"nop", 0 , 0 }, // C0 .. C3 + {"CPY", AM_Z , R_}, {"CMP", AM_Z , R_}, {"DEC", AM_Z , RW}, {"nop", 0 , 0 }, // C4 .. C7 + {"INY", 0 , 0}, {"CMP", AM_M , im}, {"DEX", 0 , 0}, {"nop", 0 , 0 }, // C8 .. CB + {"CPY", AM_A , R_}, {"CMP", AM_A , R_}, {"DEC", AM_A , RW}, {"nop", 0 , 0 }, // CC .. CF + {"BNE", AM_R , 0}, {"CMP", AM_NZY, R_}, {"CMP", AM_NZ , 0}, {"nop", 0 , 0 }, // D0 .. D3 + {"nop", AM_ZX , 0}, {"CMP", AM_ZX , R_}, {"DEC", AM_ZX , RW}, {"nop", 0 , 0 }, // D4 .. D7 + {"CLD", 0 , 0}, {"CMP", AM_AY , R_}, {"PHX", 0 , 0}, {"nop", 0 , 0 }, // D8 .. DB + {"nop", AM_AX , 0}, {"CMP", AM_AX , R_}, {"DEC", AM_AX , RW}, {"nop", 0 , 0 }, // DC .. DF + + {"CPX", AM_M , im}, {"SBC", AM_IZX, R_}, {"nop", AM_M , im}, {"nop", 0 , 0 }, // E0 .. E3 + {"CPX", AM_Z , R_}, {"SBC", AM_Z , R_}, {"INC", AM_Z , RW}, {"nop", 0 , 0 }, // E4 .. E7 + {"INX", 0 , 0}, {"SBC", AM_M , R_}, {"NOP", 0 , 0}, {"nop", 0 , 0 }, // E8 .. EB + {"CPX", AM_A , R_}, {"SBC", AM_A , R_}, {"INC", AM_A , RW}, {"nop", 0 , 0 }, // EC .. EF + {"BEQ", AM_R , 0}, {"SBC", AM_NZY, R_}, {"SBC", AM_NZ , 0}, {"nop", 0 , 0 }, // F0 .. F3 + {"nop", AM_ZX , 0}, {"SBC", AM_ZX , R_}, {"INC", AM_ZX , RW}, {"nop", 0 , 0 }, // F4 .. F7 + {"SED", 0 , 0}, {"SBC", AM_AY , R_}, {"PLX", 0 , 0}, {"nop", 0 , 0 }, // F8 .. FB + {"nop", AM_AX , 0}, {"SBC", AM_AX , R_}, {"INC", AM_AX , RW}, {"nop", 0 , 0 } // FF .. FF +}; + +const Opcodes_t g_aOpcodes6502[ NUM_OPCODES ] = +{ // Should match Cpu.cpp InternalCpuExecute() switch (*(mem+regs.pc++)) !! + +/* + Based on: http://axis.llx.com/~nparker/a2/opcodes.html + + If you really want to know what the undocumented --- (n/a) opcodes do, see + CPU.cpp + + x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF +0x BRK ORA (d,X) --- --- tsb d ORA d ASL d --- PHP ORA # ASL A --- tsb a ORA a ASL a --- +1x BPL r ORA (d),Y ora (d) --- trb d ORA d,X ASL d,X --- CLC ORA a,Y ina A --- trb a ORA a,X ASL a,X --- +2x JSR a AND (d,X) --- --- BIT d AND d ROL d --- PLP AND # ROL A --- BIT a AND a ROL a --- +3x BMI r AND (d),Y and (d) --- bit d,X AND d,X ROL d,X --- SEC AND a,Y dea A --- bit a,X AND a,X ROL a,X --- +4x RTI EOR (d,X) --- --- --- EOR d LSR d --- PHA EOR # LSR A --- JMP a EOR a LSR a --- +5x BVC r EOR (d),Y eor (d) --- --- EOR d,X LSR d,X --- CLI EOR a,Y phy --- --- EOR a,X LSR a,X --- +6x RTS ADC (d,X) --- --- stz d ADC d ROR d --- PLA ADC # ROR A --- JMP (a) ADC a ROR a --- +7x BVS r ADC (d),Y adc (d) --- stz d,X ADC d,X ROR d,X --- SEI ADC a,Y ply --- jmp (a,X) ADC a,X ROR a,X --- +8x bra r STA (d,X) --- --- STY d STA d STX d --- DEY bit # TXA --- STY a STA a STX a --- +9x BCC r STA (d),Y sta (d) --- STY d,X STA d,X STX d,Y --- TYA STA a,Y TXS --- Stz a STA a,X stz a,X --- +Ax LDY # LDA (d,X) LDX # --- LDY d LDA d LDX d --- TAY LDA # TAX --- LDY a LDA a LDX a --- +Bx BCS r LDA (d),Y lda (d) --- LDY d,X LDA d,X LDX d,Y --- CLV LDA a,Y TSX --- LDY a,X LDA a,X LDX a,Y --- +Cx CPY # CMP (d,X) --- --- CPY d CMP d DEC d --- INY CMP # DEX --- CPY a CMP a DEC a --- +Dx BNE r CMP (d),Y cmp (d) --- --- CMP d,X DEC d,X --- CLD CMP a,Y phx --- --- CMP a,X DEC a,X --- +Ex CPX # SBC (d,X) --- --- CPX d SBC d INC d --- INX SBC # NOP --- CPX a SBC a INC a --- +Fx BEQ r SBC (d),Y sbc (d) --- --- SBC d,X INC d,X --- SED SBC a,Y plx --- --- SBC a,X INC a,X --- + + Legend: + UPPERCASE 6502 + lowercase 65C02 + 80 + 12, 32, 52, 72, 92, B2, D2, F2 + 04, 14, 34, 64, 74 + 89 + 1A, 3A, 5A, 7A, DA, FA + 0C, 1C, 3C, 7C, 9C; + # Immediate + A Accumulator (implicit for mnemonic) + a absolute + r Relative + d Destination + z Zero Page + d,x + (d,X) + (d),Y + +*/ + {"BRK", 0 , 0}, {"ORA", AM_IZX, R_}, {"hlt", 0 , 0 }, {"aso", AM_IZX, RW}, // 00 .. 03 + {"nop", AM_Z , R_}, {"ORA", AM_Z , R_}, {"ASL", AM_Z , RW}, {"aso", AM_Z , RW}, // 04 .. 07 + {"PHP", 0 , SW}, {"ORA", AM_M , im}, {"ASL", 0 , 0}, {"anc", AM_M , im}, // 08 .. 0B + {"nop", AM_AX , 0}, {"ORA", AM_A , R_}, {"ASL", AM_A , RW}, {"aso", AM_A , RW}, // 0C .. 0F + {"BPL", AM_R , 0}, {"ORA", AM_NZY, R_}, {"hlt", 0 , 0}, {"aso", AM_NZY, RW}, // 10 .. 13 + {"nop", AM_ZX , 0}, {"ORA", AM_ZX , R_}, {"ASL", AM_ZX , RW}, {"aso", AM_ZX , RW}, // 14 .. 17 + {"CLC", 0 , 0}, {"ORA", AM_AY , R_}, {"nop", 0 , 0}, {"aso", AM_AY , RW}, // 18 .. 1B + {"nop", AM_AX , 0}, {"ORA", AM_AX , R_}, {"ASL", AM_AX , RW}, {"aso", AM_AX , RW}, // 1C .. 1F + + {"JSR", AM_A , SW}, {"AND", AM_IZX, R_}, {"hlt", 0 , 0}, {"rla", AM_IZX, RW}, // 20 .. 23 + {"BIT", AM_Z , R_}, {"AND", AM_Z , R_}, {"ROL", AM_Z , RW}, {"rla", AM_Z , RW}, // 24 .. 27 + {"PLP", 0 , SR}, {"AND", AM_M , im}, {"ROL", 0 , 0}, {"anc", AM_M , im}, // 28 .. 2B + {"BIT", AM_A , R_}, {"AND", AM_A , R_}, {"ROL", AM_A , RW}, {"rla", AM_A , RW}, // 2C .. 2F + {"BMI", AM_R , 0}, {"AND", AM_NZY, R_}, {"hlt", 0 , 0}, {"rla", AM_NZY, RW}, // 30 .. 33 + {"nop", AM_ZX , 0}, {"AND", AM_ZX , R_}, {"ROL", AM_ZX , RW}, {"rla", AM_ZX , RW}, // 34 .. 37 + {"SEC", 0 , 0}, {"AND", AM_AY , R_}, {"nop", 0 , 0}, {"rla", AM_AY , RW}, // 38 .. 3B + {"nop", AM_AX , 0}, {"AND", AM_AX , R_}, {"ROL", AM_AX , RW}, {"rla", AM_AX , RW}, // 3C .. 3F + + {"RTI", 0 , 0}, {"EOR", AM_IZX, R_}, {"hlt", 0 , 0}, {"lse", AM_IZX, RW}, // 40 .. 43 + {"nop", AM_Z , 0}, {"EOR", AM_Z , R_}, {"LSR", AM_Z , RW}, {"lse", AM_Z , RW}, // 44 .. 47 + {"PHA", 0 , SW}, {"EOR", AM_M , im}, {"LSR", 0 , 0}, {"alr", AM_M , im}, // 48 .. 4B + {"JMP", AM_A , 0}, {"EOR", AM_A , R_}, {"LSR", AM_A , RW}, {"lse", AM_A , RW}, // 4C .. 4F + {"BVC", AM_R , 0}, {"EOR", AM_NZY, R_}, {"hlt", 0 , 0}, {"lse", AM_NZY, RW}, // 50 .. 53 + {"nop", AM_ZX , 0}, {"EOR", AM_ZX , R_}, {"LSR", AM_ZX , RW}, {"lse", AM_ZX , RW}, // 54 .. 57 + {"CLI", 0 , 0}, {"EOR", AM_AY , R_}, {"nop", 0 , 0}, {"lse", AM_AY , RW}, // 58 .. 5B + {"nop", AM_AX , 0}, {"EOR", AM_AX , R_}, {"LSR", AM_AX , RW}, {"lse", AM_AX , RW}, // 5C .. 5F + + {"RTS", 0 , SR}, {"ADC", AM_IZX, R_}, {"hlt", 0 , 0}, {"rra", AM_IZX, RW}, // 60 .. 63 + {"nop", AM_Z , 0}, {"ADC", AM_Z , R_}, {"ROR", AM_Z , RW}, {"rra", AM_Z , RW}, // 64 .. 67 + {"PLA", 0 , SR}, {"ADC", AM_M , im}, {"ROR", 0 , 0}, {"arr", AM_M , im}, // 68 .. 6B + {"JMP", AM_NA , 0}, {"ADC", AM_A , R_}, {"ROR", AM_A , RW}, {"rra", AM_A , RW}, // 6C .. 6F + {"BVS", AM_R , 0}, {"ADC", AM_NZY, R_}, {"hlt", 0 , 0}, {"rra", AM_NZY, RW}, // 70 .. 73 + {"nop", AM_ZX , 0}, {"ADC", AM_ZX , R_}, {"ROR", AM_ZX , RW}, {"rra", AM_ZX , RW}, // 74 .. 77 + {"SEI", 0 , 0}, {"ADC", AM_AY , R_}, {"nop", 0 , 0}, {"rra", AM_AY , RW}, // 78 .. 7B + {"nop", AM_AX , 0}, {"ADC", AM_AX , R_}, {"ROR", AM_AX , RW}, {"rra", AM_AX , RW}, // 7C .. 7F + + {"nop", AM_M , im}, {"STA", AM_IZX, _W}, {"nop", AM_M , im}, {"axs", AM_IZX, _W}, // 80 .. 83 + {"STY", AM_Z , _W}, {"STA", AM_Z , _W}, {"STX", AM_Z , _W}, {"axs", AM_Z , _W}, // 84 .. 87 + {"DEY", 0 , 0}, {"nop", AM_M , im}, {"TXA", 0 , 0}, {"xaa", AM_M , im}, // 88 .. 8B + {"STY", AM_A , _W}, {"STA", AM_A , _W}, {"STX", AM_A , _W}, {"axs", AM_A , _W}, // 8C .. 8F + {"BCC", AM_R , 0}, {"STA", AM_NZY, _W}, {"hlt", 0 , 0}, {"axa", AM_NZY, _W}, // 90 .. 93 + {"STY", AM_ZX , _W}, {"STA", AM_ZX , _W}, {"STX", AM_ZY , _W}, {"axs", AM_ZY , _W}, // 94 .. 97 + {"TYA", 0 , 0}, {"STA", AM_AY , _W}, {"TXS", 0 , 0}, {"tas", AM_AY , _W}, // 98 .. 9B + {"say", AM_AX , _W}, {"STA", AM_AX , _W}, {"xas", AM_AX , _W}, {"axa", AM_AY , _W}, // 9C .. 9F + + {"LDY", AM_M , im}, {"LDA", AM_IZX, R_}, {"LDX", AM_M , im}, {"lax", AM_IZX, R_}, // A0 .. A3 + {"LDY", AM_Z , R_}, {"LDA", AM_Z , R_}, {"LDX", AM_Z , R_}, {"lax", AM_Z , R_}, // A4 .. A7 + {"TAY", 0 , 0}, {"LDA", AM_M , im}, {"TAX", 0 , 0 }, {"oal", AM_M , im}, // A8 .. AB + {"LDY", AM_A , R_}, {"LDA", AM_A , R_}, {"LDX", AM_A , R_}, {"lax", AM_A , R_}, // AC .. AF + {"BCS", AM_R , 0}, {"LDA", AM_NZY, R_}, {"hlt", 0 , 0 }, {"lax", AM_NZY, R_}, // B0 .. B3 + {"LDY", AM_ZX , R_}, {"LDA", AM_ZX , R_}, {"LDX", AM_ZY , R_}, {"lax", AM_ZY , 0 }, // B4 .. B7 + {"CLV", 0 , 0}, {"LDA", AM_AY , R_}, {"TSX", 0 , 0 }, {"las", AM_AY , R_}, // B8 .. BB + {"LDY", AM_AX , R_}, {"LDA", AM_AX , R_}, {"LDX", AM_AY , R_}, {"lax", AM_AY , R_}, // BC .. BF + + {"CPY", AM_M , im}, {"CMP", AM_IZX, R_}, {"nop", AM_M , im}, {"dcm", AM_IZX, RW}, // C0 .. C3 + {"CPY", AM_Z , R_}, {"CMP", AM_Z , R_}, {"DEC", AM_Z , RW}, {"dcm", AM_Z , RW}, // C4 .. C7 + {"INY", 0 , 0}, {"CMP", AM_M , im}, {"DEX", 0 , 0}, {"sax", AM_M , im}, // C8 .. CB + {"CPY", AM_A , R_}, {"CMP", AM_A , R_}, {"DEC", AM_A , RW}, {"dcm", AM_A , RW}, // CC .. CF + {"BNE", AM_R , 0}, {"CMP", AM_NZY, R_}, {"hlt", 0 , 0}, {"dcm", AM_NZY, RW}, // D0 .. D3 + {"nop", AM_ZX , 0}, {"CMP", AM_ZX , R_}, {"DEC", AM_ZX , RW}, {"dcm", AM_ZX , RW}, // D4 .. D7 + {"CLD", 0 , 0}, {"CMP", AM_AY , R_}, {"nop", 0 , 0}, {"dcm", AM_AY , RW}, // D8 .. DB + {"nop", AM_AX , 0}, {"CMP", AM_AX , R_}, {"DEC", AM_AX , RW}, {"dcm", AM_AX , RW}, // DC .. DF + + {"CPX", AM_M , im}, {"SBC", AM_IZX, R_}, {"nop", AM_M , im}, {"ins", AM_IZX, RW}, // E0 .. E3 + {"CPX", AM_Z , R_}, {"SBC", AM_Z , R_}, {"INC", AM_Z , RW}, {"ins", AM_Z , RW}, // E4 .. E7 + {"INX", 0 , 0}, {"SBC", AM_M , im}, {"NOP", 0 , 0}, {"sbc", AM_M , im}, // E8 .. EB + {"CPX", AM_A , R_}, {"SBC", AM_A , R_}, {"INC", AM_A , RW}, {"ins", AM_A , RW}, // EC .. EF + {"BEQ", AM_R , 0}, {"SBC", AM_NZY, R_}, {"hlt", 0 , 0}, {"ins", AM_NZY, RW}, // F0 .. F3 + {"nop", AM_ZX , 0}, {"SBC", AM_ZX , R_}, {"INC", AM_ZX , RW}, {"ins", AM_ZX , RW}, // F4 .. F7 + {"SED", 0 , 0}, {"SBC", AM_AY , R_}, {"nop", 0 , 0}, {"ins", AM_AY , RW}, // F8 .. FB + {"nop", AM_AX , 0}, {"SBC", AM_AX , R_}, {"INC", AM_AX , RW}, {"ins", AM_AX , RW} // FF .. FF +}; + +#undef R_ +#undef _W +#undef RW +#undef _S +#undef im +#undef SW +#undef SR + +// @reference: http://www.textfiles.com/apple/DOCUMENTATION/merlin.docs1 + +// Private __________________________________________________________________ + + +// enum Nopcode_t +// { +// NOPCODE_NONE, // line.iOpcode is valid: [0,0xFF] + + // Acme + AssemblerDirective_t g_aAssemblerDirectives[ NUM_ASM_DIRECTIVES ] = + { + // NULL n/a + {""}, + // Acme + {"???"}, + // Big Mac + {"???"}, + // DOS Tool Kit + {"???"}, + // Lisa + {"???"}, + // Merlin + {"ASC"}, // ASC "postive" 'negative' + {"DDB"}, // Define Double Byte (Define WORD) + {"DFB"}, // DeFine Byte + {"DS" }, // Defin Storage + {"HEX"}, // HEX ###### or HEX ##,##,... + {"ORG"}, // Origin + // MicroSparc + {"???"}, + // ORCA/M + {"???"}, + // SC ... + {".OR"}, // ORigin + {".TA"}, // Target Address + {".EN"}, // ENd of program + {".EQ"}, // EQuate + {".DA"}, // DAta + {".AS"}, // Ascii String + {".HS"}, // Hex String + // Ted II + {"???"}, + // Weller + {"???"}, + }; + +// Assemblers + + enum AssemblerFlags_e + { + AF_HaveLabel = (1 << 0), + AF_HaveComma = (1 << 1), + AF_HaveHash = (1 << 2), + AF_HaveImmediate = (1 << 3), + AF_HaveDollar = (1 << 4), + AF_HaveLeftParen = (1 << 5), + AF_HaveRightParen = (1 << 6), + AF_HaveEitherParen= (1 << 7), + AF_HaveBothParen = (1 << 8), + AF_HaveRegisterX = (1 << 9), + AF_HaveRegisterY = (1 <<10), + AF_HaveZeroPage = (1 <<11), + AF_HaveTarget = (1 <<12), + }; + + enum AssemblerState_e + { + AS_GET_MNEMONIC + , AS_GET_MNEMONIC_PARM + , AS_GET_HASH + , AS_GET_TARGET + , AS_GET_PAREN + , AS_GET_INDEX + , AS_DONE + }; + + int m_bAsmFlags; + vector m_vAsmOpcodes; + int m_iAsmAddressMode = AM_IMPLIED; + + struct DelayedTarget_t + { + char m_sAddress[ MAX_SYMBOLS_LEN + 1 ]; + WORD m_nBaseAddress; // mem address to store symbol at + int m_nOpcode ; + int m_iOpmode ; // AddressingMode_e + }; + + vector m_vDelayedTargets; + bool m_bDelayedTargetsDirty = false; + + int m_nAsmBytes = 0; + WORD m_nAsmBaseAddress = 0; + WORD m_nAsmTargetAddress = 0; + WORD m_nAsmTargetValue = 0; + +// Implementation ___________________________________________________________ + + +//=========================================================================== +bool _6502_CalcRelativeOffset( int nOpcode, int nBaseAddress, int nTargetAddress, WORD * pTargetOffset_ ) +{ + if (_6502_IsOpcodeBranch( nOpcode)) + { + // Branch is + // a) relative to address+2 + // b) in 2's compliment + // + // i.e. + // 300: D0 7F -> BNE $381 0x381 - 0x300 = 0x81 +129 + // 300: D0 80 -> BNE $282 0x282 - 0x300 = -126 + // + // 300: D0 7E BNE $380 + // ^ ^ ^ ^ + // | | | TargetAddress + // | | TargetOffset + // | Opcode + // BaseAddress + int nDistance = nTargetAddress - nBaseAddress; + if (pTargetOffset_) + *pTargetOffset_ = (BYTE)(nDistance - 2); + + if ((nDistance - 2) > _6502_BRANCH_POS) + m_iAsmAddressMode = NUM_OPMODES; // signal bad + + if ((nDistance - 2) < _6502_BRANCH_NEG) + m_iAsmAddressMode = NUM_OPMODES; // signal bad + + return true; + } + + return false; +} + + +//=========================================================================== +int _6502_GetOpmodeOpbyte ( const int iAddress, int & iOpmode_, int & nOpbyte_ ) +{ +#if _DEBUG + if (! g_aOpcodes) + { + MessageBox( g_hFrameWindow, "Debugger not properly initialized", "ERROR", MB_OK ); + } +#endif + +// Data Disassembler +// Smart Disassembly - Data Section +// Assemblyer Directives - Psuedo Mnemonics + + int iOpcode_ = *(mem + iAddress); + iOpmode_ = g_aOpcodes[ iOpcode_ ].nAddressMode; + nOpbyte_ = g_aOpmodes[ iOpmode_ ].m_nBytes; + +#if _DEBUG + if (iOpcode_ >= NUM_OPCODES) + { + bool bStop = true; + } +#endif + + return iOpcode_; +} + + +//=========================================================================== +void _6502_GetOpcodeOpmodeOpbyte ( int & iOpcode_, int & iOpmode_, int & nOpbyte_ ) +{ + iOpcode_ = _6502_GetOpmodeOpbyte( regs.pc, iOpmode_, nOpbyte_ ); +} + +//=========================================================================== +bool _6502_GetStackReturnAddress ( WORD & nAddress_ ) +{ + unsigned nStack = regs.sp; + nStack++; + + if (nStack <= (_6502_STACK_END - 1)) + { + nAddress_ = 0; + nAddress_ = (unsigned)*(LPBYTE)(mem + nStack); + nStack++; + + nAddress_ += ((unsigned)*(LPBYTE)(mem + nStack)) << 8; + nAddress_++; + return true; + } + return false; +} + + +//=========================================================================== +bool _6502_GetTargets ( WORD nAddress, int *pTargetPartial_, int *pTargetPointer_, int * pTargetBytes_, bool bIgnoreJSRJMP, bool bIgnoreBranch ) +{ + bool bStatus = false; + + if (! pTargetPartial_) + return bStatus; + + if (! pTargetPointer_) + return bStatus; + +// if (! pTargetBytes_) +// return bStatus; + + *pTargetPartial_ = NO_6502_TARGET; + *pTargetPointer_ = NO_6502_TARGET; + + if (pTargetBytes_) + *pTargetBytes_ = 0; + + bStatus = true; + + BYTE nOpcode = *(LPBYTE)(mem + nAddress ); + BYTE nTarget8 = *(LPBYTE)(mem + nAddress + 1); + WORD nTarget16 = *(LPWORD)(mem + nAddress + 1); + + int eMode = g_aOpcodes[ nOpcode ].nAddressMode; + + switch (eMode) + { + case AM_A: // $Absolute + *pTargetPointer_ = nTarget16; + if (pTargetBytes_) + *pTargetBytes_ = 2; + break; + + case AM_IAX: // Indexed (Absolute) Indirect + nTarget16 += regs.x; + *pTargetPartial_ = nTarget16; + *pTargetPointer_ = *(LPWORD)(mem + nTarget16); + if (pTargetBytes_) + *pTargetBytes_ = 2; + break; + + case AM_AX: // Absolute, X + nTarget16 += regs.x; + *pTargetPointer_ = nTarget16; + if (pTargetBytes_) + *pTargetBytes_ = 2; + break; + + case AM_AY: // Absolute, Y + nTarget16 += regs.y; + *pTargetPointer_ = nTarget16; + if (pTargetBytes_) + *pTargetBytes_ = 2; + break; + + case AM_NA: // Indirect (Absolute) i.e. JMP + *pTargetPartial_ = nTarget16; + *pTargetPointer_ = *(LPWORD)(mem + nTarget16); + if (pTargetBytes_) + *pTargetBytes_ = 2; + break; + + case AM_IZX: // Indexed (Zeropage Indirect, X) + nTarget8 += regs.x; + *pTargetPartial_ = nTarget8; + *pTargetPointer_ = *(LPWORD)(mem + nTarget8); + if (pTargetBytes_) + *pTargetBytes_ = 2; + break; + + case AM_NZY: // Indirect (Zeropage) Indexed, Y + *pTargetPartial_ = nTarget8; + *pTargetPointer_ = ((*(LPWORD)(mem + nTarget8)) + regs.y) & _6502_MEM_END; // Bugfix: + if (pTargetBytes_) + *pTargetBytes_ = 1; + break; + + case AM_NZ: // Indirect (Zeropage) + *pTargetPartial_ = nTarget8; + *pTargetPointer_ = *(LPWORD)(mem + nTarget8); + if (pTargetBytes_) + *pTargetBytes_ = 2; + break; + + case AM_R: + if (! bIgnoreBranch) + { + *pTargetPartial_ = nTarget8; + *pTargetPointer_ = nAddress + 2; + + if (nTarget8 <= _6502_BRANCH_POS) + *pTargetPointer_ += nTarget8; // + + else + *pTargetPointer_ -= nTarget8; // - + + *pTargetPointer_ &= _6502_MEM_END; + + if (pTargetBytes_) + *pTargetBytes_ = 1; + } + break; + + case AM_Z: // Zeropage + *pTargetPointer_ = nTarget8; + if (pTargetBytes_) + *pTargetBytes_ = 1; + break; + + case AM_ZX: // Zeropage, X + *pTargetPointer_ = (nTarget8 + regs.x) & 0xFF; // .21 Bugfix: shouldn't this wrap around? Yes. + if (pTargetBytes_) + *pTargetBytes_ = 1; + break; + + case AM_ZY: // Zeropage, Y + *pTargetPointer_ = (nTarget8 + regs.y) & 0xFF; // .21 Bugfix: shouldn't this wrap around? Yes. + if (pTargetBytes_) + *pTargetBytes_ = 1; + break; + + default: + if (pTargetBytes_) + *pTargetBytes_ = 0; + break; + } + + if (bIgnoreJSRJMP) + { + // If 6502 is jumping, don't show byte [nAddressTarget] + if ((*pTargetPointer_ >= 0) && ( + (nOpcode == OPCODE_JSR ) || // 0x20 + (nOpcode == OPCODE_JMP_A ))) // 0x4C +// (nOpcode == OPCODE_JMP_NA ) || // 0x6C +// (nOpcode == OPCODE_JMP_IAX))) // 0x7C + { + *pTargetPointer_ = NO_6502_TARGET; + if (pTargetBytes_) + *pTargetBytes_ = 0; + } + } + + return bStatus; +} + + +//=========================================================================== +bool _6502_GetTargetAddress ( const WORD & nAddress, WORD & nTarget_ ) +{ + int iOpcode; + int iOpmode; + int nOpbytes; + iOpcode = _6502_GetOpmodeOpbyte( nAddress, iOpmode, nOpbytes ); + + // Composite string that has the target nAddress +// WORD nTarget = 0; + int nTargetOffset_ = 0; + + if ((iOpmode != AM_IMPLIED) && + (iOpmode != AM_1) && + (iOpmode != AM_2) && + (iOpmode != AM_3)) + { + int nTargetPartial; + int nTargetPointer; + WORD nTargetValue = 0; // de-ref + int nTargetBytes; + _6502_GetTargets( nAddress, &nTargetPartial, &nTargetPointer, &nTargetBytes, false, false ); + +// if (nTargetPointer == NO_6502_TARGET) +// { +// if (_6502_IsOpcodeBranch( nOpcode ) +// { +// return true; +// } +// } + if (nTargetPointer != NO_6502_TARGET) +// else + { + nTarget_ = nTargetPointer & _6502_MEM_END; + return true; + } + } + return false; +} + +//=========================================================================== +bool _6502_IsOpcodeBranch ( int iOpcode ) +{ + // 76543210 Bit + // xxx10000 Branch + if (iOpcode == OPCODE_BRA) + return true; + + if ((iOpcode & 0x1F) != 0x10) // low nibble not zero? + return false; + + if ((iOpcode >> 4) & 1) + return true; + +// (nOpcode == 0x10) || // BPL +// (nOpcode == 0x30) || // BMI +// (nOpcode == 0x50) || // BVC +// (nOpcode == 0x70) || // BVS +// (nOpcode == 0x90) || // BCC +// (nOpcode == 0xB0) || // BCS +// (nOpcode == 0xD0) || // BNE +// (nOpcode == 0xF0) || // BEQ + return false; +} + + +//=========================================================================== +bool _6502_IsOpcodeValid ( int iOpcode ) +{ + if ((iOpcode & 0x3) == 0x3) + return false; + + if (islower( g_aOpcodes6502[ iOpcode ].sMnemonic[ 0 ] )) + return false; + + return true; +} + +// Assembler ________________________________________________________________ + + +//=========================================================================== +int AssemblerHashMnemonic ( const TCHAR * pMnemonic ) +{ + const TCHAR *pText = pMnemonic; + int nMnemonicHash = 0; + int iHighBits; + + const int NUM_LOW_BITS = 19; // 24 -> 19 prime + const int NUM_MSK_BITS = 5; // 4 -> 5 prime + const Hash_t BIT_MSK_HIGH = ((1 << NUM_MSK_BITS) - 1) << NUM_LOW_BITS; + + for( int iChar = 0; iChar < 4; iChar++ ) + { + nMnemonicHash = (nMnemonicHash << NUM_MSK_BITS) + *pText; + iHighBits = (nMnemonicHash & BIT_MSK_HIGH); + if (iHighBits) + { + nMnemonicHash = (nMnemonicHash ^ (iHighBits >> NUM_LOW_BITS)) & ~ BIT_MSK_HIGH; + } + pText++; + } + + return nMnemonicHash; +} + + +//=========================================================================== +void AssemblerHashOpcodes () +{ + Hash_t nMnemonicHash; + int iOpcode; + + for( iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ ) + { + const TCHAR *pMnemonic = g_aOpcodes65C02[ iOpcode ].sMnemonic; + nMnemonicHash = AssemblerHashMnemonic( pMnemonic ); + g_aOpcodesHash[ iOpcode ] = nMnemonicHash; + } + +} + +// TODO: Change .. AssemblerHashDirectives() +//=========================================================================== +void AssemblerHashMerlinDirectives () +{ + Hash_t nMnemonicHash; + int iOpcode; + + for( iOpcode = 0; iOpcode < NUM_ASM_M_DIRECTIVES; iOpcode++ ) + { + int iNopcode = FIRST_M_DIRECTIVE + iOpcode; +//. const TCHAR *pMnemonic = g_aAssemblerDirectivesMerlin[ iOpcode ].m_pMnemonic; + const TCHAR *pMnemonic = g_aAssemblerDirectives[ iNopcode ].m_pMnemonic; + nMnemonicHash = AssemblerHashMnemonic( pMnemonic ); + g_aAssemblerDirectives[ iNopcode ].m_nHash = nMnemonicHash; + } +} + +//=========================================================================== +void AssemblerStartup() +{ + AssemblerHashOpcodes(); + AssemblerHashMerlinDirectives(); +} + +//=========================================================================== +void _CmdAssembleHashDump () +{ +// #if DEBUG_ASM_HASH + vector vHashes; + HashOpcode_t tHash; + TCHAR sText[ CONSOLE_WIDTH ]; + + int iOpcode; + for( iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ ) + { + tHash.m_iOpcode = iOpcode; + tHash.m_nValue = g_aOpcodesHash[ iOpcode ]; + vHashes.push_back( tHash ); + } + + sort( vHashes.begin(), vHashes.end(), HashOpcode_t() ); + + Hash_t nPrevHash = vHashes.at( 0 ).m_nValue; + Hash_t nThisHash = 0; + + for( iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ ) + { + tHash = vHashes.at( iOpcode ); + + Hash_t iThisHash = tHash.m_nValue; + int nOpcode = tHash.m_iOpcode; + int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode; + + wsprintf( sText, "%08X %02X %s %s" + , iThisHash + , nOpcode + , g_aOpcodes65C02[ nOpcode ].sMnemonic + , g_aOpmodes[ nOpmode ].m_sName + ); + ConsoleBufferPush( sText ); + nThisHash++; + +// if (nPrevHash != iThisHash) +// { +// wsprintf( sText, "Total: %d", nThisHash ); +// ConsoleBufferPush( sText ); +// nThisHash = 0; +// } + } + + ConsoleUpdate(); +//#endif +} + + + +//=========================================================================== +int AssemblerPokeAddress( const int Opcode, const int nOpmode, const WORD nBaseAddress, const WORD nTargetOffset ) +{ +// int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode; + int nOpbytes = g_aOpmodes[ nOpmode ].m_nBytes; + + // if (nOpbytes != nBytes) + // ConsoleDisplayError( TEXT(" ERROR: Input Opcode bytes differs from actual!" ) ); + + *(memdirty + (nBaseAddress >> 8)) |= 1; +// *(mem + nBaseAddress) = (BYTE) nOpcode; + + if (nOpbytes > 1) + *(mem + nBaseAddress + 1) = (BYTE)(nTargetOffset >> 0); + + if (nOpbytes > 2) + *(mem + nBaseAddress + 2) = (BYTE)(nTargetOffset >> 8); + + return nOpbytes; +} + +//=========================================================================== +bool AssemblerPokeOpcodeAddress( const WORD nBaseAddress ) +{ + int iAddressMode = m_iAsmAddressMode; // opmode detected from input + int nTargetValue = m_nAsmTargetValue; + + int iOpcode; + int nOpcodes = m_vAsmOpcodes.size(); + + for( iOpcode = 0; iOpcode < nOpcodes; iOpcode++ ) + { + int nOpcode = m_vAsmOpcodes.at( iOpcode ); // m_iOpcode; + int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode; + + if (nOpmode == iAddressMode) + { + *(mem + nBaseAddress) = (BYTE) nOpcode; + int nOpbytes = AssemblerPokeAddress( nOpcode, nOpmode, nBaseAddress, nTargetValue ); + + if (m_bDelayedTargetsDirty) + { + int nDelayedTargets = m_vDelayedTargets.size(); + DelayedTarget_t *pTarget = & m_vDelayedTargets.at( nDelayedTargets - 1 ); + + pTarget->m_nOpcode = nOpcode; + pTarget->m_iOpmode = nOpmode; + } + + g_nAssemblerAddress += nOpbytes; + return true; + } + + } + + return false; +} + + +//=========================================================================== +bool TestFlag( AssemblerFlags_e eFlag ) +{ + if (m_bAsmFlags & eFlag) + return true; + + return false; +} + +//=========================================================================== +void SetFlag( AssemblerFlags_e eFlag, bool bValue = true ) +{ + if (bValue) + m_bAsmFlags |= eFlag; + else + m_bAsmFlags &= ~ eFlag; +} + + +/* + Output + AM_IMPLIED + AM_M + AM_A + AM_Z + AM_I // indexed or indirect +*/ +//=========================================================================== +bool AssemblerGetArgs( int iArg, int nArgs, WORD nBaseAddress ) +{ + m_iAsmAddressMode = AM_IMPLIED; + AssemblerState_e eNextState = AS_GET_MNEMONIC; + + m_bAsmFlags = 0; + m_nAsmTargetAddress = 0; + + int nBase = 10; + + // Sync up to Raw Args for matching mnemonic + // Process them instead of the cooked args, since we need the orginal tokens + Arg_t *pArg = &g_aArgRaw[ iArg ]; + + while (iArg < g_nArgRaw) + { + int iToken = pArg->eToken; + int iType = pArg->bType; + + if (iToken == TOKEN_HASH) + { + if (eNextState != AS_GET_MNEMONIC_PARM) + { + ConsoleBufferPush( TEXT( " Syntax Error: '#'" ) ); + return false; + } + if (TestFlag( AF_HaveHash )) + { + ConsoleBufferPush( TEXT( " Syntax Error: Extra '#'" ) ); // No thanks, we already have one + return false; + } + SetFlag( AF_HaveHash ); + + m_iAsmAddressMode = AM_M; // Immediate + eNextState = AS_GET_TARGET; + m_nAsmBytes = 1; + } + else + if (iToken == TOKEN_DOLLAR) + { + if (TestFlag( AF_HaveDollar )) + { + ConsoleBufferPush( TEXT( " Syntax Error: Extra '$'" ) ); // No thanks, we already have one + return false; + } + + nBase = 16; // switch to hex + + if (! TestFlag( AF_HaveHash)) + { + SetFlag( AF_HaveDollar ); + m_iAsmAddressMode = AM_A; // Absolute + } + eNextState = AS_GET_TARGET; + m_nAsmBytes = 2; + } + else + if (iToken == TOKEN_PAREN_L) + { + if (TestFlag( AF_HaveLeftParen )) + { + ConsoleBufferPush( TEXT( " Syntax Error: Extra '('" ) ); // No thanks, we already have one + return false; + } + SetFlag( AF_HaveLeftParen ); + + // Indexed or Indirect + m_iAsmAddressMode = AM_I; + } + else + if (iToken == TOKEN_PAREN_R) + { + if (TestFlag( AF_HaveRightParen )) + { + ConsoleBufferPush( TEXT( " Syntax Error: Extra ')'" ) ); // No thanks, we already have one + return false; + } + SetFlag( AF_HaveRightParen ); + + // Indexed or Indirect + m_iAsmAddressMode = AM_I; + } + else + if (iToken == TOKEN_COMMA) + { + if (TestFlag( AF_HaveComma )) + { + ConsoleBufferPush( TEXT( " Syntax Error: Extra ','" ) ); // No thanks, we already have one + return false; + } + SetFlag( AF_HaveComma ); + eNextState = AS_GET_INDEX; + // We should have address by now + } + else + if (iToken == TOKEN_LESS_THAN) + { + } + else + if (iToken == TOKEN_GREATER_THAN) + { + } + else + if (iToken == TOKEN_SEMI) // comment + { + break; + } + else + if (iToken == TOKEN_ALPHANUMERIC) + { + if (eNextState == AS_GET_MNEMONIC) + { + eNextState = AS_GET_MNEMONIC_PARM; + } + else + if (eNextState == AS_GET_MNEMONIC_PARM) + { + eNextState = AS_GET_TARGET; + } + + if (eNextState == AS_GET_TARGET) + { + SetFlag( AF_HaveTarget ); + + ArgsGetValue( pArg, & m_nAsmTargetAddress, nBase ); + + // Do Symbol Lookup + WORD nSymbolAddress; + bool bExists = FindAddressFromSymbol( pArg->sArg, &nSymbolAddress ); + if (bExists) + { + m_nAsmTargetAddress = nSymbolAddress; + + if (m_iAsmAddressMode == AM_IMPLIED) + m_iAsmAddressMode = AM_A; + } + else + { + // if valid hex address, don't have delayed target + TCHAR sAddress[ 32 ]; + wsprintf( sAddress, "%X", m_nAsmTargetAddress); + if (_tcscmp( sAddress, pArg->sArg)) + { + DelayedTarget_t tDelayedTarget; + + tDelayedTarget.m_nBaseAddress = nBaseAddress; + strncpy( tDelayedTarget.m_sAddress, pArg->sArg, MAX_SYMBOLS_LEN ); + tDelayedTarget.m_sAddress[ MAX_SYMBOLS_LEN ] = 0; + + // Flag this target that we need to update it when we have the relevent info + m_bDelayedTargetsDirty = true; + + tDelayedTarget.m_nOpcode = 0; + tDelayedTarget.m_iOpmode = m_iAsmAddressMode; + + m_vDelayedTargets.push_back( tDelayedTarget ); + + m_nAsmTargetAddress = 0; + } + } + + if ((m_iAsmAddressMode != AM_M) && + (m_iAsmAddressMode != AM_IMPLIED) && + (! m_bDelayedTargetsDirty)) + { + if (m_nAsmTargetAddress <= _6502_ZEROPAGE_END) + { + m_iAsmAddressMode = AM_Z; + m_nAsmBytes = 1; + } + } + } + if (eNextState == AS_GET_INDEX) + { + if (pArg->nArgLen == 1) + { + if (pArg->sArg[0] == 'X') + { + if (! TestFlag( AF_HaveComma )) + { + ConsoleBufferPush( TEXT( " Syntax Error: Missing ','" ) ); + return false; + } + SetFlag( AF_HaveRegisterX ); + } + if (pArg->sArg[0] == 'Y') + { + if (! (TestFlag( AF_HaveComma ))) + { + ConsoleBufferPush( TEXT( " Syntax Error: Missing ','" ) ); + return false; + } + SetFlag( AF_HaveRegisterY ); + } + } + } + } + + iArg++; + pArg++; + } + + return true; +} + + +//=========================================================================== +bool AssemblerUpdateAddressingMode() +{ + SetFlag( AF_HaveEitherParen, TestFlag(AF_HaveLeftParen) || TestFlag(AF_HaveRightParen) ); + SetFlag( AF_HaveBothParen, TestFlag(AF_HaveLeftParen) && TestFlag(AF_HaveRightParen) ); + + if ((TestFlag( AF_HaveLeftParen )) && (! TestFlag( AF_HaveRightParen ))) + { + ConsoleBufferPush( TEXT( " Syntax Error: Missing ')'" ) ); + return false; + } + + if ((! TestFlag( AF_HaveLeftParen )) && ( TestFlag( AF_HaveRightParen ))) + { + ConsoleBufferPush( TEXT( " Syntax Error: Missing '('" ) ); + return false; + } + + if (TestFlag( AF_HaveComma )) + { + if ((! TestFlag( AF_HaveRegisterX )) && (! TestFlag( AF_HaveRegisterY ))) + { + ConsoleBufferPush( TEXT( " Syntax Error: Index 'X' or 'Y'" ) ); + return false; + } + } + + if (TestFlag( AF_HaveBothParen )) + { + if (TestFlag( AF_HaveComma )) + { + if (TestFlag( AF_HaveRegisterX )) + { + m_iAsmAddressMode = AM_AX; + m_nAsmBytes = 2; + if (m_nAsmTargetAddress <= _6502_ZEROPAGE_END) + { + m_iAsmAddressMode = AM_ZX; + m_nAsmBytes = 1; + } + } + if (TestFlag( AF_HaveRegisterY )) + { + m_iAsmAddressMode = AM_AY; + m_nAsmBytes = 2; + if (m_nAsmTargetAddress <= _6502_ZEROPAGE_END) + { + m_iAsmAddressMode = AM_ZY; + m_nAsmBytes = 1; + } + } + } + } + + if ((m_iAsmAddressMode == AM_A) || (m_iAsmAddressMode == AM_Z)) + { + if (! TestFlag( AF_HaveEitherParen)) // if no paren + { + if (TestFlag( AF_HaveComma ) && TestFlag( AF_HaveRegisterX )) + { + if (m_iAsmAddressMode == AM_Z) + m_iAsmAddressMode = AM_ZX; + else + m_iAsmAddressMode = AM_AX; + } + if (TestFlag( AF_HaveComma ) && TestFlag( AF_HaveRegisterY )) + { + if (m_iAsmAddressMode == AM_Z) + m_iAsmAddressMode = AM_ZY; + else + m_iAsmAddressMode = AM_AY; + } + } + } + + if (m_iAsmAddressMode == AM_I) + { + if (! TestFlag( AF_HaveEitherParen)) // if no paren + { + // Indirect Zero Page + // Indirect Absolute + } + } + + m_nAsmTargetValue = m_nAsmTargetAddress; + + int nOpcode = m_vAsmOpcodes.at( 0 ); // branch opcodes don't vary (only 1 Addressing Mode) + if (_6502_CalcRelativeOffset( nOpcode, m_nAsmBaseAddress, m_nAsmTargetAddress, & m_nAsmTargetValue )) + { + if (m_iAsmAddressMode == NUM_OPMODES) + return false; + + m_iAsmAddressMode = AM_R; + } + + return true; +} + + +//=========================================================================== +int AssemblerDelayedTargetsSize() +{ + int nSize = m_vDelayedTargets.size(); + return nSize; +} + + +// The Assembler was terminated, with Symbol(s) declared, but not (yet) defined. +// i.e. +// A 300 +// BNE $DONE +// +//=========================================================================== +void AssemblerProcessDelayedSymols() +{ + m_bDelayedTargetsDirty = false; // assembler set signal if new symbol was added + + bool bModified = false; + while (! bModified) + { + bModified = false; + + vector::iterator iSymbol; + for( iSymbol = m_vDelayedTargets.begin(); iSymbol != m_vDelayedTargets.end(); ++iSymbol ) + { + DelayedTarget_t *pTarget = & (*iSymbol); // m_vDelayedTargets.at( iSymbol ); + + WORD nTargetAddress; + bool bExists = FindAddressFromSymbol( pTarget->m_sAddress, & nTargetAddress ); + if (bExists) + { + // TODO: need to handle #symbol, symbol+n, symbol-n + + bModified = true; + + int nOpcode = pTarget->m_nOpcode; + int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode; +// int nOpbytes = g_aOpmodes[ nOpmode ].m_nBytes; + + // 300: D0 7E BNE $380 + // ^ ^ ^ + // | | TargetAddress + // | TargetValue + // BaseAddress + WORD nTargetValue = nTargetAddress; + + if (_6502_CalcRelativeOffset( nOpcode, pTarget->m_nBaseAddress, nTargetAddress, & nTargetValue )) + { + if (m_iAsmAddressMode == NUM_OPMODES) + { + nTargetValue = 0; + bModified = false; + } + } + + if (bModified) + { + AssemblerPokeAddress( nOpcode, nOpmode, pTarget->m_nBaseAddress, nTargetValue ); + *(memdirty + (pTarget->m_nBaseAddress >> 8)) |= 1; + + m_vDelayedTargets.erase( iSymbol ); + + // iterators are invalid after the point of deletion + // need to restart enumeration + break; + } + } + } + + if (! bModified) + break; + } +} + + +bool Assemble( int iArg, int nArgs, WORD nAddress ) +{ + bool bGotArgs; + bool bGotMode; + bool bGotByte; + + // Since, making 2-passes is not an option, + // we need to buffer the target address fix-ups. + AssemblerProcessDelayedSymols(); + + m_nAsmBaseAddress = nAddress; + + TCHAR *pMnemonic = g_aArgs[ iArg ].sArg; + int nMnemonicHash = AssemblerHashMnemonic( pMnemonic ); + + m_vAsmOpcodes.clear(); // Candiate opcodes + int iOpcode; + + // Ugh! Linear search. + for( iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ ) + { + if (nMnemonicHash == g_aOpcodesHash[ iOpcode ]) + { + m_vAsmOpcodes.push_back( iOpcode ); + } + } + + int nOpcodes = m_vAsmOpcodes.size(); + if (! nOpcodes) + { + // Check for assembler directive + + + ConsoleBufferPush( TEXT(" Syntax Error: Invalid mnemonic") ); + return false; + } + else + { + bGotArgs = AssemblerGetArgs( iArg, nArgs, nAddress ); + if (bGotArgs) + { + bGotMode = AssemblerUpdateAddressingMode(); + if (bGotMode) + { + bGotByte = AssemblerPokeOpcodeAddress( nAddress ); + } + } + } + + return true; +} + + +//=========================================================================== +void AssemblerOn () +{ + g_bAssemblerInput = true; + g_sConsolePrompt[0] = g_aConsolePrompt[ PROMPT_ASSEMBLER ]; +} + +//=========================================================================== +void AssemblerOff () +{ + g_bAssemblerInput = false; + g_sConsolePrompt[0] = g_aConsolePrompt[ PROMPT_COMMAND ]; +} + diff --git a/AppleWin/source/Debugger/Debugger_Assembler.h b/AppleWin/source/Debugger/Debugger_Assembler.h new file mode 100644 index 00000000..a416d000 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Assembler.h @@ -0,0 +1,180 @@ +#ifndef DEBUGGER_ASSEMBLER_H +#define DEBUGGER_ASSEMBLER_H + +// Directives + + // Assemblers + // A = Acme + // B = Big Mac S= S-C Macro Assembler + // K = DOS Tool Kit T = TED II + // L = Lisa W = Weller's Assembler + // M = Merlin + // u = MicroSparc + // O = ORCA/M + enum AsmAcmeDirective_e + { + ASM_A_DEFINE_BYTE + ,NUM_ASM_A_DIRECTIVES + }; + + enum AsmBigMacDirective_e + { + ASM_B_DEFINE_BYTE + ,NUM_ASM_B_DIRECTIVES + }; + + enum AsmDosToolKitDirective_e + { + ASM_K_DEFINE_BYTE + ,NUM_ASM_K_DIRECTIVES + }; + + enum AsmLisaDirective_e + { + ASM_L_DEFINE_BYTE + ,NUM_ASM_L_DIRECTIVES + }; + + enum AsmMerlinDirective_e + { + ASM_M_ASCII + , ASM_M_DEFINE_WORD + , ASM_M_DEFINE_BYTE + , ASM_M_DEFINE_STORAGE + , ASM_M_HEX + , ASM_M_ORIGIN + , NUM_ASM_M_DIRECTIVES + , ASM_M_DEFINE_BYTE_ALIAS + , ASM_M_DEFINE_WORD_ALIAS + }; + + enum AsmMicroSparcDirective_e + { + ASM_u_DEFINE_BYTE + ,NUM_ASM_u_DIRECTIVES + }; + + enum AsmOrcamDirective_e + { + ASM_O_DEFINE_BYTE + ,NUM_ASM_O_DIRECTIVES + }; + + enum AsmSCMacroDirective_e + { + ASM_S_ORIGIN + ,ASM_S_TARGET_ADDRESS + ,ASM_S_END_PROGRAM + ,ASM_S_EQUATE + ,ASM_S_DATA + ,ASM_S_ASCII_STRING + ,ASM_S_HEX_STRING + ,NUM_ASM_S_DIRECTIVES + }; + + enum AsmTedDirective_e + { + ASM_T_DEFINE_BYTE + ,NUM_ASM_T_DIRECTIVES + }; + + enum AsmWellersDirective_e + { + ASM_W_DEFINE_BYTE + ,NUM_ASM_W_DIRECTIVES + }; + + // NOTE: Must keep in sync: AsmDirectives_e g_aAssemblerDirectives + enum AsmDirectives_e + { + FIRST_A_DIRECTIVE = 1, + FIRST_B_DIRECTIVE = FIRST_A_DIRECTIVE + NUM_ASM_A_DIRECTIVES, // Acme + FIRST_K_DIRECTIVE = FIRST_B_DIRECTIVE + NUM_ASM_B_DIRECTIVES, // Big Mac + FIRST_L_DIRECTIVE = FIRST_K_DIRECTIVE + NUM_ASM_K_DIRECTIVES, // DOS Tool Kit + FIRST_M_DIRECTIVE = FIRST_L_DIRECTIVE + NUM_ASM_L_DIRECTIVES, // Lisa + FIRST_u_DIRECTIVE = FIRST_M_DIRECTIVE + NUM_ASM_M_DIRECTIVES, // Merlin + FIRST_O_DIRECTIVE = FIRST_u_DIRECTIVE + NUM_ASM_u_DIRECTIVES, // MicroSparc + FIRST_S_DIRECTIVE = FIRST_O_DIRECTIVE + NUM_ASM_O_DIRECTIVES, // Orca + FIRST_T_DIRECTIVE = FIRST_S_DIRECTIVE + NUM_ASM_S_DIRECTIVES, // SC + FIRST_W_DIRECTIVE = FIRST_T_DIRECTIVE + NUM_ASM_T_DIRECTIVES, // Ted + NUM_ASM_DIRECTIVES= FIRST_W_DIRECTIVE + NUM_ASM_W_DIRECTIVES, // Ted + +// NUM_ASM_DIRECTIVES = 1 + // Opcode ... rest are psuedo opcodes +// NUM_ASM_A_DIRECTIVES + // Acme +// NUM_ASM_B_DIRECTIVES + // Big Mac +// NUM_ASM_K_DIRECTIVES + // DOS Tool Kit +// NUM_ASM_L_DIRECTIVES + // Lisa +// NUM_ASM_M_DIRECTIVES + // Merlin +// NUM_ASM_u_DIRECTIVES + // MicroSparc +// NUM_ASM_O_DIRECTIVES + // Orca +// NUM_ASM_S_DIRECTIVES + // SC +// NUM_ASM_T_DIRECTIVES + // Ted +// NUM_ASM_W_DIRECTIVES // Weller + }; + +// Addressing _____________________________________________________________________________________ + + extern AddressingMode_t g_aOpmodes[ NUM_ADDRESSING_MODES ]; + +// Assembler ______________________________________________________________________________________ + + // Hashing for Assembler + typedef unsigned int Hash_t; + + struct HashOpcode_t + { + int m_iOpcode; + Hash_t m_nValue; + + // functor + bool operator () (const HashOpcode_t & rLHS, const HashOpcode_t & rRHS) const + { + bool bLessThan = (rLHS.m_nValue < rRHS.m_nValue); + return bLessThan; + } + }; + + struct AssemblerDirective_t + { + char *m_pMnemonic; + Hash_t m_nHash; + }; + + extern int g_bAssemblerOpcodesHashed; // = false; + extern Hash_t g_aOpcodesHash[ NUM_OPCODES ]; // for faster mnemonic lookup, for the assembler + extern bool g_bAssemblerInput; // = false; + extern int g_nAssemblerAddress; // = 0; + + extern const Opcodes_t *g_aOpcodes; // = NULL; // & g_aOpcodes65C02[ 0 ]; + + extern const Opcodes_t g_aOpcodes65C02[ NUM_OPCODES ]; + extern const Opcodes_t g_aOpcodes6502 [ NUM_OPCODES ]; + + extern AssemblerDirective_t g_aAssemblerDirectives[ NUM_ASM_DIRECTIVES ]; + +// Prototypes _______________________________________________________________ + + int _6502_GetOpmodeOpbyte( const int iAddress, int & iOpmode_, int & nOpbytes_ ); +// void _6502_GetOpcodeOpmode( int & iOpcode_, int & iOpmode_, int & nOpbytes_ ); + void _6502_GetOpcodeOpmodeOpbyte( int & iOpcode_, int & iOpmode_, int & nOpbytes_ ); + bool _6502_GetStackReturnAddress( WORD & nAddress_ ); + bool _6502_GetTargets( WORD nAddress, int *pTargetPartial_, int *pTargetPointer_, int * pBytes_ + , const bool bIgnoreJSRJMP = true, bool bIgnoreBranch = true ); + bool _6502_GetTargetAddress( const WORD & nAddress, WORD & nTarget_ ); + bool _6502_IsOpcodeBranch( int nOpcode ); + bool _6502_IsOpcodeValid( int nOpcode ); + + int AssemblerHashMnemonic ( const TCHAR * pMnemonic ); + void AssemblerHashOpcodes (); + void AssemblerHashMerlinDirectives (); +// bool AssemblerGetAddressingMode ( int iArg, int nArgs, WORD nAddress, vector & vOpcodes ); + void _CmdAssembleHashDump (); + + int AssemblerDelayedTargetsSize(); + void AssemblerStartup (); + bool Assemble( int iArg, int nArgs, WORD nAddress ); + + void AssemblerOn (); + void AssemblerOff (); + +#endif diff --git a/AppleWin/source/Debugger/Debugger_Console.cpp b/AppleWin/source/Debugger/Debugger_Console.cpp new file mode 100644 index 00000000..f92034ab --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Console.cpp @@ -0,0 +1,625 @@ +/* +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-2007, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Debugger + * + * Author: Copyright (C) 2006, Michael Pohoreski + */ + +#include "StdAfx.h" + + +// Console ________________________________________________________________________________________ + + // See ConsoleInputReset() for why the console input + // is tied to the zero'th output of g_aConsoleDisplay + // and not using a seperate var: g_aConsoleInput[ CONSOLE_WIDTH ]; + // + // : g_aConsoleBuffer[4] | ^ g_aConsoleDisplay[5] : + // : g_aConsoleBuffer[3] | | g_aConsoleDisplay[4] <- g_nConsoleDisplayTotal + // g_nConsoleBuffer -> g_aConsoleBuffer[2] | | g_aConsoleDisplay[3] : + // : g_aConsoleBuffer[1] v | g_aConsoleDisplay[2] : + // . g_aConsoleBuffer[0] -----> | g_aConsoleDisplay[1] . + // | + // g_aBufferedInput[0] -----> ConsoleInput ----> | g_aConsoleDisplay[0] + // g_aBufferedInput[1] ^ + // g_aBufferedInput[2] | + // g_aBufferedInput[3] | + + // Buffer + bool g_bConsoleBufferPaused = false; // buffered output is waiting for user to continue + int g_nConsoleBuffer = 0; + conchar_t g_aConsoleBuffer[ CONSOLE_BUFFER_HEIGHT ][ CONSOLE_WIDTH ]; // TODO: stl::vector< line_t > + + // Cursor + char g_sConsoleCursor[] = "_"; + + // Display + char g_aConsolePrompt[] = ">!"; // input, assembler // NUM_PROMPTS + char g_sConsolePrompt[] = ">"; // No, NOT Integer Basic! The nostalgic '*' "Monitor" doesn't look as good, IMHO. :-( + int g_nConsolePromptLen = 1; + + bool g_bConsoleFullWidth = true; // false + + int g_iConsoleDisplayStart = 0; // to allow scrolling + int g_nConsoleDisplayTotal = 0; // number of lines added to console + int g_nConsoleDisplayLines = 0; + int g_nConsoleDisplayWidth = 0; + conchar_t g_aConsoleDisplay[ CONSOLE_HEIGHT ][ CONSOLE_WIDTH ]; + + // Input History + int g_nHistoryLinesStart = 0; + int g_nHistoryLinesTotal = 0; // number of commands entered + char g_aHistoryLines[ HISTORY_HEIGHT ][ HISTORY_WIDTH ] = {""}; + + // Input Line + + // Raw input Line (has prompt) + char g_aConsoleInput[ CONSOLE_WIDTH ]; // = g_aConsoleDisplay[0]; + + // Cooked input line (no prompt) + int g_nConsoleInputChars = 0; + char * g_pConsoleInput = 0; // points to past prompt + const char * g_pConsoleFirstArg = 0; // points to first arg + bool g_bConsoleInputQuoted = false; // Allows lower-case to be entered + char g_nConsoleInputSkip = '~'; + +// Prototypes _______________________________________________________________ + +// Console ________________________________________________________________________________________ + +int ConsoleLineLength( const conchar_t * pText ) +{ + int nLen = 0; + const conchar_t *pSrc = pText; + + if (pText ) + { + while (*pSrc) + { + pSrc++; + } + nLen = pSrc - pText; + } + return nLen; +} + + +//=========================================================================== +const conchar_t* ConsoleBufferPeek () +{ + return g_aConsoleBuffer[ 0 ]; +} + + +//=========================================================================== +bool ConsolePrint ( const char * pText ) +{ + while (g_nConsoleBuffer >= CONSOLE_BUFFER_HEIGHT) + { + ConsoleBufferToDisplay(); + } + + // Convert color string to native console color text + // Ignores g_nConsoleDisplayWidth + char c; + + int x = 0; + const char *pSrc = pText; + conchar_t *pDst = & g_aConsoleBuffer[ g_nConsoleBuffer ][ 0 ]; + + conchar_t g = 0; + bool bHaveColor = false; + char cColor = 0; + + while ((x < CONSOLE_WIDTH) && (c = *pSrc)) + { + if ((c == '\n') || (x >= (CONSOLE_WIDTH - 1))) + { + *pDst = 0; + x = 0; + if (g_nConsoleBuffer >= CONSOLE_BUFFER_HEIGHT) + { + ConsoleBufferToDisplay(); + } + else + { + g_nConsoleBuffer++; + } + pSrc++; + pDst = & g_aConsoleBuffer[ g_nConsoleBuffer ][ 0 ]; + } + else + { + g = (c & _CONSOLE_COLOR_MASK); + + // `# `A color encode mouse text + if (ConsoleColor_IsCharMeta( c )) + { + if (! pSrc[1]) + break; + + if (ConsoleColor_IsCharMeta( pSrc[1] )) // ` ` + { + bHaveColor = false; + cColor = 0; + g = ConsoleColor_MakeColor( cColor, c ); + *pDst = g; + x++; + pDst++; + } + else + if (ConsoleColor_IsCharColor( pSrc[1] )) // ` # + { + cColor = pSrc[1]; + bHaveColor = true; + } + else // ` @ + { + c = ConsoleColor_MakeMouse( pSrc[1] ); + g = ConsoleColor_MakeColor( cColor, c ); + *pDst = g; + x++; + pDst++; + } + pSrc++; + pSrc++; + } + else + { + if (bHaveColor) + { + g = ConsoleColor_MakeColor( cColor, c ); + bHaveColor = false; + } + *pDst = g; + x++; + pDst++; + pSrc++; + } + } +/* + if (ConsoleColor_IsCharMeta( c )) + { + // Convert mult-byte to packed char + // 0 1 2 Offset + // ===== + // 1 ~ - null + // 2 ~ 0 - null - exit + // 3 ~ 0 x color (3 bytes packed into char16 + // 4 ~ @ - mouse text + // 5 ~ @ x mouse Text + // 6 ~ ~ ~ + // Legend: + // ~ Color escape + // x Any char + // - Null + if (pSrc[1]) + { + if (ConsoleColor_IsCharMeta( pSrc[1] )) // 6 + { + *pDst = c; + x++; + pSrc += 2; + pDst++; + } + else + if (ConsoleColor_IsCharColor( pSrc[1] )) + { + if (pSrc[2]) // 3 + { + x++; + *pDst = ConsoleColor_MakeColor( pSrc[1], pSrc[2] ); + pSrc += 3; + pDst++; + } + else + break; // 2 + } + else // 4 or 5 + { + *pDst = ConsoleColor_MakeMeta( pSrc[1] ); + x++; + pSrc += 2; + pDst++; + } + } + else + break; // 1 + } + else + { + *pDst = (c & _CONSOLE_COLOR_MASK); + x++; + pSrc++; + pDst++; + } +*/ + } + *pDst = 0; + g_nConsoleBuffer++; + + return true; +} + +// Add string to buffered output +// Shifts the buffered console output lines "Up" +//=========================================================================== +bool ConsoleBufferPush ( const char * pText ) +{ + while (g_nConsoleBuffer >= CONSOLE_BUFFER_HEIGHT) + { + ConsoleBufferToDisplay(); + } + + conchar_t c; + + int x = 0; + const char *pSrc = pText; + conchar_t *pDst = & g_aConsoleBuffer[ g_nConsoleBuffer ][ 0 ]; + + while ((x < CONSOLE_WIDTH) && (c = *pSrc)) + { + if ((c == '\n') || (x == (CONSOLE_WIDTH - 1))) + { + *pDst = 0; + x = 0; + if (g_nConsoleBuffer >= CONSOLE_BUFFER_HEIGHT) + { + ConsoleBufferToDisplay(); + } + else + { + g_nConsoleBuffer++; + } + pSrc++; + pDst = & g_aConsoleBuffer[ g_nConsoleBuffer ][ 0 ]; + } + else + { + *pDst = (c & _CONSOLE_COLOR_MASK); + x++; + pSrc++; + pDst++; + } + } + *pDst = 0; + g_nConsoleBuffer++; + + return true; +} + +// Shifts the buffered console output "down" +//=========================================================================== +void ConsoleBufferPop () +{ + int y = 0; + while (y < g_nConsoleBuffer) + { + memcpy( + g_aConsoleBuffer[ y ], + g_aConsoleBuffer[ y+1 ], + sizeof( conchar_t ) * CONSOLE_WIDTH + ); + y++; + } + + g_nConsoleBuffer--; + if (g_nConsoleBuffer < 0) + g_nConsoleBuffer = 0; +} + +// Remove string from buffered output +//=========================================================================== +void ConsoleBufferToDisplay () +{ + ConsoleDisplayPush( ConsoleBufferPeek() ); + ConsoleBufferPop(); +} + +// No mark-up. Straight ASCII conversion +//=========================================================================== +void ConsoleConvertFromText ( conchar_t * sText, const char * pText ) +{ + int x = 0; + const char *pSrc = pText; + conchar_t *pDst = sText; + while (pSrc && *pSrc) + { + *pDst = (conchar_t) (*pSrc & _CONSOLE_COLOR_MASK); + pSrc++; + pDst++; + } + *pDst = 0; +} + +//=========================================================================== +Update_t ConsoleDisplayError ( const char * pText) +{ + ConsoleBufferPush( pText ); + return ConsoleUpdate(); +} + + +//=========================================================================== +void ConsoleDisplayPush ( const char * pText ) +{ + conchar_t sText[ CONSOLE_WIDTH * 2 ]; + ConsoleConvertFromText( sText, pText ); + ConsoleDisplayPush( sText ); +} + + +// Shifts the console display lines "up" +//=========================================================================== +void ConsoleDisplayPush ( const conchar_t * pText ) +{ + int nLen = MIN( g_nConsoleDisplayTotal, CONSOLE_HEIGHT - 1 - CONSOLE_FIRST_LINE); + while (nLen--) + { + memcpy( + (char*) g_aConsoleDisplay[(nLen + 1 + CONSOLE_FIRST_LINE )] + , (char*) g_aConsoleDisplay[nLen + CONSOLE_FIRST_LINE] + , sizeof(conchar_t) * CONSOLE_WIDTH + ); + } + + if (pText) + { + memcpy( + (char*) g_aConsoleDisplay[ CONSOLE_FIRST_LINE ] + , pText + , sizeof(conchar_t) * CONSOLE_WIDTH + ); + } + + g_nConsoleDisplayTotal++; + if (g_nConsoleDisplayTotal > (CONSOLE_HEIGHT - CONSOLE_FIRST_LINE)) + g_nConsoleDisplayTotal = (CONSOLE_HEIGHT - CONSOLE_FIRST_LINE); + +} + + +//=========================================================================== +void ConsoleDisplayPause () +{ + if (g_nConsoleBuffer) + { +#if CONSOLE_INPUT_CHAR16 + ConsoleConvertFromText( + g_aConsoleInput, + "...press SPACE continue, ESC skip..." + ); + g_nConsolePromptLen = ConsoleLineLength( g_pConsoleInput ) + 1; +#else + strcpy( + g_aConsoleInput, + "...press SPACE continue, ESC skip..." + ); + g_nConsolePromptLen = strlen( g_pConsoleInput ) + 1; +#endif + g_nConsoleInputChars = 0; + g_bConsoleBufferPaused = true; + } + else + { + ConsoleInputReset(); + } +} + +//=========================================================================== +bool ConsoleInputBackSpace () +{ + if (g_nConsoleInputChars) + { + g_pConsoleInput[ g_nConsoleInputChars ] = CHAR_SPACE; + + g_nConsoleInputChars--; + + if ((g_pConsoleInput[ g_nConsoleInputChars ] == CHAR_QUOTE_DOUBLE) || + (g_pConsoleInput[ g_nConsoleInputChars ] == CHAR_QUOTE_SINGLE)) + g_bConsoleInputQuoted = ! g_bConsoleInputQuoted; + + g_pConsoleInput[ g_nConsoleInputChars ] = CHAR_SPACE; + return true; + } + return false; +} + +// Clears prompt too +//=========================================================================== +bool ConsoleInputClear () +{ + ZeroMemory( g_aConsoleInput, CONSOLE_WIDTH ); + + if (g_nConsoleInputChars) + { + g_nConsoleInputChars = 0; + return true; + } + return false; +} + +//=========================================================================== +bool ConsoleInputChar ( const char ch ) +{ + if (g_nConsoleInputChars < g_nConsoleDisplayWidth) // bug? include prompt? + { + g_pConsoleInput[ g_nConsoleInputChars ] = ch; + g_nConsoleInputChars++; + return true; + } + return false; +} + +//=========================================================================== +void ConsoleUpdateCursor ( char ch ) +{ + if (ch) + g_sConsoleCursor[0] = ch; + else + { + ch = (char) g_aConsoleInput[ g_nConsoleInputChars + g_nConsolePromptLen ]; + if (! ch) + { + ch = CHAR_SPACE; + } + g_sConsoleCursor[0] = ch; + } +} + + +//=========================================================================== +const char * ConsoleInputPeek () +{ +// return g_aConsoleDisplay[0]; +// return g_pConsoleInput; + return g_aConsoleInput; +} + +//=========================================================================== +void ConsoleInputReset () +{ + // Not using g_aConsoleInput since we get drawing of the input Line for "Free" + // Even if we add console scrolling, we don't need any special logic to draw the input line. + g_bConsoleInputQuoted = false; + + ConsoleInputClear(); + +// _tcscpy( g_aConsoleInput, g_sConsolePrompt ); // Assembler can change prompt + g_aConsoleInput[0] = g_sConsolePrompt[0]; + g_nConsolePromptLen = 1; + +// int nLen = strlen( g_aConsoleInput ); +#if CONSOLE_INPUT_CHAR16 + int nLen = ConsoleLineLength( g_aConsoleInput ); +#else + int nLen = strlen( g_aConsoleInput ); +#endif + + g_pConsoleInput = &g_aConsoleInput[ g_nConsolePromptLen ]; + g_nConsoleInputChars = 0; +} + +//=========================================================================== +int ConsoleInputTabCompletion () +{ + return UPDATE_CONSOLE_INPUT; +} + +//=========================================================================== +Update_t ConsoleScrollHome () +{ + g_iConsoleDisplayStart = g_nConsoleDisplayTotal - CONSOLE_FIRST_LINE; + if (g_iConsoleDisplayStart < 0) + g_iConsoleDisplayStart = 0; + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t ConsoleScrollEnd () +{ + g_iConsoleDisplayStart = 0; + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t ConsoleScrollUp ( int nLines ) +{ + g_iConsoleDisplayStart += nLines; + + if (g_iConsoleDisplayStart > (g_nConsoleDisplayTotal - CONSOLE_FIRST_LINE)) + g_iConsoleDisplayStart = (g_nConsoleDisplayTotal - CONSOLE_FIRST_LINE); + + if (g_iConsoleDisplayStart < 0) + g_iConsoleDisplayStart = 0; + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t ConsoleScrollDn ( int nLines ) +{ + g_iConsoleDisplayStart -= nLines; + if (g_iConsoleDisplayStart < 0) + g_iConsoleDisplayStart = 0; + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t ConsoleScrollPageUp () +{ + ConsoleScrollUp( g_nConsoleDisplayLines - CONSOLE_FIRST_LINE ); + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t ConsoleScrollPageDn () +{ + ConsoleScrollDn( g_nConsoleDisplayLines - CONSOLE_FIRST_LINE ); + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +Update_t ConsoleBufferTryUnpause (int nLines) +{ + for( int y = 0; y < nLines; y++ ) + { + ConsoleBufferToDisplay(); + } + + g_bConsoleBufferPaused = false; + if (g_nConsoleBuffer) + { + g_bConsoleBufferPaused = true; + ConsoleDisplayPause(); + return UPDATE_CONSOLE_INPUT | UPDATE_CONSOLE_DISPLAY; + } + + return UPDATE_CONSOLE_DISPLAY; +} + +// Flush the console +//=========================================================================== +Update_t ConsoleUpdate () +{ + if (! g_bConsoleBufferPaused) + { + int nLines = MIN( g_nConsoleBuffer, g_nConsoleDisplayLines - 1); + return ConsoleBufferTryUnpause( nLines ); + } + + return UPDATE_CONSOLE_DISPLAY; +} + +//=========================================================================== +void ConsoleFlush () +{ + int nLines = g_nConsoleBuffer; + ConsoleBufferTryUnpause( nLines ); +} diff --git a/AppleWin/source/Debugger/Debugger_Console.h b/AppleWin/source/Debugger/Debugger_Console.h new file mode 100644 index 00000000..fc8f07db --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Console.h @@ -0,0 +1,256 @@ +#ifndef DEBUGGER_CONSOLE_H +#define DEBUGGER_CONSOLE_H + + enum + { + CONSOLE_HEIGHT = 384, // Lines, was 128, but need ~ 256+16 for PROFILE LIST + CONSOLE_WIDTH = 80, + + // need min 256+ lines for "profile list" + CONSOLE_BUFFER_HEIGHT = 384, + + HISTORY_HEIGHT = 128, + HISTORY_WIDTH = 128, + + CONSOLE_FIRST_LINE = 1, // where ConsoleDisplay is pushed up from + }; + +// Color ____________________________________________________________________ + + // typedef unsigned char conchar_t; + typedef short conchar_t; + + enum ConsoleColors_e + { + CONSOLE_COLOR_K, // 0 + CONSOLE_COLOR_x = 0, // default console foreground + CONSOLE_COLOR_R, // 1 + CONSOLE_COLOR_G, // 2 + CONSOLE_COLOR_Y, // 3 + CONSOLE_COLOR_B, // 4 + CONSOLE_COLOR_M, // 5 Lite Blue + CONSOLE_COLOR_C, // 6 + CONSOLE_COLOR_W, // 7 + CONSOLE_COLOR_O, // 8 + CONSOLE_COLOR_k, // 9 Grey + NUM_CONSOLE_COLORS + }; + extern COLORREF g_anConsoleColor[ NUM_CONSOLE_COLORS ]; + + // Note: THe ` ~ key should always display ~ to prevent rendering errors + #define CONSOLE_COLOR_ESCAPE_CHAR '`' + #define _CONSOLE_COLOR_MASK 0x7F + +/* Help Colors +*/ +#if 1 // USE_APPLE_FONT + // Console Help Color + #define CHC_DEFAULT "`0" + #define CHC_USAGE "`3" + #define CHC_CATEGORY "`6" + #define CHC_COMMAND "`2" + #define CHC_KEY "`1" + #define CHC_ARG_MAND "`7" // < > + #define CHC_ARG_OPT "`4" // [ ] + #define CHC_ARG_SEP "`9" // | grey + #define CHC_NUM_DEC "`6" // cyan looks better then yellow + #define CHC_NUM_HEX "`3" + #define CHC_SYMBOL "`2" + #define CHC_ADDRESS "`8" + #define CHC_ERROR "`1" + #define CHC_STRING "`6" + #define CHC_EXAMPLE "`5" +#else + #define CHC_DEFAULT "" + #define CHC_USAGE "" + #define CHC_COMMAND "" + #define CHC_KEY "" + #define CHC_ARG_MAND "" + #define CHC_ARG_OPT "" + #define CHC_ARG_SEP "" + #define CHC_NUMBER "" + #define CHC_SYMBOL "" + #define CHC_ADDRESS "" + #define CHC_ERROR "" + #define CHC_STRING "" + #define CHC_EXAMPLE "" +#endif + + // ascii markup + inline bool ConsoleColor_IsCharMeta( unsigned char c ) + { + if (CONSOLE_COLOR_ESCAPE_CHAR == c) + return true; + return false; + } + + inline bool ConsoleColor_IsCharColor( unsigned char c ) + { + if ((c >= '0') && ((c - '0') < NUM_CONSOLE_COLORS)) + return true; + return false; + } + + // Console "Native" Chars + // + // There are a few different ways of encoding color chars & mouse text + // Simplist method is to use a user-defined ESCAPE char to shift + // into color mode, or mouse text mode. The other solution + // is to use a wide-char, simulating unicode16. + // + // C1C0 char16 of High Byte (c1) and Low Byte (c0) + // 1) --?? Con: Colors chars take up extra chars. + // Con: String Length is complicated. + // Pro: simple to parse + // + // <-- WE USE THIS + // 2) ccea Pro: Efficient packing of plain text and mouse text + // Pro: Color is optional (only record new color) + // Con: need to provide char8 and char16 API + // Con: little more difficult to parse/convert plain text + // i.e. + // ea = 0x20 - 0x7F ASCII + // 0x80 - 0xFF Mouse Text '@'-'Z' -> 0x00 - 0x1F + // cc = ASCII '0' - '9' (color) + // 3) ??cc Con: Colors chars take up extra chars + // 4) f?? Con: Colors chars take up extra chars + // + // Legend: + // f Flag + // -- Not Applicable (n/a) + // ?? ASCII (0x20 - 0x7F) + // ea Extended ASCII with High-Bit representing Mouse Text + // cc Encoded Color / Mouse Text + // + inline bool ConsoleColor_IsColorOrMouse( conchar_t g ) + { + if (g > _CONSOLE_COLOR_MASK) + return true; + return false; + } + + inline bool ConsoleColor_IsColor( conchar_t g ) + { + return ConsoleColor_IsCharColor (g >> 8); + } + + inline COLORREF ConsoleColor_GetColor( conchar_t g ) + { + const int iColor = (g >> 8) - '0'; + if (iColor < NUM_CONSOLE_COLORS) + return g_anConsoleColor[ iColor ]; + + return g_anConsoleColor[ 0 ]; + } + + inline char ConsoleColor_GetMeta( conchar_t g ) + { + return ((g >> 8) & _CONSOLE_COLOR_MASK); + } + + inline char ConsoleChar_GetChar( conchar_t g ) + { + return (g & _CONSOLE_COLOR_MASK); + } + + inline char ConsoleColor_MakeMouse( unsigned char c ) + { + return ((c - '@') + (_CONSOLE_COLOR_MASK + 1)); + } + + inline conchar_t ConsoleColor_MakeMeta( unsigned char c ) + { + conchar_t g = (ConsoleColor_MakeMouse(c) << 8); + return g; + } + + inline conchar_t ConsoleColor_MakeColor( unsigned char color, unsigned char text ) + { + conchar_t g = (color << 8) | text; + return g; + } + +// Globals __________________________________________________________________ + + // Buffer + extern bool g_bConsoleBufferPaused; + extern int g_nConsoleBuffer; + extern conchar_t g_aConsoleBuffer[ CONSOLE_BUFFER_HEIGHT ][ CONSOLE_WIDTH ]; // TODO: stl::vector< line_t > + + // Cursor + extern char g_sConsoleCursor[]; + + // Display + extern char g_aConsolePrompt[];// = TEXT(">!"); // input, assembler // NUM_PROMPTS + extern char g_sConsolePrompt[];// = TEXT(">"); // No, NOT Integer Basic! The nostalgic '*' "Monitor" doesn't look as good, IMHO. :-( + extern int g_nConsolePromptLen; + + extern bool g_bConsoleFullWidth;// = false; + + extern int g_iConsoleDisplayStart ; // to allow scrolling + extern int g_nConsoleDisplayTotal ; // number of lines added to console + extern int g_nConsoleDisplayLines ; + extern int g_nConsoleDisplayWidth ; + extern conchar_t g_aConsoleDisplay[ CONSOLE_HEIGHT ][ CONSOLE_WIDTH ]; + + // Input History + extern int g_nHistoryLinesStart;// = 0; + extern int g_nHistoryLinesTotal;// = 0; // number of commands entered + extern char g_aHistoryLines[ HISTORY_HEIGHT ][ HISTORY_WIDTH ];// = {TEXT("")}; + + // Input Line + // Raw input Line (has prompt) + extern char g_aConsoleInput[ CONSOLE_WIDTH ]; + + // Cooked input line (no prompt) + extern int g_nConsoleInputChars ; + extern char * g_pConsoleInput ; // points to past prompt + extern const char * g_pConsoleFirstArg ; // points to first arg + extern bool g_bConsoleInputQuoted ; + + extern char g_nConsoleInputSkip ; + + +// Prototypes _______________________________________________________________ + +// Console + + // Buffered + bool ConsolePrint( const char * pText ); + void ConsoleBufferToDisplay (); + const conchar_t* ConsoleBufferPeek (); + void ConsoleBufferPop (); + bool ConsoleBufferPush ( const char * pString ); + + void ConsoleConvertFromText( conchar_t * sText, const char * pText ); + + // Display + Update_t ConsoleDisplayError ( const char * pTextError ); + void ConsoleDisplayPause (); + void ConsoleDisplayPush ( const char * pText ); + void ConsoleDisplayPush ( const conchar_t * pText ); + Update_t ConsoleUpdate (); + void ConsoleFlush (); + + // Input + void ConsoleInputToDisplay (); + const char *ConsoleInputPeek (); + bool ConsoleInputClear (); + bool ConsoleInputBackSpace (); + bool ConsoleInputChar ( TCHAR ch ); + void ConsoleInputReset (); + int ConsoleInputTabCompletion (); + + void ConsoleUpdateCursor( char ch ); + + Update_t ConsoleBufferTryUnpause (int nLines); + + // Scrolling + Update_t ConsoleScrollHome (); + Update_t ConsoleScrollEnd (); + Update_t ConsoleScrollUp ( int nLines ); + Update_t ConsoleScrollDn ( int nLines ); + Update_t ConsoleScrollPageUp (); + Update_t ConsoleScrollPageDn (); + +#endif diff --git a/AppleWin/source/Debugger/Debugger_DisassemblerData.cpp b/AppleWin/source/Debugger/Debugger_DisassemblerData.cpp new file mode 100644 index 00000000..20bd0d9b --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_DisassemblerData.cpp @@ -0,0 +1,367 @@ +/* +AppleWin : An Apple //e emulator for Windows + +/* Description: Data Blocks shown in Disassembler + * + * Author: Copyright (C) 2009 Michael Pohoreski + */ + +#include "StdAfx.h" + + +// Disassembler Data ______________________________________________________________________________ + +// __ Debugger Interaface ____________________________________________________________________________ + +//=========================================================================== +WORD _CmdDefineByteRange(int nArgs,int iArg,DisasmData_t & tData_) +{ + WORD nAddress = 0; + WORD nAddress2 = 0; + WORD nEnd = 0; + int nLen = 0; + + if( nArgs < 2 ) + { + nAddress = g_nDisasmCurAddress; + } + else + { + RangeType_t eRange = Range_Get( nAddress, nAddress2, iArg); + if ((eRange == RANGE_HAS_END) || + (eRange == RANGE_HAS_LEN)) + { + Range_CalcEndLen( eRange, nAddress, nAddress2, nEnd, nLen ); + //dArg = 2; + } + else + { + nAddress = g_aArgs[ 2 ].nValue; + } + } + + if (!nLen) + { + nLen = 1; + } + + tData_.nStartAddress = nAddress; + tData_.nEndAddress = nAddress + nLen; + + char *pSymbolName = ""; + if( nArgs ) + { + pSymbolName = g_aArgs[ 1 ].sArg; + SymbolTable_Index_e eSymbolTable = SYMBOLS_ASSEMBLY; + // bRemoveSymbol = false // use arg[2] + // bUpdateSymbol = true // add the symbol to the table + SymbolUpdate( eSymbolTable, pSymbolName, nAddress, false, true ); + // Note: need to call ConsoleUpdate(), as may print symbol has been updated + } + else + { + // TODO: 'DB' with no args, should define D_# DB $XX + } + + strcpy( tData_.sSymbol, pSymbolName ); + + return nAddress; +} + +// Undefine Data +//=========================================================================== +Update_t CmdDisasmDataDefCode (int nArgs) +{ + // treat memory (bytes) as code + if (! ((nArgs <= 2) || (nArgs == 4))) + { + return Help_Arg_1( CMD_DISASM_CODE ); + } + + DisasmData_t tData; + int iArg = 2; + WORD nAddress = _CmdDefineByteRange( nArgs, iArg, tData ); + + // Need to iterate through all blocks + // DB TEST1 300:320 + // DB TEST2 310:330 + // DB TEST3 320:340 + // !DB 300 + + DisasmData_t *pData = Disassembly_IsDataAddress( nAddress ); + if( pData ) + { + // Need to split the data +// *pData = tData; + Disassembly_AddData( tData ); + } + else + { + Disassembly_DelData( tData ); + } + + return UPDATE_DISASM | ConsoleUpdate(); +} + +// List the data blocks +//=========================================================================== +Update_t CmdDisasmDataList (int nArgs) +{ + // Need to iterate through all blocks + DisasmData_t* pData = NULL; + char sText[ CONSOLE_WIDTH ]; + while( pData = Disassembly_Enumerate( pData ) ) + { + // `TEST `300`:`320 + sprintf( sText, "%s%s %s%04X%s:%s%04X\n" + , CHC_SYMBOL + , pData->sSymbol + , CHC_ADDRESS + , pData->nStartAddress + , CHC_ARG_SEP + , pData->nEndAddress + ); + ConsolePrint( sText ); + } + + return UPDATE_DISASM | ConsoleUpdate(); +} + +// Common code +//=========================================================================== +Update_t _CmdDisasmDataDefByteX (int nArgs) +{ + // DB + // DB symbol + // DB symbol address + // symbol range:range + int iCmd = NOP_BYTE_1 - g_aArgs[0].nValue; + + if (! ((nArgs <= 2) || (nArgs == 4))) + { + return Help_Arg_1( CMD_DEFINE_DATA_BYTE1 + iCmd ); + } + + DisasmData_t tData; + int iArg = 2; + WORD nAddress = _CmdDefineByteRange( nArgs, iArg, tData ); + + tData.iDirective = FIRST_M_DIRECTIVE + ASM_M_DEFINE_BYTE; + tData.eElementType = NOP_BYTE_1 + iCmd; + tData.bSymbolLookup = false; + tData.nTargetAddress = 0; + + // Already exists, so update + DisasmData_t *pData = Disassembly_IsDataAddress( nAddress ); + if( pData ) + { + *pData = tData; + } + else + Disassembly_AddData( tData ); + + return UPDATE_DISASM | ConsoleUpdate(); +} + +//=========================================================================== +Update_t _CmdDisasmDataDefWordX (int nArgs) +{ + // DW + // DW symbol + // DW symbol address + // symbol range:range + int iCmd = NOP_WORD_1 - g_aArgs[0].nValue; + + if (! ((nArgs <= 2) || (nArgs == 4))) + { + return Help_Arg_1( CMD_DEFINE_DATA_WORD1 + iCmd ); + } + + DisasmData_t tData; + int iArg = 2; + WORD nAddress = _CmdDefineByteRange( nArgs, iArg, tData ); + + tData.iDirective = FIRST_M_DIRECTIVE + ASM_M_DEFINE_WORD; + tData.eElementType = NOP_WORD_1 + iCmd; + tData.bSymbolLookup = false; + tData.nTargetAddress = 0; + + // Already exists, so update + DisasmData_t *pData = Disassembly_IsDataAddress( nAddress ); + if( pData ) + { + *pData = tData; + } + else + Disassembly_AddData( tData ); + + return UPDATE_DISASM | ConsoleUpdate(); +} + +//=========================================================================== +Update_t CmdDisasmDataDefAddress8H (int nArgs) +{ + return UPDATE_DISASM; +} + +//=========================================================================== +Update_t CmdDisasmDataDefAddress8L (int nArgs) +{ + return UPDATE_DISASM; +} + +//=========================================================================== +Update_t CmdDisasmDataDefAddress16 (int nArgs) +{ + return UPDATE_DISASM; +} + +Update_t CmdDisasmDataDefByte1 ( int nArgs ) +{ + g_aArgs[0].nValue = NOP_BYTE_1; + return _CmdDisasmDataDefByteX( nArgs ); +} + +Update_t CmdDisasmDataDefByte2 ( int nArgs ) +{ + g_aArgs[0].nValue = NOP_BYTE_2; + return _CmdDisasmDataDefByteX( nArgs ); +} + +Update_t CmdDisasmDataDefByte4 ( int nArgs ) +{ + g_aArgs[0].nValue = NOP_BYTE_4; + return _CmdDisasmDataDefByteX( nArgs ); +} + +Update_t CmdDisasmDataDefByte8 ( int nArgs ) +{ + g_aArgs[0].nValue = NOP_BYTE_8; + return _CmdDisasmDataDefByteX( nArgs ); +} + +Update_t CmdDisasmDataDefWord1 ( int nArgs ) +{ + g_aArgs[0].nValue = NOP_WORD_1; + return _CmdDisasmDataDefWordX( nArgs ); +} + +Update_t CmdDisasmDataDefWord2 ( int nArgs ) +{ + g_aArgs[0].nValue = NOP_WORD_2; + return _CmdDisasmDataDefWordX( nArgs ); +} + +Update_t CmdDisasmDataDefWord4 ( int nArgs ) +{ + g_aArgs[0].nValue = NOP_WORD_4; + return _CmdDisasmDataDefWordX( nArgs ); +} + +Update_t CmdDisasmDataDefString ( int nArgs ) +{ + return UPDATE_DISASM; +} + +// __ Disassembler View Interface ____________________________________________________________________ + +/// @param pCurrent NULL start a new serch, or continue enumerating +//=========================================================================== +DisasmData_t* Disassembly_Enumerate( DisasmData_t *pCurrent ) +{ + DisasmData_t *pData = NULL; // bIsNopcode = false + int nDataTargets = g_aDisassemblerData.size(); + + if( pCurrent ) + { + pCurrent++; + pData = & g_aDisassemblerData[ nDataTargets ]; + if( pCurrent < pData ) + return pCurrent; + else + return NULL; + } + else + { + pData = & g_aDisassemblerData[ 0 ]; + if( nDataTargets ) + return pData; + else + return NULL; + } +} + +// returns NULL if address has no data associated with it +//=========================================================================== +DisasmData_t* Disassembly_IsDataAddress ( WORD nAddress ) +{ + DisasmData_t *pData = NULL; // bIsNopcode = false + int nDataTargets = g_aDisassemblerData.size(); + + if( nDataTargets ) + { + // TODO: Replace with binary search -- should store data in sorted order, via start address + pData = & g_aDisassemblerData[ 0 ]; + for( int iTarget = 0; iTarget < nDataTargets; iTarget++ ) + { + if( (nAddress >= pData->nStartAddress) && (nAddress < pData->nEndAddress) ) + { + return pData; + } + pData++; + } + pData = NULL; // bIsNopCode = false + } + return pData; +} + +//=========================================================================== +void Disassembly_AddData( DisasmData_t tData) +{ + g_aDisassemblerData.push_back( tData ); +} + +//=========================================================================== +void Disassembly_GetData ( WORD nBaseAddress, const DisasmData_t *pData, DisasmLine_t & line_ ) +{ + line_.ClearFlags(); + + line_.iNoptype = pData->eElementType; + switch( pData->eElementType ) + { + case NOP_BYTE_1: + line_.nOpbyte = 1; + break; + case NOP_BYTE_2: + line_.nOpbyte = 2; + break; + case NOP_WORD_1: + line_.nOpbyte= 2; + break; + case NOP_WORD_2: + line_.nOpbyte= 4; + break; + case NOP_STRING_APPLESOFT: + // scan memory for high byte + line_.nOpbyte = 8; + break; + default: + line_.nOpbyte = 1; + break; + } + + FormatOpcodeBytes( nBaseAddress, line_ ); + + //pMnemonic = g_aOpcodes[ iOpcode ].sMnemonic; + line_.iNopcode = pData->iDirective; + strcpy( line_.sMnemonic, g_aAssemblerDirectives[ line_.iNopcode ].m_pMnemonic ); + + FormatNopcodeBytes( nBaseAddress, line_ ); +} + +//=========================================================================== +void Disassembly_DelData( DisasmData_t tData) +{ + // g_aDisassemblerData.erase( ); +} + diff --git a/AppleWin/source/Debugger/Debugger_DisassemblerData.h b/AppleWin/source/Debugger/Debugger_DisassemblerData.h new file mode 100644 index 00000000..8d83b3fc --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_DisassemblerData.h @@ -0,0 +1,55 @@ +#ifndef DEBUGGER_DISASSEMBLERDATA_H +#define DEBUGGER_DISASSEMBLERDATA_H + + enum NopcodeType_e + { + NOP_BYTE_1 // 1 bytes/line + ,NOP_BYTE_2 // 2 bytes/line + ,NOP_BYTE_4 // 4 bytes/line + ,NOP_BYTE_8 // 8 bytes/line + ,NOP_WORD_1 // 1 words/line + ,NOP_WORD_2 // 2 words/line + ,NOP_WORD_4 // 4 words/line + ,NOP_ADDRESS// 1 word/line + ,NOP_HEX + ,NOP_CHAR + ,NOP_STRING_ASCII + ,NOP_STRING_APPLE + ,NOP_STRING_APPLESOFT + ,NOP_FAC + ,NUM_NOPCODE_TYPES + }; + + // Disassembler Data + // type symbol[start:end] + struct DisasmData_t + { + char sSymbol[ MAX_SYMBOLS_LEN+1 ]; + WORD iDirective ; // Assembler directive -> nopcode + WORD nStartAddress; // link to block [start,end) + WORD nEndAddress ; + WORD nArraySize ; // Total bytes +// WORD nBytePerRow ; // 1, 8 + char eElementType; // + + // with symbol lookup + char bSymbolLookup ; + WORD nTargetAddress; + }; + + Update_t _CmdDisasmDataDefByteX (int nArgs); + Update_t _CmdDisasmDataDefWordX (int nArgs); + +// Data Disassembler ______________________________________________________________________________ + + int Disassembly_FindOpcode( WORD nAddress ); + DisasmData_t* Disassembly_IsDataAddress( WORD nAddress ); + + void Disassembly_AddData( DisasmData_t tData); + void Disassembly_GetData ( WORD nBaseAddress, const DisasmData_t *pData_, DisasmLine_t & line_ ); + void Disassembly_DelData( DisasmData_t tData); + DisasmData_t* Disassembly_Enumerate( DisasmData_t *pCurrent = NULL ); + + extern vector g_aDisassemblerData; + +#endif diff --git a/AppleWin/source/Debugger/Debugger_Display.cpp b/AppleWin/source/Debugger/Debugger_Display.cpp new file mode 100644 index 00000000..b0cb9ad7 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Display.cpp @@ -0,0 +1,3383 @@ +/* +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-2007, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Debugger + * + * Author: Copyright (C) 2006, Michael Pohoreski + */ + +#include "StdAfx.h" + + +// NEW UI debugging +#define DEBUG_FORCE_DISPLAY 0 + +#if _DEBUG + #define DEBUG_FONT_NO_BACKGROUND_CHAR 0 + #define DEBUG_FONT_NO_BACKGROUND_TEXT 0 + #define DEBUG_FONT_NO_BACKGROUND_FILL_CON 0 + #define DEBUG_FONT_NO_BACKGROUND_FILL_INFO 0 + #define DEBUG_FONT_NO_BACKGROUND_FILL_MAIN 0 + + // no top console line + #define DEBUG_BACKGROUND 0 +#endif + +//#define WATCH_ZERO_BG BG_DATA_1 +#define WATCH_ZERO_BG BG_INFO + + #define DISPLAY_MEMORY_TITLE 1 +// #define DISPLAY_BREAKPOINT_TITLE 1 +// #define DISPLAY_WATCH_TITLE 1 + +// Public _________________________________________________________________________________________ + +// Font + FontConfig_t g_aFontConfig[ NUM_FONTS ]; + +// Private ________________________________________________________________________________________ + +// Display - Win32 +// HDC g_hDstDC = NULL; // App Window + + HDC g_hConsoleFontDC = NULL; + HBRUSH g_hConsoleFontBrush = NULL; + HBITMAP g_hConsoleFontBitmap = NULL; + + HBRUSH g_hConsoleBrushFG = NULL; + HBRUSH g_hConsoleBrushBG = NULL; + + COLORREF g_anConsoleColor[ NUM_CONSOLE_COLORS ] = + { + RGB( 0, 0, 0 ), // 0 000 K + RGB( 255, 32, 32 ), // 1 001 R + RGB( 0, 255, 0 ), // 2 010 G + RGB( 255, 255, 0 ), // 3 011 Y + RGB( 64, 64, 255 ), // 4 100 B +// RGB( 255, 0, 255 ), // 5 101 M Purple/Magenta is useless + RGB( 80, 192, 255 ), + RGB( 0, 255, 255 ), // 6 110 C + RGB( 255, 255, 255 ), // 7 111 W + RGB( 255, 128, 0 ), // 8 Orange + RGB( 128, 128, 128 ) // 9 Grey + }; + +// 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 + char * g_sConfigBranchIndicatorUp [ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "^", "\x8B" }; // "`K" 0x4B + char * g_sConfigBranchIndicatorEqual[ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "=", "\x88" }; // "`H" 0x48 + char * g_sConfigBranchIndicatorDown [ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "v", "\x8A" }; // "`J" 0x4A +#else + char * g_sConfigBranchIndicatorUp [ NUM_DISASM_BRANCH_TYPES+1 ] = { " ", "^", "\x35" }; + 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; + // New Font = 50.5 char * 7 px/char = 353.5 + const int DISPLAY_DISASM_RIGHT = 353 ; + +#if USE_APPLE_FONT + // Horizontal Column (pixels) of Stack & Regs + const int INFO_COL_1 = (51 * 7); // nFontWidth + const int DISPLAY_REGS_COLUMN = INFO_COL_1; + const int DISPLAY_FLAG_COLUMN = INFO_COL_1; + const int DISPLAY_STACK_COLUMN = INFO_COL_1; + const int DISPLAY_TARGETS_COLUMN = INFO_COL_1; + const int DISPLAY_ZEROPAGE_COLUMN= INFO_COL_1; + + // Horizontal Column (pixels) of BPs, Watches & Mem + const int INFO_COL_2 = (62 * 7); // nFontWidth + const int DISPLAY_BP_COLUMN = INFO_COL_2; + const int DISPLAY_WATCHES_COLUMN = INFO_COL_2; + const int DISPLAY_MINIMEM_COLUMN = INFO_COL_2; +#else + const int DISPLAY_REGS_COLUMN = SCREENSPLIT1; + const int DISPLAY_FLAG_COLUMN = SCREENSPLIT1; // + 63; + const int DISPLAY_STACK_COLUMN = SCREENSPLIT1; + const int DISPLAY_TARGETS_COLUMN = SCREENSPLIT1; + const int DISPLAY_ZEROPAGE_COLUMN= SCREENSPLIT1; + + const int SCREENSPLIT2 = SCREENSPLIT1 + (12 * 7); // moved left 3 chars to show B. prefix in breakpoint #, W. prefix in watch # + const int DISPLAY_BP_COLUMN = SCREENSPLIT2; + const int DISPLAY_WATCHES_COLUMN = SCREENSPLIT2; + const int DISPLAY_MINIMEM_COLUMN = SCREENSPLIT2; // nFontWidth +#endif + + int MAX_DISPLAY_REGS_LINES = 7; + int MAX_DISPLAY_STACK_LINES = 8; + int MAX_DISPLAY_ZEROPAGE_LINES = 8; + +// int MAX_DISPLAY_BREAKPOINTS_LINES = 7; // 7 +// int MAX_DISPLAY_WATCHES_LINES = 8; // 8 + int MAX_DISPLAY_MEMORY_LINES_1 = 4; // 4 + int MAX_DISPLAY_MEMORY_LINES_2 = 4; // 4 // 2 + int g_nDisplayMemoryLines; + + // Height +// const int DISPLAY_LINES = 24; // FIXME: Should be pixels + // 304 = bottom of disassembly + // 368 = bottom console + // 384 = 16 * 24 very bottom +// const int DEFAULT_HEIGHT = 16; + +// static HDC g_hDC = 0; + + +static void SetupColorsHiLoBits ( bool bHiBit, bool bLoBit, + const int iBackground, const int iForeground, + const int iColorHiBG , /*const int iColorHiFG, + const int iColorLoBG , */const int iColorLoFG ); +static char ColorizeSpecialChar( char * sText, BYTE nData, const MemoryView_e iView, + const int iTxtBackground = BG_INFO , const int iTxtForeground = FG_DISASM_CHAR, + const int iHighBackground = BG_INFO_CHAR, const int iHighForeground = FG_INFO_CHAR_HI, + const int iLowBackground = BG_INFO_CHAR, const int iLowForeground = FG_INFO_CHAR_LO ); + + char FormatCharTxtAsci ( const BYTE b, bool * pWasAsci_ ); + + void DrawSubWindow_Code ( int iWindow ); + void DrawSubWindow_IO (Update_t bUpdate); + void DrawSubWindow_Source1 (Update_t bUpdate); + void DrawSubWindow_Source2 (Update_t bUpdate); + void DrawSubWindow_Symbols (Update_t bUpdate); + void DrawSubWindow_ZeroPage (Update_t bUpdate); + + void DrawWindowBottom ( Update_t bUpdate, int iWindow ); + + +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_6n77.asp +enum WinROP4_e +{ + DSna = 0x00220326, + DPSao = 0x00EA02E9, +}; + +/* + Reverse Polish Notation + a Bitwise AND + n Bitwise NOT (inverse) + o Bitwise OR + x Bitwise exclusive OR (XOR) + + Pen(P) 1 1 0 0 Decimal Result + Dest(D) 1 0 1 0 Boolean Operation + + R2_BLACK 0 0 0 0 0 0 + R2_NOTMERGEPEN 0 0 0 1 1 ~(P | D) + R2_MASKNOTPEN 0 0 1 0 2 ~P & D + R2_NOTCOPYPEN 0 0 1 1 3 ~P + R2_MASKPENNOT 0 1 0 0 4 P & ~D + R2_NOT 0 1 0 1 5 ~D + R2_XORPEN 0 1 1 0 6 P ^ D + R2_NOTMASKPEN 0 1 1 1 7 ~(P & D) + R2_MASKPEN 1 0 0 0 8 P & D + R2_NOTXORPEN 1 0 0 1 9 ~(P ^ D) + R2_NOPR2_NOP 1 0 1 0 10 D + R2_MERGENOTPEN 1 0 1 1 11 ~P | D + R2_COPYPEN 1 1 0 0 12 P (default) + R2_MERGEPENNOT 1 1 0 1 13 P | ~D + R2_MERGEPEN 1 1 1 0 14 P | D + R2_WHITE 1 1 1 1 15 1 +*/ + +#if DEBUG_FONT_ROP +const DWORD aROP4[ 256 ] = +{ + 0x00000042, // BLACKNESS + 0x00010289, // DPSoon + 0x00020C89, // DPSona + 0x000300AA, // PSon + 0x00040C88, // SDPona + 0x000500A9, // DPon + 0x00060865, // PDSxnon + 0x000702C5, // PDSaon + 0x00080F08, // SDPnaa + 0x00090245, // PDSxon + 0x000A0329, // DPna + 0x000B0B2A, // PSDnaon + 0x000C0324, // SPna + 0x000D0B25, // PDSnaon + 0x000E08A5, // PDSonon + 0x000F0001, // Pn + 0x00100C85, // PDSona + 0x001100A6, // DSon NOTSRCERASE + 0x00120868, // SDPxnon + 0x001302C8, // SDPaon + 0x00140869, // DPSxnon + 0x001502C9, // DPSaon + 0x00165CCA, // PSDPSanaxx // 16 + 0x00171D54, // SSPxDSxaxn + 0x00180D59, // SPxPDxa + 0x00191CC8, // SDPSanaxn + 0x001A06C5, // PDSPaox + 0x001B0768, // SDPSxaxn + 0x001C06CA, // PSDPaox + 0x001D0766, // DSPDxaxn + 0x001E01A5, // PDSox + 0x001F0385, // PDSoan + 0x00200F09, // DPSnaa + 0x00210248, // SDPxon + 0x00220326, // DSna + 0x00230B24, // SPDnaon + 0x00240D55, // SPxDSxa + 0x00251CC5, // PDSPanaxn + 0x002606C8, // SDPSaox + 0x00271868, // SDPSxnox + 0x00280369, // DPSxa + 0x002916CA, // PSDPSaoxxn + 0x002A0CC9, // DPSana + 0x002B1D58, // SSPxPDxaxn + 0x002C0784, // SPDSoax + 0x002D060A, // PSDnox + 0x002E064A, // PSDPxox + 0x002F0E2A, // PSDnoan + 0x0030032A, // PSna + 0x00310B28, // SDPnaon + 0x00320688, // SDPSoox + 0x00330008, // Sn // 33 NOTSRCCOPY + 0x003406C4, // SPDSaox + 0x00351864, // SPDSxnox + 0x003601A8, // SDPox + 0x00370388, // SDPoan + 0x0038078A, // PSDPoax + 0x00390604, // SPDnox + 0x003A0644, // SPDSxox + 0x003B0E24, // SPDnoan + 0x003C004A, // PSx + 0x003D18A4, // SPDSonox + 0x003E1B24, // SPDSnaox + 0x003F00EA, // PSan + 0x00400F0A, // PSDnaa + 0x00410249, // DPSxon + 0x00420D5D, // SDxPDxa + 0x00431CC4, // SPDSanaxn + 0x00440328, // SDna // 44 SRCERASE + 0x00450B29, // DPSnaon + 0x004606C6, // DSPDaox + 0x0047076A, // PSDPxaxn + 0x00480368, // SDPxa + 0x004916C5, // PDSPDaoxxn + 0x004A0789, // DPSDoax + 0x004B0605, // PDSnox + 0x004C0CC8, // SDPana + 0x004D1954, // SSPxDSxoxn + 0x004E0645, // PDSPxox + 0x004F0E25, // PDSnoan + 0x00500325, // PDna + 0x00510B26, // DSPnaon + 0x005206C9, // DPSDaox + 0x00530764, // SPDSxaxn + 0x005408A9, // DPSonon + 0x00550009, // Dn // 55 DSTINVERT + 0x005601A9, // DPSox + 0x00570389, // DPSoan + 0x00580785, // PDSPoax + 0x00590609, // DPSnox + 0x005A0049, // DPx // 5A PATINVERT + 0x005B18A9, // DPSDonox + 0x005C0649, // DPSDxox + 0x005D0E29, // DPSnoan + 0x005E1B29, // DPSDnaox + 0x005F00E9, // DPan + 0x00600365, // PDSxa + 0x006116C6, // DSPDSaoxxn + 0x00620786, // DSPDoax + 0x00630608, // SDPnox + 0x00640788, // SDPSoax + 0x00650606, // DSPnox + 0x00660046, // DSx // 66 SRCINVERT + 0x006718A8, // SDPSonox + 0x006858A6, // DSPDSonoxxn + 0x00690145, // PDSxxn + 0x006A01E9, // DPSax + 0x006B178A, // PSDPSoaxxn + 0x006C01E8, // SDPax + 0x006D1785, // PDSPDoaxxn + 0x006E1E28, // SDPSnoax + 0x006F0C65, // PDSxnan + 0x00700CC5, // PDSana + 0x00711D5C, // SSDxPDxaxn + 0x00720648, // SDPSxox + 0x00730E28, // SDPnoan + 0x00740646, // DSPDxox + 0x00750E26, // DSPnoan + 0x00761B28, // SDPSnaox + 0x007700E6, // DSan + 0x007801E5, // PDSax + 0x00791786, // DSPDSoaxxn + 0x007A1E29, // DPSDnoax + 0x007B0C68, // SDPxnan + 0x007C1E24, // SPDSnoax + 0x007D0C69, // DPSxnan + 0x007E0955, // SPxDSxo + 0x007F03C9, // DPSaan + 0x008003E9, // DPSaa + 0x00810975, // SPxDSxon + 0x00820C49, // DPSxna + 0x00831E04, // SPDSnoaxn + 0x00840C48, // SDPxna + 0x00851E05, // PDSPnoaxn + 0x008617A6, // DSPDSoaxx + 0x008701C5, // PDSaxn + 0x008800C6, // DSa // 88 SRCAND + 0x00891B08, // SDPSnaoxn + 0x008A0E06, // DSPnoa + 0x008B0666, // DSPDxoxn + 0x008C0E08, // SDPnoa + 0x008D0668, // SDPSxoxn + 0x008E1D7C, // SSDxPDxax + 0x008F0CE5, // PDSanan + 0x00900C45, // PDSxna + 0x00911E08, // SDPSnoaxn + 0x009217A9, // DPSDPoaxx + 0x009301C4, // SPDaxn + 0x009417AA, // PSDPSoaxx + 0x009501C9, // DPSaxn + 0x00960169, // DPSxx + 0x0097588A, // PSDPSonoxx + 0x00981888, // SDPSonoxn + 0x00990066, // DSxn + 0x009A0709, // DPSnax + 0x009B07A8, // SDPSoaxn + 0x009C0704, // SPDnax + 0x009D07A6, // DSPDoaxn + 0x009E16E6, // DSPDSaoxx + 0x009F0345, // PDSxan + 0x00A000C9, // DPa + 0x00A11B05, // PDSPnaoxn + 0x00A20E09, // DPSnoa + 0x00A30669, // DPSDxoxn + 0x00A41885, // PDSPonoxn + 0x00A50065, // PDxn + 0x00A60706, // DSPnax + 0x00A707A5, // PDSPoaxn + 0x00A803A9, // DPSoa + 0x00A90189, // DPSoxn + 0x00AA0029, // D // AA DSTCOPY + 0x00AB0889, // DPSono + 0x00AC0744, // SPDSxax + 0x00AD06E9, // DPSDaoxn + 0x00AE0B06, // DSPnao + 0x00AF0229, // DPno + 0x00B00E05, // PDSnoa + 0x00B10665, // PDSPxoxn + 0x00B21974, // SSPxDSxox + 0x00B30CE8, // SDPanan + 0x00B4070A, // PSDnax + 0x00B507A9, // DPSDoaxn + 0x00B616E9, // DPSDPaoxx + 0x00B70348, // SDPxan + 0x00B8074A, // PSDPxax + 0x00B906E6, // DSPDaoxn + 0x00BA0B09, // DPSnao + 0x00BB0226, // DSno // BB MERGEPAINT + 0x00BC1CE4, // SPDSanax + 0x00BD0D7D, // SDxPDxan + 0x00BE0269, // DPSxo + 0x00BF08C9, // DPSano + 0x00C000CA, // PSa // C0 MERGECOPY + 0x00C11B04, // SPDSnaoxn + 0x00C21884, // SPDSonoxn + 0x00C3006A, // PSxn + 0x00C40E04, // SPDnoa + 0x00C50664, // SPDSxoxn + 0x00C60708, // SDPnax + 0x00C707AA, // PSDPoaxn + 0x00C803A8, // SDPoa + 0x00C90184, // SPDoxn + 0x00CA0749, // DPSDxax + 0x00CB06E4, // SPDSaoxn + 0x00CC0020, // S // CC SRCCOPY + 0x00CD0888, // SDPono + 0x00CE0B08, // SDPnao + 0x00CF0224, // SPno + 0x00D00E0A, // PSDnoa + 0x00D1066A, // PSDPxoxn + 0x00D20705, // PDSnax + 0x00D307A4, // SPDSoaxn + 0x00D41D78, // SSPxPDxax + 0x00D50CE9, // DPSanan + 0x00D616EA, // PSDPSaoxx + 0x00D70349, // DPSxan + 0x00D80745, // PDSPxax + 0x00D906E8, // SDPSaoxn + 0x00DA1CE9, // DPSDanax + 0x00DB0D75, // SPxDSxan + 0x00DC0B04, // SPDnao + 0x00DD0228, // SDno + 0x00DE0268, // SDPxo + 0x00DF08C8, // SDPano + 0x00E003A5, // PDSoa + 0x00E10185, // PDSoxn + 0x00E20746, // DSPDxax + 0x00E306EA, // PSDPaoxn + 0x00E40748, // SDPSxax + 0x00E506E5, // PDSPaoxn + 0x00E61CE8, // SDPSanax + 0x00E70D79, // SPxPDxan + 0x00E81D74, // SSPxDSxax + 0x00E95CE6, // DSPDSanaxxn + 0x00EA02E9, // DPSao + 0x00EB0849, // DPSxno + 0x00EC02E8, // SDPao + 0x00ED0848, // SDPxno + 0x00EE0086, // DSo // EE SRCPAINT + 0x00EF0A08, // SDPnoo + 0x00F00021, // P // F0 PATCOPY + 0x00F10885, // PDSono + 0x00F20B05, // PDSnao + 0x00F3022A, // PSno + 0x00F40B0A, // PSDnao + 0x00F50225, // PDno + 0x00F60265, // PDSxo + 0x00F708C5, // PDSano + 0x00F802E5, // PDSao + 0x00F90845, // PDSxno + 0x00FA0089, // DPo + 0x00FB0A09, // DPSnoo // FB PATPAINT + 0x00FC008A, // PSo + 0x00FD0A0A, // PSDnoo + 0x00FE02A9, // DPSoo + 0x00FF0062 // _WHITE // FF WHITENESS +}; +#endif + + // PATPAINT + // MERGECOPY + // SRCINVERT + // SRCCOPY + // 0xAA00EC + // 0x00EC02E8 + +#if DEBUG_FONT_ROP + static iRop4 = 0; +#endif + +// Font: Apple Text +//=========================================================================== +void DebuggerSetColorFG( COLORREF nRGB ) +{ +#if USE_APPLE_FONT + if (g_hConsoleBrushFG) + { + SelectObject( g_hFrameDC, GetStockObject(NULL_BRUSH) ); + DeleteObject( g_hConsoleBrushFG ); + g_hConsoleBrushFG = NULL; + } + + g_hConsoleBrushFG = CreateSolidBrush( nRGB ); +#else + SetTextColor( g_hFrameDC, nRGB ); +#endif +} + +//=================================================== +void DebuggerSetColorBG( COLORREF nRGB, bool bTransparent ) +{ +#if USE_APPLE_FONT + if (g_hConsoleBrushBG) + { + SelectObject( g_hFrameDC, GetStockObject(NULL_BRUSH) ); + DeleteObject( g_hConsoleBrushBG ); + g_hConsoleBrushBG = NULL; + } + + if (! bTransparent) + { + g_hConsoleBrushBG = CreateSolidBrush( nRGB ); + } +#else + SetBkColor( g_hFrameDC, nRGB ); +#endif +} + +// @param glyph Specifies a native glyph from the 16x16 chars Apple Font Texture. +//=========================================================================== +void PrintGlyph( const int x, const int y, const char glyph ) +{ + HDC g_hDstDC = FrameGetDC(); + + int xDst = x; + int yDst = y; + + // 16x8 chars in bitmap + int xSrc = (glyph & 0x0F) * CONSOLE_FONT_GRID_X; + int ySrc = (glyph >> 4) * CONSOLE_FONT_GRID_Y; + +#if !DEBUG_FONT_NO_BACKGROUND_CHAR + // Background color + if (g_hConsoleBrushBG) + { + SelectObject( g_hDstDC, g_hConsoleBrushBG ); + + // Draw Background (solid pattern) + BitBlt( + g_hFrameDC, // hdcDest + xDst, yDst, // nXDest, nYDest + CONSOLE_FONT_WIDTH, CONSOLE_FONT_HEIGHT, // nWidth, nHeight + g_hConsoleFontDC, // hdcSrc + 0, CONSOLE_FONT_GRID_Y * 2, // nXSrc, nYSrc // FontTexture[2][0] = Solid (Filled) Space + PATCOPY // dwRop + ); + } +#endif + +// SelectObject( g_hDstDC, GetStockBrush( WHITE_BRUSH ) ); + + // http://kkow.net/etep/docs/rop.html + // P 1 1 1 1 0 0 0 0 (Pen/Pattern) + // S 1 1 0 0 1 1 0 0 (Source) + // D 1 0 1 0 1 0 1 0 (Destination) + // ================= + // 0 0 1 0 0 0 1 0 0x22 DSna + // 1 1 1 0 1 0 1 0 0xEA DPSao + + // Black = Transparent (DC Background) + // White = Opaque (DC Text color) + +#if DEBUG_FONT_ROP + SelectObject( g_hDstDC, g_hConsoleBrushFG ); + BitBlt( + g_hFrameDC, + xDst, yDst, + DEBUG_FONT_WIDTH, DEBUG_FONT_HEIGHT, + g_hDebugFontDC, + xSrc, ySrc, + aROP4[ iRop4 ] + ); +#else + // Use inverted source as mask (AND) + // D & ~S -> DSna + BitBlt( + g_hFrameDC, + xDst, yDst, + CONSOLE_FONT_WIDTH, CONSOLE_FONT_HEIGHT, + g_hConsoleFontDC, + xSrc, ySrc, + DSna + ); + + SelectObject( g_hDstDC, g_hConsoleBrushFG ); + + // Use Source ask mask to make color Pattern mask (AND), then apply to dest (OR) + // D | (P & S) -> DPSao + BitBlt( + g_hFrameDC, + xDst, yDst, + CONSOLE_FONT_WIDTH, CONSOLE_FONT_HEIGHT, + g_hConsoleFontDC, + xSrc, ySrc, + DPSao + ); +#endif + + SelectObject( g_hFrameDC, GetStockObject(NULL_BRUSH) ); +} + + +//=========================================================================== +void DebuggerPrint ( int x, int y, const char *pText ) +{ + const int nLeft = x; + + char c; + const char *p = pText; + + while (c = *p) + { + if (c == '\n') + { + x = nLeft; + y += CONSOLE_FONT_HEIGHT; + p++; + continue; + } + c &= 0x7F; + PrintGlyph( x, y, c ); + x += CONSOLE_FONT_WIDTH; + p++; + } +} + +//=========================================================================== +void DebuggerPrintColor( int x, int y, const conchar_t * pText ) +{ + int nLeft = x; + + conchar_t g; + const conchar_t *pSrc = pText; + + if( !pText) + return; + + while (g = (*pSrc)) + { + if (g == '\n') + { + x = nLeft; + y += CONSOLE_FONT_HEIGHT; + pSrc++; + continue; + } + + if (ConsoleColor_IsColorOrMouse( g )) + { + if (ConsoleColor_IsColor( g )) + { + DebuggerSetColorFG( ConsoleColor_GetColor( g ) ); + } + + g = ConsoleChar_GetChar( g ); + } + + PrintGlyph( x, y, (char) (g & _CONSOLE_COLOR_MASK) ); + x += CONSOLE_FONT_WIDTH; + pSrc++; + } +} + + +// Utility ________________________________________________________________________________________ + + +//=========================================================================== +bool CanDrawDebugger() +{ + if (g_bDebuggerViewingAppleOutput) + return false; + + if ((g_nAppMode == MODE_DEBUG) || (g_nAppMode == MODE_STEPPING)) + return true; + + return false; +} + + +//=========================================================================== +int PrintText ( const char * pText, RECT & rRect ) +{ +#if _DEBUG + if (! pText) + MessageBox( NULL, "pText = NULL!", "DrawText()", MB_OK ); +#endif + + int nLen = strlen( pText ); + +#if !DEBUG_FONT_NO_BACKGROUND_TEXT + FillRect( g_hFrameDC, &rRect, g_hConsoleBrushBG ); +#endif + + DebuggerPrint( rRect.left, rRect.top, pText ); + return nLen; +} + +//=========================================================================== +void PrintTextColor ( const conchar_t *pText, RECT & rRect ) +{ +#if !DEBUG_FONT_NO_BACKGROUND_TEXT + FillRect( g_hFrameDC, &rRect, g_hConsoleBrushBG ); +#endif + + DebuggerPrintColor( rRect.left, rRect.top, pText ); +} + +// Updates the horizontal cursor +//=========================================================================== +int PrintTextCursorX ( const char * pText, RECT & rRect ) +{ + int nChars = 0; + if (pText) + { + nChars = PrintText( pText, rRect ); + int nFontWidth = g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontWidthAvg; + rRect.left += (nFontWidth * nChars); + } + return nChars; +} + +//=========================================================================== +int PrintTextCursorY ( const char * pText, RECT & rRect ) +{ + int nChars = PrintText( pText, rRect ); + rRect.top += g_nFontHeight; + rRect.bottom += g_nFontHeight; + return nChars; +} + +//=========================================================================== +char FormatCharTxtAsci ( const BYTE b, bool * pWasAsci_ ) +{ + if (pWasAsci_) + *pWasAsci_ = false; + + char c = (b & 0x7F); + if (b <= 0x7F) + { + if (pWasAsci_) + { + *pWasAsci_ = true; + } + } + return c; +} + +//=========================================================================== +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; +} + + + + +//=========================================================================== +void SetupColorsHiLoBits ( bool bHighBit, bool bCtrlBit, + const int iBackground, const int iForeground, + const int iColorHiBG , const int iColorHiFG, + const int iColorLoBG , const int iColorLoFG ) +{ + // 4 cases: + // Hi Lo Background Foreground -> just map Lo -> FG, Hi -> BG + // 0 0 normal normal BG_INFO FG_DISASM_CHAR (dark cyan bright cyan) + // 0 1 normal LoFG BG_INFO FG_DISASM_OPCODE (dark cyan yellow) + // 1 0 HiBG normal BG_INFO_CHAR FG_DISASM_CHAR (mid cyan bright cyan) + // 1 1 HiBG LoFG BG_INFO_CHAR FG_DISASM_OPCODE (mid cyan yellow) + + DebuggerSetColorBG( DebuggerGetColor( iBackground )); + DebuggerSetColorFG( DebuggerGetColor( iForeground )); + + if (bHighBit) + { + DebuggerSetColorBG( DebuggerGetColor( iColorHiBG )); + DebuggerSetColorFG( DebuggerGetColor( iColorHiFG )); // was iForeground + } + + if (bCtrlBit) + { + DebuggerSetColorBG( DebuggerGetColor( iColorLoBG )); + DebuggerSetColorFG( DebuggerGetColor( iColorLoFG )); + } +} + + +// To flush out color bugs... swap: iAsciBackground & iHighBackground +//=========================================================================== +char ColorizeSpecialChar( char * sText, BYTE nData, const MemoryView_e iView, + const int iAsciBackground /*= 0 */, const int iTextForeground /*= FG_DISASM_CHAR */, + const int iHighBackground /*= BG_INFO_CHAR*/, const int iHighForeground /*= FG_INFO_CHAR_HI*/, + const int iCtrlBackground /*= BG_INFO_CHAR*/, const int iCtrlForeground /*= FG_INFO_CHAR_LO*/ ) +{ + bool bHighBit = false; + bool bAsciBit = false; + bool bCtrlBit = false; + + int iTextBG = iAsciBackground; + int iHighBG = iHighBackground; + int iCtrlBG = iCtrlBackground; + int iTextFG = iTextForeground; + int iHighFG = iHighForeground; + int iCtrlFG = iCtrlForeground; + + BYTE nByte = FormatCharTxtHigh( nData, & bHighBit ); + char nChar = FormatCharTxtCtrl( nByte, & bCtrlBit ); + + switch (iView) + { + case MEM_VIEW_ASCII: + iHighBG = iTextBG; + iCtrlBG = iTextBG; + break; + case MEM_VIEW_APPLE: + iHighBG = iTextBG; + if (!bHighBit) + { + iTextBG = iCtrlBG; + } + + if (bCtrlBit) + { + iTextFG = iCtrlFG; + if (bHighBit) + { + iHighFG = iTextFG; + } + } + bCtrlBit = false; + break; + default: break; + } + + if (sText) + sprintf( sText, "%c", nChar ); + +#if OLD_CONSOLE_COLOR + if (sText) + { + if (ConsoleColor_IsEscapeMeta( nChar )) + sprintf( sText, "%c%c", nChar, nChar ); + else + sprintf( sText, "%c", nChar ); + } +#endif + +// if (hDC) + { + SetupColorsHiLoBits( bHighBit, bCtrlBit + , iTextBG, iTextFG // FG_DISASM_CHAR + , iHighBG, iHighFG // BG_INFO_CHAR + , iCtrlBG, iCtrlFG // FG_DISASM_OPCODE + ); + } + return nChar; +} + + +// Main Windows ___________________________________________________________________________________ + + +//=========================================================================== +void DrawBreakpoints ( int line ) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return; + + RECT rect; + rect.left = DISPLAY_BP_COLUMN; + rect.top = (line * g_nFontHeight); + rect.right = DISPLAY_WIDTH; + rect.bottom = rect.top + g_nFontHeight; + + const int MAX_BP_LEN = 16; + char sText[16] = "Breakpoints"; // TODO: Move to BP1 + +#if DISPLAY_BREAKPOINT_TITLE + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); // COLOR_BG_DATA + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); //COLOR_STATIC + PrintText( sText, rect ); + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; +#endif + + int nBreakpointsDisplayed = 0; + + int iBreakpoint; + for (iBreakpoint = 0; iBreakpoint < MAX_BREAKPOINTS; iBreakpoint++ ) + { + Breakpoint_t *pBP = &g_aBreakpoints[iBreakpoint]; + WORD nLength = pBP->nLength; + +#if DEBUG_FORCE_DISPLAY + nLength = 2; +#endif + if (nLength) + { + bool bSet = pBP->bSet; + bool bEnabled = pBP->bEnabled; + WORD nAddress1 = pBP->nAddress; + WORD nAddress2 = nAddress1 + nLength - 1; + +#if DEBUG_FORCE_DISPLAY +// if (iBreakpoint < MAX_DISPLAY_BREAKPOINTS_LINES) + bSet = true; +#endif + if (! bSet) + continue; + + nBreakpointsDisplayed++; + +// if (nBreakpointsDisplayed > MAX_DISPLAY_BREAKPOINTS_LINES) +// break; + + RECT rect2; + rect2 = rect; + + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE ) ); + sprintf( sText, "B" ); + PrintTextCursorX( sText, rect2 ); + + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_BULLET ) ); + sprintf( sText, "%X ", iBreakpoint ); + PrintTextCursorX( sText, rect2 ); + +// DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR ) ); +// strcpy( sText, "." ); +// PrintTextCursorX( sText, rect2 ); + +#if DEBUG_FORCE_DISPLAY + pBP->eSource = (BreakpointSource_t) iBreakpoint; +#endif + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_REG ) ); + int nRegLen = PrintTextCursorX( g_aBreakpointSource[ pBP->eSource ], rect2 ); + + // Pad to 2 chars + if (nRegLen < 2) + rect2.left += g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; + + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_BULLET ) ); +#if DEBUG_FORCE_DISPLAY + if (iBreakpoint < 3) + pBP->eOperator = (BreakpointOperator_t)(iBreakpoint * 2); +// else +// pBP->eOperator = (BreakpointOperator_t)(iBreakpoint-3 + BP_OP_READ); +#endif + PrintTextCursorX( g_aBreakpointSymbols [ pBP->eOperator ], rect2 ); + + DebugColors_e iForeground; + DebugColors_e iBackground = BG_INFO; + + if (bSet) + { + if (bEnabled) + { + iBackground = BG_DISASM_BP_S_C; +// iForeground = FG_DISASM_BP_S_X; + iForeground = FG_DISASM_BP_S_C; + } + else + { + iForeground = FG_DISASM_BP_0_X; + } + } + else + { + iForeground = FG_INFO_TITLE; + } + + DebuggerSetColorBG( DebuggerGetColor( iBackground ) ); + DebuggerSetColorFG( DebuggerGetColor( iForeground ) ); + +#if DEBUG_FORCE_DISPLAY + extern COLORREF gaColorPalette[ NUM_PALETTE ]; + + int iColor = R8 + iBreakpoint; + COLORREF nColor = gaColorPalette[ iColor ]; + if (iBreakpoint >= 8) + { + DebuggerSetColorBG( DebuggerGetColor( BG_DISASM_BP_S_C ) ); + nColor = DebuggerGetColor( FG_DISASM_BP_S_C ); + } + DebuggerSetColorFG( nColor ); +#endif + + sprintf( sText, "%04X", nAddress1 ); + PrintTextCursorX( sText, rect2 ); + + if (nLength > 1) + { + DebuggerSetColorBG( DebuggerGetColor( BG_INFO ) ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR ) ); + +// if (g_bConfigDisasmOpcodeSpaces) +// { +// PrintTextCursorX( " ", rect2 ); +// rect2.left += g_nFontWidthAvg; +// } + + PrintTextCursorX( ":", rect2 ); +// rect2.left += g_nFontWidthAvg; +// if (g_bConfigDisasmOpcodeSpaces) // TODO: Might have to remove spaces, for BPIO... addr-addr xx +// { +// rect2.left += g_nFontWidthAvg; +// } + + DebuggerSetColorBG( DebuggerGetColor( iBackground ) ); + DebuggerSetColorFG( DebuggerGetColor( iForeground ) ); +#if DEBUG_FORCE_DISPLAY + COLORREF nColor = gaColorPalette[ iColor ]; + if (iBreakpoint >= 8) + { + nColor = DebuggerGetColor( BG_INFO ); + DebuggerSetColorBG( nColor ); + nColor = DebuggerGetColor( FG_DISASM_BP_S_X ); + } + DebuggerSetColorFG( nColor ); +#endif + sprintf( sText, "%04X", nAddress2 ); + PrintTextCursorX( sText, rect2 ); + } + +#if !USE_APPLE_FONT + // Windows HACK: Bugfix: Rest of line is still breakpoint background color + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); // COLOR_BG_DATA + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); //COLOR_STATIC + PrintTextCursorX( " ", rect2 ); +#endif + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; + } + } +} + + +// Console ________________________________________________________________________________________ + + +//=========================================================================== +int GetConsoleLineHeightPixels() +{ + int nHeight = nHeight = g_aFontConfig[ FONT_CONSOLE ]._nFontHeight; // _nLineHeight; // _nFontHeight; +/* + if (g_iFontSpacing == FONT_SPACING_CLASSIC) + { + nHeight++; // "Classic" Height/Spacing + } + else + if (g_iFontSpacing == FONT_SPACING_CLEAN) + { + nHeight++; + } + else + if (g_iFontSpacing == FONT_SPACING_COMPRESSED) + { + // default case handled + } +*/ + return nHeight; +} + +//=========================================================================== +int GetConsoleTopPixels( int y ) +{ + int nLineHeight = GetConsoleLineHeightPixels(); + int nTop = DISPLAY_HEIGHT - ((y + 1) * nLineHeight); + return nTop; +} + +//=========================================================================== +void DrawConsoleCursor () +{ + DebuggerSetColorFG( DebuggerGetColor( FG_CONSOLE_INPUT )); + DebuggerSetColorBG( DebuggerGetColor( BG_CONSOLE_INPUT )); + + int nWidth = g_aFontConfig[ FONT_CONSOLE ]._nFontWidthAvg; + + int nLineHeight = GetConsoleLineHeightPixels(); + int y = 0; + + RECT rect; + rect.left = (g_nConsoleInputChars + g_nConsolePromptLen) * nWidth; + rect.top = GetConsoleTopPixels( y ); + rect.bottom = rect.top + nLineHeight; //g_nFontHeight; + rect.right = rect.left + nWidth; + + PrintText( g_sConsoleCursor, rect ); +} + +//=========================================================================== +void GetConsoleRect ( const int y, RECT & rect ) +{ + int nLineHeight = GetConsoleLineHeightPixels(); + + rect.left = 0; + rect.top = GetConsoleTopPixels( y ); + rect.bottom = rect.top + nLineHeight; //g_nFontHeight; + +// int nHeight = WindowGetHeight( g_iWindowThis ); + + int nFontWidth = g_aFontConfig[ FONT_CONSOLE ]._nFontWidthAvg; + int nMiniConsoleRight = g_nConsoleDisplayWidth * nFontWidth; + int nFullConsoleRight = DISPLAY_WIDTH; + int nRight = g_bConsoleFullWidth ? nFullConsoleRight : nMiniConsoleRight; + rect.right = nRight; +} + +//=========================================================================== +void DrawConsoleLine ( const conchar_t * pText, int y ) +{ + if (y < 0) + return; + + RECT rect; + GetConsoleRect( y, rect ); + + // Console background is drawn in DrawWindowBackground_Info + PrintTextColor( pText, rect ); +} + +//=========================================================================== +void DrawConsoleInput () +{ + DebuggerSetColorFG( DebuggerGetColor( FG_CONSOLE_INPUT )); + DebuggerSetColorBG( DebuggerGetColor( BG_CONSOLE_INPUT )); + + RECT rect; + GetConsoleRect( 0, rect ); + + // Console background is drawn in DrawWindowBackground_Info +// DrawConsoleLine( g_aConsoleInput, 0 ); + PrintText( g_aConsoleInput, rect ); +} + + +// Disassembly ____________________________________________________________________________________ + + +// Get the data needed to disassemble one line of opcodes +// 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_.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 + + const int nMaxOpcodes = 3; + unsigned int nMinBytesLen = (nMaxOpcodes * (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; + line_.nTargetOffset = 0; + +// if (g_aOpmodes[ iMode ]._sFormat[0]) + if ((iOpmode != AM_IMPLIED) && + (iOpmode != AM_1) && + (iOpmode != AM_2) && + (iOpmode != AM_3)) + { + nTarget = *(LPWORD)(mem+nBaseAddress+1); + 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 + // if ((nBaseAddress == regs.pc) && CheckJump(nAddress)) + 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; + + LPCTSTR pTarget = NULL; + LPCTSTR pSymbol = FindSymbolFromAddress( nTarget ); + 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 + } + } + + 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 $3F3 BREAK+1 + } + } + + if (! (bDisasmFormatFlags & DISASM_FORMAT_SYMBOL)) + { + pTarget = FormatAddress( nTarget, nOpbyte ); + } + +// 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 nTargetPointer; + WORD nTargetValue = 0; // de-ref + int nTargetBytes; + _6502_GetTargets( nBaseAddress, &nTargetPartial, &nTargetPointer, &nTargetBytes ); + + if (nTargetPointer != NO_6502_TARGET) + { + bDisasmFormatFlags |= DISASM_FORMAT_TARGET_POINTER; + + nTargetValue = *(LPWORD)(mem+nTargetPointer); + +// if (((iOpmode >= AM_A) && (iOpmode <= AM_NZ)) && (iOpmode != AM_R)) + // nTargetBytes refers to size of pointer, not size of value +// sprintf( sTargetValue_, "%04X", nTargetValue ); // & 0xFFFF + + if (g_iConfigDisasmTargets & DISASM_TARGET_ADDR) + sprintf( line_.sTargetPointer, "%04X", nTargetPointer & 0xFFFF ); + + if (iOpmode != AM_NA ) // Indirect Absolute + { + 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_ ); + + 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; + for( int iByte = 0; iByte < nOpbyte; iByte++ ) + { + BYTE nMem = (unsigned)*(mem+nBaseAddress + iByte); + sprintf( pDst, "%02X", nMem ); // sBytes+strlen(sBytes) + pDst += 2; + + 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; + 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: + sprintf( pDst, "$%02X", nTarget8 ); // sBytes+strlen(sBytes) + pDst += 3; + iByte++; + if( iByte < line_.nOpbyte ) + { + *pDst++ = ','; + } + break; + case NOP_WORD_1: + sprintf( pDst, "$%04X", nTarget16 ); // sBytes+strlen(sBytes) + pDst += 5; + iByte+= 2; + if( iByte < line_.nOpbyte ) + { + *pDst++ = ','; + } + break; + case NOP_STRING_APPLESOFT: + iByte = line_.nOpbyte; + strncpy( pDst, (const char*)(mem + nBaseAddress), iByte ); + pDst += iByte; + *pDst = 0; + default: + break; + } +// else // 4 bytes +// if( line_.nOpbyte == 4) +// { +// } +// else // 8 bytes +// if( line_.nOpbyte == 8) +// { +// } + } +} + + +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, "#" ); + strcpy( sTarget, line.sTarget ); // sTarget + } + else + sprintf( sTarget, g_aOpmodes[ line.iOpmode ].m_sFormat, line.nTarget ); + + strcat( sDisassembly, "$" ); + strcat( sDisassembly, sTarget ); + } +} + +//=========================================================================== +WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress ) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return 0; + + int iOpcode; + int iOpmode; + int nOpbyte; + DisasmLine_t line; + LPCSTR pSymbol = NULL; + const char * pMnemonic = NULL; + + int bDisasmFormatFlags = GetDisassemblyLine( nBaseAddress, line ); + DisasmData_t *pData = Disassembly_IsDataAddress( nBaseAddress ); + if( pData ) + { + Disassembly_GetData( nBaseAddress, pData, line ); +// pSymbol = line.sLabel; + } + + { + pSymbol = FindSymbolFromAddress( nBaseAddress ); +// strcpy( line.sLabel, pSymbol ); + } + + iOpcode = line.iOpcode; + iOpmode = line.iOpmode; + nOpbyte = line.nOpbyte; + + // Data Disassembler + // + // sAddress, sOpcodes, sTarget, sTargetOffset, nTargetOffset, sTargetPointer, sTargetValue, sImmediate, nImmediate, sBranch ); + //> Address Seperator Opcodes Label Mnemonic Target [Immediate] [Branch] + // + //> xxxx: xx xx xx LABEL MNEMONIC 'E' = + //> ^ ^ ^ ^ ^ + //> 6 17 27 41 46 + const int nDefaultFontWidth = 7; // g_aFontConfig[FONT_DISASM_DEFAULT]._nFontWidth or g_nFontWidthAvg + + enum TabStop_e + { + TS_OPCODE + , TS_LABEL + , TS_INSTRUCTION + , TS_IMMEDIATE + , TS_BRANCH + , TS_CHAR + , _NUM_TAB_STOPS + }; + +// int X_OPCODE = 6 * nDefaultFontWidth; +// int X_LABEL = 17 * nDefaultFontWidth; +// int X_INSTRUCTION = 26 * nDefaultFontWidth; // 27 +// int X_IMMEDIATE = 40 * nDefaultFontWidth; // 41 +// int X_BRANCH = 46 * nDefaultFontWidth; + + float aTabs[ _NUM_TAB_STOPS ] = +// { 6, 16, 26, 41, 46, 49 }; // 6, 17, 26, 40, 46 +#if USE_APPLE_FONT +// { 5, 14, 20, 40, 46, 49 }; + // xxxx:xx xx xx LABELxxxxxx MNEMONIC 'E' = + // 0 45 14 26 + { 5, 14, 26, 41, 48, 49 }; +#else + { 5.75, 15.5, 25, 40.5, 45.5, 48.5 }; +#endif + +#if !USE_APPLE_FONT + if (! g_bConfigDisasmAddressColon) + { + aTabs[ TS_OPCODE ] -= 1; + } + + if ((g_bConfigDisasmOpcodesView) && (! g_bConfigDisasmOpcodeSpaces)) + { + aTabs[ TS_LABEL ] -= 3; + aTabs[ TS_INSTRUCTION ] -= 2; + aTabs[ TS_IMMEDIATE ] -= 1; + } +#endif + const int OPCODE_TO_LABEL_SPACE = static_cast( aTabs[ TS_INSTRUCTION ] - aTabs[ TS_LABEL ] ); + + int iTab = 0; + int nSpacer = 11; // 9 + for (iTab = 0; iTab < _NUM_TAB_STOPS; iTab++ ) + { + if (! g_bConfigDisasmAddressView ) + { + if (iTab < TS_IMMEDIATE) // TS_BRANCH) + { + aTabs[ iTab ] -= 4; + } + } + if (! g_bConfigDisasmOpcodesView) + { + if (iTab < TS_IMMEDIATE) // TS_BRANCH) + { + aTabs[ iTab ] -= nSpacer; + if (nSpacer > 0) + nSpacer -= 2; + } + } + + aTabs[ iTab ] *= nDefaultFontWidth; + } + +#if USE_APPLE_FONT + const int DISASM_SYMBOL_LEN = 12; +#else + const int DISASM_SYMBOL_LEN = 9; +#endif + + HDC dc = g_hFrameDC; + if (dc) + { + int nFontHeight = g_aFontConfig[ FONT_DISASM_DEFAULT ]._nLineHeight; // _nFontHeight; // g_nFontHeight + + RECT linerect; + linerect.left = 0; + linerect.top = iLine * nFontHeight; + linerect.right = DISPLAY_DISASM_RIGHT; + linerect.bottom = linerect.top + nFontHeight; + +// BOOL bp = g_nBreakpoints && CheckBreakpoint(nBaseAddress,nBaseAddress == regs.pc); + + bool bBreakpointActive; + bool bBreakpointEnable; + GetBreakpointInfo( nBaseAddress, bBreakpointActive, bBreakpointEnable ); + bool bAddressAtPC = (nBaseAddress == regs.pc); + bool bAddressIsBookmark = Bookmark_Find( nBaseAddress ); + + DebugColors_e iBackground = BG_DISASM_1; + DebugColors_e iForeground = FG_DISASM_MNEMONIC; // FG_DISASM_TEXT; + bool bCursorLine = false; + + if (((! g_bDisasmCurBad) && (iLine == g_nDisasmCurLine)) + || (g_bDisasmCurBad && (iLine == 0))) + { + bCursorLine = true; + + // Breakpoint, + if (bBreakpointActive) + { + if (bBreakpointEnable) + { + iBackground = BG_DISASM_BP_S_C; iForeground = FG_DISASM_BP_S_C; + } + else + { + iBackground = BG_DISASM_BP_0_C; iForeground = FG_DISASM_BP_0_C; + } + } + else + if (bAddressAtPC) + { + iBackground = BG_DISASM_PC_C; iForeground = FG_DISASM_PC_C; + } + else + { + iBackground = BG_DISASM_C; iForeground = FG_DISASM_C; + // HACK? Sync Cursor back up to Address + // The cursor line may of had to be been moved, due to Disasm Singularity. + g_nDisasmCurAddress = nBaseAddress; + } + } + else + { + if (iLine & 1) + { + iBackground = BG_DISASM_1; + } + else + { + iBackground = BG_DISASM_2; + } + + // This address has a breakpoint, but the cursor is not on it (atm) + if (bBreakpointActive) + { + if (bBreakpointEnable) + { + iForeground = FG_DISASM_BP_S_X; // Red (old Yellow) + } + else + { + iForeground = FG_DISASM_BP_0_X; // Yellow + } + } + else + if (bAddressAtPC) + { + iBackground = BG_DISASM_PC_X; iForeground = FG_DISASM_PC_X; + } + else + { + iForeground = FG_DISASM_MNEMONIC; + } + } + + if (bAddressIsBookmark) + { + DebuggerSetColorBG( DebuggerGetColor( BG_DISASM_BOOKMARK ) ); + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_BOOKMARK ) ); + } + else + { + DebuggerSetColorBG( DebuggerGetColor( iBackground ) ); + DebuggerSetColorFG( DebuggerGetColor( iForeground ) ); + } + + // Address + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_ADDRESS ) ); +// else +// { +// DebuggerSetColorBG( dc, DebuggerGetColor( FG_DISASM_BOOKMARK ) ); // swapped +// DebuggerSetColorFG( dc, DebuggerGetColor( BG_DISASM_BOOKMARK ) ); // swapped +// } + + if( g_bConfigDisasmAddressView ) + { + PrintTextCursorX( (LPCTSTR) line.sAddress, linerect ); + } + + if (bAddressIsBookmark) + { + DebuggerSetColorBG( DebuggerGetColor( iBackground ) ); + DebuggerSetColorFG( DebuggerGetColor( iForeground ) ); + } + + // Address Seperator + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR ) ); + + if (g_bConfigDisasmAddressColon) + PrintTextCursorX( ":", linerect ); + else + PrintTextCursorX( " ", linerect ); // bugfix, not showing "addr:" doesn't alternate color lines + + // Opcodes + linerect.left = (int) aTabs[ TS_OPCODE ]; + + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPCODE ) ); +// PrintTextCursorX( " ", linerect ); + + if (g_bConfigDisasmOpcodesView) + PrintTextCursorX( (LPCTSTR) line.sOpCodes, linerect ); +// PrintTextCursorX( " ", linerect ); + + // Label + linerect.left = (int) aTabs[ TS_LABEL ]; + + LPCSTR pSymbol = FindSymbolFromAddress( nBaseAddress ); + if (pSymbol) + { + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_SYMBOL ) ); + PrintTextCursorX( pSymbol, linerect ); + } +// linerect.left += (g_nFontWidthAvg * DISASM_SYMBOL_LEN); +// PrintTextCursorX( " ", linerect ); + + // Instruction / Mnemonic + linerect.left = (int) aTabs[ TS_INSTRUCTION ]; + + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( iForeground ) ); + + if( pData ) + { +// pMnemonic = g_aAssemblerDirectives[ line.iNopcode ].sMnemonic; + pMnemonic = line.sMnemonic; + } + else + { + pMnemonic = g_aOpcodes[ iOpcode ].sMnemonic; + } + + PrintTextCursorX( pMnemonic, linerect ); + PrintTextCursorX( " ", linerect ); + + // Target + if (line.bTargetImmediate) + { + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + PrintTextCursorX( "#$", linerect ); + } + + if (line.bTargetIndexed || line.bTargetIndirect) + { + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + PrintTextCursorX( "(", linerect ); + } + + char *pTarget = line.sTarget; + if (*pTarget == '$') + { + pTarget++; + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + PrintTextCursorX( "$", linerect ); + } + + if (! bCursorLine) + { + if (bDisasmFormatFlags & DISASM_FORMAT_SYMBOL) + { + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_SYMBOL ) ); + } + else + { + if (iOpmode == AM_M) +// if (bDisasmFormatFlags & DISASM_FORMAT_CHAR) + { + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPCODE ) ); + } + else + { + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_TARGET ) ); + } + } + } + PrintTextCursorX( pTarget, linerect ); +// PrintTextCursorX( " ", linerect ); + + if( pData ) + { + return nOpbyte; + } + + // Target Offset +/- + if (bDisasmFormatFlags & DISASM_FORMAT_OFFSET) + { + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + + if (line.nTargetOffset > 0) + PrintTextCursorX( "+", linerect ); + else + if (line.nTargetOffset < 0) + PrintTextCursorX( "-", linerect ); + + if (! bCursorLine) + { + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPCODE )); // Technically, not a hex number, but decimal + } + PrintTextCursorX( line.sTargetOffset, linerect ); + } + // Inside Parenthesis = Indirect Target Regs + if (line.bTargetIndirect || line.bTargetX || line.bTargetY) + { + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + + if (line.bTargetX) + { + PrintTextCursorX( ",", linerect ); + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_REG ) ); + PrintTextCursorX( "X", linerect ); + } + else + if ((line.bTargetY) && (! line.bTargetIndirect)) + { + PrintTextCursorX( ",", linerect ); + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_REG ) ); + PrintTextCursorX( "Y", linerect ); + } + } + + if (line.bTargetIndexed || line.bTargetIndirect) + { + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + + PrintTextCursorX( ")", linerect ); + } + + if (line.bTargetIndexed) + { + if (line.bTargetY) + { + PrintTextCursorX( ",", linerect ); + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_REG ) ); + PrintTextCursorX( "Y", linerect ); + } + } + + // Memory Pointer and Value + if (bDisasmFormatFlags & DISASM_FORMAT_TARGET_POINTER) // (bTargetValue) + { + linerect.left = (int) aTabs[ TS_IMMEDIATE ]; // TS_IMMEDIATE ]; + +// PrintTextCursorX( " ", linerect ); + + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_ADDRESS )); + + PrintTextCursorX( line.sTargetPointer, linerect ); + + if (bDisasmFormatFlags & DISASM_FORMAT_TARGET_VALUE) + { + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + + if (g_iConfigDisasmTargets & DISASM_TARGET_BOTH) + PrintTextCursorX( ":", linerect ); + + if (! bCursorLine) + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPCODE )); + + PrintTextCursorX( line.sTargetValue, linerect ); + PrintTextCursorX( " ", linerect ); + } + } + + // Immediate Char + if (bDisasmFormatFlags & DISASM_FORMAT_CHAR) + { + linerect.left = (int) aTabs[ TS_CHAR ]; // TS_IMMEDIATE ]; + + if (! bCursorLine) + { + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR ) ); + } + +// if (! (bDisasmFormatFlags & DISASM_FORMAT_TARGET_POINTER)) +// PrintTextCursorX( "'", linerect ); + + if (! bCursorLine) + { + ColorizeSpecialChar( NULL, line.nImmediate, MEM_VIEW_ASCII, iBackground ); +// iBackground, FG_INFO_CHAR_HI, FG_DISASM_CHAR, FG_INFO_CHAR_LO ); + } + PrintTextCursorX( line.sImmediate, linerect ); + + DebuggerSetColorBG( DebuggerGetColor( iBackground ) ); // Hack: Colorize can "color bleed to EOL" + if (! bCursorLine) + { + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR ) ); + } + +// if (! (bDisasmFormatFlags & DISASM_FORMAT_TARGET_POINTER)) +// PrintTextCursorX( "'", linerect ); + } + + // Branch Indicator + if (bDisasmFormatFlags & DISASM_FORMAT_BRANCH) + { + linerect.left = (int) aTabs[ TS_BRANCH ]; + + if (! bCursorLine) + { + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_BRANCH ) ); + } + +#if !USE_APPLE_FONT + if (g_iConfigDisasmBranchType == DISASM_BRANCH_FANCY) + SelectObject( g_hFrameDC, g_aFontConfig[ FONT_DISASM_BRANCH ]._hFont ); // g_hFontWebDings +#endif + +// PrintTextColor( sBranch, linerect ); + PrintText( line.sBranch, linerect ); + +#if !USE_APPLE_FONT + if (g_iConfigDisasmBranchType) + SelectObject( dc, g_aFontConfig[ FONT_DISASM_DEFAULT ]._hFont ); // g_hFontDisasm +#endif + } + } + + return nOpbyte; +} + + +// Optionally copy the flags to pText_ +//=========================================================================== +void DrawFlags ( int line, WORD nRegFlags, LPTSTR pFlagNames_) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return; + + char sFlagNames[ _6502_NUM_FLAGS+1 ] = ""; // = "NVRBDIZC"; // copy from g_aFlagNames + char sText[4] = "?"; + RECT rect; + + int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; + + // Regs are 10 chars across + // Flags are 8 chars across -- scale "up" + int nSpacerWidth = nFontWidth; + +#if OLD_FLAGS_SPACING + const int nScaledWidth = 10; + if (nFontWidth) + nSpacerWidth = (nScaledWidth * nFontWidth) / 8; + nSpacerWidth++; +#endif + + if (g_hFrameDC) + { + rect.top = line * g_nFontHeight; + rect.bottom = rect.top + g_nFontHeight; + rect.left = DISPLAY_FLAG_COLUMN; + rect.right = rect.left + (10 * nFontWidth); + + DebuggerSetColorBG( DebuggerGetColor( BG_DATA_1 )); // BG_INFO + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_REG )); + PrintText( "P ", rect ); + + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; + + sprintf( sText, "%02X", nRegFlags ); + + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); + PrintText( sText, rect ); + + rect.top -= g_nFontHeight; + rect.bottom -= g_nFontHeight; + sText[1] = 0; + + rect.left += ((2 + _6502_NUM_FLAGS) * nSpacerWidth); + rect.right = rect.left + nFontWidth; + } + + int iFlag = 0; + int nFlag = _6502_NUM_FLAGS; + while (nFlag--) + { + iFlag = (_6502_NUM_FLAGS - nFlag - 1); + + bool bSet = (nRegFlags & 1); + if (g_hFrameDC) + { + sText[0] = g_aBreakpointSource[ BP_SRC_FLAG_C + iFlag ][0]; + if (bSet) + { + DebuggerSetColorBG( DebuggerGetColor( BG_INFO_INVERSE )); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_INVERSE )); + } + else + { + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); + } + rect.left -= nSpacerWidth; + rect.right -= nSpacerWidth; + PrintText( sText, rect ); + + // Print Binary value + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); // + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); + + sText[0] = '0' + static_cast(bSet); + PrintText( sText, rect ); + rect.top -= g_nFontHeight; + rect.bottom -= g_nFontHeight; + } + + if (pFlagNames_) + { + if (! bSet) //(nFlags & 1)) + { + sFlagNames[nFlag] = '.'; + } + else + { + sFlagNames[nFlag] = g_aBreakpointSource[ BP_SRC_FLAG_C + iFlag ][0]; + } + } + + nRegFlags >>= 1; + } + + if (pFlagNames_) + strcpy(pFlagNames_,sFlagNames); +/* + if (g_hFrameDC) + { + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; + rect.left = DISPLAY_FLAG_COLUMN; + rect.right = rect.left + (10 * nFontWidth); + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_REG )); + PrintTextCursorX( "P ", rect ); + + + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); // COLOR_BG_DATA + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_REG )); + PrintTextCursorX( "P ", rect ); + + rect.left += (_6502_NUM_FLAGS * nSpacerWidth); + rect.right = rect.left + nFontWidth; + } +*/ +} + +//=========================================================================== +void DrawMemory ( int line, int iMemDump ) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return; + + MemoryDump_t* pMD = &g_aMemDump[ iMemDump ]; + + USHORT nAddr = pMD->nAddress; + DEVICE_e eDevice = pMD->eDevice; + MemoryView_e iView = pMD->eView; + + SS_CARD_MOCKINGBOARD SS_MB; + + if ((eDevice == DEV_SY6522) || (eDevice == DEV_AY8910)) + MB_GetSnapshot(&SS_MB, 4+(nAddr>>1)); // Slot4 or Slot5 + + int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; + + RECT rect; + rect.left = DISPLAY_MINIMEM_COLUMN; + rect.top = (line * g_nFontHeight); + rect.right = DISPLAY_WIDTH; + rect.bottom = rect.top + g_nFontHeight; + + RECT rect2; + rect2 = rect; + + const int MAX_MEM_VIEW_TXT = 16; + char sText[ MAX_MEM_VIEW_TXT * 2 ]; + char sData[ MAX_MEM_VIEW_TXT * 2 ]; + + char sType [ 4 ] = "Mem"; + char sAddress[ 8 ] = ""; + + int iForeground = FG_INFO_OPCODE; + int iBackground = BG_INFO; + +#if DISPLAY_MEMORY_TITLE + if (eDevice == DEV_SY6522) + { +// sprintf(sData,"Mem at SY#%d", nAddr); + sprintf( sAddress,"SY#%d", nAddr ); + } + else if(eDevice == DEV_AY8910) + { +// sprintf(sData,"Mem at AY#%d", nAddr); + sprintf( sAddress,"AY#%d", nAddr ); + } + else + { + sprintf( sAddress,"%04X",(unsigned)nAddr); + + if (iView == MEM_VIEW_HEX) + sprintf( sType, "HEX" ); + else + if (iView == MEM_VIEW_ASCII) + sprintf( sType, "ASCII" ); + else + sprintf( sType, "TEXT" ); + } + + rect2 = rect; + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); + PrintTextCursorX( sType, rect2 ); + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); + PrintTextCursorX( " at ", rect2 ); + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); + PrintTextCursorY( sAddress, rect2 ); +#endif + + rect.top = rect2.top; + rect.bottom = rect2.bottom; + + sData[0] = 0; + + WORD iAddress = nAddr; + + int nLines = g_nDisplayMemoryLines; + int nCols = 4; + + if (iView != MEM_VIEW_HEX) + { + nCols = MAX_MEM_VIEW_TXT; + } + + if( (eDevice == DEV_SY6522) || (eDevice == DEV_AY8910) ) + { + iAddress = 0; + nCols = 6; + } + + rect.right = DISPLAY_WIDTH - 1; + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); + + for (int iLine = 0; iLine < nLines; iLine++ ) + { + rect2 = rect; + + if (iView == MEM_VIEW_HEX) + { + sprintf( sText, "%04X", iAddress ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); + PrintTextCursorX( sText, rect2 ); + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); + PrintTextCursorX( ":", rect2 ); + } + + for (int iCol = 0; iCol < nCols; iCol++) + { + bool bHiBit = false; + bool bLoBit = false; + + DebuggerSetColorBG( DebuggerGetColor( iBackground )); + DebuggerSetColorFG( DebuggerGetColor( iForeground )); + +// .12 Bugfix: DrawMemory() should draw memory byte for IO address: ML1 C000 +// if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END)) +// { +// sprintf( sText, "IO " ); +// } +// else + if (eDevice == DEV_SY6522) + { + sprintf( sText, "%02X", (unsigned) ((BYTE*)&SS_MB.Unit[nAddr & 1].RegsSY6522)[iAddress] ); + if (iCol & 1) + DebuggerSetColorFG( DebuggerGetColor( iForeground )); + else + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); + } + else + if (eDevice == DEV_AY8910) + { + sprintf( sText, "%02X", (unsigned)SS_MB.Unit[nAddr & 1].RegsAY8910[iAddress] ); + if (iCol & 1) + DebuggerSetColorFG( DebuggerGetColor( iForeground )); + else + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); + } + else + { + BYTE nData = (unsigned)*(LPBYTE)(mem+iAddress); + sText[0] = 0; + + char c = nData; + + if (iView == MEM_VIEW_HEX) + { + if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END)) + { + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_IO_BYTE )); + } + sprintf(sText, "%02X ", nData ); + } + else + { +// .12 Bugfix: DrawMemory() should draw memory byte for IO address: ML1 C000 + if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END)) + iBackground = BG_INFO_IO_BYTE; + + ColorizeSpecialChar( sText, nData, iView, iBackground ); + } + } + int nChars = PrintTextCursorX( sText, rect2 ); // PrintTextCursorX() + iAddress++; + } + // Windows HACK: Bugfix: Rest of line is still background color +// DebuggerSetColorBG( hDC, DebuggerGetColor( BG_INFO )); // COLOR_BG_DATA +// DebuggerSetColorFG(hDC, DebuggerGetColor( FG_INFO_TITLE )); //COLOR_STATIC +// PrintTextCursorX( " ", rect2 ); + + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; + sData[0] = 0; + } +} + +//=========================================================================== +void DrawRegister ( int line, LPCTSTR name, const int nBytes, const WORD nValue, int iSource ) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return; + + int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; + + RECT rect; + rect.top = line * g_nFontHeight; + rect.bottom = rect.top + g_nFontHeight; + rect.left = DISPLAY_REGS_COLUMN; + rect.right = rect.left + (10 * nFontWidth); // + 1; + + if ((PARAM_REG_A == iSource) || + (PARAM_REG_X == iSource) || + (PARAM_REG_Y == iSource) || + (PARAM_REG_PC == iSource) || + (PARAM_REG_SP == iSource)) + { + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_REG )); + } + else + { +// DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); + rect.left += nFontWidth; + } + + // 2.6.0.0 Alpha - Regs not "boxed" + int iBackground = BG_DATA_1; // BG_INFO + + DebuggerSetColorBG( DebuggerGetColor( iBackground )); + PrintText( name, rect ); + + unsigned int nData = nValue; + int nOffset = 6; + + char sValue[8]; + + if (PARAM_REG_SP == iSource) + { + WORD nStackDepth = _6502_STACK_END - nValue; + sprintf( sValue, "%02X", nStackDepth ); + int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; + rect.left += (2 * nFontWidth) + (nFontWidth >> 1); // 2.5 looks a tad nicer then 2 + + // ## = Stack Depth (in bytes) + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); // FG_INFO_OPCODE, FG_INFO_TITLE + PrintText( sValue, rect ); + } + + if (nBytes == 2) + { + sprintf(sValue,"%04X", nData); + } + else + { + rect.left = DISPLAY_REGS_COLUMN + (3 * nFontWidth); +// rect.right = SCREENSPLIT2; + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); + PrintTextCursorX( "'", rect ); // PrintTextCursorX + + ColorizeSpecialChar( sValue, nData, MEM_VIEW_ASCII ); // MEM_VIEW_APPLE for inverse background little hard on the eyes + + DebuggerSetColorBG( DebuggerGetColor( iBackground )); + PrintTextCursorX( sValue, rect ); // PrintTextCursorX() + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); + PrintTextCursorX( "'", rect ); // PrintTextCursorX() + + sprintf(sValue," %02X", nData ); + } + + // Needs to be far enough over, since 4 chars of ZeroPage symbol also calls us + rect.left = DISPLAY_REGS_COLUMN + (nOffset * nFontWidth); + + if ((PARAM_REG_PC == iSource) || (PARAM_REG_SP == iSource)) // Stack Pointer is target address, but doesn't look as good. + { + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); + } + else + { + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); // FG_DISASM_OPCODE + } + PrintText( sValue, rect ); +} + + +//=========================================================================== +void DrawSourceLine( int iSourceLine, RECT &rect ) +{ + char sLine[ CONSOLE_WIDTH ]; + ZeroMemory( sLine, CONSOLE_WIDTH ); + + if ((iSourceLine >=0) && (iSourceLine < g_AssemblerSourceBuffer.GetNumLines() )) + { + char * pSource = g_AssemblerSourceBuffer.GetLine( iSourceLine ); + +// int nLenSrc = strlen( pSource ); +// if (nLenSrc >= CONSOLE_WIDTH) +// bool bStop = true; + + TextConvertTabsToSpaces( sLine, pSource, CONSOLE_WIDTH-1 ); // bugfix 2,3,1,15: fence-post error, buffer over-run + +// int nLenTab = strlen( sLine ); + } + else + { + strcpy( sLine, " " ); + } + + PrintText( sLine, rect ); + rect.top += g_nFontHeight; +} + + +//=========================================================================== +void DrawStack ( int line) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return; + + unsigned nAddress = regs.sp; +#if DEBUG_FORCE_DISPLAY + nAddress = 0x100; +#endif + + int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; + + // 2.6.0.0 Alpha - Stack was dark cyan BG_DATA_1 + DebuggerSetColorBG( DebuggerGetColor( BG_DATA_1 )); // BG_INFO // recessed 3d look + + int iStack = 0; + while (iStack < MAX_DISPLAY_STACK_LINES) + { + nAddress++; + + RECT rect; + rect.left = DISPLAY_STACK_COLUMN; + rect.top = (iStack+line) * g_nFontHeight; + rect.right = rect.left + (10 * nFontWidth) + 1; + rect.bottom = rect.top + g_nFontHeight; + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); // [COLOR_STATIC + + char sText[8] = ""; + if (nAddress <= _6502_STACK_END) + { + sprintf( sText,"%04X: ", nAddress ); + PrintTextCursorX( sText, rect ); + } + + if (nAddress <= _6502_STACK_END) + { + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); // COLOR_FG_DATA_TEXT + sprintf(sText, " %02X",(unsigned)*(LPBYTE)(mem+nAddress)); + PrintTextCursorX( sText, rect ); + } + iStack++; + } +} + + +//=========================================================================== +void DrawTargets ( int line) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return; + + int aTarget[2]; + _6502_GetTargets( regs.pc, &aTarget[0],&aTarget[1], NULL ); + + RECT rect; + int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; + + int iAddress = 2; + while (iAddress--) + { + // .6 Bugfix: DrawTargets() should draw target byte for IO address: R PC FB33 +// if ((aTarget[iAddress] >= _6502_IO_BEGIN) && (aTarget[iAddress] <= _6502_IO_END)) +// aTarget[iAddress] = NO_6502_TARGET; + + char sAddress[8] = "-none-"; + char sData[8] = ""; + +#if DEBUG_FORCE_DISPLAY + if (aTarget[iAddress] == NO_6502_TARGET) + aTarget[iAddress] = 0; +#endif + if (aTarget[iAddress] != NO_6502_TARGET) + { + sprintf(sAddress,"%04X",aTarget[iAddress]); + if (iAddress) + sprintf(sData,"%02X",*(LPBYTE)(mem+aTarget[iAddress])); + else + sprintf(sData,"%04X",*(LPWORD)(mem+aTarget[iAddress])); + } + + rect.left = DISPLAY_TARGETS_COLUMN; + rect.top = (line+iAddress) * g_nFontHeight; + int nColumn = rect.left + (7 * nFontWidth); + rect.right = nColumn; + rect.bottom = rect.top + g_nFontHeight; + + if (iAddress == 0) + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); // Temp Address + else + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); // Target Address + + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); + PrintText( sAddress, rect ); + + rect.left = nColumn; + rect.right = rect.left + (10 * nFontWidth); // SCREENSPLIT2 + + if (iAddress == 0) + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); // Temp Target + else + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); // Target Bytes + + PrintText( sData, rect ); + } +} + +//=========================================================================== +void DrawWatches (int line) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return; + + RECT rect; + rect.left = DISPLAY_WATCHES_COLUMN; + rect.top = (line * g_nFontHeight); + rect.right = DISPLAY_WIDTH; + rect.bottom = rect.top + g_nFontHeight; + + char sText[16] = "Watches"; + + DebuggerSetColorBG( DebuggerGetColor( WATCH_ZERO_BG )); // BG_INFO + +#if DISPLAY_WATCH_TITLE + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE )); + PrintTextCursorY( sText, rect ); +#endif + + int iWatch; + for (iWatch = 0; iWatch < MAX_WATCHES; iWatch++ ) + { +#if DEBUG_FORCE_DISPLAY + if (true) +#else + if (g_aWatches[iWatch].bEnabled) +#endif + { + RECT rect2 = rect; + +// DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE ) ); + PrintTextCursorX( "W", rect2 ); + + sprintf( sText, "%X ",iWatch ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_BULLET )); + PrintTextCursorX( sText, rect2 ); + +// DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); +// PrintTextCursorX( ".", rect2 ); + + sprintf( sText,"%04X", g_aWatches[iWatch].nAddress ); + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_ADDRESS )); + PrintTextCursorX( sText, rect2 ); + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); + PrintTextCursorX( ":", rect2 ); + + BYTE nTarget8 = (unsigned)*(LPBYTE)(mem+g_aWatches[iWatch].nAddress); + sprintf(sText,"%02X", nTarget8 ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); + PrintTextCursorX( sText, rect2 ); + + WORD nTarget16 = (unsigned)*(LPWORD)(mem+g_aWatches[iWatch].nAddress); + sprintf( sText," %04X", nTarget16 ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); + PrintTextCursorX( sText, rect2 ); + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); + PrintTextCursorX( ":", rect2 ); + + BYTE nValue8 = (unsigned)*(LPBYTE)(mem + nTarget16); + sprintf(sText,"%02X", nValue8 ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); + PrintTextCursorX( sText, rect2 ); + } + rect.top += g_nFontHeight; + rect.bottom += g_nFontHeight; + } +} + + +//=========================================================================== +void DrawZeroPagePointers ( int line ) +{ + if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA)))) + return; + + int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg; + + RECT rect; + rect.top = line * g_nFontHeight; + rect.bottom = rect.top + g_nFontHeight; + rect.left = DISPLAY_ZEROPAGE_COLUMN; + rect.right = rect.left + (10 * nFontWidth); + + DebuggerSetColorBG( DebuggerGetColor( WATCH_ZERO_BG )); // BG_INFO + + const int nMaxSymbolLen = 7; + char sText[nMaxSymbolLen+1] = ""; + + for(int iZP = 0; iZP < MAX_ZEROPAGE_POINTERS; iZP++) + { + RECT rect2 = rect; + + Breakpoint_t *pZP = &g_aZeroPagePointers[iZP]; + bool bEnabled = pZP->bEnabled; + +#if DEBUG_FORCE_DISPLAY + bEnabled = true; +#endif + if (bEnabled) + { + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE ) ); + PrintTextCursorX( "Z", rect2 ); + + sprintf( sText, "%X ", iZP ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_BULLET )); + PrintTextCursorX( sText, rect2 ); + +// DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); +// PrintTextCursorX( " ", rect2 ); + + BYTE nZPAddr1 = (g_aZeroPagePointers[iZP].nAddress ) & 0xFF; // +MJP missig: "& 0xFF", or "(BYTE) ..." + BYTE nZPAddr2 = (g_aZeroPagePointers[iZP].nAddress+1) & 0xFF; + + // Get nZPAddr1 last (for when neither symbol is not found - GetSymbol() return ptr to static buffer) + const char* pSymbol2 = GetSymbol(nZPAddr2, 2); // 2:8-bit value (if symbol not found) + const char* pSymbol1 = GetSymbol(nZPAddr1, 2); // 2:8-bit value (if symbol not found) + + int nLen1 = strlen( pSymbol1 ); + int nLen2 = strlen( pSymbol2 ); + + +// if ((nLen1 == 1) && (nLen2 == 1)) +// sprintf( sText, "%s%s", pszSymbol1, pszSymbol2); + + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_ADDRESS )); + + int x; + for( x = 0; x < nMaxSymbolLen; x++ ) + { + sText[ x ] = CHAR_SPACE; + } + sText[nMaxSymbolLen] = 0; + + if ((nLen1) && (pSymbol1[0] == '$')) + { +// sprintf( sText, "%s%s", pSymbol1 ); +// sprintf( sText, "%04X", nZPAddr1 ); + } + else + if ((nLen2) && (pSymbol2[0] == '$')) + { +// sprintf( sText, "%s%s", pSymbol2 ); +// sprintf( sText, "%04X", nZPAddr2 ); + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_ADDRESS )); + } + else + { + int nMin = min( nLen1, nMaxSymbolLen ); + memcpy(sText, pSymbol1, nMin); + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_SYMBOL ) ); + } +// DrawRegister( line+iZP, szZP, 2, nTarget16); +// PrintText( szZP, rect2 ); + PrintText( sText, rect2); + + rect2.left = rect.left; + rect2.top += g_nFontHeight; + rect2.bottom += g_nFontHeight; + + sprintf( sText, "%02X", nZPAddr1 ); + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_ADDRESS )); + PrintTextCursorX( sText, rect2 ); + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); + PrintTextCursorX( ":", rect2 ); + + WORD nTarget16 = (WORD)mem[ nZPAddr1 ] | ((WORD)mem[ nZPAddr2 ]<< 8); + sprintf( sText, "%04X", nTarget16 ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_ADDRESS )); + PrintTextCursorX( sText, rect2 ); + + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPERATOR )); + PrintTextCursorX( ":", rect2 ); + + BYTE nValue8 = (unsigned)*(LPBYTE)(mem + nTarget16); + sprintf(sText, "%02X", nValue8 ); + DebuggerSetColorFG( DebuggerGetColor( FG_INFO_OPCODE )); + PrintTextCursorX( sText, rect2 ); + } + rect.top += (g_nFontHeight * 2); + rect.bottom += (g_nFontHeight * 2); + } +} + + +// Sub Windows ____________________________________________________________________________________ + +//=========================================================================== +void DrawSubWindow_Console (Update_t bUpdate) +{ + if (! CanDrawDebugger()) + return; + +#if !USE_APPLE_FONT + SelectObject( g_hFrameDC, g_aFontConfig[ FONT_CONSOLE ]._hFont ); +#endif + + if ((bUpdate & UPDATE_CONSOLE_DISPLAY) + || (bUpdate & UPDATE_CONSOLE_INPUT)) + { + DebuggerSetColorBG( DebuggerGetColor( BG_CONSOLE_OUTPUT )); + +// int nLines = MIN(g_nConsoleDisplayTotal - g_iConsoleDisplayStart, g_nConsoleDisplayHeight); + int iLine = g_iConsoleDisplayStart + CONSOLE_FIRST_LINE; + for (int y = 1; y < g_nConsoleDisplayLines ; y++ ) + { + if (iLine <= (g_nConsoleDisplayTotal + CONSOLE_FIRST_LINE)) + { + DebuggerSetColorFG( DebuggerGetColor( FG_CONSOLE_OUTPUT )); + DrawConsoleLine( g_aConsoleDisplay[ iLine ], y ); + } + else + { + // bugfix: 2.6.1.34 + // scrolled past top of console... Draw blank line + DrawConsoleLine( NULL, y ); + } + iLine++; + } + + DrawConsoleInput(); + } + +// if (bUpdate & UPDATE_CONSOLE_INPUT) + { +// DrawConsoleInput(); // g_hFrameDC ); + } +} + +//=========================================================================== +void DrawSubWindow_Data (Update_t bUpdate) +{ +// HDC hDC = g_hDC; + int iBackground; + + const int nMaxOpcodes = WINDOW_DATA_BYTES_PER_LINE; + char sAddress [ 5]; + + assert( CONSOLE_WIDTH > WINDOW_DATA_BYTES_PER_LINE ); + + char sOpcodes [ CONSOLE_WIDTH ] = ""; + char sImmediate[ 4 ]; // 'c' + + const int nDefaultFontWidth = 7; // g_aFontConfig[FONT_DISASM_DEFAULT]._nFontWidth or g_nFontWidthAvg + int X_OPCODE = 6 * nDefaultFontWidth; + int X_CHAR = (6 + (nMaxOpcodes*3)) * nDefaultFontWidth; + + int iMemDump = 0; + + MemoryDump_t* pMD = &g_aMemDump[ iMemDump ]; + USHORT nAddress = pMD->nAddress; + DEVICE_e eDevice = pMD->eDevice; + MemoryView_e iView = pMD->eView; + + if (!pMD->bActive) + return; + + int iByte; + WORD iAddress = nAddress; + + int iLine; + int nLines = g_nDisasmWinHeight; + + for (iLine = 0; iLine < nLines; iLine++ ) + { + iAddress = nAddress; + + // Format + sprintf( sAddress, "%04X", iAddress ); + + sOpcodes[0] = 0; + for ( iByte = 0; iByte < nMaxOpcodes; iByte++ ) + { + BYTE nData = (unsigned)*(LPBYTE)(mem + iAddress + iByte); + sprintf( &sOpcodes[ iByte * 3 ], "%02X ", nData ); + } + sOpcodes[ nMaxOpcodes * 3 ] = 0; + + int nFontHeight = g_aFontConfig[ FONT_DISASM_DEFAULT ]._nLineHeight; + + // Draw + RECT rect; + rect.left = 0; + rect.top = iLine * nFontHeight; + rect.right = DISPLAY_DISASM_RIGHT; + rect.bottom = rect.top + nFontHeight; + + if (iLine & 1) + { + iBackground = BG_DATA_1; + } + else + { + iBackground = BG_DATA_2; + } + DebuggerSetColorBG( DebuggerGetColor( iBackground ) ); + + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_ADDRESS ) ); + PrintTextCursorX( (LPCTSTR) sAddress, rect ); + + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR ) ); + if (g_bConfigDisasmAddressColon) + PrintTextCursorX( ":", rect ); + + rect.left = X_OPCODE; + + DebuggerSetColorFG( DebuggerGetColor( FG_DATA_BYTE ) ); + PrintTextCursorX( (LPCTSTR) sOpcodes, rect ); + + rect.left = X_CHAR; + + // Seperator + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + PrintTextCursorX( " | ", rect ); + + + // Plain Text + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_CHAR ) ); + + MemoryView_e eView = pMD->eView; + if ((eView != MEM_VIEW_ASCII) && (eView != MEM_VIEW_APPLE)) + eView = MEM_VIEW_ASCII; + + iAddress = nAddress; + for (iByte = 0; iByte < nMaxOpcodes; iByte++ ) + { + BYTE nImmediate = (unsigned)*(LPBYTE)(mem + iAddress); + int iTextBackground = iBackground; + if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END)) + { + iTextBackground = BG_INFO_IO_BYTE; + } + + ColorizeSpecialChar( sImmediate, (BYTE) nImmediate, eView, iBackground ); + PrintTextCursorX( (LPCSTR) sImmediate, rect ); + + iAddress++; + } +/* + // Colorized Text + iAddress = nAddress; + for (iByte = 0; iByte < nMaxOpcodes; iByte++ ) + { + BYTE nImmediate = (unsigned)*(LPBYTE)(membank + iAddress); + int iTextBackground = iBackground; // BG_INFO_CHAR; +//pMD->eView == MEM_VIEW_HEX + if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END)) + iTextBackground = BG_INFO_IO_BYTE; + + ColorizeSpecialChar( hDC, sImmediate, (BYTE) nImmediate, MEM_VIEW_APPLE, iBackground ); + PrintTextCursorX( (LPCSTR) sImmediate, rect ); + + iAddress++; + } + + DebuggerSetColorBG( DebuggerGetColor( iBackground ) ); // Hack, colorize Char background "spills over to EOL" + PrintTextCursorX( " ", rect ); +*/ + DebuggerSetColorBG( DebuggerGetColor( iBackground ) ); // HACK: Colorize() can "spill over" to EOL + + DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR )); + PrintTextCursorX( " | ", rect ); + + nAddress += nMaxOpcodes; + } +} + + +// DrawRegisters(); +//=========================================================================== +void DrawSubWindow_Info( int iWindow ) +{ + if (g_iWindowThis == WINDOW_CONSOLE) + return; + + const char **sReg = g_aBreakpointSource; + + int yRegs = 0; // 12 + int yStack = yRegs + MAX_DISPLAY_REGS_LINES + 0; // 0 + int yTarget = yStack + MAX_DISPLAY_STACK_LINES - 1; // 9 + int yZeroPage = 16; // 19 + + DrawRegister( yRegs++, sReg[ BP_SRC_REG_A ] , 1, regs.a , PARAM_REG_A ); + DrawRegister( yRegs++, sReg[ BP_SRC_REG_X ] , 1, regs.x , PARAM_REG_X ); + DrawRegister( yRegs++, sReg[ BP_SRC_REG_Y ] , 1, regs.y , PARAM_REG_Y ); + DrawRegister( yRegs++, sReg[ BP_SRC_REG_PC] , 2, regs.pc, PARAM_REG_PC ); + DrawFlags ( yRegs , regs.ps, NULL); + yRegs += 2; + DrawRegister( yRegs++, sReg[ BP_SRC_REG_S ] , 2, regs.sp, PARAM_REG_SP ); + + DrawStack( yStack ); + + if (g_bConfigInfoTargetPointer) + { + DrawTargets( yTarget ); + } + + DrawZeroPagePointers( yZeroPage ); + +#if defined(SUPPORT_Z80_EMU) && defined(OUTPUT_Z80_REGS) + DrawRegister( 19,"AF",2,*(WORD*)(membank+REG_AF)); + DrawRegister( 20,"BC",2,*(WORD*)(membank+REG_BC)); + DrawRegister( 21,"DE",2,*(WORD*)(membank+REG_DE)); + DrawRegister( 22,"HL",2,*(WORD*)(membank+REG_HL)); + DrawRegister( 23,"IX",2,*(WORD*)(membank+REG_IX)); +#endif + + // Right Side + int yBreakpoints = 0; + int yWatches = yBreakpoints + MAX_BREAKPOINTS; // MAX_DISPLAY_BREAKPOINTS_LINES; // 7 + int yMemory = yWatches + MAX_WATCHES ; // MAX_DISPLAY_WATCHES_LINES ; // 14 + +// if ((MAX_DISPLAY_BREAKPOINTS_LINES + MAX_DISPLAY_WATCHES_LINES) < 12) +// yWatches++; + +#if DEBUG_FORCE_DISPLAY + if (true) +#else + if (g_nBreakpoints) +#endif + DrawBreakpoints( yBreakpoints ); + +#if DEBUG_FORCE_DISPLAY + if (true) +#else + if (g_nWatches) +#endif + DrawWatches( yWatches ); + + g_nDisplayMemoryLines = MAX_DISPLAY_MEMORY_LINES_1; + +#if DEBUG_FORCE_DISPLAY + if (true) +#else + if (g_aMemDump[0].bActive) +#endif + DrawMemory( yMemory, 0 ); // g_aMemDump[0].nAddress, g_aMemDump[0].eDevice); + + yMemory += (g_nDisplayMemoryLines + 1); + g_nDisplayMemoryLines = MAX_DISPLAY_MEMORY_LINES_2; + +#if DEBUG_FORCE_DISPLAY + if (true) +#else + if (g_aMemDump[1].bActive) +#endif + DrawMemory( yMemory, 1 ); // g_aMemDump[1].nAddress, g_aMemDump[1].eDevice); + +} + +//=========================================================================== +void DrawSubWindow_IO (Update_t bUpdate) +{ +} + +//=========================================================================== +void DrawSubWindow_Source (Update_t bUpdate) +{ +} + + +//=========================================================================== +void DrawSubWindow_Source2 (Update_t bUpdate) +{ +// if (! g_bSourceLevelDebugging) +// return; + + DebuggerSetColorFG( DebuggerGetColor( FG_SOURCE )); + + int iSource = g_iSourceDisplayStart; + int nLines = g_nDisasmWinHeight; + + int y = g_nDisasmWinHeight; + int nHeight = g_nDisasmWinHeight; + + if (g_aWindowConfig[ g_iWindowThis ].bSplit) // HACK: Split Window Height is odd, so bottom window gets +1 height + nHeight++; + + RECT rect; + rect.top = (y * g_nFontHeight); + rect.bottom = rect.top + (nHeight * g_nFontHeight); + rect.left = 0; + rect.right = DISPLAY_DISASM_RIGHT; // HACK: MAGIC #: 7 + +// Draw Title + char sTitle[ CONSOLE_WIDTH ]; + char sText [ CONSOLE_WIDTH ]; + strcpy ( sTitle, " Source: " ); + strncpy( sText , g_aSourceFileName, g_nConsoleDisplayWidth - strlen( sTitle ) - 1 ); + strcat ( sTitle, sText ); + + DebuggerSetColorBG( DebuggerGetColor( BG_SOURCE_TITLE )); + DebuggerSetColorFG( DebuggerGetColor( FG_SOURCE_TITLE )); + PrintText( sTitle, rect ); + rect.top += g_nFontHeight; + +// Draw Source Lines + int iBackground; + int iForeground; + + int iSourceCursor = 2; // (g_nDisasmWinHeight / 2); + int iSourceLine = FindSourceLine( regs.pc ); + + if (iSourceLine == NO_SOURCE_LINE) + { + iSourceCursor = NO_SOURCE_LINE; + } + else + { + iSourceLine -= iSourceCursor; + if (iSourceLine < 0) + iSourceLine = 0; + } + + for( int iLine = 0; iLine < nLines; iLine++ ) + { + if (iLine != iSourceCursor) + { + iBackground = BG_SOURCE_1; + if (iLine & 1) + iBackground = BG_SOURCE_2; + iForeground = FG_SOURCE; + } + else + { + // Hilighted cursor line + iBackground = BG_DISASM_PC_X; // _C + iForeground = FG_DISASM_PC_X; // _C + } + DebuggerSetColorBG( DebuggerGetColor( iBackground )); + DebuggerSetColorFG( DebuggerGetColor( iForeground )); + + DrawSourceLine( iSourceLine, rect ); + iSourceLine++; + } +} + +//=========================================================================== +void DrawSubWindow_Symbols (Update_t bUpdate) +{ +} + +//=========================================================================== +void DrawSubWindow_ZeroPage (Update_t bUpdate) +{ +} + + +//=========================================================================== +void DrawWindow_Code( Update_t bUpdate ) +{ + DrawSubWindow_Code( g_iWindowThis ); + +// DrawWindowTop( g_iWindowThis ); + DrawWindowBottom( bUpdate, g_iWindowThis ); + + DrawSubWindow_Info( g_iWindowThis ); +} + +// Full Screen console +//=========================================================================== +void DrawWindow_Console( Update_t bUpdate ) +{ + // Nothing to do, since text and draw background handled by DrawSubWindow_Console() + // If the full screen console is only showing partial lines + // don't erase the background + + // FillRect( g_hFrameDC, &rect, g_hConsoleBrushBG ); +} + +//=========================================================================== +void DrawWindow_Data( Update_t bUpdate ) +{ + DrawSubWindow_Data( g_iWindowThis ); + DrawSubWindow_Info( g_iWindowThis ); +} + +//=========================================================================== +void DrawWindow_IO( Update_t bUpdate ) +{ + DrawSubWindow_IO( g_iWindowThis ); + DrawSubWindow_Info( g_iWindowThis ); +} + +//=========================================================================== +void DrawWindow_Source( Update_t bUpdate ) +{ + DrawSubWindow_Source( g_iWindowThis ); + DrawSubWindow_Info( g_iWindowThis ); +} + +//=========================================================================== +void DrawWindow_Symbols( Update_t bUpdate ) +{ + DrawSubWindow_Symbols( g_iWindowThis ); + DrawSubWindow_Info( g_iWindowThis ); +} + +void DrawWindow_ZeroPage( Update_t bUpdate ) +{ + DrawSubWindow_ZeroPage( g_iWindowThis ); + DrawSubWindow_Info( g_iWindowThis ); +} + +//=========================================================================== +void DrawWindowBackground_Main( int g_iWindowThis ) +{ + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = DISPLAY_DISASM_RIGHT; + int nTop = GetConsoleTopPixels( g_nConsoleDisplayLines - 1 ); + rect.bottom = nTop; // DISPLAY_HEIGHT + + // TODO/FIXME: COLOR_BG_CODE -> g_iWindowThis, once all tab backgrounds are listed first in g_aColors ! + DebuggerSetColorBG( DebuggerGetColor( BG_DISASM_1 )); // COLOR_BG_CODE + +#if !DEBUG_FONT_NO_BACKGROUND_FILL_MAIN + FillRect( g_hFrameDC, &rect, g_hConsoleBrushBG ); +#endif +} + +//=========================================================================== +void DrawWindowBackground_Info( int g_iWindowThis ) +{ + RECT rect; + rect.top = 0; + rect.left = DISPLAY_DISASM_RIGHT; + rect.right = DISPLAY_WIDTH; + int nTop = GetConsoleTopPixels( g_nConsoleDisplayLines - 1 ); + rect.bottom = nTop; // DISPLAY_HEIGHT + + DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); // COLOR_BG_DATA + +#if !DEBUG_FONT_NO_BACKGROUND_FILL_INFO + FillRect( g_hFrameDC, &rect, g_hConsoleBrushBG ); +#endif +} + + +//=========================================================================== +void UpdateDisplay (Update_t bUpdate) +{ + static int spDrawMutex = false; + + if (spDrawMutex) + { +#if DEBUG + MessageBox( g_hFrameWindow, "Already drawing!", "!", MB_OK ); +#endif + } + spDrawMutex = true; + + FrameGetDC(); + + // Hack: Full screen console scrolled, "erase" left over console lines + if (g_iWindowThis == WINDOW_CONSOLE) + bUpdate |= UPDATE_BACKGROUND; + + if (bUpdate & UPDATE_BACKGROUND) + { +#if USE_APPLE_FONT + //VideoDrawLogoBitmap( g_hFrameDC ); // TC: Remove purple-flash after every single-step + + SetBkMode( g_hFrameDC, OPAQUE); + SetBkColor(g_hFrameDC, RGB(0,0,0)); +#else + SelectObject( g_hFrameDC, g_aFontConfig[ FONT_INFO ]._hFont ); // g_hFontDebugger +#endif + } + + SetTextAlign( g_hFrameDC, TA_TOP | TA_LEFT); + + if ((bUpdate & UPDATE_BREAKPOINTS) + || (bUpdate & UPDATE_DISASM) + || (bUpdate & UPDATE_FLAGS) + || (bUpdate & UPDATE_MEM_DUMP) + || (bUpdate & UPDATE_REGS) + || (bUpdate & UPDATE_STACK) + || (bUpdate & UPDATE_SYMBOLS) + || (bUpdate & UPDATE_TARGETS) + || (bUpdate & UPDATE_WATCH) + || (bUpdate & UPDATE_ZERO_PAGE)) + { + bUpdate |= UPDATE_BACKGROUND; + bUpdate |= UPDATE_CONSOLE_INPUT; + } + + if (bUpdate & UPDATE_BACKGROUND) + { + if (g_iWindowThis != WINDOW_CONSOLE) + { + DrawWindowBackground_Main( g_iWindowThis ); + DrawWindowBackground_Info( g_iWindowThis ); + } + } + + switch( g_iWindowThis ) + { + case WINDOW_CODE: + DrawWindow_Code( bUpdate ); + break; + + case WINDOW_CONSOLE: + DrawWindow_Console( bUpdate ); + break; + + case WINDOW_DATA: + DrawWindow_Data( bUpdate ); + break; + + case WINDOW_IO: + DrawWindow_IO( bUpdate ); + + case WINDOW_SOURCE: + DrawWindow_Source( bUpdate ); + + case WINDOW_SYMBOLS: + DrawWindow_Symbols( bUpdate ); + break; + + case WINDOW_ZEROPAGE: + DrawWindow_ZeroPage( bUpdate ); + + default: + break; + } + + if ((bUpdate & UPDATE_CONSOLE_DISPLAY) || (bUpdate & UPDATE_CONSOLE_INPUT)) + DrawSubWindow_Console( bUpdate ); + + FrameReleaseDC(); + + spDrawMutex = false; +} + + + + +//=========================================================================== +void DrawWindowBottom ( Update_t bUpdate, int iWindow ) +{ + if (! g_aWindowConfig[ iWindow ].bSplit) + return; + + WindowSplit_t * pWindow = &g_aWindowConfig[ iWindow ]; + +// if (pWindow->eBot == WINDOW_DATA) +// { +// DrawWindow_Data( bUpdate, false ); +// } + + if (pWindow->eBot == WINDOW_SOURCE) + DrawSubWindow_Source2( bUpdate ); +} + +//=========================================================================== +void DrawSubWindow_Code ( int iWindow ) +{ + int nLines = g_nDisasmWinHeight; + + // Check if we have a bad disasm + // BUG: This still doesn't catch all cases + // G FB53, SPACE, PgDn * + // Note: DrawDisassemblyLine() has kludge. +// DisasmCalcTopFromCurAddress( false ); + // These should be functionally equivalent. + // DisasmCalcTopFromCurAddress(); + // DisasmCalcBotFromTopAddress(); +#if !USE_APPLE_FONT + SelectObject( g_hFrameDC, g_aFontConfig[ FONT_DISASM_DEFAULT ]._hFont ); +#endif + + WORD nAddress = g_nDisasmTopAddress; // g_nDisasmCurAddress; + for (int iLine = 0; iLine < nLines; iLine++ ) + { + nAddress += DrawDisassemblyLine( iLine, nAddress ); + } + +#if !USE_APPLE_FONT + SelectObject( g_hFrameDC, g_aFontConfig[ FONT_INFO ]._hFont ); +#endif +} diff --git a/AppleWin/source/Debugger/Debugger_Display.h b/AppleWin/source/Debugger/Debugger_Display.h new file mode 100644 index 00000000..24b2a928 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Display.h @@ -0,0 +1,96 @@ +#ifndef DEBUGGER_DISPLAY_H +#define DEBUGGER_DISPLAY_H + +// use the new Debugger Font (Apple Font) +#define USE_APPLE_FONT 1 + +// Test Colors & Glyphs +#define DEBUG_APPLE_FONT 0 + +// Win32 Debugger Font +// 1 = Use Debugger_Font.BMP (7x8) +// 0 = Use CHARSET40.bmp (fg & bg colors aren't proper) +#define APPLE_FONT_NEW 1 + +#if APPLE_FONT_NEW + #define APPLE_FONT_BITMAP_PADDED 0 +#else + #define APPLE_FONT_BITMAP_PADDED 1 +#endif + + enum ConsoleFontSize_e + { +#if APPLE_FONT_NEW + // Grid Alignment + CONSOLE_FONT_GRID_X = 7, + CONSOLE_FONT_GRID_Y = 8, + + // Font Char Width/Height in pixels + CONSOLE_FONT_WIDTH = 7, + CONSOLE_FONT_HEIGHT = 8, +#else + CONSOLE_FONT_GRID_X = 8, + CONSOLE_FONT_GRID_Y = 8, + + // Font Char Width/Height in pixels + CONSOLE_FONT_WIDTH = 7, + CONSOLE_FONT_HEIGHT = 8, +#endif + }; + +// extern HDC g_hDstDC ; + extern HBRUSH g_hConsoleBrushFG; + extern HBRUSH g_hConsoleBrushBG; + + extern HDC g_hConsoleFontDC; + extern HBRUSH g_hConsoleFontBrush; + extern HBITMAP g_hConsoleFontBitmap; + + enum + { + DISPLAY_HEIGHT = 384, + MAX_DISPLAY_LINES = DISPLAY_HEIGHT / CONSOLE_FONT_HEIGHT, + }; + + int GetConsoleTopPixels( int y ); + + extern FontConfig_t g_aFontConfig[ NUM_FONTS ]; + + void DebuggerSetColorFG( COLORREF nRGB ); + void DebuggerSetColorBG( COLORREF nRGB, bool bTransparent = false ); + + void PrintGlyph ( const int x, const int y, const int iChar ); + int PrintText ( const char * pText, RECT & rRect ); + int PrintTextCursorX( const char * pText, RECT & rRect ); + int PrintTextCursorY( const char * pText, RECT & rRect ); + + void PrintTextColor ( const conchar_t * pText, RECT & rRect ); + + void DrawWindow_Source (Update_t bUpdate); + + void DrawBreakpoints ( int line); + void DrawConsoleInput (); + 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_ ); + + void DrawFlags ( int line, WORD nRegFlags, LPTSTR pFlagNames_); + void DrawMemory ( int line, int iMem ); + void DrawRegister ( int line, LPCTSTR name, int bytes, WORD value, int iSource = 0 ); + void DrawStack ( int line); + void DrawTargets ( int line); + void DrawWatches ( int line); + void DrawZeroPagePointers ( int line); + + void Debug_UpdatePalette( BYTE *pPalDst ); + +#endif diff --git a/AppleWin/source/Debugger/Debugger_Help.cpp b/AppleWin/source/Debugger/Debugger_Help.cpp new file mode 100644 index 00000000..7de91b73 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Help.cpp @@ -0,0 +1,1552 @@ +/* +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-2008, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Debugger + * + * Author: Copyright (C) 2006-2008 Michael Pohoreski + */ + +#include "StdAfx.h" + + +#define DEBUG_COLOR_CONSOLE 0 + + +// Utility ________________________________________________________________________________________ + +/* + String types: + + http://www.codeproject.com/cpp/unicode.asp + + TEXT() _tcsrev + _UNICODE Unicode _wcsrev + _MBCS Multi-byte _mbsrev + n/a ASCII strrev + +*/ + +// tests if pSrc fits into pDst +// returns true if pSrc safely fits into pDst, else false (pSrc would of overflowed pDst) +//=========================================================================== +bool TestStringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize ) +{ + int nLenDst = _tcslen( pDst ); + int nLenSrc = _tcslen( pSrc ); + int nSpcDst = nDstSize - nLenDst; + int nChars = MIN( nLenSrc, nSpcDst ); + + bool bOverflow = (nSpcDst <= nLenSrc); // 2.5.6.25 BUGFIX + if (bOverflow) + { + return false; + } + return true; +} + + +// tests if pSrc fits into pDst +// returns true if pSrc safely fits into pDst, else false (pSrc would of overflowed pDst) +//=========================================================================== +bool TryStringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize ) +{ + int nLenDst = _tcslen( pDst ); + int nLenSrc = _tcslen( pSrc ); + int nSpcDst = nDstSize - nLenDst; + int nChars = MIN( nLenSrc, nSpcDst ); + + bool bOverflow = (nSpcDst < nLenSrc); + if (bOverflow) + { + return false; + } + + _tcsncat( pDst, pSrc, nChars ); + return true; +} + +// cats string as much as possible +// returns true if pSrc safely fits into pDst, else false (pSrc would of overflowed pDst) +//=========================================================================== +int StringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize ) +{ + int nLenDst = _tcslen( pDst ); + int nLenSrc = _tcslen( pSrc ); + int nSpcDst = nDstSize - nLenDst; + int nChars = MIN( nLenSrc, nSpcDst ); + + _tcsncat( pDst, pSrc, nChars ); + + bool bOverflow = (nSpcDst < nLenSrc); + if (bOverflow) + return 0; + + return nChars; +} + + + +// Help ___________________________________________________________________________________________ + + +//=========================================================================== +Update_t HelpLastCommand() +{ + return Help_Arg_1( g_iCommand ); +} + + +// Loads the arguments with the command to get help on and call display help. +//=========================================================================== +Update_t Help_Arg_1( int iCommandHelp ) +{ + _Arg_1( iCommandHelp ); + + wsprintf( g_aArgs[ 1 ].sArg, g_aCommands[ iCommandHelp ].m_sName ); // .3 Fixed: Help_Arg_1() now copies command name into arg.name + + return CmdHelpSpecific( 1 ); +} + + +//=========================================================================== +void Help_Categories() +{ + const int nBuf = CONSOLE_WIDTH * 2; + + char sText[ nBuf ] = ""; + int nLen = 0; + + // TODO/FIXME: Colorize( sText, ... ) + // Colorize("Usage:") + nLen += StringCat( sText, CHC_USAGE , nBuf ); + nLen += StringCat( sText, "Usage", nBuf ); + + nLen += StringCat( sText, CHC_DEFAULT, nBuf ); + nLen += StringCat( sText, ": " , nBuf ); + + nLen += StringCat( sText, CHC_ARG_OPT, nBuf ); + nLen += StringCat( sText, "[ ", nBuf ); + + nLen += StringCat( sText, CHC_ARG_MAND, nBuf ); + nLen += StringCat( sText, "< ", nBuf ); + + + for (int iCategory = _PARAM_HELPCATEGORIES_BEGIN ; iCategory < _PARAM_HELPCATEGORIES_END; iCategory++) + { + char *pName = g_aParameters[ iCategory ].m_sName; + + if (nLen + strlen( pName ) >= (CONSOLE_WIDTH - 1)) + { + ConsolePrint( sText ); + sText[ 0 ] = 0; + nLen = StringCat( sText, " ", nBuf ); // indent + } + + StringCat( sText, CHC_COMMAND, nBuf ); + nLen += StringCat( sText, pName , nBuf ); + + if (iCategory < (_PARAM_HELPCATEGORIES_END - 1)) + { + char sSep[] = " | "; + + if (nLen + strlen( sSep ) >= (CONSOLE_WIDTH - 1)) + { + ConsolePrint( sText ); + sText[ 0 ] = 0; + nLen = StringCat( sText, " ", nBuf ); // indent + } + StringCat( sText, CHC_ARG_SEP, nBuf ); + nLen += StringCat( sText, sSep, nBuf ); + } + } + StringCat( sText, CHC_ARG_MAND, nBuf ); + StringCat( sText, " >", nBuf); + + StringCat( sText, CHC_ARG_OPT, nBuf ); + StringCat( sText, " ]", nBuf); + +// ConsoleBufferPush( sText ); + ConsolePrint( sText ); // Transcode colored text to native console color text + + sprintf( sText, "%sNotes%s: %s<>%s = mandatory, %s[]%s = optional, %s|%s argument option" + , CHC_USAGE + , CHC_DEFAULT + , CHC_ARG_MAND + , CHC_DEFAULT + , CHC_ARG_OPT + , CHC_DEFAULT + , CHC_ARG_SEP + , CHC_DEFAULT + ); + ConsolePrint( sText ); // Transcode colored text to native console color text +// ConsoleBufferPush( sText ); +} + +void Help_Examples() +{ + char sText[ CONSOLE_WIDTH ]; + sprintf( sText, " %sExamples%s:" + , CHC_USAGE + , CHC_DEFAULT + ); + ConsolePrint( sText ); +} + +//=========================================================================== +void Help_Range() +{ + ConsoleBufferPush( " Where is of the form:" ); + ConsoleBufferPush( " address , length [address,address+length)" ); + ConsoleBufferPush( " address : end [address,end]" ); +} + +//=========================================================================== +void Help_Operators() +{ + char sText[ CONSOLE_WIDTH ]; + +// sprintf( sText," %sOperators%s:" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); +// sprintf( sText," Operators: (Math)" ); + sprintf( sText," Operators: (%sMath%s)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s+%s Addition" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s-%s Subtraction" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s*%s Multiplication" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s/%s Division" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s%%%s Modulas or Remainder" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); +//ConsoleBufferPush( " Operators: (Bit Wise)" ); + sprintf( sText," Operators: (%sBit Wise%s)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s&%s Bit-wise and (AND)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s|%s Bit-wise or (OR )" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s^%s Bit-wise exclusive-or (EOR/XOR)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s!%s Bit-wise negation (NOT)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); +//ConsoleBufferPush( " Operators: (Input)" ); + sprintf( sText," Operators: (%sInput%s)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s@%s next number refers to search results", CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s\"%s Designate string in ASCII format" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s\'%s Desginate string in High-Bit apple format", CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s$%s Designate number/symbol" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s#%s Designate number in hex" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); +//ConsoleBufferPush( " Operators: (Range)" ); + sprintf( sText," Operators: (%sRange%s)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s,%s range seperator (2nd address is relative)", CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s:%s range seperator (2nd address is absolute)", CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); +// sprintf( sText," Operators: (Misc)" ); + sprintf( sText," Operators: (%sMisc%s)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText," %s//%s comment until end of line" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); +//ConsoleBufferPush( " Operators: (Breakpoint)" ); + sprintf( sText," Operators: (%sBreakpoint%s)" , CHC_USAGE, CHC_DEFAULT ); ConsolePrint( sText ); + + _tcscpy( sText, " " ); + _tcscat( sText, CHC_USAGE ); + int iBreakOp = 0; + for( iBreakOp = 0; iBreakOp < NUM_BREAKPOINT_OPERATORS; iBreakOp++ ) + { + if ((iBreakOp >= PARAM_BP_LESS_EQUAL) && + (iBreakOp <= PARAM_BP_GREATER_EQUAL)) + { + _tcscat( sText, g_aBreakpointSymbols[ iBreakOp ] ); + _tcscat( sText, " " ); + } + } + _tcscat( sText, CHC_DEFAULT ); + ConsolePrint( sText ); +} + +void Help_KeyboardShortcuts() +{ + ConsoleBufferPush(" Scrolling:" ); + ConsoleBufferPush(" Up Arrow" ); + ConsoleBufferPush(" Down Arrow" ); + ConsoleBufferPush(" Shift + Up Arrow" ); + ConsoleBufferPush(" Shift + Down Arrow" ); + ConsoleBufferPush(" Page Up" ); + ConsoleBufferPush(" Page Down" ); + ConsoleBufferPush(" Shift + Page Up" ); + ConsoleBufferPush(" Shift + Page Down" ); + + ConsoleBufferPush(" Bookmarks:" ); + ConsoleBufferPush(" Ctrl-Shift-#" ); + ConsoleBufferPush(" Ctrl-# " ); +} + + +void _ColorizeHeader( + char * & pDst,const char * & pSrc, + const char * pHeader, const int nHeaderLen ) +{ + int nLen; + + nLen = strlen( CHC_USAGE ); + strcpy( pDst, CHC_USAGE ); + pDst += nLen; + + nLen = nHeaderLen - 1; + strncpy( pDst, pHeader, nLen ); + pDst += nLen; + + pSrc += nHeaderLen; + + nLen = strlen( CHC_ARG_SEP ); + strcpy( pDst, CHC_ARG_SEP ); + pDst += nLen; + + *pDst = ':'; + pDst++; + + nLen = strlen( CHC_DEFAULT ); + strcpy( pDst, CHC_DEFAULT ); + pDst += nLen; +} + +void _ColorizeOperator( + char * & pDst, const char * & pSrc, + char * pOperator ) +{ + int nLen; + + nLen = strlen( pOperator ); + strcpy( pDst, pOperator ); + pDst += nLen; + + *pDst = *pSrc; + pDst++; + + nLen = strlen( CHC_DEFAULT ); + strcpy( pDst, CHC_DEFAULT ); + pDst += nLen; + + pSrc++; +} + + +bool Colorize( char * pDst, const char * pSrc ) +{ + if (! pSrc) + return false; + + if (! pDst) + return false; + + const char sNote [] = "Note:"; + const int nNote = sizeof( sNote ) - 1; + + const char sSeeAlso[] = "See also:"; + const char nSeeAlso = sizeof( sSeeAlso ) - 1; + + const char sUsage[] = "Usage:"; + const int nUsage = sizeof( sUsage ) - 1; + + const char sTotal[] = "Total:"; + const int nTotal = sizeof( sTotal ) - 1; + + int nLen = 0; + while (*pSrc) + { + if (strncmp( sUsage, pSrc, nUsage) == 0) + { + _ColorizeHeader( pDst, pSrc, sUsage, nUsage ); + } + else + if (strncmp( sSeeAlso, pSrc, nSeeAlso) == 0) + { + _ColorizeHeader( pDst, pSrc, sSeeAlso, nSeeAlso ); + } + else + if (strncmp( sNote, pSrc, nNote) == 0) + { + _ColorizeHeader( pDst, pSrc, sNote, nNote ); + } + else + if (strncmp( sTotal, pSrc, nNote) == 0) + { + _ColorizeHeader( pDst, pSrc, sTotal, nTotal ); + } + else + if (*pSrc == '[') + { + _ColorizeOperator( pDst, pSrc, CHC_ARG_OPT ); + } + else + if (*pSrc == ']') + { + _ColorizeOperator( pDst, pSrc, CHC_ARG_OPT ); + } + else + if (*pSrc == '<') + { + _ColorizeOperator( pDst, pSrc, CHC_ARG_MAND ); + } + else + if (*pSrc == '>') + { + _ColorizeOperator( pDst, pSrc, CHC_ARG_MAND ); + } + else + if (*pSrc == '|') + { + _ColorizeOperator( pDst, pSrc, CHC_ARG_SEP ); + } + else + if (*pSrc == '\'') + { + _ColorizeOperator( pDst, pSrc, CHC_ARG_SEP ); + } + else + { + *pDst = *pSrc; + pDst++; + pSrc++; + } + } + *pDst = 0; + return true; +} + +//=========================================================================== +Update_t CmdMOTD( int nArgs ) +{ + char sText[ CONSOLE_WIDTH*2 ]; + char sTemp[ CONSOLE_WIDTH*2 ]; + +#if DEBUG_COLOR_CONSOLE + ConsolePrint( "`" ); + ConsolePrint( "`A" ); + ConsolePrint( "`2`A" ); +#endif + + sprintf( sText, "`9`A`7 Apple `9][ ][+ //e `7Emulator for Windows (TM) `9`@" ); + ConsolePrint( sText ); + + CmdVersion(0); + CmdSymbols(0); + sprintf( sTemp, " '%sCtrl ~'%s console, '%s%s'%s (specific), '%s%s'%s (all)" + , CHC_KEY + , CHC_DEFAULT + , CHC_COMMAND + , g_aCommands[ CMD_HELP_SPECIFIC ].m_sName + , CHC_DEFAULT +// , g_aCommands[ CMD_HELP_SPECIFIC ].pHelpSummary + , CHC_COMMAND + , g_aCommands[ CMD_HELP_LIST ].m_sName + , CHC_DEFAULT +// , g_aCommands[ CMD_HELP_LIST ].pHelpSummary + ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + + ConsoleUpdate(); + + return UPDATE_ALL; +} + + +// Help on specific command +//=========================================================================== +Update_t CmdHelpSpecific (int nArgs) +{ + int iArg; + char sText[ CONSOLE_WIDTH * 2 ]; + char sTemp[ CONSOLE_WIDTH * 2 ]; + ZeroMemory( sText, CONSOLE_WIDTH*2 ); + ZeroMemory( sTemp, CONSOLE_WIDTH*2 ); + + if (! nArgs) + { + Help_Categories(); + return ConsoleUpdate(); + } + + CmdFuncPtr_t pFunction = NULL; + bool bAllCommands = false; + bool bCategory = false; + bool bDisplayCategory = true; + + if ((! _tcscmp( g_aArgs[1].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName)) || + (! _tcscmp( g_aArgs[1].sArg, g_aParameters[ PARAM_MEM_SEARCH_WILD ].m_sName)) ) + { + bAllCommands = true; + nArgs = NUM_COMMANDS; + } + + // If Help on category, push command name as arg + // Mame has categories: + // General, Memory, Execution, Breakpoints, Watchpoints, Expressions, Comments + int iParam = 0; + + int nNewArgs = 0; + int iCmdBegin = 0; + int iCmdEnd = 0; + int nFound = 0; + int iCommand = 0; + + if (! bAllCommands) + { + for (iArg = 1; iArg <= nArgs; iArg++ ) + { + // int nFoundCategory = FindParam( g_aArgs[ iArg ].sArg, MATCH_EXACT, iParam, _PARAM_HELPCATEGORIES_BEGIN, _PARAM_HELPCATEGORIES_END ); + int nFoundCategory = FindParam( g_aArgs[ iArg ].sArg, MATCH_FUZZY, iParam, _PARAM_HELPCATEGORIES_BEGIN, _PARAM_HELPCATEGORIES_END ); + bCategory = true; + switch( iParam ) + { + case PARAM_CAT_BOOKMARKS : iCmdBegin = CMD_BOOKMARK ; iCmdEnd = CMD_BOOKMARK_SAVE ; break; + case PARAM_CAT_BREAKPOINTS: iCmdBegin = CMD_BREAKPOINT ; iCmdEnd = CMD_BREAKPOINT_SAVE ; break; + case PARAM_CAT_CONFIG : iCmdBegin = CMD_BENCHMARK ; iCmdEnd = CMD_CONFIG_SAVE ; break; + case PARAM_CAT_CPU : iCmdBegin = CMD_ASSEMBLE ; iCmdEnd = CMD_UNASSEMBLE ; break; + case PARAM_CAT_FLAGS : + // iCmdBegin = CMD_FLAG_CLEAR ; iCmdEnd = CMD_FLAG_SET_N ; break; + // HACK: check if we have an exact command match first + nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); + if (nFound && (iCommand != CMD_MEMORY_FILL)) + { + iCmdBegin = CMD_FLAG_CLEAR ; iCmdEnd = CMD_FLAG_SET_N; + bCategory = true; + } + else + bCategory = false; + break; + case PARAM_CAT_HELP : iCmdBegin = CMD_HELP_LIST ; iCmdEnd = CMD_MOTD ; break; + case PARAM_CAT_KEYBOARD : + // HACK: check if we have an exact command match first + nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); + if ((!nFound) || (iCommand != CMD_INPUT_KEY)) + { + nArgs = 0; + Help_KeyboardShortcuts(); + } + bCategory = false; + break; + case PARAM_CAT_MEMORY : + // iCmdBegin = CMD_MEMORY_COMPARE ; iCmdEnd = CMD_MEMORY_FILL ; break; + nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); + if (nFound && (iCommand != CMD_MEMORY_MOVE)) + { + iCmdBegin = CMD_MEMORY_COMPARE ; iCmdEnd = CMD_MEMORY_FILL ; + bCategory = true; + } + else + bCategory = false; + break; + + case PARAM_CAT_OUTPUT : + // HACK: check if we have an exact command match first + nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); + if (nFound && (iCommand != CMD_OUT)) + { + iCmdBegin = CMD_OUTPUT_CALC ; iCmdEnd = CMD_OUTPUT_RUN ; + bCategory = true; + } + else + bCategory = false; + break; + + case PARAM_CAT_SYMBOLS : + // HACK: check if we have an exact command match first + nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); + if (nFound && (iCommand != CMD_SYMBOLS_LOOKUP) && (iCommand != CMD_MEMORY_SEARCH)) + { + iCmdBegin = CMD_SYMBOLS_LOOKUP ; iCmdEnd = CMD_SYMBOLS_LIST ; + bCategory = true; + } + else + bCategory = false; + break; + + case PARAM_CAT_VIEW : + // HACK: check if we have an exact command match first +// nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); +// if (nFound && (iCommand != CMD_VIEW_TEXT4X)) + { + iCmdBegin = CMD_VIEW_TEXT4X ; iCmdEnd = CMD_VIEW_DHGR2 ; + bCategory = true; + } +// else +// bCategory = false; + break; + + case PARAM_CAT_WATCHES : + // HACK: check if we have an exact command match first + nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); + if (nFound && (iCommand != CMD_WATCH_ADD)) + { + iCmdBegin = CMD_WATCH_ADD ; iCmdEnd = CMD_WATCH_LIST ; + bCategory = true; + } + else + bCategory = false; + break; + + case PARAM_CAT_WINDOW : iCmdBegin = CMD_WINDOW ; iCmdEnd = CMD_WINDOW_OUTPUT ; break; + case PARAM_CAT_ZEROPAGE : iCmdBegin = CMD_ZEROPAGE_POINTER; iCmdEnd = CMD_ZEROPAGE_POINTER_SAVE;break; + +// case PARAM_CAT_EXPRESSION : // fall-through + case PARAM_CAT_OPERATORS : nArgs = 0; Help_Operators(); break; + + case PARAM_CAT_RANGE : + // HACK: check if we have an exact command match first + nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); + if ((!nFound) || (iCommand != CMD_REGISTER_SET)) + { + nArgs = 0; + Help_Range(); + } + bCategory = false; + break; + default: + bCategory = false; + break; + } + if (iCmdEnd) + iCmdEnd++; + nNewArgs = (iCmdEnd - iCmdBegin); + if (nNewArgs > 0) + break; + } + } + + if (nNewArgs > 0) + { + nArgs = nNewArgs; + for (iArg = 1; iArg <= nArgs; iArg++ ) + { +#if DEBUG_VAL_2 + g_aArgs[ iArg ].nVal2 = iCmdBegin + iArg - 1; +#endif + g_aArgs[ iArg ].nValue = iCmdBegin + iArg - 1; + } + } + + for (iArg = 1; iArg <= nArgs; iArg++ ) + { + iCommand = 0; + nFound = 0; + + if (bCategory) + { +#if DEBUG_VAL_2 + iCommand = g_aArgs[iArg].nVal2; +#endif + iCommand = g_aArgs[ iArg ].nValue; + nFound = 1; + } + else + if (bAllCommands) + { + iCommand = iArg; + if (iCommand == NUM_COMMANDS) // skip: Internal Consistency Check __COMMANDS_VERIFY_TXT__ + continue; + nFound = 1; + } + else + nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand ); + + if (nFound > 1) + { + DisplayAmbigiousCommands( nFound ); + } + + if (iCommand > NUM_COMMANDS) + continue; + + if ((nArgs == 1) && (! nFound)) + iCommand = g_aArgs[iArg].nValue; + + Command_t *pCommand = & g_aCommands[ iCommand ]; + + if (! nFound) + { + iCommand = NUM_COMMANDS; + pCommand = NULL; + } + +// if (nFound && (! bAllCommands) && (! bCategory)) + if (nFound && (! bAllCommands) && bDisplayCategory) + { + char sCategory[ CONSOLE_WIDTH ]; + int iCmd = g_aCommands[ iCommand ].iCommand; // Unaliased command + + // HACK: Major kludge to display category!!! + if (iCmd <= CMD_UNASSEMBLE) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_CPU ].m_sName ); + else + if (iCmd <= CMD_BOOKMARK_SAVE) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_BOOKMARKS ].m_sName ); + else + if (iCmd <= CMD_BREAKPOINT_SAVE) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_BREAKPOINTS ].m_sName ); + else + if (iCmd <= CMD_CONFIG_SAVE) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_CONFIG ].m_sName ); + else + if (iCmd <= CMD_CURSOR_PAGE_DOWN_4K) + wsprintf( sCategory, "Scrolling" ); + else + if (iCmd <= CMD_FLAG_SET_N) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_FLAGS ].m_sName ); + else + if (iCmd <= CMD_MOTD) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_HELP ].m_sName ); + else + if (iCmd <= CMD_MEMORY_FILL) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_MEMORY ].m_sName ); + else + if (iCmd <= CMD_OUTPUT_RUN) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_OUTPUT ].m_sName ); + else + if (iCmd <= CMD_SYNC) + wsprintf( sCategory, "Source" ); + else + if (iCmd <= CMD_SYMBOLS_LIST) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_SYMBOLS ].m_sName ); + else + if (iCmd <= CMD_VIEW_DHGR2) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_VIEW ].m_sName ); + else + if (iCmd <= CMD_WATCH_SAVE) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_WATCHES ].m_sName ); + else + if (iCmd <= CMD_WINDOW_OUTPUT) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_WINDOW ].m_sName ); + else + if (iCmd <= CMD_ZEROPAGE_POINTER_SAVE) + wsprintf( sCategory, g_aParameters[ PARAM_CAT_ZEROPAGE ].m_sName ); + else + wsprintf( sCategory, "Unknown!" ); + + sprintf( sText, "%sCategory%s: %s%s" + , CHC_USAGE + , CHC_DEFAULT + , CHC_CATEGORY + , sCategory ); + ConsolePrint( sText ); + + if (bCategory) + if (bDisplayCategory) + bDisplayCategory = false; + } + + if (pCommand) + { + char *pHelp = pCommand->pHelpSummary; + if (pHelp) + { + if (bCategory) + sprintf( sText, "%s%8s%s, " + , CHC_COMMAND + , pCommand->m_sName + , CHC_ARG_SEP + ); + else + sprintf( sText, "%s%s%s, " + , CHC_COMMAND + , pCommand->m_sName + , CHC_ARG_SEP + ); + +// if (! TryStringCat( sText, pHelp, g_nConsoleDisplayWidth )) +// { +// if (! TryStringCat( sText, pHelp, CONSOLE_WIDTH-1 )) +// { + strncat( sText, CHC_DEFAULT, CONSOLE_WIDTH ); + strncat( sText, pHelp , CONSOLE_WIDTH ); +// ConsoleBufferPush( sText ); +// } +// } + ConsolePrint( sText ); + } + else + { +#if _DEBUG + wsprintf( sText, "%s <-- Missing", pCommand->m_sName ); + ConsoleBufferPush( sText ); + #if DEBUG_COMMAND_HELP + if (! bAllCommands) // Release version doesn't display message + { + wsprintf( sText, "Missing Summary Help: %s", g_aCommands[ iCommand ].aName ); + ConsoleBufferPush( sText ); + } + #endif +#endif + } + + if (bCategory) + continue; + } + + // MASTER HELP + switch (iCommand) + { + // CPU / General + case CMD_ASSEMBLE: + ConsoleBufferPush( " Built-in assember isn't functional yet." ); + break; + case CMD_UNASSEMBLE: + Colorize( sText, " Usage: [address | symbol]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Disassembles memory." ); + break; + case CMD_GO: + Colorize( sText, " Usage: address | symbol [Skip,Length]" ); + ConsolePrint( sText ); + Colorize( sText, " Usage: address | symbol [Start:End]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Skip : Start address to skip stepping" ); + ConsoleBufferPush( " Length: Range of bytes past start address to skip stepping" ); + ConsoleBufferPush( " End : Inclusive end address to skip stepping" ); + ConsoleBufferPush( " If the Program Counter is outside the skip range, resumes single-stepping." ); + ConsoleBufferPush( " Can be used to skip ROM/OS/user code." ); + Help_Examples(); + sprintf( sText, "%s G C600 FA00,600" , CHC_EXAMPLE ); ConsolePrint( sText ); + sprintf( sText, "%s G C600 F000:FFFF", CHC_EXAMPLE ); ConsolePrint( sText ); + break; + case CMD_JSR: + Colorize( sText, " %sUsage%s: %s[symbol | address]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Pushes PC on stack; calls the named subroutine." ); + break; + case CMD_NOP: + ConsoleBufferPush( TEXT(" Puts a NOP opcode at current instruction") ); + break; + case CMD_OUT: + Colorize( sText, " Usage: [address8 | address16 | symbol] ## [##]" ); + ConsolePrint( sText ); + ConsoleBufferPush( TEXT(" Ouput a byte or word to the IO address $C0xx" ) ); + break; + case CMD_PROFILE: + sprintf( sTemp, " Usage: [%s | %s | %s]" + , g_aParameters[ PARAM_RESET ].m_sName + , g_aParameters[ PARAM_SAVE ].m_sName + , g_aParameters[ PARAM_LIST ].m_sName + ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( " No arguments resets the profile." ); + break; + // Registers + case CMD_REGISTER_SET: + Colorize( sText, " Usage: " ); + ConsolePrint( sText ); + ConsoleBufferPush( " Where is one of: A X Y PC SP " ); + sprintf( sTemp, " See also: %s%s" + , CHC_CATEGORY + , g_aParameters[ PARAM_CAT_OPERATORS ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + Help_Examples(); + sprintf( sText, "%s R PC RESET + 1", CHC_EXAMPLE ); ConsolePrint( sText ); + sprintf( sText, "%s R PC $FC58" , CHC_EXAMPLE ); ConsolePrint( sText ); + sprintf( sText, "%s R A A1" , CHC_EXAMPLE ); ConsolePrint( sText ); + sprintf( sText, "%s R A $A1" , CHC_EXAMPLE ); ConsolePrint( sText ); + sprintf( sText, "%s R A #A1" , CHC_EXAMPLE ); ConsolePrint( sText ); + break; + case CMD_SOURCE: +// ConsoleBufferPush( TEXT(" Reads assembler source file." ) ); + sprintf( sTemp, " Usage: [ %s | %s ] \"filename\"" , g_aParameters[ PARAM_SRC_MEMORY ].m_sName, g_aParameters[ PARAM_SRC_SYMBOLS ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + sprintf( sText, " %s: read source bytes into memory." , g_aParameters[ PARAM_SRC_MEMORY ].m_sName ); ConsoleBufferPush( sText ); + sprintf( sText, " %s: read symbols into Source symbol table.", g_aParameters[ PARAM_SRC_SYMBOLS ].m_sName ); ConsoleBufferPush( sText ); + sprintf( sText, " Supports: %s." , g_aParameters[ PARAM_SRC_MERLIN ].m_sName ); ConsoleBufferPush( sText ); + break; + case CMD_STEP_OUT: + ConsoleBufferPush( " Steps out of current subroutine" ); + ConsoleBufferPush( " Hotkey: Ctrl-Space" ); // TODO: FIXME + break; + case CMD_STEP_OVER: // Bad name? FIXME/TODO: do we need to rename? + Colorize( sText, " Usage: [#]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Steps, # times, thru current instruction" ); + ConsoleBufferPush( " JSR will be stepped into AND out of." ); + ConsoleBufferPush( " Hotkey: Ctrl-Space" ); // TODO: FIXME + break; + case CMD_TRACE: + Colorize( sText, " Usage: [#]" ); ConsolePrint( sText ); + ConsoleBufferPush( " Traces, # times, current instruction(s)" ); + ConsoleBufferPush( " JSR will be stepped into" ); + ConsoleBufferPush( " Hotkey: Shift-Space" ); + case CMD_TRACE_FILE: + Colorize( sText, " Usage: \"[filename]\"" ); + ConsolePrint( sText ); + break; + case CMD_TRACE_LINE: + Colorize( sText, " Usage: [#]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Traces into current instruction" ); + ConsoleBufferPush( " with cycle counting." ); + break; + // Bookmarks + case CMD_BOOKMARK: + case CMD_BOOKMARK_ADD: + Colorize( sText, " Usage: [address | symbol]" ); ConsolePrint( sText ); + Colorize( sText, " Usage: #
" ); ConsolePrint( sText ); + ConsoleBufferPush(" If no address or symbol is specified, lists the current bookmarks." ); + ConsoleBufferPush(" Updates the specified bookmark (#)" ); + Help_Examples(); + sprintf( sText, "%s %s RESET ", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s 1 HOME", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + break; + case CMD_BOOKMARK_CLEAR: + Colorize( sText, " Usage: [# | *]" ); ConsolePrint( sText ); + ConsoleBufferPush( " Clears specified bookmark, or all." ); + Help_Examples(); + sprintf( sText, "%s %s 1", CHC_EXAMPLE, pCommand->m_sName ); + ConsolePrint( sText ); + break; + case CMD_BOOKMARK_LIST: +// case CMD_BOOKMARK_LOAD: + case CMD_BOOKMARK_SAVE: + break; + // Breakpoints + case CMD_BREAKPOINT: + sprintf( sTemp, TEXT(" Usage: [%s%s | %s%s | %s%s]") + , CHC_COMMAND + , g_aParameters[ PARAM_LOAD ].m_sName + , CHC_COMMAND + , g_aParameters[ PARAM_SAVE ].m_sName + , CHC_COMMAND + , g_aParameters[ PARAM_RESET ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + sprintf( sText, " Maximum breakpoints: %s%d", CHC_NUM_DEC, MAX_BREAKPOINTS ); + ConsolePrint( sText ); + ConsoleBufferPush( " Set breakpoint at PC if no args." ); + ConsoleBufferPush( " Loading/Saving not yet implemented." ); + break; + case CMD_BREAKPOINT_ADD_REG: + Colorize( sText, " Usage: [A|X|Y|PC|S] [op] " ); + ConsolePrint( sText ); + ConsoleBufferPush( " Set breakpoint when reg is [op] value" ); + ConsoleBufferPush( " Default operator is '='" ); + sprintf( sTemp, " See also: %s%s" + , CHC_CATEGORY + , g_aParameters[ PARAM_CAT_OPERATORS ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + // ConsoleBufferPush( " Examples:" ); + Help_Examples(); + sprintf( sText, "%s %s PC < D000" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s PC = F000:FFFF PC < D000,1000", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s A <= D5" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s A != 01:FF" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s X = A5" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + break; + case CMD_BREAKPOINT_ADD_SMART: + Colorize( sText, " Usage: [address | register]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " If address, sets two breakpoints" ); + ConsoleBufferPush( " 1. one memory access at address" ); + ConsoleBufferPush( " 2. if PC reaches address" ); +// "Sets a breakpoint at the current PC or specified address." ); + ConsoleBufferPush( " If an IO address, sets breakpoint on IO access." ); + ConsoleBufferPush( " If register, sets a breakpoint on memory access at address of register." ); + break; + case CMD_BREAKPOINT_ADD_PC: + Colorize( sText, " Usage: [address]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Sets a breakpoint at the current PC or at the specified address." ); + break; + case CMD_BREAKPOINT_CLEAR: + Colorize( sText, " Usage: [# | *]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Clears specified breakpoint, or all." ); + Help_Examples(); + sprintf( sText, "%s %s 1", CHC_EXAMPLE, pCommand->m_sName ); + ConsolePrint( sText ); + break; + case CMD_BREAKPOINT_DISABLE: + Colorize( sText, " Usage: [# [,#] | *]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Disable breakpoint previously set, or all." ); + Help_Examples(); + sprintf( sText, "%s %s 1", CHC_EXAMPLE, pCommand->m_sName ); + ConsolePrint( sText ); + break; + case CMD_BREAKPOINT_ENABLE: + Colorize( sText, " Usage: [# [,#] | *]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Re-enables breakpoint previously set, or all." ); + Help_Examples(); + sprintf( sText, "%s %s 1", CHC_EXAMPLE, pCommand->m_sName ); + ConsolePrint( sText ); + break; + case CMD_BREAKPOINT_LIST: + break; + // Config - Load / Save + case CMD_CONFIG_LOAD: + Colorize( sText, " Usage: [\"filename\"]" ); + ConsolePrint( sText ); + sprintf( sText, " Load debugger configuration from '%s', or the specificed file.", g_sFileNameConfig ); ConsoleBufferPush( sText ); + break; + case CMD_CONFIG_SAVE: + Colorize( sText, " Usage: [\"filename\"]" ); + ConsolePrint( sText ); + sprintf( sText, " Save debugger configuration to '%s', or the specificed file.", g_sFileNameConfig ); ConsoleBufferPush( sText ); + break; + // Config - Color + case CMD_CONFIG_COLOR: + ConsoleBufferPush( TEXT(" Usage: [<#> | <# RR GG BB>]" ) ); + ConsoleBufferPush( TEXT(" 0 params: switch to 'color' scheme" ) ); + ConsoleBufferPush( TEXT(" 1 param : dumps R G B for scheme 'color'") ); + ConsoleBufferPush( TEXT(" 4 params: sets R G B for scheme 'color'" ) ); + break; + case CMD_CONFIG_MONOCHROME: + ConsoleBufferPush( TEXT(" Usage: [<#> | <# RR GG BB>]" ) ); + ConsoleBufferPush( TEXT(" 0 params: switch to 'monochrome' scheme" ) ); + ConsoleBufferPush( TEXT(" 1 param : dumps R G B for scheme 'monochrome'") ); + ConsoleBufferPush( TEXT(" 4 params: sets R G B for scheme 'monochrome'" ) ); + break; + // Config - Diasm + case CMD_CONFIG_DISASM: + { + Colorize( sText, " Note: All arguments effect the disassembly view" ); + ConsolePrint( sText ); + + sprintf( sTemp, " Usage: [%s%s | %s%s | %s%s | %s%s | %s%s]" + , CHC_COMMAND + , g_aParameters[ PARAM_CONFIG_BRANCH ].m_sName + , CHC_COMMAND + , g_aParameters[ PARAM_CONFIG_COLON ].m_sName + , CHC_COMMAND + , g_aParameters[ PARAM_CONFIG_OPCODE ].m_sName + , CHC_COMMAND + , g_aParameters[ PARAM_CONFIG_SPACES ].m_sName + , CHC_COMMAND + , g_aParameters[ PARAM_CONFIG_TARGET ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( " Display current settings if no args." ); + + iParam = PARAM_CONFIG_BRANCH; + sprintf( sTemp, " Usage: %s [#]", g_aParameters[ iParam ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( " Set the type of branch character:" ); + sprintf( sText, " %d off, %d plain, %d fancy", + DISASM_BRANCH_OFF, DISASM_BRANCH_PLAIN, DISASM_BRANCH_FANCY ); + ConsoleBufferPush( sText ); + sprintf( sText, " i.e. %s%s %s 1", CHC_EXAMPLE, pCommand->m_sName, g_aParameters[ iParam ].m_sName ); + ConsolePrint( sText ); + + iParam = PARAM_CONFIG_COLON; + sprintf( sTemp, " Usage: %s [0|1]", g_aParameters[ iParam ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( " Display a colon after the address" ); + sprintf( sText, " i.e. %s%s %s 0", CHC_EXAMPLE, pCommand->m_sName, g_aParameters[ iParam ].m_sName ); + ConsolePrint( sText ); + + iParam = PARAM_CONFIG_OPCODE; + sprintf( sTemp, " Usage: %s [0|1]", g_aParameters[ iParam ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( " Display opcode(s) after colon" ); + sprintf( sText, " i.e. %s%s %s 1", CHC_EXAMPLE, pCommand->m_sName, g_aParameters[ iParam ].m_sName ); + ConsolePrint( sText ); + + iParam = PARAM_CONFIG_SPACES; + sprintf( sTemp, " Usage: %s [0|1]", g_aParameters[ iParam ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( " Display spaces between opcodes" ); + sprintf( sText, " i.e. %s%s %s 0", CHC_EXAMPLE, pCommand->m_sName, g_aParameters[ iParam ].m_sName ); + ConsolePrint( sText ); + + iParam = PARAM_CONFIG_TARGET; + sprintf( sTemp, " Usage: %s [#]", g_aParameters[ iParam ].m_sName ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( " Set the type of target address/value displayed:" ); + sprintf( sText, " %d off, %d value only, %d address only, %d both", + DISASM_TARGET_OFF, DISASM_TARGET_VAL, DISASM_TARGET_ADDR, DISASM_TARGET_BOTH ); + ConsoleBufferPush( sText ); + sprintf( sText, " i.e. %s%s %s %d", CHC_EXAMPLE, pCommand->m_sName, g_aParameters[ iParam ].m_sName, DISASM_TARGET_VAL ); + ConsolePrint( sText ); + break; + } + // Config - Font + case CMD_CONFIG_FONT: + sprintf( sText, " No longer applicable with new debugger font" ); + ConsolePrint( sText ); +/* + sprintf( sText, TEXT(" Usage: [%s | %s] \"FontName\" [Height]" ), + g_aParameters[ PARAM_FONT_MODE ].m_sName, g_aParameters[ PARAM_DISASM ].m_sName ); + ConsoleBufferPush( sText ); + ConsoleBufferPush( TEXT(" i.e. FONT \"Courier\" 12" ) ); + ConsoleBufferPush( TEXT(" i.e. FONT \"Lucida Console\" 12" ) ); + wsprintf( sText, TEXT(" %s Controls line spacing."), g_aParameters[ PARAM_FONT_MODE ].m_sName ); + ConsoleBufferPush( sText ); + wsprintf( sText, TEXT(" Valid values are: %d, %d, %d." ), + FONT_SPACING_CLASSIC, FONT_SPACING_CLEAN, FONT_SPACING_COMPRESSED ); + ConsoleBufferPush( sText ); +*/ + break; + + // Memory + case CMD_MEMORY_ENTER_BYTE: + sprintf( sTemp, " Usage:
## [## ... ##]" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( TEXT(" Sets memory to the specified 8-Bit Values (bytes)" ) ); + Help_Examples(); + sprintf( sText, "%s %s 00 4C FF69", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s 00:4C FF69", CHC_EXAMPLE ); ConsolePrint( sText ); + break; + case CMD_MEMORY_ENTER_WORD: + sprintf( sTemp, " Usage:
#### [#### ... ####]" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( TEXT(" Sets memory to the specified 16-Bit Values (words)" ) ); + break; + case CMD_MEMORY_FILL: + sprintf( sTemp, " Usage:
##" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( TEXT(" Fills the memory range with the specified byte" ) ); + sprintf( sTemp, " Note: Can't fill IO addresses %s$%sC0xx", CHC_ARG_SEP, CHC_ADDRESS ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + Help_Examples(); + sprintf( sText, "%s %s 2000:3FFF 00 // Clear HGR page 1", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s 4000,2000 00 // Clear HGR page 2", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s 2000 3FFF 00 // Clear HGR page 1", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + break; + case CMD_MEMORY_MOVE: + sprintf( sTemp, " Usage: destination range" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( TEXT(" Copies bytes specified by the range to the destination starting address." ) ); + Help_Examples(); + sprintf( sText, "%s %s 4000 2000:3FFF // move HGR page 1 to page 2", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s 2001 2000:3FFF // clear $2000-$3FFF with the byte at $2000", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s 2001<2000:3FFFM", CHC_EXAMPLE ); ConsolePrint( sText ); + break; +// case CMD_MEM_MINI_DUMP_ASC_1: +// case CMD_MEM_MINI_DUMP_ASC_2: + case CMD_MEM_MINI_DUMP_ASCII_1: + case CMD_MEM_MINI_DUMP_ASCII_2: + sprintf( sTemp, " Usage:
" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( TEXT(" Displays ASCII text in the Mini-Memory area") ); + ConsoleBufferPush( TEXT(" ASCII control chars are hilighted") ); + ConsoleBufferPush( TEXT(" ASCII hi-bit chars are normal") ); +// break; +// case CMD_MEM_MINI_DUMP_TXT_LO_1: +// case CMD_MEM_MINI_DUMP_TXT_LO_2: + case CMD_MEM_MINI_DUMP_APPLE_1: + case CMD_MEM_MINI_DUMP_APPLE_2: + sprintf( sTemp, " Usage:
" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + ConsoleBufferPush( " Displays APPLE text in the Mini-Memory area" ); + ConsoleBufferPush( " APPLE control chars are inverse" ); + ConsoleBufferPush( " APPLE hi-bit chars are normal" ); + break; +// case CMD_MEM_MINI_DUMP_TXT_HI_1: +// case CMD_MEM_MINI_DUMP_TXT_HI_2: +// ConsoleBufferPush( TEXT(" Usage:
") ); +// ConsoleBufferPush( TEXT(" Displays text in the Memory Mini-Dump area") ); +// ConsoleBufferPush( TEXT(" ASCII chars with the hi-bit set, is inverse") ); + break; + + case CMD_MEMORY_LOAD: + case CMD_MEMORY_SAVE: + if (iCommand == CMD_MEMORY_LOAD) + { + sprintf( sTemp, " Usage: [\"Filename\"],address[,length]" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + sprintf( sTemp, " Usage: [\"Filename\"],range" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + Help_Range(); + ConsoleBufferPush( " Notes: If no filename specified, defaults to the last filename (if possible)" ); + } + if (iCommand == CMD_MEMORY_SAVE) + { + sprintf( sTemp, " Usage: [\"Filename\"],address,length" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + sprintf( sTemp, " Usage: [\"Filename\"],range" ); + Colorize( sText, sTemp ); + ConsolePrint( sText ); + Help_Range(); + ConsoleBufferPush( " Notes: If no filename specified, defaults to: '####.####.bin'" ); + ConsoleBufferPush( " Where the form is
..bin" ); + } + +// ConsoleBufferPush( TEXT(" Examples:" ) ); + Help_Examples(); + sprintf( sText, "%s BSAVE \"test\",FF00,100" , CHC_EXAMPLE ); ConsolePrint( sText ); + sprintf( sText, "%s BLOAD \"test\",2000:2010" , CHC_EXAMPLE ); ConsolePrint( sText ); + sprintf( sText, "%s BSAVE \"test\",F000:FFFF" , CHC_EXAMPLE ); ConsolePrint( sText ); + sprintf( sText, "%s BLOAD \"test\",4000" , CHC_EXAMPLE ); ConsolePrint( sText ); + break; + case CMD_MEMORY_SEARCH: + Colorize( sText, " Usage: range <\"ASCII text\" | 'apple text' | hex>" ); + ConsolePrint( sText ); + Help_Range(); + ConsoleBufferPush( " Where text is of the form:" ); + ConsoleBufferPush( " \"...\" designate ASCII text" ); + ConsoleBufferPush( " '...' designate Apple High-Bit text" ); + Help_Examples(); + sprintf( sText, "%s %s F000,1000 'Apple' // search High-Bit", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s MT1 @2" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s D000:FFFF \"FLAS\" // search ASCII ", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s MA1 @1" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s D000,4000 \"EN\" 'D' // Mixed text" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s MT1 @1" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s D000,4000 'Apple' ? ']'" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + break; + case CMD_MEMORY_SEARCH_HEX: + Colorize( sText, " Usage: range [text | byte1 [byte2 ...]]" ); + ConsolePrint( sText ); + Help_Range(); + ConsoleBufferPush( " Where is of the form:" ); + ConsoleBufferPush( " ## match specific byte" ); + ConsoleBufferPush( " #### match specific 16-bit value" ); + ConsoleBufferPush( " ? match any byte" ); + ConsoleBufferPush( " ?# match any high nibble, match low nibble to specific number" ); + ConsoleBufferPush( " #? match specific high nibble, match any low nibble" ); + Help_Examples(); + sprintf( sText, "%s %s F000,1000 AD ? C0", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s U @1" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s F000,1000 ?1 C0" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s F000,1000 5? C0" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s F000,1000 10 C?" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s U @2 - 1" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s F000:FFFF C030" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s U @1 - 1" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + break; +// case CMD_MEMORY_SEARCH_APPLE: +// wsprintf( sText, TEXT("Deprecated. Use: %s" ), g_aCommands[ CMD_MEMORY_SEARCH ].m_sName ); ConsoleBufferPush( sText ); +// break; +// case CMD_MEMORY_SEARCH_ASCII: +// wsprintf( sText, TEXT("Deprecated. Use: %s" ), g_aCommands[ CMD_MEMORY_SEARCH ].m_sName ); ConsoleBufferPush( sText ); +// break; + // Output + case CMD_OUTPUT_CALC: + Colorize( sText, " Usage:
" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Expression is one of: + - * / % ^ ~" ); + ConsoleBufferPush( " Output order is: Hex Bin Dec Char" ); + ConsoleBufferPush( " Note: symbols take piority." ); + Help_Examples(); + ConsoleBufferPush( "Note: #A (if you don't want the accumulator value)" ); + ConsoleBufferPush( "Note: #F (if you don't want the flags value)" ); + break; + case CMD_OUTPUT_ECHO: + Colorize( sText, " Usage: string" ); + ConsolePrint( sText ); +// ConsoleBufferPush( TEXT(" Examples:" ) ); + Help_Examples(); + sprintf( sText, "%s %s Checkpoint", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s PC" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); +// ConsoleBufferPush( TEXT(" Echo the string to the console" ) ); + break; + case CMD_OUTPUT_PRINT: + Colorize( sText, " Usage: [, string | expression]*" ); + ConsolePrint( sText ); + Colorize( sText, " Note: To print Register values, they must be in upper case" ); + ConsolePrint( sText ); + Help_Examples(); + sprintf( sText, "%s %s \"A:\",A,\" X:\",X", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s A,\" \",X,\" \",Y" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s PC" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + break; + case CMD_OUTPUT_PRINTF: + Colorize( sText, " Usage: [, expression, ...]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " The string may contain c-style printf formatting flags: %d %x %z %c" ); + ConsoleBufferPush( " Where: %d decimal, %x hex, %z binary, %c char, %% percent" ); + Help_Examples(); + sprintf( sText, "%s %s \"Dec: %%d Hex: %%x Bin: %%z Char: %c\",A,A,A,A", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s \"%%x %%x %%x\",A,X,Y" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + + break; + // Symbols + case CMD_SYMBOLS_LOOKUP: + Colorize( sText, " Usage: symbol [=
]" ); + ConsolePrint( sText ); + Help_Examples(); + wsprintf( sText, "%s %s HOME" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + wsprintf( sText, "%s %s LIFE = 2000", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + wsprintf( sText, "%s %s LIFE" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + break; + case CMD_SYMBOLS_ROM: + case CMD_SYMBOLS_APPLESOFT: + case CMD_SYMBOLS_ASSEMBLY: + case CMD_SYMBOLS_USER_1: + case CMD_SYMBOLS_USER_2: + case CMD_SYMBOLS_SRC_1: + case CMD_SYMBOLS_SRC_2: +// ConsoleBufferPush( TEXT(" Usage: [ ON | OFF | symbol | address ]" ) ); +// ConsoleBufferPush( TEXT(" Usage: [ LOAD [\"filename\"] | SAVE \"filename\"]" ) ); +// ConsoleBufferPush( TEXT(" ON : Turns symbols on in the disasm window" ) ); +// ConsoleBufferPush( TEXT(" OFF : Turns symbols off in the disasm window" ) ); +// ConsoleBufferPush( TEXT(" LOAD: Loads symbols from last/default filename" ) ); +// ConsoleBufferPush( TEXT(" SAVE: Saves symbol table to file" ) ); +// ConsoleBufferPush( TEXT(" CLEAR: Clears the symbol table" ) ); + Colorize( sText, " Usage: [ | symbol | address ]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Where is one of:" ); + sprintf( sText, "%s%-5s%s: Turns symbols on in the disasm window" , CHC_STRING, g_aParameters[ PARAM_ON ].m_sName, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText, "%s%-5s%s: Turns symbols off in the disasm window" , CHC_STRING, g_aParameters[ PARAM_OFF ].m_sName, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText, "%s%-5s%s: Loads symbols from last/default \"filename\"", CHC_STRING, g_aParameters[ PARAM_SAVE ].m_sName, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText, "%s%-5s%s: Saves symbol table to \"filename\"" , CHC_STRING, g_aParameters[ PARAM_LOAD ].m_sName, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText, "%s%-5s%s: Clears the symbol table" , CHC_STRING, g_aParameters[ PARAM_CLEAR ].m_sName, CHC_DEFAULT ); ConsolePrint( sText ); + sprintf( sText, "%s%-5s%s: Remove symbol" , CHC_STRING, g_aTokens[ TOKEN_EXCLAMATION ].sToken, CHC_DEFAULT ); ConsolePrint( sText ); + break; + case CMD_SYMBOLS_LIST : + Colorize( sText, " Usage: symbol" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Looks up symbol in all 3 symbol tables: main, user, source" ); + break; + // View + case CMD_VIEW_TEXT4X: + case CMD_VIEW_TEXT41: + case CMD_VIEW_TEXT42: + case CMD_VIEW_TEXT8X: + case CMD_VIEW_TEXT81: + case CMD_VIEW_TEXT82: + case CMD_VIEW_GRX : + case CMD_VIEW_GR1 : + case CMD_VIEW_GR2 : + case CMD_VIEW_DGRX : + case CMD_VIEW_DGR1 : + case CMD_VIEW_DGR2 : + case CMD_VIEW_HGRX : + case CMD_VIEW_HGR1 : + case CMD_VIEW_HGR2 : + case CMD_VIEW_DHGRX : + case CMD_VIEW_DHGR1 : + case CMD_VIEW_DHGR2 : + break; + // Watches + case CMD_WATCH_ADD: + Colorize( sText, " Usage:
" ); + ConsolePrint( sText ); + ConsoleBufferPush( " Adds the specified memory location to the watch window." ); + break; + // Window + case CMD_WINDOW_CODE : // summary is good enough + case CMD_WINDOW_CODE_2 : // summary is good enough + case CMD_WINDOW_SOURCE_2: // summary is good enough + break; + // Zero Page pointers + case CMD_ZEROPAGE_POINTER: + case CMD_ZEROPAGE_POINTER_ADD: + Colorize( sText, " Usage:
" ); + ConsolePrint( sText ); + Colorize( sText, " Usage: #
[address...]" ); + ConsolePrint( sText ); + ConsoleBufferPush(" Adds the specified memory location to the zero page pointer window." ); + ConsoleBufferPush(" Update the specified zero page pointer (#) with the address." ); + ConsoleBufferPush(" Note: Displayed as symbol name (if possible) and the 16-bit target pointer" ); + Help_Examples(); + sprintf( sText, "%s %s CH" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s 0 CV" , CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + sprintf( sText, "%s %s 0 CV CH", CHC_EXAMPLE, pCommand->m_sName ); ConsolePrint( sText ); + break; + case CMD_ZEROPAGE_POINTER_CLEAR: + Colorize( sText, " Usage: [# | *]" ); + ConsoleBufferPush( " Clears specified zero page pointer, or all." ); + sprintf( sText, " i.e. %s%s 1", CHC_EXAMPLE, pCommand->m_sName ); + ConsolePrint( sText ); + break; + case CMD_ZEROPAGE_POINTER_0: + case CMD_ZEROPAGE_POINTER_1: + case CMD_ZEROPAGE_POINTER_2: + case CMD_ZEROPAGE_POINTER_3: + case CMD_ZEROPAGE_POINTER_4: + case CMD_ZEROPAGE_POINTER_5: + case CMD_ZEROPAGE_POINTER_6: + case CMD_ZEROPAGE_POINTER_7: + Colorize( sText, " Usage: [
]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " If no address specified, will remove watching the zero page pointer." ); + break; + + // Misc + case CMD_VERSION: + Colorize( sText, " Usage: [*]" ); + ConsolePrint( sText ); + ConsoleBufferPush( " * Display extra internal stats" ); + break; + + default: + if (bAllCommands) + break; + + if ((! nFound) || (! pCommand)) + { + wsprintf( sText, " Invalid command." ); + ConsoleBufferPush( sText ); + } + else + { +//#if DEBUG_COMMAND_HELP +#if _DEBUG + wsprintf( sText, "Command help not done yet!: %s", g_aCommands[ iCommand ].m_sName ); + ConsoleBufferPush( sText ); +#endif + } + + break; + } + + } + + return ConsoleUpdate(); +} + +//=========================================================================== +Update_t CmdHelpList (int nArgs) +{ + const int nBuf = CONSOLE_WIDTH * 2; + + char sText[ nBuf ] = ""; + + int nLenLine = strlen( sText ); + int y = 0; + int nLinesScrolled = 0; + + int nMaxWidth = g_nConsoleDisplayWidth - 1; + int iCommand; + + extern vector g_vSortedCommands; + + if (! g_vSortedCommands.size()) + { + for (iCommand = 0; iCommand < NUM_COMMANDS_WITH_ALIASES; iCommand++ ) + { + g_vSortedCommands.push_back( g_aCommands[ iCommand ] ); + } + std::sort( g_vSortedCommands.begin(), g_vSortedCommands.end(), commands_functor_compare() ); + } + int nCommands = g_vSortedCommands.size(); + + int nLen = 0; +// Colorize( sText, "Commands: " ); + StringCat( sText, CHC_USAGE , nBuf ); + nLen += StringCat( sText, "Commands", nBuf ); + + StringCat( sText, CHC_DEFAULT, nBuf ); + nLen += StringCat( sText, ": " , nBuf ); + + for( iCommand = 0; iCommand < NUM_COMMANDS_WITH_ALIASES; iCommand++ ) // aliases are not printed + { + Command_t *pCommand = & g_vSortedCommands.at( iCommand ); +// Command_t *pCommand = & g_aCommands[ iCommand ]; + char *pName = pCommand->m_sName; + + if (! pCommand->pFunction) + continue; // not implemented function + + int nLenCmd = strlen( pName ); + if ((nLen + nLenCmd) < (nMaxWidth)) + { + StringCat( sText, CHC_COMMAND, nBuf ); + nLen += StringCat( sText, pName , nBuf ); + } + else + { + ConsolePrint( sText ); + nLen = 1; + strcpy( sText, " " ); + StringCat( sText, CHC_COMMAND, nBuf ); + nLen += StringCat( sText, pName, nBuf ); + } + + strcat( sText, " " ); + nLen++; + } + + //ConsoleBufferPush( sText ); + ConsolePrint( sText ); + ConsoleUpdate(); + + return UPDATE_CONSOLE_DISPLAY; +} + + +//=========================================================================== +Update_t CmdVersion (int nArgs) +{ + TCHAR sText[ CONSOLE_WIDTH ]; + + unsigned int nVersion = DEBUGGER_VERSION; + int nMajor; + int nMinor; + int nFixMajor; + int nFixMinor; + UnpackVersion( nVersion, nMajor, nMinor, nFixMajor, nFixMinor ); + + sprintf( sText, " Emulator: %s%s%s Debugger: %s%d.%d.%d.%d%s" + , CHC_SYMBOL + , VERSIONSTRING + , CHC_DEFAULT + , CHC_SYMBOL + , nMajor, nMinor, nFixMajor, nFixMinor + , CHC_DEFAULT + ); + ConsolePrint( sText ); + + if (nArgs) + { + for (int iArg = 1; iArg <= g_nArgRaw; iArg++ ) + { + // * PARAM_WILDSTAR -> ? PARAM_MEM_SEARCH_WILD + if ((! _tcscmp( g_aArgs[ iArg ].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName )) || + (! _tcscmp( g_aArgs[ iArg ].sArg, g_aParameters[ PARAM_MEM_SEARCH_WILD ].m_sName )) ) + { + wsprintf( sText, " Arg: %d bytes * %d = %d bytes", + sizeof(Arg_t), MAX_ARGS, sizeof(g_aArgs) ); + ConsoleBufferPush( sText ); + + wsprintf( sText, " Console: %d bytes * %d height = %d bytes", + sizeof( g_aConsoleDisplay[0] ), CONSOLE_HEIGHT, sizeof(g_aConsoleDisplay) ); + ConsoleBufferPush( sText ); + + wsprintf( sText, " Commands: %d (Aliased: %d) Params: %d", + NUM_COMMANDS, NUM_COMMANDS_WITH_ALIASES, NUM_PARAMS ); + ConsoleBufferPush( sText ); + + wsprintf( sText, " Cursor(%d) T: %04X C: %04X B: %04X %c D: %02X", // Top, Cur, Bot, Delta + g_nDisasmCurLine, g_nDisasmTopAddress, g_nDisasmCurAddress, g_nDisasmBotAddress, + g_bDisasmCurBad ? TEXT('*') : TEXT(' ') + , g_nDisasmBotAddress - g_nDisasmTopAddress + ); + ConsoleBufferPush( sText ); + + CmdConfigGetFont( 0 ); + + break; + } + else + return Help_Arg_1( CMD_VERSION ); + } + } + + return ConsoleUpdate(); +} + diff --git a/AppleWin/source/Debugger/Debugger_Help.h b/AppleWin/source/Debugger/Debugger_Help.h new file mode 100644 index 00000000..246dc336 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Help.h @@ -0,0 +1,33 @@ +#ifndef DEBUGGER_HELP_H +#define DEBUGGER_HELP_H + + enum Match_e + { + MATCH_EXACT, + MATCH_FUZZY + }; + + +// Prototypes _______________________________________________________________ + + Update_t HelpLastCommand(); + + void DisplayAmbigiousCommands ( int nFound ); + + int FindParam( LPTSTR pLookupName, Match_e eMatch, int & iParam_, const int iParamBegin = 0, const int iParamEnd = NUM_PARAMS - 1 ); + int FindCommand( LPTSTR pName, CmdFuncPtr_t & pFunction_, int * iCommand_ = NULL ); + +inline void UnpackVersion( const unsigned int nVersion, + int & nMajor_, int & nMinor_, int & nFixMajor_ , int & nFixMinor_ ) + { + nMajor_ = (nVersion >> 24) & 0xFF; + nMinor_ = (nVersion >> 16) & 0xFF; + nFixMajor_ = (nVersion >> 8) & 0xFF; + nFixMinor_ = (nVersion >> 0) & 0xFF; + } + + bool TestStringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize ); + bool TryStringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize ); + int StringCat( TCHAR * pDst, LPCSTR pSrc, const int nDstSize ); + +#endif diff --git a/AppleWin/source/Debugger/Debugger_Parser.cpp b/AppleWin/source/Debugger/Debugger_Parser.cpp new file mode 100644 index 00000000..5edcfc52 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Parser.cpp @@ -0,0 +1,1060 @@ +/* +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-2007, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Debugger + * + * Author: Copyright (C) 2006, Michael Pohoreski + */ + +#include "StdAfx.h" + + +// Args ___________________________________________________________________________________________ + + int g_nArgRaw; + Arg_t g_aArgRaw[ MAX_ARGS ]; // pre-processing + Arg_t g_aArgs [ MAX_ARGS ]; // post-processing (cooked) + + const TCHAR TCHAR_LF = TEXT('\x0D'); + const TCHAR TCHAR_CR = TEXT('\x0A'); + const TCHAR TCHAR_SPACE = TEXT(' '); + const TCHAR TCHAR_TAB = TEXT('\t'); +// const TCHAR TCHAR_QUOTED = TEXT('"'); + const TCHAR TCHAR_QUOTE_DOUBLE = TEXT('"'); + const TCHAR TCHAR_QUOTE_SINGLE = TEXT('\''); + const TCHAR TCHAR_ESCAPE = TEXT('\x1B'); + + + // NOTE: ArgToken_e and g_aTokens must match! + const TokenTable_t g_aTokens[ NUM_TOKENS ] = + { // Input + { TOKEN_ALPHANUMERIC, TYPE_STRING , 0 }, // Default, if doen't match anything else + { TOKEN_AMPERSAND , TYPE_OPERATOR, "&" }, // bit-and + { TOKEN_AT , TYPE_OPERATOR, "@" }, // reference results + { TOKEN_BRACE_L , TYPE_STRING , "{" }, + { TOKEN_BRACE_R , TYPE_STRING , "}" }, + { TOKEN_BRACKET_L , TYPE_STRING , "[" }, + { TOKEN_BRACKET_R , TYPE_STRING , "]" }, + { TOKEN_BSLASH , TYPE_OPERATOR, "\\" }, + { TOKEN_CARET , TYPE_OPERATOR, "^" }, // bit-eor, C/C++: xor, Math: POWER + { TOKEN_COLON , TYPE_OPERATOR, ":" }, + { TOKEN_COMMA , TYPE_OPERATOR, "," }, + { TOKEN_DOLLAR , TYPE_STRING , "$" }, + { TOKEN_EQUAL , TYPE_OPERATOR, "=" }, + { TOKEN_EXCLAMATION , TYPE_OPERATOR, "!" }, // NOT + { TOKEN_FSLASH , TYPE_OPERATOR, "/" }, // div + { TOKEN_GREATER_THAN, TYPE_OPERATOR, ">" }, // TODO/FIXME: Parser will break up '>=' (needed for uber breakpoints) + { TOKEN_HASH , TYPE_OPERATOR, "#" }, + { TOKEN_LESS_THAN , TYPE_OPERATOR, "<" }, + { TOKEN_MINUS , TYPE_OPERATOR, "-" }, // sub + { TOKEN_PAREN_L , TYPE_OPERATOR, "(" }, + { TOKEN_PAREN_R , TYPE_OPERATOR, ")" }, + { TOKEN_PERCENT , TYPE_OPERATOR, "%" }, // mod + { TOKEN_PIPE , TYPE_OPERATOR, "|" }, // bit-or + { TOKEN_PLUS , TYPE_OPERATOR, "+" }, // add +// { TOKEN_QUESTION , TYPE_OPERATOR, TEXT('?') }, // Not a token 1) wildcard needs to stay together with other chars + { TOKEN_QUOTE_SINGLE, TYPE_QUOTED_1, "\'" }, + { TOKEN_QUOTE_DOUBLE, TYPE_QUOTED_2, "\"" }, // for strings + { TOKEN_SEMI , TYPE_STRING , ";" }, + { TOKEN_SPACE , TYPE_STRING , " " }, // space is also a delimiter between tokens/args + { TOKEN_STAR , TYPE_OPERATOR, "*" }, // Not a token 1) wildcard needs to stay together with other chars +// { TOKEN_TAB , TYPE_STRING , TEXT('\t') } + { TOKEN_TILDE , TYPE_OPERATOR, "~" }, // C/C++: Not. Used for console. + + { TOKEN_COMMENT_EOL , TYPE_STRING , "//" }, + { TOKEN_GREATER_EQUAL,TYPE_OPERATOR, ">=" }, + { TOKEN_LESS_EQUAL , TYPE_OPERATOR, "<=" }, + { TOKEN_NOT_EQUAL , TYPE_OPERATOR , "!=" } + }; + +// Arg ____________________________________________________________________________________________ + + +//=========================================================================== +int _Arg_1( int nValue ) +{ + g_aArgs[1].nValue = nValue; + return 1; +} + +//=========================================================================== +int _Arg_1( LPTSTR pName ) +{ + int nLen = _tcslen( g_aArgs[1].sArg ); + if (nLen < MAX_ARG_LEN) + { + _tcscpy( g_aArgs[1].sArg, pName ); + } + else + { + _tcsncpy( g_aArgs[1].sArg, pName, MAX_ARG_LEN - 1 ); + } + return 1; +} + +/** + @description Copies Args[iSrc .. iEnd] to Args[0] + @param iSrc First argument to copy + @param iEnd Last argument to end + @return nArgs Number of new args + Usually called as: nArgs = _Arg_Shift( iArg, nArgs ); +//=========================================================================== */ +int _Arg_Shift( int iSrc, int iEnd, int iDst ) +{ + if (iDst < 0) + return ARG_SYNTAX_ERROR; + if (iDst > MAX_ARGS) + return ARG_SYNTAX_ERROR; + + int nArgs = (iEnd - iSrc); + int nLen = nArgs + 1; + + if ((iDst + nLen) > MAX_ARGS) + return ARG_SYNTAX_ERROR; + + while (nLen--) + { + g_aArgs[iDst] = g_aArgs[iSrc]; + iSrc++; + iDst++; + } + return nArgs; +} + +//=========================================================================== +int _Args_Insert( int iSrc, int iEnd, int nLen ) +{ + iSrc += nLen; + int iDst = iEnd + nLen; + + if (iDst > MAX_ARGS) + return ARG_SYNTAX_ERROR; + + if (iSrc > MAX_ARGS) + return ARG_SYNTAX_ERROR; + + while (nLen--) + { + g_aArgs[iDst] = g_aArgs[iSrc]; + iSrc--; + iDst--; + } + + return 0; +} + + +//=========================================================================== +void ArgsClear () +{ + Arg_t *pArg = &g_aArgs[0]; + + for (int iArg = 0; iArg < MAX_ARGS; iArg++ ) + { + pArg->bSymbol = false; + pArg->eDevice = NUM_DEVICES; // none + pArg->eToken = NO_TOKEN ; // none + pArg->bType = TYPE_STRING; + pArg->nValue = 0; +#if DEBUG_VAL_2 + pArg->nVal2 = 0; +#endif + pArg->sArg[0] = 0; + + pArg++; + } +} + +//=========================================================================== +bool ArgsGetValue ( Arg_t *pArg, WORD * pAddressValue_, const int nBase ) +{ + TCHAR *pSrc = & (pArg->sArg[ 0 ]); + TCHAR *pEnd = NULL; + + if (pArg && pAddressValue_) + { + *pAddressValue_ = (WORD)(_tcstoul( pSrc, &pEnd, nBase) & _6502_MEM_END); + return true; + } + return false; +} + + +//=========================================================================== +bool ArgsGetImmediateValue ( Arg_t *pArg, WORD * pAddressValue_ ) +{ + if (pArg && pAddressValue_) + { + if (pArg->eToken == TOKEN_HASH) + { + pArg++; + return ArgsGetValue( pArg, pAddressValue_ ); + } + } + + return false; +} + +// Processes the raw args, turning them into tokens and types. +//=========================================================================== +int ArgsGet ( TCHAR * pInput ) +{ + LPCTSTR pSrc = pInput; + LPCTSTR pEnd = NULL; + int nBuf = 0; + + ArgToken_e iTokenSrc = NO_TOKEN; + ArgToken_e iTokenEnd = NO_TOKEN; + ArgType_e iType = TYPE_STRING; + int nLen; + + int iArg = 0; + int nArg = 0; + Arg_t *pArg = &g_aArgRaw[0]; // &g_aArgs[0]; + + g_pConsoleFirstArg = NULL; + + // BP FAC8:FACA // Range=3 + // BP FAC8,2 // Length=2 + // ^ ^^ ^^ + // | || |pSrc + // | || pSrc + // | |pSrc + // | pEnd + // pSrc + while ((*pSrc) && (iArg < MAX_ARGS)) + { + // Technically, there shouldn't be any leading spaces, + // since pressing the spacebar is an alias for TRACE. + // However, there is spaces between arguments + pSrc = const_cast( SkipWhiteSpace( pSrc )); + + if (pSrc) + { + pEnd = FindTokenOrAlphaNumeric( pSrc, g_aTokens, NUM_TOKENS, &iTokenSrc ); + if ((iTokenSrc == NO_TOKEN) || (iTokenSrc == TOKEN_ALPHANUMERIC)) + { + pEnd = SkipUntilToken( pSrc+1, g_aTokens, NUM_TOKENS, &iTokenEnd ); + } + + if (iTokenSrc == TOKEN_COMMENT_EOL) + break; + + if (iTokenSrc == NO_TOKEN) + { + iTokenSrc = TOKEN_ALPHANUMERIC; + } + + iType = g_aTokens[ iTokenSrc ].eType; + + if (iTokenSrc == TOKEN_SEMI) + { + // TODO - command seperator, must handle non-quoted though! + } + + if (iTokenSrc == TOKEN_QUOTE_DOUBLE) + { + pSrc++; // Don't store start of quote + pEnd = SkipUntilChar( pSrc, CHAR_QUOTE_DOUBLE ); + } + else + if (iTokenSrc == TOKEN_QUOTE_SINGLE) + { + pSrc++; // Don't store start of quote + pEnd = SkipUntilChar( pSrc, CHAR_QUOTE_SINGLE ); + } + + if (pEnd) + { + nBuf = pEnd - pSrc; + } + + if (nBuf > 0) + { + nLen = MIN( nBuf, MAX_ARG_LEN-1 ); + _tcsncpy( pArg->sArg, pSrc, nLen ); + pArg->sArg[ nLen ] = 0; + pArg->nArgLen = nLen; + pArg->eToken = iTokenSrc; + pArg->bType = iType; + + if (iTokenSrc == TOKEN_QUOTE_DOUBLE) + { + pEnd++; + } + else + if (iTokenSrc == TOKEN_QUOTE_SINGLE) + { + if (nLen > 1) + { + // Technically, chars aren't allowed to be multi-char + // But we've extended the syntax to allow the user + // to input High-Bit Apple Text + } + pEnd++; + } + + pSrc = pEnd; + iArg++; + pArg++; + + if (iArg == 1) + { + g_pConsoleFirstArg = pSrc; + } + } + } + } + + if (iArg) + { + nArg = iArg - 1; // first arg is command + } + + g_nArgRaw = iArg; + + return nArg; +} + + +//=========================================================================== +bool ArgsGetRegisterValue ( Arg_t *pArg, WORD * pAddressValue_ ) +{ + bool bStatus = false; + + if (pArg && pAddressValue_) + { + // Check if we refer to reg A X Y P S + for( int iReg = 0; iReg < (NUM_BREAKPOINT_SOURCES-1); iReg++ ) + { + // Skip Opcode/Instruction/Mnemonic + if (iReg == BP_SRC_OPCODE) + continue; + + // Skip individual flag names + if ((iReg >= BP_SRC_FLAG_C) && (iReg <= BP_SRC_FLAG_N)) + continue; + + // Handle one char names + if ((pArg->nArgLen == 1) && (pArg->sArg[0] == g_aBreakpointSource[ iReg ][0])) + { + switch( iReg ) + { + case BP_SRC_REG_A : *pAddressValue_ = regs.a & 0xFF; bStatus = true; break; + case BP_SRC_REG_P : *pAddressValue_ = regs.ps & 0xFF; bStatus = true; break; + case BP_SRC_REG_X : *pAddressValue_ = regs.x & 0xFF; bStatus = true; break; + case BP_SRC_REG_Y : *pAddressValue_ = regs.y & 0xFF; bStatus = true; break; + case BP_SRC_REG_S : *pAddressValue_ = regs.sp ; bStatus = true; break; + default: + break; + } + } + else + if (iReg == BP_SRC_REG_PC) + { + if ((pArg->nArgLen == 2) && (_tcscmp( pArg->sArg, g_aBreakpointSource[ iReg ] ) == 0)) + { + *pAddressValue_ = regs.pc ; bStatus = true; break; + } + } + } + } + return bStatus; +} + + +//=========================================================================== +void ArgsRawParse ( void ) +{ + const int BASE = 16; // hex + TCHAR *pSrc = NULL; + TCHAR *pEnd = NULL; + + int iArg = 1; + Arg_t *pArg = & g_aArgRaw[ iArg ]; + int nArg = g_nArgRaw; + + WORD nAddressArg; + WORD nAddressSymbol; + WORD nAddressValue; + int nParamLen = 0; + + while (iArg <= nArg) + { + pSrc = & (pArg->sArg[ 0 ]); + + nAddressArg = (WORD)(_tcstoul( pSrc, &pEnd, BASE) & _6502_MEM_END); + nAddressValue = nAddressArg; + + bool bFound = false; + if (! (pArg->bType & TYPE_NO_SYM)) + { + bFound = FindAddressFromSymbol( pSrc, & nAddressSymbol ); + if (bFound) + { + nAddressValue = nAddressSymbol; + pArg->bSymbol = true; + } + } + + if (! (pArg->bType & TYPE_VALUE)) // already up to date? + pArg->nValue = nAddressValue; + + pArg->bType |= TYPE_ADDRESS; + + iArg++; + pArg++; + } +} + + +/** + @param nArgs Number of raw args. + @param bProcessMask Bit-flags of which arg operators to process. + + Note: The number of args can be changed via: + + address1,length Length + address1:address2 Range + address1+delta Delta + address1-delta Delta +//=========================================================================== */ +int ArgsCook ( const int nArgs ) //, const int bProcessMask ) +{ + const int BASE = 16; // hex + TCHAR *pSrc = NULL; + TCHAR *pEnd2 = NULL; + + int nArg = nArgs; + int iArg = 1; + Arg_t *pArg = NULL; + Arg_t *pPrev = NULL; + Arg_t *pNext = NULL; + + WORD nAddressArg; + WORD nAddressRHS; + WORD nAddressSym; + WORD nAddressVal; + int nParamLen = 0; + int nArgsLeft = 0; + + while (iArg <= nArg) + { + pArg = & (g_aArgs[ iArg ]); + pSrc = & (pArg->sArg[ 0 ]); + +// if (bProcessMask & (1 << TOKEN_DOLLAR)) + if (pArg->eToken == TOKEN_DOLLAR) // address + { +// TODO: Need to flag was a DOLLAR token for assembler + pNext = NULL; + + nArgsLeft = (nArg - iArg); + if (nArgsLeft > 0) + { + pNext = pArg + 1; + + _Arg_Shift( iArg + 1, nArgs, iArg ); + nArg--; + iArg--; // inc for start of next loop + + // Don't do register lookup + pArg->bType |= TYPE_NO_REG; + } + else + return ARG_SYNTAX_ERROR; + } + + if (pArg->bType & TYPE_OPERATOR) // prev op type == address? + { + pPrev = NULL; // pLHS + pNext = NULL; // pRHS + nParamLen = 0; + + if (pArg->eToken == TOKEN_HASH) // HASH # immediate + nParamLen = 1; + + nArgsLeft = (nArg - iArg); + if (nArgsLeft < nParamLen) + { + return ARG_SYNTAX_ERROR; + } + + pPrev = pArg - 1; + + // Pass wildstar '*' to commands if only arg + if ((pArg->eToken == TOKEN_STAR) && (nArg == 1)) + ; + else + if (nArgsLeft > 0) // These ops take at least 1 argument + { + pNext = pArg + 1; + pSrc = &pNext->sArg[0]; + + nAddressVal = 0; + if (ArgsGetValue( pNext, & nAddressRHS )) + nAddressVal = nAddressRHS; + + bool bFound = FindAddressFromSymbol( pSrc, & nAddressSym ); + if (bFound) + { + nAddressVal = nAddressSym; + pArg->bSymbol = true; + } + + // Comma and Colon are range operators, but they are not parsed here, + // since args no longer have a 1st and 2nd value +/* + pPrev->eToken = TOKEN_COLON; + pPrev->bType |= TYPE_ADDRESS; + pPrev->bType |= TYPE_RANGE; +*/ + +// if (bProcessMask & (1 << TOKEN_AMPERSAND)) + if (pArg->eToken == TOKEN_AMPERSAND) // AND & delta + { + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + ArgsGetRegisterValue( pNext, & nAddressRHS ); + } + pPrev->nValue &= nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 2; + } + +// if (bProcessMask & (1 << TOKEN_PIPE)) + if (pArg->eToken == TOKEN_PIPE) // OR | delta + { + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + ArgsGetRegisterValue( pNext, & nAddressRHS ); + } + pPrev->nValue |= nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 2; + } + +// if (bProcessMask & (1 << TOKEN_CARET)) + if (pArg->eToken == TOKEN_CARET) // XOR ^ delta + { + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + ArgsGetRegisterValue( pNext, & nAddressRHS ); + } + pPrev->nValue ^= nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 2; + } + +// if (bProcessMask & (1 << TOKEN_PLUS)) + if (pArg->eToken == TOKEN_PLUS) // PLUS + delta + { + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + ArgsGetRegisterValue( pNext, & nAddressRHS ); + } + pPrev->nValue += nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 2; + } + +// if (bProcessMask & (1 << TOKEN_MINUS)) + if (pArg->eToken == TOKEN_MINUS) // MINUS - delta + { + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + ArgsGetRegisterValue( pNext, & nAddressRHS ); + } + pPrev->nValue -= nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 2; + } + +// if (bProcessMask & (1 << TOKEN_PERCENT)) + if (pArg->eToken == TOKEN_PERCENT) // PERCENT % delta + { + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + ArgsGetRegisterValue( pNext, & nAddressRHS ); + } + pPrev->nValue %= nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 2; + } + +// if (bProcessMask & (1 << TOKEN_STAR)) + if (pArg->eToken == TOKEN_STAR) // STAR * delta + { + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + ArgsGetRegisterValue( pNext, & nAddressRHS ); + } + pPrev->nValue *= nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 2; + } + +// if (bProcessMask & (1 << TOKEN_FSLASH)) + if (pArg->eToken == TOKEN_FSLASH) // FORWARD SLASH / delta + { + if (pNext->eToken == TOKEN_FSLASH) // Comment + { + nArg = iArg - 1; + return nArg; + } + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + ArgsGetRegisterValue( pNext, & nAddressRHS ); + } + if (! nAddressRHS) + nAddressRHS = 1; // divide by zero bug + pPrev->nValue /= nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 2; + } + +// if (bProcessMask & (1 << TOKEN_EQUAL)) + if (pArg->eToken == TOKEN_EQUAL) // EQUAL = assign + { + pPrev->nValue = nAddressRHS; + pPrev->bType |= TYPE_VALUE; // signal already up to date + nParamLen = 0; // need token for Smart BreakPoints + } + +// if (bProcessMask & (1 << TOKEN_AT)) + if (pArg->eToken == TOKEN_AT) // AT @ pointer de-reference + { + nParamLen = 1; + _Arg_Shift( iArg + nParamLen, nArgs, iArg ); + nArg--; + + pArg->nValue = 0; // nAddressRHS; + pArg->bSymbol = false; + + int nPointers = g_vMemorySearchResults.size(); + if ((nPointers) && + (nAddressRHS < nPointers)) + { + pArg->nValue = g_vMemorySearchResults.at( nAddressRHS ); + pArg->bType = TYPE_VALUE | TYPE_ADDRESS | TYPE_NO_REG | TYPE_NO_SYM; + } + nParamLen = 0; + } + +// if (bProcessMask & (1 << TOKEN_HASH)) + if (pArg->eToken == TOKEN_HASH) // HASH # immediate + { + pArg->nValue = nAddressRHS; + pArg->bSymbol = false; + pArg->bType = TYPE_VALUE | TYPE_ADDRESS | TYPE_NO_REG | TYPE_NO_SYM; + nParamLen = 0; + } + +// if (bProcessMask & (1 << TOKEN_LESS_THAN)) + if (pArg->eToken == TOKEN_LESS_THAN) // < + { + nParamLen = 0; + } + +// if (bProcessMask & (1 << TOKEN_GREATER_THAN)) + if (pArg->eToken == TOKEN_GREATER_THAN) // > + { + nParamLen = 0; + } + +// if (bProcessMask & (1 << TOKEN_EXCLAMATION)) + if (pArg->eToken == TOKEN_EXCLAMATION) // NOT ! + { + if (! ArgsGetImmediateValue( pNext, & nAddressRHS )) + { + if (! ArgsGetRegisterValue( pNext, & nAddressRHS )) + { + nAddressRHS = nAddressVal; + } + } + pArg->nValue = ~nAddressRHS; + pArg->bType |= TYPE_VALUE; // signal already up to date + // Don't remove, since "SYM ! symbol" needs token to remove symbol + } + + if (nParamLen) + { + _Arg_Shift( iArg + nParamLen, nArgs, iArg ); + nArg -= nParamLen; + iArg = 0; // reset args, to handle multiple operators + } + } + else + return ARG_SYNTAX_ERROR; + } + else // not an operator, try (1) address, (2) symbol lookup + { + nAddressArg = (WORD)(_tcstoul( pSrc, &pEnd2, BASE) & _6502_MEM_END); + + if (! (pArg->bType & TYPE_NO_REG)) + { + ArgsGetRegisterValue( pArg, & nAddressArg ); + } + + nAddressVal = nAddressArg; + + bool bFound = false; + if (! (pArg->bType & TYPE_NO_SYM)) + { + bFound = FindAddressFromSymbol( pSrc, & nAddressSym ); + if (bFound) + { + nAddressVal = nAddressSym; + pArg->bSymbol = true; + } + } + + if (! (pArg->bType & TYPE_VALUE)) // already up to date? + pArg->nValue = nAddressVal; + + pArg->bType |= TYPE_ADDRESS; + } + + iArg++; + } + + return nArg; +} + + +// Text Util ______________________________________________________________________________________ + + + +//=========================================================================== +const char * ParserFindToken( const char *pSrc, const TokenTable_t *aTokens, const int nTokens, ArgToken_e * pToken_ ) +{ + if (! pSrc) + return NULL; + + const TCHAR *pName = NULL; + int iToken; + + // Look-ahead for <= + // Look-ahead for >= + for (iToken = _TOKEN_FLAG_MULTI; iToken < NUM_TOKENS; iToken++ ) + { + pName = & (g_aTokens[ iToken ].sToken[0]); + if ((pSrc[0] == pName[ 0 ]) && + (pSrc[1] == pName[ 1 ])) + { + *pToken_ = g_aTokens[ iToken ].eToken; + return pSrc + 2; + } + } + + const TokenTable_t *pToken = aTokens; + + for (iToken = 0; iToken < _TOKEN_FLAG_MULTI; iToken++ ) + { + pName = & (pToken->sToken[0]); + if (*pSrc == *pName) + { + if ( pToken_) + { + *pToken_ = (ArgToken_e) iToken; + } + return pSrc + 1; + } + pToken++; + } + return NULL; +} + + +//=========================================================================== +const TCHAR * FindTokenOrAlphaNumeric ( const TCHAR *pSrc, const TokenTable_t *aTokens, const int nTokens, ArgToken_e * pToken_ ) +{ + if (pToken_) + *pToken_ = NO_TOKEN; + + const TCHAR *pEnd = pSrc; + + if (pSrc && (*pSrc)) + { + if (isalnum( *pSrc )) + { + if (pToken_) + *pToken_ = TOKEN_ALPHANUMERIC; + } + else + { + pEnd = ParserFindToken( pSrc, aTokens, nTokens, pToken_ ); + if (! pEnd) + pEnd = pSrc; + } + } + return pEnd; +} + + +//=========================================================================== +void TextConvertTabsToSpaces( TCHAR *pDeTabified_, LPCTSTR pText, const int nDstSize, int nTabStop ) +{ + int nLen = _tcslen( pText ); + + int TAB_SPACING = 8; + int TAB_SPACING_1 = 16; + int TAB_SPACING_2 = 21; + + if (nTabStop) + TAB_SPACING = nTabStop; + + LPCTSTR pSrc = pText; + LPTSTR pDst = pDeTabified_; + + int iTab = 0; // number of tabs seen + int nTab = 0; // gap left to next tab + int nGap = 0; // actual gap + int nCur = 0; // current cursor position + while (pSrc && *pSrc && (nCur < nDstSize)) + { + if (*pSrc == CHAR_TAB) + { + if (nTabStop) + { + nTab = nCur % TAB_SPACING; + nGap = (TAB_SPACING - nTab); + } + else + { + if (nCur <= TAB_SPACING_1) + { + nGap = (TAB_SPACING_1 - nCur); + } + else + if (nCur <= TAB_SPACING_2) + { + nGap = (TAB_SPACING_2 - nCur); + } + else + { + nTab = nCur % TAB_SPACING; + nGap = (TAB_SPACING - nTab); + } + } + + + if ((nCur + nGap) >= nDstSize) + break; + + for( int iSpc = 0; iSpc < nGap; iSpc++ ) + { + *pDst++ = CHAR_SPACE; + } + nCur += nGap; + } + else + if ((*pSrc == CHAR_LF) || (*pSrc == CHAR_CR)) + { + *pDst++ = 0; // *pSrc; + nCur++; + } + else + { + *pDst++ = *pSrc; + nCur++; + } + pSrc++; + } + *pDst = 0; +} + + +// @return Length of new string +//=========================================================================== +int RemoveWhiteSpaceReverse ( TCHAR *pSrc ) +{ + int nLen = _tcslen( pSrc ); + char *pDst = pSrc + nLen; + while (nLen--) + { + pDst--; + if (*pDst == CHAR_SPACE) + { + *pDst = 0; + } + else + { + break; + } + } + return nLen; +} + + +//=========================================================================== +/* +inline +const TCHAR* SkipEOL ( const TCHAR *pSrc ) +{ + while (pSrc && ((*pSrc == CHAR_LF) || (*pSrc == CHAR_CR))) + { + pSrc++; + } + return pSrc; +} +*/ + +//=========================================================================== +/* +inline +const TCHAR* SkipUntilChar ( const TCHAR *pSrc, const TCHAR nDelim ) +{ + while (pSrc && (*pSrc)) + { + if (*pSrc == nDelim) + break; + pSrc++; + } + return pSrc; +} +*/ + + +//=========================================================================== +/* +inline +const TCHAR* SkipUntilEOL ( const TCHAR *pSrc ) +{ + while (pSrc && (*pSrc)) + { + if ((*pSrc == CHAR_LF) || (*pSrc == CHAR_CR)) + { + break; + } + pSrc++; + } + return pSrc; +} +*/ + + +//=========================================================================== +/* +inline +const TCHAR* SkipUntilTab ( const TCHAR *pSrc ) +{ + while (pSrc && (*pSrc)) + { + if (*pSrc == CHAR_TAB) + { + break; + } + pSrc++; + } + return pSrc; +} +*/ + + +//=========================================================================== +/* +const TCHAR* SkipUntilToken ( const TCHAR *pSrc, const TokenTable_t *aTokens, const int nTokens, ArgToken_e *pToken_ ) +{ + if ( pToken_) + *pToken_ = NO_TOKEN; + + while (pSrc && (*pSrc)) + { + // Common case is TOKEN_ALPHANUMERIC, so continue until we don't have one + if (ParserFindToken( pSrc, aTokens, pToken_ )) + return pSrc; + + pSrc++; + } + return pSrc; +} +*/ + +//=========================================================================== +/* +inline +const TCHAR* SkipUntilWhiteSpace ( const TCHAR *pSrc ) +{ + while (pSrc && (*pSrc)) + { + if ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB)) + { + break; + } + pSrc++; + } + return pSrc; +} +*/ + + +// @param pStart Start of line. +//=========================================================================== +/* +inline +const TCHAR *SkipUntilWhiteSpaceReverse ( const TCHAR *pSrc, const TCHAR *pStart ) +{ + while (pSrc && (pSrc > pStart)) + { + if ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB)) + { + break; + } + pSrc--; + } + return pSrc; +} +*/ + + +//=========================================================================== +/* +inline +const TCHAR* SkipWhiteSpace ( const TCHAR *pSrc ) +{ + while (pSrc && ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB))) + { + pSrc++; + } + return pSrc; +} +*/ + + +// @param pStart Start of line. +//=========================================================================== +/* +inline +const TCHAR *SkipWhiteSpaceReverse ( const TCHAR *pSrc, const TCHAR *pStart ) +{ + while (pSrc && ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB)) && (pSrc > pStart)) + { + pSrc--; + } + return pSrc; +} +*/ + +// EOF diff --git a/AppleWin/source/Debugger/Debugger_Parser.h b/AppleWin/source/Debugger/Debugger_Parser.h new file mode 100644 index 00000000..34b9300e --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Parser.h @@ -0,0 +1,240 @@ +#ifndef DEBUGGER_PARSER_H +#define DEBUGGER_PARSER_H + + #define CHAR_LF '\x0D' + #define CHAR_CR '\x0A' + #define CHAR_SPACE ' ' + #define CHAR_TAB '\t' + #define CHAR_QUOTE_DOUBLE '"' + #define CHAR_QUOTE_SINGLE '\'' + #define CHAR_ESCAPE '\x1B' + +// Globals __________________________________________________________________ + + extern int g_nArgRaw; + extern Arg_t g_aArgRaw[ MAX_ARGS ]; // pre-processing + extern Arg_t g_aArgs [ MAX_ARGS ]; // post-processing + + extern const TCHAR * g_pConsoleFirstArg; // = 0; // points to first arg + + extern const TokenTable_t g_aTokens[ NUM_TOKENS ]; + + extern const TCHAR TCHAR_LF ;//= 0x0D; + extern const TCHAR TCHAR_CR ;//= 0x0A; + extern const TCHAR TCHAR_SPACE ;//= TEXT(' '); + extern const TCHAR TCHAR_TAB ;//= TEXT('\t'); + extern const TCHAR TCHAR_QUOTE_DOUBLE; + extern const TCHAR TCHAR_QUOTE_SINGLE; + +// Prototypes _______________________________________________________________ + +// Arg - Command Processing + Update_t Help_Arg_1( int iCommandHelp ); + int _Arg_1 ( int nValue ); + int _Arg_1 ( LPTSTR pName ); + int _Arg_Shift ( int iSrc, int iEnd, int iDst = 0 ); + int _Args_Insert( int iSrc, int iEnd, int nLen ); + void ArgsClear (); + + bool ArgsGetValue ( Arg_t *pArg, WORD * pAddressValue_, const int nBase = 16 ); + bool ArgsGetImmediateValue ( Arg_t *pArg, WORD * pAddressValue_ ); + int ArgsGet ( TCHAR * pInput ); + bool ArgsGetRegisterValue ( Arg_t *pArg, WORD * pAddressValue_ ); + void ArgsRawParse ( void ); + int ArgsCook ( const int nArgs ); // const int bProcessMask ); + +// Token + const char * ParserFindToken( const char *pSrc, const TokenTable_t *aTokens, const int nTokens, ArgToken_e * pToken_ ); + +// Text Util +/* +inline const char* SkipEOL ( const char *pSrc ) + { + while (pSrc && ((*pSrc == CHAR_LF) || (*pSrc == CHAR_CR))) + if (pSrc) + { + pSrc++; + } + return pSrc; + } +*/ + +inline const char* EatEOL ( const char *pSrc ) + { + if (pSrc) + { + if (*pSrc == CHAR_LF) + pSrc++; + + if (*pSrc == CHAR_CR) + pSrc++; + } + return pSrc; + } + +inline const char* SkipWhiteSpace ( const char *pSrc ) + { + while (pSrc && ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB))) + { + pSrc++; + } + return pSrc; + } + +inline const char* SkipWhiteSpaceReverse ( const char *pSrc, const char *pStart ) + { + while (pSrc && ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB)) && (pSrc > pStart)) + { + pSrc--; + } + return pSrc; + } + +inline const char* SkipUntilChar ( const char *pSrc, const char nDelim ) + { + while (pSrc && (*pSrc)) + { + if (*pSrc == nDelim) + break; + pSrc++; + } + return pSrc; + } + +inline const char* SkipUntilEOL ( const char *pSrc ) + { + // EOL delims: NULL, LF, CR + while (pSrc && (*pSrc)) + { + if ((*pSrc == CHAR_LF) || (*pSrc == CHAR_CR)) + { + break; + } + pSrc++; + } + return pSrc; + } + +inline const char* SkipUntilTab ( const char *pSrc) + { + while (pSrc && (*pSrc)) + { + if (*pSrc == CHAR_TAB) + { + break; + } + pSrc++; + } + return pSrc; + } + +inline const char* SkipUntilToken ( const char *pSrc, const TokenTable_t *aTokens, const int nTokens, ArgToken_e *pToken_ ) + { + if ( pToken_) + *pToken_ = NO_TOKEN; + + while (pSrc && (*pSrc)) + { + if (ParserFindToken( pSrc, aTokens, nTokens, pToken_ )) + return pSrc; + + pSrc++; + } + return pSrc; + } + +inline const char* SkipUntilWhiteSpace ( const char *pSrc ) + { + while (pSrc && (*pSrc)) + { + if ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB)) + { + break; + } + pSrc++; + } + return pSrc; + } + +inline const char* SkipUntilWhiteSpaceReverse ( const char *pSrc, const char *pStart ) + { + while (pSrc && (pSrc > pStart)) + { + if ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB)) + { + break; + } + pSrc--; + } + return pSrc; + } + + +/* + const TCHAR* SkipEOL ( const TCHAR *pSrc ); + const TCHAR* SkipWhiteSpace ( const TCHAR *pSrc ); + const TCHAR* SkipWhiteSpaceReverse ( const TCHAR *pSrc, const TCHAR *pStart ); + const TCHAR* SkipUntilChar ( const TCHAR *pSrc, const TCHAR nDelim ); + const TCHAR* SkipUntilEOL ( const TCHAR *pSrc ); + const TCHAR* SkipUntilToken ( const TCHAR *pSrc, const TokenTable_t *aTokens, const int nTokens, ArgToken_e *pToken_ ); + const TCHAR* SkipUntilWhiteSpace ( const TCHAR *pSrc ); + const TCHAR* SkipUntilWhiteSpaceReverse ( const TCHAR *pSrc, const TCHAR *pStart ); + const TCHAR* SkipUntilTab ( const TCHAR *pSrc); +*/ + + const TCHAR * FindTokenOrAlphaNumeric ( const TCHAR *pSrc, const TokenTable_t *aTokens, const int nTokens, ArgToken_e * pToken_ ); +// TextRemoveWhiteSpaceReverse + int RemoveWhiteSpaceReverse ( char *pSrc ); +// TextExpandTabsToSpaces + void TextConvertTabsToSpaces( TCHAR *pDeTabified_, LPCTSTR pText, const int nDstSize, int nTabStop = 0 ); + + +/** Assumes text are valid hex digits! +//=========================================================================== */ +inline BYTE TextConvert2CharsToByte ( char *pText ) + { + BYTE n = ((pText[0] <= '@') ? (pText[0] - '0') : (pText[0] - 'A' + 10)) << 4; + n += ((pText[1] <= '@') ? (pText[1] - '0') : (pText[1] - 'A' + 10)) << 0; + return n; + } + +//=========================================================================== +inline bool TextIsHexChar( char nChar ) + { + if ((nChar >= '0') && (nChar <= '9')) + return true; + + if ((nChar >= 'A') && (nChar <= 'F')) + return true; + + if ((nChar >= 'a') && (nChar <= 'f')) + return true; + + return false; + } + + +//=========================================================================== +inline bool TextIsHexByte( char *pText ) + { + if (TextIsHexChar( pText[0] ) && + TextIsHexChar( pText[1] )) + return true; + + return false; + } + +//=========================================================================== +inline bool TextIsHexString ( LPCSTR pText ) + { + while (*pText) + { + if (! TextIsHexChar( *pText )) + return false; + + pText++; + } + return true; + } + +#endif diff --git a/AppleWin/source/Debugger/Debugger_Range.cpp b/AppleWin/source/Debugger/Debugger_Range.cpp new file mode 100644 index 00000000..62f84031 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Range.cpp @@ -0,0 +1,123 @@ +/* +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-2009, Tom Charlesworth, Michael Pohoreski + +AppleWin is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +AppleWin is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AppleWin; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Description: Debugger Utility Range + * + * Author: Copyright (C) 2006-2009 Michael Pohoreski + */ + +#include "StdAfx.h" + + +// Util - Range _______________________________________________________________ + + +//=========================================================================== +bool Range_CalcEndLen( const RangeType_t eRange + , const WORD & nAddress1, const WORD & nAddress2 + , WORD & nAddressEnd_, int & nAddressLen_ ) +{ + bool bValid = false; + + if (eRange == RANGE_HAS_LEN) + { + // BSAVE 2000,0 Len=0 End=n/a + // BSAVE 2000,1 Len=1 End=2000 + // 0,FFFF [,) + // End = FFFE = Len-1 + // Len = FFFF + nAddressLen_ = nAddress2; + unsigned int nTemp = nAddress1 + nAddressLen_ - 1; + if (nTemp > _6502_MEM_END) + nTemp = _6502_MEM_END; + nAddressEnd_ = nTemp; + bValid = true; + } + else + if (eRange == RANGE_HAS_END) + { + // BSAVE 2000:2000 Len=0, End=n/a + // BSAVE 2000:2001 Len=1, End=2000 + // 0:FFFF [,] + // End = FFFF + // Len = 10000 = End+1 + nAddressEnd_ = nAddress2; + nAddressLen_ = nAddress2 - nAddress1 + 1; + bValid = true; + } + + return bValid; +} + + +//=========================================================================== +RangeType_t Range_Get( WORD & nAddress1_, WORD & nAddress2_, const int iArg ) // =1 +{ + nAddress1_ = (unsigned) g_aArgs[ iArg ].nValue; + if (nAddress1_ > _6502_MEM_END) + nAddress1_ = _6502_MEM_END; + + nAddress2_ = 0; + int nTemp = 0; + + RangeType_t eRange = RANGE_MISSING_ARG_2; + + if (g_aArgs[ iArg + 1 ].eToken == TOKEN_COMMA) + { + // 0,FFFF [,) // Note the mathematical range + // End = FFFE = Len-1 + // Len = FFFF + eRange = RANGE_HAS_LEN; + nTemp = g_aArgs[ iArg + 2 ].nValue; + nAddress2_ = nTemp; + } + else + if (g_aArgs[ iArg + 1 ].eToken == TOKEN_COLON) + { + // 0:FFFF [,] // Note the mathematical range + // End = FFFF + // Len = 10000 = End+1 + eRange = RANGE_HAS_END; + nTemp = g_aArgs[ iArg + 2 ].nValue; + + // i.e. + // FFFF:D000 + // 1 2 Temp + // FFFF D000 + // FFFF + // D000 + if (nAddress1_ > nTemp) + { + nAddress2_ = nAddress1_; + nAddress1_ = nTemp; + } + else + nAddress2_ = nTemp; + } + + // .17 Bug Fix: D000,FFFF -> D000,CFFF (nothing searched!) +// if (nTemp > _6502_MEM_END) +// nTemp = _6502_MEM_END; + + return eRange; +} diff --git a/AppleWin/source/Debugger/Debugger_Range.h b/AppleWin/source/Debugger/Debugger_Range.h new file mode 100644 index 00000000..7663ef87 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Range.h @@ -0,0 +1,4 @@ + RangeType_t Range_Get( WORD & nAddress1_, WORD &nAddress2_, const int iArg = 1 ); + bool Range_CalcEndLen( const RangeType_t eRange + , const WORD & nAddress1, const WORD & nAddress2 + , WORD & nAddressEnd_, int & nAddressLen_ ); diff --git a/AppleWin/source/Debugger/Debugger_Symbols.cpp b/AppleWin/source/Debugger/Debugger_Symbols.cpp new file mode 100644 index 00000000..a6982775 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Symbols.cpp @@ -0,0 +1,862 @@ +#include "StdAfx.h" + + +// Symbols ________________________________________________________________________________________ + + char* g_sFileNameSymbols[ NUM_SYMBOL_TABLES ] = { + "APPLE2E.SYM", + "A2_BASIC.SYM", + "A2_ASM.SYM", + "A2_USER1.SYM", + "A2_USER2.SYM", + "A2_SRC1.SYM", + "A2_SRC2.SYM" + }; + char g_sFileNameSymbolsUser [ MAX_PATH ] = ""; + + char * g_aSymbolTableNames[ NUM_SYMBOL_TABLES ] = + { + "Main", + "Basic", + "Assembly", + "User1", + "User2", + "Src1", + "Src2" + }; + + bool g_bSymbolsDisplayMissingFile = true; + + SymbolTable_t g_aSymbols[ NUM_SYMBOL_TABLES ]; + int g_nSymbolsLoaded = 0; // on Last Load + bool g_aConfigSymbolsDisplayed[ NUM_SYMBOL_TABLES ] = + { + true, + true, + true + }; + + +// Utils _ ________________________________________________________________________________________ + +//=========================================================================== +LPCTSTR GetSymbol (WORD nAddress, int nBytes) +{ + LPCSTR pSymbol = FindSymbolFromAddress( nAddress ); + if (pSymbol) + return pSymbol; + + return FormatAddress( nAddress, nBytes ); +} + +//=========================================================================== +int GetSymbolTableFromCommand() +{ + return (g_iCommand - CMD_SYMBOLS_ROM); +} + +//=========================================================================== +LPCTSTR FindSymbolFromAddress (WORD nAddress, int * iTable_ ) +{ + // Bugfix/User feature: User symbols should be searched first + int iTable = NUM_SYMBOL_TABLES; + while (iTable-- > 0) + { + if (g_aSymbols[iTable].size()) + { + map::iterator iSymbols = g_aSymbols[iTable].find(nAddress); + if(g_aSymbols[iTable].find(nAddress) != g_aSymbols[iTable].end()) + { + if (iTable_) + { + *iTable_ = iTable; + } + return iSymbols->second.c_str(); + } + } + } + return NULL; +} + +//=========================================================================== +bool FindAddressFromSymbol ( LPCTSTR pSymbol, WORD * pAddress_, int * iTable_ ) +{ + // Bugfix/User feature: User symbols should be searched first + for (int iTable = NUM_SYMBOL_TABLES; iTable-- > 0; ) + { + if (! g_aSymbols[iTable].size()) + continue; + +// map::iterator iSymbol = g_aSymbols[iTable].begin(); + SymbolTable_t :: iterator iSymbol = g_aSymbols[iTable].begin(); + while (iSymbol != g_aSymbols[iTable].end()) + { + if (!_tcsicmp( iSymbol->second.c_str(), pSymbol)) + { + if (pAddress_) + { + *pAddress_ = iSymbol->first; + } + if (iTable_) + { + *iTable_ = iTable; + } + return true; + } + iSymbol++; + } + } + return false; +} + + + +// Symbols ________________________________________________________________________________________ + +//=========================================================================== +WORD GetAddressFromSymbol (LPCTSTR pSymbol) +{ + WORD nAddress; + bool bFoundSymbol = FindAddressFromSymbol( pSymbol, & nAddress ); + if (! bFoundSymbol) + { + nAddress = 0; + } + return nAddress; +} + + + +//=========================================================================== +bool String2Address( LPCTSTR pText, WORD & nAddress_ ) +{ + TCHAR sHexApple[ CONSOLE_WIDTH ]; + + if (pText[0] == '$') + { + if (!TextIsHexString( pText+1)) + return false; + + _tcscpy( sHexApple, "0x" ); + _tcsncpy( sHexApple+2, pText+1, MAX_SYMBOLS_LEN - 3 ); + pText = sHexApple; + } + + if (pText[0] == TEXT('0')) + { + if ((pText[1] == TEXT('X')) || pText[1] == TEXT('x')) + { + if (!TextIsHexString( pText+2)) + return false; + + TCHAR *pEnd; + nAddress_ = (WORD) _tcstol( pText, &pEnd, 16 ); + return true; + } + if (TextIsHexString( pText )) + { + TCHAR *pEnd; + nAddress_ = (WORD) _tcstol( pText, &pEnd, 16 ); + return true; + } + } + + return false; +} + + +//=========================================================================== +Update_t CmdSymbols (int nArgs) +{ + if (! nArgs) + return CmdSymbolsInfo( 0 ); + + Update_t iUpdate = _CmdSymbolsUpdate( nArgs, SYMBOL_TABLE_USER_1 ); + if (iUpdate != UPDATE_NOTHING) + return iUpdate; + + int bSymbolTables = (1 << NUM_SYMBOL_TABLES) - 1; + return _CmdSymbolsListTables( nArgs, bSymbolTables ); +} + +//=========================================================================== +Update_t CmdSymbolsClear (int nArgs) +{ + SymbolTable_Index_e eSymbolTable = SYMBOLS_USER_1; + _CmdSymbolsClear( eSymbolTable ); + return (UPDATE_DISASM | UPDATE_SYMBOLS); +} + +void _CmdSymbolsInfoHeader( int iTable, char * pText ) +{ + int nSymbols = g_aSymbols[ iTable ].size(); + sprintf( pText, " %s: %s%d%s" + , g_aSymbolTableNames[ iTable ] + , CHC_NUM_DEC + , nSymbols + , CHC_DEFAULT + ); +} + +//=========================================================================== +Update_t CmdSymbolsInfo (int nArgs) +{ + char sText[ CONSOLE_WIDTH * 2 ] = ""; + char sTemp[ CONSOLE_WIDTH ] = ""; + + int bDisplaySymbolTables = 0; + + if (! nArgs) + { + // default to all tables + bDisplaySymbolTables = (1 << NUM_SYMBOL_TABLES) - 1; + } + else + { // Convert Command Index to parameter + int iWhichTable = GetSymbolTableFromCommand(); + if ((iWhichTable < 0) || (iWhichTable >= NUM_SYMBOL_TABLES)) + { + sprintf( sText, "Only %s%d%s symbol tables supported!" + , CHC_NUM_DEC + , NUM_SYMBOL_TABLES + , CHC_DEFAULT ); + return ConsoleDisplayError( sText ); + } + + bDisplaySymbolTables = (1 << iWhichTable); + } + + //sprintf( sText, " Symbols Main: %s%d%s User: %s%d%s Source: %s%d%s" + + int bTable = 1; + int iTable = 0; + for( ; bTable <= bDisplaySymbolTables; iTable++, bTable <<= 1 ) { + if( bDisplaySymbolTables & bTable ) { + _CmdSymbolsInfoHeader( iTable, sTemp ); + strcat( sText, sTemp ); + } + } + ConsolePrint( sText ); + + return ConsoleUpdate(); +} + +//=========================================================================== +void _CmdPrintSymbol( LPCTSTR pSymbol, WORD nAddress, int iTable ) +{ + char sText[ CONSOLE_WIDTH ]; + sprintf( sText, " %s$%s%04X%s (%s%s%s) %s%s" + , CHC_ARG_SEP + , CHC_ADDRESS + , nAddress + , CHC_DEFAULT + , CHC_STRING + , g_aSymbolTableNames[ iTable ] + , CHC_DEFAULT + , CHC_SYMBOL + , pSymbol ); + // ConsoleBufferPush( sText ); + ConsolePrint( sText ); +} + + +// Test if bit-mask to index (equal to number of bit-shifs required to reach table) +//=========================================================================== */ +bool _FindSymbolTable( int bSymbolTables, int iTable ) +{ + // iTable is enumeration + // bSymbolTables is bit-flags of enabled tables to search + + if( bSymbolTables & (1 << iTable) ) + { + return true; + } + + return false; +} + +// Convert bit-mask to index +//=========================================================================== */ +int _GetSymbolTableFromFlag( int bSymbolTables ) +{ + int iTable = 0; + int bTable = 1; + + for( ; bTable <= bSymbolTables; iTable++, bTable <<= 1 ) + { + if( bTable & bSymbolTables ) + break; + } + + return iTable; +} + + +/** + @param bSymbolTables Bit Flags of which symbol tables to search +//=========================================================================== */ +bool _CmdSymbolList_Address2Symbol( int nAddress, int bSymbolTables ) +{ + int iTable; + LPCTSTR pSymbol = FindSymbolFromAddress( nAddress, &iTable ); + + if (pSymbol) + { + if (_FindSymbolTable( bSymbolTables, iTable )) + { + _CmdPrintSymbol( pSymbol, nAddress, iTable ); + return true; + } + } + + return false; +} + +//=========================================================================== +bool _CmdSymbolList_Symbol2Address( LPCTSTR pSymbol, int bSymbolTables ) +{ + int iTable; + WORD nAddress; + + + bool bFoundSymbol = FindAddressFromSymbol( pSymbol, &nAddress, &iTable ); + if (bFoundSymbol) + { + if (_FindSymbolTable( bSymbolTables, iTable )) + { + _CmdPrintSymbol( pSymbol, nAddress, iTable ); + } + } + return bFoundSymbol; +} + +// LIST is normally an implicit "LIST *", but due to the numbers of symbols +// only look up symbols the user specifies +//=========================================================================== +Update_t CmdSymbolsList (int nArgs ) +{ + int bSymbolTables = (1 << NUM_SYMBOL_TABLES) - 1; // default to all + return _CmdSymbolsListTables( nArgs, bSymbolTables ); +} + + +//=========================================================================== +Update_t _CmdSymbolsListTables (int nArgs, int bSymbolTables ) +{ + if (! nArgs) + { + return Help_Arg_1( CMD_SYMBOLS_LIST ); + } + + /* + Test Cases + + SYM 0 RESET FA6F $FA59 + $0000 LOC0 + $FA6F RESET + $FA6F INITAN + $FA59 OLDBRK + SYM B + + SYMBOL B = $2000 + SYM B + */ + + TCHAR sText[ CONSOLE_WIDTH ] = ""; + + for( int iArgs = 1; iArgs <= nArgs; iArgs++ ) + { + WORD nAddress = g_aArgs[iArgs].nValue; + LPCTSTR pSymbol = g_aArgs[iArgs].sArg; + + // Dump all symbols for this table + if( g_aArgRaw[iArgs].eToken == TOKEN_STAR) + { + // int iWhichTable = (g_iCommand - CMD_SYMBOLS_MAIN); + // bDisplaySymbolTables = (1 << iWhichTable); + + int iTable = 0; + int bTable = 1; + for( ; bTable <= bSymbolTables; iTable++, bTable <<= 1 ) + { + if( bTable & bSymbolTables ) + { + int nSymbols = g_aSymbols[iTable].size(); + if (nSymbols) + { + // map::iterator iSymbol = g_aSymbols[iTable].begin(); + SymbolTable_t :: iterator iSymbol = g_aSymbols[iTable].begin(); + while (iSymbol != g_aSymbols[iTable].end()) + { + const char *pSymbol = iSymbol->second.c_str(); + unsigned short nAddress = iSymbol->first; + _CmdPrintSymbol( pSymbol, nAddress, iTable ); + ++iSymbol; + } + } + _CmdSymbolsInfoHeader( iTable, sText ); + ConsolePrint( sText ); + } + } + } + else + if (nAddress) + { // Have address, do symbol lookup first + if (! _CmdSymbolList_Symbol2Address( pSymbol, bSymbolTables )) + { + // nope, ok, try as address + if (! _CmdSymbolList_Address2Symbol( nAddress, bSymbolTables)) + { + wsprintf( sText + , TEXT(" Address not found: %s$%s%04X%s" ) + , CHC_ARG_SEP + , CHC_ADDRESS, nAddress, CHC_DEFAULT ); + ConsolePrint( sText ); + } + } + } + else + { // Have symbol, do address lookup + if (! _CmdSymbolList_Symbol2Address( pSymbol, bSymbolTables )) + { // nope, ok, try as address + if (String2Address( pSymbol, nAddress )) + { + if (! _CmdSymbolList_Address2Symbol( nAddress, bSymbolTables )) + { + wsprintf( sText + , TEXT(" Symbol not found: %s%s%s") + , CHC_SYMBOL, pSymbol, CHC_DEFAULT + ); + ConsolePrint( sText ); + } + } + else + { + wsprintf( sText + , TEXT(" Symbol not found: %s%s%s") + , CHC_SYMBOL, pSymbol, CHC_DEFAULT + ); + ConsolePrint( sText ); + } + } + } + } + return ConsoleUpdate(); +} + + +void Print_Current_Path() +{ + ConsoleDisplayError( g_sProgramDir ); +} + +//=========================================================================== +int ParseSymbolTable( TCHAR *pFileName, SymbolTable_Index_e eSymbolTableWrite, int nSymbolOffset ) +{ + int nSymbolsLoaded = 0; + + if (! pFileName) + return nSymbolsLoaded; + +//#if _UNICODE +// TCHAR sFormat1[ MAX_SYMBOLS_LEN ]; +// TCHAR sFormat2[ MAX_SYMBOLS_LEN ]; +// wsprintf( sFormat1, "%%x %%%ds", MAX_SYMBOLS_LEN ); // i.e. "%x %13s" +// wsprintf( sFormat2, "%%%ds %%x", MAX_SYMBOLS_LEN ); // i.e. "%13s %x" +// ascii + char sFormat1[ MAX_SYMBOLS_LEN ]; + char sFormat2[ MAX_SYMBOLS_LEN ]; + sprintf( sFormat1, "%%x %%%ds", MAX_SYMBOLS_LEN ); // i.e. "%x %13s" + sprintf( sFormat2, "%%%ds %%x", MAX_SYMBOLS_LEN ); // i.e. "%13s %x" + + FILE *hFile = fopen(pFileName,"rt"); + + if( !hFile && g_bSymbolsDisplayMissingFile ) + { + ConsoleDisplayError( "Symbol File not found:" ); + Print_Current_Path(); + nSymbolsLoaded = -1; // HACK: ERROR: FILE NOT EXIST + } + + bool bDupSymbolHeader = false; + if( hFile ) + { + while( !feof(hFile) ) + { + // Support 2 types of symbols files: + // 1) AppleWin: + // . 0000 SYMBOL + // . FFFF SYMBOL + // 2) ACME: + // . SYMBOL =$0000; Comment + // . SYMBOL =$FFFF; Comment + // + DWORD nAddress = _6502_MEM_END + 1; // default to invalid address + char sName[ MAX_SYMBOLS_LEN+1 ] = ""; + + const int MAX_LINE = 256; + char szLine[ MAX_LINE ] = ""; + + if( !fgets(szLine, MAX_LINE-1, hFile) ) // Get next line + { + //ConsolePrint("< MAX_SYMBOLS_LEN) + { + memset(&szLine[MAX_SYMBOLS_LEN], ' ', nLen-MAX_SYMBOLS_LEN); // sscanf fails for nAddress if string too long + } + sscanf(szLine, sFormat2, sName, &nAddress); + } + + // SymbolOffset + nAddress += nSymbolOffset; + + if( (nAddress > _6502_MEM_END) || (sName[0] == 0) ) + continue; + + #if 1 // _DEBUG + // If updating symbol, print duplicate symbols + WORD nAddressPrev; + int iTable; + bool bExists = FindAddressFromSymbol( sName, &nAddressPrev, &iTable ); + if( bExists ) + { + char sText[ CONSOLE_WIDTH * 3 ]; + if( !bDupSymbolHeader ) + { + bDupSymbolHeader = true; + sprintf( sText, " %sDup Symbol Name%s (%s%s%s) %s" + , CHC_ERROR + , CHC_DEFAULT + , CHC_STRING + , g_aSymbolTableNames[ iTable ] + , CHC_DEFAULT + , pFileName + ); + ConsolePrint( sText ); + } + + sprintf( sText, " %s$%s%04X %s%-31s%s" + , CHC_ARG_SEP + , CHC_ADDRESS + , nAddress + , CHC_SYMBOL + , sName + , CHC_DEFAULT + ); + ConsolePrint( sText ); + } + #endif + g_aSymbols[ eSymbolTableWrite ] [ (WORD) nAddress ] = sName; + nSymbolsLoaded++; + } + fclose(hFile); + } + + return nSymbolsLoaded; +} + + +//=========================================================================== +Update_t CmdSymbolsLoad (int nArgs) +{ + TCHAR sFileName[MAX_PATH]; + _tcscpy(sFileName,g_sProgramDir); + + int iSymbolTable = GetSymbolTableFromCommand(); + if ((iSymbolTable < 0) || (iSymbolTable >= NUM_SYMBOL_TABLES)) + { + wsprintf( sFileName, "Only %d symbol tables supported!", NUM_SYMBOL_TABLES ); + return ConsoleDisplayError( sFileName ); + } + + int nSymbols = 0; + + if (! nArgs) + { + // Default to main table +// if (g_iCommand == CMD_SYMBOLS_MAIN) +// _tcscat(sFileName, g_sFileNameSymbolsMain ); +// else +// { +// if (! _tcslen( g_sFileNameSymbolsUser )) +// { +// return ConsoleDisplayError(TEXT("No user symbol file to reload.")); +// } +// // load user symbols +// _tcscat( sFileName, g_sFileNameSymbolsUser ); +// } + _tcscat(sFileName, g_sFileNameSymbols[ iSymbolTable ]); + nSymbols = ParseSymbolTable( sFileName, (SymbolTable_Index_e) iSymbolTable ); + } + + int iArg = 1; + if (iArg <= nArgs) + { + TCHAR *pFileName = NULL; + + if( g_aArgs[ iArg ].bType & TYPE_QUOTED_2 ) + { + pFileName = g_aArgs[ iArg ].sArg; + + _tcscpy(sFileName,g_sProgramDir); + _tcscat(sFileName, pFileName); + + // Remember File Name of last symbols loaded + _tcscpy( g_sFileNameSymbolsUser, pFileName ); + } + + // SymbolOffset + // sym load "filename" [,symbol_offset] + unsigned int nOffsetAddr = 0; + + iArg++; + if( iArg <= nArgs) + { + if (g_aArgs[ iArg ].eToken == TOKEN_COMMA) + { + iArg++; + if( iArg <= nArgs ) + { + nOffsetAddr = g_aArgs[ iArg ].nValue; + if( (nOffsetAddr < _6502_MEM_BEGIN) || (nOffsetAddr > _6502_MEM_END) ) + { + nOffsetAddr = 0; + } + } + } + } + + if( pFileName ) + { + nSymbols = ParseSymbolTable( sFileName, (SymbolTable_Index_e) iSymbolTable, nOffsetAddr ); + } + } + + if( nSymbols > 0 ) + { + g_nSymbolsLoaded = nSymbols; + } + + Update_t bUpdateDisplay = UPDATE_DISASM; + bUpdateDisplay |= (nSymbols > 0) ? UPDATE_SYMBOLS : 0; + + return bUpdateDisplay; +} + +//=========================================================================== +Update_t _CmdSymbolsClear( SymbolTable_Index_e eSymbolTable ) +{ + g_aSymbols[ eSymbolTable ].clear(); + + return UPDATE_SYMBOLS; +} + + +//=========================================================================== +void SymbolUpdate( SymbolTable_Index_e eSymbolTable, char *pSymbolName, WORD nAddress, bool bRemoveSymbol, bool bUpdateSymbol ) +{ + if (bRemoveSymbol) + pSymbolName = g_aArgs[2].sArg; + + if (_tcslen( pSymbolName ) < MAX_SYMBOLS_LEN) + { + WORD nAddressPrev; + int iTable; + bool bExists = FindAddressFromSymbol( pSymbolName, &nAddressPrev, &iTable ); + + if (bExists) + { + if (iTable == eSymbolTable) + { + if (bRemoveSymbol) + { + ConsoleBufferPush( TEXT(" Removing symbol." ) ); + } + + g_aSymbols[ eSymbolTable ].erase( nAddressPrev ); + + if (bUpdateSymbol) + { + char sText[ CONSOLE_WIDTH * 2 ]; + sprintf( sText, " Updating %s%s%s from %s$%s%04X%s to %s$%s%04X%s" + , CHC_SYMBOL, pSymbolName, CHC_DEFAULT + , CHC_ARG_SEP + , CHC_ADDRESS, nAddressPrev, CHC_DEFAULT + , CHC_ARG_SEP + , CHC_ADDRESS, nAddress, CHC_DEFAULT + ); + ConsolePrint( sText ); + } + } + } + else + { + if (bRemoveSymbol) + { + ConsoleBufferPush( TEXT(" Symbol not in table." ) ); + } + } + + if (bUpdateSymbol) + { +#if _DEBUG + LPCTSTR pSymbol = FindSymbolFromAddress( nAddress, &iTable ); + { + // Found another symbol for this address. Harmless. + // TODO: Probably should check if same name? + } +#endif + g_aSymbols[ eSymbolTable ][ nAddress ] = pSymbolName; + } + } +} + + +//=========================================================================== +Update_t _CmdSymbolsUpdate( int nArgs, int bSymbolTables ) +{ + bool bRemoveSymbol = false; + bool bUpdateSymbol = false; + + if ((nArgs == 2) && + ((g_aArgs[ 1 ].eToken == TOKEN_EXCLAMATION) || (g_aArgs[1].eToken == TOKEN_TILDE)) ) + bRemoveSymbol = true; + + if ((nArgs == 3) && (g_aArgs[ 2 ].eToken == TOKEN_EQUAL )) + bUpdateSymbol = true; + + if (bRemoveSymbol || bUpdateSymbol) + { + TCHAR *pSymbolName = g_aArgs[1].sArg; + WORD nAddress = g_aArgs[3].nValue; + + int iTable = _GetSymbolTableFromFlag( bSymbolTables ); + SymbolUpdate( (SymbolTable_Index_e) iTable, pSymbolName, nAddress, bRemoveSymbol, bUpdateSymbol ); + return ConsoleUpdate(); + } + + return UPDATE_NOTHING; +} + + +//=========================================================================== +Update_t _CmdSymbolsCommon ( int nArgs, int bSymbolTables ) +{ + if (! nArgs) + { + return Help_Arg_1( g_iCommand ); + } + + Update_t iUpdate = _CmdSymbolsUpdate( nArgs, bSymbolTables ); + if (iUpdate != UPDATE_NOTHING) + return iUpdate; + + TCHAR sText[ CONSOLE_WIDTH ]; + + int iArg = 0; + while (iArg++ <= nArgs) + { + int iParam; + int nParams = FindParam( g_aArgs[iArg].sArg, MATCH_EXACT, iParam ); // MATCH_FUZZY + if (nParams) + { + if (iParam == PARAM_CLEAR) + { + int iTable = _GetSymbolTableFromFlag( bSymbolTables ); + if (iTable != NUM_SYMBOL_TABLES) + { + Update_t iUpdate = _CmdSymbolsClear( (SymbolTable_Index_e) iTable ); + wsprintf( sText, TEXT(" Cleared symbol table: %s"), + g_aSymbolTableNames[ iTable ] + ); + ConsoleBufferPush( sText ); + iUpdate |= ConsoleUpdate(); + return iUpdate; + } + else + { + ConsoleBufferPush( TEXT(" Error: Unknown Symbol Table Type") ); + return ConsoleUpdate(); + } +// if (bSymbolTable & SYMBOL_TABLE_MAIN) +// return _CmdSymbolsClear( SYMBOLS_MAIN ); +// else +// if (bSymbolsTable & SYMBOL_TABLE_USER) +// return _CmdSymbolsClear( SYMBOLS_USER ); +// else + // Shouldn't have multiple symbol tables selected +// nArgs = _Arg_1( eSymbolsTable ); + } + else + if (iParam == PARAM_LOAD) + { + nArgs = _Arg_Shift( iArg, nArgs); + Update_t bUpdate = CmdSymbolsLoad( nArgs ); + + int iTable = _GetSymbolTableFromFlag( bSymbolTables ); + if (iTable != NUM_SYMBOL_TABLES) + { + if( bUpdate & UPDATE_SYMBOLS ) + { + wsprintf( sText, " Symbol Table: %s, loaded symbols: %d", + g_aSymbolTableNames[ iTable ], g_nSymbolsLoaded ); + ConsoleBufferPush( sText ); + } + } + else + { + ConsoleBufferPush( TEXT(" Error: Unknown Symbol Table Type") ); + } + return ConsoleUpdate(); + } + else + if (iParam == PARAM_SAVE) + { + nArgs = _Arg_Shift( iArg, nArgs); + return CmdSymbolsSave( nArgs ); + } + } + else + { + return _CmdSymbolsListTables( nArgs, bSymbolTables ); // bSymbolTables + } + + } + + return ConsoleUpdate(); +} + +//=========================================================================== +Update_t CmdSymbolsCommand (int nArgs) +{ + if (! nArgs) + { + return CmdSymbolsInfo( 1 ); + } + + int bSymbolTable = SYMBOL_TABLE_MAIN << GetSymbolTableFromCommand(); + return _CmdSymbolsCommon( nArgs, SYMBOL_TABLE_MAIN ); +} + +//=========================================================================== +Update_t CmdSymbolsSave (int nArgs) +{ + return UPDATE_CONSOLE_DISPLAY; +} diff --git a/AppleWin/source/Debugger/Debugger_Symbols.h b/AppleWin/source/Debugger/Debugger_Symbols.h new file mode 100644 index 00000000..f1690872 --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Symbols.h @@ -0,0 +1,17 @@ + +// Variables + extern SymbolTable_t g_aSymbols[ NUM_SYMBOL_TABLES ]; + +// 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 ); + + bool _CmdSymbolList_Address2Symbol ( int nAddress , int bSymbolTables ); + bool _CmdSymbolList_Symbol2Address ( LPCTSTR pSymbol, int bSymbolTables ); + + // SymbolOffset + int ParseSymbolTable ( TCHAR *pFileName, SymbolTable_Index_e eWhichTableToLoad, int nSymbolOffset = 0 ); + diff --git a/AppleWin/source/Debugger/Debugger_Types.h b/AppleWin/source/Debugger/Debugger_Types.h new file mode 100644 index 00000000..de6eb73b --- /dev/null +++ b/AppleWin/source/Debugger/Debugger_Types.h @@ -0,0 +1,1579 @@ +#pragma once + + +// Addressing _____________________________________________________________________________________ + + enum + { +// MAX_ADDRESSING_MODE_LEN = 12 + + MAX_OPMODE_FORMAT = 12, + MAX_OPMODE_NAME = 32 + + , NO_6502_TARGET = -1 + , _6502_NUM_FLAGS = 8 + }; + + enum RangeType_t + { + RANGE_MISSING_ARG_2 = 0, // error + RANGE_HAS_LEN , // valid case 1 + RANGE_HAS_END , // valid case 2 + }; + + struct AddressingMode_t + { + char m_sFormat[ MAX_OPMODE_FORMAT ]; + int m_nBytes; + char m_sName [ MAX_OPMODE_NAME ]; + }; + + /* + +---------------------+--------------------------+ + | Opmode e | assembler format | + +=====================+==========================+ + | Immediate | #aa | + | Absolute | aaaa | + | Zero Page | aa | Note: + | Implied | | + | Indirect Absolute | (aaaa) | aa = 2 hex digits + | Absolute Indexed,X | aaaa,X | as $FF + | Absolute Indexed,Y | aaaa,Y | + | Zero Page Indexed,X | aa,X | aaaa = 4 hex + | Zero Page Indexed,Y | aa,Y | digits as + | Indexed Indirect | (aa,X) | $FFFF + | Indirect Indexed | (aa),Y | + | Relative | aaaa | Can also be + | Accumulator | A | assembler labels + +---------------------+--------------------------+ + (Table 2-3. _6502 Software Design_, Scanlon, 1980) + + Opcode: opc aaa od + opc...od = Mnemonic / Opcode + ...aaa.. = Addressing g_nAppMode + od = 00 + 000 #Immediate + 001 Zero page + 011 Absolute + 101 Zero page,X + 111 Absolute,X + od = 01 + 000 (Zero page,X) + 001 Zero page + 010 #Immediate + 011 Absolute + 100 (Zero page),Y + 101 Zero page,X + 110 Absolute,Y + 111 Absolute,X + od = 10 + 000 #Immediate + 001 Zero page + 010 Accumulator + 011 Absolute + 101 Zero page,X + 111 Absolute,X + */ + /* + Legend: + A = Absolute (fortunately Accumulator is implicit, leaving us to use 'A') + I = Indexed ( would of been X, but need reg X) + M = iMmediate + N = iNdirect + R = Relative + X = Offset X Register + Y = Offset Y Register + Z = Zeropage + */ + enum AddressingMode_e // ADDRESSING_MODES_e + { + AM_IMPLIED // Note: SetDebugBreakOnInvalid() assumes this order of first 4 entries + , AM_1 // Invalid 1 Byte + , AM_2 // Invalid 2 Bytes + , AM_3 // Invalid 3 Bytes + , AM_M // 4 #Immediate + , AM_A // 5 $Absolute + , AM_Z // 6 Zeropage + , AM_AX // 7 Absolute, X + , AM_AY // 8 Absolute, Y + , AM_ZX // 9 Zeropage, X + , AM_ZY // 10 Zeropage, Y + , AM_R // 11 Relative + , AM_IZX // 12 Indexed (Zeropage Indirect, X) + , AM_IAX // 13 Indexed (Absolute Indirect, X) + , AM_NZY // 14 Indirect (Zeropage) Indexed, Y + , AM_NZ // 15 Indirect (Zeropage) + , AM_NA // 16 Indirect (Absolute) i.e. JMP + + , NUM_ADDRESSING_MODES + , NUM_OPMODES = NUM_ADDRESSING_MODES + , AM_I = NUM_ADDRESSING_MODES, // for assemler + }; + + +// Assembler ______________________________________________________________________________________ + + enum Prompt_e + { + PROMPT_COMMAND, + PROMPT_ASSEMBLER, + NUM_PROMPTS + }; + + enum + { + // raised from 13 to 31 for Contiki + MAX_SYMBOLS_LEN = 31 + }; + +// Bookmarks ______________________________________________________________________________________ + + enum + { + MAX_BOOKMARKS = 10 + }; + +// Breakpoints ____________________________________________________________________________________ + + enum + { + MAX_BREAKPOINTS = 16 + }; + + /* + Breakpoints are now in a tri-state. + This allows one to set a bunch of breakpoints, and re-enable the ones you want + without having to remember which addresses you previously added. :-) + + The difference between Set and Enabled breakpoints: + + Set Enabled Break? + x x yes, listed as full brightness + x - no, listed as dimmed + - ? no, not listed + */ + // NOTE: Order must match _PARAM_REGS_* + // NOTE: Order must match Breakpoint_Source_t + // NOTE: Order must match g_aBreakpointSource + enum BreakpointSource_t + { + BP_SRC_REG_A , + BP_SRC_REG_X , + BP_SRC_REG_Y , + + BP_SRC_REG_PC, // Program Counter + BP_SRC_REG_S , // Stack Counter + + BP_SRC_REG_P , // Processor Status + BP_SRC_FLAG_C, // Carry + BP_SRC_FLAG_Z, // Zero + BP_SRC_FLAG_I, // Interrupt + BP_SRC_FLAG_D, // Decimal + BP_SRC_FLAG_B, // Break + BP_SRC_FLAG_R, // Reserved + BP_SRC_FLAG_V, // Overflow + BP_SRC_FLAG_N, // Sign + + BP_SRC_OPCODE, + BP_SRC_MEM_1 , + + NUM_BREAKPOINT_SOURCES + }; + + // Note: Order must match Breakpoint_Operator_t + // Note: Order must much _PARAM_BREAKPOINT_* + // Note: Order must match g_aBreakpointSymbols + enum BreakpointOperator_t + { + BP_OP_LESS_EQUAL , // <= REG + BP_OP_LESS_THAN , // < REG + BP_OP_EQUAL , // = REG + BP_OP_NOT_EQUAL , // != REG +// BP_OP_NOT_EQUAL_1 , // ! REG + BP_OP_GREATER_THAN , // > REG + BP_OP_GREATER_EQUAL, // >= REG + BP_OP_READ , // @ MEM @ ? * + BP_OP_WRITE , // * MEM @ ? * + BP_OP_READ_WRITE , // ? MEM @ ? * + NUM_BREAKPOINT_OPERATORS + }; + + struct Breakpoint_t + { + WORD nAddress; // for registers, functions as nValue + WORD nLength ; + BreakpointSource_t eSource; + BreakpointOperator_t eOperator; + bool bSet ; // used to be called enabled pre 2.0 + bool bEnabled; + bool bTemp; // If true then remove BP when hit or stepping cancelled (eg. G xxxx) + }; + + typedef Breakpoint_t Bookmark_t; + typedef Breakpoint_t Watches_t; + typedef Breakpoint_t ZeroPagePointers_t; + + +// Colors ___________________________________________________________________ + + enum Color_Schemes_e + { + SCHEME_COLOR, // NOTE: MUST match order in CMD_WINDOW_COLOR + SCHEME_MONO , // NOTE: MUST match order in CMD_WINDOW_MONOCHROME + SCHEME_BW , // NOTE: MUST match order in CMD_WINDOW_BW +// SCHEME_CUSTOM + NUM_COLOR_SCHEMES + }; + + // Named, since they are easier to remember. + // Ok, maybe RGB + CYMK is a little "too" cute. But what the hell, it works out nicely. + enum DebugPalette_e + { + // mipmap level: 8 7 6 5 4 3 2 1 0 + // color depth: 256 224 192 160 128 96 64 32 0 + // +32 +32 +32 +32 +32 +32 +32 +32 + // NOTE: Levels of black are redundant. + // // BGR + K0, // --- K + R8, R7, R6, R5, R4, R3, R2, R1, // --1 R Red + G8, G7, G6, G5, G4, G3, G2, G1, // -1- G Green + Y8, Y7, Y6, Y5, Y4, Y3, Y2, Y1, // -11 Y Yellow + B8, B7, B6, B5, B4, B3, B2, B1, // 1-- B Blue + M8, M7, M6, M5, M4, M3, M2, M1, // 1-1 M Magenta + C8, C7, C6, C5, C4, C3, C2, C1, // 11- C Cyan + W8, W7, W6, W5, W4, W3, W2, W1, // 111 W White / Gray / Black + + COLOR_CUSTOM_01, COLOR_CUSTOM_02, COLOR_CUSTOM_03, COLOR_CUSTOM_04, + COLOR_CUSTOM_05, COLOR_CUSTOM_06, COLOR_CUSTOM_07, COLOR_CUSTOM_08, + COLOR_CUSTOM_09, COLOR_CUSTOM_11, CUSTOM_COLOR_11, COLOR_CUSTOM_12, + COLOR_CUSTOM_13, COLOR_CUSTOM_14, COLOR_CUSTOM_15, COLOR_CUSTOM_16, + + NUM_PALETTE, + + // Gray Aliases + G000 = K0, + G032 = W1, + G064 = W2, + G096 = W3, + G128 = W4, + G160 = W5, + G192 = W6, + G224 = W7, + G256 = W8 + }; + + // Yeah, this was a PITA to organize. + enum DebugColors_e + { + BG_CONSOLE_OUTPUT // Black Window + , FG_CONSOLE_OUTPUT // White + , BG_CONSOLE_INPUT // Black Window + , FG_CONSOLE_INPUT // Light Blue + + , BG_DISASM_1 // Blue* Odd address + , BG_DISASM_2 // Blue* Even address + + , BG_DISASM_BP_S_C // Red Breakpoint Set (cursor) + , FG_DISASM_BP_S_C // White Breakpoint Set&Ena (cursor) + + // Note: redundant BG_DISASM_BP_0_C = BG_DISASM_BP_S_C + , BG_DISASM_BP_0_C // DimRed Breakpoint Disabled (cursor) + , FG_DISASM_BP_0_C // Gray192 Breakpoint Disabled (cursor) + + , FG_DISASM_BP_S_X // Red Set (not cursor) + , FG_DISASM_BP_0_X // White Disabled (not cursor) + + , BG_DISASM_C // White (Cursor) + , FG_DISASM_C // Blue (Cursor) + + , BG_DISASM_PC_C // Yellow (not cursor) + , FG_DISASM_PC_C // White (not cursor) + + , BG_DISASM_PC_X // Dim Yellow (not cursor) + , FG_DISASM_PC_X // White (not cursor) + + , BG_DISASM_BOOKMARK // Lite Blue (always) + , FG_DISASM_BOOKMARK // White addr (always) + + , FG_DISASM_ADDRESS // White addr + , FG_DISASM_OPERATOR // Gray192 : $ (also around instruction addressing g_nAppMode) + , FG_DISASM_OPCODE // Yellow xx xx xx + , FG_DISASM_MNEMONIC // White LDA + , FG_DISASM_TARGET // Orange FAC8 + , FG_DISASM_SYMBOL // Purple HOME + , FG_DISASM_CHAR // Cyan 'c' + , FG_DISASM_BRANCH // Green ^ = v + + , BG_INFO // Cyan Regs/Stack/BP/Watch/ZP + , FG_INFO_TITLE // White Regs/Stack/BP/Watch/ZP + , FG_INFO_BULLET // 1 + , FG_INFO_OPERATOR // Gray192 : - + , FG_INFO_ADDRESS // Orange FA62 FA63 (Yellow -> Orange) + , FG_INFO_OPCODE // Yellow xx + , FG_INFO_REG // Orange (Breakpoints) + , BG_INFO_INVERSE // White + , FG_INFO_INVERSE // Cyan + , BG_INFO_CHAR // mid Cyan + , FG_INFO_CHAR_HI // White + , FG_INFO_CHAR_LO // Yellow + + , BG_INFO_IO_BYTE // Orange (high bit) + , FG_INFO_IO_BYTE // Orange (non-high bit) + + , BG_DATA_1 // Cyan* Window + , BG_DATA_2 // Cyan* + , FG_DATA_BYTE // default same as FG_DISASM_OPCODE + , FG_DATA_TEXT // default same as FG_DISASM_NMEMONIC + + , BG_SYMBOLS_1 // window + , BG_SYMBOLS_2 + , FG_SYMBOLS_ADDRESS // default same as FG_DISASM_ADDRESS + , FG_SYMBOLS_NAME // default same as FG_DISASM_SYMBOL + + , BG_SOURCE_TITLE + , FG_SOURCE_TITLE + , BG_SOURCE_1 // odd + , BG_SOURCE_2 // even + , FG_SOURCE + + , NUM_DEBUG_COLORS + }; + +// Config _________________________________________________________________________________________ + + enum ConfigSave_t + { + CONFIG_SAVE_FILE_CREATE, + CONFIG_SAVE_FILE_APPEND + }; + +// Commands _______________________________________________________________________________________ + + enum Update_e + { + UPDATE_NOTHING, + UPDATE_BACKGROUND = (1 << 0), + UPDATE_BREAKPOINTS = (1 << 1), + UPDATE_CONSOLE_DISPLAY = (1 << 2), + UPDATE_CONSOLE_INPUT = (1 << 3), + UPDATE_DISASM = (1 << 4), + UPDATE_FLAGS = (1 << 5), + UPDATE_MEM_DUMP = (1 << 6), + UPDATE_REGS = (1 << 7), + UPDATE_STACK = (1 << 8), + UPDATE_SYMBOLS = (1 << 9), + UPDATE_TARGETS = (1 << 10), + UPDATE_WATCH = (1 << 11), + UPDATE_ZERO_PAGE = (1 << 12), + + UPDATE_ALL = -1 + }; + + typedef int Update_t; + + enum + { + MAX_COMMAND_LEN = 12, + + MAX_ARGS = 32, // was 40 + ARG_SYNTAX_ERROR= -1, + MAX_ARG_LEN = 56, // was 12, extended to allow font names + }; + + // NOTE: All Commands return flags of what needs to be redrawn + typedef Update_t (*CmdFuncPtr_t)(int); + + struct Command_t + { + char m_sName[ MAX_COMMAND_LEN ]; + CmdFuncPtr_t pFunction; + int iCommand; // offset (enum) for direct command name lookup + char *pHelpSummary; // 1 line help summary +// Hash_t m_nHash; // TODO + }; + + // Commands sorted by Category + // NOTE: Commands_e and g_aCommands[] order _MUST_ match !!! Aliases are listed at the end + enum Commands_e + { +// Assembler + CMD_ASSEMBLE +// CPU + , CMD_CURSOR_JUMP_PC // Shift + , CMD_CURSOR_SET_PC // Ctrl + , CMD_BREAK_INVALID + , CMD_BREAK_OPCODE + , CMD_GO + , CMD_IN + , CMD_INPUT_KEY + , CMD_JSR + , CMD_NOP + , CMD_OUT +// CPU - Meta Info + , CMD_PROFILE + , CMD_REGISTER_SET +// CPU - Stack +// , CMD_STACK_LIST + , CMD_STACK_POP + , CMD_STACK_POP_PSEUDO + , CMD_STACK_PUSH +// , CMD_STACK_RETURN + , CMD_STEP_OVER + , CMD_STEP_OUT +// CPU - Meta Info + , CMD_TRACE + , CMD_TRACE_FILE + , CMD_TRACE_LINE + , CMD_UNASSEMBLE +// Bookmarks + , CMD_BOOKMARK + , CMD_BOOKMARK_ADD + , CMD_BOOKMARK_CLEAR + , CMD_BOOKMARK_LIST +// , CMD_BOOKMARK_LOAD + , CMD_BOOKMARK_GOTO + , CMD_BOOKMARK_SAVE +// Breakpoints + , CMD_BREAKPOINT + , CMD_BREAKPOINT_ADD_SMART // smart breakpoint + , CMD_BREAKPOINT_ADD_REG // break on: PC == Address (fetch/execute) + , CMD_BREAKPOINT_ADD_PC // alias BPX = BA +// , CMD_BREAKPOINT_SET = CMD_BREAKPOINT_ADD_ADDR // alias +// , CMD_BREAKPOINT_EXEC = CMD_BREAKPOINT_ADD_ADDR // alias + , CMD_BREAKPOINT_ADD_IO // break on: [$C000-$C7FF] Load/Store + , CMD_BREAKPOINT_ADD_MEM // break on: [$0000-$FFFF], excluding IO + + , CMD_BREAKPOINT_CLEAR +// , CMD_BREAKPOINT_REMOVE = CMD_BREAKPOINT_CLEAR // alias + , CMD_BREAKPOINT_DISABLE + , CMD_BREAKPOINT_EDIT + , CMD_BREAKPOINT_ENABLE + , CMD_BREAKPOINT_LIST +// , CMD_BREAKPOINT_LOAD + , CMD_BREAKPOINT_SAVE +// Benchmark / Timing +// , CMD_BENCHMARK_START +// , CMD_BENCHMARK_STOP +// , CMD_PROFILE_START +// , CMD_PROFILE_STOP +// Config (debugger settings) + , CMD_BENCHMARK + , CMD_CONFIG_BW // BW # rr gg bb + , CMD_CONFIG_COLOR // COLOR # rr gg bb + + , CMD_CONFIG_DISASM +// , CMD_CONFIG_DISASM_BRANCH +// , CMD_CONFIG_DISASM_COLON +// , CMD_CONFIG_DISASM_OPCODE +// , CMD_CONFIG_DISASM_SPACES + + , CMD_CONFIG_FONT +// , CMD_CONFIG_FONT2 // PARAM_FONT_DISASM PARAM_FONT_INFO PARAM_FONT_SOURCE + , CMD_CONFIG_HCOLOR // TODO Video :: SETFRAMECOLOR(#,R,G,B) + , CMD_CONFIG_LOAD + , CMD_CONFIG_MONOCHROME // MONO # rr gg bb + , CMD_CONFIG_SAVE +// Cursor + , CMD_CURSOR_JUMP_RET_ADDR + , CMD_CURSOR_LINE_UP // Smart Line Up + , CMD_CURSOR_LINE_UP_1 // Shift + , CMD_CURSOR_LINE_DOWN // Smart Line Down + , CMD_CURSOR_LINE_DOWN_1 // Shift +// , CMD_CURSOR_PAGE_UP +// , CMD_CURSOR_PAGE_DOWN + , CMD_CURSOR_PAGE_UP + , CMD_CURSOR_PAGE_UP_256 // up to nearest page boundary + , CMD_CURSOR_PAGE_UP_4K // Up to nearest 4K boundary + + , CMD_CURSOR_PAGE_DOWN + , CMD_CURSOR_PAGE_DOWN_256 // Down to nearest page boundary + , CMD_CURSOR_PAGE_DOWN_4K // Down to nearest 4K boundary +// Disassembler Data + , CMD_DISASM_DATA + , CMD_DISASM_CODE + , CMD_DISASM_LIST + , CMD_DEFINE_DATA_BYTE1 // DB $00,$04,$08,$0C,$10,$14,$18,$1C + , CMD_DEFINE_DATA_BYTE2 + , CMD_DEFINE_DATA_BYTE4 + , CMD_DEFINE_DATA_BYTE8 + + , CMD_DEFINE_DATA_WORD1 // DW $300 + , CMD_DEFINE_DATA_WORD2 + , CMD_DEFINE_DATA_WORD4 + , CMD_DEFINE_DATA_STR +// , CMD_DEFINE_DATA_FACP +// , CMD_DEFINE_DATA_FACU +// , CMD_DATA_DEFINE_ADDR_BYTE_L // DB< address symbol +// , CMD_DATA_DEFINE_ADDR_BYTE_H // DB> address symbol + , CMD_DEFINE_ADDR_WORD // .DA address symbol +// Disk + , CMD_DISK +// Flags - CPU + , CMD_FLAG_CLEAR // Flag order must match g_aFlagNames CZIDBRVN + , CMD_FLAG_CLR_C // 8 + , CMD_FLAG_CLR_Z // 7 + , CMD_FLAG_CLR_I // 6 + , CMD_FLAG_CLR_D // 5 + , CMD_FLAG_CLR_B // 4 + , CMD_FLAG_CLR_R // 3 + , CMD_FLAG_CLR_V // 2 + , CMD_FLAG_CLR_N // 1 + + , CMD_FLAG_SET // Flag order must match g_aFlagNames CZIDBRVN + , CMD_FLAG_SET_C // 8 + , CMD_FLAG_SET_Z // 7 + , CMD_FLAG_SET_I // 6 + , CMD_FLAG_SET_D // 5 + , CMD_FLAG_SET_B // 4 + , CMD_FLAG_SET_R // 3 + , CMD_FLAG_SET_V // 2 + , CMD_FLAG_SET_N // 1 +// Help + , CMD_HELP_LIST + , CMD_HELP_SPECIFIC + , CMD_VERSION + , CMD_MOTD // Message of the Day +// Memory + , CMD_MEMORY_COMPARE + + , _CMD_MEM_MINI_DUMP_HEX_1_1 // Memory Dump + , CMD_MEM_MINI_DUMP_HEX_1 // Mini Memory Dump 1 + , CMD_MEM_MINI_DUMP_HEX_2 // Mini Memory Dump 2 + , _CMD_MEM_MINI_DUMP_HEX_1_3 // alias M1 + , _CMD_MEM_MINI_DUMP_HEX_2_1 // alias M2 + + , CMD_MEM_MINI_DUMP_ASCII_1 // ASCII + , CMD_MEM_MINI_DUMP_ASCII_2 + , CMD_MEM_MINI_DUMP_APPLE_1 // Low-Bit inverse, High-Bit normal + , CMD_MEM_MINI_DUMP_APPLE_2 +// , CMD_MEM_MINI_DUMP_TXT_LO_1 // ASCII (Controls Chars) +// , CMD_MEM_MINI_DUMP_TXT_LO_2 +// , CMD_MEM_MINI_DUMP_TXT_HI_1 // ASCII (High Bit) +// , CMD_MEM_MINI_DUMP_TXT_HI_2 + +// , CMD_MEMORY_DUMP = CMD_MEM_MINI_DUMP_HEX_1 + , CMD_MEMORY_EDIT + , CMD_MEMORY_ENTER_BYTE + , CMD_MEMORY_ENTER_WORD + , CMD_MEMORY_LOAD + , CMD_MEMORY_MOVE + , CMD_MEMORY_SAVE + , CMD_MEMORY_SEARCH + , CMD_MEMORY_FIND_RESULTS +// , CMD_MEMORY_SEARCH_ASCII // Ascii Text +// , CMD_MEMORY_SEARCH_APPLE // Flashing Chars, Hi-Bit Set + , CMD_MEMORY_SEARCH_HEX + , CMD_MEMORY_FILL +// Output + , CMD_OUTPUT_CALC + , CMD_OUTPUT_ECHO + , CMD_OUTPUT_PRINT + , CMD_OUTPUT_PRINTF + , CMD_OUTPUT_RUN +// Source Level Debugging + , CMD_SOURCE + , CMD_SYNC +// Symbols + , CMD_SYMBOLS_LOOKUP +// , CMD_SYMBOLS + , CMD_SYMBOLS_ROM + , CMD_SYMBOLS_APPLESOFT + , CMD_SYMBOLS_ASSEMBLY + , CMD_SYMBOLS_USER_1 + , CMD_SYMBOLS_USER_2 + , CMD_SYMBOLS_SRC_1 + , CMD_SYMBOLS_SRC_2 +// , CMD_SYMBOLS_FIND +// , CMD_SYMBOLS_CLEAR + , CMD_SYMBOLS_INFO + , CMD_SYMBOLS_LIST +// , CMD_SYMBOLS_LOAD_1 +// , CMD_SYMBOLS_LOAD_2 +// , CMD_SYMBOLS_SAVE +// View + , CMD_VIEW_TEXT4X + , CMD_VIEW_TEXT41 + , CMD_VIEW_TEXT42 + , CMD_VIEW_TEXT8X + , CMD_VIEW_TEXT81 + , CMD_VIEW_TEXT82 + , CMD_VIEW_GRX + , CMD_VIEW_GR1 + , CMD_VIEW_GR2 + , CMD_VIEW_DGRX + , CMD_VIEW_DGR1 + , CMD_VIEW_DGR2 + , CMD_VIEW_HGRX + , CMD_VIEW_HGR1 + , CMD_VIEW_HGR2 + , CMD_VIEW_DHGRX + , CMD_VIEW_DHGR1 + , CMD_VIEW_DHGR2 +// Watch + , CMD_WATCH + , CMD_WATCH_ADD + , CMD_WATCH_CLEAR + , CMD_WATCH_DISABLE + , CMD_WATCH_ENABLE + , CMD_WATCH_LIST +// , CMD_WATCH_LOAD + , CMD_WATCH_SAVE +// Window +// , CMD_WINDOW_COLOR_CUSTOM + , CMD_WINDOW + + , CMD_WINDOW_CODE + , CMD_WINDOW_CODE_1 + , CMD_WINDOW_CODE_2 + + , CMD_WINDOW_CONSOLE + + , CMD_WINDOW_DATA + , CMD_WINDOW_DATA_1 + , CMD_WINDOW_DATA_2 + + // SOURCE is reserved for source level debugging + , CMD_WINDOW_SOURCE_1 + , CMD_WINDOW_SOURCE_2 + +// , CMD_WINDOW_STACK_1 +// , CMD_WINDOW_STACK_2 + + // SYMBOLS is reserved for symbols lookup/commands +// , CMD_WINDOW_SYMBOLS_1 +// , CMD_WINDOW_SYMBOLS_2 + +// , CMD_WINDOW_ZEROPAGE_1 +// , CMD_WINDOW_ZEROPAGE_2 + + , CMD_WINDOW_OUTPUT +// , CMD_WINDOW_SOURCE +// ZeroPage + , CMD_ZEROPAGE_POINTER + , CMD_ZEROPAGE_POINTER_0 + , CMD_ZEROPAGE_POINTER_1 + , CMD_ZEROPAGE_POINTER_2 + , CMD_ZEROPAGE_POINTER_3 + , CMD_ZEROPAGE_POINTER_4 + , CMD_ZEROPAGE_POINTER_5 + , CMD_ZEROPAGE_POINTER_6 + , CMD_ZEROPAGE_POINTER_7 + , CMD_ZEROPAGE_POINTER_ADD + , CMD_ZEROPAGE_POINTER_CLEAR + , CMD_ZEROPAGE_POINTER_DISABLE + , CMD_ZEROPAGE_POINTER_ENABLE + , CMD_ZEROPAGE_POINTER_LIST +// , CMD_ZEROPAGE_POINTER_LOAD + , CMD_ZEROPAGE_POINTER_SAVE + + , NUM_COMMANDS + }; + +// Assembler + Update_t CmdAssemble (int nArgs); + +// Disassembler Data + Update_t CmdDisasmDataDefCode (int nArgs); + Update_t CmdDisasmDataList (int nArgs); + + Update_t CmdDisasmDataDefByte1 (int nArgs); + Update_t CmdDisasmDataDefByte2 (int nArgs); + Update_t CmdDisasmDataDefByte4 (int nArgs); + Update_t CmdDisasmDataDefByte8 (int nArgs); + + Update_t CmdDisasmDataDefWord1 (int nArgs); + Update_t CmdDisasmDataDefWord2 (int nArgs); + Update_t CmdDisasmDataDefWord4 (int nArgs); + + Update_t CmdDisasmDataDefString (int nArgs); + + Update_t CmdDisasmDataDefAddress8H(int nArgs); + Update_t CmdDisasmDataDefAddress8L(int nArgs); + Update_t CmdDisasmDataDefAddress16(int nArgs); + +// CPU + Update_t CmdCursorJumpPC(int nArgs); + Update_t CmdCursorSetPC (int nArgs); + Update_t CmdBreakInvalid(int nArgs); // Breakpoint IFF Full-speed! + Update_t CmdBreakOpcode (int nArgs); // Breakpoint IFF Full-speed! + Update_t CmdGo (int nArgs); + Update_t CmdIn (int nArgs); + Update_t CmdKey (int nArgs); + Update_t CmdJSR (int nArgs); + Update_t CmdNOP (int nArgs); + Update_t CmdOut (int nArgs); + Update_t CmdStepOver (int nArgs); + Update_t CmdStepOut (int nArgs); + Update_t CmdTrace (int nArgs); // alias for CmdStepIn + Update_t CmdTraceFile (int nArgs); + Update_t CmdTraceLine (int nArgs); + Update_t CmdUnassemble (int nArgs); // code dump, aka, Unassemble +// Bookmarks + Update_t CmdBookmark (int nArgs); + Update_t CmdBookmarkAdd (int nArgs); + Update_t CmdBookmarkClear (int nArgs); + Update_t CmdBookmarkList (int nArgs); + Update_t CmdBookmarkGoto (int nArgs); +// Update_t CmdBookmarkLoad (int nArgs); + Update_t CmdBookmarkSave (int nArgs); +// Breakpoints + Update_t CmdBreakpoint (int nArgs); + Update_t CmdBreakpointAddSmart(int nArgs); + Update_t CmdBreakpointAddReg (int nArgs); + Update_t CmdBreakpointAddPC (int nArgs); + Update_t CmdBreakpointAddIO (int nArgs); + Update_t CmdBreakpointAddMem (int nArgs); + Update_t CmdBreakpointClear (int nArgs); + Update_t CmdBreakpointDisable (int nArgs); + Update_t CmdBreakpointEdit (int nArgs); + Update_t CmdBreakpointEnable (int nArgs); + Update_t CmdBreakpointList (int nArgs); +// Update_t CmdBreakpointLoad (int nArgs); + Update_t CmdBreakpointSave (int nArgs); +// Benchmark + Update_t CmdBenchmark (int nArgs); + Update_t CmdBenchmarkStart (int nArgs); //Update_t CmdSetupBenchmark (int nArgs); + Update_t CmdBenchmarkStop (int nArgs); //Update_t CmdExtBenchmark (int nArgs); + Update_t CmdProfile (int nArgs); + Update_t CmdProfileStart (int nArgs); + Update_t CmdProfileStop (int nArgs); +// Config +// Update_t CmdConfigMenu (int nArgs); +// Update_t CmdConfigBase (int nArgs); +// Update_t CmdConfigBaseHex (int nArgs); +// Update_t CmdConfigBaseDec (int nArgs); + Update_t CmdConfigColorMono (int nArgs); + Update_t CmdConfigDisasm (int nArgs); + Update_t CmdConfigFont (int nArgs); + Update_t CmdConfigHColor (int nArgs); + Update_t CmdConfigLoad (int nArgs); + Update_t CmdConfigSave (int nArgs); + Update_t CmdConfigSetFont (int nArgs); + Update_t CmdConfigGetFont (int nArgs); +// Cursor + Update_t CmdCursorFollowTarget(int nArgs); + Update_t CmdCursorLineDown (int nArgs); + Update_t CmdCursorLineUp (int nArgs); + Update_t CmdCursorJumpRetAddr (int nArgs); + Update_t CmdCursorRunUntil (int nArgs); + Update_t CmdCursorPageDown (int nArgs); + Update_t CmdCursorPageDown256 (int nArgs); + Update_t CmdCursorPageDown4K (int nArgs); + Update_t CmdCursorPageUp (int nArgs); + Update_t CmdCursorPageUp256 (int nArgs); + Update_t CmdCursorPageUp4K (int nArgs); +// Disk + Update_t CmdDisk (int nArgs); +// Help + Update_t CmdHelpList (int nArgs); + Update_t CmdHelpSpecific (int Argss); + Update_t CmdVersion (int nArgs); + Update_t CmdMOTD (int nArgs); +// Flags + Update_t CmdFlag (int nArgs); + Update_t CmdFlagClear (int nArgs); + Update_t CmdFlagSet (int nArgs); +// Memory (Data) + Update_t CmdMemoryCompare (int nArgs); + Update_t CmdMemoryMiniDumpHex (int nArgs); + Update_t CmdMemoryMiniDumpAscii(int nArgs); + Update_t CmdMemoryMiniDumpApple(int nArgs); +// Update_t CmdMemoryMiniDumpLow (int nArgs); +// Update_t CmdMemoryMiniDumpHigh (int nArgs); + + Update_t CmdMemoryEdit (int nArgs); + Update_t CmdMemoryEnterByte (int nArgs); + Update_t CmdMemoryEnterWord (int nArgs); + Update_t CmdMemoryFill (int nArgs); + Update_t CmdMemoryLoad (int nArgs); + Update_t CmdMemoryMove (int nArgs); + Update_t CmdMemorySave (int nArgs); + Update_t CmdMemorySearch (int nArgs); + Update_t _SearchMemoryDisplay (int nArgs=0); +// Update_t CmdMemorySearchLowBit (int nArgs); +// Update_t CmdMemorySearchHiBit (int nArgs); + Update_t CmdMemorySearchAscii (int nArgs); + Update_t CmdMemorySearchApple (int nArgs); + Update_t CmdMemorySearchHex (int nArgs); +// Output/Scripts + Update_t CmdOutputCalc (int nArgs); + Update_t CmdOutputEcho (int nArgs); + Update_t CmdOutputPrint (int nArgs); + Update_t CmdOutputPrintf (int nArgs); + Update_t CmdOutputRun (int nArgs); +// Registers + Update_t CmdRegisterSet (int nArgs); +// Source Level Debugging + Update_t CmdSource (int nArgs); + Update_t CmdSync (int nArgs); +// Stack + Update_t CmdStackPush (int nArgs); + Update_t CmdStackPop (int nArgs); + Update_t CmdStackPopPseudo (int nArgs); + Update_t CmdStackReturn (int nArgs); +// Symbols + Update_t CmdSymbols (int nArgs); + Update_t CmdSymbolsClear (int nArgs); + Update_t CmdSymbolsList (int nArgs); + Update_t CmdSymbolsLoad (int nArgs); + Update_t CmdSymbolsInfo (int nArgs); + Update_t CmdSymbolsSave (int nArgs); + + Update_t CmdSymbolsCommand (int nArgs); +// Update_t CmdSymbolsMain (int nArgs); +// Update_t CmdSymbolsBasic (int nArgs); +// Update_t CmdSymbolsUser (int nArgs); +// Update_t CmdSymbolsAssembly (int nArgs); +// Update_t CmdSymbolsSource (int nArgs); + + // View + Update_t CmdViewOutput_Text4X (int nArgs); + Update_t CmdViewOutput_Text41 (int nArgs); + Update_t CmdViewOutput_Text42 (int nArgs); + Update_t CmdViewOutput_Text8X (int nArgs); + Update_t CmdViewOutput_Text81 (int nArgs); + Update_t CmdViewOutput_Text82 (int nArgs); + + Update_t CmdViewOutput_GRX (int nArgs); + Update_t CmdViewOutput_GR1 (int nArgs); + Update_t CmdViewOutput_GR2 (int nArgs); + Update_t CmdViewOutput_DGRX (int nArgs); + Update_t CmdViewOutput_DGR1 (int nArgs); + Update_t CmdViewOutput_DGR2 (int nArgs); + + Update_t CmdViewOutput_HGRX (int nArgs); + Update_t CmdViewOutput_HGR1 (int nArgs); + Update_t CmdViewOutput_HGR2 (int nArgs); + Update_t CmdViewOutput_DHGRX (int nArgs); + Update_t CmdViewOutput_DHGR1 (int nArgs); + Update_t CmdViewOutput_DHGR2 (int nArgs); +// Watch + Update_t CmdWatch (int nArgs); + Update_t CmdWatchAdd (int nArgs); + Update_t CmdWatchClear (int nArgs); + Update_t CmdWatchDisable (int nArgs); + Update_t CmdWatchEnable (int nArgs); + Update_t CmdWatchList (int nArgs); +// Update_t CmdWatchLoad (int nArgs); + Update_t CmdWatchSave (int nArgs); +// Window + Update_t CmdWindow (int nArgs); + Update_t CmdWindowCycleNext (int nArgs); + Update_t CmdWindowCyclePrev (int nArgs); + Update_t CmdWindowLast (int nArgs); + + Update_t CmdWindowShowCode (int nArgs); + Update_t CmdWindowShowCode1 (int nArgs); + Update_t CmdWindowShowCode2 (int nArgs); + Update_t CmdWindowShowData (int nArgs); + Update_t CmdWindowShowData1 (int nArgs); + Update_t CmdWindowShowData2 (int nArgs); + Update_t CmdWindowShowSymbols1(int nArgs); + Update_t CmdWindowShowSymbols2(int nArgs); + Update_t CmdWindowShowSource (int nArgs); + Update_t CmdWindowShowSource1 (int nArgs); + Update_t CmdWindowShowSource2 (int nArgs); + + Update_t CmdWindowViewCode (int nArgs); + Update_t CmdWindowViewConsole (int nArgs); + Update_t CmdWindowViewData (int nArgs); + Update_t CmdWindowViewOutput (int nArgs); + Update_t CmdWindowViewSource (int nArgs); + Update_t CmdWindowViewSymbols (int nArgs); + + Update_t CmdWindowWidthToggle (int nArgs); + +// Update_t CmdZeroPageShow (int nArgs); +// Update_t CmdZeroPageHide (int nArgs); +// Update_t CmdZeroPageToggle (int nArgs); + +// ZeroPage + Update_t CmdZeroPage (int nArgs); + Update_t CmdZeroPageAdd (int nArgs); + Update_t CmdZeroPageClear (int nArgs); + Update_t CmdZeroPageDisable (int nArgs); + Update_t CmdZeroPageEnable (int nArgs); + Update_t CmdZeroPageList (int nArgs); +// Update_t CmdZeroPageLoad (int nArgs); + Update_t CmdZeroPageSave (int nArgs); + Update_t CmdZeroPagePointer (int nArgs); + + +// Cursor _________________________________________________________________________________________ + enum Cursor_Align_e + { + CURSOR_ALIGN_TOP, + CURSOR_ALIGN_CENTER + }; + + enum CursorHiLightState_e + { + CURSOR_NORMAL , // White + CURSOR_CPU_PC , // Yellow + CURSOR_BREAKPOINT, // Red + }; + + +// Disassembly ____________________________________________________________________________________ + + enum DisasmBranch_e + { + DISASM_BRANCH_OFF = 0 + , DISASM_BRANCH_PLAIN + , DISASM_BRANCH_FANCY + , NUM_DISASM_BRANCH_TYPES + }; + + enum DisasmFormat_e + { + DISASM_FORMAT_CHAR = (1 << 0), + DISASM_FORMAT_SYMBOL = (1 << 1), + DISASM_FORMAT_OFFSET = (1 << 2), + DISASM_FORMAT_BRANCH = (1 << 3), + DISASM_FORMAT_TARGET_POINTER = (1 << 4), + DISASM_FORMAT_TARGET_VALUE = (1 << 5), + }; + + enum DisasmImmediate_e + { + DISASM_IMMED_OFF = 0 + , DISASM_IMMED_TARGET + , DISASM_IMMED_MODE + , DISASM_IMMED_BOTH + , NUM_DISASM_IMMED_TYPES + }; + + enum DisasmTargets_e + { + DISASM_TARGET_OFF = 0 + , DISASM_TARGET_VAL // Note: Also treated as bit flag !! + , DISASM_TARGET_ADDR // Note: Also treated as bit flag !! + , DISASM_TARGET_BOTH // Note: Also treated as bit flag !! + , NUM_DISASM_TARGET_TYPES + }; + + enum DisasmText_e + { + nMaxAddressLen = 40, + nMaxOpcodes = 3, + CHARS_FOR_ADDRESS = 8, // 4 digits + end-of-string + padding + }; + + struct DisasmLine_t + { + short iOpcode; + short iOpmode; + int nOpbyte; + + char sAddress [ CHARS_FOR_ADDRESS ]; + char sOpCodes [(nMaxOpcodes*3)+1]; + + // Added for Data Disassembler + char sLabel [ MAX_SYMBOLS_LEN+1 ]; // label is a symbol + int iNopcode; // directive / pseudo opcode + int iNoptype; // element type + char sMnemonic [ MAX_SYMBOLS_LEN+1 ]; + + int nTarget; + char sTarget [nMaxAddressLen]; + + char sTargetOffset[ CHARS_FOR_ADDRESS ]; // +/- 255, realistically +/-1 + int nTargetOffset; + + char sTargetPointer[ CHARS_FOR_ADDRESS ]; + char sTargetValue [ CHARS_FOR_ADDRESS ]; +// char sTargetAddress[ CHARS_FOR_ADDRESS ]; + + char sImmediate[ 4 ]; // 'c' + char nImmediate; + char sBranch [ 4 ]; // ^ + + bool bTargetImmediate; + bool bTargetIndirect; + bool bTargetIndexed ; + bool bTargetRelative; + bool bTargetX ; + bool bTargetY ; + bool bTargetValue ; + + void Clear() + { + sAddress [ 0 ] = 0; + sOpCodes [ 0 ] = 0; + + nTarget = 0; + sTarget [ 0 ] = 0; + + sTargetOffset[ 0 ] = 0; + nTargetOffset = 0; + + sTargetPointer[ 0 ] = 0; + sTargetValue [ 0 ] = 0; + + sImmediate[ 0 ] = 0; + nImmediate = 0; + + sBranch [ 0 ] = 0; + ClearFlags(); + } + void ClearFlags() + { + bTargetImmediate = false; // display "#" + bTargetIndexed = false; // display () + bTargetIndirect = false; // display () + bTargetRelative = false; // display () + bTargetX = false; // display ",X" + bTargetY = false; // display ",Y" + bTargetValue = false; // display $#### + } + }; + +// Font ___________________________________________________________________________________________ + enum FontType_e + { +// FONT_DEFAULT + FONT_INFO + , FONT_CONSOLE + , FONT_DISASM_DEFAULT + , FONT_DISASM_BRANCH + // , FONT_SOURCE + , NUM_FONTS + }; + + enum + { + MAX_FONT_NAME = MAX_ARG_LEN // was 64 + }; + + enum FontSpacing_e + { + FONT_SPACING_CLASSIC , // least lines (most spacing) + FONT_SPACING_CLEAN , // more lines (minimal spacing) + FONT_SPACING_COMPRESSED, // max lines (least spacing) + NUM_FONT_SPACING + }; + + struct FontConfig_t + { + char _sFontName[ MAX_FONT_NAME ]; + HFONT _hFont; +// int _iFontType; + int _nFontWidthAvg; + int _nFontWidthMax; + int _nFontHeight; + int _nLineHeight; // may or may not include spacer + }; + + +// Instructions / Opcodes _________________________________________________________________________ + + //#define SUPPORT_Z80_EMU + #ifdef SUPPORT_Z80_EMU + #define OUTPUT_Z80_REGS + #define REG_AF 0xF0 + #define REG_BC 0xF2 + #define REG_DE 0xF4 + #define REG_HL 0xF6 + #define REG_IX 0xF8 + #endif + + enum MemoryAccess_e + { + MEM_R = (1 << 0), // Read + MEM_W = (1 << 1), // Write + MEM_RI = (1 << 2), // Read Implicit (Implied) + MEM_WI = (1 << 3), // Write Implicit (Implied) + MEM_S = (1 << 4), // Stack (Read/Write) + MEM_IM = (1 << 5), // Immediate - Technically reads target byte + + NUM_MEM_ACCESS, + + // Alias + MEM_READ = (1 << 0), + MEM_WRITE = (1 << 1), + }; + + enum + { + // First 256 are 6502 + // TODO: Second 256 are Directives/Pseudo Mnemonics + NUM_OPCODES = 256, + + MAX_MNEMONIC_LEN = 3, + }; + + struct Opcodes_t + { + char sMnemonic[ MAX_MNEMONIC_LEN+1 ]; + // int16 for structure 8-byte alignment + short nAddressMode; // TODO/FIX: nOpmode + short nMemoryAccess; + }; + + struct Instruction2_t + { + char sMnemonic[MAX_MNEMONIC_LEN+1]; + int nAddressMode; + int iMemoryAccess; + }; + + enum Opcode_e + { + OPCODE_BRA = 0x80, + + OPCODE_JSR = 0x20, + OPCODE_JMP_A = 0x4C, // Absolute + OPCODE_JMP_NA = 0x6C, // Indirect Absolute + OPCODE_JMP_IAX = 0x7C, // Indexed (Absolute Indirect, X) + }; + + // Note: "int" causes overflow when profiling for any amount of time. + // typedef unsigned int Profile_t; + // i.e. + // double nPercent = static_cast(100 * tProfileOpcode.uProfile) / nOpcodeTotal; // overflow + typedef double Profile_t; + + struct ProfileOpcode_t + { + int m_iOpcode; + Profile_t m_nCount; // Histogram + + // functor + bool operator () (const ProfileOpcode_t & rLHS, const ProfileOpcode_t & rRHS) const + { + bool bGreater = (rLHS.m_nCount > rRHS.m_nCount); + return bGreater; + } + }; + + struct ProfileOpmode_t + { + int m_iOpmode; + Profile_t m_nCount; // Histogram + + // functor + bool operator () (const ProfileOpmode_t & rLHS, const ProfileOpmode_t & rRHS) const + { + bool bGreater = (rLHS.m_nCount > rRHS.m_nCount); + return bGreater; + } + }; + + enum ProfileFormat_e + { + PROFILE_FORMAT_SPACE, + PROFILE_FORMAT_TAB, + PROFILE_FORMAT_COMMA, + }; + +// Memory _________________________________________________________________________________________ + + extern const int _6502_BRANCH_POS ;//= +127 + extern const int _6502_BRANCH_NEG ;//= -128 + extern const unsigned int _6502_ZEROPAGE_END ;//= 0x00FF; + extern const unsigned int _6502_STACK_END ;//= 0x01FF; + extern const unsigned int _6502_IO_BEGIN ;//= 0xC000; + extern const unsigned int _6502_IO_END ;//= 0xC0FF; + extern const unsigned int _6502_MEM_BEGIN ;//= 0x0000; + extern const unsigned int _6502_MEM_END ;//= 0xFFFF; + + + enum DEVICE_e + { + DEV_MEMORY, + DEV_DISK2 , + DEV_SY6522, + DEV_AY8910, + NUM_DEVICES + }; + + enum MemoryView_e + { + MEM_VIEW_HEX , + + // 0x00 .. 0x1F Ctrl (Inverse) + // 0x20 .. 0x7F Flash / MouseText (Cyan) + // 0x80 .. 0x9F Hi-Bit Ctrl (Yellow) + // 0xA0 .. 0xFF Hi-Bit Normal (White) + MEM_VIEW_ASCII , + MEM_VIEW_APPLE , // Low-Bit ASCII (Colorized Background) +// MEM_VIEW_TXT_LO, // Ctrl Chars mapped to visible range, and inverse +// MEM_VIEW_TXT_HI, // High Bit Ascii + NUM_MEM_VIEWS + }; + + struct MemoryDump_t + { + bool bActive; + WORD nAddress; // nAddressMemDump; // was USHORT + DEVICE_e eDevice; + MemoryView_e eView; + }; + + enum MemoryDump_e + { + MEM_DUMP_1, + MEM_DUMP_2, + NUM_MEM_DUMPS + }; + + enum MemoryMiniDump_e + { + NUM_MEM_MINI_DUMPS = 2 + }; + + enum MemorySearch_e + { + MEM_SEARCH_BYTE_EXACT , // xx + MEM_SEARCH_NIB_LOW_EXACT , // ?x + MEM_SEARCH_NIB_HIGH_EXACT, // x? + MEM_SEARCH_BYTE_1_WILD , // ? + MEM_SEARCH_BYTE_N_WILD , // ?? + + MEM_SEARCH_TYPE_MASK = (1 << 16) - 1, + MEM_SEARCH_FOUND = (1 << 16) + }; + + struct MemorySearch_t + { + BYTE m_nValue ; // search value + MemorySearch_e m_iType ; // + bool m_bFound ; // + }; + + typedef vector MemorySearchValues_t; + typedef vector MemorySearchResults_t; + +// Parameters _____________________________________________________________________________________ + + /* i.e. + SYM LOAD = $C600 (1) type: string, nVal1 = symlookup; (2) type: operator, token: EQUAL; (3) type: address, token:DOLLAR + BP LOAD type: + BP $LOAD type: (1) = symbol, val=1adress + */ + enum ArgToken_e // Arg Token Type + { + // Single Char Tokens must come first + TOKEN_ALPHANUMERIC // + , TOKEN_AMPERSAND // & + , TOKEN_AT // @ results dereference. i.e. S 0,FFFF C030; L @1 + , TOKEN_BRACE_L // { + , TOKEN_BRACE_R // } + , TOKEN_BRACKET_L // [ + , TOKEN_BRACKET_R // ] + , TOKEN_BSLASH // \xx Hex Literal + , TOKEN_CARET // ^ +// , TOKEN_CHAR + , TOKEN_COLON // : Range + , TOKEN_COMMA // , Length +// , TOKEN_DIGIT + , TOKEN_DOLLAR // $ Address (symbol lookup forced) + , TOKEN_EQUAL // = Assign Argment.n2 = Argument2 + , TOKEN_EXCLAMATION // ! + , TOKEN_FSLASH // / + , TOKEN_GREATER_THAN // > + , TOKEN_HASH // # Value no symbol lookup + , TOKEN_LESS_THAN // < + , TOKEN_MINUS // - Delta Argument1 -= Argument2 + , TOKEN_PAREN_L // ( + , TOKEN_PAREN_R // ) + , TOKEN_PERCENT // % + , TOKEN_PIPE // | + , TOKEN_PLUS // + Delta Argument1 += Argument2 + , TOKEN_QUOTE_SINGLE // ' + , TOKEN_QUOTE_DOUBLE // " + , TOKEN_SEMI // ; Command Seperator + , TOKEN_SPACE // Token Delimiter + , TOKEN_STAR // * +// , TOKEN_TAB // '\t' + , TOKEN_TILDE // ~ + + // Multi char tokens come last + , TOKEN_COMMENT_EOL // // + ,_TOKEN_FLAG_MULTI = TOKEN_COMMENT_EOL + , TOKEN_GREATER_EQUAL// >= + , TOKEN_LESS_EQUAL // <= + , TOKEN_NOT_EQUAL // != +// , TOKEN_COMMENT_1 // /* +// , TOKEN_COMMENT_2 // */ + + , NUM_TOKENS // signal none, or bad + , NO_TOKEN = NUM_TOKENS + }; + + enum ArgType_e + { + TYPE_ADDRESS = (1 << 0) // $#### or $symbolname + , TYPE_OPERATOR = (1 << 1) + , TYPE_QUOTED_1 = (1 << 2) + , TYPE_QUOTED_2 = (1 << 3) // "..." + , TYPE_STRING = (1 << 4) // LOAD + , TYPE_RANGE = (1 << 5) + , TYPE_LENGTH = (1 << 6) + , TYPE_VALUE = (1 << 7) + , TYPE_NO_REG = (1 << 8) // Don't do register value -> Argument.nValue + , TYPE_NO_SYM = (1 << 9) // Don't do symbol lookup -> Argument.nValue + }; + + struct TokenTable_t + { + ArgToken_e eToken; + ArgType_e eType ; + char sToken[4]; + }; + + struct Arg_t + { + char sArg[ MAX_ARG_LEN ]; // Array chars comes first, for alignment + int nArgLen; // Needed for TextSearch "ABC\x00" + WORD nValue ; // 2 +// WORD nVal1 ; // 2 +// WORD nVal2 ; // 2 If we have a Len (,) + // Enums and Bools should come last for alignment + ArgToken_e eToken ; // 1/2/4 + int bType ; // 1/2/4 // Flags of ArgType_e + DEVICE_e eDevice; // 1/2/4 + bool bSymbol; // 1 + }; + + // NOTE: Order MUST match g_aParameters[] !!! + enum Parameters_e + { + // Note: Order must match Breakpoint_Operator_t + // Note: Order must match _PARAM_BREAKPOINT_* + // Note: Order must match g_aBreakpointSymbols + _PARAM_BREAKPOINT_BEGIN + , PARAM_BP_LESS_EQUAL = _PARAM_BREAKPOINT_BEGIN // <= + , PARAM_BP_LESS_THAN // < + , PARAM_BP_EQUAL // = + , PARAM_BP_NOT_EQUAL // != + , PARAM_BP_NOT_EQUAL_1 // ! + , PARAM_BP_GREATER_THAN // > + , PARAM_BP_GREATER_EQUAL // >= + , PARAM_BP_READ // R + ,_PARAM_BP_READ // ? alias READ + , PARAM_BP_WRITE // W + ,_PARAM_BP_WRITE // @ alias write + , PARAM_BP_READ_WRITE // * alias READ WRITE + , _PARAM_BREAKPOINT_END + , PARAM_BREAKPOINT_NUM = _PARAM_BREAKPOINT_END - _PARAM_BREAKPOINT_BEGIN + +// , PARAM_SIZE // TODO: used by FONT SIZE + + // Note: Order must match Breakpoint_Source_t + , _PARAM_REGS_BEGIN = _PARAM_BREAKPOINT_END // Daisy Chain +// Regs + , PARAM_REG_A = _PARAM_REGS_BEGIN + , PARAM_REG_X + , PARAM_REG_Y + , PARAM_REG_PC // Program Counter + , PARAM_REG_SP // Stack Pointer +// Flags + , PARAM_FLAGS // Processor Status + , PARAM_FLAG_C // Carry + , PARAM_FLAG_Z // Zero + , PARAM_FLAG_I // Interrupt + , PARAM_FLAG_D // Decimal + , PARAM_FLAG_B // Break + , PARAM_FLAG_R // Reserved + , PARAM_FLAG_V // Overflow + , PARAM_FLAG_N // Sign + , _PARAM_REGS_END + , PARAM_REGS_NUM = _PARAM_REGS_END - _PARAM_REGS_BEGIN + +// Disasm + , _PARAM_CONFIG_BEGIN = _PARAM_REGS_END // Daisy Chain + , PARAM_CONFIG_BRANCH = _PARAM_CONFIG_BEGIN // g_iConfigDisasmBranchType [0|1|2] + , PARAM_CONFIG_COLON // g_bConfigDisasmAddressColon [0|1] + , PARAM_CONFIG_OPCODE // g_bConfigDisasmOpcodesView [0|1] + , PARAM_CONFIG_POINTER // g_bConfigInfoTargetPointer [0|1] + , PARAM_CONFIG_SPACES // g_bConfigDisasmOpcodeSpaces [0|1] + , PARAM_CONFIG_TARGET // g_iConfigDisasmTargets [0|1|2] + , _PARAM_CONFIG_END + , PARAM_CONFIG_NUM = _PARAM_CONFIG_END - _PARAM_CONFIG_BEGIN + +// Disk + , _PARAM_DISK_BEGIN = _PARAM_CONFIG_END // Daisy Chain + , PARAM_DISK_EJECT = _PARAM_DISK_BEGIN // DISK 1 EJECT + , PARAM_DISK_PROTECT // DISK 1 PROTECT + , PARAM_DISK_READ // DISK 1 READ Track Sector NumSectors MemAddress + , _PARAM_DISK_END + , PARAM_DISK_NUM = _PARAM_DISK_END - _PARAM_DISK_BEGIN + + , _PARAM_FONT_BEGIN = _PARAM_DISK_END // Daisy Chain + , PARAM_FONT_MODE = _PARAM_FONT_BEGIN + , _PARAM_FONT_END + , PARAM_FONT_NUM = _PARAM_FONT_END - _PARAM_FONT_BEGIN + + , _PARAM_GENERAL_BEGIN = _PARAM_FONT_END // Daisy Chain + , PARAM_FIND = _PARAM_GENERAL_BEGIN + , PARAM_BRANCH + , PARAM_CATEGORY + , PARAM_CLEAR + , PARAM_LOAD + , PARAM_LIST + , PARAM_OFF + , PARAM_ON + , PARAM_RESET + , PARAM_SAVE + , PARAM_START + , PARAM_STOP + , _PARAM_GENERAL_END + , PARAM_GENERAL_NUM = _PARAM_GENERAL_END - _PARAM_GENERAL_BEGIN + + , _PARAM_HELPCATEGORIES_BEGIN = _PARAM_GENERAL_END // Daisy Chain + , PARAM_WILDSTAR = _PARAM_HELPCATEGORIES_BEGIN + , PARAM_CAT_BOOKMARKS + , PARAM_CAT_BREAKPOINTS + , PARAM_CAT_CONFIG + , PARAM_CAT_CPU +// , PARAM_CAT_EXPRESSION + , PARAM_CAT_FLAGS + , PARAM_CAT_HELP + , PARAM_CAT_KEYBOARD + , PARAM_CAT_MEMORY + , PARAM_CAT_OUTPUT + , PARAM_CAT_OPERATORS + , PARAM_CAT_RANGE +// , PARAM_CAT_REGISTERS + , PARAM_CAT_SYMBOLS + , PARAM_CAT_VIEW + , PARAM_CAT_WATCHES + , PARAM_CAT_WINDOW + , PARAM_CAT_ZEROPAGE + , _PARAM_HELPCATEGORIES_END + , PARAM_HELPCATEGORIES_NUM = _PARAM_HELPCATEGORIES_END - _PARAM_HELPCATEGORIES_BEGIN + + , _PARAM_MEM_SEARCH_BEGIN = _PARAM_HELPCATEGORIES_END // Daisy Chain + , PARAM_MEM_SEARCH_WILD = _PARAM_MEM_SEARCH_BEGIN +// , PARAM_MEM_SEARCH_BYTE + , _PARAM_MEM_SEARCH_END + , PARAM_MEM_SEARCH_NUM = _PARAM_MEM_SEARCH_END - _PARAM_MEM_SEARCH_BEGIN + + , _PARAM_SOURCE_BEGIN = _PARAM_MEM_SEARCH_END // Daisy Chain + , PARAM_SRC_MEMORY = _PARAM_SOURCE_BEGIN + ,_PARAM_SRC_MEMORY // alias MEM = MEMORY + , PARAM_SRC_SYMBOLS + ,_PARAM_SRC_SYMBOLS // alias SYM = SYMBOLS + , PARAM_SRC_MERLIN + , PARAM_SRC_ORCA + , _PARAM_SOURCE_END + , PARAM_SOURCE_NUM = _PARAM_SOURCE_END - _PARAM_SOURCE_BEGIN + + , _PARAM_WINDOW_BEGIN = _PARAM_SOURCE_END // Daisy Chain + // These are the "full screen" "windows" / Panels / Tab sheets + , PARAM_CODE = _PARAM_WINDOW_BEGIN // disasm +// , PARAM_CODE_1 // disasm top // removed, since can't set top window for code/data + , PARAM_CODE_2 // disasm bot + , PARAM_CONSOLE + , PARAM_DATA // data all +// , PARAM_DATA_1 // data top // removed, since can't set top window for code/data + , PARAM_DATA_2 // data bot + , PARAM_DISASM + , PARAM_INFO // Togle INFO on/off + , PARAM_SOURCE + , _PARAM_SRC // alias SRC = SOURCE +// , PARAM_SOURCE_1 // source top // removed, since can't set top window for code/data + , PARAM_SOURCE_2 // source bot + , PARAM_SYMBOLS + , _PARAM_SYM // alias SYM = SYMBOLS +// , PARAM_SYMBOL_1 // symbols top // removed, since can't set top window for code/data + , PARAM_SYMBOL_2 // symbols bot + , _PARAM_WINDOW_END + , PARAM_WINDOW_NUM = _PARAM_WINDOW_END - _PARAM_WINDOW_BEGIN + + , NUM_PARAMS = _PARAM_WINDOW_END // Daisy Chain + +// Aliases (actuall names) +// ,PARAM_DISASM = PARAM_CODE_1 +// , PARAM_BREAKPOINT_READ = PARAM_READ +// , PARAM_BREAKPOINT_WRITE = PARAM_WRITE + }; + + +// Source Level Debugging _________________________________________________________________________ + + enum + { + NO_SOURCE_LINE = -1 + }; + + typedef map SourceAssembly_t; // Address -> Line # & FileName + + +// Symbols ________________________________________________________________________________________ + + // **************************************** + // WARNING: This is the index (enumeration) to select which table + // See: g_aSymbols[] + // **************************************** + enum SymbolTable_Index_e // Symbols_e -> SymbolTable_Index_e + { + SYMBOLS_MAIN, + SYMBOLS_APPLESOFT, + SYMBOLS_ASSEMBLY, + SYMBOLS_USER_1, + SYMBOLS_USER_2, + SYMBOLS_SRC_1, + SYMBOLS_SRC_2, + NUM_SYMBOL_TABLES + }; + + // **************************************** + // WARNING: This is the bit-flags to select which table. + // See: CmdSymbolsListTable() + // **************************************** + enum SymbolTable_Masks_e // SymbolTable_e -> + { + SYMBOL_TABLE_MAIN = (1 << 0), + SYMBOL_TABLE_APPLESOFT = (1 << 1), + SYMBOL_TABLE_ASSEMBLY = (1 << 2), + SYMBOL_TABLE_USER_1 = (1 << 3), + SYMBOL_TABLE_USER_2 = (1 << 4), + SYMBOL_TABLE_SRC_1 = (1 << 5), + SYMBOL_TABLE_SRC_2 = (1 << 6), + }; + + typedef map SymbolTable_t; + + +// Watches ________________________________________________________________________________________ + + enum + { + MAX_WATCHES = 16 + }; + + +// Window _________________________________________________________________________________________ + + enum Window_e + { + WINDOW_CODE , + WINDOW_DATA , + WINDOW_CONSOLE , + NUM_WINDOWS , +// Not implemented yet + WINDOW_IO , // soft switches $addr name state + WINDOW_SYMBOLS , + WINDOW_ZEROPAGE, + WINDOW_SOURCE , + }; + + struct WindowSplit_t + { + bool bSplit; + Window_e eTop; + Window_e eBot; + // TODO: nTopHeight + // TODO: nBotHeight + }; + + +// Zero Page ______________________________________________________________________________________ + + enum + { + MAX_ZEROPAGE_POINTERS = 8 + }; +