mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-09-07 00:54:25 +00:00
11638 lines
330 KiB
C++
11638 lines
330 KiB
C++
|
/*
|
||
|
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, 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
|
||
|
*/
|
||
|
|
||
|
// disable warning C4786: symbol greater than 255 character:
|
||
|
#pragma warning(disable: 4786)
|
||
|
|
||
|
#include "StdAfx.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
// NEW UI debugging
|
||
|
// #define DEBUG_FORCE_DISPLAY 1
|
||
|
// #define DEBUG_COMMAND_HELP 1
|
||
|
// #define DEBUG_ASM_HASH 1
|
||
|
|
||
|
// enable warning C4786: symbol greater than 255 character:
|
||
|
//#pragma warning(enable: 4786)
|
||
|
|
||
|
// TCHAR DEBUG_VERSION = "0.0.0.0"; // App Version
|
||
|
#define DEBUGGER_VERSION MAKE_VERSION(2,4,2,16);
|
||
|
|
||
|
// TODO: COLOR RESET
|
||
|
// TODO: COLOR SAVE ["filename"]
|
||
|
// TODO: COLOR LOAD ["filename"]
|
||
|
|
||
|
// Patch 22
|
||
|
// .16 fixed BPM. i.e. BPM C400,100. Boot: ulti4bo.dsk, breaks at: 81BC: STA ($88),Y $0088=$C480 ... C483: A0
|
||
|
|
||
|
// Patch 21
|
||
|
// .15 Fixed: CmdRegisterSet() equal sign is now optional. i.e. R A [=] Y
|
||
|
// .14 Optimized: ArgsParse()
|
||
|
// .13 Fixed: HELP "..." on ambigious command displays potential commands
|
||
|
// .12 Added: Token %, calculator mod
|
||
|
// .11 Added: Token /, calculator div
|
||
|
// .10 Added: Token ^, calculator bit-xor
|
||
|
// .9 Added: Token |, calculator bit-or
|
||
|
// .8 Added: Token &, calculator bit-and
|
||
|
// .7 Added: Mini-Assembler
|
||
|
// .6 Added: MOTD (Message of the Day) : Moved from DebugBegin()
|
||
|
// .5 Added: HELP SOURCE
|
||
|
// .4 Fixed: SYMMAIN SYMUSER SYMSRC to now only search their respective symbol tables
|
||
|
// .3 Added: _CmdSymbolList_Address2Symbol() _CmdSymbolList_Symbol2Address() now take bit-flags of which tables to search
|
||
|
// .2 Added: EB alias for E
|
||
|
// .1 Added: EW address value16 CmdMemoryEnterWord() to set memory with 16-Bit Values
|
||
|
// 2.4.2.0
|
||
|
// .14 Added: SYM ! name to remove (user) symbol. _CmdSymbolsUpdate()
|
||
|
// .13 Added: JSR address|symbol CmdJSR()
|
||
|
// .12 Fixed: SYM address|symbol now reports if address or symbol not found. CmdSymbolsList()
|
||
|
// .11 Fixed PageUp*, PagDn* not being recognized valid commands.
|
||
|
|
||
|
// Patch 20
|
||
|
// .10 Added: SYM2 symbolname = value
|
||
|
// .9 Added: Undocumented command: FONT *
|
||
|
// .8 Improved: FONT MODE # is now more accurate. i.e. U 301
|
||
|
// FONT MODE 0 Classic line spacing (19 lines: 301 .. 313)
|
||
|
// FONT MODE 1 Improved line spacing (20 lines: 301 .. 314)
|
||
|
// FONT MODE 2 Optimal line spacing (22 lines: 301 .. 316)
|
||
|
// .7 Fixed: ArgsParse() wasn't parsing #value properly. i.e. CALC #A+0A
|
||
|
// .6 Cleanup: DrawWatches()
|
||
|
|
||
|
// Patch 19
|
||
|
// .5 Fixed: ProfileSave() doesn't strip '%' percent signs anymore. Changed: fprintf() to fputs()
|
||
|
// Fixed: PROFILE RESET doesn't do dummy run of formatting profile data.
|
||
|
// .4 Fixed: Exporting Profile data is now Excel/OpenOffice friendly.
|
||
|
// Zero counts not listed on console. (They are when saved to file.)
|
||
|
|
||
|
// Patch 18
|
||
|
// .3 Fixed: Help_Arg_1() now copies command name into arg.name
|
||
|
// .2 Fixed: Temporarily removed extra windows that aren't done yet from showing up: WINDOW_IO WINDOW_SYMBOLS WINDOW_ZEROPAGE WINDOW_SOURCE
|
||
|
// .1 Added: PROFILE LIST -- can now view the profile data from witin the debugger!
|
||
|
// 2.4.1 Added: PROFILE SAVE -- now we can optimize (D0 BNE), and (10 BPL) sucking up the major of the emulator's time. WOOT!
|
||
|
// Added: _6502GetOpmodeOpbyte() and _6502GetOpcodeOpmode()
|
||
|
// .37 Fixed: Misc. commands not updating the console when processed
|
||
|
|
||
|
// Patch 17
|
||
|
// .36 Data window now shows text dump based on memory view set (ASCII or APPLE)
|
||
|
// MA1 D0D0; DATA;
|
||
|
// MT1 D0D0; DATA;
|
||
|
// D D0D0; DATA;
|
||
|
// .35 Renamed: ML1 ML2 to MT1 MT2 (Mem Text)
|
||
|
// .34 Removed: MH1 MH2 (redundant MEM_VIEW_APPLE_TEXT)
|
||
|
// .33 Fixed: Tweaking of Lo,Hi,Norm Ascii colors for Disasm Immediate & Memory Dumps
|
||
|
// ML1 D0D0; MH2 D0D0; U FA75
|
||
|
// .32 Changed: Lo now maps High Ascii to printable chars. i.e. ML1 D0D0
|
||
|
// .31 Ctrl-Tab, and Ctrl-Shift-Tab now cycle next/prev windows.
|
||
|
// .30 Added: Up,Down,PageUp,PageDown,Shift-PageUp,Shift-PageDown,Ctrl-PageUp,Ctrl-PageDown now scroll Data window
|
||
|
// .29 Added: DATA window now shows memory dump
|
||
|
|
||
|
// Patch 16
|
||
|
// .28 Fixed: MONO wasn't setting monochrome scheme
|
||
|
// .27 Changed: Registers now drawn in light blue for both DrawSubWindow_Info() [DrawRegisters()] and DrawBreakpoints()
|
||
|
// Reg names in DrawSubWindow_Info no longer hard-coded: using g_areakpointSource[]
|
||
|
// .26 Changed: DrawTargets() now shows Temp Address, and Final Address as orange (FG_INFO_ADDRESS)
|
||
|
// .25 Changed: Flag Clear "FC" to "CL" (like 6502 mnemonic)
|
||
|
// Changed: Flag Set "FS" to "SE" (like 6502 mnemonic)
|
||
|
// Added: Mirrored 6502 Mnemonics to clear/set flags as commands
|
||
|
// Moved: Legacy Flag Clear/Set commands "R?" "S?" to aliases
|
||
|
// .24 Fixed OPCODE 2F: AM_INVALID1 -> AM_INVALID3
|
||
|
// .23 Fixed OPCODE 0F: AM_INVALID1 -> AM_INVALID3
|
||
|
// .22 Fixed: Shift-PageUp Shift-PageDown Ctrl-PageUp Ctrl-PageDown -> _CursorMoveUpAligned() & _CursorMoveDownAligned()
|
||
|
// Bug: U F001, Ctrl-PageDown
|
||
|
// Was using current disasm cursor address instead of top disasm cursor
|
||
|
// .21 Fixed: _CursorMoveUpAligned() & _CursorMoveDownAligned() not wrapping around past FF00 to 0, and wrapping around past 0 to FF00
|
||
|
// .20 Fixed: DisasmCalcTopFromCurAddress() causing bogus g_bDisasmCurBad when disasm invalid opcodes.
|
||
|
// .19 g_aAddressingFormat[] -> g_aOpmodes[]
|
||
|
// .18 Reverted .17 Changed StackPointer Input/Output. 'SP' is now back to 'S' (to be consistent with 6502 mnemonics)
|
||
|
|
||
|
// Patch 15
|
||
|
// .17 Changed StackPointer Input/Output from 'S' to 'SP'
|
||
|
// .16 Fixed Go StopAddress [SkipAddress,Length] Trace() not working afterwards
|
||
|
// .15 Added Info Regs color - Foreground and Background (orange)
|
||
|
|
||
|
// Patch 14
|
||
|
// .14 Added: Stack register now shows stack depth
|
||
|
// .13 Bugfix: CmdBreakpointAddPC() operators now don't add extra breakpoints. i.e. BPX P < FA00
|
||
|
// .12 Bugfix: DrawMemory() should draw memory byte for IO address: ML1 C000
|
||
|
|
||
|
// Patch 13
|
||
|
// NightlyBuild
|
||
|
// .11 Disasm now looks up symbols +1,-1. i.e. U FA85, u FAAE
|
||
|
// .10 Fixed '~' full console height
|
||
|
// .9 Fixed: FindCommand() to update command found if not exact match
|
||
|
// .8 Moved: Flag names from g_aFlagNames[] to "inlined" g_aBreakpointSource[]
|
||
|
// .7 Extended: Calc to show binary values, and char is single-quoted
|
||
|
// Nightly Build
|
||
|
// .6 Bugfix: DrawTargets() should draw target byte for IO address: R PC FB33
|
||
|
// .5 Extended: FONT "FontName" [Height]
|
||
|
// .4 Extended: Go StopAddress [SkipAddress,Len]
|
||
|
// .3 Added BPR F // break on flag
|
||
|
// Added ! // new breakpoint operator: NOT_EQUAL
|
||
|
|
||
|
// Patch 12
|
||
|
// .2 Fixed: FindCommand() and FindParam() now returns 0 if name length is 0.
|
||
|
// .1 Fixed: CmdHelpSpecific() wasn't printing help for 1 argument set by other commands
|
||
|
// 2.4.0.0 added: uber breakpoints: BPR [A|X|Y|PC|SP] [<,<=,=,>,>=] address
|
||
|
// .2 fixed: parsing console input to detect immediate values on operators '+', '-'
|
||
|
// You can now do register arithmetic: CALC A+X+Y
|
||
|
// .1 added: mini-calculator 'CALC'
|
||
|
// 2.3.2 Rewrote parsing of console input
|
||
|
// You can now do stuff like:
|
||
|
// BPA INITAN+3
|
||
|
// FONT "Lucida Console"
|
||
|
|
||
|
// Patch 11
|
||
|
// .19 fixed disasm: new color for disasm target address (orange)
|
||
|
// U FF14 shouldn't colorize ',X'
|
||
|
// U FF16 shouldn't colorize ',Y'
|
||
|
// U FF21 shouldn't colorze 'symbol,Y'
|
||
|
// Addr should be purple or orange to verify is fixed
|
||
|
// .18 fixed disasm: all indirects to do symbol lookup, and colorized '('...')' as operators
|
||
|
// .17 added disasm: syntax coloring to immediate mode prefix '#$'
|
||
|
// .16 fixed disasm window to work with proportional fonts
|
||
|
// .15 fixed buffer-overun crash in TextConvertTabsToSpaces()
|
||
|
|
||
|
// Patch 10
|
||
|
// .14 fixed help CATEGORY & SPECIFIC not working properly
|
||
|
// .13 fixed bug of CODE not removing CODE window split
|
||
|
// .12 fixed split window bug of re-sizing console too large
|
||
|
// .11 removed hard-coded height of 16 for line height in various Draw*()
|
||
|
// .10 added alpha feature: SOURCE2 now shows source assembly listing in bottom half of window DrawSourceLine()
|
||
|
// .9 added P [#] to step number of times specified
|
||
|
// .8 added Up-Arrow, Down-Arrow to scroll console by one line in full screen console window
|
||
|
// .7 Added source level debugger to buffer complete assembly source listing file
|
||
|
// .6 Added help for MA#, ML#, MH#
|
||
|
// .5 added 3rd symbol table: SRC
|
||
|
// .4 Added: seperated console input color, console output color
|
||
|
// .3 SYM now prints which symbol table the symbol was found in.
|
||
|
// .2 Added "DFB" to add assembler variable to user symbol table
|
||
|
// .1 Fixed FindAddressFromSymbol() and FindSymbolFromAddress() to search user symbol table first
|
||
|
// 2.3.1 Renamed all globals to conform to coding standard
|
||
|
|
||
|
// .10 added TAB to move the cursor back to the PC, if there is no console input
|
||
|
// .9 fixed bug of setting reg, always moving the cursor back the PC
|
||
|
// .8 added detection if font is proportional. Still doesn't draw properly, but slowly getting there.
|
||
|
// .7 added colorized chars for regs, and memory ascii dump
|
||
|
// .6 fixed console buffering BUG: ~,~,VERSION *
|
||
|
// .5 added ~ to toggle full console on/off
|
||
|
// .4 Fixed BUG: 'G' DebugContinueStepping() disasm window cursor getting out of sync: R PC FA62; U FB40; G FB53
|
||
|
// .3 Fixed spelling of CmdWindowLast()
|
||
|
// .2 Added undocumented "VERSION *" to show the number of bytes in the disasm "window"
|
||
|
// .1 Fixed BUG: CmdTrace() disasm window cursor getting out of sync: Start, F7, PageUp, Space
|
||
|
// 2.3.0.0 Syntax coloring for the disassembler! Plus a fancy branch indicator to 'PR#6'! Rock on!
|
||
|
// 38 Fixed FindParam() bug of skipping every other parameter
|
||
|
// 37 Fixed _PARAM_*_BEGIN _PARAM_*_END _PARAM_*_NUM
|
||
|
// 36 Added Regs A,X,Y to show character
|
||
|
// 35 Added syntax coloring for DrawBreakpoints()
|
||
|
// 34 Fixed DrawMemory() viewing memory ASCII to map control-chars to a printable glyph
|
||
|
// 33 Fixed 0 addr not working in CmdMemoryCompare()
|
||
|
// 32 Added BG_INFO_INVERSE, FG_INFO_INVERSE for flag hilighting
|
||
|
// 31 Changed FG_INFO_OPCODE color to yellow
|
||
|
// 30 Fixed MDC 0, bug in CmdUnassemble()with garbage address, due to var not init, and symbol lookup failed
|
||
|
// 29 Fixed typos in help summary, A, and D
|
||
|
// 28 Fixed Scrolling with and without g_bDisasmCurBad
|
||
|
// 27 Found bug -- can't scroll up past $5FFF with Tom's Bug Sample .. CmdCursorLineUp() not checking for gbDisamBad;
|
||
|
// 26 Code cleanup: still have some '#define's to convert over to 'const'
|
||
|
// 25 Fixed disasm singularity not showing up in DrawDisassemblyLine()
|
||
|
// 24 Fixed an disasm singularity in DisasmCalcTopFromCurAddress() i.e. F7, G FB53, then Space (to trace) once.
|
||
|
// 23 Fixed bug Watches not being cleared: _ClearViaArgs()
|
||
|
// 22 Code Cleanup: Moved most ExtTextOut() to DebugDrawText()
|
||
|
// 21 Changed End to jump $8000, due to redundant funcationality of Home, and wrap-around.
|
||
|
// 20 Added: DisasmCalc*From*()
|
||
|
// 19 New colors Enum & Array
|
||
|
// 18 implemented RTS. fixed RET to use common stack return address logic.
|
||
|
// 17 fixed console PageUp PageDn not refreshing console
|
||
|
// .2 WINDOW_CONSOLE &
|
||
|
// Implemented commands: MemoryDumpAscii*(): MA1 MA2 ML1 ML2 MH1 MH2
|
||
|
// 16 removed BOOL Cmd*(), replaced with UPDATE_*
|
||
|
// 15 New Console Scrolling
|
||
|
// 14 extended FindParam() to specify [begin,end]
|
||
|
// 13 added split window infastructure, added Window_e
|
||
|
// 12 fixed PARAM aliases
|
||
|
// 11 fixed FindParam() to allow aliases
|
||
|
// 10 fixed SYM1 CLEAR, SYM2 CLEAR not actuall clearing
|
||
|
// 9 fixed BufferOuput() in DebugBegin() clobbering first buffered output line
|
||
|
// .1 since source level debugging is a minor feature
|
||
|
// 8 added command "VERSION *" to show internal debug info
|
||
|
// 7 fixed mem enter not refreshing screen
|
||
|
// 6 added source level debuggig back-end
|
||
|
// 5 fixed "SYM 0" bug
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
const int MAX_BREAKPOINTS = 5;
|
||
|
const int MAX_WATCHES = 5;
|
||
|
const int MAX_ZEROPAGE_POINTERS = 5;
|
||
|
|
||
|
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_BEG_MEM_ADDRESS = 0x0000;
|
||
|
const unsigned int _6502_END_MEM_ADDRESS = 0xFFFF;
|
||
|
|
||
|
|
||
|
// 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 ADDR_INDX // ($%02X,X) -> %s,X
|
||
|
{TEXT("(%04X,X)"), 3 , "(Absolute),X" }, // AM_IAX ADDR_ABSIINDX // ($%04X,X) -> %s,X
|
||
|
{TEXT("(%02X),Y"), 2 , "(Zero Page),Y" }, // AM_NZY ADDR_INDY // ($%02X),Y
|
||
|
{TEXT("(%02X)") , 2 , "(Zero Page)" }, // AM_NZ ADDR_IZPG // ($%02X) -> $%02X
|
||
|
{TEXT("(%04X)") , 3 , "(Absolute)" } // AM_NA ADDR_IABS // (%04X) -> %s
|
||
|
};
|
||
|
|
||
|
|
||
|
// Args ___________________________________________________________________________________________
|
||
|
int g_nArgRaw;
|
||
|
Arg_t g_aArgRaw[ MAX_ARGS ]; // pre-processing
|
||
|
|
||
|
Arg_t g_aArgs [ MAX_ARGS ]; // post-processing
|
||
|
|
||
|
|
||
|
const TCHAR CHAR_LF = 0x0D;
|
||
|
const TCHAR CHAR_CR = 0x0A;
|
||
|
const TCHAR CHAR_SPACE = TEXT(' ');
|
||
|
const TCHAR CHAR_TAB = TEXT('\t');
|
||
|
const TCHAR CHAR_QUOTED= TEXT('"' );
|
||
|
|
||
|
// NOTE: Token_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, TEXT('&') }, // bit-and
|
||
|
// { TOKEN_AT , TYPE_OPERATOR, TEXT('@') }, // force Register? or PointerDeref?
|
||
|
{ TOKEN_BSLASH , TYPE_OPERATOR, TEXT('\\') },
|
||
|
{ TOKEN_CARET , TYPE_OPERATOR, TEXT('^') }, // bit-eor, C/C++: xor, Math: POWER
|
||
|
{ TOKEN_COLON , TYPE_OPERATOR, TEXT(':') },
|
||
|
{ TOKEN_COMMA , TYPE_OPERATOR, TEXT(',') },
|
||
|
{ TOKEN_DOLLAR , TYPE_STRING , TEXT('$') },
|
||
|
{ TOKEN_EQUAL , TYPE_OPERATOR, TEXT('=') },
|
||
|
{ TOKEN_EXCLAMATION , TYPE_OPERATOR, TEXT('!') }, // NOT
|
||
|
{ TOKEN_FSLASH , TYPE_OPERATOR, TEXT('/') }, // div
|
||
|
{ TOKEN_GREATER_THAN, TYPE_OPERATOR, TEXT('>') }, // TODO/FIXME: Parser will break up '>=' (needed for uber breakpoints)
|
||
|
{ TOKEN_HASH , TYPE_OPERATOR, TEXT('#') },
|
||
|
{ TOKEN_LEFT_PAREN , TYPE_OPERATOR, TEXT('(') },
|
||
|
{ TOKEN_LESS_THAN , TYPE_OPERATOR, TEXT('<') },
|
||
|
{ TOKEN_MINUS , TYPE_OPERATOR, TEXT('-') }, // sub
|
||
|
// { TOKEN_TILDE , TYPE_OPERATOR, TEXT('~') }, // C/C++: Not. Used for console.
|
||
|
{ TOKEN_PERCENT , TYPE_OPERATOR, TEXT('%') }, // mod
|
||
|
{ TOKEN_PIPE , TYPE_OPERATOR, TEXT('|') }, // bit-or
|
||
|
{ TOKEN_PLUS , TYPE_OPERATOR, TEXT('+') }, // add
|
||
|
{ TOKEN_QUOTED , TYPE_QUOTED , TEXT('"') },
|
||
|
{ TOKEN_RIGHT_PAREN , TYPE_OPERATOR, TEXT(')') },
|
||
|
{ TOKEN_SEMI , TYPE_STRING , TEXT(';') },
|
||
|
{ TOKEN_SPACE , TYPE_STRING , TEXT(' ') } // space is also a delimiter between tokens/args
|
||
|
// { TOKEN_STAR , TYPE_OPERATOR, TEXT('*') },
|
||
|
// { TOKEN_TAB , TYPE_STRING , TEXT('\t') }
|
||
|
};
|
||
|
|
||
|
// const TokenTable_t g_aTokens2[ ] =
|
||
|
// { // Input
|
||
|
// { TOKEN_GREATER_EQUAL,TYPE_OPERATOR, TEXT(">=\x00") }, // TODO/FIXME: Parser will break up '>=' (needed for uber breakpoints)
|
||
|
// { TOKEN_LESS_EQUAL , TYPE_OPERATOR, TEXT("<=\x00") }, // TODO/FIXME: Parser will break up '<=' (needed for uber breakpoints)
|
||
|
// }
|
||
|
|
||
|
// Breakpoints ____________________________________________________________________________________
|
||
|
int g_nBreakpoints = 0;
|
||
|
Breakpoint_t g_aBreakpoints[ MAX_BREAKPOINTS ];
|
||
|
|
||
|
// NOTE: Breakpoint_Source_t and g_aBreakpointSource must match!
|
||
|
const TCHAR *g_aBreakpointSource[ NUM_BREAKPOINT_SOURCES ] =
|
||
|
{ // Used to be one char, since ArgsParse also uses // TODO/FIXME: Parser use Param[] ?
|
||
|
// Used for both Input & Output!
|
||
|
// Regs
|
||
|
TEXT("A"), // Reg A
|
||
|
TEXT("X"), // Reg X
|
||
|
TEXT("Y"), // Reg Y
|
||
|
// Special
|
||
|
TEXT("PC"), // Program Counter
|
||
|
TEXT("S" ), // Stack Pointer
|
||
|
// Flags -- .8 Moved: Flag names from g_aFlagNames[] to "inlined" g_aBreakpointSource[]
|
||
|
TEXT("P"), // Processor Status
|
||
|
TEXT("C"), // ---- ---1 Carry
|
||
|
TEXT("Z"), // ---- --1- Zero
|
||
|
TEXT("I"), // ---- -1-- Interrupt
|
||
|
TEXT("D"), // ---- 1--- Decimal
|
||
|
TEXT("B"), // ---1 ---- Break
|
||
|
TEXT("R"), // --1- ---- Reserved
|
||
|
TEXT("V"), // -1-- ---- Overflow
|
||
|
TEXT("N"), // 1--- ---- Sign
|
||
|
// Misc
|
||
|
TEXT("OP"), // Opcode/Instruction/Mnemonic
|
||
|
// Memory
|
||
|
TEXT("M") // Main
|
||
|
};
|
||
|
|
||
|
// Note: BreakpointOperator_t, _PARAM_BREAKPOINT_, and g_aBreakpointSymbols must match!
|
||
|
TCHAR *g_aBreakpointSymbols[ NUM_BREAKPOINT_OPERATORS] =
|
||
|
{ // Output: Must be 2 chars!
|
||
|
TEXT("<="), // LESS_EQAUL
|
||
|
TEXT("< "), // LESS_THAN
|
||
|
TEXT("= "), // EQUAL
|
||
|
TEXT("! "), // NOT_EQUAL
|
||
|
TEXT("> "), // GREATER_THAN
|
||
|
TEXT(">="), // GREATER_EQUAL
|
||
|
TEXT("? "), // READ // Q. IO Read use 'I'? A. No, since I=Interrupt
|
||
|
TEXT("@ "), // WRITE // Q. IO Write use 'O'? A. No, since O=Opcode
|
||
|
TEXT("* "), // Read/Write
|
||
|
};
|
||
|
|
||
|
|
||
|
// Commands _______________________________________________________________________________________
|
||
|
|
||
|
#define __COMMANDS_VERIFY_TXT__ "\xDE\xAD\xC0\xDE"
|
||
|
#define __PARAMS_VERIFY_TXT__ "\xDE\xAD\xDA\x1A"
|
||
|
|
||
|
class commands_functor_compare
|
||
|
{
|
||
|
public:
|
||
|
int operator() ( const Command_t & rLHS, const Command_t & rRHS ) const
|
||
|
{
|
||
|
return _tcscmp( rLHS.m_sName, rRHS.m_sName );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
int g_iCommand; // last command (enum) // used for consecuitive commands
|
||
|
|
||
|
vector<int> g_vPotentialCommands; // global, since TAB-completion also needs
|
||
|
vector<Command_t> 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 match! Aliases are listed at the end
|
||
|
Command_t g_aCommands[] =
|
||
|
{
|
||
|
// CPU (Main)
|
||
|
{TEXT("A") , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" },
|
||
|
{TEXT("U") , CmdUnassemble , CMD_UNASSEMBLE , "Disassemble instructions" },
|
||
|
{TEXT("CALC") , CmdCalculator , CMD_CALC , "Display mini calc result" },
|
||
|
{TEXT("GOTO") , CmdGo , CMD_GO , "Run [until PC = address]" },
|
||
|
{TEXT("I") , CmdInput , CMD_INPUT , "Input from IO $C0xx" },
|
||
|
{TEXT("KEY") , CmdFeedKey , CMD_INPUT_KEY , "Feed key into emulator" },
|
||
|
{TEXT("JSR") , CmdJSR , CMD_JSR , "Call sub-routine" },
|
||
|
{TEXT("O") , CmdOutput , CMD_OUTPUT , "Output from io $C0xx" },
|
||
|
{TEXT("NOP") , CmdNOP , CMD_NOP , "Zap the current instruction with a NOP" },
|
||
|
{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)" },
|
||
|
// Breakpoints
|
||
|
{TEXT("BP") , CmdBreakpoint , CMD_BREAKPOINT , "Access breakpoint options" },
|
||
|
{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("BC") , CmdBreakpointClear , CMD_BREAKPOINT_CLEAR , "Clear breakpoint # or *" }, // SoftICE
|
||
|
{TEXT("BD") , CmdBreakpointDisable , CMD_BREAKPOINT_DISABLE , "Disable breakpoint # or *" }, // SoftICE
|
||
|
{TEXT("BPE") , CmdBreakpointEdit , CMD_BREAKPOINT_EDIT , "Edit breakpoint # or *" }, // SoftICE
|
||
|
{TEXT("BE") , CmdBreakpointEnable , CMD_BREAKPOINT_ENABLE , "Enable breakpoint # or *" }, // SoftICE
|
||
|
{TEXT("BL") , CmdBreakpointList , CMD_BREAKPOINT_LIST , "List breakpoints" }, // SoftICE
|
||
|
{TEXT("BPLOAD") , CmdBreakpointLoad , CMD_BREAKPOINT_LOAD , "Loads breakpoints" },
|
||
|
{TEXT("BPSAVE") , CmdBreakpointSave , CMD_BREAKPOINT_SAVE , "Saves breakpoints" },
|
||
|
// Benchmark / Timing
|
||
|
{TEXT("BENCHMARK") , CmdBenchmark , CMD_BENCHMARK , "Benchmark the emulator" },
|
||
|
{TEXT("PROFILE") , CmdProfile , CMD_PROFILE , "List/Save 6502 profiling" },
|
||
|
// Config
|
||
|
{TEXT("COLOR") , CmdConfigColorMono , CMD_CONFIG_COLOR , "Sets/Shows RGB for color scheme" },
|
||
|
{TEXT("CONFIG") , CmdConfig , CMD_CONFIG , "Access config 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("RUN") , CmdConfigRun , CMD_CONFIG_RUN , "Run script file of debugger commands" },
|
||
|
{TEXT("SAVE") , CmdConfigSave , CMD_CONFIG_SAVE , "Save debugger configuration" },
|
||
|
// Cursor
|
||
|
{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("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
|
||
|
// 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("MD") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // alias
|
||
|
{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("E") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE },
|
||
|
{TEXT("EW") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD },
|
||
|
{TEXT("M") , CmdMemoryMove , CMD_MEMORY_MOVE },
|
||
|
{TEXT("S") , CmdMemorySearch , CMD_MEMORY_SEARCH },
|
||
|
{TEXT("SA") , CmdMemorySearchText , CMD_MEMORY_SEARCH_ASCII }, // Search Ascii
|
||
|
{TEXT("SAL") , CmdMemorySearchLowBit, CMD_MEMORY_SEARCH_TXT_LO }, // Search Ascii Low
|
||
|
{TEXT("SAH") , CmdMemorySearchHiBit , CMD_MEMORY_SEARCH_TXT_HI }, // Search "Ascii" High
|
||
|
{TEXT("SH") , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX }, // Search Hex
|
||
|
{TEXT("F") , CmdMemoryFill , CMD_MEMORY_FILL },
|
||
|
// Registers
|
||
|
{TEXT("R") , CmdRegisterSet , CMD_REGISTER_SET }, // TODO: Set/Clear flags
|
||
|
// 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" },
|
||
|
// Stack
|
||
|
{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 },
|
||
|
// Symbols
|
||
|
{TEXT("SYM") , CmdSymbols , CMD_SYMBOLS_LOOKUP , "Lookup symbol or address" },
|
||
|
|
||
|
{TEXT("SYMMAIN") , CmdSymbolsMain , CMD_SYMBOLS_MAIN , "Main symbol table lookup/menu" }, // CLEAR,LOAD,SAVE
|
||
|
{TEXT("SYMUSER") , CmdSymbolsUser , CMD_SYMBOLS_USER , "User symbol table lookup/menu" }, // CLEAR,LOAD,SAVE
|
||
|
{TEXT("SYMSRC" ) , CmdSymbolsSource , CMD_SYMBOLS_SRC , "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 },
|
||
|
{TEXT("SYMLIST") , CmdSymbolsList , CMD_SYMBOLS_LIST }, // '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 },
|
||
|
// Watch
|
||
|
{TEXT("W") , CmdWatchAdd , CMD_WATCH_ADD },
|
||
|
{TEXT("WC") , CmdWatchClear , CMD_WATCH_CLEAR },
|
||
|
{TEXT("WD") , CmdWatchDisable , CMD_WATCH_DISABLE },
|
||
|
{TEXT("WE") , CmdWatchEnable , CMD_WATCH_ENABLE },
|
||
|
{TEXT("WL") , CmdWatchList , CMD_WATCH_LIST },
|
||
|
{TEXT("WLOAD") , CmdWatchLoad , CMD_WATCH_LOAD }, // Cant use as param to W
|
||
|
{TEXT("WSAVE") , CmdWatchSave , CMD_WATCH_SAVE }, // due to symbol look-up
|
||
|
// Window
|
||
|
{TEXT("WIN") , CmdWindow , CMD_WINDOW , "Show specified debugger window" },
|
||
|
{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" },
|
||
|
{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 },
|
||
|
// {TEXT("INFO") , CmdToggleInfoPanel , CMD_WINDOW_TOGGLE },
|
||
|
// {TEXT("WINSOURCE") , CmdWindowShowSource , CMD_WINDOW_SOURCE },
|
||
|
// {TEXT("ZEROPAGE") , CmdWindowShowZeropage, CMD_WINDOW_ZEROPAGE },
|
||
|
// ZeroPage
|
||
|
{TEXT("ZP") , CmdZeroPage , CMD_ZEROPAGE_POINTER },
|
||
|
{TEXT("ZP0") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_0 },
|
||
|
{TEXT("ZP1") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_1 },
|
||
|
{TEXT("ZP2") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_2 },
|
||
|
{TEXT("ZP3") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_3 },
|
||
|
{TEXT("ZP4") , CmdZeroPagePointer , CMD_ZEROPAGE_POINTER_4 },
|
||
|
{TEXT("ZPA") , CmdZeroPageAdd , CMD_ZEROPAGE_POINTER_ADD },
|
||
|
{TEXT("ZPC") , CmdZeroPageClear , CMD_ZEROPAGE_POINTER_CLEAR },
|
||
|
{TEXT("ZPD") , CmdZeroPageDisable , CMD_ZEROPAGE_POINTER_CLEAR },
|
||
|
{TEXT("ZPE") , CmdZeroPageEnable , CMD_ZEROPAGE_POINTER_CLEAR },
|
||
|
{TEXT("ZPL") , CmdZeroPageList , CMD_ZEROPAGE_POINTER_LIST },
|
||
|
{TEXT("ZPLOAD") , CmdZeroPageLoad , CMD_ZEROPAGE_POINTER_LOAD }, // Cant use as param to ZP
|
||
|
{TEXT("ZPSAVE") , CmdZeroPageSave , CMD_ZEROPAGE_POINTER_SAVE }, // 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") , CmdInput , CMD_INPUT },
|
||
|
// 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("EB" ) , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE },
|
||
|
{TEXT("E8" ) , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE },
|
||
|
{TEXT("E16") , CmdMemoryEnterWord , CMD_MEMORY_ENTER_WORD },
|
||
|
{TEXT("MF") , CmdMemoryFill , CMD_MEMORY_FILL },
|
||
|
{TEXT("MM") , CmdMemoryMove , CMD_MEMORY_MOVE },
|
||
|
{TEXT("MS") , CmdMemorySearch , CMD_MEMORY_SEARCH }, // CmdMemorySearch
|
||
|
{TEXT("BW") , CmdConfigColorMono , CMD_CONFIG_MONOCHROME },
|
||
|
{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("SYM1" ) , CmdSymbolsInfo , CMD_SYMBOLS_MAIN },
|
||
|
{TEXT("SYM2" ) , CmdSymbolsInfo , CMD_SYMBOLS_USER },
|
||
|
{TEXT("SYM3" ) , CmdSymbolsInfo , CMD_SYMBOLS_SRC },
|
||
|
{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("MDC") , CmdUnassemble , CMD_UNASSEMBLE }, // MemoryDumpCode // Did anyone actually use this??
|
||
|
{TEXT("MEB") , CmdMemoryEnterByte , CMD_MEMORY_ENTER_BYTE }, // MemoryEnterByte // Did anyone actually use this??
|
||
|
{TEXT("MEMORY") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this??
|
||
|
};
|
||
|
|
||
|
// static const TCHAR 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_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, B8, // BG_DISASM_C FG_DISASM_C
|
||
|
Y8, B8, // BG_DISASM_PC_C FG_DISASM_PC_C
|
||
|
Y4, W8, // BG_DISASM_PC_X FG_DISASM_PC_X
|
||
|
|
||
|
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_COLORS ];
|
||
|
|
||
|
|
||
|
// 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] .
|
||
|
// |
|
||
|
// ConsoleInput ----> | g_aConsoleDisplay[0]
|
||
|
//
|
||
|
const int CONSOLE_HEIGHT = 384; // Lines, was 128, but need ~ 256+16 for PROFILE LIST
|
||
|
const int CONSOLE_WIDTH = 80;
|
||
|
|
||
|
// Buffer
|
||
|
bool g_bConsoleBufferPaused = false; // buffered output is waiting for user to continue
|
||
|
int g_nConsoleBuffer = 0;
|
||
|
TCHAR g_aConsoleBuffer[ CONSOLE_HEIGHT ][ CONSOLE_WIDTH ]; // TODO: stl::vector< line_t >
|
||
|
|
||
|
// Display
|
||
|
TCHAR g_aConsolePrompt[] = TEXT(">!"); // input, assembler
|
||
|
TCHAR g_sConsolePrompt[] = TEXT(">"); // No, NOT Integer Basic! The nostalgic '*' "Monitor" doesn't look as good, IMHO. :-(
|
||
|
bool g_bConsoleFullWidth = false;
|
||
|
|
||
|
int g_iConsoleDisplayStart = 0; // to allow scrolling
|
||
|
int g_nConsoleDisplayTotal = 0; // number of lines added to console
|
||
|
int g_nConsoleDisplayHeight = 0;
|
||
|
int g_nConsoleDisplayWidth = 0;
|
||
|
TCHAR g_aConsoleDisplay[ CONSOLE_HEIGHT ][ CONSOLE_WIDTH ];
|
||
|
|
||
|
// Input History
|
||
|
int g_nHistoryLinesStart = 0;
|
||
|
int g_nHistoryLinesTotal = 0; // number of commands entered
|
||
|
TCHAR g_aHistoryLines[ CONSOLE_HEIGHT ][ CONSOLE_WIDTH ] = {TEXT("")};
|
||
|
|
||
|
// Input Line
|
||
|
// Raw input Line (has prompt)
|
||
|
const int CONSOLE_FIRST_LINE = 1; // where ConsoleDisplay is pushed up from
|
||
|
TCHAR * const g_aConsoleInput = g_aConsoleDisplay[0];
|
||
|
// Cooked input line (no prompt)
|
||
|
int g_nConsoleInputChars = 0;
|
||
|
TCHAR * g_pConsoleInput = 0; // points to past prompt
|
||
|
bool g_bConsoleInputQuoted = false; // Allows lower-case to be entered
|
||
|
bool g_bConsoleInputSkip = false;
|
||
|
|
||
|
|
||
|
// Cursor _________________________________________________________________________________________
|
||
|
|
||
|
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;
|
||
|
|
||
|
// Disassembly
|
||
|
bool g_bConfigDisasmOpcodeSpaces = true; // TODO: CONFIG DISASM SPACE [0|1]
|
||
|
bool g_bConfigDisasmAddressColon = true; // TODO: CONFIG DISASM COLON [0|1]
|
||
|
bool g_bConfigDisasmFancyBranch = true; // TODO: CONFIG DISASM BRANCH [0|1]
|
||
|
// TCHAR g_aConfigDisasmAddressColon[] = TEXT(" :");
|
||
|
|
||
|
/*
|
||
|
* Wingdings
|
||
|
\xE1 Up Arrow
|
||
|
\xE2 Down Arrow
|
||
|
* Webdings // M$ Font
|
||
|
\x35 Up Arrow
|
||
|
\x33 Left Arrow
|
||
|
\x36 Down Arrow
|
||
|
* Symols
|
||
|
\xAD Up Arrow
|
||
|
\xAF Down Arrow
|
||
|
*/
|
||
|
TCHAR g_sConfigBranchIndicatorUp [] = TEXT("^\x35"); // was \x18 ?? // string
|
||
|
TCHAR g_sConfigBranchIndicatorEqual[] = TEXT("=\x33"); // was \x18 ?? // string
|
||
|
TCHAR g_sConfigBranchIndicatorDown [] = TEXT("v\x36"); // was \x19 ?? // string
|
||
|
|
||
|
// Drawing
|
||
|
// Width
|
||
|
const int DISPLAY_WIDTH = 560;
|
||
|
#define SCREENSPLIT1 356 // Horizontal Column (pixels?) of Stack & Regs
|
||
|
// #define SCREENSPLIT2 456 // Horizontal Column (pixels?) of BPs, Watches & Mem
|
||
|
const int SCREENSPLIT2 = 456-7; // moved left one "char" to show PC in breakpoint:
|
||
|
|
||
|
const int DISPLAY_BP_COLUMN = SCREENSPLIT2;
|
||
|
const int DISPLAY_MINI_CONSOLE = SCREENSPLIT1 - 6; // - 1 chars
|
||
|
const int DISPLAY_DISASM_RIGHT = SCREENSPLIT1 - 6; // - 1 char
|
||
|
const int DISPLAY_FLAG_COLUMN = SCREENSPLIT1 + 63;
|
||
|
const int DISPLAY_MINIMEM_COLUMN = SCREENSPLIT2 + 7;
|
||
|
const int DISPLAY_REGS_COLUMN = SCREENSPLIT1;
|
||
|
const int DISPLAY_STACK_COLUMN = SCREENSPLIT1;
|
||
|
const int DISPLAY_TARGETS_COLUMN = SCREENSPLIT1;
|
||
|
const int DISPLAY_WATCHES_COLUMN = SCREENSPLIT2;
|
||
|
const int DISPLAY_ZEROPAGE_COLUMN= SCREENSPLIT1;
|
||
|
|
||
|
// 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;
|
||
|
const int DISPLAY_HEIGHT = 384; // 368; // DISPLAY_LINES * g_nFontHeight;
|
||
|
|
||
|
const int WINDOW_DATA_BYTES_PER_LINE = 8;
|
||
|
// Font
|
||
|
FontConfig_t g_aFontConfig[ NUM_FONTS ];
|
||
|
|
||
|
TCHAR g_sFontNameDefault[ MAX_FONT_NAME ] = TEXT("Courier New");
|
||
|
// TCHAR g_sFontNameCustom [ MAX_FONT_NAME ] = TEXT("Courier New"); // Arial
|
||
|
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");
|
||
|
int g_nFontHeight = 15; // 13 -> 12 Lucida Console is readable
|
||
|
int g_iFontSpacing = FONT_SPACING_CLEAN;
|
||
|
// int g_nFontWidthAvg = 0;
|
||
|
// int g_nFontWidthMax = 0;
|
||
|
// HFONT g_hFontDebugger = (HFONT)0;
|
||
|
// HFONT g_hFontDisasm = (HFONT)0;
|
||
|
HFONT g_hFontWebDings = (HFONT)0;
|
||
|
|
||
|
|
||
|
const int MIN_DISPLAY_CONSOLE_LINES = 4; // doesn't include ConsoleInput
|
||
|
|
||
|
int g_nTotalLines = 0; // DISPLAY_HEIGHT / g_nFontHeight;
|
||
|
int MAX_DISPLAY_DISASM_LINES = 0; // g_nTotalLines - MIN_DISPLAY_CONSOLE_LINES; // 19;
|
||
|
|
||
|
int MAX_DISPLAY_STACK_LINES = 8;
|
||
|
int MAX_DISPLAY_CONSOLE_LINES = 0; // MAX_DISPLAY_DISASM_LINES + MIN_DISPLAY_CONSOLE_LINES; // 23
|
||
|
|
||
|
|
||
|
// Instructions / Opcodes _________________________________________________________________________
|
||
|
|
||
|
|
||
|
// @reference: http://www.6502.org/tutorials/compare_instructions.html
|
||
|
// 10 signed: BPL BGE
|
||
|
// B0 unsigned: BCS BGE
|
||
|
|
||
|
int g_bOpcodesHashed = false;
|
||
|
int g_aOpcodesHash[ NUM_OPCODES ]; // for faster mnemonic lookup, for the assembler
|
||
|
|
||
|
#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_2 , 0 }, {"NOP", AM_1 , 0 }, // 00 .. 03
|
||
|
{"TSB", AM_Z , _W}, {"ORA", AM_Z , R_}, {"ASL", AM_Z , RW}, {"NOP", AM_1 , 0 }, // 04 .. 07
|
||
|
{"PHP", 0 , SW}, {"ORA", AM_M , im}, {"ASL", 0 , 0}, {"NOP", AM_1 , 0 }, // 08 .. 0B
|
||
|
{"TSB", AM_A , _W}, {"ORA", AM_A , R_}, {"ASL", AM_A , RW}, {"NOP", AM_3 , 0 }, // 0C .. 0F
|
||
|
{"BPL", AM_R , 0}, {"ORA", AM_NZY, R_}, {"ORA", AM_NZ , R_}, {"NOP", AM_1 , 0 }, // 10 .. 13
|
||
|
{"TRB", AM_Z , _W}, {"ORA", AM_ZX , R_}, {"ASL", AM_ZX , RW}, {"NOP", AM_1 , 0 }, // 14 .. 17
|
||
|
{"CLC", 0 , 0}, {"ORA", AM_AY , R_}, {"INA", 0 , 0}, {"NOP", AM_1 , 0 }, // 18 .. 1B
|
||
|
{"TRB", AM_A , _W}, {"ORA", AM_AX , R_}, {"ASL", AM_AX , RW}, {"NOP", AM_1 , 0 }, // 1C .. 1F
|
||
|
|
||
|
{"JSR", AM_A , SW}, {"AND", AM_IZX, R_}, {"NOP", AM_2 , 0}, {"NOP", AM_1 , 0 }, // 20 .. 23
|
||
|
{"BIT", AM_Z , R_}, {"AND", AM_Z , R_}, {"ROL", AM_Z , RW}, {"NOP", AM_1 , 0 }, // 24 .. 27
|
||
|
{"PLP", 0 , SR}, {"AND", AM_M , im}, {"ROL", 0 , 0}, {"NOP", AM_1 , 0 }, // 28 .. 2B
|
||
|
{"BIT", AM_A , R_}, {"AND", AM_A , R_}, {"ROL", AM_A , RW}, {"NOP", AM_3 , 0 }, // 2C .. 2F
|
||
|
{"BMI", AM_R , 0}, {"AND", AM_NZY, R_}, {"AND", AM_NZ , R_}, {"NOP", AM_1 , 0 }, // 30 .. 33
|
||
|
{"BIT", AM_ZX , R_}, {"AND", AM_ZX , R_}, {"ROL", AM_ZX , RW}, {"NOP", AM_1 , 0 }, // 34 .. 37
|
||
|
{"SEC", 0 , 0}, {"AND", AM_AY , R_}, {"DEA", 0 , 0}, {"NOP", AM_1 , 0 }, // 38 .. 3B
|
||
|
{"BIT", AM_AX , R_}, {"AND", AM_AX , R_}, {"ROL", AM_AX , RW}, {"NOP", AM_1 , 0 }, // 3C .. 3F
|
||
|
|
||
|
{"RTI", 0 , 0}, {"EOR", AM_IZX, R_}, {"NOP", AM_2 , 0}, {"NOP", AM_1 , 0 }, // 40 .. 43
|
||
|
{"NOP", AM_2 , 0}, {"EOR", AM_Z , R_}, {"LSR", AM_Z , _W}, {"NOP", AM_1 , 0 }, // 44 .. 47
|
||
|
{"PHA", 0 , SW}, {"EOR", AM_M , im}, {"LSR", 0 , 0}, {"NOP", AM_1 , 0 }, // 48 .. 4B
|
||
|
{"JMP", AM_A , 0}, {"EOR", AM_A , R_}, {"LSR", AM_A , _W}, {"NOP", AM_1 , 0 }, // 4C .. 4F
|
||
|
{"BVC", AM_R , 0}, {"EOR", AM_NZY, R_}, {"EOR", AM_NZ , R_}, {"NOP", AM_1 , 0 }, // 50 .. 53
|
||
|
{"NOP", AM_2 , 0}, {"EOR", AM_ZX , R_}, {"LSR", AM_ZX , _W}, {"NOP", AM_1 , 0 }, // 54 .. 57
|
||
|
{"CLI", 0 , 0}, {"EOR", AM_AY , R_}, {"PHY", 0 , SW}, {"NOP", AM_1 , 0 }, // 58 .. 5B
|
||
|
{"NOP", AM_3 , 0}, {"EOR", AM_AX , R_}, {"LSR", AM_AX , RW}, {"NOP", AM_1 , 0 }, // 5C .. 5F
|
||
|
|
||
|
{"RTS", 0 , SR}, {"ADC", AM_IZX, R_}, {"NOP", AM_2 , 0}, {"NOP", AM_1 , 0 }, // 60 .. 63
|
||
|
{"STZ", AM_Z , _W}, {"ADC", AM_Z , R_}, {"ROR", AM_Z , RW}, {"NOP", AM_1 , 0 }, // 64 .. 67
|
||
|
{"PLA", 0 , SR}, {"ADC", AM_M , im}, {"ROR", 0 , 0}, {"NOP", AM_1 , 0 }, // 68 .. 6B
|
||
|
{"JMP", AM_NA , 0}, {"ADC", AM_A , R_}, {"ROR", AM_A , RW}, {"NOP", AM_1 , 0 }, // 6C .. 6F
|
||
|
{"BVS", AM_R , 0}, {"ADC", AM_NZY, R_}, {"ADC", AM_NZ , R_}, {"NOP", AM_1 , 0 }, // 70 .. 73
|
||
|
{"STZ", AM_ZX , _W}, {"ADC", AM_ZX , R_}, {"ROR", AM_ZX , RW}, {"NOP", AM_1 , 0 }, // 74 .. 77
|
||
|
{"SEI", 0 , 0}, {"ADC", AM_AY , R_}, {"PLY", 0 , SR}, {"NOP", AM_1 , 0 }, // 78 .. 7B
|
||
|
{"JMP", AM_IAX, 0}, {"ADC", AM_AX , R_}, {"ROR", AM_AX , RW}, {"NOP", AM_1 , 0 }, // 7C .. 7F
|
||
|
|
||
|
{"BRA", AM_R , 0}, {"STA", AM_IZX, _W}, {"NOP", AM_2 , 0}, {"NOP", AM_1 , 0 }, // 80 .. 83
|
||
|
{"STY", AM_Z , _W}, {"STA", AM_Z , _W}, {"STX", AM_Z , _W}, {"NOP", AM_1 , 0 }, // 84 .. 87
|
||
|
{"DEY", 0 , 0}, {"BIT", AM_M , im}, {"TXA", 0 , 0}, {"NOP", AM_1 , 0 }, // 88 .. 8B
|
||
|
{"STY", AM_A , _W}, {"STA", AM_A , _W}, {"STX", AM_A , _W}, {"NOP", AM_1 , 0 }, // 8C .. 8F
|
||
|
{"BCC", AM_R , 0}, {"STA", AM_NZY, _W}, {"STA", AM_NZ , _W}, {"NOP", AM_1 , 0 }, // 90 .. 93
|
||
|
{"STY", AM_ZX , _W}, {"STA", AM_ZX , _W}, {"STX", AM_ZY , _W}, {"NOP", AM_1 , 0 }, // 94 .. 97
|
||
|
{"TYA", 0 , 0}, {"STA", AM_AY , _W}, {"TXS", 0 , 0}, {"NOP", AM_1 , 0 }, // 98 .. 9B
|
||
|
{"STZ", AM_A , _W}, {"STA", AM_AX , _W}, {"STZ", AM_AX , _W}, {"NOP", AM_1 , 0 }, // 9C .. 9F
|
||
|
|
||
|
{"LDY", AM_M , im}, {"LDA", AM_IZX, R_}, {"LDX", AM_M , im}, {"NOP", AM_1 , 0 }, // A0 .. A3
|
||
|
{"LDY", AM_Z , R_}, {"LDA", AM_Z , R_}, {"LDX", AM_Z , R_}, {"NOP", AM_1 , 0 }, // A4 .. A7
|
||
|
{"TAY", 0 , 0}, {"LDA", AM_M , im}, {"TAX", 0 , 0 }, {"NOP", AM_1 , 0 }, // A8 .. AB
|
||
|
{"LDY", AM_A , R_}, {"LDA", AM_A , R_}, {"LDX", AM_A , R_}, {"NOP", AM_1 , 0 }, // AC .. AF
|
||
|
{"BCS", AM_R , 0}, {"LDA", AM_NZY, R_}, {"LDA", AM_NZ , R_}, {"NOP", AM_1 , 0 }, // B0 .. B3
|
||
|
{"LDY", AM_ZX , R_}, {"LDA", AM_ZX , R_}, {"LDX", AM_ZY , R_}, {"NOP", AM_1 , 0 }, // B4 .. B7
|
||
|
{"CLV", 0 , 0}, {"LDA", AM_AY , R_}, {"TSX", 0 , 0 }, {"NOP", AM_1 , 0 }, // B8 .. BB
|
||
|
{"LDY", AM_AX , R_}, {"LDA", AM_AX , R_}, {"LDX", AM_AY , R_}, {"NOP", AM_1 , 0 }, // BC .. BF
|
||
|
|
||
|
{"CPY", AM_M , im}, {"CMP", AM_IZX, R_}, {"NOP", AM_2 , 0}, {"NOP", AM_1 , 0 }, // C0 .. C3
|
||
|
{"CPY", AM_Z , R_}, {"CMP", AM_Z , R_}, {"DEC", AM_Z , RW}, {"NOP", AM_1 , 0 }, // C4 .. C7
|
||
|
{"INY", 0 , 0}, {"CMP", AM_M , im}, {"DEX", 0 , 0}, {"NOP", AM_1 , 0 }, // C8 .. CB
|
||
|
{"CPY", AM_A , R_}, {"CMP", AM_A , R_}, {"DEC", AM_A , RW}, {"NOP", AM_1 , 0 }, // CC .. CF
|
||
|
{"BNE", AM_R , 0}, {"CMP", AM_NZY, R_}, {"CMP", AM_NZ , 0}, {"NOP", AM_1 , 0 }, // D0 .. D3
|
||
|
{"NOP", AM_2 , 0}, {"CMP", AM_ZX , R_}, {"DEC", AM_ZX , RW}, {"NOP", AM_1 , 0 }, // D4 .. D7
|
||
|
{"CLD", 0 , 0}, {"CMP", AM_AY , R_}, {"PHX", 0 , 0}, {"NOP", AM_1 , 0 }, // D8 .. DB
|
||
|
{"NOP", AM_3 , 0}, {"CMP", AM_AX , R_}, {"DEC", AM_AX , RW}, {"NOP", AM_1 , 0 }, // DC .. DF
|
||
|
|
||
|
{"CPX", AM_M , im}, {"SBC", AM_IZX, R_}, {"NOP", AM_2 , 0}, {"NOP", AM_1 , 0 }, // E0 .. E3
|
||
|
{"CPX", AM_Z , R_}, {"SBC", AM_Z , R_}, {"INC", AM_Z , RW}, {"NOP", AM_1 , 0 }, // E4 .. E7
|
||
|
{"INX", 0 , 0}, {"SBC", AM_M , R_}, {"NOP", 0 , 0}, {"NOP", AM_1 , 0 }, // E8 .. EB
|
||
|
{"CPX", AM_A , R_}, {"SBC", AM_A , R_}, {"INC", AM_A , RW}, {"NOP", AM_1 , 0 }, // EC .. EF
|
||
|
{"BEQ", AM_R , 0}, {"SBC", AM_NZY, R_}, {"SBC", AM_NZ , 0}, {"NOP", AM_1 , 0 }, // F0 .. F3
|
||
|
{"NOP", AM_2 , 0}, {"SBC", AM_ZX , R_}, {"INC", AM_ZX , RW}, {"NOP", AM_1 , 0 }, // F4 .. F7
|
||
|
{"SED", 0 , 0}, {"SBC", AM_AY , R_}, {"PLX", 0 , 0}, {"NOP", AM_1 , 0 }, // F8 .. FB
|
||
|
{"NOP", AM_3 , 0}, {"SBC", AM_AX , R_}, {"INC", AM_AX , RW}, {"NOP", AM_1 , 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:
|
||
|
http://www.strotmann.de/twiki/bin/view/APG/AsmUnusedOpcodes
|
||
|
|
||
|
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
|
||
|
|
||
|
*/
|
||
|
// x3 x7 xB xF are never used
|
||
|
{TEXT("BRK"), 0 , 0 }, // 00h
|
||
|
{TEXT("ORA"), ADDR_INDX , R_ }, // 01h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // 02h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 03h
|
||
|
{TEXT("TSB"), ADDR_ZP , _W }, // 04h // 65C02
|
||
|
{TEXT("ORA"), ADDR_ZP , R_ }, // 05h
|
||
|
{TEXT("ASL"), ADDR_ZP , _W }, // 06h // MEM_R ?
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 07h
|
||
|
{TEXT("PHP"), 0 , SW }, // 08h
|
||
|
{TEXT("ORA"), ADDR_IMM , im }, // 09h
|
||
|
{TEXT("ASL"), 0 , 0 }, // 0Ah // MEM_IMPLICIT
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 0Bh
|
||
|
{TEXT("TSB"), ADDR_ABS , _W }, // 0Ch // 65C02
|
||
|
{TEXT("ORA"), ADDR_ABS , R_ }, // 0Dh
|
||
|
{TEXT("ASL"), ADDR_ABS , _W }, // 0Eh // MEM_R ?
|
||
|
{TEXT("NOP"), ADDR_INVALID3 , 0 }, // 0Fh
|
||
|
{TEXT("BPL"), ADDR_REL , 0 }, // 10h // signed: BGE @reference: http://www.6502.org/tutorials/compare_instructions.html
|
||
|
{TEXT("ORA"), ADDR_INDY , R_ }, // 11h
|
||
|
{TEXT("ORA"), ADDR_IZPG , R_ }, // 12h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 13h
|
||
|
{TEXT("TRB"), ADDR_ZP , _W }, // 14h
|
||
|
{TEXT("ORA"), ADDR_ZP_X , R_ }, // 15h
|
||
|
{TEXT("ASL"), ADDR_ZP_X , _W }, // 16h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 17h
|
||
|
{TEXT("CLC"), 0 , 0 }, // 18h
|
||
|
{TEXT("ORA"), ADDR_ABSY , R_ }, // 19h
|
||
|
{TEXT("INA"), 0 , 0 }, // 1Ah INC A
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 1Bh
|
||
|
{TEXT("TRB"), ADDR_ABS , _W }, // 1Ch
|
||
|
{TEXT("ORA"), ADDR_ABSX , R_ }, // 1Dh
|
||
|
{TEXT("ASL"), ADDR_ABSX }, // 1Eh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 1Fh
|
||
|
{TEXT("JSR"), ADDR_ABS }, // 20h
|
||
|
{TEXT("AND"), ADDR_INDX }, // 21h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // 22h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 23h
|
||
|
{TEXT("BIT"), ADDR_ZP }, // 24h
|
||
|
{TEXT("AND"), ADDR_ZP }, // 25h
|
||
|
{TEXT("ROL"), ADDR_ZP }, // 26h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 27h
|
||
|
{TEXT("PLP"), 0 }, // 28h
|
||
|
{TEXT("AND"), ADDR_IMM }, // 29h
|
||
|
{TEXT("ROL"), 0 }, // 2Ah
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 2Bh
|
||
|
{TEXT("BIT"), ADDR_ABS }, // 2Ch
|
||
|
{TEXT("AND"), ADDR_ABS }, // 2Dh
|
||
|
{TEXT("ROL"), ADDR_ABS }, // 2Eh
|
||
|
{TEXT("NOP"), ADDR_INVALID3 , 0 }, // 2Fh
|
||
|
{TEXT("BMI"), ADDR_REL }, // 30h
|
||
|
{TEXT("AND"), ADDR_INDY }, // 31h
|
||
|
{TEXT("AND"), ADDR_IZPG }, // 32h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 33h
|
||
|
{TEXT("BIT"), ADDR_ZP_X }, // 34h
|
||
|
{TEXT("AND"), ADDR_ZP_X }, // 35h
|
||
|
{TEXT("ROL"), ADDR_ZP_X }, // 36h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 37h
|
||
|
{TEXT("SEC"), 0 }, // 38h
|
||
|
{TEXT("AND"), ADDR_ABSY }, // 39h
|
||
|
{TEXT("DEA"), 0 }, // 3Ah
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 3Bh
|
||
|
{TEXT("BIT"), ADDR_ABSX }, // 3Ch
|
||
|
{TEXT("AND"), ADDR_ABSX }, // 3Dh
|
||
|
{TEXT("ROL"), ADDR_ABSX }, // 3Eh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 3Fh
|
||
|
{TEXT("RTI"), 0 , 0 }, // 40h
|
||
|
{TEXT("EOR"), ADDR_INDX }, // 41h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // 42h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 43h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // 44h
|
||
|
{TEXT("EOR"), ADDR_ZP }, // 45h
|
||
|
{TEXT("LSR"), ADDR_ZP , _W }, // 46h // MEM_R ?
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 47h
|
||
|
{TEXT("PHA"), 0 }, // 48h // MEM_WRITE_IMPLIED | MEM_STACK
|
||
|
{TEXT("EOR"), ADDR_IMM }, // 49h
|
||
|
{TEXT("LSR"), 0 }, // 4Ah
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 4Bh
|
||
|
{TEXT("JMP"), ADDR_ABS }, // 4Ch
|
||
|
{TEXT("EOR"), ADDR_ABS }, // 4Dh
|
||
|
{TEXT("LSR"), ADDR_ABS , _W }, // 4Eh // MEM_R ?
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 4Fh
|
||
|
{TEXT("BVC"), ADDR_REL }, // 50h
|
||
|
{TEXT("EOR"), ADDR_INDY }, // 51h
|
||
|
{TEXT("EOR"), ADDR_IZPG }, // 52h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 53h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // 54h
|
||
|
{TEXT("EOR"), ADDR_ZP_X }, // 55h
|
||
|
{TEXT("LSR"), ADDR_ZP_X , _W }, // 56h // MEM_R ?
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 57h
|
||
|
{TEXT("CLI"), 0 }, // 58h
|
||
|
{TEXT("EOR"), ADDR_ABSY }, // 59h
|
||
|
{TEXT("PHY"), 0 }, // 5Ah
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 5Bh
|
||
|
{TEXT("NOP"), ADDR_INVALID3 , 0 }, // 5Ch
|
||
|
{TEXT("EOR"), ADDR_ABSX }, // 5Dh
|
||
|
{TEXT("LSR"), ADDR_ABSX }, // 5Eh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 5Fh
|
||
|
{TEXT("RTS"), 0 , SR }, // 60h
|
||
|
{TEXT("ADC"), ADDR_INDX }, // 61h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // 62h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 63h
|
||
|
{TEXT("STZ"), ADDR_ZP }, // 64h
|
||
|
{TEXT("ADC"), ADDR_ZP }, // 65h
|
||
|
{TEXT("ROR"), ADDR_ZP }, // 66h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 67h
|
||
|
{TEXT("PLA"), 0 , SW }, // 68h
|
||
|
{TEXT("ADC"), ADDR_IMM }, // 69h
|
||
|
{TEXT("ROR"), 0 }, // 6Ah
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 6Bh
|
||
|
{TEXT("JMP"), ADDR_IABS }, // 6Ch
|
||
|
{TEXT("ADC"), ADDR_ABS }, // 6Dh
|
||
|
{TEXT("ROR"), ADDR_ABS }, // 6Eh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 6Fh
|
||
|
{TEXT("BVS"), ADDR_REL }, // 70h
|
||
|
{TEXT("ADC"), ADDR_INDY }, // 71h
|
||
|
{TEXT("ADC"), ADDR_IZPG }, // 72h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 73h
|
||
|
{TEXT("STZ"), ADDR_ZP_X }, // 74h
|
||
|
{TEXT("ADC"), ADDR_ZP_X }, // 75h
|
||
|
{TEXT("ROR"), ADDR_ZP_X }, // 76h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 77h
|
||
|
{TEXT("SEI"), 0 }, // 78h
|
||
|
{TEXT("ADC"), ADDR_ABSY }, // 79h
|
||
|
{TEXT("PLY"), 0 , SR }, // 7Ah
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 7Bh
|
||
|
{TEXT("JMP"), ADDR_ABSIINDX }, // 7Ch
|
||
|
{TEXT("ADC"), ADDR_ABSX }, // 7Dh
|
||
|
{TEXT("ROR"), ADDR_ABSX }, // 7Eh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 7Fh
|
||
|
{TEXT("BRA"), ADDR_REL }, // 80h
|
||
|
{TEXT("STA"), ADDR_INDX , _W }, // 81h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // 82h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 83h
|
||
|
{TEXT("STY"), ADDR_ZP , _W }, // 84h
|
||
|
{TEXT("STA"), ADDR_ZP , _W }, // 85h
|
||
|
{TEXT("STX"), ADDR_ZP , _W }, // 86h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 87h
|
||
|
{TEXT("DEY"), 0 , 0 }, // 88h // Explicit
|
||
|
{TEXT("BIT"), ADDR_IMM }, // 89h
|
||
|
{TEXT("TXA"), 0 , 0 }, // 8Ah // Explicit
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 8Bh
|
||
|
{TEXT("STY"), ADDR_ABS , _W }, // 8Ch
|
||
|
{TEXT("STA"), ADDR_ABS , _W }, // 8Dh
|
||
|
{TEXT("STX"), ADDR_ABS , _W }, // 8Eh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 8Fh
|
||
|
{TEXT("BCC"), ADDR_REL , 0 }, // 90h // MEM_IMMEDIATE
|
||
|
{TEXT("STA"), ADDR_INDY , _W }, // 91h
|
||
|
{TEXT("STA"), ADDR_IZPG , _W }, // 92h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 93h
|
||
|
{TEXT("STY"), ADDR_ZP_X , _W }, // 94h
|
||
|
{TEXT("STA"), ADDR_ZP_X , _W }, // 95h
|
||
|
{TEXT("STX"), ADDR_ZP_Y , _W }, // 96h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 97h
|
||
|
{TEXT("TYA"), 0 , 0 }, // 98h // Explicit
|
||
|
{TEXT("STA"), ADDR_ABSY , _W }, // 99h
|
||
|
{TEXT("TXS"), 0 , 0 }, // 9Ah // EXplicit
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 9Bh
|
||
|
{TEXT("STZ"), ADDR_ABS , _W }, // 9Ch
|
||
|
{TEXT("STA"), ADDR_ABSX , _W }, // 9Dh
|
||
|
{TEXT("STZ"), ADDR_ABSX , _W }, // 9Eh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // 9Fh
|
||
|
{TEXT("LDY"), ADDR_IMM , 0 }, // A0h // MEM_IMMEDIATE
|
||
|
{TEXT("LDA"), ADDR_INDX , R_ }, // A1h
|
||
|
{TEXT("LDX"), ADDR_IMM , 0 }, // A2h // MEM_IMMEDIATE
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // A3h
|
||
|
{TEXT("LDY"), ADDR_ZP , R_ }, // A4h
|
||
|
{TEXT("LDA"), ADDR_ZP , R_ }, // A5h
|
||
|
{TEXT("LDX"), ADDR_ZP , R_ }, // A6h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // A7h
|
||
|
{TEXT("TAY"), 0 , 0 }, // A8h // Explicit
|
||
|
{TEXT("LDA"), ADDR_IMM , 0 }, // A9h // MEM_IMMEDIATE
|
||
|
{TEXT("TAX"), 0 , 0 }, // AAh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // ABh
|
||
|
{TEXT("LDY"), ADDR_ABS , R_ }, // ACh
|
||
|
{TEXT("LDA"), ADDR_ABS , R_ }, // ADh
|
||
|
{TEXT("LDX"), ADDR_ABS , R_ }, // AEh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // AFh
|
||
|
{TEXT("BCS"), ADDR_REL , 0 }, // B0h // MEM_IMMEDIATE // unsigned: BGE
|
||
|
{TEXT("LDA"), ADDR_INDY , R_ }, // B1h
|
||
|
{TEXT("LDA"), ADDR_IZPG , R_ }, // B2h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // B3h
|
||
|
{TEXT("LDY"), ADDR_ZP_X , R_ }, // B4h
|
||
|
{TEXT("LDA"), ADDR_ZP_X , R_ }, // B5h
|
||
|
{TEXT("LDX"), ADDR_ZP_Y , R_ }, // B6h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // B7h
|
||
|
{TEXT("CLV"), 0 , 0 }, // B8h // Explicit
|
||
|
{TEXT("LDA"), ADDR_ABSY , R_ }, // B9h
|
||
|
{TEXT("TSX"), 0 , 0 }, // BAh // Explicit
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // BBh
|
||
|
{TEXT("LDY"), ADDR_ABSX , R_ }, // BCh
|
||
|
{TEXT("LDA"), ADDR_ABSX , R_ }, // BDh
|
||
|
{TEXT("LDX"), ADDR_ABSY , R_ }, // BEh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // BFh
|
||
|
{TEXT("CPY"), ADDR_IMM }, // C0h
|
||
|
{TEXT("CMP"), ADDR_INDX }, // C1h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // C2h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // C3h
|
||
|
{TEXT("CPY"), ADDR_ZP }, // C4h
|
||
|
{TEXT("CMP"), ADDR_ZP }, // C5h
|
||
|
{TEXT("DEC"), ADDR_ZP }, // C6h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // C7h
|
||
|
{TEXT("INY"), 0 }, // C8h
|
||
|
{TEXT("CMP"), ADDR_IMM }, // C9h
|
||
|
{TEXT("DEX"), 0 }, // CAh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // CBh
|
||
|
{TEXT("CPY"), ADDR_ABS }, // CCh
|
||
|
{TEXT("CMP"), ADDR_ABS }, // CDh
|
||
|
{TEXT("DEC"), ADDR_ABS }, // CEh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 }, // CFh
|
||
|
{TEXT("BNE"), ADDR_REL }, // D0h
|
||
|
{TEXT("CMP"), ADDR_INDY }, // D1h
|
||
|
{TEXT("CMP"), ADDR_IZPG }, // D2h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // D3h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // D4h
|
||
|
{TEXT("CMP"), ADDR_ZP_X }, // D5h
|
||
|
{TEXT("DEC"), ADDR_ZP_X }, // D6h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // D7h
|
||
|
{TEXT("CLD"), 0 }, // D8h
|
||
|
{TEXT("CMP"), ADDR_ABSY }, // D9h
|
||
|
{TEXT("PHX"), 0 }, // DAh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // DBh
|
||
|
{TEXT("NOP"), ADDR_INVALID3 , 0 }, // DCh
|
||
|
{TEXT("CMP"), ADDR_ABSX }, // DDh
|
||
|
{TEXT("DEC"), ADDR_ABSX }, // DEh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // DFh
|
||
|
{TEXT("CPX"), ADDR_IMM }, // E0h
|
||
|
{TEXT("SBC"), ADDR_INDX }, // E1h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // E2h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // E3h
|
||
|
{TEXT("CPX"), ADDR_ZP }, // E4h
|
||
|
{TEXT("SBC"), ADDR_ZP }, // E5h
|
||
|
{TEXT("INC"), ADDR_ZP }, // E6h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // E7h
|
||
|
{TEXT("INX"), 0 }, // E8h
|
||
|
{TEXT("SBC"), ADDR_IMM }, // E9h
|
||
|
{TEXT("NOP"), 0 , 0 }, // EAh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 }, // EBh
|
||
|
{TEXT("CPX"), ADDR_ABS }, // ECh
|
||
|
{TEXT("SBC"), ADDR_ABS }, // EDh
|
||
|
{TEXT("INC"), ADDR_ABS }, // EEh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // EFh
|
||
|
{TEXT("BEQ"), ADDR_REL }, // F0h
|
||
|
{TEXT("SBC"), ADDR_INDY }, // F1h
|
||
|
{TEXT("SBC"), ADDR_IZPG }, // F2h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // F3h
|
||
|
{TEXT("NOP"), ADDR_INVALID2 , 0 }, // F4h
|
||
|
{TEXT("SBC"), ADDR_ZP_X }, // F5h
|
||
|
{TEXT("INC"), ADDR_ZP_X }, // F6h
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // F7h
|
||
|
{TEXT("SED"), 0 }, // F8h
|
||
|
{TEXT("SBC"), ADDR_ABSY }, // F9h
|
||
|
{TEXT("PLX"), 0 }, // FAh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 }, // FBh
|
||
|
{TEXT("NOP"), ADDR_INVALID3 , 0 }, // FCh
|
||
|
{TEXT("SBC"), ADDR_ABSX }, // FDh
|
||
|
{TEXT("INC"), ADDR_ABSX }, // FEh
|
||
|
{TEXT("NOP"), ADDR_INVALID1 , 0 } // FFh
|
||
|
};
|
||
|
|
||
|
#undef R_
|
||
|
#undef _W
|
||
|
#undef RW
|
||
|
#undef _S
|
||
|
#undef im
|
||
|
#undef SW
|
||
|
#undef SR
|
||
|
|
||
|
const Opcodes_t *g_aOpcodes = NULL; // & g_aOpcodes65C02[ 0 ];
|
||
|
|
||
|
|
||
|
// Memory _________________________________________________________________________________________
|
||
|
MemoryDump_t g_aMemDump[ NUM_MEM_DUMPS ];
|
||
|
|
||
|
|
||
|
// 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_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
|
||
|
// Font
|
||
|
{TEXT("MODE") , NULL, PARAM_FONT_MODE }, // also INFO, CONSOLE, DISASM (from Window)
|
||
|
// General
|
||
|
{TEXT("FIND") , NULL, PARAM_FIND },
|
||
|
{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
|
||
|
{TEXT("*") , NULL, PARAM_WILDSTAR },
|
||
|
{TEXT("BREAKPOINTS"), NULL, PARAM_CAT_BREAKPOINTS },
|
||
|
{TEXT("CONFIG") , NULL, PARAM_CAT_CONFIG },
|
||
|
{TEXT("CPU") , NULL, PARAM_CAT_CPU },
|
||
|
{TEXT("FLAGS") , NULL, PARAM_CAT_FLAGS },
|
||
|
{TEXT("MEMORY") , NULL, PARAM_CAT_MEMORY },
|
||
|
{TEXT("MEM") , NULL, PARAM_CAT_MEMORY }, // alias // SOURCE [SYMBOLS] [MEMORY] filename
|
||
|
{TEXT("SYMBOLS") , NULL, PARAM_CAT_SYMBOLS },
|
||
|
{TEXT("WATCHES") , NULL, PARAM_CAT_WATCHES },
|
||
|
{TEXT("WINDOW") , NULL, PARAM_CAT_WINDOW },
|
||
|
{TEXT("ZEROPAGE") , NULL, PARAM_CAT_ZEROPAGE },
|
||
|
// 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 },
|
||
|
// 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;
|
||
|
|
||
|
TCHAR g_aSourceFileName[ MAX_PATH ] = TEXT("");
|
||
|
TCHAR g_aSourceFontName[ MAX_FONT_NAME ] = TEXT("Arial");
|
||
|
int g_nSourceBuffer = 0; // Allocated bytes for buffer
|
||
|
char *g_pSourceBuffer = NULL; // Buffer of File
|
||
|
vector<char *> g_vSourceLines; // array of pointers to start of lines
|
||
|
|
||
|
int g_iSourceDisplayStart = 0;
|
||
|
// int g_nSourceDisplayTotal = 0;
|
||
|
|
||
|
int g_nSourceAssembleBytes = 0;
|
||
|
int g_nSourceAssemblyLines = 0;
|
||
|
int g_nSourceAssemblySymbols = 0;
|
||
|
|
||
|
// TODO: Support multiple source filenames
|
||
|
SourceAssembly_t g_aSourceDebug;
|
||
|
|
||
|
|
||
|
// Symbols ________________________________________________________________________________________
|
||
|
TCHAR * g_aSymbolTableNames[ NUM_SYMBOL_TABLES ] =
|
||
|
{
|
||
|
TEXT("Main"),
|
||
|
TEXT("User"),
|
||
|
TEXT("Src" )
|
||
|
};
|
||
|
|
||
|
SymbolTable_t g_aSymbols[ NUM_SYMBOL_TABLES ];
|
||
|
int g_nSymbolsLoaded = 0; // on Last Load
|
||
|
bool g_aConfigSymbolsDisplayed[ NUM_SYMBOL_TABLES ] =
|
||
|
{
|
||
|
true,
|
||
|
true,
|
||
|
true
|
||
|
};
|
||
|
|
||
|
|
||
|
// Watches ________________________________________________________________________________________
|
||
|
int g_nWatches = 0;
|
||
|
Watches_t g_aWatches[ MAX_WATCHES ]; // use vector<Watch_t> ??
|
||
|
|
||
|
|
||
|
// 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<> ?
|
||
|
|
||
|
|
||
|
enum DebugConfigVersion_e
|
||
|
{
|
||
|
VERSION_0,
|
||
|
CURRENT_VERSION = VERSION_0
|
||
|
};
|
||
|
|
||
|
|
||
|
// Misc. __________________________________________________________________________________________
|
||
|
|
||
|
TCHAR g_FileNameConfig [] = TEXT("Debug.cfg"); // CONFIGSAVE
|
||
|
TCHAR g_FileNameSymbolsMain[] = TEXT("APPLE2E.SYM");
|
||
|
TCHAR g_FileNameSymbolsUser[ MAX_PATH ] = TEXT("");
|
||
|
TCHAR g_FileNameTrace [] = TEXT("Trace.txt");
|
||
|
|
||
|
bool g_bBenchmarking = false;
|
||
|
|
||
|
BOOL fulldisp = 0;
|
||
|
WORD lastpc = 0;
|
||
|
LPBYTE membank = NULL;
|
||
|
|
||
|
BOOL g_bProfiling = 0;
|
||
|
int g_nDebugSteps = 0;
|
||
|
DWORD g_nDebugStepCycles = 0;
|
||
|
int g_nDebugStepStart = 0;
|
||
|
int g_nDebugStepUntil = -1;
|
||
|
|
||
|
int g_nDebugSkipStart = 0;
|
||
|
int g_nDebugSkipLen = 0;
|
||
|
|
||
|
FILE *g_hTraceFile = NULL;
|
||
|
|
||
|
// PUBLIC
|
||
|
DWORD extbench = 0;
|
||
|
bool g_bDebuggerViewingAppleOutput = false;
|
||
|
|
||
|
// Prototypes _______________________________________________________________
|
||
|
|
||
|
// 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 );
|
||
|
void ArgsClear ();
|
||
|
int ArgsGet (TCHAR *pInput);
|
||
|
int ArgsParse (const int nArgs);
|
||
|
|
||
|
void DisplayAmbigiousCommands ( int nFound );
|
||
|
|
||
|
enum Match_e
|
||
|
{
|
||
|
MATCH_EXACT,
|
||
|
MATCH_FUZZY
|
||
|
};
|
||
|
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 );
|
||
|
|
||
|
int ParseConsoleInput( LPTSTR pConsoleInput );
|
||
|
|
||
|
// Console
|
||
|
// DWORD _Color( int iWidget );
|
||
|
|
||
|
// Buffered
|
||
|
void ConsoleBufferToDisplay();
|
||
|
LPCSTR ConsoleBufferPeek();
|
||
|
void ConsoleBufferPop();
|
||
|
bool ConsoleBufferPush( const TCHAR * pString );
|
||
|
|
||
|
// Display
|
||
|
Update_t ConsoleDisplayError (LPCTSTR errortext);
|
||
|
void ConsoleDisplayPause ();
|
||
|
void ConsoleDisplayPush ( LPCSTR pText );
|
||
|
Update_t ConsoleUpdate ();
|
||
|
|
||
|
// Input
|
||
|
void ConsoleInputToDisplay();
|
||
|
LPCSTR ConsoleInputPeek ();
|
||
|
bool ConsoleInputClear ();
|
||
|
bool ConsoleInputBackSpace();
|
||
|
bool ConsoleInputChar ( TCHAR ch );
|
||
|
void ConsoleInputReset ();
|
||
|
int ConsoleInputTabCompletion();
|
||
|
|
||
|
// Scrolling
|
||
|
Update_t ConsoleScrollHome ();
|
||
|
Update_t ConsoleScrollEnd ();
|
||
|
Update_t ConsoleScrollUp ( int nLines );
|
||
|
Update_t ConsoleScrollDn ( int nLines );
|
||
|
Update_t ConsoleScrollPageUp ();
|
||
|
Update_t ConsoleScrollPageDn ();
|
||
|
|
||
|
// Source Level Debugging
|
||
|
bool BufferAssemblyListing ( TCHAR * pFileName );
|
||
|
bool ParseAssemblyListing ( bool bBytesToMemory, bool bAddSymbols );
|
||
|
|
||
|
// Font
|
||
|
void _UpdateWindowFontHeights(int nFontHeight);
|
||
|
|
||
|
// Drawing
|
||
|
COLORREF DebugGetColor ( int iColor );
|
||
|
bool DebugSetColor ( const int iScheme, const int iColor, const COLORREF nColor );
|
||
|
void _CmdColorGet ( const int iScheme, const int iColor );
|
||
|
|
||
|
HDC g_hDC = 0;
|
||
|
|
||
|
int DebugDrawText ( LPCTSTR pText, RECT & rRect );
|
||
|
int DebugDrawTextFixed ( LPCTSTR pText, RECT & rRect );
|
||
|
int DebugDrawTextLine ( LPCTSTR pText, RECT & rRect );
|
||
|
int DebugDrawTextHorz ( LPCTSTR pText, RECT & rRect );
|
||
|
|
||
|
|
||
|
void DrawWindow_Source (Update_t bUpdate);
|
||
|
|
||
|
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 DrawBreakpoints (HDC dc, int line);
|
||
|
void DrawConsoleInput (HDC dc);
|
||
|
void DrawConsoleLine (LPCSTR pText, int y);
|
||
|
WORD DrawDisassemblyLine (HDC dc, int line, WORD offset, LPTSTR text);
|
||
|
void DrawFlags (HDC dc, int line, WORD nRegFlags, LPTSTR pFlagNames_);
|
||
|
void DrawMemory (HDC dc, int line, int iMem );
|
||
|
void DrawRegister (HDC dc, int line, LPCTSTR name, int bytes, WORD value, int iSource = 0 );
|
||
|
void DrawStack (HDC dc, int line);
|
||
|
void DrawTargets (HDC dc, int line);
|
||
|
void DrawWatches (HDC dc, int line);
|
||
|
void DrawZeroPagePointers (HDC dc, int line);
|
||
|
|
||
|
void UpdateDisplay( Update_t bUpdate );
|
||
|
|
||
|
// Symbol Table / Memory
|
||
|
Update_t _CmdSymbolsClear ( Symbols_e eSymbolTable );
|
||
|
Update_t _CmdSymbolsCommon ( int nArgs, int bSymbolTables );
|
||
|
Update_t _CmdSymbolsListTables (int nArgs, int bSymbolTables );
|
||
|
Update_t _CmdSymbolsUpdate ( int nArgs );
|
||
|
|
||
|
bool _CmdSymbolList_Address2Symbol( int nAddress , int bSymbolTables );
|
||
|
bool _CmdSymbolList_Symbol2Address( LPCTSTR pSymbol, int bSymbolTables );
|
||
|
|
||
|
bool FindAddressFromSymbol( LPCSTR pSymbol, WORD * pAddress_ = NULL, int * iTable_ = NULL );
|
||
|
WORD GetAddressFromSymbol (LPCTSTR symbol); // -PATCH MJP, HACK: returned 0 if symbol not found
|
||
|
|
||
|
LPCTSTR FindSymbolFromAddress (WORD nAdress, int * iTable_ = NULL );
|
||
|
LPCTSTR GetSymbol (WORD nAddress, int nBytes);
|
||
|
bool Get6502Targets (int *pTemp_, int *pFinal_, int *pBytes_ );
|
||
|
|
||
|
// 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
|
||
|
BYTE Chars2ToByte( char *pText );
|
||
|
bool IsHexString( LPCSTR pText );
|
||
|
|
||
|
int RemoveWhiteSpaceReverse ( char *pSrc );
|
||
|
const TCHAR* SkipEOL ( const TCHAR *pSrc );
|
||
|
const TCHAR* SkipUntilChar ( const TCHAR *pSrc, const TCHAR nDelim );
|
||
|
const TCHAR* SkipUntilEOL ( const TCHAR *pSrc );
|
||
|
const TCHAR* SkipWhiteSpace ( const TCHAR *pSrc );
|
||
|
const TCHAR* SkipUntilWhiteSpace ( const TCHAR *pSrc );
|
||
|
const TCHAR* SkipUntilTab ( const TCHAR *pSrc);
|
||
|
const TCHAR* SkipWhiteSpaceReverse ( const TCHAR *pSrc, const TCHAR *pStart );
|
||
|
const TCHAR* SkipUntilWhiteSpaceReverse ( const TCHAR *pSrc, const TCHAR *pStart );
|
||
|
void TextConvertTabsToSpaces( TCHAR *pDeTabified_, LPCTSTR pText, const int nDstSize, int nTabStop = 0 );
|
||
|
|
||
|
bool StringCat( TCHAR * pDst, LPCSTR pSrc, const int nDstSize );
|
||
|
bool TestStringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize );
|
||
|
bool TryStringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize );
|
||
|
|
||
|
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 SetupColorsHiLoBits ( HDC dc, bool bHiBit, bool bLoBit,
|
||
|
const int iBackground, const int iForeground,
|
||
|
const int iColorHiBG , /*const int iColorHiFG,
|
||
|
const int iColorLoBG , */const int iColorLoFG );
|
||
|
char ColorizeSpecialChar( HDC hDC, TCHAR * 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 );
|
||
|
|
||
|
int FormatDisassemblyLine( WORD nOffset, int iMode, int nOpBytes,
|
||
|
char *sAddress_, char *sOpCodes_, char *sTarget_, char *sTargetOffset_, int & nTargetOffset_, char * sImmediate_, char & nImmediate_, char *sBranch_ );
|
||
|
|
||
|
// 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 _CmdBreakpointAddCommonArg ( int iArg, int nArg, BreakpointSource_t iSrc, BreakpointOperator_t iCmp );
|
||
|
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 );
|
||
|
|
||
|
int _6502GetOpmodeOpbyte( const int iAddress, int & iOpmode_, int & nOpbyte_ );
|
||
|
void _6502GetOpcodeOpmode( int & iOpcode_, int & iOpmode_, int & nOpbyte_ );
|
||
|
|
||
|
// Utility ________________________________________________________________________________________
|
||
|
|
||
|
|
||
|
int _6502GetOpmodeOpbyte( const int iAddress, int & iOpmode_, int & nOpbyte_ )
|
||
|
{
|
||
|
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_;
|
||
|
}
|
||
|
|
||
|
inline
|
||
|
void _6502GetOpcodeOpmodeOpbyte( int & iOpcode_, int & iOpmode_, int & nOpbyte_ )
|
||
|
{
|
||
|
iOpcode_ = _6502GetOpmodeOpbyte( regs.pc, iOpmode_, nOpbyte_ );
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
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 ( HDC hDC, 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)
|
||
|
|
||
|
SetBkColor( hDC, DebugGetColor( iBackground ));
|
||
|
SetTextColor( hDC, DebugGetColor( iForeground ));
|
||
|
|
||
|
if (bHighBit)
|
||
|
{
|
||
|
SetBkColor( hDC, DebugGetColor( iColorHiBG ));
|
||
|
SetTextColor( hDC, DebugGetColor( iColorHiFG )); // was iForeground
|
||
|
}
|
||
|
|
||
|
if (bCtrlBit)
|
||
|
{
|
||
|
SetBkColor( hDC, DebugGetColor( iColorLoBG ));
|
||
|
SetTextColor( hDC, DebugGetColor( iColorLoFG ));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// To flush out color bugs... swap: iAsciBackground & iHighBackground
|
||
|
//===========================================================================
|
||
|
char ColorizeSpecialChar( HDC hDC, TCHAR * 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)
|
||
|
wsprintf( sText, TEXT("%c"), nChar );
|
||
|
|
||
|
if (hDC)
|
||
|
{
|
||
|
SetupColorsHiLoBits( hDC, bHighBit, bCtrlBit
|
||
|
, iTextBG, iTextFG // FG_DISASM_CHAR
|
||
|
, iHighBG, iHighFG // BG_INFO_CHAR
|
||
|
, iCtrlBG, iCtrlFG // FG_DISASM_OPCODE
|
||
|
);
|
||
|
}
|
||
|
return nChar;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
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);
|
||
|
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)
|
||
|
//===========================================================================
|
||
|
bool 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 false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
inline
|
||
|
BYTE Chars2ToByte ( 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 IsHexString ( LPCSTR pText )
|
||
|
{
|
||
|
// static const TCHAR sHex[] = "0123456789ABCDEF";
|
||
|
|
||
|
while (*pText)
|
||
|
{
|
||
|
if (*pText < TEXT('0'))
|
||
|
return false;
|
||
|
if (*pText > TEXT('f'))
|
||
|
return false;
|
||
|
if ((*pText > TEXT('9')) && (*pText < TEXT('A')) ||
|
||
|
((*pText > TEXT('F') && (*pText < TEXT('a')))))
|
||
|
return false;
|
||
|
|
||
|
pText++;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
// @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;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
//const char* SkipUntilChar ( const char *pSrc, const char nDelim )
|
||
|
const TCHAR* SkipUntilChar ( const TCHAR *pSrc, const TCHAR nDelim )
|
||
|
{
|
||
|
while (pSrc && (*pSrc))
|
||
|
{
|
||
|
if (*pSrc == nDelim)
|
||
|
break;
|
||
|
pSrc++;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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
|
||
|
{
|
||
|
const TokenTable_t *pEntry = aTokens;
|
||
|
const TCHAR *pToken = NULL;
|
||
|
for (int iToken = 0; iToken < nTokens; iToken++ )
|
||
|
{
|
||
|
pToken = & (pEntry->sToken);
|
||
|
if (*pSrc == *pToken)
|
||
|
{
|
||
|
if (pToken_)
|
||
|
*pToken_ = (ArgToken_e) iToken;
|
||
|
pEnd = pSrc + 1; // _tcslen( pToken );
|
||
|
break;
|
||
|
}
|
||
|
pEntry++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return pEnd;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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 (isalnum( *pSrc ))
|
||
|
// {
|
||
|
// if ( pToken_)
|
||
|
// {
|
||
|
// *pToken_ = TOKEN_ALPHANUMERIC;
|
||
|
// }
|
||
|
// return pSrc;
|
||
|
// }
|
||
|
|
||
|
const TokenTable_t *pEntry = aTokens;
|
||
|
const TCHAR *pToken = NULL;
|
||
|
for (int iToken = 0; iToken < nTokens; iToken++ )
|
||
|
{
|
||
|
pToken = & (pEntry->sToken);
|
||
|
if (*pSrc == *pToken)
|
||
|
{
|
||
|
if ( pToken_)
|
||
|
{
|
||
|
*pToken_ = (ArgToken_e) iToken;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
pEntry++;
|
||
|
}
|
||
|
pSrc++;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
inline
|
||
|
// const char* SkipUntilEOL ( const char *pSrc )
|
||
|
const TCHAR* SkipUntilEOL ( const TCHAR *pSrc )
|
||
|
{
|
||
|
|
||
|
while (pSrc && (*pSrc))
|
||
|
{
|
||
|
if ((*pSrc == CHAR_LF) || (*pSrc == CHAR_CR))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
pSrc++;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
inline
|
||
|
//const char* SkipWhiteSpace ( const char *pSrc )
|
||
|
const TCHAR* SkipWhiteSpace ( const TCHAR *pSrc )
|
||
|
{
|
||
|
while (pSrc && ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB)))
|
||
|
{
|
||
|
pSrc++;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
inline
|
||
|
//const char* SkipUntilWhiteSpace ( const char *pSrc )
|
||
|
const TCHAR* SkipUntilWhiteSpace ( const TCHAR *pSrc )
|
||
|
{
|
||
|
while (pSrc && (*pSrc))
|
||
|
{
|
||
|
if ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
pSrc++;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
inline
|
||
|
//const char* SkipUntilTab ( const char *pSrc )
|
||
|
const TCHAR* SkipUntilTab ( const TCHAR *pSrc )
|
||
|
{
|
||
|
while (pSrc && (*pSrc))
|
||
|
{
|
||
|
if (*pSrc == CHAR_TAB)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
pSrc++;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
|
||
|
// @param pStart Start of line.
|
||
|
//===========================================================================
|
||
|
inline
|
||
|
//const char *SkipWhiteSpaceReverse ( const char *pSrc, const char *pStart )
|
||
|
const TCHAR *SkipWhiteSpaceReverse ( const TCHAR *pSrc, const TCHAR *pStart )
|
||
|
{
|
||
|
while (pSrc && ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB)) && (pSrc > pStart))
|
||
|
{
|
||
|
pSrc--;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
|
||
|
// @param pStart Start of line.
|
||
|
//===========================================================================
|
||
|
inline
|
||
|
//const char *SkipUntilWhiteSpaceReverse ( const char *pSrc, const char *pStart )
|
||
|
const TCHAR *SkipUntilWhiteSpaceReverse ( const TCHAR *pSrc, const TCHAR *pStart )
|
||
|
{
|
||
|
while (pSrc && (pSrc > pStart))
|
||
|
{
|
||
|
if ((*pSrc == CHAR_SPACE) || (*pSrc == CHAR_TAB))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
pSrc--;
|
||
|
}
|
||
|
return pSrc;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Breakpoints ____________________________________________________________________________________
|
||
|
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
Get6502Targets( &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:
|
||
|
if (_CheckBreakpointValue( pBP, regs.pc ))
|
||
|
return true;
|
||
|
break;
|
||
|
case BP_SRC_REG_A:
|
||
|
if (_CheckBreakpointValue( pBP, regs.a ))
|
||
|
return true;
|
||
|
break;
|
||
|
case BP_SRC_REG_X:
|
||
|
if (_CheckBreakpointValue( pBP, regs.x ))
|
||
|
return true;
|
||
|
break;
|
||
|
case BP_SRC_REG_Y:
|
||
|
if (_CheckBreakpointValue( pBP, regs.y ))
|
||
|
return true;
|
||
|
break;
|
||
|
case BP_SRC_REG_P:
|
||
|
if (_CheckBreakpointValue( pBP, regs.ps ))
|
||
|
return true;
|
||
|
break;
|
||
|
case BP_SRC_REG_S:
|
||
|
if (_CheckBreakpointValue( pBP, regs.sp ))
|
||
|
return true;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
BOOL CheckJump (WORD targetaddress)
|
||
|
{
|
||
|
WORD savedpc = regs.pc;
|
||
|
InternalSingleStep();
|
||
|
BOOL result = (regs.pc == targetaddress);
|
||
|
regs.pc = savedpc;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Console ________________________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
LPCSTR ConsoleBufferPeek()
|
||
|
{
|
||
|
return g_aConsoleBuffer[ 0 ];
|
||
|
}
|
||
|
|
||
|
|
||
|
// Add string to buffered output
|
||
|
// Shifts the buffered console output lines "Up"
|
||
|
//===========================================================================
|
||
|
bool ConsoleBufferPush( const TCHAR * pString ) // LPCSTR
|
||
|
{
|
||
|
if (g_nConsoleBuffer < CONSOLE_HEIGHT)
|
||
|
{
|
||
|
int nLen = _tcslen( pString );
|
||
|
if (nLen < g_nConsoleDisplayWidth)
|
||
|
{
|
||
|
_tcscpy( g_aConsoleBuffer[ g_nConsoleBuffer ], pString );
|
||
|
g_nConsoleBuffer++;
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if _DEBUG
|
||
|
// TCHAR sText[ CONSOLE_WIDTH * 2 ];
|
||
|
// sprintf( sText, "ConsoleBufferPush(pString) > g_nConsoleDisplayWidth: %d", g_nConsoleDisplayWidth );
|
||
|
// MessageBox( framewindow, sText, "Warning", MB_OK );
|
||
|
#endif
|
||
|
// push multiple lines
|
||
|
while ((nLen >= g_nConsoleDisplayWidth) && (g_nConsoleBuffer < CONSOLE_HEIGHT))
|
||
|
{
|
||
|
// _tcsncpy( g_aConsoleBuffer[ g_nConsoleBuffer ], pString, (g_nConsoleDisplayWidth-1) );
|
||
|
// pString += g_nConsoleDisplayWidth;
|
||
|
_tcsncpy( g_aConsoleBuffer[ g_nConsoleBuffer ], pString, (CONSOLE_WIDTH-1) );
|
||
|
pString += (CONSOLE_WIDTH-1);
|
||
|
g_nConsoleBuffer++;
|
||
|
nLen = _tcslen( pString );
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TODO: Warning: Too much output.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Shifts the buffered console output "down"
|
||
|
//===========================================================================
|
||
|
void ConsoleBufferPop()
|
||
|
{
|
||
|
int y = 0;
|
||
|
while (y < g_nConsoleBuffer)
|
||
|
{
|
||
|
_tcscpy( g_aConsoleBuffer[ y ], g_aConsoleBuffer[ y+1 ] );
|
||
|
y++;
|
||
|
}
|
||
|
|
||
|
g_nConsoleBuffer--;
|
||
|
if (g_nConsoleBuffer < 0)
|
||
|
g_nConsoleBuffer = 0;
|
||
|
}
|
||
|
|
||
|
// Remove string from buffered output
|
||
|
//===========================================================================
|
||
|
void ConsoleBufferToDisplay()
|
||
|
{
|
||
|
ConsoleDisplayPush( ConsoleBufferPeek() );
|
||
|
ConsoleBufferPop();
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t ConsoleDisplayError (LPCTSTR pText)
|
||
|
{
|
||
|
ConsoleBufferPush( pText );
|
||
|
return ConsoleUpdate();
|
||
|
}
|
||
|
|
||
|
// ConsoleDisplayPush()
|
||
|
// Shifts the console display lines "up"
|
||
|
//===========================================================================
|
||
|
void ConsoleDisplayPush( LPCSTR pText )
|
||
|
{
|
||
|
int nLen = MIN( g_nConsoleDisplayTotal, CONSOLE_HEIGHT - 1 - CONSOLE_FIRST_LINE);
|
||
|
while (nLen--)
|
||
|
{
|
||
|
_tcsncpy(
|
||
|
g_aConsoleDisplay[(nLen + 1 + CONSOLE_FIRST_LINE )],
|
||
|
g_aConsoleDisplay[nLen + CONSOLE_FIRST_LINE],
|
||
|
CONSOLE_WIDTH );
|
||
|
}
|
||
|
|
||
|
if (pText)
|
||
|
_tcsncpy( g_aConsoleDisplay[ CONSOLE_FIRST_LINE ], pText, CONSOLE_WIDTH );
|
||
|
|
||
|
g_nConsoleDisplayTotal++;
|
||
|
if (g_nConsoleDisplayTotal > (CONSOLE_HEIGHT - CONSOLE_FIRST_LINE))
|
||
|
g_nConsoleDisplayTotal = (CONSOLE_HEIGHT - CONSOLE_FIRST_LINE);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
void ConsoleDisplayPause()
|
||
|
{
|
||
|
if (g_nConsoleBuffer)
|
||
|
{
|
||
|
_tcscpy( g_pConsoleInput, TEXT("...press SPACE continue, ESC skip..." ) );
|
||
|
g_bConsoleBufferPaused = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ConsoleInputReset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
bool ConsoleInputBackSpace()
|
||
|
{
|
||
|
if (g_nConsoleInputChars)
|
||
|
{
|
||
|
g_nConsoleInputChars--;
|
||
|
|
||
|
if (g_pConsoleInput[ g_nConsoleInputChars ] == TEXT('"'))
|
||
|
g_bConsoleInputQuoted = ! g_bConsoleInputQuoted;
|
||
|
|
||
|
g_pConsoleInput[ g_nConsoleInputChars ] = 0;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
bool ConsoleInputClear()
|
||
|
{
|
||
|
if (g_nConsoleInputChars)
|
||
|
{
|
||
|
ZeroMemory( g_pConsoleInput, g_nConsoleDisplayWidth );
|
||
|
g_nConsoleInputChars = 0;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
bool ConsoleInputChar( TCHAR ch )
|
||
|
{
|
||
|
if (g_nConsoleInputChars < g_nConsoleDisplayWidth) // bug? include prompt?
|
||
|
{
|
||
|
g_pConsoleInput[ g_nConsoleInputChars ] = ch;
|
||
|
g_nConsoleInputChars++;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
LPCSTR ConsoleInputPeek()
|
||
|
{
|
||
|
return g_aConsoleDisplay[0];
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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;
|
||
|
|
||
|
ZeroMemory( g_aConsoleInput, CONSOLE_WIDTH );
|
||
|
_tcscpy( g_aConsoleInput, g_sConsolePrompt );
|
||
|
_tcscat( g_aConsoleInput, TEXT(" " ) );
|
||
|
|
||
|
int nLen = _tcslen( g_aConsoleInput );
|
||
|
g_pConsoleInput = &g_aConsoleInput[nLen];
|
||
|
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_nConsoleDisplayHeight - CONSOLE_FIRST_LINE );
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t ConsoleScrollPageDn()
|
||
|
{
|
||
|
ConsoleScrollDn( g_nConsoleDisplayHeight - CONSOLE_FIRST_LINE );
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void ConsoleBufferTryUnpause (int nLines)
|
||
|
{
|
||
|
for( int y = 0; y < nLines; y++ )
|
||
|
{
|
||
|
ConsoleBufferToDisplay();
|
||
|
}
|
||
|
|
||
|
g_bConsoleBufferPaused = false;
|
||
|
if (g_nConsoleBuffer)
|
||
|
{
|
||
|
g_bConsoleBufferPaused = true;
|
||
|
ConsoleDisplayPause();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t ConsoleUpdate()
|
||
|
{
|
||
|
if (! g_bConsoleBufferPaused)
|
||
|
{
|
||
|
int nLines = MIN( g_nConsoleBuffer, g_nConsoleDisplayHeight - 1);
|
||
|
ConsoleBufferTryUnpause( nLines );
|
||
|
}
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Commands _______________________________________________________________________________________
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
int HashMnemonic( 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 _CmdAssembleHashOpcodes()
|
||
|
{
|
||
|
int nMnemonicHash;
|
||
|
int iOpcode;
|
||
|
|
||
|
for( iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ )
|
||
|
{
|
||
|
const TCHAR *pMnemonic = g_aOpcodes65C02[ iOpcode ].sMnemonic;
|
||
|
nMnemonicHash = HashMnemonic( pMnemonic );
|
||
|
g_aOpcodesHash[ iOpcode ] = nMnemonicHash;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
void _CmdAssembleHashDump()
|
||
|
{
|
||
|
// #if DEBUG_ASM_HASH
|
||
|
vector<HashOpcode_t> 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
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
bool AssemblerOpcodeIsBranch( int nOpcode )
|
||
|
{
|
||
|
// 76543210 Bit
|
||
|
// xxx10000 Branch
|
||
|
|
||
|
if (nOpcode == OPCODE_BRA)
|
||
|
return true;
|
||
|
|
||
|
if ((nOpcode & 0x1F) != 0x10) // low nibble not zero?
|
||
|
return false;
|
||
|
|
||
|
if ((nOpcode >> 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 AssemblerGetAddressingMode( int nArgs, WORD nAddress, vector<int> vOpcodes )
|
||
|
{
|
||
|
bool bHaveComma = false;
|
||
|
bool bHaveHash = false;
|
||
|
bool bHaveDollar = false;
|
||
|
bool bHaveLeftParen = false;
|
||
|
bool bHaveRightParen = false;
|
||
|
bool bHaveParen = false;
|
||
|
bool bHaveRegisterX = false;
|
||
|
bool bHaveRegisterY = false;
|
||
|
bool bHaveZeroPage = false;
|
||
|
|
||
|
// int iArgRawMnemonic = 0;
|
||
|
int iArg;
|
||
|
|
||
|
// Sync up to Raw Args for matching mnemonic
|
||
|
iArg = 3;
|
||
|
Arg_t *pArg = &g_aArgRaw[ iArg ];
|
||
|
|
||
|
// Process them instead of the cooked args, since we need the orginal tokens
|
||
|
int iAddressMode = AM_IMPLIED;
|
||
|
int nBytes = 0;
|
||
|
WORD nTarget = 0;
|
||
|
|
||
|
while (iArg <= g_nArgRaw)
|
||
|
{
|
||
|
int iToken = pArg->eToken;
|
||
|
int iType = pArg->bType;
|
||
|
|
||
|
if (iToken == TOKEN_HASH)
|
||
|
{
|
||
|
if (bHaveHash)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Extra '#'" ) ); // No thanks, we already have one
|
||
|
return false;
|
||
|
}
|
||
|
bHaveHash = true;
|
||
|
|
||
|
iAddressMode = AM_M; // Immediate
|
||
|
nTarget = pArg[1].nVal1;
|
||
|
nBytes = 1;
|
||
|
}
|
||
|
else
|
||
|
if (iToken == TOKEN_DOLLAR)
|
||
|
{
|
||
|
if (bHaveDollar)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Extra '$'" ) ); // No thanks, we already have one
|
||
|
return false;
|
||
|
}
|
||
|
bHaveDollar = true;
|
||
|
|
||
|
iAddressMode = AM_A; // Absolute
|
||
|
nTarget = pArg[1].nVal1;
|
||
|
nBytes = 2;
|
||
|
|
||
|
if (nTarget <= _6502_ZEROPAGE_END)
|
||
|
{
|
||
|
iAddressMode = AM_Z;
|
||
|
nBytes = 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (iToken == TOKEN_LEFT_PAREN)
|
||
|
{
|
||
|
if (bHaveLeftParen)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Extra '('" ) ); // No thanks, we already have one
|
||
|
return false;
|
||
|
}
|
||
|
bHaveLeftParen = true;
|
||
|
|
||
|
// Indexed or Indirect
|
||
|
iAddressMode = AM_IZX;
|
||
|
}
|
||
|
else
|
||
|
if (iToken == TOKEN_RIGHT_PAREN)
|
||
|
{
|
||
|
if (bHaveRightParen)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Extra ')'" ) ); // No thanks, we already have one
|
||
|
return false;
|
||
|
}
|
||
|
bHaveRightParen = true;
|
||
|
|
||
|
// Indexed or Indirect
|
||
|
iAddressMode = AM_IZX;
|
||
|
}
|
||
|
else
|
||
|
if (iToken == TOKEN_COMMA)
|
||
|
{
|
||
|
if (bHaveComma)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Extra ','" ) ); // No thanks, we already have one
|
||
|
return false;
|
||
|
}
|
||
|
bHaveComma = true;
|
||
|
// We should have address by now
|
||
|
}
|
||
|
else
|
||
|
if (iToken = TOKEN_ALPHANUMERIC)
|
||
|
{
|
||
|
if (pArg->nArgLen == 1)
|
||
|
{
|
||
|
if (pArg->sArg[0] == 'X')
|
||
|
{
|
||
|
if (! bHaveComma)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Missing ','" ) );
|
||
|
return false;
|
||
|
}
|
||
|
bHaveRegisterX = true;
|
||
|
}
|
||
|
if (pArg->sArg[0] == 'Y')
|
||
|
{
|
||
|
if (! bHaveComma)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Missing ','" ) );
|
||
|
return false;
|
||
|
}
|
||
|
bHaveRegisterY = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
if (iType & TYPE_VALUE)
|
||
|
{
|
||
|
iAddressMode = AM_M; // Immediate
|
||
|
nTarget = g_aArgs[ iArg ].nVal1;
|
||
|
nBytes = 1;
|
||
|
}
|
||
|
if (iType & TYPE_ADDRESS)
|
||
|
{
|
||
|
iAddressMode = AM_A; // Absolute
|
||
|
nTarget = g_aArgs[ iArg ].nVal1;
|
||
|
nBytes = 2;
|
||
|
|
||
|
if (nTarget <= _6502_ZEROPAGE_END)
|
||
|
{
|
||
|
iAddressMode = AM_Z;
|
||
|
nBytes = 1;
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
iArg++;
|
||
|
}
|
||
|
|
||
|
if (( bHaveLeftParen) && (! bHaveRightParen))
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Missing ')'" ) );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ((! bHaveLeftParen) && ( bHaveRightParen))
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Missing '('" ) );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (bHaveComma)
|
||
|
{
|
||
|
if ((! bHaveRegisterX) && (! bHaveRegisterY))
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT( " Syntax Error: Index 'X' or 'Y'" ) );
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bHaveParen = (bHaveLeftParen || bHaveRightParen);
|
||
|
if (! bHaveParen)
|
||
|
{
|
||
|
if (bHaveComma)
|
||
|
{
|
||
|
if (bHaveRegisterX)
|
||
|
{
|
||
|
iAddressMode = AM_AX;
|
||
|
nBytes = 2;
|
||
|
if (nTarget <= _6502_ZEROPAGE_END)
|
||
|
{
|
||
|
iAddressMode = AM_ZX;
|
||
|
nBytes = 1;
|
||
|
}
|
||
|
}
|
||
|
if (bHaveRegisterY)
|
||
|
{
|
||
|
iAddressMode = AM_AY;
|
||
|
nBytes = 2;
|
||
|
if (nTarget <= _6502_ZEROPAGE_END)
|
||
|
{
|
||
|
iAddressMode = AM_ZY;
|
||
|
nBytes = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int iOpcode;
|
||
|
int nOpcodes = vOpcodes.size();
|
||
|
|
||
|
for( iOpcode = 0; iOpcode < nOpcodes; iOpcode++ )
|
||
|
{
|
||
|
int nOpcode = vOpcodes.at( iOpcode ); // m_iOpcode;
|
||
|
int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode;
|
||
|
|
||
|
if (AssemblerOpcodeIsBranch( nOpcode))
|
||
|
nOpmode = AM_R;
|
||
|
|
||
|
if (nOpmode == iAddressMode)
|
||
|
{
|
||
|
*(memdirty + (nAddress >> 8)) |= 1;
|
||
|
*(mem + nAddress) = (BYTE) nOpcode;
|
||
|
|
||
|
if (nBytes > 0)
|
||
|
*(mem + nAddress + 1) = (BYTE)(nTarget >> 0);
|
||
|
|
||
|
if (nBytes > 1)
|
||
|
*(mem + nAddress + 2) = (BYTE)(nTarget >> 8);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdAssemble (int nArgs)
|
||
|
{
|
||
|
if (! g_bOpcodesHashed)
|
||
|
{
|
||
|
_CmdAssembleHashOpcodes();
|
||
|
g_bOpcodesHashed = true;
|
||
|
}
|
||
|
|
||
|
if (! nArgs)
|
||
|
return Help_Arg_1( CMD_ASSEMBLE );
|
||
|
|
||
|
if (nArgs == 1) // undocumented ASM *
|
||
|
{
|
||
|
if (_tcscmp( g_aArgs[ 1 ].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName ) == 0)
|
||
|
{
|
||
|
_CmdAssembleHashDump();
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
// g_nAssemblerAddress = g_aArgs[1].nVal1;
|
||
|
return Help_Arg_1( CMD_ASSEMBLE );
|
||
|
}
|
||
|
|
||
|
if (nArgs < 2)
|
||
|
return Help_Arg_1( CMD_ASSEMBLE );
|
||
|
|
||
|
WORD nAddress = g_aArgs[1].nVal1;
|
||
|
|
||
|
TCHAR *pMnemonic = g_aArgs[2].sArg;
|
||
|
int nMnemonicHash = HashMnemonic( pMnemonic );
|
||
|
|
||
|
vector<int> vOpcodes; // Candiate opcodes
|
||
|
int iOpcode;
|
||
|
|
||
|
// Ugh! Linear search.
|
||
|
for( iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ )
|
||
|
{
|
||
|
if (nMnemonicHash == g_aOpcodesHash[ iOpcode ])
|
||
|
{
|
||
|
vOpcodes.push_back( iOpcode );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int nOpcodes = vOpcodes.size();
|
||
|
if (! nOpcodes)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT(" Syntax Error: Invalid mnemonic") );
|
||
|
}
|
||
|
else
|
||
|
if (nOpcodes == 1)
|
||
|
{
|
||
|
*(memdirty + (nAddress >> 8)) |= 1;
|
||
|
|
||
|
int nOpcode = vOpcodes.at( 0 );
|
||
|
*(mem + nAddress) = (BYTE) nOpcode;
|
||
|
}
|
||
|
else // ambigious -- need to parse Addressing Mode
|
||
|
{
|
||
|
bool bStatus = AssemblerGetAddressingMode( nArgs, nAddress, vOpcodes );
|
||
|
}
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Unassemble
|
||
|
//===========================================================================
|
||
|
Update_t CmdUnassemble (int nArgs)
|
||
|
{
|
||
|
if (! nArgs)
|
||
|
return Help_Arg_1( CMD_UNASSEMBLE );
|
||
|
|
||
|
WORD nAddress = g_aArgs[1].nVal1;
|
||
|
g_nDisasmTopAddress = nAddress;
|
||
|
|
||
|
DisasmCalcCurFromTopAddress();
|
||
|
DisasmCalcBotFromTopAddress();
|
||
|
|
||
|
return UPDATE_DISASM;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdCalculator (int nArgs)
|
||
|
{
|
||
|
const int nBits = 8;
|
||
|
|
||
|
if (! nArgs)
|
||
|
return Help_Arg_1( CMD_CALC );
|
||
|
|
||
|
WORD nAddress = g_aArgs[1].nVal1;
|
||
|
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 CmdFeedKey (int nArgs)
|
||
|
{
|
||
|
KeybQueueKeypress(
|
||
|
nArgs ? g_aArgs[1].nVal1 ? g_aArgs[1].nVal1 : g_aArgs[1].sArg[0] : TEXT(' '), 1); // FIXME!!!
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdInput (int nArgs)
|
||
|
{
|
||
|
if (!nArgs)
|
||
|
return Help_Arg_1( CMD_INPUT );
|
||
|
|
||
|
WORD nAddress = g_aArgs[1].nVal1;
|
||
|
|
||
|
// ioread[ g_aArgs[1].nVal1 & 0xFF ](regs.pc,g_aArgs[1].nVal1 & 0xFF,0,0,0);
|
||
|
ioread[ nAddress & 0xFF ](regs.pc, nAddress & 0xFF,0,0,0); // g_aArgs[1].nVal1
|
||
|
|
||
|
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].nVal1 & _6502_END_MEM_ADDRESS;
|
||
|
|
||
|
// 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 nOpbyte;
|
||
|
|
||
|
_6502GetOpcodeOpmodeOpbyte( iOpcode, iOpmode, nOpbyte );
|
||
|
|
||
|
while (nOpbyte--)
|
||
|
{
|
||
|
*(mem+regs.pc + nOpbyte) = 0xEA;
|
||
|
}
|
||
|
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdOutput (int nArgs)
|
||
|
{
|
||
|
// if ((!nArgs) ||
|
||
|
// ((g_aArgs[1].sArg[0] != TEXT('0')) && (!g_aArgs[1].nVal1) && (!GetAddress(g_aArgs[1].sArg))))
|
||
|
// return DisplayHelp(CmdInput);
|
||
|
|
||
|
if (!nArgs)
|
||
|
Help_Arg_1( CMD_OUTPUT );
|
||
|
|
||
|
WORD nAddress = g_aArgs[1].nVal1;
|
||
|
|
||
|
// iowrite[ g_aArgs[1].nVal1 & 0xFF](regs.pc,g_aArgs[1].nVal1 & 0xFF,1,g_aArgs[2].nVal1 & 0xFF,0);
|
||
|
iowrite[ nAddress & 0xFF ] (regs.pc, nAddress & 0xFF, 1, g_aArgs[2].nVal1 & 0xFF,0);
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY; // TODO: Verify // 1
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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();
|
||
|
mode = MODE_RUNNING;
|
||
|
FrameRefreshStatus(DRAW_TITLE);
|
||
|
VideoRedrawScreen();
|
||
|
DWORD currtime = GetTickCount();
|
||
|
while ((extbench = GetTickCount()) != currtime)
|
||
|
; // intentional busy-waiting
|
||
|
KeybQueueKeypress(TEXT(' '),1);
|
||
|
resettiming = 1;
|
||
|
|
||
|
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 );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Breakpoint _____________________________________________________________________________________
|
||
|
|
||
|
// Menu: LOAD SAVE RESET
|
||
|
//===========================================================================
|
||
|
Update_t CmdBreakpoint (int nArgs)
|
||
|
{
|
||
|
// This is temporary until the menu is in.
|
||
|
CmdBreakpointAddPC( nArgs );
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
// smart breakpoint
|
||
|
//===========================================================================
|
||
|
Update_t CmdBreakpointAddSmart (int nArgs)
|
||
|
{
|
||
|
int nAddress = g_aArgs[1].nVal1;
|
||
|
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
// return Help_Arg_1( CMD_BREAKPOINT_ADD_SMART );
|
||
|
g_aArgs[1].nVal1 = 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_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))
|
||
|
{
|
||
|
bAdded = _CmdBreakpointAddCommonArg( iArg, nArgs, iSrc, iCmp );
|
||
|
if (!bAdded)
|
||
|
{
|
||
|
return Help_Arg_1( CMD_BREAKPOINT_ADD_REG );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
bool _CmdBreakpointAddReg( Breakpoint_t *pBP, BreakpointSource_t iSrc, BreakpointOperator_t iCmp, WORD nAddress, int nLen )
|
||
|
{
|
||
|
bool bStatus = false;
|
||
|
|
||
|
if (pBP)
|
||
|
{
|
||
|
pBP->eSource = iSrc;
|
||
|
pBP->eOperator = iCmp;
|
||
|
pBP->nAddress = nAddress;
|
||
|
pBP->nLength = nLen;
|
||
|
pBP->bSet = true;
|
||
|
pBP->bEnabled = true;
|
||
|
bStatus = true;
|
||
|
}
|
||
|
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
bool _CmdBreakpointAddCommonArg ( int iArg, int nArg, BreakpointSource_t iSrc, BreakpointOperator_t iCmp )
|
||
|
{
|
||
|
bool bStatus = false;
|
||
|
|
||
|
int iBreakpoint = 0;
|
||
|
Breakpoint_t *pBP = & g_aBreakpoints[ iBreakpoint ];
|
||
|
|
||
|
while ((iBreakpoint < MAX_BREAKPOINTS) && g_aBreakpoints[iBreakpoint].nLength)
|
||
|
{
|
||
|
iBreakpoint++;
|
||
|
pBP++;
|
||
|
}
|
||
|
|
||
|
if (iBreakpoint >= MAX_BREAKPOINTS)
|
||
|
{
|
||
|
ConsoleDisplayError(TEXT("All Breakpoints slots are currently in use."));
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
if (iArg <= nArg)
|
||
|
{
|
||
|
WORD nAddress = g_aArgs[iArg].nVal1;
|
||
|
|
||
|
int nLen = g_aArgs[iArg].nVal2;
|
||
|
if ( !nLen)
|
||
|
{
|
||
|
nLen = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Clamp Length so it stays within the 6502 memory address
|
||
|
int nSlack = (_6502_END_MEM_ADDRESS + 1) - nAddress;
|
||
|
int nWantedLength = g_aArgs[iArg].nVal2;
|
||
|
nLen = MIN( nSlack, nWantedLength );
|
||
|
}
|
||
|
|
||
|
bStatus = _CmdBreakpointAddReg( pBP, iSrc, iCmp, nAddress, nLen );
|
||
|
g_nBreakpoints++;
|
||
|
}
|
||
|
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
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].nVal1 = regs.pc;
|
||
|
}
|
||
|
|
||
|
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
|
||
|
{
|
||
|
bAdded = _CmdBreakpointAddCommonArg( iArg, nArgs, iSrc, iCmp );
|
||
|
if (!bAdded)
|
||
|
{
|
||
|
return Help_Arg_1( CMD_BREAKPOINT_ADD_PC );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
{
|
||
|
bAdded = _CmdBreakpointAddCommonArg( iArg, nArgs, iSrc, iCmp );
|
||
|
if (!bAdded)
|
||
|
{
|
||
|
return Help_Arg_1( CMD_BREAKPOINT_ADD_MEM );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return UPDATE_BREAKPOINTS | UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
void _Clear( Breakpoint_t * aBreakWatchZero, int iBreakpoint )
|
||
|
{
|
||
|
aBreakWatchZero[iBreakpoint].bSet = false;
|
||
|
aBreakWatchZero[iBreakpoint].bEnabled = false;
|
||
|
aBreakWatchZero[iBreakpoint].nLength = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// called by BreakpointsClear, WatchesClear, ZeroPagePointersClear
|
||
|
//===========================================================================
|
||
|
void _ClearViaArgs( int nArgs, Breakpoint_t * aBreakWatchZero, const int nMax, int & gnBWZ )
|
||
|
{
|
||
|
int iBWZ;
|
||
|
|
||
|
// CLEAR EACH BREAKPOINT IN THE LIST
|
||
|
while (nArgs)
|
||
|
{
|
||
|
iBWZ = g_aArgs[nArgs].nVal1;
|
||
|
if (! _tcscmp(g_aArgs[nArgs].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName))
|
||
|
{
|
||
|
iBWZ = nMax;
|
||
|
while (iBWZ--)
|
||
|
{
|
||
|
if (aBreakWatchZero[iBWZ].bSet)
|
||
|
{
|
||
|
_Clear( aBreakWatchZero, iBWZ );
|
||
|
gnBWZ--;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
else if ((iBWZ >= 1) && (iBWZ <= nMax))
|
||
|
{
|
||
|
if (aBreakWatchZero[iBWZ-1].bSet)
|
||
|
{
|
||
|
_Clear( aBreakWatchZero, iBWZ - 1 );
|
||
|
gnBWZ--;
|
||
|
}
|
||
|
}
|
||
|
nArgs--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// called by BreakpointsEnable, WatchesEnable, ZeroPagePointersEnable
|
||
|
// called by BreakpointsDisable, WatchesDisable, ZeroPagePointersDisable
|
||
|
void _EnableDisableViaArgs( int nArgs, Breakpoint_t * aBreakWatchZero, const int nMax, const bool bEnabled )
|
||
|
{
|
||
|
// Enable each breakpoint in the list
|
||
|
while (nArgs)
|
||
|
{
|
||
|
int iBWZ = g_aArgs[nArgs].nVal1;
|
||
|
if (! _tcscmp(g_aArgs[nArgs].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName))
|
||
|
{
|
||
|
int iBWZ = nMax;
|
||
|
while (iBWZ--)
|
||
|
{
|
||
|
aBreakWatchZero[iBWZ].bEnabled = bEnabled;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
if ((iBWZ >= 1) && (iBWZ <= nMax))
|
||
|
{
|
||
|
aBreakWatchZero[iBWZ-1].bEnabled = bEnabled;
|
||
|
}
|
||
|
nArgs--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdBreakpointClear (int nArgs)
|
||
|
{
|
||
|
if (!g_nBreakpoints)
|
||
|
return ConsoleDisplayError(TEXT("There are no breakpoints defined."));
|
||
|
|
||
|
int iBreakpoint;
|
||
|
|
||
|
// CHECK FOR ERRORS
|
||
|
if (!nArgs)
|
||
|
{
|
||
|
iBreakpoint = MAX_BREAKPOINTS;
|
||
|
while (iBreakpoint--)
|
||
|
{
|
||
|
if ((g_aBreakpoints[iBreakpoint].bSet) &&
|
||
|
(g_aBreakpoints[iBreakpoint].nAddress == regs.pc)) // TODO: FIXME
|
||
|
{
|
||
|
_Clear( g_aBreakpoints, iBreakpoint );
|
||
|
g_nBreakpoints--;
|
||
|
}
|
||
|
}
|
||
|
// return DisplayHelp(CmdBreakpointClear);
|
||
|
}
|
||
|
|
||
|
_ClearViaArgs( nArgs, g_aBreakpoints, MAX_BREAKPOINTS, g_nBreakpoints );
|
||
|
|
||
|
if (! g_nBreakpoints)
|
||
|
{
|
||
|
return (UPDATE_DISASM | UPDATE_BREAKPOINTS);
|
||
|
}
|
||
|
|
||
|
return UPDATE_BREAKPOINTS | UPDATE_CONSOLE_DISPLAY; // 1;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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 );
|
||
|
|
||
|
_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 );
|
||
|
|
||
|
_EnableDisableViaArgs( nArgs, g_aBreakpoints, MAX_BREAKPOINTS, true );
|
||
|
|
||
|
return UPDATE_BREAKPOINTS;
|
||
|
}
|
||
|
|
||
|
void _ListBreakWatchZero( Breakpoint_t * aBreakWatchZero, int iBWZ )
|
||
|
{
|
||
|
static TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
static const TCHAR sFlags[] = "-*";
|
||
|
static TCHAR sName[ MAX_SYMBOLS_LEN+1 ];
|
||
|
|
||
|
WORD nAddress = aBreakWatchZero[ iBWZ ].nAddress;
|
||
|
LPCTSTR pSymbol = GetSymbol( nAddress, 2 );
|
||
|
if (! pSymbol)
|
||
|
{
|
||
|
sName[0] = 0;
|
||
|
pSymbol = sName;
|
||
|
}
|
||
|
|
||
|
wsprintf( sText, " #%d %c %04X %s",
|
||
|
iBWZ + 1,
|
||
|
sFlags[ (int) aBreakWatchZero[ iBWZ ].bEnabled ],
|
||
|
aBreakWatchZero[ iBWZ ].nAddress,
|
||
|
pSymbol
|
||
|
);
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdBreakpointList (int nArgs)
|
||
|
{
|
||
|
// ConsoleBufferPush( );
|
||
|
// vector<int> 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)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT(" There are no current breakpoints." ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int iBreakpoint = 0;
|
||
|
while (iBreakpoint < MAX_BREAKPOINTS)
|
||
|
{
|
||
|
if (g_aBreakpoints[ iBreakpoint ].bSet)
|
||
|
{
|
||
|
_ListBreakWatchZero( g_aBreakpoints, iBreakpoint );
|
||
|
}
|
||
|
iBreakpoint++;
|
||
|
}
|
||
|
}
|
||
|
return ConsoleUpdate();
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdBreakpointLoad (int nArgs)
|
||
|
{
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdBreakpointSave (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Config _________________________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdConfig (int nArgs)
|
||
|
{
|
||
|
if (nArgs)
|
||
|
{
|
||
|
int iParam;
|
||
|
int iArg = 1;
|
||
|
if (FindParam( g_aArgs[iArg].sArg, MATCH_FUZZY, iParam ))
|
||
|
{
|
||
|
switch (iParam)
|
||
|
{
|
||
|
case PARAM_SAVE:
|
||
|
nArgs = _Arg_Shift( iArg, nArgs );
|
||
|
return CmdConfigSave( nArgs );
|
||
|
break;
|
||
|
case PARAM_LOAD:
|
||
|
nArgs = _Arg_Shift( iArg, nArgs );
|
||
|
return CmdConfigLoad( nArgs );
|
||
|
break;
|
||
|
default:
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
wsprintf( sText, "Syntax error: %s", g_aArgs[1].sArg );
|
||
|
return ConsoleDisplayError( sText );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdConfigLoad (int nArgs)
|
||
|
{
|
||
|
// TODO: CmdRun( gaFileNameConfig )
|
||
|
|
||
|
// TCHAR sFileNameConfig[ MAX_PATH ];
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
// gDebugConfigName
|
||
|
// DEBUGLOAD file // load debugger setting
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
|
||
|
|
||
|
Update_t CmdConfigRun (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Save Debugger Settings
|
||
|
//===========================================================================
|
||
|
Update_t CmdConfigSave (int nArgs)
|
||
|
{
|
||
|
TCHAR filename[ MAX_PATH ];
|
||
|
_tcscpy(filename, progdir);
|
||
|
_tcscat(filename, g_FileNameConfig );
|
||
|
|
||
|
HANDLE hFile = CreateFile(filename,
|
||
|
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;
|
||
|
|
||
|
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 );
|
||
|
|
||
|
// History
|
||
|
// UserSymbol
|
||
|
|
||
|
CloseHandle( hFile );
|
||
|
}
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
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 ].nVal1;
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
iArg = 1;
|
||
|
|
||
|
if (nArgs == 1)
|
||
|
{
|
||
|
// FONT * is undocumented, like VERSION *
|
||
|
if (_tcscmp( g_aArgs[ iArg ].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName ) == 0)
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
wsprintf( sText, "Lines: %d Font Px: %d Line Px: %d"
|
||
|
, g_nTotalLines
|
||
|
, 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 );
|
||
|
}
|
||
|
|
||
|
int GetConsoleHeightPixels()
|
||
|
{
|
||
|
int nHeight = nHeight = g_aFontConfig[ FONT_CONSOLE ]._nFontHeight; // _nLineHeight; // _nFontHeight;
|
||
|
|
||
|
if (g_iFontSpacing == FONT_SPACING_CLEAN)
|
||
|
{
|
||
|
// int nHeight = g_aFontConfig[ FONT_DEFAULT ]._nFontHeight + 1; // "Classic" Height/Spacing
|
||
|
nHeight++; // "Classic" Height/Spacing
|
||
|
}
|
||
|
else
|
||
|
if (g_iFontSpacing == FONT_SPACING_COMPRESSED)
|
||
|
{
|
||
|
// default case handled
|
||
|
}
|
||
|
else
|
||
|
if (g_iFontSpacing == FONT_SPACING_CLASSIC)
|
||
|
{
|
||
|
nHeight++;
|
||
|
}
|
||
|
|
||
|
return nHeight;
|
||
|
}
|
||
|
|
||
|
int GetConsoleTopPixels( int y )
|
||
|
{
|
||
|
int nLineHeight = GetConsoleHeightPixels();
|
||
|
int nTop = DISPLAY_HEIGHT - ((y + 1) * nLineHeight); // DISPLAY_HEIGHT - (y * nFontHeight); // ((g_nTotalLines - y) * g_nFontHeight; // 368 = 23 lines * 16 pixels/line // MAX_DISPLAY_CONSOLE_LINES
|
||
|
return nTop;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Only for FONT_DISASM_DEFAULT !
|
||
|
void _UpdateWindowFontHeights( int nFontHeight )
|
||
|
{
|
||
|
if (nFontHeight)
|
||
|
{
|
||
|
// The screen layout defaults to a "virtal" font height of 16 pixels.
|
||
|
// The disassmebler has 19 lines.
|
||
|
// Total: 19 * 16 pixels
|
||
|
//
|
||
|
// Figure out how many lines we can display, given our new font height.
|
||
|
// Given: Total_Pixels = Lines * Pixels_Line
|
||
|
// Calc: Lines = Total_Pixels / Pixels_Line
|
||
|
int nConsoleTopY = 19 * 16;
|
||
|
int nHeight = 0;
|
||
|
|
||
|
if (g_iFontSpacing == FONT_SPACING_CLASSIC)
|
||
|
{
|
||
|
nHeight = nFontHeight + 1;
|
||
|
g_nTotalLines = nConsoleTopY / nHeight;
|
||
|
}
|
||
|
else
|
||
|
if (g_iFontSpacing == FONT_SPACING_CLEAN)
|
||
|
{
|
||
|
nHeight = nFontHeight;
|
||
|
g_nTotalLines = nConsoleTopY / nHeight;
|
||
|
}
|
||
|
else
|
||
|
if (g_iFontSpacing == FONT_SPACING_COMPRESSED)
|
||
|
{
|
||
|
nHeight = nFontHeight - 1;
|
||
|
g_nTotalLines = (nConsoleTopY + nHeight) / nHeight; // Ceil()
|
||
|
}
|
||
|
|
||
|
g_aFontConfig[ FONT_DISASM_DEFAULT ]._nLineHeight = nHeight;
|
||
|
|
||
|
// int nHeightOptimal = (nHeight0 + nHeight1) / 2;
|
||
|
// int nLinesOptimal = nConsoleTopY / nHeightOptimal;
|
||
|
// g_nTotalLines = nLinesOptimal;
|
||
|
|
||
|
MAX_DISPLAY_DISASM_LINES = g_nTotalLines;
|
||
|
|
||
|
// TODO/FIXME: Needs to take into account the console height
|
||
|
MAX_DISPLAY_CONSOLE_LINES = MAX_DISPLAY_DISASM_LINES + MIN_DISPLAY_CONSOLE_LINES; // 23
|
||
|
// if (MAX_DISPLAY_CONSOLE_LINES > 23)
|
||
|
// MAX_DISPLAY_CONSOLE_LINES = 23;
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
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_QUOTED)
|
||
|
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 ))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
for( int iLine = 0; iLine <= nLen; iLine++ ) // min 1 opcode/instruction
|
||
|
{
|
||
|
if (iLine == g_nDisasmCurLine) // && (iAddress == g_nDisasmCurAddress))
|
||
|
{
|
||
|
if (iAddress == g_nDisasmCurAddress)
|
||
|
{
|
||
|
g_nDisasmTopAddress = iTop;
|
||
|
bFound = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int iOpmode;
|
||
|
int nOpbyte;
|
||
|
_6502GetOpmodeOpbyte( iAddress, iOpmode, nOpbyte );
|
||
|
|
||
|
// .20 Fixed: DisasmCalcTopFromCurAddress()
|
||
|
//if ((eMode >= ADDR_INVALID1) && (eMode <= ADDR_INVALID3))
|
||
|
{
|
||
|
#if 0 // _DEBUG
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
wsprintf( sText, "%04X : %d bytes\n", iAddress, nOpbyte );
|
||
|
OutputDebugString( sText );
|
||
|
#endif
|
||
|
iAddress += nOpbyte;
|
||
|
}
|
||
|
}
|
||
|
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 is not really a good idea, since we're breaking the user paradigm.
|
||
|
// 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( framewindow, sText, "ERROR", MB_OK );
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
WORD DisasmCalcAddressFromLines( WORD iAddress, int nLines )
|
||
|
{
|
||
|
while (nLines-- > 0)
|
||
|
{
|
||
|
int iOpmode;
|
||
|
int nOpbyte;
|
||
|
_6502GetOpmodeOpbyte( iAddress, iOpmode, nOpbyte );
|
||
|
iAddress += nOpbyte;
|
||
|
}
|
||
|
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 CmdCursorLineDown (int nArgs)
|
||
|
{
|
||
|
int iOpmode;
|
||
|
int nOpbyte;
|
||
|
_6502GetOpmodeOpbyte( g_nDisasmCurAddress, iOpmode, nOpbyte ); // g_nDisasmTopAddress
|
||
|
|
||
|
if (g_iWindowThis == WINDOW_DATA)
|
||
|
{
|
||
|
_CursorMoveDownAligned( WINDOW_DATA_BYTES_PER_LINE );
|
||
|
}
|
||
|
else
|
||
|
if (nArgs)
|
||
|
{
|
||
|
nOpbyte = nArgs; // HACKL g_aArgs[1].val
|
||
|
|
||
|
g_nDisasmTopAddress += nOpbyte;
|
||
|
g_nDisasmCurAddress += nOpbyte;
|
||
|
g_nDisasmBotAddress += nOpbyte;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Works except on one case: G FB53, SPACE, DOWN
|
||
|
WORD nTop = g_nDisasmTopAddress;
|
||
|
WORD nCur = g_nDisasmCurAddress + nOpbyte;
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
// Can't use use + nBytes due to Disasm Singularity
|
||
|
// DisasmCalcTopBotAddress();
|
||
|
|
||
|
return UPDATE_DISASM;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdCursorLineUp (int nArgs)
|
||
|
{
|
||
|
WORD nBest = g_nDisasmTopAddress;
|
||
|
int nBytes = 1;
|
||
|
|
||
|
if (g_iWindowThis == WINDOW_DATA)
|
||
|
{
|
||
|
_CursorMoveUpAligned( WINDOW_DATA_BYTES_PER_LINE );
|
||
|
}
|
||
|
else
|
||
|
if (nArgs)
|
||
|
{
|
||
|
nBytes = nArgs; // HACK: g_aArgs[1].nVal1
|
||
|
|
||
|
g_nDisasmTopAddress--;
|
||
|
DisasmCalcCurFromTopAddress();
|
||
|
DisasmCalcBotFromTopAddress();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nBytes = 1;
|
||
|
|
||
|
// 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
|
||
|
//
|
||
|
WORD nCur = g_nDisasmCurAddress - nBytes;
|
||
|
|
||
|
// Adjust Top until nNewCur is at > Cur
|
||
|
do
|
||
|
{
|
||
|
g_nDisasmTopAddress--;
|
||
|
DisasmCalcCurFromTopAddress();
|
||
|
} while (g_nDisasmCurAddress > nCur);
|
||
|
|
||
|
DisasmCalcCurFromTopAddress();
|
||
|
DisasmCalcBotFromTopAddress();
|
||
|
g_bDisasmCurBad = false;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
bool _Get6502ReturnAddress( 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;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdCursorJumpRetAddr (int nArgs)
|
||
|
{
|
||
|
WORD nAddress;
|
||
|
if (_Get6502ReturnAddress( 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 > 0xFFFF)
|
||
|
nAddress = 0xFFFF;
|
||
|
|
||
|
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_END_MEM_ADDRESS;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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_END_MEM_ADDRESS; // .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_END_MEM_ADDRESS;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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_END_MEM_ADDRESS; // .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 = 1; // 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
|
||
|
{
|
||
|
while (++iLines < nLines)
|
||
|
CmdCursorLineDown(nArgs);
|
||
|
}
|
||
|
|
||
|
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 = 1; // 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);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Help ___________________________________________________________________________________________
|
||
|
|
||
|
|
||
|
// 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 _CmdHelpSpecific()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMOTD( int nArgs )
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
|
||
|
ConsoleBufferPush( TEXT(" Apple ][+ //e Emulator for Windows") );
|
||
|
CmdVersion(0);
|
||
|
CmdSymbols(0);
|
||
|
wsprintf( sText, " '~' console, '%s' (specific), '%s' (all)"
|
||
|
, g_aCommands[ CMD_HELP_SPECIFIC ].m_sName
|
||
|
// , g_aCommands[ CMD_HELP_SPECIFIC ].pHelpSummary
|
||
|
, g_aCommands[ CMD_HELP_LIST ].m_sName
|
||
|
// , g_aCommands[ CMD_HELP_LIST ].pHelpSummary
|
||
|
);
|
||
|
ConsoleBufferPush( sText );
|
||
|
|
||
|
ConsoleUpdate();
|
||
|
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Help on specific command
|
||
|
//===========================================================================
|
||
|
Update_t CmdHelpSpecific (int nArgs)
|
||
|
{
|
||
|
int iArg;
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
ZeroMemory( sText, CONSOLE_WIDTH );
|
||
|
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
// ConsoleBufferPush( TEXT(" [] = optional, {} = mandatory. Categories are: ") );
|
||
|
|
||
|
_tcscpy( sText, TEXT("Usage: [{ ") );
|
||
|
for (int iCategory = _PARAM_HELPCATEGORIES_BEGIN ; iCategory < _PARAM_HELPCATEGORIES_END; iCategory++)
|
||
|
{
|
||
|
TCHAR *pName = g_aParameters[ iCategory ].m_sName;
|
||
|
if (! TestStringCat( sText, pName, g_nConsoleDisplayWidth - 3 )) // CONSOLE_WIDTH
|
||
|
{
|
||
|
ConsoleBufferPush( sText );
|
||
|
_tcscpy( sText, TEXT(" ") );
|
||
|
}
|
||
|
|
||
|
StringCat( sText, pName, CONSOLE_WIDTH );
|
||
|
if (iCategory < (_PARAM_HELPCATEGORIES_END - 1))
|
||
|
{
|
||
|
StringCat( sText, TEXT(" | "), CONSOLE_WIDTH );
|
||
|
}
|
||
|
}
|
||
|
StringCat( sText, TEXT(" }]"), CONSOLE_WIDTH );
|
||
|
ConsoleBufferPush( sText );
|
||
|
|
||
|
wsprintf( sText, TEXT("Note: [] = optional, {} = mandatory"), CONSOLE_WIDTH );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
|
||
|
|
||
|
bool bAllCommands = false;
|
||
|
bool bCategory = false;
|
||
|
|
||
|
if (! _tcscmp( g_aArgs[1].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName))
|
||
|
{
|
||
|
bAllCommands = true;
|
||
|
nArgs = NUM_COMMANDS;
|
||
|
}
|
||
|
|
||
|
// If Help on category, push command name as arg
|
||
|
int nNewArgs = 0;
|
||
|
int iCmdBegin = 0;
|
||
|
int iCmdEnd = 0;
|
||
|
for (iArg = 1; iArg <= nArgs; iArg++ )
|
||
|
{
|
||
|
int iParam;
|
||
|
int nFoundCategory = FindParam( g_aArgs[ iArg ].sArg, MATCH_EXACT, iParam, _PARAM_HELPCATEGORIES_BEGIN, _PARAM_HELPCATEGORIES_END );
|
||
|
switch( iParam )
|
||
|
{
|
||
|
case PARAM_CAT_BREAKPOINTS: iCmdBegin = CMD_BREAKPOINT ; iCmdEnd = CMD_BREAKPOINT_SAVE + 1; break;
|
||
|
case PARAM_CAT_CONFIG : iCmdBegin = CMD_CONFIG_COLOR ; iCmdEnd = CMD_CONFIG_SAVE + 1; break;
|
||
|
case PARAM_CAT_CPU : iCmdBegin = CMD_ASSEMBLE ; iCmdEnd = CMD_TRACE_LINE + 1; break;
|
||
|
case PARAM_CAT_FLAGS : iCmdBegin = CMD_FLAG_CLEAR ; iCmdEnd = CMD_FLAG_SET_N + 1; break;
|
||
|
case PARAM_CAT_MEMORY : iCmdBegin = CMD_MEMORY_COMPARE ; iCmdEnd = CMD_MEMORY_FILL + 1; break;
|
||
|
case PARAM_CAT_SYMBOLS : iCmdBegin = CMD_SYMBOLS_LOOKUP ; iCmdEnd = CMD_SYMBOLS_LIST + 1; break;
|
||
|
case PARAM_CAT_WATCHES : iCmdBegin = CMD_WATCH_ADD ; iCmdEnd = CMD_WATCH_LIST + 1; break;
|
||
|
case PARAM_CAT_WINDOW : iCmdBegin = CMD_WINDOW ; iCmdEnd = CMD_WINDOW_OUTPUT + 1; break;
|
||
|
case PARAM_CAT_ZEROPAGE : iCmdBegin = CMD_ZEROPAGE_POINTER; iCmdEnd = CMD_ZEROPAGE_POINTER_SAVE+1;break;
|
||
|
default: break;
|
||
|
}
|
||
|
nNewArgs = (iCmdEnd - iCmdBegin);
|
||
|
if (nNewArgs > 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (nNewArgs > 0)
|
||
|
{
|
||
|
bCategory = true;
|
||
|
|
||
|
nArgs = nNewArgs;
|
||
|
for (iArg = 1; iArg <= nArgs; iArg++ )
|
||
|
{
|
||
|
g_aArgs[ iArg ].nVal2 = iCmdBegin + iArg - 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CmdFuncPtr_t pFunction;
|
||
|
|
||
|
for (iArg = 1; iArg <= nArgs; iArg++ )
|
||
|
{
|
||
|
int iCommand = 0;
|
||
|
int nFound = FindCommand( g_aArgs[iArg].sArg, pFunction, & iCommand );
|
||
|
|
||
|
if (bCategory)
|
||
|
{
|
||
|
iCommand = g_aArgs[iArg].nVal2;
|
||
|
}
|
||
|
|
||
|
if (bAllCommands)
|
||
|
{
|
||
|
iCommand = iArg;
|
||
|
if (iCommand == NUM_COMMANDS) // skip: Internal Consistency Check __COMMANDS_VERIFY_TXT__
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (nFound > 1)
|
||
|
{
|
||
|
DisplayAmbigiousCommands( nFound );
|
||
|
}
|
||
|
|
||
|
if (iCommand > NUM_COMMANDS)
|
||
|
continue;
|
||
|
|
||
|
if ((nArgs == 1) && (! nFound))
|
||
|
iCommand = g_aArgs[iArg].nVal1;
|
||
|
|
||
|
Command_t *pCommand = & g_aCommands[ iCommand ];
|
||
|
|
||
|
if (! nFound)
|
||
|
{
|
||
|
iCommand = NUM_COMMANDS;
|
||
|
pCommand = NULL;
|
||
|
}
|
||
|
|
||
|
if (nFound && (! bAllCommands))
|
||
|
{
|
||
|
TCHAR sCategory[ CONSOLE_WIDTH ];
|
||
|
int iCmd = g_aCommands[ iCommand ].iCommand; // Unaliased command
|
||
|
|
||
|
// HACK: Major kludge to display category!!!
|
||
|
if (iCmd <= CMD_TRACE_LINE)
|
||
|
wsprintf( sCategory, "Main" );
|
||
|
else
|
||
|
if (iCmd <= CMD_BREAKPOINT_SAVE)
|
||
|
wsprintf( sCategory, "Breakpoint" );
|
||
|
else
|
||
|
if (iCmd <= CMD_PROFILE)
|
||
|
wsprintf( sCategory, "Profile" );
|
||
|
else
|
||
|
if (iCmd <= CMD_CONFIG_SAVE)
|
||
|
wsprintf( sCategory, "Config" );
|
||
|
else
|
||
|
if (iCmd <= CMD_CURSOR_PAGE_DOWN_4K)
|
||
|
wsprintf( sCategory, "Scrolling" );
|
||
|
else
|
||
|
if (iCmd <= CMD_FLAG_SET_N)
|
||
|
wsprintf( sCategory, "Flags" );
|
||
|
else
|
||
|
if (iCmd <= CMD_MOTD)
|
||
|
wsprintf( sCategory, "Help" );
|
||
|
else
|
||
|
if (iCmd <= CMD_MEMORY_FILL)
|
||
|
wsprintf( sCategory, "Memory" );
|
||
|
else
|
||
|
if (iCmd <= CMD_REGISTER_SET)
|
||
|
wsprintf( sCategory, "Registers" );
|
||
|
else
|
||
|
if (iCmd <= CMD_SYNC)
|
||
|
wsprintf( sCategory, "Source" );
|
||
|
else
|
||
|
if (iCmd <= CMD_STACK_PUSH)
|
||
|
wsprintf( sCategory, "Stack" );
|
||
|
else
|
||
|
if (iCmd <= CMD_SYMBOLS_LIST)
|
||
|
wsprintf( sCategory, "Symbols" );
|
||
|
else
|
||
|
if (iCmd <= CMD_WATCH_SAVE)
|
||
|
wsprintf( sCategory, "Watch" );
|
||
|
else
|
||
|
if (iCmd <= CMD_WINDOW_OUTPUT)
|
||
|
wsprintf( sCategory, "Window" );
|
||
|
else
|
||
|
if (iCmd <= CMD_ZEROPAGE_POINTER_SAVE)
|
||
|
wsprintf( sCategory, "Zero Page" );
|
||
|
else
|
||
|
wsprintf( sCategory, "Unknown!" );
|
||
|
|
||
|
wsprintf( sText, "Category: %s", sCategory );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
|
||
|
if (pCommand)
|
||
|
{
|
||
|
char *pHelp = pCommand->pHelpSummary;
|
||
|
if (pHelp)
|
||
|
{
|
||
|
wsprintf( sText, "%s, ", pCommand->m_sName );
|
||
|
if (! TryStringCat( sText, pHelp, g_nConsoleDisplayWidth ))
|
||
|
{
|
||
|
if (! TryStringCat( sText, pHelp, CONSOLE_WIDTH ))
|
||
|
{
|
||
|
StringCat( sText, pHelp, CONSOLE_WIDTH );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
}
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintf( sText, "%s", 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
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MASTER HELP
|
||
|
switch (iCommand)
|
||
|
{
|
||
|
// CPU / General
|
||
|
case CMD_ASSEMBLE:
|
||
|
ConsoleBufferPush( TEXT(" Built-in assember isn't functional yet.") );
|
||
|
break;
|
||
|
case CMD_UNASSEMBLE:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address | symbol}") );
|
||
|
ConsoleBufferPush( TEXT(" Disassembles memory.") );
|
||
|
break;
|
||
|
case CMD_CALC:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address | symbol | + | - }" ) );
|
||
|
ConsoleBufferPush( TEXT(" Output order is: Hex Bin Dec Char" ) );
|
||
|
ConsoleBufferPush( TEXT(" Note: symbols take piority." ) );
|
||
|
ConsoleBufferPush( TEXT("i.e. #A (if you don't want accum. val)" ) );
|
||
|
ConsoleBufferPush( TEXT("i.e. #F (if you don't want flags val)" ) );
|
||
|
break;
|
||
|
case CMD_GO:
|
||
|
ConsoleBufferPush( TEXT(" Usage: [address | symbol [Skip,End]]") );
|
||
|
ConsoleBufferPush( TEXT(" Skip: Start address to skip stepping" ) );
|
||
|
ConsoleBufferPush( TEXT(" End : End address to skip stepping" ) );
|
||
|
ConsoleBufferPush( TEXT(" If the Program Counter is outside the" ) );
|
||
|
ConsoleBufferPush( TEXT(" skip range, resumes single-stepping." ) );
|
||
|
ConsoleBufferPush( TEXT(" Can be used to skip ROM/OS/user code." ));
|
||
|
ConsoleBufferPush( TEXT(" i.e. G C600 F000,FFFF" ) );
|
||
|
break;
|
||
|
case CMD_NOP:
|
||
|
ConsoleBufferPush( TEXT(" Puts a NOP opcode at current instruction") );
|
||
|
break;
|
||
|
case CMD_JSR:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {symbol | address}") );
|
||
|
ConsoleBufferPush( TEXT(" Pushes PC on stack; calls the named subroutine.") );
|
||
|
break;
|
||
|
case CMD_PROFILE:
|
||
|
wsprintf( sText, TEXT(" Usage: [%s | %s | %s]")
|
||
|
, g_aParameters[ PARAM_RESET ].m_sName
|
||
|
, g_aParameters[ PARAM_SAVE ].m_sName
|
||
|
, g_aParameters[ PARAM_LIST ].m_sName
|
||
|
);
|
||
|
ConsoleBufferPush( sText );
|
||
|
ConsoleBufferPush( TEXT(" No arguments resets the profile.") );
|
||
|
break;
|
||
|
case CMD_SOURCE:
|
||
|
ConsoleBufferPush( TEXT(" Reads assembler source file." ) );
|
||
|
wsprintf( sText, TEXT(" Usage: [ %s | %s ] \"filename\"" ), g_aParameters[ PARAM_SRC_MEMORY ].m_sName, g_aParameters[ PARAM_SRC_SYMBOLS ].m_sName ); ConsoleBufferPush( sText );
|
||
|
wsprintf( sText, TEXT(" %s: read source bytes into memory." ), g_aParameters[ PARAM_SRC_MEMORY ].m_sName ); ConsoleBufferPush( sText );
|
||
|
wsprintf( sText, TEXT(" %s: read symbols into Source symbol table."), g_aParameters[ PARAM_SRC_SYMBOLS ].m_sName ); ConsoleBufferPush( sText );
|
||
|
wsprintf( sText, TEXT(" Supports: %s." ), g_aParameters[ PARAM_SRC_MERLIN ].m_sName ); ConsoleBufferPush( sText );
|
||
|
break;
|
||
|
case CMD_STEP_OUT:
|
||
|
ConsoleBufferPush( TEXT(" Steps out of current subroutine") );
|
||
|
ConsoleBufferPush( TEXT(" Hotkey: Ctrl-Space" ) );
|
||
|
break;
|
||
|
case CMD_STEP_OVER: // Bad name? FIXME/TODO: do we need to rename?
|
||
|
ConsoleBufferPush( TEXT(" Usage: [#]") );
|
||
|
ConsoleBufferPush( TEXT(" Steps, # times, thru current instruction") );
|
||
|
ConsoleBufferPush( TEXT(" JSR will be stepped into AND out of.") );
|
||
|
ConsoleBufferPush( TEXT(" Hotkey: Ctrl-Space" ) );
|
||
|
break;
|
||
|
case CMD_TRACE:
|
||
|
ConsoleBufferPush( TEXT(" Usage: [#]") );
|
||
|
ConsoleBufferPush( TEXT(" Traces, # times, current instruction(s)") );
|
||
|
ConsoleBufferPush( TEXT(" JSR will be stepped into") );
|
||
|
ConsoleBufferPush( TEXT(" Hotkey: Shift-Space" ) );
|
||
|
case CMD_TRACE_FILE:
|
||
|
ConsoleBufferPush( TEXT(" Usage: [filename]") );
|
||
|
break;
|
||
|
case CMD_TRACE_LINE:
|
||
|
ConsoleBufferPush( TEXT(" Usage: [#]") );
|
||
|
ConsoleBufferPush( TEXT(" Traces into current instruction") );
|
||
|
ConsoleBufferPush( TEXT(" with cycle counting." ) );
|
||
|
break;
|
||
|
// Breakpoints
|
||
|
case CMD_BREAKPOINT:
|
||
|
wsprintf( sText, " Maximum breakpoints are: %d", MAX_BREAKPOINTS );
|
||
|
ConsoleBufferPush( sText );
|
||
|
break;
|
||
|
case CMD_BREAKPOINT_ADD_REG:
|
||
|
ConsoleBufferPush( TEXT(" Usage: [A|X|Y|PC|S] [<,=,>] value") );
|
||
|
ConsoleBufferPush( TEXT(" Set breakpoint when reg is [op] value") );
|
||
|
break;
|
||
|
case CMD_BREAKPOINT_ADD_SMART:
|
||
|
case CMD_BREAKPOINT_ADD_PC:
|
||
|
ConsoleBufferPush( TEXT(" Usage: [address]") );
|
||
|
ConsoleBufferPush( TEXT(" Sets a breakpoint at the current PC") );
|
||
|
ConsoleBufferPush( TEXT(" or at the specified address.") );
|
||
|
break;
|
||
|
case CMD_BREAKPOINT_ENABLE:
|
||
|
ConsoleBufferPush( TEXT(" Usage: [# [,#] | *]") );
|
||
|
ConsoleBufferPush( TEXT(" Re-enables breakpoint previously set, or all.") );
|
||
|
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;
|
||
|
case CMD_OUTPUT:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address8 | address16 | symbol} ## [##]") );
|
||
|
ConsoleBufferPush( TEXT(" Ouput a byte or word to the IO address $C0xx" ) );
|
||
|
break;
|
||
|
// Config - Font
|
||
|
case CMD_CONFIG_FONT:
|
||
|
wsprintf( 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:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address | symbol} ## [## ... ##]") );
|
||
|
ConsoleBufferPush( TEXT(" Sets memory to the specified 8-Bit Values (bytes)" ) );
|
||
|
break;
|
||
|
case CMD_MEMORY_ENTER_WORD:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address | symbol} #### [#### ... ####]") );
|
||
|
ConsoleBufferPush( TEXT(" Sets memory to the specified 16-Bit Values (words)" ) );
|
||
|
break;
|
||
|
case CMD_MEMORY_FILL:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address | symbol} {address | symbol} ##" ) );
|
||
|
ConsoleBufferPush( TEXT(" Fills the memory range with the specified byte" ) );
|
||
|
ConsoleBufferPush( TEXT(" Can't fill IO address $C0xx" ) );
|
||
|
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:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address | symbol}") );
|
||
|
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:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address | symbol}") );
|
||
|
ConsoleBufferPush( TEXT(" Displays APPLE text in the Mini-Memory area") );
|
||
|
ConsoleBufferPush( TEXT(" APPLE control chars are inverse") );
|
||
|
ConsoleBufferPush( TEXT(" 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: {address | symbol}") );
|
||
|
// ConsoleBufferPush( TEXT(" Displays text in the Memory Mini-Dump area") );
|
||
|
// ConsoleBufferPush( TEXT(" ASCII chars with the hi-bit set, is inverse") );
|
||
|
break;
|
||
|
// Symbols
|
||
|
case CMD_SYMBOLS_MAIN:
|
||
|
case CMD_SYMBOLS_USER:
|
||
|
case CMD_SYMBOLS_SRC :
|
||
|
// 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" ) );
|
||
|
ConsoleBufferPush( TEXT(" Usage: [ ... | symbol | address ]") );
|
||
|
ConsoleBufferPush( TEXT(" Where ... is one of:" ) );
|
||
|
wsprintf( sText, TEXT(" %s " ": Turns symbols on in the disasm window" ), g_aParameters[ PARAM_ON ].m_sName ); ConsoleBufferPush( sText );
|
||
|
wsprintf( sText, TEXT(" %s " ": Turns symbols off in the disasm window" ), g_aParameters[ PARAM_OFF ].m_sName ); ConsoleBufferPush( sText );
|
||
|
wsprintf( sText, TEXT(" %s" ": Loads symbols from last/default \"filename\"" ), g_aParameters[ PARAM_SAVE ].m_sName ); ConsoleBufferPush( sText );
|
||
|
wsprintf( sText, TEXT(" %s" ": Saves symbol table to \"filename\"" ), g_aParameters[ PARAM_LOAD ].m_sName ); ConsoleBufferPush( sText );
|
||
|
wsprintf( sText, TEXT(" %s" ": Clears the symbol table" ), g_aParameters[ PARAM_CLEAR ].m_sName ); ConsoleBufferPush( sText );
|
||
|
break;
|
||
|
// Watches
|
||
|
case CMD_WATCH_ADD:
|
||
|
ConsoleBufferPush( TEXT(" Usage: {address | symbol}" ) );
|
||
|
ConsoleBufferPush( TEXT(" 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;
|
||
|
|
||
|
// Misc
|
||
|
case CMD_VERSION:
|
||
|
ConsoleBufferPush( TEXT(" Usage: [*]") );
|
||
|
ConsoleBufferPush( TEXT(" * Display extra internal stats" ) );
|
||
|
break;
|
||
|
default:
|
||
|
if (bAllCommands)
|
||
|
break;
|
||
|
#if DEBUG_COMMAND_HELP
|
||
|
wsprintf( sText, "Command help not done yet: %s", g_aCommands[ iCommand ].aName );
|
||
|
ConsoleBufferPush( sText );
|
||
|
#endif
|
||
|
if ((! nFound) || (! pCommand))
|
||
|
{
|
||
|
wsprintf( sText, " Invalid command." );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return ConsoleUpdate();
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdHelpList (int nArgs)
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ] = TEXT("Commands: ");
|
||
|
int nLenLine = _tcslen( sText );
|
||
|
int y = 0;
|
||
|
int nLinesScrolled = 0;
|
||
|
|
||
|
int nMaxWidth = g_nConsoleDisplayWidth - 1;
|
||
|
int iCommand;
|
||
|
|
||
|
/*
|
||
|
if (! g_vSortedCommands.size())
|
||
|
{
|
||
|
for (iCommand = 0; iCommand < NUM_COMMANDS_WITH_ALIASES; iCommand++ )
|
||
|
{
|
||
|
// TCHAR *pName = g_aCommands[ iCommand ].aName );
|
||
|
g_vSortedCommands.push_back( g_aCommands[ iCommand ] );
|
||
|
}
|
||
|
|
||
|
std::sort( g_vSortedCommands.begin(), g_vSortedCommands.end(), commands_functor_compare() );
|
||
|
}
|
||
|
int nCommands = g_vSortedCommands.size();
|
||
|
*/
|
||
|
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 ];
|
||
|
TCHAR *pName = pCommand->m_sName;
|
||
|
|
||
|
if (! pCommand->pFunction)
|
||
|
continue; // not implemented function
|
||
|
|
||
|
int nLenCmd = _tcslen( pName );
|
||
|
if ((nLenLine + nLenCmd) < (nMaxWidth))
|
||
|
{
|
||
|
_tcscat( sText, pName );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ConsoleBufferPush( sText );
|
||
|
nLenLine = 1;
|
||
|
_tcscpy( sText, TEXT(" " ) );
|
||
|
_tcscat( sText, pName );
|
||
|
}
|
||
|
|
||
|
_tcscat( sText, TEXT(" ") );
|
||
|
nLenLine += (nLenCmd + 1);
|
||
|
}
|
||
|
|
||
|
ConsoleBufferPush( 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 );
|
||
|
|
||
|
// wsprintf( sText, "Version" ); ConsoleBufferPush( sText );
|
||
|
wsprintf( sText, " Emulator: %s Debugger: %d.%d.%d.%d"
|
||
|
, VERSIONSTRING
|
||
|
, nMajor, nMinor, nFixMajor, nFixMinor );
|
||
|
ConsoleBufferPush( sText );
|
||
|
|
||
|
if (nArgs)
|
||
|
{
|
||
|
for (int iArg = 1; iArg <= nArgs; iArg++ )
|
||
|
{
|
||
|
if (_tcscmp( g_aArgs[ iArg ].sArg, g_aParameters[ PARAM_WILDSTAR ].m_sName ) == 0)
|
||
|
{
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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->nVal1;
|
||
|
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*)(membank+REG_AF);
|
||
|
bUpdate = true;
|
||
|
}
|
||
|
else if(strcmp(g_aArgs[1].sArg, "*BC") == 0)
|
||
|
{
|
||
|
nAddress = *(WORD*)(membank+REG_BC);
|
||
|
bUpdate = true;
|
||
|
}
|
||
|
else if(strcmp(g_aArgs[1].sArg, "*DE") == 0)
|
||
|
{
|
||
|
nAddress = *(WORD*)(membank+REG_DE);
|
||
|
bUpdate = true;
|
||
|
}
|
||
|
else if(strcmp(g_aArgs[1].sArg, "*HL") == 0)
|
||
|
{
|
||
|
nAddress = *(WORD*)(membank+REG_HL);
|
||
|
bUpdate = true;
|
||
|
}
|
||
|
else if(strcmp(g_aArgs[1].sArg, "*IX") == 0)
|
||
|
{
|
||
|
nAddress = *(WORD*)(membank+REG_IX);
|
||
|
bUpdate = true;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (bUpdate)
|
||
|
{
|
||
|
pArg->nVal1 = 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].nVal1;
|
||
|
WORD nLenByte = 0;
|
||
|
WORD nDstAddr = g_aArgs[3].nVal1;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemoryEnterByte (int nArgs)
|
||
|
{
|
||
|
if ((nArgs < 2) ||
|
||
|
((g_aArgs[2].sArg[0] != TEXT('0')) && (!g_aArgs[2].nVal1))) // arg2 not numeric or not specified
|
||
|
{
|
||
|
Help_Arg_1( CMD_MEMORY_ENTER_WORD );
|
||
|
}
|
||
|
|
||
|
WORD nAddress = g_aArgs[1].nVal1;
|
||
|
while (nArgs >= 2)
|
||
|
{
|
||
|
*(membank+nAddress+nArgs-2) = (BYTE)g_aArgs[nArgs].nVal1;
|
||
|
*(memdirty+(nAddress >> 8)) = 1;
|
||
|
nArgs--;
|
||
|
}
|
||
|
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemoryEnterWord (int nArgs)
|
||
|
{
|
||
|
if ((nArgs < 2) ||
|
||
|
((g_aArgs[2].sArg[0] != TEXT('0')) && (!g_aArgs[2].nVal1))) // arg2 not numeric or not specified
|
||
|
{
|
||
|
Help_Arg_1( CMD_MEMORY_ENTER_WORD );
|
||
|
}
|
||
|
|
||
|
WORD nAddress = g_aArgs[1].nVal1;
|
||
|
while (nArgs >= 2)
|
||
|
{
|
||
|
WORD nData = g_aArgs[nArgs].nVal1;
|
||
|
|
||
|
// Little Endian
|
||
|
*(membank + nAddress + nArgs - 2) = (BYTE)(nData >> 0);
|
||
|
*(membank + nAddress + nArgs - 1) = (BYTE)(nData >> 8);
|
||
|
|
||
|
*(memdirty+(nAddress >> 8)) |= 1;
|
||
|
nArgs--;
|
||
|
}
|
||
|
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemoryFill (int nArgs)
|
||
|
{
|
||
|
if (!nArgs)
|
||
|
return Help_Arg_1( CMD_MEMORY_FILL );
|
||
|
|
||
|
WORD nAddress = g_aArgs[1].nVal1;
|
||
|
WORD nBytes = MAX(1,g_aArgs[1].nVal2); // TODO: This actually work??
|
||
|
|
||
|
while (nBytes--)
|
||
|
{
|
||
|
if ((nAddress < _6502_IO_BEGIN) || (nAddress > _6502_IO_END))
|
||
|
{
|
||
|
*(membank+nAddress) = (BYTE)(g_aArgs[2].nVal1 & 0xFF); // HACK: Undocumented fill with ZERO
|
||
|
}
|
||
|
nAddress++;
|
||
|
}
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemoryMove (int nArgs)
|
||
|
{
|
||
|
if (nArgs < 3)
|
||
|
return Help_Arg_1( CMD_MEMORY_MOVE );
|
||
|
|
||
|
WORD nSrc = g_aArgs[1].nVal1;
|
||
|
WORD nLen = g_aArgs[2].nVal1 - nSrc;
|
||
|
WORD nDst = g_aArgs[3].nVal1;
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemorySearch (int nArgs)
|
||
|
{
|
||
|
if (nArgs < 3)
|
||
|
Help_Arg_1( CMD_MEMORY_SEARCH );
|
||
|
|
||
|
if (g_aArgs[2].sArg[0] == TEXT('\"'))
|
||
|
CmdMemorySearchText( nArgs );
|
||
|
else
|
||
|
CmdMemorySearchHex( nArgs );
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
// Search for Ascii Hi-Bit set
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemorySearchHiBit (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemorySearchLowBit (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
bool _GetStartEnd( WORD & nAddressStart_, WORD & nAddressEnd_ )
|
||
|
{
|
||
|
nAddressStart_ = g_aArgs[1].nVal1 ? g_aArgs[1].nVal1 : GetAddressFromSymbol( g_aArgs[1].sArg );
|
||
|
nAddressEnd_ = g_aArgs[2].nVal1 ? g_aArgs[2].nVal1 : GetAddressFromSymbol( g_aArgs[2].sArg );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemorySearchHex (int nArgs)
|
||
|
{
|
||
|
WORD nAddrStart;
|
||
|
WORD nAddrEnd;
|
||
|
_GetStartEnd( nAddrStart, nAddrEnd );
|
||
|
// TODO: if (!_tcscmp(g_aArgs[nArgs].sArg,TEXT("*"))) { }
|
||
|
// TODO: if (!_tcscmp(g_aArgs[nArgs].sArg,TEXT("?"))) { }
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdMemorySearchText (int nArgs)
|
||
|
{
|
||
|
WORD nAddrStart;
|
||
|
WORD nAddrEnd;
|
||
|
_GetStartEnd( nAddrStart, nAddrEnd );
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// 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].nVal1))
|
||
|
{
|
||
|
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 ].nVal1 & 0xFF);
|
||
|
WORD w = (WORD)(g_aArgs[ iArg ].nVal1 & 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
|
||
|
}
|
||
|
|
||
|
|
||
|
// Source Level Debugging _________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
bool BufferAssemblyListing( TCHAR *pFileName )
|
||
|
{
|
||
|
bool bStatus = false; // true = loaded
|
||
|
|
||
|
if (! pFileName)
|
||
|
return bStatus;
|
||
|
|
||
|
FILE *hFile = fopen(pFileName,"rt");
|
||
|
|
||
|
if (hFile)
|
||
|
{
|
||
|
fseek( hFile, 0, SEEK_END );
|
||
|
long nSize = ftell( hFile );
|
||
|
fseek( hFile, 0, SEEK_SET );
|
||
|
|
||
|
if (nSize > 0)
|
||
|
g_nSourceBuffer = nSize;
|
||
|
|
||
|
g_pSourceBuffer = new char [ nSize + 1 ];
|
||
|
ZeroMemory( g_pSourceBuffer, nSize + 1 );
|
||
|
|
||
|
fread( (void*)g_pSourceBuffer, nSize, 1, hFile );
|
||
|
fclose(hFile);
|
||
|
|
||
|
g_vSourceLines.erase( g_vSourceLines.begin(), g_vSourceLines.end() );
|
||
|
|
||
|
g_nSourceAssemblyLines = 0;
|
||
|
|
||
|
char *pBegin = g_pSourceBuffer;
|
||
|
char *pEnd = NULL;
|
||
|
char *pEnd2;
|
||
|
while (pBegin)
|
||
|
{
|
||
|
g_nSourceAssemblyLines++;
|
||
|
g_vSourceLines.push_back( pBegin );
|
||
|
|
||
|
pEnd = const_cast<char*>( SkipUntilEOL( pBegin ));
|
||
|
pEnd2 = const_cast<char*>( SkipEOL( pEnd ));
|
||
|
if (pEnd)
|
||
|
{
|
||
|
*pEnd = 0;
|
||
|
}
|
||
|
if (! *pEnd2)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
pBegin = pEnd2;
|
||
|
// *(pEnd-1) = 0;
|
||
|
// if (! pEnd)
|
||
|
// {
|
||
|
// break;
|
||
|
// }
|
||
|
// pEnd = const_cast<char*>( SkipEOL( pEnd ));
|
||
|
// pBegin = pEnd;
|
||
|
}
|
||
|
bStatus = true;
|
||
|
}
|
||
|
|
||
|
if (g_nSourceAssemblyLines)
|
||
|
{
|
||
|
g_bSourceLevelDebugging = true;
|
||
|
}
|
||
|
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
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_END_MEM_ADDRESS + 1;
|
||
|
|
||
|
bool bPrevSymbol = false;
|
||
|
bool bFourBytes = false;
|
||
|
BYTE nByte4 = 0;
|
||
|
|
||
|
|
||
|
int nLines = g_vSourceLines.size();
|
||
|
for( int iLine = 0; iLine < nLines; iLine++ )
|
||
|
{
|
||
|
ZeroMemory( sText, MAX_LINE );
|
||
|
strncpy( sText, g_vSourceLines[ iLine ], 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;
|
||
|
for (int iByte = 0; iByte < 3; iByte++ )
|
||
|
{
|
||
|
// xx xx xx
|
||
|
// ^ ^
|
||
|
// | |
|
||
|
// | end
|
||
|
// start
|
||
|
pStart = pEnd + 1;
|
||
|
pEnd = const_cast<char*>( SkipUntilWhiteSpace( pStart ));
|
||
|
int nLen = (pEnd - pStart);
|
||
|
if (nLen != 2)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
*pEnd = 0;
|
||
|
BYTE nByte = Chars2ToByte( 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<char*>( SkipWhiteSpaceReverse( pLabelEnd, &sLine[ 0 ] ));
|
||
|
char * pLabelStart = NULL; // SkipWhiteSpaceReverse( pLabelEnd, &sLine[ 0 ] );
|
||
|
if (pLabelEnd)
|
||
|
{
|
||
|
pLabelStart = const_cast<char*>( 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][ (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,progdir);
|
||
|
_tcscat(sFileName, pFileName);
|
||
|
|
||
|
if (BufferAssemblyListing( sFileName ))
|
||
|
{
|
||
|
_tcscpy( g_aSourceFileName, pFileName );
|
||
|
|
||
|
if (! ParseAssemblyListing( g_bSourceAddMemory, g_bSourceAddSymbols ))
|
||
|
{
|
||
|
const int MAX_MINI_FILENAME = 20;
|
||
|
TCHAR sMiniFileName[ MAX_MINI_FILENAME + 1 ];
|
||
|
_tcsncpy( sMiniFileName, pFileName, MAX_MINI_FILENAME - 1 );
|
||
|
sMiniFileName[ MAX_MINI_FILENAME ] = 0;
|
||
|
|
||
|
wsprintf( sFileName, "Couldn't load filename: %s", sMiniFileName );
|
||
|
ConsoleBufferPush( sFileName );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
wsprintf( sFileName, " Read: %d lines, %d symbols", g_nSourceAssemblyLines, g_nSourceAssemblySymbols );
|
||
|
|
||
|
if (g_nSourceAssembleBytes)
|
||
|
{
|
||
|
wsprintf( sText, ", %d bytes", g_nSourceAssembleBytes );
|
||
|
_tcscat( sFileName, sText );
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
// Symbols ________________________________________________________________________________________
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdSymbols (int nArgs)
|
||
|
{
|
||
|
if (! nArgs)
|
||
|
return CmdSymbolsInfo( 0 );
|
||
|
|
||
|
Update_t iUpdate = _CmdSymbolsUpdate( nArgs);
|
||
|
if (iUpdate != UPDATE_NOTHING)
|
||
|
return iUpdate;
|
||
|
|
||
|
// return CmdSymbolsList( nArgs );
|
||
|
int bSymbolTables = SYMBOL_TABLE_MAIN | SYMBOL_TABLE_USER | SYMBOL_TABLE_SRC;
|
||
|
return _CmdSymbolsListTables( nArgs, bSymbolTables );
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdSymbolsClear (int nArgs)
|
||
|
{
|
||
|
Symbols_e eSymbolsTable = SYMBOLS_USER;
|
||
|
_CmdSymbolsClear( eSymbolsTable );
|
||
|
return (UPDATE_DISASM | UPDATE_SYMBOLS);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdSymbolsInfo (int nArgs)
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
|
||
|
bool bDisplayMain = false;
|
||
|
bool bDisplayUser = false;
|
||
|
bool bDisplaySrc = false;
|
||
|
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
bDisplayMain = true;
|
||
|
bDisplayUser = true;
|
||
|
bDisplaySrc = true;
|
||
|
}
|
||
|
else
|
||
|
if (CMD_SYMBOLS_MAIN == g_iCommand)
|
||
|
bDisplayMain = true;
|
||
|
else
|
||
|
if (CMD_SYMBOLS_USER == g_iCommand)
|
||
|
bDisplayUser = true;
|
||
|
else
|
||
|
if (CMD_SYMBOLS_SRC == g_iCommand)
|
||
|
bDisplaySrc = true;
|
||
|
|
||
|
int nSymbolsMain = g_aSymbols[SYMBOLS_MAIN].size();
|
||
|
int nSymbolsUser = g_aSymbols[SYMBOLS_USER].size();
|
||
|
int nSymbolsSrc = g_aSymbols[SYMBOLS_SRC ].size();
|
||
|
|
||
|
if (bDisplayMain && bDisplayUser && bDisplaySrc)
|
||
|
{
|
||
|
wsprintf( sText, " Symbols Main: %d User: %d Source: %d",
|
||
|
nSymbolsMain, nSymbolsUser, nSymbolsSrc );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
else
|
||
|
if (bDisplayMain)
|
||
|
{
|
||
|
wsprintf( sText, " Main symbols: %d", nSymbolsMain ); ConsoleBufferPush( sText );
|
||
|
}
|
||
|
else
|
||
|
if (bDisplayUser)
|
||
|
{
|
||
|
wsprintf( sText, " User symbols: %d", nSymbolsUser ); ConsoleBufferPush( sText );
|
||
|
}
|
||
|
else
|
||
|
if (bDisplaySrc)
|
||
|
{
|
||
|
wsprintf( sText, " Source symbols: %d", nSymbolsSrc ); ConsoleBufferPush( sText );
|
||
|
}
|
||
|
|
||
|
if (bDisplayMain || bDisplayUser || bDisplaySrc)
|
||
|
return ConsoleUpdate();
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
void _CmdPrintSymbol( LPCTSTR pSymbol, WORD nAddress, int iTable )
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
wsprintf( sText, " $%04X (%s) %s", nAddress, g_aSymbolTableNames[ iTable ], pSymbol );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//=========================================================================== */
|
||
|
bool _FindSymbolTable( int bSymbolTables, int iTable )
|
||
|
{
|
||
|
// iTable is enumeration
|
||
|
// bSymbolTables is bit-flags of enabled tables to search
|
||
|
|
||
|
if (bSymbolTables & SYMBOL_TABLE_MAIN)
|
||
|
if (iTable == SYMBOLS_MAIN)
|
||
|
return true;
|
||
|
|
||
|
if (bSymbolTables & SYMBOL_TABLE_USER)
|
||
|
if (iTable == SYMBOLS_USER)
|
||
|
return true;
|
||
|
|
||
|
if (bSymbolTables & SYMBOL_TABLE_SRC )
|
||
|
if (iTable == SYMBOLS_SRC)
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
//=========================================================================== */
|
||
|
int _GetSymbolTableFromFlag( int bSymbolTables )
|
||
|
{
|
||
|
int iTable = NUM_SYMBOL_TABLES;
|
||
|
|
||
|
if (bSymbolTables & SYMBOL_TABLE_MAIN)
|
||
|
iTable = SYMBOLS_MAIN;
|
||
|
else
|
||
|
if (bSymbolTables & SYMBOL_TABLE_USER)
|
||
|
iTable = SYMBOLS_USER;
|
||
|
else
|
||
|
if (bSymbolTables & SYMBOL_TABLE_SRC )
|
||
|
iTable = SYMBOLS_SRC;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
bool String2Address( LPCTSTR pText, WORD & nAddress_ )
|
||
|
{
|
||
|
TCHAR sHexApple[ CONSOLE_WIDTH ];
|
||
|
|
||
|
if (pText[0] == TEXT('$'))
|
||
|
{
|
||
|
if (!IsHexString( pText+1))
|
||
|
return false;
|
||
|
|
||
|
_tcscpy( sHexApple, TEXT("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 (!IsHexString( pText+2))
|
||
|
return false;
|
||
|
|
||
|
TCHAR *pEnd;
|
||
|
nAddress_ = (WORD) _tcstol( pText, &pEnd, 16 );
|
||
|
return true;
|
||
|
}
|
||
|
if (IsHexString( pText ))
|
||
|
{
|
||
|
TCHAR *pEnd;
|
||
|
nAddress_ = (WORD) _tcstol( pText, &pEnd, 16 );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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 = SYMBOL_TABLE_MAIN | SYMBOL_TABLE_USER | SYMBOL_TABLE_SRC;
|
||
|
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].nVal1;
|
||
|
LPCTSTR pSymbol = g_aArgs[iArgs].sArg;
|
||
|
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: %04X" ), nAddress );
|
||
|
ConsoleBufferPush( 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"), pSymbol );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintf( sText, TEXT(" Symbol not found: %s"), pSymbol );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ConsoleUpdate();
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
int ParseSymbolTable( TCHAR *pFileName, Symbols_e eWhichTableToLoad )
|
||
|
{
|
||
|
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");
|
||
|
while(hFile && !feof(hFile))
|
||
|
{
|
||
|
// Support 2 types of symbols files:
|
||
|
// 1) AppleWin:
|
||
|
// . 0000 SYMBOL
|
||
|
// . FFFF SYMBOL
|
||
|
// 2) ACME:
|
||
|
// . SYMBOL =$0000; Comment
|
||
|
// . SYMBOL =$FFFF; Comment
|
||
|
//
|
||
|
DWORD INVALID_ADDRESS = 0xFFFF + 1;
|
||
|
DWORD nAddress = INVALID_ADDRESS;
|
||
|
char sName[ MAX_SYMBOLS_LEN+1 ] = "";
|
||
|
|
||
|
const int MAX_LINE = 256;
|
||
|
char szLine[ MAX_LINE ];
|
||
|
fgets(szLine, MAX_LINE-1, hFile); // Get next line
|
||
|
|
||
|
if(strstr(szLine, "$") == NULL)
|
||
|
{
|
||
|
sscanf(szLine, sFormat1, &nAddress, sName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char* p = strstr(szLine, "="); // Optional
|
||
|
if(p) *p = ' ';
|
||
|
p = strstr(szLine, "$");
|
||
|
if(p) *p = ' ';
|
||
|
p = strstr(szLine, ";"); // Optional
|
||
|
if(p) *p = 0;
|
||
|
p = strstr(szLine, " "); // 1st space between name & value
|
||
|
int nLen = p - szLine;
|
||
|
if (nLen > 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);
|
||
|
}
|
||
|
|
||
|
if( (nAddress >= INVALID_ADDRESS) || (sName[0] == 0) )
|
||
|
continue;
|
||
|
|
||
|
g_aSymbols[ eWhichTableToLoad ] [ (WORD) nAddress ] = sName;
|
||
|
nSymbolsLoaded++;
|
||
|
}
|
||
|
|
||
|
if(hFile)
|
||
|
fclose(hFile);
|
||
|
|
||
|
return nSymbolsLoaded;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdSymbolsLoad (int nArgs)
|
||
|
{
|
||
|
TCHAR sFileName[MAX_PATH];
|
||
|
_tcscpy(sFileName,progdir);
|
||
|
|
||
|
int iWhichTable = (g_iCommand - CMD_SYMBOLS_MAIN);
|
||
|
if ((iWhichTable < 0) || (iWhichTable >= NUM_SYMBOL_TABLES))
|
||
|
{
|
||
|
wsprintf( sFileName, "Only %d symbol tables supported!", NUM_SYMBOL_TABLES );
|
||
|
return ConsoleDisplayError( sFileName );
|
||
|
}
|
||
|
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
// Default to main table
|
||
|
if (g_iCommand == CMD_SYMBOLS_MAIN)
|
||
|
_tcscat(sFileName, g_FileNameSymbolsMain );
|
||
|
else
|
||
|
{
|
||
|
if (! _tcslen( g_FileNameSymbolsUser ))
|
||
|
{
|
||
|
return ConsoleDisplayError(TEXT("No user symbol file to reload."));
|
||
|
}
|
||
|
// load user symbols
|
||
|
_tcscat( sFileName, g_FileNameSymbolsUser );
|
||
|
}
|
||
|
g_nSymbolsLoaded = ParseSymbolTable( sFileName, (Symbols_e) iWhichTable );
|
||
|
|
||
|
return (UPDATE_DISASM || UPDATE_SYMBOLS);
|
||
|
}
|
||
|
|
||
|
int iArg = 0;
|
||
|
while (iArg++ <= nArgs)
|
||
|
{
|
||
|
TCHAR *pFileName = g_aArgs[ iArg ].sArg;
|
||
|
|
||
|
_tcscpy(sFileName,progdir);
|
||
|
_tcscat(sFileName, pFileName);
|
||
|
|
||
|
// Remember File ame of symbols loaded
|
||
|
_tcscpy( g_FileNameSymbolsUser, pFileName );
|
||
|
|
||
|
g_nSymbolsLoaded = ParseSymbolTable( sFileName, (Symbols_e) iWhichTable );
|
||
|
}
|
||
|
|
||
|
return (UPDATE_DISASM || UPDATE_SYMBOLS);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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<WORD, string>::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;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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<WORD, string>::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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
WORD GetAddressFromSymbol (LPCTSTR pSymbol)
|
||
|
{
|
||
|
WORD nAddress;
|
||
|
bool bFoundSymbol = FindAddressFromSymbol( pSymbol, & nAddress );
|
||
|
if (! bFoundSymbol)
|
||
|
{
|
||
|
nAddress = 0;
|
||
|
}
|
||
|
return nAddress;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t _CmdSymbolsClear( Symbols_e eSymbolTable )
|
||
|
{
|
||
|
g_aSymbols[ eSymbolTable ].clear();
|
||
|
|
||
|
return UPDATE_SYMBOLS;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t _CmdSymbolsUpdate( int nArgs )
|
||
|
{
|
||
|
bool bRemoveSymbol = false;
|
||
|
bool bUpdateSymbol = false;
|
||
|
|
||
|
if ((nArgs == 2) && (g_aArgs[ 1 ].eToken == TOKEN_EXCLAMATION))
|
||
|
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].nVal1;
|
||
|
|
||
|
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 == SYMBOLS_USER)
|
||
|
{
|
||
|
if (bRemoveSymbol)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT(" Removing symbol." ) );
|
||
|
}
|
||
|
|
||
|
g_aSymbols[SYMBOLS_USER].erase( nAddressPrev );
|
||
|
|
||
|
if (bUpdateSymbol)
|
||
|
{
|
||
|
ConsoleBufferPush( TEXT(" Updating symbol to new address." ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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[SYMBOLS_USER][ nAddress ] = pSymbolName;
|
||
|
}
|
||
|
|
||
|
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 );
|
||
|
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( (Symbols_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);
|
||
|
CmdSymbolsLoad( nArgs );
|
||
|
|
||
|
int iTable = _GetSymbolTableFromFlag( bSymbolTables );
|
||
|
if (iTable != NUM_SYMBOL_TABLES)
|
||
|
{
|
||
|
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 );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return ConsoleUpdate();
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdSymbolsMain (int nArgs)
|
||
|
{
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
return CmdSymbolsInfo( nArgs );
|
||
|
}
|
||
|
|
||
|
return _CmdSymbolsCommon( nArgs, SYMBOL_TABLE_MAIN ); // SYMBOLS_MAIN );
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdSymbolsUser (int nArgs)
|
||
|
{
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
return CmdSymbolsInfo( nArgs );
|
||
|
}
|
||
|
|
||
|
return _CmdSymbolsCommon( nArgs, SYMBOL_TABLE_USER ); // SYMBOLS_USER );
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdSymbolsSource (int nArgs)
|
||
|
{
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
return CmdSymbolsInfo( nArgs );
|
||
|
}
|
||
|
|
||
|
return _CmdSymbolsCommon( nArgs, SYMBOL_TABLE_SRC ); // SYMBOLS_SRC );
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
LPCTSTR GetSymbol (WORD nAddress, int nBytes)
|
||
|
{
|
||
|
LPCSTR pSymbol = FindSymbolFromAddress( nAddress );
|
||
|
if (pSymbol)
|
||
|
return pSymbol;
|
||
|
|
||
|
return FormatAddress( nAddress, nBytes );
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdSymbolsSave (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
// CPU Step, Trace ________________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdGo (int nArgs)
|
||
|
{
|
||
|
g_nDebugSteps = -1;
|
||
|
g_nDebugStepCycles = 0;
|
||
|
g_nDebugStepStart = regs.pc;
|
||
|
g_nDebugStepUntil = nArgs ? g_aArgs[1].nVal1 : -1;
|
||
|
g_nDebugSkipStart = -1;
|
||
|
g_nDebugSkipLen = -1;
|
||
|
|
||
|
// Extended Go ... addr_skip, len
|
||
|
if (nArgs > 1)
|
||
|
{
|
||
|
int iArg = 2;
|
||
|
|
||
|
g_nDebugSkipStart = g_aArgs[ iArg ].nVal1;
|
||
|
WORD nAddress = g_aArgs[ iArg ].nVal2;
|
||
|
|
||
|
// int nSlack = (_6502_END_MEM_ADDRESS + 1) - nAddress;
|
||
|
// int nWantedLength = g_aArgs[iArg].nVal2;
|
||
|
// g_nDebugSkipLen = MIN( nSlack, nWantedLength );
|
||
|
int nEnd = nAddress - g_nDebugSkipStart;
|
||
|
if (nEnd < 0)
|
||
|
g_nDebugSkipLen = g_nDebugSkipStart - nAddress;
|
||
|
else
|
||
|
g_nDebugSkipLen = nAddress - g_nDebugSkipStart;
|
||
|
|
||
|
g_nDebugSkipLen &= _6502_END_MEM_ADDRESS;
|
||
|
}
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
mode = 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].nVal1 : 1;
|
||
|
WORD nDebugSteps = nArgs ? g_aArgs[1].nVal1 : 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 == ADDR_ABS) &&
|
||
|
|
||
|
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 (_Get6502ReturnAddress( 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].nVal1 : 1;
|
||
|
g_nDebugStepCycles = 0;
|
||
|
g_nDebugStepStart = regs.pc;
|
||
|
g_nDebugStepUntil = -1;
|
||
|
mode = MODE_STEPPING;
|
||
|
FrameRefreshStatus(DRAW_TITLE);
|
||
|
DebugContinueStepping();
|
||
|
|
||
|
return UPDATE_ALL; // TODO: Verify // 0
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdTraceFile (int nArgs) {
|
||
|
if (g_hTraceFile)
|
||
|
fclose(g_hTraceFile);
|
||
|
|
||
|
TCHAR filename[MAX_PATH];
|
||
|
_tcscpy(filename,progdir);
|
||
|
_tcscat(filename,(nArgs && g_aArgs[1].sArg[0]) ? g_aArgs[1].sArg : g_FileNameTrace );
|
||
|
g_hTraceFile = fopen(filename,TEXT("wt"));
|
||
|
|
||
|
return UPDATE_ALL; // TODO: Verify // 0
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdTraceLine (int nArgs)
|
||
|
{
|
||
|
g_nDebugSteps = nArgs ? g_aArgs[1].nVal1 : 1;
|
||
|
g_nDebugStepCycles = 1;
|
||
|
g_nDebugStepStart = regs.pc;
|
||
|
g_nDebugStepUntil = -1;
|
||
|
|
||
|
mode = MODE_STEPPING;
|
||
|
FrameRefreshStatus(DRAW_TITLE);
|
||
|
DebugContinueStepping();
|
||
|
|
||
|
return UPDATE_ALL; // TODO: Verify // 0
|
||
|
}
|
||
|
|
||
|
|
||
|
// Variables ______________________________________________________________________________________
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdVarsClear (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdVarsDefine (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdVarsDefineInt8 (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdVarsDefineInt16 (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdVarsList (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdVarsLoad (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdVarsSave (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdVarsSet (int nArgs)
|
||
|
{
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Watches ________________________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdWatchAdd (int nArgs)
|
||
|
{
|
||
|
if (!nArgs)
|
||
|
return Help_Arg_1( CMD_WATCH_ADD );
|
||
|
|
||
|
bool bAdded = false;
|
||
|
int iArg = 0;
|
||
|
|
||
|
while (iArg++ < nArgs)
|
||
|
{
|
||
|
WORD nAddress = g_aArgs[iArg].nVal1;
|
||
|
{
|
||
|
// FIND A FREE SLOT FOR THIS NEW WATCH
|
||
|
int iWatch = 0;
|
||
|
while ((iWatch < MAX_WATCHES) && (g_aWatches[iWatch].bSet))
|
||
|
iWatch++;
|
||
|
if ((iWatch >= MAX_WATCHES) && !bAdded)
|
||
|
return ConsoleDisplayError(TEXT("All watches slots are currently in use."));
|
||
|
|
||
|
// VERIFY THAT THE WATCH IS NOT ON AN I/O LOCATION
|
||
|
if ((nAddress >= _6502_IO_BEGIN) && (nAddress <= _6502_IO_END))
|
||
|
return ConsoleDisplayError(TEXT("You may not watch an I/O location."));
|
||
|
|
||
|
// ADD THE WATCH
|
||
|
if (iWatch < MAX_WATCHES) {
|
||
|
g_aWatches[iWatch].bSet = true;
|
||
|
g_aWatches[iWatch].bEnabled = true;
|
||
|
g_aWatches[iWatch].nAddress = nAddress;
|
||
|
bAdded = true;
|
||
|
g_nWatches++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bAdded)
|
||
|
return Help_Arg_1( CMD_WATCH_ADD );
|
||
|
|
||
|
return UPDATE_WATCH; // 1;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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 );
|
||
|
|
||
|
_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 );
|
||
|
|
||
|
_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 );
|
||
|
|
||
|
_EnableDisableViaArgs( nArgs, g_aWatches, MAX_WATCHES, true );
|
||
|
|
||
|
return UPDATE_WATCH;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdWatchList (int nArgs)
|
||
|
{
|
||
|
int iWatch = 0;
|
||
|
while (iWatch < MAX_WATCHES)
|
||
|
{
|
||
|
if (g_aWatches[ iWatch ].bSet)
|
||
|
{
|
||
|
_ListBreakWatchZero( g_aWatches, iWatch );
|
||
|
}
|
||
|
iWatch++;
|
||
|
}
|
||
|
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 _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_COLORS)
|
||
|
{
|
||
|
// COLORREF nColor = g_aColors[ iScheme ][ iColor ];
|
||
|
DebugColors_e eColor = static_cast<DebugColors_e>( iColor );
|
||
|
COLORREF nColor = DebugGetColor( eColor );
|
||
|
_ColorPrint( iColor, nColor );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
wsprintf( sText, "Color: %d\nOut of range!", iColor );
|
||
|
MessageBox( framewindow, sText, TEXT("ERROR"), MB_OK );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
inline COLORREF DebugGetColor( 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_COLORS))
|
||
|
{
|
||
|
nColor = g_aColors[ g_iColorScheme ][ iColor ];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
if (SCHEME_COLOR == g_iColorScheme)
|
||
|
// nColor = gaColorValue[ iColor ];
|
||
|
// nColor = gaColorPalette[ g_aColorIndex[ iColor ] ];
|
||
|
else
|
||
|
if (SCHEME_MONO == g_iColorScheme)
|
||
|
nColor = gaMonoValue[ iColor ];
|
||
|
// nColor = gaMonoPalette[ g_aColorIndex[ iColor ] ];
|
||
|
*/
|
||
|
return nColor;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool DebugSetColor( const int iScheme, const int iColor, const COLORREF nColor )
|
||
|
{
|
||
|
bool bStatus = false;
|
||
|
if ((g_iColorScheme < NUM_COLOR_SCHEMES) && (iColor < NUM_COLORS))
|
||
|
{
|
||
|
g_aColors[ iScheme ][ iColor ] = nColor;
|
||
|
bStatus = true;
|
||
|
}
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdConfigColorMono (int nArgs)
|
||
|
{
|
||
|
int iScheme;
|
||
|
|
||
|
if (g_iCommand == CMD_CONFIG_COLOR)
|
||
|
iScheme = SCHEME_COLOR;
|
||
|
if (g_iCommand == CMD_CONFIG_MONOCHROME)
|
||
|
iScheme = SCHEME_MONO;
|
||
|
|
||
|
if ((iScheme < 0) || (iScheme > NUM_COLOR_SCHEMES)) // sanity check
|
||
|
iScheme = SCHEME_COLOR;
|
||
|
|
||
|
if (! nArgs)
|
||
|
{
|
||
|
g_iColorScheme = iScheme;
|
||
|
UpdateDisplay( UPDATE_BACKGROUND ); // 1
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
|
||
|
if ((nArgs != 1) && (nArgs != 4))
|
||
|
return Help_Arg_1( g_iCommand );
|
||
|
|
||
|
int iColor = g_aArgs[ 1 ].nVal1;
|
||
|
if ((iColor < 0) || iColor >= NUM_COLORS)
|
||
|
return Help_Arg_1( g_iCommand );
|
||
|
|
||
|
if (nArgs == 1)
|
||
|
{ // Dump Color
|
||
|
_CmdColorGet( iScheme, iColor );
|
||
|
return ConsoleUpdate();
|
||
|
}
|
||
|
else
|
||
|
{ // Set Color
|
||
|
int R = g_aArgs[2].nVal1 & 0xFF;
|
||
|
int G = g_aArgs[3].nVal1 & 0xFF;
|
||
|
int B = g_aArgs[4].nVal1 & 0xFF;
|
||
|
COLORREF nColor = RGB(R,G,B);
|
||
|
|
||
|
DebugSetColor( iScheme, iColor, nColor );
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Update_t CmdConfigHColor (int nArgs)
|
||
|
{
|
||
|
if ((nArgs != 1) && (nArgs != 4))
|
||
|
return Help_Arg_1( g_iCommand );
|
||
|
|
||
|
int iColor = g_aArgs[ 1 ].nVal1;
|
||
|
if ((iColor < 0) || iColor >= NUM_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
|
||
|
// DebugSetColor( iScheme, iColor );
|
||
|
return UPDATE_ALL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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_nConsoleDisplayHeight = MIN_DISPLAY_CONSOLE_LINES;
|
||
|
g_nConsoleDisplayWidth = (CONSOLE_WIDTH / 2) + 8;
|
||
|
g_bConsoleFullWidth = false;
|
||
|
|
||
|
if (g_iWindowThis == WINDOW_CONSOLE)
|
||
|
{
|
||
|
g_nConsoleDisplayHeight = MAX_DISPLAY_CONSOLE_LINES;
|
||
|
g_nConsoleDisplayWidth = CONSOLE_WIDTH - 1;
|
||
|
g_bConsoleFullWidth = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
int WindowGetHeight( int iWindow )
|
||
|
{
|
||
|
// if (iWindow == WINDOW_CODE)
|
||
|
return g_nDisasmWinHeight;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void WindowUpdateDisasmSize()
|
||
|
{
|
||
|
if (g_aWindowConfig[ g_iWindowThis ].bSplit)
|
||
|
{
|
||
|
g_nDisasmWinHeight = (MAX_DISPLAY_DISASM_LINES) / 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_nDisasmWinHeight = MAX_DISPLAY_DISASM_LINES;
|
||
|
}
|
||
|
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)
|
||
|
{
|
||
|
if (!nArgs)
|
||
|
return Help_Arg_1( CMD_ZEROPAGE_POINTER );
|
||
|
|
||
|
return UPDATE_CONSOLE_DISPLAY;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdZeroPageAdd (int nArgs)
|
||
|
{
|
||
|
if (!nArgs)
|
||
|
return Help_Arg_1( CMD_ZEROPAGE_POINTER_ADD );
|
||
|
|
||
|
bool bAdded = false;
|
||
|
int iArg = 0;
|
||
|
while (iArg++ < nArgs)
|
||
|
{
|
||
|
WORD nAddress = g_aArgs[iArg].nVal1;
|
||
|
{
|
||
|
int iZP = 0;
|
||
|
while ((iZP < MAX_ZEROPAGE_POINTERS) && (g_aZeroPagePointers[iZP].bSet))
|
||
|
{
|
||
|
iZP++;
|
||
|
}
|
||
|
if ((iZP >= MAX_ZEROPAGE_POINTERS) && !bAdded)
|
||
|
return ConsoleDisplayError(TEXT("All (ZP) pointers are currently in use."));
|
||
|
|
||
|
if (iZP < MAX_ZEROPAGE_POINTERS)
|
||
|
{
|
||
|
g_aZeroPagePointers[iZP].bSet = true;
|
||
|
g_aZeroPagePointers[iZP].bEnabled = true;
|
||
|
g_aZeroPagePointers[iZP].nAddress = (BYTE) nAddress;
|
||
|
bAdded = true;
|
||
|
g_nZeroPagePointers++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bAdded)
|
||
|
return Help_Arg_1( CMD_ZEROPAGE_POINTER_ADD );
|
||
|
|
||
|
return UPDATE_ZERO_PAGE;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdZeroPageClear (int nArgs)
|
||
|
{
|
||
|
if (!g_nBreakpoints)
|
||
|
return ConsoleDisplayError(TEXT("There are no (ZP) pointers defined."));
|
||
|
|
||
|
// CHECK FOR ERRORS
|
||
|
if (!nArgs)
|
||
|
return Help_Arg_1( CMD_ZEROPAGE_POINTER_CLEAR );
|
||
|
|
||
|
_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 ConsoleDisplayError(TEXT("There are no (ZP) pointers defined."));
|
||
|
|
||
|
_EnableDisableViaArgs( nArgs, g_aZeroPagePointers, MAX_ZEROPAGE_POINTERS, false );
|
||
|
|
||
|
return UPDATE_ZERO_PAGE;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdZeroPageEnable (int nArgs)
|
||
|
{
|
||
|
if (! g_nZeroPagePointers)
|
||
|
return ConsoleDisplayError(TEXT("There are no (ZP) pointers defined."));
|
||
|
|
||
|
if (!nArgs)
|
||
|
return Help_Arg_1( CMD_ZEROPAGE_POINTER_ENABLE );
|
||
|
|
||
|
_EnableDisableViaArgs( nArgs, g_aZeroPagePointers, MAX_ZEROPAGE_POINTERS, true );
|
||
|
|
||
|
return UPDATE_ZERO_PAGE;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t CmdZeroPageList (int nArgs)
|
||
|
{
|
||
|
int iZP = 0;
|
||
|
while (iZP < MAX_ZEROPAGE_POINTERS)
|
||
|
{
|
||
|
if (g_aZeroPagePointers[ iZP ].bEnabled)
|
||
|
{
|
||
|
_ListBreakWatchZero( g_aZeroPagePointers, iZP );
|
||
|
}
|
||
|
iZP++;
|
||
|
}
|
||
|
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] <ZeroPageAddr> : 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].nVal1;
|
||
|
g_aZeroPagePointers[iZP].nAddress = (BYTE) nAddress;
|
||
|
}
|
||
|
|
||
|
return UPDATE_ZERO_PAGE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Drawing ________________________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawBreakpoints (HDC dc, 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;
|
||
|
TCHAR sText[16] = TEXT("Breakpoints"); // TODO: Move to BP1
|
||
|
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO )); // COLOR_BG_DATA
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_TITLE )); //COLOR_STATIC
|
||
|
DebugDrawText( sText, rect );
|
||
|
rect.top += g_nFontHeight;
|
||
|
rect.bottom += g_nFontHeight;
|
||
|
|
||
|
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;
|
||
|
|
||
|
RECT rect2;
|
||
|
rect2 = rect;
|
||
|
|
||
|
SetBkColor( dc, DebugGetColor( BG_INFO ));
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_BULLET ) );
|
||
|
wsprintf( sText, TEXT("%d"), iBreakpoint+1 );
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_OPERATOR ) );
|
||
|
_tcscpy( sText, TEXT(":") );
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
pBP->eSource = (BreakpointSource_t) iBreakpoint;
|
||
|
#endif
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_REG ) );
|
||
|
int nRegLen = DebugDrawTextFixed( g_aBreakpointSource[ pBP->eSource ], rect2 );
|
||
|
|
||
|
// Pad to 2 chars
|
||
|
if (nRegLen < 2) // (g_aBreakpointSource[ pBP->eSource ][1] == 0) // HACK: Avoid strlen()
|
||
|
rect2.left += g_aFontConfig[ FONT_INFO ]._nFontWidthAvg;
|
||
|
|
||
|
SetBkColor( dc, DebugGetColor( BG_INFO ));
|
||
|
SetTextColor( dc, DebugGetColor( 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
|
||
|
DebugDrawTextFixed( 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;
|
||
|
}
|
||
|
|
||
|
SetBkColor( dc, DebugGetColor( iBackground ) );
|
||
|
SetTextColor( dc, DebugGetColor( iForeground ) );
|
||
|
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
int iColor = R8 + (iBreakpoint*2);
|
||
|
COLORREF nColor = gaColorPalette[ iColor ];
|
||
|
if (iBreakpoint >= 4)
|
||
|
{
|
||
|
SetBkColor ( dc, DebugGetColor( BG_DISASM_BP_S_C ) );
|
||
|
nColor = DebugGetColor( FG_DISASM_BP_S_C );
|
||
|
}
|
||
|
SetTextColor( dc, nColor );
|
||
|
#endif
|
||
|
|
||
|
wsprintf( sText, TEXT("%04X"), nAddress1 );
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
|
||
|
if (nLength > 1)
|
||
|
{
|
||
|
SetBkColor( dc, DebugGetColor( BG_INFO ) );
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_OPERATOR ) );
|
||
|
|
||
|
// if (g_bConfigDisasmOpcodeSpaces)
|
||
|
// {
|
||
|
// DebugDrawTextHorz( TEXT(" "), rect2 );
|
||
|
// rect2.left += g_nFontWidthAvg;
|
||
|
// }
|
||
|
|
||
|
DebugDrawTextFixed( TEXT("-"), rect2 );
|
||
|
// rect2.left += g_nFontWidthAvg;
|
||
|
// if (g_bConfigDisasmOpcodeSpaces) // TODO: Might have to remove spaces, for BPIO... addr-addr xx
|
||
|
// {
|
||
|
// rect2.left += g_nFontWidthAvg;
|
||
|
// }
|
||
|
|
||
|
SetBkColor( dc, DebugGetColor( iBackground ) );
|
||
|
SetTextColor( dc, DebugGetColor( iForeground ) );
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
iColor++;
|
||
|
COLORREF nColor = gaColorPalette[ iColor ];
|
||
|
if (iBreakpoint >= 4)
|
||
|
{
|
||
|
nColor = DebugGetColor( BG_INFO );
|
||
|
SetBkColor( dc, nColor );
|
||
|
nColor = DebugGetColor( FG_DISASM_BP_S_X );
|
||
|
}
|
||
|
SetTextColor( dc, nColor );
|
||
|
#endif
|
||
|
wsprintf( sText, TEXT("%04X"), nAddress2 );
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
}
|
||
|
|
||
|
// Bugfix: Rest of line is still breakpoint background color
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO )); // COLOR_BG_DATA
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_TITLE )); //COLOR_STATIC
|
||
|
DebugDrawTextHorz( TEXT(" "), rect2 );
|
||
|
|
||
|
}
|
||
|
rect.top += g_nFontHeight;
|
||
|
rect.bottom += g_nFontHeight;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawConsoleInput( HDC dc )
|
||
|
{
|
||
|
g_hDC = dc;
|
||
|
|
||
|
SetTextColor( g_hDC, DebugGetColor( FG_CONSOLE_INPUT ));
|
||
|
SetBkColor( g_hDC, DebugGetColor( BG_CONSOLE_INPUT ));
|
||
|
|
||
|
DrawConsoleLine( g_aConsoleInput, 0 );
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawConsoleLine( LPCSTR pText, int y )
|
||
|
{
|
||
|
if (y < 0)
|
||
|
return;
|
||
|
|
||
|
// int nHeight = WindowGetHeight( g_iWindowThis );
|
||
|
int nLineHeight = GetConsoleHeightPixels();
|
||
|
|
||
|
RECT rect;
|
||
|
rect.left = 0;
|
||
|
// rect.top = (g_nTotalLines - y) * nFontHeight; // DISPLAY_HEIGHT - (y * nFontHeight); // ((g_nTotalLines - y) * g_nFontHeight; // 368 = 23 lines * 16 pixels/line // MAX_DISPLAY_CONSOLE_LINES
|
||
|
|
||
|
rect.top = GetConsoleTopPixels( y );
|
||
|
rect.bottom = rect.top + nLineHeight; //g_nFontHeight;
|
||
|
|
||
|
// Default: (356-14) = 342 pixels ~= 48 chars (7 pixel width)
|
||
|
// rect.right = SCREENSPLIT1-14;
|
||
|
// rect.right = (g_nConsoleDisplayWidth * g_nFontWidthAvg) + (g_nFontWidthAvg - 1);
|
||
|
|
||
|
int nMiniConsoleRight = DISPLAY_MINI_CONSOLE; // (g_nConsoleDisplayWidth * g_nFontWidthAvg) + (g_nFontWidthAvg * 2); // +14
|
||
|
int nFullConsoleRight = DISPLAY_WIDTH;
|
||
|
int nRight = g_bConsoleFullWidth ? nFullConsoleRight : nMiniConsoleRight;
|
||
|
rect.right = nRight;
|
||
|
|
||
|
DebugDrawText( pText, rect );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Disassembly formatting flags returned
|
||
|
//===========================================================================
|
||
|
int FormatDisassemblyLine( WORD nOffset, int iMode, int nOpBytes,
|
||
|
char *sAddress_, char *sOpCodes_, char *sTarget_, char *sTargetOffset_, int & nTargetOffset_, char * sImmediate_, char & nImmediate_, char *sBranch_ )
|
||
|
{
|
||
|
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;
|
||
|
nTargetOffset_ = 0;
|
||
|
|
||
|
// if (g_aOpmodes[ iMode ]._sFormat[0])
|
||
|
if ((iMode != AM_IMPLIED) &&
|
||
|
(iMode != AM_1) &&
|
||
|
(iMode != AM_2) &&
|
||
|
(iMode != AM_3))
|
||
|
{
|
||
|
nTarget = *(LPWORD)(mem+nOffset+1);
|
||
|
if (nOpBytes == 2)
|
||
|
nTarget &= 0xFF;
|
||
|
|
||
|
if (iMode == AM_R) // Relative ADDR_REL)
|
||
|
{
|
||
|
nTarget = nOffset+2+(int)(signed char)nTarget;
|
||
|
|
||
|
// Always show branch indicators
|
||
|
// if ((nOffset == regs.pc) && CheckJump(nAddress))
|
||
|
bDisasmFormatFlags |= DISASM_BRANCH_INDICATOR;
|
||
|
|
||
|
if (nTarget < nOffset)
|
||
|
{
|
||
|
wsprintf( sBranch_, TEXT("%c"), g_sConfigBranchIndicatorUp[ g_bConfigDisasmFancyBranch ] );
|
||
|
}
|
||
|
else
|
||
|
if (nTarget > nOffset)
|
||
|
{
|
||
|
wsprintf( sBranch_, TEXT("%c"), g_sConfigBranchIndicatorDown[ g_bConfigDisasmFancyBranch ] );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintf( sBranch_, TEXT("%c"), g_sConfigBranchIndicatorEqual[ g_bConfigDisasmFancyBranch ] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if (_tcsstr(g_aOpmodes[ iMode ]._sFormat,TEXT("%s")))
|
||
|
// if ((iMode >= ADDR_ABS) && (iMode <= ADDR_IABS))
|
||
|
if ((iMode == ADDR_ABS ) ||
|
||
|
(iMode == ADDR_ZP ) ||
|
||
|
(iMode == ADDR_ABSX) ||
|
||
|
(iMode == ADDR_ABSY) ||
|
||
|
(iMode == ADDR_ZP_X) ||
|
||
|
(iMode == ADDR_ZP_Y) ||
|
||
|
(iMode == ADDR_REL ) ||
|
||
|
(iMode == ADDR_INDX) ||
|
||
|
(iMode == ADDR_ABSIINDX) ||
|
||
|
(iMode == ADDR_INDY) ||
|
||
|
(iMode == ADDR_ABS ) ||
|
||
|
(iMode == ADDR_IZPG) ||
|
||
|
(iMode == ADDR_IABS))
|
||
|
{
|
||
|
LPCTSTR pTarget = NULL;
|
||
|
LPCTSTR pSymbol = FindSymbolFromAddress( nTarget );
|
||
|
if (pSymbol)
|
||
|
{
|
||
|
bDisasmFormatFlags |= DISASM_TARGET_SYMBOL;
|
||
|
pTarget = pSymbol;
|
||
|
}
|
||
|
|
||
|
if (! (bDisasmFormatFlags & DISASM_TARGET_SYMBOL))
|
||
|
{
|
||
|
pSymbol = FindSymbolFromAddress( nTarget - 1 );
|
||
|
if (pSymbol)
|
||
|
{
|
||
|
bDisasmFormatFlags |= DISASM_TARGET_SYMBOL;
|
||
|
bDisasmFormatFlags |= DISASM_TARGET_OFFSET;
|
||
|
pTarget = pSymbol;
|
||
|
nTargetOffset_ = +1; // U FA82 LDA #3F1 BREAK+1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (! (bDisasmFormatFlags & DISASM_TARGET_SYMBOL))
|
||
|
{
|
||
|
pSymbol = FindSymbolFromAddress( nTarget + 1 );
|
||
|
if (pSymbol)
|
||
|
{
|
||
|
bDisasmFormatFlags |= DISASM_TARGET_SYMBOL;
|
||
|
bDisasmFormatFlags |= DISASM_TARGET_OFFSET;
|
||
|
pTarget = pSymbol;
|
||
|
nTargetOffset_ = -1; // U FA82 LDA #3F3 BREAK-1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (! (bDisasmFormatFlags & DISASM_TARGET_SYMBOL))
|
||
|
{
|
||
|
pTarget = FormatAddress( nTarget, nOpBytes );
|
||
|
}
|
||
|
|
||
|
// wsprintf( sTarget, g_aOpmodes[ iMode ]._sFormat, pTarget );
|
||
|
if (bDisasmFormatFlags & DISASM_TARGET_OFFSET)
|
||
|
{
|
||
|
int nAbsTargetOffset = (nTargetOffset_ > 0) ? nTargetOffset_ : -nTargetOffset_;
|
||
|
wsprintf( sTargetOffset_, "%d", nAbsTargetOffset );
|
||
|
}
|
||
|
wsprintf( sTarget_, "%s", pTarget );
|
||
|
}
|
||
|
else
|
||
|
if (iMode == AM_M)
|
||
|
{
|
||
|
// wsprintf( sTarget, g_aOpmodes[ iMode ]._sFormat, (unsigned)nTarget );
|
||
|
wsprintf( sTarget_, "%02X", (unsigned)nTarget );
|
||
|
|
||
|
if (iMode == ADDR_IMM)
|
||
|
{
|
||
|
bDisasmFormatFlags |= DISASM_IMMEDIATE_CHAR;
|
||
|
nImmediate_ = (BYTE) nTarget;
|
||
|
wsprintf( sImmediate_, "%c", FormatCharTxtCtrl( FormatCharTxtHigh( nImmediate_, NULL ), NULL ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
wsprintf( sAddress_, "%04X", nOffset );
|
||
|
|
||
|
// Opcode Bytes
|
||
|
TCHAR *pDst = sOpCodes_;
|
||
|
for( int iBytes = 0; iBytes < nOpBytes; iBytes++ )
|
||
|
{
|
||
|
BYTE nMem = (unsigned)*(mem+nOffset+iBytes);
|
||
|
wsprintf( pDst, TEXT("%02X"), nMem ); // sBytes+_tcslen(sBytes)
|
||
|
pDst += 2;
|
||
|
|
||
|
if (g_bConfigDisasmOpcodeSpaces)
|
||
|
{
|
||
|
_tcscat( pDst, TEXT(" " ) );
|
||
|
}
|
||
|
pDst++;
|
||
|
}
|
||
|
while (_tcslen(sOpCodes_) < nMinBytesLen)
|
||
|
{
|
||
|
_tcscat( sOpCodes_, TEXT(" ") );
|
||
|
}
|
||
|
|
||
|
return bDisasmFormatFlags;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
WORD DrawDisassemblyLine (HDC dc, int iLine, WORD nOffset, LPTSTR text)
|
||
|
{
|
||
|
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
|
||
|
return 0;
|
||
|
|
||
|
const int nMaxAddressLen = 40;
|
||
|
const int nMaxOpcodes = 3;
|
||
|
|
||
|
int iOpcode;
|
||
|
int iOpmode;
|
||
|
int nOpbyte;
|
||
|
iOpcode = _6502GetOpmodeOpbyte( nOffset, iOpmode, nOpbyte );
|
||
|
|
||
|
TCHAR sAddress [ 5];
|
||
|
TCHAR sOpcodes [(nMaxOpcodes*3)+1] = TEXT("");
|
||
|
TCHAR sTarget [nMaxAddressLen] = TEXT("");
|
||
|
TCHAR sTargetOffset[ 4 ] = TEXT(""); // +/- 255, realistically +/-1
|
||
|
int nTargetOffset;
|
||
|
char nImmediate = 0;
|
||
|
TCHAR sImmediate[ 4 ]; // 'c'
|
||
|
TCHAR sBranch [ 2 ]; // ^
|
||
|
|
||
|
bool bTargetIndirect = false;
|
||
|
bool bTargetX = false;
|
||
|
bool bTargetY = false;
|
||
|
|
||
|
if ((iOpmode >= ADDR_INDX) && (iOpmode <= ADDR_IABS))
|
||
|
bTargetIndirect = true;
|
||
|
|
||
|
if ((iOpmode == ADDR_ABSX) || (iOpmode == ADDR_ZP_X) || (iOpmode == ADDR_INDX) || (iOpmode == ADDR_ABSIINDX))
|
||
|
bTargetX = true;
|
||
|
|
||
|
if ((iOpmode == ADDR_ABSY) || (iOpmode == ADDR_ZP_Y))
|
||
|
bTargetY = true;
|
||
|
|
||
|
int bDisasmFormatFlags = FormatDisassemblyLine( nOffset, iOpmode, nOpbyte,
|
||
|
sAddress, sOpcodes, sTarget, sTargetOffset, nTargetOffset, sImmediate, nImmediate, sBranch );
|
||
|
|
||
|
// wsprintf(sLine,
|
||
|
// TEXT("%04X%c %s %-9s %s %s"),
|
||
|
// (unsigned)nOffset,
|
||
|
// g_aConfigDisasmAddressColon[ g_bConfigDisasmAddressColon ],
|
||
|
// (LPCTSTR)sBytes,
|
||
|
// (LPCTSTR)GetSymbol(nOffset,0), // Label
|
||
|
// (LPCTSTR)g_aOpcodes[nOpcode].mnemonic, // Instruct
|
||
|
// (LPCTSTR)sTarget); // Target
|
||
|
|
||
|
|
||
|
//> Address Seperator Opcodes Label Mnemonic Target [Immediate] [Branch]
|
||
|
//> xxxx: xx xx xx LABEL MNEMONIC 'E' v
|
||
|
//> ^ ^ ^ ^ ^
|
||
|
//> 6 17 27 41 46
|
||
|
const int nDefaultFontWidth = 7; // g_aFontConfig[FONT_DISASM_DEFAULT]._nFontWidth or g_nFontWidthAvg
|
||
|
int X_OPCODE = 6 * nDefaultFontWidth;
|
||
|
int X_LABEL = 17 * nDefaultFontWidth;
|
||
|
int X_INSTRUCTION = 27 * nDefaultFontWidth;
|
||
|
int X_IMMEDIATE = 41 * nDefaultFontWidth;
|
||
|
int X_BRANCH = 46 * nDefaultFontWidth;
|
||
|
|
||
|
const int DISASM_SYMBOL_LEN = 9;
|
||
|
|
||
|
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; // HACK: MAGIC #: 14 -> g_nFontWidthAvg
|
||
|
linerect.bottom = linerect.top + nFontHeight;
|
||
|
|
||
|
// BOOL bp = g_nBreakpoints && CheckBreakpoint(nOffset,nOffset == regs.pc);
|
||
|
|
||
|
bool bBreakpointActive;
|
||
|
bool bBreakpointEnable;
|
||
|
GetBreakpointInfo( nOffset, bBreakpointActive, bBreakpointEnable );
|
||
|
bool bAddressAtPC = (nOffset == regs.pc);
|
||
|
|
||
|
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 = nOffset;
|
||
|
}
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
SetBkColor( dc, DebugGetColor( iBackground ) );
|
||
|
SetTextColor( dc, DebugGetColor( iForeground ) );
|
||
|
|
||
|
// Address
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_ADDRESS ) );
|
||
|
DebugDrawTextHorz( (LPCTSTR) sAddress, linerect );
|
||
|
|
||
|
// Address Seperator
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPERATOR ) );
|
||
|
if (g_bConfigDisasmAddressColon)
|
||
|
DebugDrawTextHorz( TEXT(":"), linerect );
|
||
|
|
||
|
// Opcodes
|
||
|
linerect.left = X_OPCODE;
|
||
|
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPCODE ) );
|
||
|
// DebugDrawTextHorz( TEXT(" "), linerect );
|
||
|
DebugDrawTextHorz( (LPCTSTR) sOpcodes, linerect );
|
||
|
// DebugDrawTextHorz( TEXT(" "), linerect );
|
||
|
|
||
|
// Label
|
||
|
linerect.left = X_LABEL;
|
||
|
|
||
|
LPCSTR pSymbol = FindSymbolFromAddress( nOffset );
|
||
|
if (pSymbol)
|
||
|
{
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_SYMBOL ) );
|
||
|
DebugDrawTextHorz( pSymbol, linerect );
|
||
|
}
|
||
|
// linerect.left += (g_nFontWidthAvg * DISASM_SYMBOL_LEN);
|
||
|
// DebugDrawTextHorz( TEXT(" "), linerect );
|
||
|
|
||
|
// Instruction
|
||
|
linerect.left = X_INSTRUCTION;
|
||
|
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( iForeground ) );
|
||
|
|
||
|
LPCTSTR pMnemonic = g_aOpcodes[ iOpcode ].sMnemonic;
|
||
|
DebugDrawTextHorz( pMnemonic, linerect );
|
||
|
|
||
|
DebugDrawTextHorz( TEXT(" "), linerect );
|
||
|
|
||
|
// Target
|
||
|
if (iOpmode == ADDR_IMM)
|
||
|
{
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPERATOR ));
|
||
|
DebugDrawTextHorz( TEXT("#$"), linerect );
|
||
|
}
|
||
|
|
||
|
if (bTargetIndirect)
|
||
|
{
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPERATOR ));
|
||
|
DebugDrawTextHorz( TEXT("("), linerect );
|
||
|
}
|
||
|
|
||
|
char *pTarget = sTarget;
|
||
|
if (*pTarget == '$')
|
||
|
{
|
||
|
pTarget++;
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPERATOR ));
|
||
|
DebugDrawTextHorz( TEXT("$"), linerect );
|
||
|
}
|
||
|
|
||
|
if (! bCursorLine)
|
||
|
{
|
||
|
if (bDisasmFormatFlags & DISASM_TARGET_SYMBOL)
|
||
|
{
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_SYMBOL ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (bDisasmFormatFlags & DISASM_IMMEDIATE_CHAR)
|
||
|
{
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPCODE ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_TARGET ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
DebugDrawTextHorz( pTarget, linerect );
|
||
|
// DebugDrawTextHorz( TEXT(" "), linerect );
|
||
|
|
||
|
// Target Offset +/-
|
||
|
if (bDisasmFormatFlags & DISASM_TARGET_OFFSET)
|
||
|
{
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPERATOR ));
|
||
|
|
||
|
if (nTargetOffset > 0)
|
||
|
DebugDrawTextHorz( TEXT("+" ), linerect );
|
||
|
if (nTargetOffset < 0)
|
||
|
DebugDrawTextHorz( TEXT("-" ), linerect );
|
||
|
|
||
|
if (! bCursorLine)
|
||
|
{
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPCODE )); // Technically, not a hex number, but decimal
|
||
|
}
|
||
|
DebugDrawTextHorz( sTargetOffset, linerect );
|
||
|
}
|
||
|
// Indirect Target Regs
|
||
|
if (bTargetIndirect || bTargetX || bTargetY)
|
||
|
{
|
||
|
if (! bCursorLine)
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPERATOR ));
|
||
|
|
||
|
if (bTargetX)
|
||
|
DebugDrawTextHorz( TEXT(",X"), linerect );
|
||
|
|
||
|
if (bTargetY)
|
||
|
DebugDrawTextHorz( TEXT(",Y"), linerect );
|
||
|
|
||
|
if (bTargetIndirect)
|
||
|
DebugDrawTextHorz( TEXT(")"), linerect );
|
||
|
|
||
|
if (iOpmode == ADDR_INDY)
|
||
|
DebugDrawTextHorz( TEXT(",Y"), linerect );
|
||
|
}
|
||
|
|
||
|
// Immediate Char
|
||
|
linerect.left = X_IMMEDIATE;
|
||
|
|
||
|
if (bDisasmFormatFlags & DISASM_IMMEDIATE_CHAR)
|
||
|
{
|
||
|
if (! bCursorLine)
|
||
|
{
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPERATOR ) );
|
||
|
}
|
||
|
DebugDrawTextHorz( TEXT("'"), linerect ); // TEXT(" '")
|
||
|
|
||
|
if (! bCursorLine)
|
||
|
{
|
||
|
ColorizeSpecialChar( dc, NULL, nImmediate, MEM_VIEW_ASCII, iBackground );
|
||
|
// iBackground, FG_INFO_CHAR_HI, FG_DISASM_CHAR, FG_INFO_CHAR_LO );
|
||
|
}
|
||
|
DebugDrawTextHorz( sImmediate, linerect );
|
||
|
|
||
|
SetBkColor( dc, DebugGetColor( iBackground ) ); // Hack: Colorize can "color bleed to EOL"
|
||
|
if (! bCursorLine)
|
||
|
{
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_OPERATOR ) );
|
||
|
}
|
||
|
DebugDrawTextHorz( TEXT("'"), linerect );
|
||
|
}
|
||
|
|
||
|
// Branch Indicator
|
||
|
linerect.left = X_BRANCH;
|
||
|
|
||
|
if (bDisasmFormatFlags & DISASM_BRANCH_INDICATOR)
|
||
|
{
|
||
|
if (! bCursorLine)
|
||
|
{
|
||
|
SetTextColor( dc, DebugGetColor( FG_DISASM_BRANCH ) );
|
||
|
}
|
||
|
|
||
|
if (g_bConfigDisasmFancyBranch)
|
||
|
SelectObject( dc, g_aFontConfig[ FONT_DISASM_BRANCH ]._hFont ); // g_hFontWebDings
|
||
|
|
||
|
DebugDrawText( sBranch, linerect );
|
||
|
|
||
|
if (g_bConfigDisasmFancyBranch)
|
||
|
SelectObject( dc, g_aFontConfig[ FONT_DISASM_DEFAULT ]._hFont ); // g_hFontDisasm
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nOpbyte;
|
||
|
}
|
||
|
|
||
|
// Optionally copy the flags to pText_
|
||
|
//===========================================================================
|
||
|
void DrawFlags (HDC dc, int line, WORD nRegFlags, LPTSTR pFlagNames_)
|
||
|
{
|
||
|
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
|
||
|
return;
|
||
|
|
||
|
TCHAR sFlagNames[ _6502_NUM_FLAGS+1 ] = TEXT(""); // = TEXT("NVRBDIZC"); // copy from g_aFlagNames
|
||
|
TCHAR sText[2] = TEXT("?");
|
||
|
RECT rect;
|
||
|
|
||
|
if (dc)
|
||
|
{
|
||
|
rect.left = DISPLAY_FLAG_COLUMN;
|
||
|
rect.top = line * g_nFontHeight;
|
||
|
rect.right = rect.left + 9;
|
||
|
rect.bottom = rect.top + g_nFontHeight;
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO )); // COLOR_BG_DATA
|
||
|
}
|
||
|
|
||
|
int iFlag = 0;
|
||
|
int nFlag = _6502_NUM_FLAGS;
|
||
|
while (nFlag--)
|
||
|
{
|
||
|
iFlag = BP_SRC_FLAG_C + (_6502_NUM_FLAGS - nFlag - 1);
|
||
|
|
||
|
bool bSet = (nRegFlags & 1);
|
||
|
if (dc)
|
||
|
{
|
||
|
|
||
|
// sText[0] = g_aFlagNames[ MAX_FLAGS - iFlag - 1]; // mnemonic[iFlag]; // mnemonic is reversed
|
||
|
sText[0] = g_aBreakpointSource[ iFlag ][0];
|
||
|
if (bSet)
|
||
|
{
|
||
|
SetBkColor( dc, DebugGetColor( BG_INFO_INVERSE ));
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_INVERSE ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO ));
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_TITLE ));
|
||
|
}
|
||
|
DebugDrawText( sText, rect );
|
||
|
rect.left -= 9; // HACK: Font Width
|
||
|
rect.right -= 9; // HACK: Font Width
|
||
|
}
|
||
|
|
||
|
if (pFlagNames_)
|
||
|
{
|
||
|
if (! bSet) //(nFlags & 1))
|
||
|
{
|
||
|
sFlagNames[nFlag] = TEXT('.');
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sFlagNames[nFlag] = g_aBreakpointSource[ iFlag ][0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nRegFlags >>= 1;
|
||
|
}
|
||
|
|
||
|
if (pFlagNames_)
|
||
|
_tcscpy(pFlagNames_,sFlagNames);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawMemory (HDC hDC, 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 - nFontWidth;
|
||
|
rect.top = (line * g_nFontHeight);
|
||
|
rect.right = DISPLAY_WIDTH;
|
||
|
rect.bottom = rect.top + g_nFontHeight;
|
||
|
|
||
|
|
||
|
const int MAX_MEM_VIEW_TXT = 16;
|
||
|
TCHAR sText[ MAX_MEM_VIEW_TXT * 2 ];
|
||
|
TCHAR sData[ MAX_MEM_VIEW_TXT * 2 ];
|
||
|
|
||
|
TCHAR sType [ 4 ] = TEXT("Mem");
|
||
|
TCHAR sAddress[ 8 ] = TEXT("");
|
||
|
|
||
|
int iForeground = FG_INFO_OPCODE;
|
||
|
int iBackground = BG_INFO;
|
||
|
|
||
|
if (eDevice == DEV_SY6522)
|
||
|
{
|
||
|
// wsprintf(sData,TEXT("Mem at SY#%d"), nAddr);
|
||
|
wsprintf( sAddress,TEXT("SY#%d"), nAddr );
|
||
|
}
|
||
|
else if(eDevice == DEV_AY8910)
|
||
|
{
|
||
|
// wsprintf(sData,TEXT("Mem at AY#%d"), nAddr);
|
||
|
wsprintf( sAddress,TEXT("AY#%d"), nAddr );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wsprintf( sAddress,TEXT("%04X"),(unsigned)nAddr);
|
||
|
|
||
|
if (iView == MEM_VIEW_HEX)
|
||
|
wsprintf( sType, TEXT("HEX") );
|
||
|
else
|
||
|
if (iView == MEM_VIEW_ASCII)
|
||
|
wsprintf( sType, TEXT("ASCII") );
|
||
|
else
|
||
|
wsprintf( sType, TEXT("TEXT") );
|
||
|
}
|
||
|
|
||
|
RECT rect2;
|
||
|
|
||
|
rect2 = rect;
|
||
|
SetTextColor( hDC, DebugGetColor( FG_INFO_TITLE ));
|
||
|
SetBkColor( hDC, DebugGetColor( BG_INFO ));
|
||
|
DebugDrawTextFixed( sType, rect2 );
|
||
|
|
||
|
SetTextColor( hDC, DebugGetColor( FG_INFO_OPERATOR ));
|
||
|
DebugDrawTextFixed( TEXT(" at " ), rect2 );
|
||
|
|
||
|
SetTextColor( hDC, DebugGetColor( FG_INFO_ADDRESS ));
|
||
|
DebugDrawTextLine( sAddress, rect2 );
|
||
|
|
||
|
rect.top = rect2.top;
|
||
|
rect.bottom = rect2.bottom;
|
||
|
|
||
|
sData[0] = 0;
|
||
|
|
||
|
WORD iAddress = nAddr;
|
||
|
|
||
|
if( (eDevice == DEV_SY6522) || (eDevice == DEV_AY8910) )
|
||
|
{
|
||
|
iAddress = 0;
|
||
|
}
|
||
|
|
||
|
int nLines = 4;
|
||
|
int nCols = 4;
|
||
|
|
||
|
if (iView != MEM_VIEW_HEX)
|
||
|
{
|
||
|
nCols = MAX_MEM_VIEW_TXT;
|
||
|
}
|
||
|
rect.right = MAX( rect.left + (nFontWidth * nCols), DISPLAY_WIDTH );
|
||
|
|
||
|
SetTextColor( hDC, DebugGetColor( FG_INFO_OPCODE ));
|
||
|
|
||
|
for (int iLine = 0; iLine < nLines; iLine++ )
|
||
|
{
|
||
|
RECT rect2;
|
||
|
rect2 = rect;
|
||
|
|
||
|
if (iView == MEM_VIEW_HEX)
|
||
|
{
|
||
|
wsprintf( sText, TEXT("%04X"), iAddress );
|
||
|
SetTextColor( hDC, DebugGetColor( FG_INFO_ADDRESS ));
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
|
||
|
SetTextColor( hDC, DebugGetColor( FG_INFO_OPERATOR ));
|
||
|
DebugDrawTextFixed( TEXT(":"), rect2 );
|
||
|
}
|
||
|
|
||
|
for (int iCol = 0; iCol < nCols; iCol++)
|
||
|
{
|
||
|
bool bHiBit = false;
|
||
|
bool bLoBit = false;
|
||
|
|
||
|
SetBkColor ( hDC, DebugGetColor( iBackground ));
|
||
|
SetTextColor( hDC, DebugGetColor( iForeground ));
|
||
|
|
||
|
// .12 Bugfix: DrawMemory() should draw memory byte for IO address: ML1 C000
|
||
|
// if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END))
|
||
|
// {
|
||
|
// wsprintf( sText, TEXT("IO ") );
|
||
|
// }
|
||
|
// else
|
||
|
if (eDevice == DEV_SY6522)
|
||
|
{
|
||
|
wsprintf( sText, TEXT("%02X "), (unsigned) ((BYTE*)&SS_MB.Unit[nAddr & 1].RegsSY6522)[iAddress] );
|
||
|
}
|
||
|
else
|
||
|
if (eDevice == DEV_AY8910)
|
||
|
{
|
||
|
wsprintf( sText, TEXT("%02X "), (unsigned)SS_MB.Unit[nAddr & 1].RegsAY8910[iAddress] );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BYTE nData = (unsigned)*(LPBYTE)(membank+iAddress);
|
||
|
sText[0] = 0;
|
||
|
|
||
|
char c = nData;
|
||
|
|
||
|
if (iView == MEM_VIEW_HEX)
|
||
|
{
|
||
|
if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END))
|
||
|
{
|
||
|
SetTextColor( hDC, DebugGetColor( FG_INFO_IO_BYTE ));
|
||
|
}
|
||
|
wsprintf(sText, TEXT("%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( hDC, sText, nData, iView, iBackground );
|
||
|
}
|
||
|
}
|
||
|
int nChars = DebugDrawTextFixed( sText, rect2 ); // DebugDrawTextFixed()
|
||
|
|
||
|
iAddress++;
|
||
|
}
|
||
|
rect.top += g_nFontHeight; // TODO/FIXME: g_nFontHeight;
|
||
|
rect.bottom += g_nFontHeight; // TODO/FIXME: g_nFontHeight;
|
||
|
sData[0] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawRegister (HDC dc, int line, LPCTSTR name, const int nBytes, const WORD nValue, int iSource )
|
||
|
{
|
||
|
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
|
||
|
return;
|
||
|
|
||
|
RECT rect;
|
||
|
rect.left = DISPLAY_REGS_COLUMN;
|
||
|
rect.top = line * g_nFontHeight;
|
||
|
rect.right = rect.left + 40; // TODO:FIXME: g_nFontWidthAvg *
|
||
|
rect.bottom = rect.top + g_nFontHeight;
|
||
|
|
||
|
if ((PARAM_REG_A == iSource) ||
|
||
|
(PARAM_REG_X == iSource) ||
|
||
|
(PARAM_REG_Y == iSource) ||
|
||
|
(PARAM_REG_PC == iSource) ||
|
||
|
(PARAM_REG_SP == iSource))
|
||
|
{
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_REG ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_TITLE ));
|
||
|
}
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO ));
|
||
|
DebugDrawText( name, rect );
|
||
|
|
||
|
unsigned int nData = nValue;
|
||
|
int nOffset = 6;
|
||
|
|
||
|
TCHAR sValue[8];
|
||
|
|
||
|
if (PARAM_REG_SP == iSource)
|
||
|
{
|
||
|
WORD nStackDepth = _6502_STACK_END - nValue;
|
||
|
wsprintf( 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)
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_OPERATOR )); // FG_INFO_OPCODE, FG_INFO_TITLE
|
||
|
DebugDrawText( sValue, rect );
|
||
|
}
|
||
|
|
||
|
if (nBytes == 2)
|
||
|
{
|
||
|
wsprintf(sValue,TEXT("%04X"), nData);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rect.left = DISPLAY_REGS_COLUMN + 21; // HACK: MAGIC #: 21 // +3 chars
|
||
|
rect.right = SCREENSPLIT2;
|
||
|
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_OPERATOR ));
|
||
|
DebugDrawTextFixed( TEXT("'"), rect ); // DebugDrawTextFixed
|
||
|
|
||
|
ColorizeSpecialChar( dc, sValue, nData, MEM_VIEW_ASCII ); // MEM_VIEW_APPLE for inverse background little hard on the eyes
|
||
|
DebugDrawTextFixed( sValue, rect ); // DebugDrawTextFixed()
|
||
|
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO ));
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_OPERATOR ));
|
||
|
DebugDrawTextFixed( TEXT("'"), rect ); // DebugDrawTextFixed()
|
||
|
|
||
|
wsprintf(sValue,TEXT(" %02X"), nData );
|
||
|
}
|
||
|
|
||
|
// Needs to be far enough over, since 4 chars of ZeroPage symbol also calls us
|
||
|
rect.left = DISPLAY_REGS_COLUMN + (nOffset * g_aFontConfig[ FONT_INFO ]._nFontWidthAvg); // HACK: MAGIC #: 40
|
||
|
rect.right = SCREENSPLIT2;
|
||
|
|
||
|
if ((PARAM_REG_PC == iSource) || (PARAM_REG_SP == iSource)) // Stack Pointer is target address, but doesn't look as good.
|
||
|
{
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_ADDRESS ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_OPCODE )); // FG_DISASM_OPCODE
|
||
|
}
|
||
|
DebugDrawText( sValue, rect );
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawStack (HDC dc, int line)
|
||
|
{
|
||
|
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
|
||
|
return;
|
||
|
|
||
|
unsigned nAddress = regs.sp;
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
nAddress = 0x100;
|
||
|
#endif
|
||
|
|
||
|
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 = DISPLAY_STACK_COLUMN + 40; // TODO/FIXME/HACK MAGIC #: g_nFontWidthAvg *
|
||
|
rect.bottom = rect.top + g_nFontHeight;
|
||
|
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_TITLE )); // [COLOR_STATIC
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO )); // COLOR_BG_DATA
|
||
|
|
||
|
TCHAR sText[8] = TEXT("");
|
||
|
if (nAddress <= _6502_STACK_END)
|
||
|
{
|
||
|
wsprintf(sText,TEXT("%04X"),nAddress);
|
||
|
}
|
||
|
|
||
|
// ExtTextOut(dc,rect.left,rect.top,
|
||
|
// ETO_CLIPPED | ETO_OPAQUE,&rect,
|
||
|
// sText,_tcslen(sText),NULL);
|
||
|
DebugDrawText( sText, rect );
|
||
|
|
||
|
rect.left = DISPLAY_STACK_COLUMN + 40; // TODO/FIXME/HACK MAGIC #: g_nFontWidthAvg *
|
||
|
rect.right = SCREENSPLIT2;
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_OPCODE )); // COLOR_FG_DATA_TEXT
|
||
|
|
||
|
if (nAddress <= _6502_STACK_END)
|
||
|
{
|
||
|
wsprintf(sText,TEXT("%02X"),(unsigned)*(LPBYTE)(mem+nAddress));
|
||
|
}
|
||
|
// ExtTextOut(dc,rect.left,rect.top,
|
||
|
// ETO_CLIPPED | ETO_OPAQUE,&rect,
|
||
|
// sText,_tcslen(sText),NULL);
|
||
|
DebugDrawText( sText, rect );
|
||
|
iStack++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawTargets (HDC dc, int line)
|
||
|
{
|
||
|
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
|
||
|
return;
|
||
|
|
||
|
int aTarget[2];
|
||
|
Get6502Targets( &aTarget[0],&aTarget[1], NULL );
|
||
|
|
||
|
RECT rect;
|
||
|
|
||
|
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;
|
||
|
|
||
|
TCHAR sAddress[8] = TEXT("");
|
||
|
TCHAR sData[8] = TEXT("");
|
||
|
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
if (aTarget[iAddress] == NO_6502_TARGET)
|
||
|
aTarget[iAddress] = 0;
|
||
|
#endif
|
||
|
if (aTarget[iAddress] != NO_6502_TARGET)
|
||
|
{
|
||
|
wsprintf(sAddress,TEXT("%04X"),aTarget[iAddress]);
|
||
|
if (iAddress)
|
||
|
wsprintf(sData,TEXT("%02X"),*(LPBYTE)(mem+aTarget[iAddress]));
|
||
|
else
|
||
|
wsprintf(sData,TEXT("%04X"),*(LPWORD)(mem+aTarget[iAddress]));
|
||
|
}
|
||
|
|
||
|
rect.left = DISPLAY_TARGETS_COLUMN;
|
||
|
rect.top = (line+iAddress) * g_nFontHeight;
|
||
|
int nColumn = DISPLAY_TARGETS_COLUMN + 40; // TODO/FIXME/HACK MAGIC #: g_nFontWidthAvg *
|
||
|
rect.right = nColumn;
|
||
|
rect.bottom = rect.top + g_nFontHeight;
|
||
|
|
||
|
if (iAddress == 0)
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_TITLE )); // Temp Address
|
||
|
else
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_ADDRESS )); // Target Address
|
||
|
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO ));
|
||
|
DebugDrawText( sAddress, rect );
|
||
|
|
||
|
rect.left = nColumn; // SCREENSPLIT1+40; // + 40
|
||
|
rect.right = SCREENSPLIT2;
|
||
|
|
||
|
if (iAddress == 0)
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_ADDRESS )); // Temp Target
|
||
|
else
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_OPCODE )); // Target Bytes
|
||
|
|
||
|
DebugDrawText( sData, rect );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawWatches (HDC dc, 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;
|
||
|
|
||
|
TCHAR sText[16] = TEXT("Watches");
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_TITLE ));
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO ));
|
||
|
DebugDrawTextLine( sText, rect );
|
||
|
|
||
|
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;
|
||
|
|
||
|
wsprintf( sText,TEXT("%d"),iWatch+1 );
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_BULLET ));
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
|
||
|
wsprintf( sText,TEXT(":") );
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_OPERATOR ));
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
|
||
|
wsprintf( sText,TEXT(" %04X"), g_aWatches[iWatch].nAddress );
|
||
|
SetTextColor( dc, DebugGetColor( FG_INFO_ADDRESS ));
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
|
||
|
wsprintf(sText,TEXT(" %02X"),(unsigned)*(LPBYTE)(mem+g_aWatches[iWatch].nAddress));
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_OPCODE ));
|
||
|
DebugDrawTextFixed( sText, rect2 );
|
||
|
}
|
||
|
|
||
|
rect.top += g_nFontHeight; // HACK:
|
||
|
rect.bottom += g_nFontHeight; // HACK:
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawZeroPagePointers(HDC dc, int line)
|
||
|
{
|
||
|
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
|
||
|
return;
|
||
|
|
||
|
for(int iZP = 0; iZP < MAX_ZEROPAGE_POINTERS; iZP++)
|
||
|
{
|
||
|
RECT rect;
|
||
|
rect.left = DISPLAY_ZEROPAGE_COLUMN;
|
||
|
rect.top = (line+iZP) * g_nFontHeight;
|
||
|
rect.right = SCREENSPLIT2; // TODO/FIXME:
|
||
|
rect.bottom = rect.top + g_nFontHeight;
|
||
|
|
||
|
TCHAR sText[8] = TEXT(" ");
|
||
|
|
||
|
SetTextColor(dc, DebugGetColor( FG_INFO_TITLE )); // COLOR_STATIC
|
||
|
SetBkColor(dc, DebugGetColor( BG_INFO ));
|
||
|
DebugDrawText( sText, rect );
|
||
|
|
||
|
Breakpoint_t *pZP = &g_aZeroPagePointers[iZP];
|
||
|
bool bEnabled = pZP->bEnabled;
|
||
|
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
bEnabled = true;
|
||
|
#endif
|
||
|
|
||
|
if (bEnabled)
|
||
|
// if (g_aZeroPagePointers[iZP].bSet) // TODO: Only list enanbled ones
|
||
|
{
|
||
|
const UINT nSymbolLen = 4;
|
||
|
char szZP[nSymbolLen+1];
|
||
|
|
||
|
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* pszSymbol2 = GetSymbol(nZPAddr2, 2); // 2:8-bit value (if symbol not found)
|
||
|
const char* pszSymbol1 = GetSymbol(nZPAddr1, 2); // 2:8-bit value (if symbol not found)
|
||
|
|
||
|
if( (strlen(pszSymbol1)==1) && (strlen(pszSymbol2)==1) )
|
||
|
{
|
||
|
sprintf(szZP, "%s%s", pszSymbol1, pszSymbol2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memcpy(szZP, pszSymbol1, nSymbolLen);
|
||
|
szZP[nSymbolLen] = 0;
|
||
|
}
|
||
|
|
||
|
WORD nZPPtr = (WORD)membank[nZPAddr1] | ((WORD)membank[nZPAddr2]<<8);
|
||
|
DrawRegister(dc, line+iZP, szZP, 2, nZPPtr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
int _Arg_1( int nValue )
|
||
|
{
|
||
|
g_aArgs[1].nVal1 = 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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
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->nVal1 = 0;
|
||
|
pArg->nVal2 = 0;
|
||
|
pArg->sArg[0] = 0;
|
||
|
|
||
|
pArg++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Processes the raw args, turning them into tokens and types.
|
||
|
//===========================================================================
|
||
|
int ArgsGet ( TCHAR * pInput )
|
||
|
{
|
||
|
LPCTSTR pSrc = pInput;
|
||
|
LPCTSTR pEnd = NULL;
|
||
|
int nBuf;
|
||
|
|
||
|
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];
|
||
|
|
||
|
// 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<char*>( 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 == 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_QUOTED)
|
||
|
{
|
||
|
pSrc++; // Don't store start of quote
|
||
|
pEnd = SkipUntilChar( pSrc, CHAR_QUOTED );
|
||
|
}
|
||
|
|
||
|
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_QUOTED)
|
||
|
{
|
||
|
pEnd++; // Don't store end of quote
|
||
|
}
|
||
|
|
||
|
pSrc = pEnd;
|
||
|
iArg++;
|
||
|
pArg++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (iArg)
|
||
|
{
|
||
|
nArg = iArg - 1; // first arg is command
|
||
|
}
|
||
|
|
||
|
g_nArgRaw = nArg;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
bool ArgsGetValue( Arg_t *pArg, WORD * pAddressValue_ )
|
||
|
{
|
||
|
const int BASE = 16; // hex
|
||
|
TCHAR *pSrc = & (pArg->sArg[ 0 ]);
|
||
|
TCHAR *pEnd = NULL;
|
||
|
|
||
|
if (pArg && pAddressValue_)
|
||
|
{
|
||
|
*pAddressValue_ = (WORD)(_tcstoul( pSrc, &pEnd, BASE) & _6502_END_MEM_ADDRESS);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
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_END_MEM_ADDRESS);
|
||
|
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->nVal1 = nAddressValue;
|
||
|
|
||
|
pArg->bType |= TYPE_ADDRESS;
|
||
|
|
||
|
iArg++;
|
||
|
pArg++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Note: The number of args can be changed via:
|
||
|
// address1,length Length
|
||
|
// address1:address2 Range
|
||
|
// address1+delta Delta
|
||
|
// address1-delta Delta
|
||
|
//===========================================================================
|
||
|
int ArgsParse( const int nArgs )
|
||
|
{
|
||
|
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 (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;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_COMMA) // COMMMA , length
|
||
|
{
|
||
|
pPrev->nVal2 = nAddressVal;
|
||
|
pPrev->eToken = TOKEN_COMMA;
|
||
|
pPrev->bType |= TYPE_ADDRESS;
|
||
|
pPrev->bType |= TYPE_LENGTH;
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_COLON) // COLON : range
|
||
|
{
|
||
|
pPrev->nVal2 = nAddressVal;
|
||
|
pPrev->eToken = TOKEN_COLON;
|
||
|
pPrev->bType |= TYPE_ADDRESS;
|
||
|
pPrev->bType |= TYPE_RANGE;
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_AMPERSAND) // AND & delta
|
||
|
{
|
||
|
if (! ArgsGetImmediateValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
ArgsGetRegisterValue( pNext, & nAddressRHS );
|
||
|
}
|
||
|
pPrev->nVal1 &= nAddressRHS;
|
||
|
pPrev->bType |= TYPE_VALUE; // signal already up to date
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_PIPE) // OR | delta
|
||
|
{
|
||
|
if (! ArgsGetImmediateValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
ArgsGetRegisterValue( pNext, & nAddressRHS );
|
||
|
}
|
||
|
pPrev->nVal1 |= nAddressRHS;
|
||
|
pPrev->bType |= TYPE_VALUE; // signal already up to date
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_CARET) // XOR ^ delta
|
||
|
{
|
||
|
if (! ArgsGetImmediateValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
ArgsGetRegisterValue( pNext, & nAddressRHS );
|
||
|
}
|
||
|
pPrev->nVal1 ^= nAddressRHS;
|
||
|
pPrev->bType |= TYPE_VALUE; // signal already up to date
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_PLUS) // PLUS + delta
|
||
|
{
|
||
|
if (! ArgsGetImmediateValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
ArgsGetRegisterValue( pNext, & nAddressRHS );
|
||
|
}
|
||
|
pPrev->nVal1 += nAddressRHS;
|
||
|
pPrev->bType |= TYPE_VALUE; // signal already up to date
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_MINUS) // MINUS - delta
|
||
|
{
|
||
|
if (! ArgsGetImmediateValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
ArgsGetRegisterValue( pNext, & nAddressRHS );
|
||
|
}
|
||
|
pPrev->nVal1 -= nAddressRHS;
|
||
|
pPrev->bType |= TYPE_VALUE; // signal already up to date
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_PERCENT) // PERCENT % delta
|
||
|
{
|
||
|
if (! ArgsGetImmediateValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
ArgsGetRegisterValue( pNext, & nAddressRHS );
|
||
|
}
|
||
|
pPrev->nVal1 %= nAddressRHS;
|
||
|
pPrev->bType |= TYPE_VALUE; // signal already up to date
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_FSLASH) // FORWARD SLASH / delta
|
||
|
{
|
||
|
if (! ArgsGetImmediateValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
ArgsGetRegisterValue( pNext, & nAddressRHS );
|
||
|
}
|
||
|
pPrev->nVal1 /= nAddressRHS;
|
||
|
pPrev->bType |= TYPE_VALUE; // signal already up to date
|
||
|
nParamLen = 2;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_EQUAL) // EQUAL = assign
|
||
|
{
|
||
|
pPrev->nVal1 = nAddressRHS;
|
||
|
pPrev->bType |= TYPE_VALUE; // signal already up to date
|
||
|
nParamLen = 0; // need token for Smart BreakPoints
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_HASH) // HASH # immediate
|
||
|
{
|
||
|
_Arg_Shift( iArg + nParamLen, nArgs, iArg );
|
||
|
nArg--;
|
||
|
|
||
|
pArg->nVal1 = nAddressRHS;
|
||
|
pArg->bSymbol = false;
|
||
|
pArg->bType = TYPE_VALUE | TYPE_ADDRESS | TYPE_NO_REG | TYPE_NO_SYM;
|
||
|
nParamLen = 0;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_LESS_THAN) // <
|
||
|
{
|
||
|
nParamLen = 0;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_GREATER_THAN) // >
|
||
|
{
|
||
|
nParamLen = 0;
|
||
|
}
|
||
|
|
||
|
if (pArg->eToken == TOKEN_EXCLAMATION) // NOT_EQUAL !
|
||
|
{
|
||
|
if (! ArgsGetImmediateValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
if (! ArgsGetRegisterValue( pNext, & nAddressRHS ))
|
||
|
{
|
||
|
nAddressRHS = nAddressVal;
|
||
|
}
|
||
|
}
|
||
|
pArg->nVal1 = ~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_END_MEM_ADDRESS);
|
||
|
|
||
|
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->nVal1 = nAddressVal;
|
||
|
|
||
|
pArg->bType |= TYPE_ADDRESS;
|
||
|
}
|
||
|
|
||
|
iArg++;
|
||
|
}
|
||
|
|
||
|
return nArg;
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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 (eMatch == MATCH_EXACT)
|
||
|
{
|
||
|
// while (iParam < NUM_PARAMS )
|
||
|
for (iParam = iParamBegin; iParam <= iParamEnd; iParam++ )
|
||
|
{
|
||
|
TCHAR *pParamName = g_aParameters[iParam].m_sName;
|
||
|
int eCompare = _tcscmp(pLookupName, pParamName);
|
||
|
if (! eCompare) // exact match?
|
||
|
{
|
||
|
nFound++;
|
||
|
iParam_ = g_aParameters[iParam].iCommand;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (eMatch == MATCH_FUZZY)
|
||
|
{
|
||
|
// while (iParam < NUM_PARAMS)
|
||
|
for (iParam = iParamBegin; iParam <= iParamEnd; iParam++ )
|
||
|
{
|
||
|
TCHAR *pParamName = g_aParameters[ iParam ].m_sName;
|
||
|
if (! _tcsncmp(pLookupName, pParamName ,nLen))
|
||
|
{
|
||
|
nFound++;
|
||
|
|
||
|
if (!_tcscmp(pLookupName, pParamName)) // exact match?
|
||
|
{
|
||
|
nFound = 1; // Exact match takes precidence over fuzzy matches
|
||
|
iParam_ = iParam_ = g_aParameters[iParam].iCommand;
|
||
|
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;
|
||
|
|
||
|
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;
|
||
|
if (! _tcsncmp(pName, pCommandName, nLen))
|
||
|
{
|
||
|
pFunction_ = g_aCommands[iCommand].pFunction;
|
||
|
if (pFunction_)
|
||
|
{
|
||
|
nFound++;
|
||
|
g_iCommand = g_aCommands[iCommand].iCommand;
|
||
|
g_vPotentialCommands.push_back( g_iCommand );
|
||
|
|
||
|
if (iCommand_)
|
||
|
*iCommand_ = iCommand;
|
||
|
|
||
|
if (!_tcscmp(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 )
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
wsprintf( sText, TEXT("Ambiguous %d Commands:"), g_vPotentialCommands.size() );
|
||
|
ConsoleBufferPush( sText );
|
||
|
|
||
|
int iCommand = 0;
|
||
|
while (iCommand < nFound)
|
||
|
{
|
||
|
TCHAR sPotentialCommands[ CONSOLE_WIDTH ] = TEXT(" ");
|
||
|
int iWidth = _tcslen( sPotentialCommands );
|
||
|
while ((iCommand < nFound) && (iWidth < g_nConsoleDisplayWidth))
|
||
|
{
|
||
|
int nCommand = g_vPotentialCommands[ iCommand ];
|
||
|
TCHAR *pName = g_aCommands[ nCommand ].m_sName;
|
||
|
int nLen = _tcslen( pName );
|
||
|
|
||
|
wsprintf( sText, TEXT("%s "), pName );
|
||
|
_tcscat( sPotentialCommands, sText );
|
||
|
iWidth += nLen + 1;
|
||
|
iCommand++;
|
||
|
}
|
||
|
ConsoleBufferPush( sPotentialCommands );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
Update_t ExecuteCommand (int nArgs)
|
||
|
{
|
||
|
LPTSTR name = _tcstok( g_pConsoleInput,TEXT(" ,-="));
|
||
|
if (!name)
|
||
|
name = g_pConsoleInput;
|
||
|
|
||
|
CmdFuncPtr_t pCommand = NULL;
|
||
|
int nFound = FindCommand( name, pCommand );
|
||
|
|
||
|
if (nFound > 1)
|
||
|
{
|
||
|
// ASSERT (nFound == g_vPotentialCommands.size() );
|
||
|
DisplayAmbigiousCommands( nFound );
|
||
|
|
||
|
return ConsoleUpdate();
|
||
|
// return ConsoleDisplayError( gaPotentialCommands );
|
||
|
}
|
||
|
else
|
||
|
if (pCommand)
|
||
|
return pCommand(nArgs);
|
||
|
else
|
||
|
return ConsoleDisplayError(TEXT("Illegal Command"));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// ________________________________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
bool Get6502Targets (int *pTemp_, int *pFinal_, int * pBytes_)
|
||
|
{
|
||
|
bool bStatus = false;
|
||
|
|
||
|
if (! pTemp_)
|
||
|
return bStatus;
|
||
|
|
||
|
if (! pFinal_)
|
||
|
return bStatus;
|
||
|
|
||
|
// if (! pBytes_)
|
||
|
// return bStatus;
|
||
|
|
||
|
*pTemp_ = NO_6502_TARGET;
|
||
|
*pFinal_ = NO_6502_TARGET;
|
||
|
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 0;
|
||
|
|
||
|
bStatus = true;
|
||
|
|
||
|
WORD nAddress = regs.pc;
|
||
|
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 ADDR_ABS:
|
||
|
*pFinal_ = nTarget16;
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 2;
|
||
|
break;
|
||
|
|
||
|
case ADDR_ABSIINDX:
|
||
|
nTarget16 += regs.x;
|
||
|
*pTemp_ = nTarget16;
|
||
|
*pFinal_ = *(LPWORD)(mem + nTarget16);
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 2;
|
||
|
break;
|
||
|
|
||
|
case ADDR_ABSX:
|
||
|
nTarget16 += regs.x;
|
||
|
*pFinal_ = nTarget16;
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 2;
|
||
|
break;
|
||
|
|
||
|
case ADDR_ABSY:
|
||
|
nTarget16 += regs.y;
|
||
|
*pFinal_ = nTarget16;
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 2;
|
||
|
break;
|
||
|
|
||
|
case ADDR_IABS:
|
||
|
*pTemp_ = nTarget16;
|
||
|
*pFinal_ = *(LPWORD)(mem + nTarget16);
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 2;
|
||
|
break;
|
||
|
|
||
|
case ADDR_INDX:
|
||
|
nTarget8 += regs.x;
|
||
|
*pTemp_ = nTarget8;
|
||
|
*pFinal_ = *(LPWORD)(mem + nTarget8);
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 2;
|
||
|
break;
|
||
|
|
||
|
case ADDR_INDY:
|
||
|
*pTemp_ = nTarget8;
|
||
|
*pFinal_ = (*(LPWORD)(mem + nTarget8)) + regs.y;
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 1;
|
||
|
break;
|
||
|
|
||
|
case ADDR_IZPG:
|
||
|
*pTemp_ = nTarget8;
|
||
|
*pFinal_ = *(LPWORD)(mem + nTarget8);
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 2;
|
||
|
break;
|
||
|
|
||
|
case ADDR_ZP:
|
||
|
*pFinal_ = nTarget8;
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 1;
|
||
|
break;
|
||
|
|
||
|
case ADDR_ZP_X:
|
||
|
*pFinal_ = nTarget8 + regs.x; // shouldn't this wrap around?
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 1;
|
||
|
break;
|
||
|
|
||
|
case ADDR_ZP_Y:
|
||
|
*pFinal_ = nTarget8 + regs.y; // shouldn't this wrap around?
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 1;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 0;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
// wtf??
|
||
|
// if ((*final >= 0) &&
|
||
|
// ((!_tcscmp(g_aOpcodes[*(mem+regs.pc)].mnemonic,TEXT("JMP"))) ||
|
||
|
// (!_tcscmp(g_aOpcodes[*(mem+regs.pc)].mnemonic,TEXT("JSR")))))
|
||
|
|
||
|
// If 6502 is jumping, don't show byte [nAddressTarget]
|
||
|
if ((*pFinal_ >= 0) &&
|
||
|
((nOpcode == OPCODE_JSR ) || // 0x20
|
||
|
(nOpcode == OPCODE_JMP_ABS ) || // 0x4C
|
||
|
(nOpcode == OPCODE_JMP_IABS ) || // 0x6C
|
||
|
(nOpcode == OPCODE_JMP_ABSINDX))) // 0x7C
|
||
|
{
|
||
|
*pFinal_ = NO_6502_TARGET;
|
||
|
if (pBytes_)
|
||
|
*pBytes_ = 0;
|
||
|
}
|
||
|
return bStatus;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
bool InternalSingleStep ()
|
||
|
{
|
||
|
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++;
|
||
|
|
||
|
CpuExecute(g_nDebugStepCycles);
|
||
|
bResult = true;
|
||
|
}
|
||
|
_except (EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
bResult = false;
|
||
|
}
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
void OutputTraceLine ()
|
||
|
{
|
||
|
// HACK: MAGIC #: 50 -> 64 chars for disassembly
|
||
|
TCHAR sDisassembly[ 64 ] ; DrawDisassemblyLine((HDC)0,0,regs.pc, sDisassembly); // Get Disasm String
|
||
|
TCHAR sFlags[ _6502_NUM_FLAGS+1]; DrawFlags( (HDC)0, 0, regs.ps, sFlags); // Get Flags String
|
||
|
|
||
|
_ftprintf(g_hTraceFile,
|
||
|
TEXT("a=%02x x=%02x y=%02x sp=%03x ps=%s %s\n"),
|
||
|
(unsigned)regs.a,
|
||
|
(unsigned)regs.x,
|
||
|
(unsigned)regs.y,
|
||
|
(unsigned)regs.sp,
|
||
|
(LPCTSTR) sFlags,
|
||
|
(LPCTSTR) sDisassembly);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
int ParseConsoleInput ( LPTSTR pConsoleInput )
|
||
|
{
|
||
|
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 ];
|
||
|
}
|
||
|
|
||
|
nArg = ArgsParse( nArg ); // Cook them
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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,
|
||
|
"%7.4f%%" DELIM "%9u" DELIM "%s" DELIM "%s" DELIM "%s\n"
|
||
|
, nPercent, sSeperator2
|
||
|
, static_cast<unsigned int>(nCount), sSeperator2
|
||
|
, sOpcode, sSeperator2
|
||
|
, g_aOpcodes[ nOpcode ].sMnemonic, sSeperator2
|
||
|
, sAddress
|
||
|
);
|
||
|
pText = ProfileLinePush();
|
||
|
}
|
||
|
|
||
|
if (! bOpcodeGood)
|
||
|
nOpcodeTotal = 0;
|
||
|
|
||
|
sprintf( pText
|
||
|
, "Total: " DELIM "%9u\n"
|
||
|
, sSeperator2
|
||
|
, static_cast<unsigned int>(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
|
||
|
, "%7.4f%%" DELIM "%9u" DELIM "%s\n"
|
||
|
, nPercent, sSeperator2
|
||
|
, static_cast<unsigned int>(nCount), sSeperator2
|
||
|
, sAddress
|
||
|
);
|
||
|
pText = ProfileLinePush();
|
||
|
}
|
||
|
|
||
|
if (! bOpmodeGood)
|
||
|
nOpmodeTotal = 0;
|
||
|
|
||
|
sprintf( pText
|
||
|
, "Total: " DELIM "%9u\n"
|
||
|
, sSeperator2
|
||
|
, static_cast<unsigned int>(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;
|
||
|
|
||
|
TCHAR filename[MAX_PATH];
|
||
|
_tcscpy(filename,progdir);
|
||
|
_tcscat(filename,g_FileNameProfile ); // TEXT("Profile.txt")); // =PATCH MJP
|
||
|
|
||
|
FILE *hFile = fopen(filename,TEXT("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;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
int DebugDrawText ( LPCTSTR pText, RECT & rRect )
|
||
|
{
|
||
|
int nLen = _tcslen( pText );
|
||
|
ExtTextOut( g_hDC,
|
||
|
rRect.left, rRect.top,
|
||
|
ETO_CLIPPED | ETO_OPAQUE, &rRect,
|
||
|
pText, nLen,
|
||
|
NULL );
|
||
|
return nLen;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Also moves cursor 'non proportional' font width, using FONT_INFO
|
||
|
//===========================================================================
|
||
|
int DebugDrawTextFixed ( LPCTSTR pText, RECT & rRect )
|
||
|
{
|
||
|
int nFontWidth = g_aFontConfig[ FONT_INFO ]._nFontWidthAvg;
|
||
|
|
||
|
int nChars = DebugDrawText( pText, rRect );
|
||
|
rRect.left += (nFontWidth * nChars);
|
||
|
return nChars;
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
int DebugDrawTextLine ( LPCTSTR pText, RECT & rRect )
|
||
|
{
|
||
|
int nChars = DebugDrawText( pText, rRect );
|
||
|
rRect.top += g_nFontHeight;
|
||
|
rRect.bottom += g_nFontHeight;
|
||
|
return nChars;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Moves cursor 'proportional' font width
|
||
|
//===========================================================================
|
||
|
int DebugDrawTextHorz ( LPCTSTR pText, RECT & rRect )
|
||
|
{
|
||
|
int nFontWidth = g_aFontConfig[ FONT_DISASM_DEFAULT ]._nFontWidthAvg;
|
||
|
|
||
|
SIZE size;
|
||
|
int nChars = DebugDrawText( pText, rRect );
|
||
|
if (GetTextExtentPoint32( g_hDC, pText, nChars, &size ))
|
||
|
{
|
||
|
rRect.left += size.cx;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rRect.left += (nFontWidth * nChars);
|
||
|
}
|
||
|
return nChars;
|
||
|
}
|
||
|
|
||
|
|
||
|
// _____________________________________________________________________________________
|
||
|
// | |
|
||
|
// | Public Functions |
|
||
|
// | |
|
||
|
// |_____________________________________________________________________________________|
|
||
|
|
||
|
//===========================================================================
|
||
|
void DebugBegin ()
|
||
|
{
|
||
|
// 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( framewindow, sText, TEXT("ERROR"), MB_OK );
|
||
|
}
|
||
|
|
||
|
if (_tcscmp( g_aParameters[ NUM_PARAMS ].m_sName, TEXT(__PARAMS_VERIFY_TXT__)))
|
||
|
{
|
||
|
wsprintf( sText, "*** ERROR *** Parameters mis-matched!" );
|
||
|
MessageBox( framewindow, sText, TEXT("ERROR"), MB_OK );
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
{
|
||
|
wsprintf( sText, TEXT("Warning: %s help is %d chars"),
|
||
|
pHelp, nLen );
|
||
|
ConsoleBufferPush( sText );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#if _DEBUG
|
||
|
//g_bConsoleBufferPaused = true;
|
||
|
#endif
|
||
|
|
||
|
CmdMOTD(0);
|
||
|
|
||
|
if (cpuemtype == CPU_FASTPAGING)
|
||
|
{
|
||
|
MemSetFastPaging(0);
|
||
|
}
|
||
|
|
||
|
if (!membank)
|
||
|
{
|
||
|
membank = mem;
|
||
|
}
|
||
|
|
||
|
mode = MODE_DEBUG;
|
||
|
FrameRefreshStatus(DRAW_TITLE);
|
||
|
|
||
|
// TODO:FIXME //e uses 65C02, ][ uses 6502
|
||
|
if (apple2e)
|
||
|
g_aOpcodes = & g_aOpcodes65C02[ 0 ]; // Enhanced Apple //e
|
||
|
else
|
||
|
g_aOpcodes = & g_aOpcodes6502[ 0 ]; // Original Apple ][
|
||
|
|
||
|
g_aOpmodes[ ADDR_INVALID2 ].m_nBytes = apple2e ? 2 : 1;
|
||
|
g_aOpmodes[ ADDR_INVALID3 ].m_nBytes = apple2e ? 3 : 1;
|
||
|
|
||
|
g_nDisasmCurAddress = regs.pc;
|
||
|
DisasmCalcTopBotAddress();
|
||
|
|
||
|
UpdateDisplay( UPDATE_ALL ); // 1
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DebugContinueStepping ()
|
||
|
{
|
||
|
static unsigned nStepsTaken = 0;
|
||
|
|
||
|
if (g_nDebugSkipLen > 0)
|
||
|
{
|
||
|
if ((regs.pc >= g_nDebugSkipStart) && (regs.pc < (g_nDebugSkipStart + g_nDebugSkipLen)))
|
||
|
{
|
||
|
// Enter go mode
|
||
|
g_nDebugSteps = -1;
|
||
|
// g_nDebugStepUntil = -1; // Could already be set via G
|
||
|
mode = MODE_STEPPING;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Enter step mode
|
||
|
g_nDebugSteps = 1;
|
||
|
// g_nDebugStepUntil = -1; // Could already be set via G
|
||
|
mode = MODE_STEPPING;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (g_nDebugSteps)
|
||
|
{
|
||
|
if (g_hTraceFile)
|
||
|
OutputTraceLine();
|
||
|
lastpc = regs.pc;
|
||
|
|
||
|
bool bBreak = CheckBreakpointsIO();
|
||
|
|
||
|
InternalSingleStep();
|
||
|
|
||
|
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
|
||
|
{
|
||
|
mode = 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);
|
||
|
|
||
|
for( int iTable = 0; iTable < NUM_SYMBOL_TABLES; iTable++ )
|
||
|
{
|
||
|
_CmdSymbolsClear( (Symbols_e) iTable );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Sub Window _____________________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
bool CanDrawDebugger()
|
||
|
{
|
||
|
if (g_bDebuggerViewingAppleOutput)
|
||
|
return false;
|
||
|
|
||
|
if ((mode == MODE_DEBUG) || (mode == MODE_STEPPING))
|
||
|
return true;
|
||
|
|
||
|
return 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();
|
||
|
SelectObject( g_hDC, g_aFontConfig[ FONT_DISASM_DEFAULT ]._hFont ); // g_hFontDisasm
|
||
|
|
||
|
WORD nAddress = g_nDisasmTopAddress; // g_nDisasmCurAddress;
|
||
|
for (int iLine = 0; iLine < nLines; iLine++ )
|
||
|
{
|
||
|
nAddress += DrawDisassemblyLine( g_hDC, iLine, nAddress, NULL);
|
||
|
}
|
||
|
|
||
|
SelectObject( g_hDC, g_aFontConfig[ FONT_INFO ]._hFont ); // g_hFontDebugger
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawSubWindow_Console (Update_t bUpdate)
|
||
|
{
|
||
|
if (! CanDrawDebugger())
|
||
|
return;
|
||
|
|
||
|
SelectObject( g_hDC, g_aFontConfig[ FONT_CONSOLE ]._hFont );
|
||
|
|
||
|
// static TCHAR sConsoleBlank[ CONSOLE_WIDTH ];
|
||
|
|
||
|
if ((bUpdate & UPDATE_CONSOLE_INPUT) || (bUpdate & UPDATE_CONSOLE_DISPLAY))
|
||
|
{
|
||
|
SetTextColor( g_hDC, DebugGetColor( FG_CONSOLE_OUTPUT )); // COLOR_FG_CONSOLE
|
||
|
SetBkColor( g_hDC, DebugGetColor( BG_CONSOLE_OUTPUT )); // COLOR_BG_CONSOLE
|
||
|
|
||
|
// int nLines = MIN(g_nConsoleDisplayTotal - g_iConsoleDisplayStart, g_nConsoleDisplayHeight);
|
||
|
int iLine = g_iConsoleDisplayStart + CONSOLE_FIRST_LINE;
|
||
|
for (int y = 0; y < g_nConsoleDisplayHeight ; y++ )
|
||
|
{
|
||
|
if (iLine <= (g_nConsoleDisplayTotal + CONSOLE_FIRST_LINE))
|
||
|
{
|
||
|
DrawConsoleLine( g_aConsoleDisplay[ iLine ], y+1 );
|
||
|
}
|
||
|
iLine++;
|
||
|
// else
|
||
|
// DrawConsoleLine( sConsoleBlank, y );
|
||
|
}
|
||
|
|
||
|
DrawConsoleInput( g_hDC );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawSubWindow_Data (Update_t bUpdate)
|
||
|
{
|
||
|
HDC hDC = g_hDC;
|
||
|
int iBackground;
|
||
|
|
||
|
const int nMaxOpcodes = WINDOW_DATA_BYTES_PER_LINE;
|
||
|
TCHAR sAddress [ 5];
|
||
|
TCHAR sOpcodes [(nMaxOpcodes*3)+1] = TEXT("");
|
||
|
TCHAR 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
|
||
|
wsprintf( sAddress, TEXT("%04X"), iAddress );
|
||
|
|
||
|
sOpcodes[0] = 0;
|
||
|
for ( iByte = 0; iByte < nMaxOpcodes; iByte++ )
|
||
|
{
|
||
|
BYTE nData = (unsigned)*(LPBYTE)(membank + iAddress + iByte);
|
||
|
wsprintf( &sOpcodes[ iByte * 3 ], TEXT("%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;
|
||
|
}
|
||
|
SetBkColor( hDC, DebugGetColor( iBackground ) );
|
||
|
|
||
|
SetTextColor( hDC, DebugGetColor( FG_DISASM_ADDRESS ) );
|
||
|
DebugDrawTextHorz( (LPCTSTR) sAddress, rect );
|
||
|
|
||
|
SetTextColor( hDC, DebugGetColor( FG_DISASM_OPERATOR ) );
|
||
|
if (g_bConfigDisasmAddressColon)
|
||
|
DebugDrawTextHorz( TEXT(":"), rect );
|
||
|
|
||
|
rect.left = X_OPCODE;
|
||
|
|
||
|
SetTextColor( hDC, DebugGetColor( FG_DATA_BYTE ) );
|
||
|
DebugDrawTextHorz( (LPCTSTR) sOpcodes, rect );
|
||
|
|
||
|
rect.left = X_CHAR;
|
||
|
|
||
|
// Seperator
|
||
|
SetTextColor( hDC, DebugGetColor( FG_DISASM_OPERATOR ));
|
||
|
DebugDrawTextHorz( (LPCSTR) TEXT(" | " ), rect );
|
||
|
|
||
|
|
||
|
// Plain Text
|
||
|
SetTextColor( hDC, DebugGetColor( 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)(membank + iAddress);
|
||
|
int iTextBackground = iBackground;
|
||
|
if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END))
|
||
|
{
|
||
|
iTextBackground = BG_INFO_IO_BYTE;
|
||
|
}
|
||
|
|
||
|
ColorizeSpecialChar( hDC, sImmediate, (BYTE) nImmediate, eView, iBackground );
|
||
|
DebugDrawTextHorz( (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 );
|
||
|
DebugDrawTextHorz( (LPCSTR) sImmediate, rect );
|
||
|
|
||
|
iAddress++;
|
||
|
}
|
||
|
|
||
|
SetBkColor( hDC, DebugGetColor( iBackground ) ); // Hack, colorize Char background "spills over to EOL"
|
||
|
DebugDrawTextHorz( (LPCSTR) TEXT(" " ), rect );
|
||
|
*/
|
||
|
SetBkColor( hDC, DebugGetColor( iBackground ) ); // HACK: Colorize() can "spill over" to EOL
|
||
|
|
||
|
SetTextColor( hDC, DebugGetColor( FG_DISASM_OPERATOR ));
|
||
|
DebugDrawTextHorz( (LPCSTR) TEXT(" | " ), rect );
|
||
|
|
||
|
nAddress += nMaxOpcodes;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// DrawRegisters();
|
||
|
//===========================================================================
|
||
|
void DrawSubWindow_Info( int iWindow )
|
||
|
{
|
||
|
if (g_iWindowThis == WINDOW_CONSOLE)
|
||
|
return;
|
||
|
|
||
|
const TCHAR **sReg = g_aBreakpointSource;
|
||
|
|
||
|
DrawStack(g_hDC,0);
|
||
|
DrawTargets(g_hDC,9);
|
||
|
DrawRegister(g_hDC,12, sReg[ BP_SRC_REG_A ] , 1, regs.a , PARAM_REG_A );
|
||
|
DrawRegister(g_hDC,13, sReg[ BP_SRC_REG_X ] , 1, regs.x , PARAM_REG_X );
|
||
|
DrawRegister(g_hDC,14, sReg[ BP_SRC_REG_Y ] , 1, regs.y , PARAM_REG_Y );
|
||
|
DrawRegister(g_hDC,15, sReg[ BP_SRC_REG_PC] , 2, regs.pc, PARAM_REG_PC );
|
||
|
DrawRegister(g_hDC,16, sReg[ BP_SRC_REG_S ] , 2, regs.sp, PARAM_REG_SP );
|
||
|
DrawFlags(g_hDC,17,regs.ps,NULL);
|
||
|
DrawZeroPagePointers(g_hDC,19);
|
||
|
|
||
|
#if defined(SUPPORT_Z80_EMU) && defined(OUTPUT_Z80_REGS)
|
||
|
DrawRegister(g_hDC,19,TEXT("AF"),2,*(WORD*)(membank+REG_AF));
|
||
|
DrawRegister(g_hDC,20,TEXT("BC"),2,*(WORD*)(membank+REG_BC));
|
||
|
DrawRegister(g_hDC,21,TEXT("DE"),2,*(WORD*)(membank+REG_DE));
|
||
|
DrawRegister(g_hDC,22,TEXT("HL"),2,*(WORD*)(membank+REG_HL));
|
||
|
DrawRegister(g_hDC,23,TEXT("IX"),2,*(WORD*)(membank+REG_IX));
|
||
|
#endif
|
||
|
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
if (true)
|
||
|
#else
|
||
|
if (g_nBreakpoints)
|
||
|
#endif
|
||
|
DrawBreakpoints(g_hDC,0);
|
||
|
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
if (true)
|
||
|
#else
|
||
|
if (g_nWatches)
|
||
|
#endif
|
||
|
DrawWatches(g_hDC,7);
|
||
|
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
if (true)
|
||
|
#else
|
||
|
if (g_aMemDump[0].bActive)
|
||
|
#endif
|
||
|
DrawMemory(g_hDC, 14, 0 ); // g_aMemDump[0].nAddress, g_aMemDump[0].eDevice);
|
||
|
|
||
|
#if DEBUG_FORCE_DISPLAY
|
||
|
if (true)
|
||
|
#else
|
||
|
if (g_aMemDump[1].bActive)
|
||
|
#endif
|
||
|
DrawMemory(g_hDC, 19, 1 ); // g_aMemDump[1].nAddress, g_aMemDump[1].eDevice);
|
||
|
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawSubWindow_IO (Update_t bUpdate)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawSubWindow_Source (Update_t bUpdate)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
int FindSourceLine( WORD nAddress )
|
||
|
{
|
||
|
int iAddress = 0;
|
||
|
int iLine = 0;
|
||
|
int iSourceLine = NO_SOURCE_LINE;
|
||
|
|
||
|
// iterate of <address,line>
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawSourceLine( int iSourceLine, RECT &rect )
|
||
|
{
|
||
|
TCHAR sLine[ CONSOLE_WIDTH ];
|
||
|
|
||
|
ZeroMemory( sLine, CONSOLE_WIDTH );
|
||
|
if ((iSourceLine >=0) && (iSourceLine < g_nSourceAssemblyLines))
|
||
|
{
|
||
|
char * pSource = g_vSourceLines[ iSourceLine ];
|
||
|
|
||
|
// int nLenSrc = _tcslen( 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 = _tcslen( sLine );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_tcscpy( sLine, TEXT(" "));
|
||
|
}
|
||
|
|
||
|
DebugDrawText( sLine, rect );
|
||
|
rect.top += g_nFontHeight;
|
||
|
// iSourceLine++;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawSubWindow_Source2 (Update_t bUpdate)
|
||
|
{
|
||
|
// if (! g_bSourceLevelDebugging)
|
||
|
// return;
|
||
|
|
||
|
SetTextColor( g_hDC, DebugGetColor( 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
|
||
|
TCHAR sTitle[ CONSOLE_WIDTH ];
|
||
|
TCHAR sText [ CONSOLE_WIDTH ];
|
||
|
_tcscpy( sTitle, TEXT(" Source: "));
|
||
|
_tcsncpy( sText, g_aSourceFileName, g_nConsoleDisplayWidth - _tcslen( sTitle ) - 1 );
|
||
|
_tcscat( sTitle, sText );
|
||
|
|
||
|
SetBkColor( g_hDC, DebugGetColor( BG_SOURCE_TITLE ));
|
||
|
SetTextColor( g_hDC, DebugGetColor( FG_SOURCE_TITLE ));
|
||
|
DebugDrawText( 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
|
||
|
}
|
||
|
SetBkColor( g_hDC, DebugGetColor( iBackground ));
|
||
|
SetTextColor( g_hDC, DebugGetColor( iForeground ));
|
||
|
|
||
|
DrawSourceLine( iSourceLine, rect );
|
||
|
iSourceLine++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawSubWindow_Symbols (Update_t bUpdate)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawSubWindow_ZeroPage (Update_t bUpdate)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Main Windows ___________________________________________________________________________________
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawWindow_Code( Update_t bUpdate )
|
||
|
{
|
||
|
DrawSubWindow_Code( g_iWindowThis );
|
||
|
|
||
|
// DrawWindowTop( g_iWindowThis );
|
||
|
DrawWindowBottom( bUpdate, g_iWindowThis );
|
||
|
|
||
|
DrawSubWindow_Info( g_iWindowThis );
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawWindow_Console( Update_t bUpdate )
|
||
|
{
|
||
|
// Nothing to do, except draw background, since text handled by DrawSubWindow_Console()
|
||
|
RECT viewportrect;
|
||
|
viewportrect.left = 0;
|
||
|
viewportrect.top = 0;
|
||
|
viewportrect.right = DISPLAY_WIDTH;
|
||
|
viewportrect.bottom = DISPLAY_HEIGHT - DEFAULT_HEIGHT; // 368 = 23 lines // TODO/FIXME
|
||
|
|
||
|
// TODO/FIXME: COLOR_BG_CODE -> g_iWindowThis, once all tab backgrounds are listed first in g_aColors !
|
||
|
SetBkColor(g_hDC, DebugGetColor( BG_DISASM_2 )); // COLOR_BG_CODE
|
||
|
// Can't use DebugDrawText, since we don't ned the CLIPPED flag
|
||
|
// TODO: add default param OPAQUE|CLIPPED
|
||
|
ExtTextOut( g_hDC
|
||
|
,0,0
|
||
|
,ETO_OPAQUE
|
||
|
,&viewportrect
|
||
|
,TEXT("")
|
||
|
,0
|
||
|
,NULL
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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 viewportrect;
|
||
|
viewportrect.left = 0;
|
||
|
viewportrect.top = 0;
|
||
|
viewportrect.right = SCREENSPLIT1 - 6; // HACK: MAGIC #: 14 -> 6 -> (g_nFonWidthAvg-1)
|
||
|
viewportrect.bottom = DISPLAY_HEIGHT - DEFAULT_HEIGHT; // 368 = 23 lines // TODO/FIXME
|
||
|
// g_nFontHeight * g_nDisasmWinHeight; // 304
|
||
|
|
||
|
// TODO/FIXME: COLOR_BG_CODE -> g_iWindowThis, once all tab backgrounds are listed first in g_aColors !
|
||
|
|
||
|
SetBkColor(g_hDC, DebugGetColor( BG_DISASM_1 )); // COLOR_BG_CODE
|
||
|
// Can't use DebugDrawText, since we don't need CLIPPED
|
||
|
ExtTextOut(g_hDC,0,0,ETO_OPAQUE,&viewportrect,TEXT(""),0,NULL);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DrawWindowBackground_Info( int g_iWindowThis )
|
||
|
{
|
||
|
RECT viewportrect;
|
||
|
viewportrect.top = 0;
|
||
|
viewportrect.left = SCREENSPLIT1 - 6; // 14 // HACK: MAGIC #: 14 -> (g_nFontWidthAvg-1)
|
||
|
viewportrect.right = 560;
|
||
|
viewportrect.bottom = DISPLAY_HEIGHT; //g_nFontHeight * MAX_DISPLAY_INFO_LINES; // 384
|
||
|
|
||
|
SetBkColor(g_hDC, DebugGetColor( BG_INFO )); // COLOR_BG_DATA
|
||
|
// Can't use DebugDrawText, since we don't need CLIPPED
|
||
|
ExtTextOut(g_hDC,0,0,ETO_OPAQUE,&viewportrect,TEXT(""),0,NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
void UpdateDisplay (Update_t bUpdate)
|
||
|
{
|
||
|
g_hDC = FrameGetDC();
|
||
|
|
||
|
SelectObject( g_hDC, g_aFontConfig[ FONT_INFO ]._hFont ); // g_hFontDebugger
|
||
|
|
||
|
SetTextAlign(g_hDC,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();
|
||
|
g_hDC = 0;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#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
|
||
|
|
||
|
void _CmdColorsReset()
|
||
|
{
|
||
|
// 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 );
|
||
|
// }
|
||
|
|
||
|
// Setup default colors
|
||
|
int iColor;
|
||
|
for (iColor = 0; iColor < NUM_COLORS; iColor++ )
|
||
|
{
|
||
|
COLORREF nColor = gaColorPalette[ g_aColorIndex[ iColor ] ];
|
||
|
|
||
|
int R = (nColor >> 0) & 0xFF;
|
||
|
int G = (nColor >> 8) & 0xFF;
|
||
|
int B = (nColor >> 16) & 0xFF;
|
||
|
|
||
|
// 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
|
||
|
COLORREF nMono = RGB(M,M,M);
|
||
|
|
||
|
DebugSetColor( SCHEME_COLOR, iColor, nColor );
|
||
|
DebugSetColor( SCHEME_MONO , iColor, nMono );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================================
|
||
|
void DebugInitialize ()
|
||
|
{
|
||
|
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();
|
||
|
|
||
|
_CmdColorsReset();
|
||
|
|
||
|
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));
|
||
|
|
||
|
g_iCommand = CMD_SYMBOLS_MAIN;
|
||
|
CmdSymbolsLoad(0);
|
||
|
|
||
|
// CREATE A FONT FOR THE DEBUGGING SCREEN
|
||
|
int nArgs = _Arg_1( g_sFontNameDefault );
|
||
|
// CmdConfigSetFont( nArgs );
|
||
|
|
||
|
for (int iFont = 0; iFont < NUM_FONTS; iFont++ )
|
||
|
{
|
||
|
g_aFontConfig[ iFont ]._hFont = NULL;
|
||
|
}
|
||
|
|
||
|
// TODO: g_aFontPitch
|
||
|
_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 ); // DEFAULT_CHARSET
|
||
|
|
||
|
/*
|
||
|
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 (g_aFontConfig[ FONT_DISASM_BRANCH ]._hFont)
|
||
|
{
|
||
|
g_bConfigDisasmFancyBranch = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_bConfigDisasmFancyBranch = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Add character to the input line
|
||
|
//===========================================================================
|
||
|
void DebugProcessChar (TCHAR ch)
|
||
|
{
|
||
|
if ((mode == MODE_STEPPING) && (ch == TEXT('\x1B'))) // HACK: ESCAPE
|
||
|
g_nDebugSteps = 0;
|
||
|
|
||
|
if (mode != MODE_DEBUG)
|
||
|
return;
|
||
|
|
||
|
if (g_bConsoleBufferPaused)
|
||
|
return;
|
||
|
|
||
|
// If don't have console input, don't pass space to the input line
|
||
|
if ((ch == TEXT(' ')) && (!g_nConsoleInputChars))
|
||
|
return;
|
||
|
|
||
|
if (g_nConsoleInputChars > (g_nConsoleDisplayWidth-1))
|
||
|
return;
|
||
|
|
||
|
if (g_bConsoleInputSkip)
|
||
|
{
|
||
|
g_bConsoleInputSkip = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((ch >= ' ') && (ch <= 126)) // HACK MAGIC # 32 -> ' ', # 126
|
||
|
{
|
||
|
if (ch == TEXT('"'))
|
||
|
g_bConsoleInputQuoted = ! g_bConsoleInputQuoted;
|
||
|
|
||
|
if (!g_bConsoleInputQuoted)
|
||
|
{
|
||
|
ch = (TCHAR)CharUpper((LPTSTR)ch);
|
||
|
}
|
||
|
ConsoleInputChar( ch );
|
||
|
|
||
|
HDC dc = FrameGetDC();
|
||
|
DrawConsoleInput( dc );
|
||
|
FrameReleaseDC();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
void DebugProcessCommand (int keycode)
|
||
|
{
|
||
|
if (mode != MODE_DEBUG)
|
||
|
return;
|
||
|
|
||
|
if (g_bDebuggerViewingAppleOutput)
|
||
|
{
|
||
|
// Normally any key press takes us out of "Viewing Apple Output" mode
|
||
|
// VK_F# are already processed, so we can't use them to cycle next video mode
|
||
|
// if ((mode != MODE_LOGO) && (mode != 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_nConsoleDisplayHeight - 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;
|
||
|
ConsoleDisplayPause();
|
||
|
}
|
||
|
else
|
||
|
// If have console input, don't invoke cursor movement
|
||
|
// TODO: Probably should disable all "movement" keys to map them to line editing mode
|
||
|
if ((keycode == VK_SPACE) && g_nConsoleInputChars)
|
||
|
return;
|
||
|
else if (keycode == VK_ESCAPE)
|
||
|
{
|
||
|
ConsoleInputClear();
|
||
|
bUpdateDisplay |= UPDATE_CONSOLE_INPUT;
|
||
|
}
|
||
|
else if (keycode == VK_BACK)
|
||
|
{
|
||
|
if (! ConsoleInputBackSpace())
|
||
|
{
|
||
|
// CmdBeep();
|
||
|
}
|
||
|
bUpdateDisplay |= UPDATE_CONSOLE_INPUT;
|
||
|
}
|
||
|
else if (keycode == VK_RETURN)
|
||
|
{
|
||
|
ConsoleDisplayPush( ConsoleInputPeek() );
|
||
|
|
||
|
if (g_nConsoleInputChars)
|
||
|
{
|
||
|
int nArgs = ParseConsoleInput( g_pConsoleInput );
|
||
|
if (nArgs == ARG_SYNTAX_ERROR)
|
||
|
{
|
||
|
TCHAR sText[ CONSOLE_WIDTH ];
|
||
|
wsprintf( sText, "Syntax error: %s", g_aArgs[0].sArg );
|
||
|
bUpdateDisplay |= ConsoleDisplayError( sText );
|
||
|
}
|
||
|
else
|
||
|
bUpdateDisplay |= ExecuteCommand( nArgs ); // ParseConsoleInput());
|
||
|
|
||
|
if (!g_bConsoleBufferPaused)
|
||
|
{
|
||
|
ConsoleInputReset();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (keycode == VK_OEM_3) // Tilde ~
|
||
|
{
|
||
|
// Switch to Console Window
|
||
|
if (g_iWindowThis != WINDOW_CONSOLE)
|
||
|
{
|
||
|
CmdWindowViewConsole( 0 );
|
||
|
}
|
||
|
else // switch back to last window
|
||
|
{
|
||
|
CmdWindowLast( 0 );
|
||
|
}
|
||
|
bUpdateDisplay |= UPDATE_ALL;
|
||
|
g_bConsoleInputSkip = true; // 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 (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_BEG_MEM_ADDRESS;
|
||
|
// DisasmCalcCurFromTopAddress();
|
||
|
// DisasmCalcBotFromTopAddress();
|
||
|
|
||
|
g_nDisasmCurAddress = _6502_BEG_MEM_ADDRESS;
|
||
|
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_END_MEM_ADDRESS / 2) + 1;
|
||
|
// DisasmCalcCurFromTopAddress();
|
||
|
// DisasmCalcTopBotAddress();
|
||
|
|
||
|
g_nDisasmCurAddress = (_6502_END_MEM_ADDRESS / 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
|
||
|
}
|
||
|
}
|
||
|
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
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (KeybGetShiftStatus())
|
||
|
bUpdateDisplay |= CmdCursorPageDown256(0);
|
||
|
else
|
||
|
if (KeybGetCtrlStatus())
|
||
|
bUpdateDisplay |= CmdCursorPageDown4K(0);
|
||
|
else
|
||
|
bUpdateDisplay |= CmdCursorPageDown(0);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// +PATCH MJP
|
||
|
// case VK_UP: bUpdateDisplay = CmdCursorLineUp(0); break; // -PATCH
|
||
|
// case VK_DOWN: bUpdateDisplay = CmdCursorLineDown(0); break; // -PATCH
|
||
|
case VK_UP:
|
||
|
if (g_iWindowThis == WINDOW_CONSOLE)
|
||
|
{
|
||
|
bUpdateDisplay |= ConsoleScrollUp( 1 );
|
||
|
}
|
||
|
else
|
||
|
if (g_nConsoleInputChars > 0)
|
||
|
{
|
||
|
if (KeybGetShiftStatus())
|
||
|
{
|
||
|
bUpdateDisplay |= ConsoleScrollUp( 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// 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 g_aOpcodes
|
||
|
if (KeybGetShiftStatus())
|
||
|
bUpdateDisplay |= CmdCursorLineUp(1);
|
||
|
else
|
||
|
bUpdateDisplay |= CmdCursorLineUp(0);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VK_DOWN:
|
||
|
if (g_iWindowThis == WINDOW_CONSOLE)
|
||
|
{
|
||
|
bUpdateDisplay |= ConsoleScrollDn( 1 );
|
||
|
}
|
||
|
else
|
||
|
if (g_nConsoleInputChars > 0)
|
||
|
{
|
||
|
if (KeybGetShiftStatus())
|
||
|
{
|
||
|
bUpdateDisplay |= ConsoleScrollDn( 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// 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
|
||
|
bUpdateDisplay |= CmdCursorJumpPC( CURSOR_ALIGN_CENTER );
|
||
|
break;
|
||
|
|
||
|
case VK_LEFT:
|
||
|
if (KeybGetShiftStatus())
|
||
|
bUpdateDisplay |= CmdCursorJumpRetAddr( CURSOR_ALIGN_TOP ); // Jump to Caller
|
||
|
else
|
||
|
bUpdateDisplay |= CmdCursorJumpRetAddr( CURSOR_ALIGN_CENTER );
|
||
|
break;
|
||
|
|
||
|
} // switch
|
||
|
}
|
||
|
|
||
|
if (bUpdateDisplay) // & 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 );
|
||
|
}
|