2086 lines
68 KiB
C
2086 lines
68 KiB
C
/*
|
|
* monitor.c - Implements a builtin system monitor for debugging
|
|
*
|
|
* Copyright (C) 1995-1998 David Firth
|
|
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
|
|
*
|
|
* This file is part of the Atari800 emulator project which emulates
|
|
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
|
*
|
|
* Atari800 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.
|
|
*
|
|
* Atari800 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 Atari800; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "antic.h"
|
|
#include "atari.h"
|
|
#include "cpu.h"
|
|
#include "gtia.h"
|
|
#include "memory.h"
|
|
#include "monitor.h"
|
|
#include "pia.h"
|
|
#include "pokey.h"
|
|
#include "util.h"
|
|
#ifdef STEREO_SOUND
|
|
#include "pokeysnd.h"
|
|
#endif
|
|
|
|
#ifdef MONITOR_READLINE
|
|
#include <readline/readline.h>
|
|
#include <readline/history.h>
|
|
#endif
|
|
|
|
#ifdef __PLUS
|
|
|
|
#include <stdarg.h>
|
|
#include "misc_win.h"
|
|
|
|
FILE *mon_output, *mon_input;
|
|
|
|
void monitor_printf(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, format);
|
|
vfprintf(mon_output, format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
#define printf monitor_printf
|
|
#define puts(s) fputs(s, mon_output)
|
|
#define putchar(c) fputc(c, mon_output)
|
|
#define perror(filename) printf("%s: %s\n", filename, strerror(errno))
|
|
|
|
#undef stdout
|
|
#define stdout mon_output
|
|
|
|
#undef stdin
|
|
#define stdin mon_input
|
|
|
|
#define PLUS_EXIT_MONITOR Misc_FreeMonitorConsole(mon_output, mon_input)
|
|
|
|
#else /* __PLUS */
|
|
|
|
#define PLUS_EXIT_MONITOR
|
|
|
|
#endif /* __PLUS */
|
|
|
|
#ifdef MONITOR_TRACE
|
|
FILE *MONITOR_trace_file = NULL;
|
|
#endif
|
|
|
|
#ifdef MONITOR_HINTS
|
|
|
|
typedef struct {
|
|
char *name;
|
|
UWORD addr;
|
|
} symtable_rec;
|
|
|
|
/* Symbol names taken from atari.equ - part of disassembler by Erich Bacher
|
|
and from antic.h, gtia.h, pia.h and pokey.h.
|
|
Symbols must be sorted by address. If the address has different names
|
|
when reading/writing to it, put the read name first. */
|
|
|
|
static const symtable_rec symtable_builtin[] = {
|
|
{"NGFLAG", 0x0001}, {"CASINI", 0x0002}, {"CASINI+1",0x0003}, {"RAMLO", 0x0004},
|
|
{"RAMLO+1", 0x0005}, {"TRAMSZ", 0x0006}, {"CMCMD", 0x0007}, {"WARMST", 0x0008},
|
|
{"BOOT", 0x0009}, {"DOSVEC", 0x000a}, {"DOSVEC+1",0x000b}, {"DOSINI", 0x000c},
|
|
{"DOSINI+1",0x000d}, {"APPMHI", 0x000e}, {"APPMHI+1",0x000f}, {"POKMSK", 0x0010},
|
|
{"BRKKEY", 0x0011}, {"RTCLOK", 0x0012}, {"RTCLOK+1",0x0013}, {"RTCLOK+2",0x0014},
|
|
{"BUFADR", 0x0015}, {"BUFADR+1",0x0016}, {"ICCOMT", 0x0017}, {"DSKFMS", 0x0018},
|
|
{"DSKFMS+1",0x0019}, {"DSKUTL", 0x001a}, {"DSKUTL+1",0x001b}, {"ABUFPT", 0x001c},
|
|
{"ABUFPT+1",0x001d}, {"ABUFPT+2",0x001e}, {"ABUFPT+3",0x001f},
|
|
{"ICHIDZ", 0x0020}, {"ICDNOZ", 0x0021}, {"ICCOMZ", 0x0022}, {"ICSTAZ", 0x0023},
|
|
{"ICBALZ", 0x0024}, {"ICBAHZ", 0x0025}, {"ICPTLZ", 0x0026}, {"ICPTHZ", 0x0027},
|
|
{"ICBLLZ", 0x0028}, {"ICBLHZ", 0x0029}, {"ICAX1Z", 0x002a}, {"ICAX2Z", 0x002b},
|
|
{"ICAX3Z", 0x002c}, {"ICAX4Z", 0x002d}, {"ICAX5Z", 0x002e}, {"ICAX6Z", 0x002f},
|
|
{"STATUS", 0x0030}, {"CHKSUM", 0x0031}, {"BUFRLO", 0x0032}, {"BUFRHI", 0x0033},
|
|
{"BFENLO", 0x0034}, {"BFENHI", 0x0035}, {"LTEMP", 0x0036}, {"LTEMP+1", 0x0037},
|
|
{"BUFRFL", 0x0038}, {"RECVDN", 0x0039}, {"XMTDON", 0x003a}, {"CHKSNT", 0x003b},
|
|
{"NOCKSM", 0x003c}, {"BPTR", 0x003d}, {"FTYPE", 0x003e}, {"FEOF", 0x003f},
|
|
{"FREQ", 0x0040}, {"SOUNDR", 0x0041}, {"CRITIC", 0x0042}, {"FMSZPG", 0x0043},
|
|
{"FMSZPG+1",0x0044}, {"FMSZPG+2",0x0045}, {"FMSZPG+3",0x0046}, {"FMSZPG+4",0x0047},
|
|
{"FMSZPG+5",0x0048}, {"FMSZPG+6",0x0049}, {"ZCHAIN", 0x004a}, {"ZCHAIN+1",0x004b},
|
|
{"DSTAT", 0x004c}, {"ATRACT", 0x004d}, {"DRKMSK", 0x004e}, {"COLRSH", 0x004f},
|
|
{"TEMP", 0x0050}, {"HOLD1", 0x0051}, {"LMARGN", 0x0052}, {"RMARGN", 0x0053},
|
|
{"ROWCRS", 0x0054}, {"COLCRS", 0x0055}, {"COLCRS+1",0x0056}, {"DINDEX", 0x0057},
|
|
{"SAVMSC", 0x0058}, {"SAVMSC+1",0x0059}, {"OLDROW", 0x005a}, {"OLDCOL", 0x005b},
|
|
{"OLDCOL+1",0x005c}, {"OLDCHR", 0x005d}, {"OLDADR", 0x005e}, {"OLDADR+1",0x005f},
|
|
{"FKDEF", 0x0060}, {"FKDEF+1", 0x0061}, {"PALNTS", 0x0062}, {"LOGCOL", 0x0063},
|
|
{"ADRESS", 0x0064}, {"ADRESS+1",0x0065}, {"MLTTMP", 0x0066}, {"MLTTMP+1",0x0067},
|
|
{"SAVADR", 0x0068}, {"SAVADR+1",0x0069}, {"RAMTOP", 0x006a}, {"BUFCNT", 0x006b},
|
|
{"BUFSTR", 0x006c}, {"BUFSTR+1",0x006d}, {"BITMSK", 0x006e}, {"SHFAMT", 0x006f},
|
|
{"ROWAC", 0x0070}, {"ROWAC+1", 0x0071}, {"COLAC", 0x0072}, {"COLAC+1", 0x0073},
|
|
{"ENDPT", 0x0074}, {"ENDPT+1", 0x0075}, {"DELTAR", 0x0076}, {"DELTAC", 0x0077},
|
|
{"DELTAC+1",0x0078}, {"KEYDEF", 0x0079}, {"KEYDEF+1",0x007a}, {"SWPFLG", 0x007b},
|
|
{"HOLDCH", 0x007c}, {"INSDAT", 0x007d}, {"COUNTR", 0x007e}, {"COUNTR+1",0x007f},
|
|
{"LOMEM", 0x0080}, {"LOMEM+1", 0x0081}, {"VNTP", 0x0082}, {"VNTP+1", 0x0083},
|
|
{"VNTD", 0x0084}, {"VNTD+1", 0x0085}, {"VVTP", 0x0086}, {"VVTP+1", 0x0087},
|
|
{"STMTAB", 0x0088}, {"STMTAB+1",0x0089}, {"STMCUR", 0x008a}, {"STMCUR+1",0x008b},
|
|
{"STARP", 0x008c}, {"STARP+1", 0x008d}, {"RUNSTK", 0x008e}, {"RUNSTK+1",0x008f},
|
|
{"TOPSTK", 0x0090}, {"TOPSTK+1",0x0091}, {"MEOLFLG", 0x0092}, {"POKADR", 0x0095},
|
|
{"POKADR+1",0x0096}, {"DATAD", 0x00b6}, {"DATALN", 0x00b7}, {"DATALN+1",0x00b8},
|
|
{"STOPLN", 0x00ba}, {"STOPLN+1",0x00bb}, {"SAVCUR", 0x00be}, {"IOCMD", 0x00c0},
|
|
{"IODVC", 0x00c1}, {"PROMPT", 0x00c2}, {"ERRSAVE", 0x00c3}, {"COLOR", 0x00c8},
|
|
{"PTABW", 0x00c9}, {"LOADFLG", 0x00ca}, {"FR0", 0x00d4}, {"FR0+1", 0x00d5},
|
|
{"FR0+2", 0x00d6}, {"FR0+3", 0x00d7}, {"FR0+4", 0x00d8}, {"FR0+5", 0x00d9},
|
|
{"FRE", 0x00da}, {"FRE+1", 0x00db}, {"FRE+2", 0x00dc}, {"FRE+3", 0x00dd},
|
|
{"FRE+4", 0x00de}, {"FRE+5", 0x00df}, {"FR1", 0x00e0}, {"FR1+1", 0x00e1},
|
|
{"FR1+2", 0x00e2}, {"FR1+3", 0x00e3}, {"FR1+4", 0x00e4}, {"FR1+5", 0x00e5},
|
|
{"FR2", 0x00e6}, {"FR2+1", 0x00e7}, {"FR2+2", 0x00e8}, {"FR2+3", 0x00e9},
|
|
{"FR2+4", 0x00ea}, {"FR2+5", 0x00eb}, {"FRX", 0x00ec}, {"EEXP", 0x00ed},
|
|
{"NSIGN", 0x00ee}, {"ESIGN", 0x00ef}, {"FCHRFLG", 0x00f0}, {"DIGRT", 0x00f1},
|
|
{"CIX", 0x00f2}, {"INBUFF", 0x00f3}, {"INBUFF+1",0x00f4}, {"ZTEMP1", 0x00f5},
|
|
{"ZTEMP1+1",0x00f6}, {"ZTEMP4", 0x00f7}, {"ZTEMP4+1",0x00f8}, {"ZTEMP3", 0x00f9},
|
|
{"ZTEMP3+1",0x00fa}, {"RADFLG", 0x00fb}, {"FLPTR", 0x00fc}, {"FLPTR+1", 0x00fd},
|
|
{"FPTR2", 0x00fe}, {"FPTR2+1", 0x00ff},
|
|
|
|
{"VDSLST", 0x0200}, {"VDSLST+1",0x0201}, {"VPRCED", 0x0202}, {"VPRCED+1",0x0203},
|
|
{"VINTER", 0x0204}, {"VINTER+1",0x0205}, {"VBREAK", 0x0206}, {"VBREAK+1",0x0207},
|
|
{"VKEYBD", 0x0208}, {"VKEYBD+1",0x0209}, {"VSERIN", 0x020a}, {"VSERIN+1",0x020b},
|
|
{"VSEROR", 0x020c}, {"VSEROR+1",0x020d}, {"VSEROC", 0x020e}, {"VSEROC+1",0x020f},
|
|
{"VTIMR1", 0x0210}, {"VTIMR1+1",0x0211}, {"VTIMR2", 0x0212}, {"VTIMR2+1",0x0213},
|
|
{"VTIMR4", 0x0214}, {"VTIMR4+1",0x0215}, {"VIMIRQ", 0x0216}, {"VIMIRQ+1",0x0217},
|
|
{"CDTMV1", 0x0218}, {"CDTMV1+1",0x0219}, {"CDTMV2", 0x021a}, {"CDTMV2+1",0x021b},
|
|
{"CDTMV3", 0x021c}, {"CDTMV3+1",0x021d}, {"CDTMV4", 0x021e}, {"CDTMV4+1",0x021f},
|
|
{"CDTMV5", 0x0220}, {"CDTMV5+1",0x0221}, {"VVBLKI", 0x0222}, {"VVBLKI+1",0x0223},
|
|
{"VVBLKD", 0x0224}, {"VVBLKD+1",0x0225}, {"CDTMA1", 0x0226}, {"CDTMA1+1",0x0227},
|
|
{"CDTMA2", 0x0228}, {"CDTMA2+1",0x0229}, {"CDTMF3", 0x022a}, {"SRTIMR", 0x022b},
|
|
{"CDTMF4", 0x022c}, {"INTEMP", 0x022d}, {"CDTMF5", 0x022e}, {"SDMCTL", 0x022f},
|
|
{"SDLSTL", 0x0230}, {"SDLSTH", 0x0231}, {"SSKCTL", 0x0232}, {"SPARE", 0x0233},
|
|
{"LPENH", 0x0234}, {"LPENV", 0x0235}, {"BRKKY", 0x0236}, {"BRKKY+1", 0x0237},
|
|
{"VPIRQ", 0x0238}, {"VPIRQ+1", 0x0239}, {"CDEVIC", 0x023a}, {"CCOMND", 0x023b},
|
|
{"CAUX1", 0x023c}, {"CAUX2", 0x023d}, {"TMPSIO", 0x023e}, {"ERRFLG", 0x023f},
|
|
{"DFLAGS", 0x0240}, {"DBSECT", 0x0241}, {"BOOTAD", 0x0242}, {"BOOTAD+1",0x0243},
|
|
{"COLDST", 0x0244}, {"RECLEN", 0x0245}, {"DSKTIM", 0x0246}, {"PDVMSK", 0x0247},
|
|
{"SHPDVS", 0x0248}, {"PDMSK", 0x0249}, {"RELADR", 0x024a}, {"RELADR+1",0x024b},
|
|
{"PPTMPA", 0x024c}, {"PPTMPX", 0x024d}, {"CHSALT", 0x026b}, {"VSFLAG", 0x026c},
|
|
{"KEYDIS", 0x026d}, {"FINE", 0x026e}, {"GPRIOR", 0x026f}, {"PADDL0", 0x0270},
|
|
{"PADDL1", 0x0271}, {"PADDL2", 0x0272}, {"PADDL3", 0x0273}, {"PADDL4", 0x0274},
|
|
{"PADDL5", 0x0275}, {"PADDL6", 0x0276}, {"PADDL7", 0x0277}, {"STICK0", 0x0278},
|
|
{"STICK1", 0x0279}, {"STICK2", 0x027a}, {"STICK3", 0x027b}, {"PTRIG0", 0x027c},
|
|
{"PTRIG1", 0x027d}, {"PTRIG2", 0x027e}, {"PTRIG3", 0x027f}, {"PTRIG4", 0x0280},
|
|
{"PTRIG5", 0x0281}, {"PTRIG6", 0x0282}, {"PTRIG7", 0x0283}, {"STRIG0", 0x0284},
|
|
{"STRIG1", 0x0285}, {"STRIG2", 0x0286}, {"STRIG3", 0x0287}, {"HIBYTE", 0x0288},
|
|
{"WMODE", 0x0289}, {"BLIM", 0x028a}, {"IMASK", 0x028b}, {"JVECK", 0x028c},
|
|
{"NEWADR", 0x028e}, {"TXTROW", 0x0290}, {"TXTCOL", 0x0291}, {"TXTCOL+1",0x0292},
|
|
{"TINDEX", 0x0293}, {"TXTMSC", 0x0294}, {"TXTMSC+1",0x0295}, {"TXTOLD", 0x0296},
|
|
{"TXTOLD+1",0x0297}, {"TXTOLD+2",0x0298}, {"TXTOLD+3",0x0299}, {"TXTOLD+4",0x029a},
|
|
{"TXTOLD+5",0x029b}, {"CRETRY", 0x029c}, {"HOLD3", 0x029d}, {"SUBTMP", 0x029e},
|
|
{"HOLD2", 0x029f}, {"DMASK", 0x02a0}, {"TMPLBT", 0x02a1}, {"ESCFLG", 0x02a2},
|
|
{"TABMAP", 0x02a3}, {"TABMAP+1",0x02a4}, {"TABMAP+2",0x02a5}, {"TABMAP+3",0x02a6},
|
|
{"TABMAP+4",0x02a7}, {"TABMAP+5",0x02a8}, {"TABMAP+6",0x02a9}, {"TABMAP+7",0x02aa},
|
|
{"TABMAP+8",0x02ab}, {"TABMAP+9",0x02ac}, {"TABMAP+A",0x02ad}, {"TABMAP+B",0x02ae},
|
|
{"TABMAP+C",0x02af}, {"TABMAP+D",0x02b0}, {"TABMAP+E",0x02b1}, {"LOGMAP", 0x02b2},
|
|
{"LOGMAP+1",0x02b3}, {"LOGMAP+2",0x02b4}, {"LOGMAP+3",0x02b5}, {"INVFLG", 0x02b6},
|
|
{"FILFLG", 0x02b7}, {"TMPROW", 0x02b8}, {"TMPCOL", 0x02b9}, {"TMPCOL+1",0x02ba},
|
|
{"SCRFLG", 0x02bb}, {"HOLD4", 0x02bc}, {"DRETRY", 0x02bd}, {"SHFLOC", 0x02be},
|
|
{"BOTSCR", 0x02bf}, {"PCOLR0", 0x02c0}, {"PCOLR1", 0x02c1}, {"PCOLR2", 0x02c2},
|
|
{"PCOLR3", 0x02c3}, {"COLOR0", 0x02c4}, {"COLOR1", 0x02c5}, {"COLOR2", 0x02c6},
|
|
{"COLOR3", 0x02c7}, {"COLOR4", 0x02c8}, {"RUNADR", 0x02c9}, {"RUNADR+1",0x02ca},
|
|
{"HIUSED", 0x02cb}, {"HIUSED+1",0x02cc}, {"ZHIUSE", 0x02cd}, {"ZHIUSE+1",0x02ce},
|
|
{"GBYTEA", 0x02cf}, {"GBYTEA+1",0x02d0}, {"LOADAD", 0x02d1}, {"LOADAD+1",0x02d2},
|
|
{"ZLOADA", 0x02d3}, {"ZLOADA+1",0x02d4}, {"DSCTLN", 0x02d5}, {"DSCTLN+1",0x02d6},
|
|
{"ACMISR", 0x02d7}, {"ACMISR+1",0x02d8}, {"KRPDER", 0x02d9}, {"KEYREP", 0x02da},
|
|
{"NOCLIK", 0x02db}, {"HELPFG", 0x02dc}, {"DMASAV", 0x02dd}, {"PBPNT", 0x02de},
|
|
{"PBUFSZ", 0x02df}, {"RUNAD", 0x02e0}, {"RUNAD+1", 0x02e1}, {"INITAD", 0x02e2},
|
|
{"INITAD+1",0x02e3}, {"RAMSIZ", 0x02e4}, {"MEMTOP", 0x02e5}, {"MEMTOP+1",0x02e6},
|
|
{"MEMLO", 0x02e7}, {"MEMLO+1", 0x02e8}, {"HNDLOD", 0x02e9}, {"DVSTAT", 0x02ea},
|
|
{"DVSTAT+1",0x02eb}, {"DVSTAT+2",0x02ec}, {"DVSTAT+3",0x02ed}, {"CBAUDL", 0x02ee},
|
|
{"CBAUDH", 0x02ef}, {"CRSINH", 0x02f0}, {"KEYDEL", 0x02f1}, {"CH1", 0x02f2},
|
|
{"CHACT", 0x02f3}, {"CHBAS", 0x02f4}, {"NEWROW", 0x02f5}, {"NEWCOL", 0x02f6},
|
|
{"NEWCOL+1",0x02f7}, {"ROWINC", 0x02f8}, {"COLINC", 0x02f9}, {"CHAR", 0x02fa},
|
|
{"ATACHR", 0x02fb}, {"CH", 0x02fc}, {"FILDAT", 0x02fd}, {"DSPFLG", 0x02fe},
|
|
{"SSFLAG", 0x02ff},
|
|
|
|
{"DDEVIC", 0x0300}, {"DUNIT", 0x0301}, {"DCOMND", 0x0302}, {"DSTATS", 0x0303},
|
|
{"DBUFLO", 0x0304}, {"DBUFHI", 0x0305}, {"DTIMLO", 0x0306}, {"DUNUSE", 0x0307},
|
|
{"DBYTLO", 0x0308}, {"DBYTHI", 0x0309}, {"DAUX1", 0x030a}, {"DAUX2", 0x030b},
|
|
{"TIMER1", 0x030c}, {"TIMER1+1",0x030d}, {"ADDCOR", 0x030e}, {"CASFLG", 0x030f},
|
|
{"TIMER2", 0x0310}, {"TIMER2+1",0x0311}, {"TEMP1", 0x0312}, {"TEMP1+1", 0x0313},
|
|
{"TEMP2", 0x0314}, {"TEMP3", 0x0315}, {"SAVIO", 0x0316}, {"TIMFLG", 0x0317},
|
|
{"STACKP", 0x0318}, {"TSTAT", 0x0319}, {"HATABS", 0x031a}, /* HATABS 1-34 */
|
|
{"PUTBT1", 0x033d}, {"PUTBT2", 0x033e}, {"PUTBT3", 0x033f},
|
|
{"B0-ICHID",0x0340}, {"B0-ICDNO",0x0341}, {"B0-ICCOM",0x0342}, {"B0-ICSTA",0x0343},
|
|
{"B0-ICBAL",0x0344}, {"B0-ICBAH",0x0345}, {"B0-ICPTL",0x0346}, {"B0-ICPTH",0x0347},
|
|
{"B0-ICBLL",0x0348}, {"B0-ICBLH",0x0349}, {"B0-ICAX1",0x034a}, {"B0-ICAX2",0x034b},
|
|
{"B0-ICAX3",0x034c}, {"B0-ICAX4",0x034d}, {"B0-ICAX5",0x034e}, {"B0-ICAX6",0x034f},
|
|
{"B1-ICHID",0x0350}, {"B1-ICDNO",0x0351}, {"B1-ICCOM",0x0352}, {"B1-ICSTA",0x0353},
|
|
{"B1-ICBAL",0x0354}, {"B1-ICBAH",0x0355}, {"B1-ICPTL",0x0356}, {"B1-ICPTH",0x0357},
|
|
{"B1-ICBLL",0x0358}, {"B1-ICBLH",0x0359}, {"B1-ICAX1",0x035a}, {"B1-ICAX2",0x035b},
|
|
{"B1-ICAX3",0x035c}, {"B1-ICAX4",0x035d}, {"B1-ICAX5",0x035e}, {"B1-ICAX6",0x035f},
|
|
{"B2-ICHID",0x0360}, {"B2-ICDNO",0x0361}, {"B2-ICCOM",0x0362}, {"B2-ICSTA",0x0363},
|
|
{"B2-ICBAL",0x0364}, {"B2-ICBAH",0x0365}, {"B2-ICPTL",0x0366}, {"B2-ICPTH",0x0367},
|
|
{"B2-ICBLL",0x0368}, {"B2-ICBLH",0x0369}, {"B2-ICAX1",0x036a}, {"B2-ICAX2",0x036b},
|
|
{"B2-ICAX3",0x036c}, {"B2-ICAX4",0x036d}, {"B2-ICAX5",0x036e}, {"B2-ICAX6",0x036f},
|
|
{"B3-ICHID",0x0370}, {"B3-ICDNO",0x0371}, {"B3-ICCOM",0x0372}, {"B3-ICSTA",0x0373},
|
|
{"B3-ICBAL",0x0374}, {"B3-ICBAH",0x0375}, {"B3-ICPTL",0x0376}, {"B3-ICPTH",0x0377},
|
|
{"B3-ICBLL",0x0378}, {"B3-ICBLH",0x0379}, {"B3-ICAX1",0x037a}, {"B3-ICAX2",0x037b},
|
|
{"B3-ICAX3",0x037c}, {"B3-ICAX4",0x037d}, {"B3-ICAX5",0x037e}, {"B3-ICAX6",0x037f},
|
|
{"B4-ICHID",0x0380}, {"B4-ICDNO",0x0381}, {"B4-ICCOM",0x0382}, {"B4-ICSTA",0x0383},
|
|
{"B4-ICBAL",0x0384}, {"B4-ICBAH",0x0385}, {"B4-ICPTL",0x0386}, {"B4-ICPTH",0x0387},
|
|
{"B4-ICBLL",0x0388}, {"B4-ICBLH",0x0389}, {"B4-ICAX1",0x038a}, {"B4-ICAX2",0x038b},
|
|
{"B4-ICAX3",0x038c}, {"B4-ICAX4",0x038d}, {"B4-ICAX5",0x038e}, {"B4-ICAX6",0x038f},
|
|
{"B5-ICHID",0x0390}, {"B5-ICDNO",0x0391}, {"B5-ICCOM",0x0392}, {"B5-ICSTA",0x0393},
|
|
{"B5-ICBAL",0x0394}, {"B5-ICBAH",0x0395}, {"B5-ICPTL",0x0396}, {"B5-ICPTH",0x0397},
|
|
{"B5-ICBLL",0x0398}, {"B5-ICBLH",0x0399}, {"B5-ICAX1",0x039a}, {"B5-ICAX2",0x039b},
|
|
{"B5-ICAX3",0x039c}, {"B5-ICAX4",0x039d}, {"B5-ICAX5",0x039e}, {"B5-ICAX6",0x039f},
|
|
{"B6-ICHID",0x03a0}, {"B6-ICDNO",0x03a1}, {"B6-ICCOM",0x03a2}, {"B6-ICSTA",0x03a3},
|
|
{"B6-ICBAL",0x03a4}, {"B6-ICBAH",0x03a5}, {"B6-ICPTL",0x03a6}, {"B6-ICPTH",0x03a7},
|
|
{"B6-ICBLL",0x03a8}, {"B6-ICBLH",0x03a9}, {"B6-ICAX1",0x03aa}, {"B6-ICAX2",0x03ab},
|
|
{"B6-ICAX3",0x03ac}, {"B6-ICAX4",0x03ad}, {"B6-ICAX5",0x03ae}, {"B6-ICAX6",0x03af},
|
|
{"B7-ICHID",0x03b0}, {"B7-ICDNO",0x03b1}, {"B7-ICCOM",0x03b2}, {"B7-ICSTA",0x03b3},
|
|
{"B7-ICBAL",0x03b4}, {"B7-ICBAH",0x03b5}, {"B7-ICPTL",0x03b6}, {"B7-ICPTH",0x03b7},
|
|
{"B7-ICBLL",0x03b8}, {"B7-ICBLH",0x03b9}, {"B7-ICAX1",0x03ba}, {"B7-ICAX2",0x03bb},
|
|
{"B7-ICAX3",0x03bc}, {"B7-ICAX4",0x03bd}, {"B7-ICAX5",0x03be}, {"B7-ICAX6",0x03bf},
|
|
{"PRNBUF", 0x03c0}, /* PRNBUF 1-39 */
|
|
{"SUPERF", 0x03e8}, {"CKEY", 0x03e9}, {"CASSBT", 0x03ea}, {"CARTCK", 0x03eb},
|
|
{"DERRF", 0x03ec}, {"ACMVAR", 0x03ed}, /* ACMVAR 1-10 */
|
|
{"BASICF", 0x03f8}, {"MINTLK", 0x03f9}, {"GINTLK", 0x03fa}, {"CHLINK", 0x03fb},
|
|
{"CHLINK+1",0x03fc}, {"CASBUF", 0x03fd},
|
|
|
|
{"M0PF", 0xd000}, {"HPOSP0",0xd000}, {"M1PF", 0xd001}, {"HPOSP1",0xd001},
|
|
{"M2PF", 0xd002}, {"HPOSP2",0xd002}, {"M3PF", 0xd003}, {"HPOSP3",0xd003},
|
|
{"P0PF", 0xd004}, {"HPOSM0",0xd004}, {"P1PF", 0xd005}, {"HPOSM1",0xd005},
|
|
{"P2PF", 0xd006}, {"HPOSM2",0xd006}, {"P3PF", 0xd007}, {"HPOSM3",0xd007},
|
|
{"M0PL", 0xd008}, {"SIZEP0",0xd008}, {"M1PL", 0xd009}, {"SIZEP1",0xd009},
|
|
{"M2PL", 0xd00a}, {"SIZEP2",0xd00a}, {"M3PL", 0xd00b}, {"SIZEP3",0xd00b},
|
|
{"P0PL", 0xd00c}, {"SIZEM", 0xd00c}, {"P1PL", 0xd00d}, {"GRAFP0",0xd00d},
|
|
{"P2PL", 0xd00e}, {"GRAFP1",0xd00e}, {"P3PL", 0xd00f}, {"GRAFP2",0xd00f},
|
|
{"TRIG0", 0xd010}, {"GRAFP3",0xd010}, {"TRIG1", 0xd011}, {"GRAFM", 0xd011},
|
|
{"TRIG2", 0xd012}, {"COLPM0",0xd012}, {"TRIG3", 0xd013}, {"COLPM1",0xd013},
|
|
{"PAL", 0xd014}, {"COLPM2",0xd014}, {"COLPM3",0xd015}, {"COLPF0",0xd016},
|
|
{"COLPF1",0xd017},
|
|
{"COLPF2",0xd018}, {"COLPF3",0xd019}, {"COLBK", 0xd01a}, {"PRIOR", 0xd01b},
|
|
{"VDELAY",0xd01c}, {"GRACTL",0xd01d}, {"HITCLR",0xd01e}, {"CONSOL",0xd01f},
|
|
|
|
{"POT0", 0xd200}, {"AUDF1", 0xd200}, {"POT1", 0xd201}, {"AUDC1", 0xd201},
|
|
{"POT2", 0xd202}, {"AUDF2", 0xd202}, {"POT3", 0xd203}, {"AUDC2", 0xd203},
|
|
{"POT4", 0xd204}, {"AUDF3", 0xd204}, {"POT5", 0xd205}, {"AUDC3", 0xd205},
|
|
{"POT6", 0xd206}, {"AUDF4", 0xd206}, {"POT7", 0xd207}, {"AUDC4", 0xd207},
|
|
{"ALLPOT",0xd208}, {"AUDCTL",0xd208}, {"KBCODE",0xd209}, {"STIMER",0xd209},
|
|
{"RANDOM",0xd20a}, {"SKREST",0xd20a}, {"POTGO", 0xd20b},
|
|
{"SERIN", 0xd20d}, {"SEROUT",0xd20d}, {"IRQST", 0xd20e}, {"IRQEN", 0xd20e},
|
|
{"SKSTAT",0xd20f}, {"SKCTL", 0xd20f},
|
|
|
|
{"PORTA", 0xd300}, {"PORTB", 0xd301}, {"PACTL", 0xd302}, {"PBCTL", 0xd303},
|
|
|
|
{"DMACTL",0xd400}, {"CHACTL",0xd401}, {"DLISTL",0xd402}, {"DLISTH",0xd403},
|
|
{"HSCROL",0xd404}, {"VSCROL",0xd405}, {"PMBASE",0xd407}, {"CHBASE",0xd409},
|
|
{"WSYNC", 0xd40a}, {"VCOUNT",0xd40b}, {"PENH", 0xd40c}, {"PENV", 0xd40d},
|
|
{"NMIEN", 0xd40e}, {"NMIST", 0xd40f}, {"NMIRES",0xd40f},
|
|
|
|
{"AFP", 0xd800}, {"FASC", 0xd8e6}, {"IFP", 0xd9aa}, {"FPI", 0xd9d2},
|
|
{"ZPRO", 0xda44}, {"ZF1", 0xda46}, {"FSUB", 0xda60}, {"FADD", 0xda66},
|
|
{"FMUL", 0xdadb}, {"FDIV", 0xdb28}, {"PLYEVL",0xdd40}, {"FLD0R", 0xdd89},
|
|
{"FLD0R", 0xdd8d}, {"FLD1R", 0xdd98}, {"FLD1P", 0xdd9c}, {"FST0R", 0xdda7},
|
|
{"FST0P", 0xddab}, {"FMOVE", 0xddb6}, {"EXP", 0xddc0}, {"EXP10", 0xddcc},
|
|
{"LOG", 0xdecd}, {"LOG10", 0xded1},
|
|
|
|
{"DSKINV",0xe453}, {"CIOV", 0xe456}, {"SIOV", 0xe459}, {"SETVBV",0xe45c},
|
|
{"SYSVBV",0xe45f}, {"XITVBV",0xe462}, {"SIOINV",0xe465}, {"SENDEV",0xe468},
|
|
{"INTINV",0xe46b}, {"CIOINV",0xe46e}, {"SELFSV",0xe471}, {"WARMSV",0xe474},
|
|
{"COLDSV",0xe477}, {"RBLOKV",0xe47a}, {"CSOPIV",0xe47d}, {"PUPDIV",0xe480},
|
|
{"SELFTSV",0xe483},{"PENTV", 0xe486}, {"PHUNLV",0xe489}, {"PHINIV",0xe48c},
|
|
{"GPDVV", 0xe48f},
|
|
|
|
{NULL, 0x0000}
|
|
};
|
|
|
|
static const symtable_rec symtable_builtin_5200[] = {
|
|
{"POKMSK", 0x0000}, {"RTCLOKH", 0x0001}, {"RTCLOKL",0x0002}, {"CRITIC", 0x0003},
|
|
{"ATRACT", 0x0004}, {"SDLSTL", 0x0005}, {"SDLSTH", 0x0006}, {"SDMCTL", 0x0007},
|
|
{"PCOLR0", 0x0008}, {"PCOLR1", 0x0009}, {"PCOLR2",0x000a}, {"PCOLR3", 0x000b},
|
|
{"COLOR0",0x000c}, {"COLOR1", 0x000d}, {"COLOR2",0x000e}, {"COLOR3", 0x000f},
|
|
{"COLOR4", 0x0010}, {"PADDL0", 0x0011}, {"PADDL1",0x0012}, {"PADDL2",0x0013},
|
|
{"PADDL3", 0x0014}, {"PADDL4",0x0015}, {"PADDL5", 0x0016}, {"PADDL6", 0x0017},
|
|
{"PADDL7",0x0018},
|
|
|
|
{"VIMIRQ", 0x0200}, {"VIMIRQ+1",0x0201}, {"VVBLKI", 0x0202}, {"VVBLKI+1",0x0203},
|
|
{"VVBLKD", 0x0204}, {"VVBLKD+1",0x0205}, {"VDSLST", 0x0206}, {"VDSLST+1",0x0207},
|
|
{"VKEYBD", 0x0208}, {"VKEYBD+1",0x0209}, {"VKPD", 0x020a}, {"VKPD+1",0x020b},
|
|
{"BRKKY", 0x020c}, {"BRKKY+1",0x020d}, {"VBREAK", 0x020e}, {"VBREAK+1",0x020f},
|
|
{"VSERIN", 0x0210}, {"VSERIN+1",0x0211}, {"VSEROR", 0x0212}, {"VSEROR+1",0x0213},
|
|
{"VSEROC", 0x0214}, {"VSEROC+1",0x0215}, {"VTIMR1", 0x0216}, {"VTIMR1+1",0x0217},
|
|
{"VTIMR2", 0x0218}, {"VTIMR2+1",0x0219}, {"VTIMR4", 0x021a}, {"VTIMR4+1",0x021b},
|
|
|
|
{"M0PF", 0xc000}, {"HPOSP0",0xc000}, {"M1PF", 0xc001}, {"HPOSP1",0xc001},
|
|
{"M2PF", 0xc002}, {"HPOSP2",0xc002}, {"M3PF", 0xc003}, {"HPOSP3",0xc003},
|
|
{"P0PF", 0xc004}, {"HPOSM0",0xc004}, {"P1PF", 0xc005}, {"HPOSM1",0xc005},
|
|
{"P2PF", 0xc006}, {"HPOSM2",0xc006}, {"P3PF", 0xc007}, {"HPOSM3",0xc007},
|
|
{"M0PL", 0xc008}, {"SIZEP0",0xc008}, {"M1PL", 0xc009}, {"SIZEP1",0xc009},
|
|
{"M2PL", 0xc00a}, {"SIZEP2",0xc00a}, {"M3PL", 0xc00b}, {"SIZEP3",0xc00b},
|
|
{"P0PL", 0xc00c}, {"SIZEM", 0xc00c}, {"P1PL", 0xc00d}, {"GRAFP0",0xc00d},
|
|
{"P2PL", 0xc00e}, {"GRAFP1",0xc00e}, {"P3PL", 0xc00f}, {"GRAFP2",0xc00f},
|
|
{"TRIG0", 0xc010}, {"GRAFP3",0xc010}, {"TRIG1", 0xc011}, {"GRAFM", 0xc011},
|
|
{"TRIG2", 0xc012}, {"COLPM0",0xc012}, {"TRIG3", 0xc013}, {"COLPM1",0xc013},
|
|
{"PAL", 0xc014}, {"COLPM2",0xc014}, {"COLPM3",0xc015}, {"COLPF0",0xc016},
|
|
{"COLPF1",0xc017},
|
|
{"COLPF2",0xc018}, {"COLPF3",0xc019}, {"COLBK", 0xc01a}, {"PRIOR", 0xc01b},
|
|
{"VDELAY",0xc01c}, {"GRACTL",0xc01d}, {"HITCLR",0xc01e}, {"CONSOL",0xc01f},
|
|
{"DMACTL",0xd400}, {"CHACTL",0xd401}, {"DLISTL",0xd402}, {"DLISTH",0xd403},
|
|
{"HSCROL",0xd404}, {"VSCROL",0xd405}, {"PMBASE",0xd407}, {"CHBASE",0xd409},
|
|
{"WSYNC", 0xd40a}, {"VCOUNT",0xd40b}, {"PENH", 0xd40c}, {"PENV", 0xd40d},
|
|
{"NMIEN", 0xd40e}, {"NMIST", 0xd40f}, {"NMIRES",0xd40f},
|
|
|
|
{"POT0", 0xe800}, {"AUDF1", 0xe800}, {"POT1", 0xe801}, {"AUDC1", 0xe801},
|
|
{"POT2", 0xe802}, {"AUDF2", 0xe802}, {"POT3", 0xe803}, {"AUDC2", 0xe803},
|
|
{"POT4", 0xe804}, {"AUDF3", 0xe804}, {"POT5", 0xe805}, {"AUDC3", 0xe805},
|
|
{"POT6", 0xe806}, {"AUDF4", 0xe806}, {"POT7", 0xe807}, {"AUDC4", 0xe807},
|
|
{"ALLPOT",0xe808}, {"AUDCTL",0xe808}, {"KBCODE",0xe809}, {"STIMER",0xe809},
|
|
{"RANDOM",0xe80a}, {"SKREST",0xe80a}, {"POTGO", 0xe80b},
|
|
{"SERIN", 0xe80d}, {"SEROUT",0xe80d}, {"IRQST", 0xe80e}, {"IRQEN", 0xe80e},
|
|
{"SKSTAT",0xe80f}, {"SKCTL", 0xe80f},
|
|
|
|
{NULL, 0x0000}
|
|
};
|
|
|
|
static int symtable_builtin_enable = TRUE;
|
|
|
|
static symtable_rec *symtable_user = NULL;
|
|
static int symtable_user_size = 0;
|
|
|
|
static const char *find_label_name(UWORD addr, int is_write)
|
|
{
|
|
int i;
|
|
for (i = 0; i < symtable_user_size; i++) {
|
|
if (symtable_user[i].addr == addr)
|
|
return symtable_user[i].name;
|
|
}
|
|
if (symtable_builtin_enable) {
|
|
const symtable_rec *p;
|
|
for (p = (Atari800_machine_type == Atari800_MACHINE_5200 ? symtable_builtin_5200 : symtable_builtin); p->name != NULL; p++) {
|
|
if (p->addr == addr) {
|
|
if (is_write && p[1].addr == addr)
|
|
p++;
|
|
return p->name;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static symtable_rec *find_user_label(const char *name)
|
|
{
|
|
int i;
|
|
for (i = 0; i < symtable_user_size; i++) {
|
|
if (Util_stricmp(symtable_user[i].name, name) == 0)
|
|
return &symtable_user[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int find_label_value(const char *name)
|
|
{
|
|
const symtable_rec *p = find_user_label(name);
|
|
if (p != NULL)
|
|
return p->addr;
|
|
if (symtable_builtin_enable) {
|
|
for (p = (Atari800_machine_type == Atari800_MACHINE_5200 ? symtable_builtin_5200 : symtable_builtin); p->name != NULL; p++) {
|
|
if (Util_stricmp(p->name, name) == 0)
|
|
return p->addr;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void free_user_labels(void)
|
|
{
|
|
if (symtable_user != NULL) {
|
|
while (symtable_user_size > 0)
|
|
free(symtable_user[--symtable_user_size].name);
|
|
free(symtable_user);
|
|
symtable_user = NULL;
|
|
}
|
|
}
|
|
|
|
static void add_user_label(const char *name, UWORD addr)
|
|
{
|
|
#define SYMTABLE_USER_INITIAL_SIZE 128
|
|
if (symtable_user == NULL)
|
|
symtable_user = (symtable_rec *) Util_malloc(SYMTABLE_USER_INITIAL_SIZE * sizeof(symtable_rec));
|
|
else if (symtable_user_size >= SYMTABLE_USER_INITIAL_SIZE
|
|
&& (symtable_user_size & (symtable_user_size - 1)) == 0) {
|
|
/* symtable_user_size is a power of two: allocate twice as much */
|
|
symtable_user = (symtable_rec *) Util_realloc(symtable_user,
|
|
2 * symtable_user_size * sizeof(symtable_rec));
|
|
}
|
|
symtable_user[symtable_user_size].name = Util_strdup(name);
|
|
symtable_user[symtable_user_size].addr = addr;
|
|
symtable_user_size++;
|
|
}
|
|
|
|
static void load_user_labels(const char *filename)
|
|
{
|
|
FILE *fp;
|
|
char line[256];
|
|
if (filename == NULL) {
|
|
printf("You must specify a filename\n");
|
|
return;
|
|
}
|
|
/* "rb" and not "r", because we strip EOLs ourselves
|
|
- this is better, because we can use CR/LF files on Unix */
|
|
fp = fopen(filename, "rb");
|
|
if (fp == NULL) {
|
|
perror(filename);
|
|
return;
|
|
}
|
|
free_user_labels();
|
|
while (fgets(line, sizeof(line), fp)) {
|
|
char *p;
|
|
unsigned int value = 0;
|
|
int digits = 0;
|
|
/* Find first 4 hex digits or more. */
|
|
/* We don't support "Cafe Assembler", "Dead Assembler" or "C0de Assembler". ;-) */
|
|
for (p = line; *p != '\0'; p++) {
|
|
if (*p >= '0' && *p <= '9') {
|
|
value = (value << 4) + *p - '0';
|
|
digits++;
|
|
}
|
|
else if (*p >= 'A' && *p <= 'F') {
|
|
value = (value << 4) + *p - 'A' + 10;
|
|
digits++;
|
|
}
|
|
else if (*p >= 'a' && *p <= 'f') {
|
|
value = (value << 4) + *p - 'a' + 10;
|
|
digits++;
|
|
}
|
|
else if (digits >= 4)
|
|
break;
|
|
else if (*p == '-')
|
|
break; /* ignore labels with negative values */
|
|
else {
|
|
/* note that xasm can put "2" before the label value and mads puts "00" */
|
|
value = 0;
|
|
digits = 0;
|
|
}
|
|
}
|
|
if (*p != ' ' && *p != '\t')
|
|
continue;
|
|
if (value > 0xffff || digits > 8)
|
|
continue;
|
|
do
|
|
p++;
|
|
while (*p == ' ' || *p == '\t');
|
|
Util_chomp(p);
|
|
if (*p == '\0')
|
|
continue;
|
|
add_user_label(p, (UWORD) value);
|
|
}
|
|
fclose(fp);
|
|
printf("Loaded %d labels\n", symtable_user_size);
|
|
}
|
|
|
|
#endif /* MONITOR_HINTS */
|
|
|
|
static const char instr6502[256][10] = {
|
|
"BRK", "ORA (1,X)", "CIM", "ASO (1,X)", "NOP 1", "ORA 1", "ASL 1", "ASO 1",
|
|
"PHP", "ORA #1", "ASL", "ANC #1", "NOP 2", "ORA 2", "ASL 2", "ASO 2",
|
|
|
|
"BPL 0", "ORA (1),Y", "CIM", "ASO (1),Y", "NOP 1,X", "ORA 1,X", "ASL 1,X", "ASO 1,X",
|
|
"CLC", "ORA 2,Y", "NOP !", "ASO 2,Y", "NOP 2,X", "ORA 2,X", "ASL 2,X", "ASO 2,X",
|
|
|
|
"JSR 2", "AND (1,X)", "CIM", "RLA (1,X)", "BIT 1", "AND 1", "ROL 1", "RLA 1",
|
|
"PLP", "AND #1", "ROL", "ANC #1", "BIT 2", "AND 2", "ROL 2", "RLA 2",
|
|
|
|
"BMI 0", "AND (1),Y", "CIM", "RLA (1),Y", "NOP 1,X", "AND 1,X", "ROL 1,X", "RLA 1,X",
|
|
"SEC", "AND 2,Y", "NOP !", "RLA 2,Y", "NOP 2,X", "AND 2,X", "ROL 2,X", "RLA 2,X",
|
|
|
|
|
|
"RTI", "EOR (1,X)", "CIM", "LSE (1,X)", "NOP 1", "EOR 1", "LSR 1", "LSE 1",
|
|
"PHA", "EOR #1", "LSR", "ALR #1", "JMP 2", "EOR 2", "LSR 2", "LSE 2",
|
|
|
|
"BVC 0", "EOR (1),Y", "CIM", "LSE (1),Y", "NOP 1,X", "EOR 1,X", "LSR 1,X", "LSE 1,X",
|
|
"CLI", "EOR 2,Y", "NOP !", "LSE 2,Y", "NOP 2,X", "EOR 2,X", "LSR 2,X", "LSE 2,X",
|
|
|
|
"RTS", "ADC (1,X)", "CIM", "RRA (1,X)", "NOP 1", "ADC 1", "ROR 1", "RRA 1",
|
|
"PLA", "ADC #1", "ROR", "ARR #1", "JMP (2)", "ADC 2", "ROR 2", "RRA 2",
|
|
|
|
"BVS 0", "ADC (1),Y", "CIM", "RRA (1),Y", "NOP 1,X", "ADC 1,X", "ROR 1,X", "RRA 1,X",
|
|
"SEI", "ADC 2,Y", "NOP !", "RRA 2,Y", "NOP 2,X", "ADC 2,X", "ROR 2,X", "RRA 2,X",
|
|
|
|
|
|
"NOP #1", "STA (1,X)", "NOP #1", "SAX (1,X)", "STY 1", "STA 1", "STX 1", "SAX 1",
|
|
"DEY", "NOP #1", "TXA", "ANE #1", "STY 2", "STA 2", "STX 2", "SAX 2",
|
|
|
|
"BCC 0", "STA (1),Y", "CIM", "SHA (1),Y", "STY 1,X", "STA 1,X", "STX 1,Y", "SAX 1,Y",
|
|
"TYA", "STA 2,Y", "TXS", "SHS 2,Y", "SHY 2,X", "STA 2,X", "SHX 2,Y", "SHA 2,Y",
|
|
|
|
"LDY #1", "LDA (1,X)", "LDX #1", "LAX (1,X)", "LDY 1", "LDA 1", "LDX 1", "LAX 1",
|
|
"TAY", "LDA #1", "TAX", "ANX #1", "LDY 2", "LDA 2", "LDX 2", "LAX 2",
|
|
|
|
"BCS 0", "LDA (1),Y", "CIM", "LAX (1),Y", "LDY 1,X", "LDA 1,X", "LDX 1,Y", "LAX 1,X",
|
|
"CLV", "LDA 2,Y", "TSX", "LAS 2,Y", "LDY 2,X", "LDA 2,X", "LDX 2,Y", "LAX 2,Y",
|
|
|
|
|
|
"CPY #1", "CMP (1,X)", "NOP #1", "DCM (1,X)", "CPY 1", "CMP 1", "DEC 1", "DCM 1",
|
|
"INY", "CMP #1", "DEX", "SBX #1", "CPY 2", "CMP 2", "DEC 2", "DCM 2",
|
|
|
|
"BNE 0", "CMP (1),Y", "ESCRTS #1", "DCM (1),Y", "NOP 1,X", "CMP 1,X", "DEC 1,X", "DCM 1,X",
|
|
"CLD", "CMP 2,Y", "NOP !", "DCM 2,Y", "NOP 2,X", "CMP 2,X", "DEC 2,X", "DCM 2,X",
|
|
|
|
|
|
"CPX #1", "SBC (1,X)", "NOP #1", "INS (1,X)", "CPX 1", "SBC 1", "INC 1", "INS 1",
|
|
"INX", "SBC #1", "NOP", "SBC #1 !", "CPX 2", "SBC 2", "INC 2", "INS 2",
|
|
|
|
"BEQ 0", "SBC (1),Y", "ESCAPE #1", "INS (1),Y", "NOP 1,X", "SBC 1,X", "INC 1,X", "INS 1,X",
|
|
"SED", "SBC 2,Y", "NOP !", "INS 2,Y", "NOP 2,X", "SBC 2,X", "INC 2,X", "INS 2,X"
|
|
};
|
|
|
|
/* Opcode type:
|
|
bits 1-0 = instruction length
|
|
bit 2 = instruction reads from memory (without stack-manipulating instructions)
|
|
bit 3 = instruction writes to memory (without stack-manipulating instructions)
|
|
bits 7-4 = adressing type:
|
|
0 = NONE (implicit)
|
|
1 = ABSOLUTE
|
|
2 = ZPAGE
|
|
3 = ABSOLUTE_X
|
|
4 = ABSOLUTE_Y
|
|
5 = INDIRECT_X
|
|
6 = INDIRECT_Y
|
|
7 = ZPAGE_X
|
|
8 = ZPAGE_Y
|
|
9 = RELATIVE
|
|
A = IMMEDIATE
|
|
B = STACK 2 (RTS)
|
|
C = STACK 3 (RTI)
|
|
D = INDIRECT (JMP () )
|
|
E = ESCRTS
|
|
F = ESCAPE */
|
|
const UBYTE MONITOR_optype6502[256] = {
|
|
0x01, 0x56, 0x01, 0x5e, 0x22, 0x26, 0x2e, 0x2e, 0x01, 0xa2, 0x01, 0xa2, 0x13, 0x17, 0x1f, 0x1f,
|
|
0x92, 0x66, 0x01, 0x6e, 0x72, 0x76, 0x7e, 0x7e, 0x01, 0x47, 0x01, 0x4f, 0x33, 0x37, 0x3f, 0x3f,
|
|
0x13, 0x56, 0x01, 0x5e, 0x26, 0x26, 0x2e, 0x2e, 0x01, 0xa2, 0x01, 0xa2, 0x17, 0x17, 0x1f, 0x1f,
|
|
0x92, 0x66, 0x01, 0x6e, 0x72, 0x76, 0x7e, 0x7e, 0x01, 0x47, 0x01, 0x4f, 0x33, 0x37, 0x3f, 0x3f,
|
|
0xc1, 0x56, 0x01, 0x5e, 0x22, 0x26, 0x2e, 0x2e, 0x01, 0xa2, 0x01, 0xa2, 0x13, 0x17, 0x1f, 0x1f,
|
|
0x92, 0x66, 0x01, 0x6e, 0x72, 0x76, 0x7e, 0x7e, 0x01, 0x47, 0x01, 0x4f, 0x33, 0x37, 0x3f, 0x3f,
|
|
0xb1, 0x56, 0x01, 0x5e, 0x22, 0x26, 0x2e, 0x2e, 0x01, 0xa2, 0x01, 0xa2, 0xd3, 0x17, 0x1f, 0x1f,
|
|
0x92, 0x66, 0x01, 0x6e, 0x72, 0x76, 0x7e, 0x7e, 0x01, 0x47, 0x01, 0x4f, 0x33, 0x37, 0x3f, 0x3f,
|
|
0xa2, 0x5a, 0x01, 0x5a, 0x2a, 0x2a, 0x2a, 0x2a, 0x01, 0xa2, 0x01, 0xa2, 0x1b, 0x1b, 0x1b, 0x1b,
|
|
0x92, 0x6a, 0x01, 0x6a, 0x7a, 0x7a, 0x8a, 0x8a, 0x01, 0x4b, 0x01, 0x4b, 0x3b, 0x3b, 0x4b, 0x4b,
|
|
0xa2, 0x56, 0xa2, 0x56, 0x26, 0x26, 0x26, 0x26, 0x01, 0xa2, 0x01, 0xa2, 0x17, 0x17, 0x17, 0x17,
|
|
0x92, 0x66, 0x01, 0x66, 0x76, 0x76, 0x86, 0x86, 0x01, 0x47, 0x01, 0x47, 0x37, 0x37, 0x47, 0x47,
|
|
0xa2, 0x56, 0xa2, 0x5e, 0x26, 0x26, 0x2e, 0x2e, 0x01, 0xa2, 0x01, 0xa2, 0x17, 0x17, 0x1f, 0x1f,
|
|
0x92, 0x66, 0xe2, 0x6e, 0x72, 0x76, 0x7e, 0x7e, 0x01, 0x47, 0x01, 0x4f, 0x33, 0x37, 0x3f, 0x3f,
|
|
0xa2, 0x56, 0xa2, 0x5e, 0x26, 0x26, 0x2e, 0x2e, 0x01, 0xa2, 0x01, 0xa2, 0x17, 0x17, 0x1f, 0x1f,
|
|
0x92, 0x66, 0xf2, 0x6e, 0x72, 0x76, 0x7e, 0x7e, 0x01, 0x47, 0x01, 0x4f, 0x33, 0x37, 0x3f, 0x3f
|
|
};
|
|
|
|
|
|
static void safe_gets(char *buffer, size_t size)
|
|
{
|
|
#ifdef HAVE_FFLUSH
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
#ifdef MONITOR_READLINE
|
|
{
|
|
char *got = readline("");
|
|
if (got) {
|
|
strncpy(buffer, got, size);
|
|
if (*got)
|
|
add_history(got);
|
|
}
|
|
}
|
|
#else
|
|
fgets(buffer, size, stdin);
|
|
#endif
|
|
Util_chomp(buffer);
|
|
}
|
|
|
|
static int pager(void)
|
|
{
|
|
char buf[100];
|
|
printf("Press Return to continue ('q' to quit): ");
|
|
safe_gets(buf, sizeof(buf));
|
|
return buf[0] == 'q' || buf[0] == 'Q';
|
|
}
|
|
|
|
static char *token_ptr;
|
|
|
|
static char *get_token(void)
|
|
{
|
|
char *p = token_ptr;
|
|
while (*p == ' ')
|
|
p++;
|
|
if (*p == '\0')
|
|
return NULL;
|
|
token_ptr = p;
|
|
do {
|
|
token_ptr++;
|
|
if (*token_ptr == ' ') {
|
|
*token_ptr++ = '\0';
|
|
break;
|
|
}
|
|
} while (*token_ptr != '\0');
|
|
return p;
|
|
}
|
|
|
|
#if defined(MONITOR_BREAK) || !defined(NO_YPOS_BREAK_FLICKER)
|
|
static int get_dec(int *decval)
|
|
{
|
|
const char *t;
|
|
t = get_token();
|
|
if (t != NULL) {
|
|
int x = Util_sscandec(t);
|
|
if (x < 0)
|
|
return FALSE;
|
|
*decval = x;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
static int parse_hex(const char *s, UWORD *hexval)
|
|
{
|
|
int x = Util_sscanhex(s);
|
|
#ifdef MONITOR_HINTS
|
|
int y = find_label_value(s);
|
|
if (y >= 0) {
|
|
if (x < 0 || x > 0xffff || x == y) {
|
|
*hexval = (UWORD) y;
|
|
return TRUE;
|
|
}
|
|
/* s can be a hex number or a label name */
|
|
printf("%s is ambiguous. Use 0%X or %X instead.\n", s, x, y);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
if (x < 0 || x > 0xffff)
|
|
return FALSE;
|
|
*hexval = (UWORD) x;
|
|
return TRUE;
|
|
}
|
|
|
|
static int get_hex(UWORD *hexval)
|
|
{
|
|
const char *t;
|
|
t = get_token();
|
|
if (t != NULL)
|
|
return parse_hex(t, hexval);
|
|
return FALSE;
|
|
}
|
|
|
|
static int get_hex2(UWORD *hexval1, UWORD *hexval2)
|
|
{
|
|
return get_hex(hexval1) && get_hex(hexval2);
|
|
}
|
|
|
|
static int get_hex3(UWORD *hexval1, UWORD *hexval2, UWORD *hexval3)
|
|
{
|
|
return get_hex(hexval1) && get_hex(hexval2) && get_hex(hexval3);
|
|
}
|
|
|
|
static void get_uword(UWORD *val)
|
|
{
|
|
if (!get_hex(val))
|
|
printf("Invalid argument!\n");
|
|
}
|
|
|
|
static void get_ubyte(UBYTE *val)
|
|
{
|
|
UWORD uword;
|
|
if (!get_hex(&uword) || uword > 0xff)
|
|
printf("Invalid argument!\n");
|
|
else
|
|
*val = (UBYTE) uword;
|
|
}
|
|
|
|
static int get_bool(void)
|
|
{
|
|
const char *t;
|
|
t = get_token();
|
|
if (t != NULL) {
|
|
int result = Util_sscanbool(t);
|
|
if (result >= 0)
|
|
return result;
|
|
}
|
|
printf("Invalid argument (should be 0 or 1)!\n");
|
|
return -1;
|
|
}
|
|
|
|
static int get_attrib_range(UWORD *addr1, UWORD *addr2)
|
|
{
|
|
if (get_hex2(addr1, addr2) && *addr1 <= *addr2) {
|
|
#ifdef PAGED_ATTRIB
|
|
if ((*addr1 & 0xff) != 0 || (*addr2 & 0xff) != 0xff) {
|
|
printf("This is PAGED_ATTRIB version of Atari800.\n"
|
|
"You can only change attributes of full memory pages.\n");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
printf("Missing or bad argument!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
static UWORD show_instruction(FILE *fp, UWORD pc)
|
|
{
|
|
UWORD addr = pc;
|
|
UBYTE insn;
|
|
const char *mnemonic;
|
|
const char *p;
|
|
int value = 0;
|
|
int nchars = 0;
|
|
|
|
insn = MEMORY_dGetByte(pc++);
|
|
mnemonic = instr6502[insn];
|
|
for (p = mnemonic + 3; *p != '\0'; p++) {
|
|
if (*p == '1') {
|
|
value = MEMORY_dGetByte(pc++);
|
|
nchars = fprintf(fp, "%04X: %02X %02X " /*"%Xcyc "*/ "%.*s$%02X%s",
|
|
addr, insn, value, /*cycles[insn],*/ (int) (p - mnemonic), mnemonic, value, p + 1);
|
|
break;
|
|
}
|
|
if (*p == '2') {
|
|
value = MEMORY_dGetWord(pc);
|
|
nchars = fprintf(fp, "%04X: %02X %02X %02X " /*"%Xcyc "*/ "%.*s$%04X%s",
|
|
addr, insn, value & 0xff, value >> 8, /*cycles[insn],*/ (int) (p - mnemonic), mnemonic, value, p + 1);
|
|
pc += 2;
|
|
break;
|
|
}
|
|
if (*p == '0') {
|
|
UBYTE op = MEMORY_dGetByte(pc++);
|
|
value = (UWORD) (pc + (SBYTE) op);
|
|
nchars = fprintf(fp, "%04X: %02X %02X " /*"3cyc "*/ "%.4s$%04X", addr, insn, op, mnemonic, value);
|
|
break;
|
|
}
|
|
}
|
|
if (*p == '\0') {
|
|
fprintf(fp, "%04X: %02X " /*"%Xcyc "*/ "%s\n", addr, insn, /*cycles[insn],*/ mnemonic);
|
|
return pc;
|
|
}
|
|
#ifdef MONITOR_HINTS
|
|
if (p[-1] != '#') {
|
|
/* different names when reading/writing memory */
|
|
const char *label = find_label_name((UWORD) value, (MONITOR_optype6502[insn] & 0x08) != 0);
|
|
if (label != NULL) {
|
|
fprintf(fp, "%*s;%s\n", 28 - nchars, "", label);
|
|
return pc;
|
|
}
|
|
}
|
|
#endif
|
|
fputc('\n', fp);
|
|
return pc;
|
|
}
|
|
|
|
void MONITOR_ShowState(FILE *fp, UWORD pc, UBYTE a, UBYTE x, UBYTE y, UBYTE s,
|
|
char n, char v, char z, char c)
|
|
{
|
|
fprintf(fp, "%3d %3d A=%02X X=%02X Y=%02X S=%02X P=%c%c*-%c%c%c%c PC=",
|
|
ANTIC_ypos, ANTIC_xpos, a, x, y, s,
|
|
n, v, (CPU_regP & CPU_D_FLAG) ? 'D' : '-', (CPU_regP & CPU_I_FLAG) ? 'I' : '-', z, c);
|
|
show_instruction(fp, pc);
|
|
}
|
|
|
|
static void show_state(void)
|
|
{
|
|
MONITOR_ShowState(stdout, CPU_regPC, CPU_regA, CPU_regX, CPU_regY, CPU_regS,
|
|
(char) ((CPU_regP & CPU_N_FLAG) ? 'N' : '-'), (char) ((CPU_regP & CPU_V_FLAG) ? 'V' : '-'),
|
|
(char) ((CPU_regP & CPU_Z_FLAG) ? 'Z' : '-'), (char) ((CPU_regP & CPU_C_FLAG) ? 'C' : '-'));
|
|
}
|
|
|
|
static UWORD disassemble(UWORD addr)
|
|
{
|
|
int count = 24;
|
|
do
|
|
addr = show_instruction(stdout, addr);
|
|
while (--count > 0);
|
|
return addr;
|
|
}
|
|
|
|
#ifdef MONITOR_ASSEMBLER
|
|
static UWORD assembler(UWORD addr)
|
|
{
|
|
printf("Simple assembler (enter empty line to exit)\n");
|
|
for (;;) {
|
|
char s[128]; /* input string */
|
|
char c[128]; /* converted input */
|
|
char *sp; /* input pointer */
|
|
char *cp; /* converted input pointer */
|
|
char *vp; /* value pointer (the value is stored in s) */
|
|
char *tp; /* type pointer (points at type character '0', '1' or '2' in converted input) */
|
|
int i;
|
|
int isa; /* the operand is "A" */
|
|
UWORD value = 0;
|
|
|
|
printf("%04X: ", (int) addr);
|
|
safe_gets(s, sizeof(s));
|
|
if (s[0] == '\0')
|
|
return addr;
|
|
|
|
Util_strupper(s);
|
|
|
|
sp = s;
|
|
cp = c;
|
|
/* copy first three characters */
|
|
for (i = 0; i < 3 && *sp != '\0'; i++)
|
|
*cp++ = *sp++;
|
|
/* insert space before operands */
|
|
*cp++ = ' ';
|
|
|
|
tp = NULL;
|
|
isa = FALSE;
|
|
|
|
/* convert input to format of instr6502[] table */
|
|
while (*sp != '\0') {
|
|
switch (*sp) {
|
|
case ' ':
|
|
case '\t':
|
|
case '$':
|
|
case '@':
|
|
sp++;
|
|
break;
|
|
case '#':
|
|
case '(':
|
|
case ')':
|
|
case ',':
|
|
isa = FALSE;
|
|
*cp++ = *sp++;
|
|
break;
|
|
default:
|
|
if (tp != NULL) {
|
|
if (*sp == 'X' || *sp == 'Y') {
|
|
*cp++ = *sp++;
|
|
break;
|
|
}
|
|
goto invalid_instr;
|
|
}
|
|
vp = s;
|
|
do
|
|
*vp++ = *sp++;
|
|
while (strchr(" \t$@#(),", *sp) == NULL && *sp != '\0');
|
|
/* If *sp=='\0', strchr() should return non-NULL,
|
|
but we do an extra check to be on safe side. */
|
|
*vp++ = '\0';
|
|
tp = cp++;
|
|
*tp = '0';
|
|
isa = (s[0] == 'A' && s[1] == '\0');
|
|
break;
|
|
}
|
|
}
|
|
if (cp[-1] == ' ')
|
|
cp--; /* no arguments (e.g. NOP or ASL @) */
|
|
*cp = '\0';
|
|
|
|
/* if there's an operand, get its value */
|
|
if (tp != NULL && !parse_hex(s, &value)) {
|
|
printf("Invalid operand!\n");
|
|
continue;
|
|
}
|
|
|
|
for (;;) {
|
|
/* search table for instruction */
|
|
for (i = 0; i < 256; i++) {
|
|
if (strcmp(instr6502[i], c) == 0) {
|
|
if (tp == NULL) {
|
|
MEMORY_dPutByte(addr, (UBYTE) i);
|
|
addr++;
|
|
}
|
|
else if (*tp == '0') {
|
|
value -= (addr + 2);
|
|
if ((SWORD) value < -128 || (SWORD) value > 127)
|
|
printf("Branch out of range!\n");
|
|
else {
|
|
MEMORY_dPutByte(addr, (UBYTE) i);
|
|
addr++;
|
|
MEMORY_dPutByte(addr, (UBYTE) value);
|
|
addr++;
|
|
}
|
|
}
|
|
else if (*tp == '1') {
|
|
c[3] = '\0';
|
|
if (isa && (strcmp(c, "ASL") == 0 || strcmp(c, "LSR") == 0 ||
|
|
strcmp(c, "ROL") == 0 || strcmp(c, "ROR") == 0)) {
|
|
printf("\"%s A\" is ambiguous.\n"
|
|
"Use \"%s\" for accumulator mode or \"%s 0A\" for zeropage mode.\n", c, c, c);
|
|
}
|
|
else {
|
|
MEMORY_dPutByte(addr, (UBYTE) i);
|
|
addr++;
|
|
MEMORY_dPutByte(addr, (UBYTE) value);
|
|
addr++;
|
|
}
|
|
}
|
|
else { /* *tp == '2' */
|
|
MEMORY_dPutByte(addr, (UBYTE) i);
|
|
addr++;
|
|
MEMORY_dPutWord(addr, value);
|
|
addr += 2;
|
|
}
|
|
goto next_instr;
|
|
}
|
|
}
|
|
/* not found */
|
|
if (tp == NULL || *tp == '2')
|
|
break;
|
|
if (++*tp == '1' && value > 0xff)
|
|
*tp = '2';
|
|
}
|
|
invalid_instr:
|
|
printf("Invalid instruction!\n");
|
|
next_instr:
|
|
;
|
|
}
|
|
}
|
|
#endif /* MONITOR_ASSEMBLER */
|
|
|
|
#ifdef MONITOR_BREAK
|
|
UWORD MONITOR_break_addr = 0xd000;
|
|
UBYTE MONITOR_break_step = FALSE;
|
|
static UBYTE break_over = FALSE;
|
|
UBYTE MONITOR_break_ret = FALSE;
|
|
UBYTE MONITOR_break_brk = FALSE;
|
|
int MONITOR_ret_nesting = 0;
|
|
#endif
|
|
|
|
#ifdef MONITOR_BREAKPOINTS
|
|
|
|
MONITOR_breakpoint_cond MONITOR_breakpoint_table[MONITOR_BREAKPOINT_TABLE_MAX];
|
|
int MONITOR_breakpoint_table_size = 0;
|
|
int MONITOR_breakpoints_enabled = TRUE;
|
|
|
|
static void breakpoint_print_flag(int flagmask)
|
|
{
|
|
switch (flagmask) {
|
|
case CPU_N_FLAG:
|
|
putchar('N');
|
|
break;
|
|
case CPU_V_FLAG:
|
|
putchar('V');
|
|
break;
|
|
case CPU_D_FLAG:
|
|
putchar('D');
|
|
break;
|
|
case CPU_I_FLAG:
|
|
putchar('I');
|
|
break;
|
|
case CPU_Z_FLAG:
|
|
putchar('Z');
|
|
break;
|
|
case CPU_C_FLAG:
|
|
putchar('C');
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int breakpoint_scan_flag(char c)
|
|
{
|
|
switch (c) {
|
|
case 'N':
|
|
return CPU_N_FLAG;
|
|
case 'V':
|
|
return CPU_V_FLAG;
|
|
case 'D':
|
|
return CPU_D_FLAG;
|
|
case 'I':
|
|
return CPU_I_FLAG;
|
|
case 'Z':
|
|
return CPU_Z_FLAG;
|
|
case 'C':
|
|
return CPU_C_FLAG;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static void breakpoints_set(int enabled)
|
|
{
|
|
int i;
|
|
if (get_dec(&i)) {
|
|
do {
|
|
if (/*i >= 0 &&*/ i < MONITOR_breakpoint_table_size)
|
|
MONITOR_breakpoint_table[i].enabled = (UBYTE) enabled;
|
|
} while (get_dec(&i));
|
|
}
|
|
else
|
|
MONITOR_breakpoints_enabled = enabled;
|
|
}
|
|
|
|
static void monitor_breakpoints(void)
|
|
{
|
|
char *t = get_token();
|
|
if (t == NULL) {
|
|
int i;
|
|
if (MONITOR_breakpoint_table_size == 0) {
|
|
printf("No breakpoints defined\n");
|
|
return;
|
|
}
|
|
printf("Breakpoints are %sabled\n", MONITOR_breakpoints_enabled ? "en" : "dis");
|
|
for (i = 0; i < MONITOR_breakpoint_table_size; i++) {
|
|
printf("%2d: ", i);
|
|
if (!MONITOR_breakpoint_table[i].enabled)
|
|
printf("OFF ");
|
|
switch (MONITOR_breakpoint_table[i].condition) {
|
|
case MONITOR_BREAKPOINT_OR:
|
|
printf("OR");
|
|
break;
|
|
case MONITOR_BREAKPOINT_FLAG_CLEAR:
|
|
printf("CLR");
|
|
breakpoint_print_flag(MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
case MONITOR_BREAKPOINT_FLAG_SET:
|
|
printf("SET");
|
|
breakpoint_print_flag(MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
default:
|
|
{
|
|
const char *op;
|
|
switch (MONITOR_breakpoint_table[i].condition & 7) {
|
|
case MONITOR_BREAKPOINT_LESS:
|
|
op = "<";
|
|
break;
|
|
case MONITOR_BREAKPOINT_EQUAL:
|
|
op = "=";
|
|
break;
|
|
case MONITOR_BREAKPOINT_LESS | MONITOR_BREAKPOINT_EQUAL:
|
|
op = "<=";
|
|
break;
|
|
case MONITOR_BREAKPOINT_GREATER:
|
|
op = ">";
|
|
break;
|
|
case MONITOR_BREAKPOINT_GREATER | MONITOR_BREAKPOINT_EQUAL:
|
|
op = ">=";
|
|
break;
|
|
case MONITOR_BREAKPOINT_LESS | MONITOR_BREAKPOINT_GREATER:
|
|
op = "!=";
|
|
break;
|
|
default:
|
|
op = "?";
|
|
break;
|
|
}
|
|
switch (MONITOR_breakpoint_table[i].condition >> 3) {
|
|
case MONITOR_BREAKPOINT_PC >> 3:
|
|
printf("PC%s%04X", op, MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
case MONITOR_BREAKPOINT_A >> 3:
|
|
printf("A%s%02X", op, MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
case MONITOR_BREAKPOINT_X >> 3:
|
|
printf("X%s%02X", op, MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
case MONITOR_BREAKPOINT_Y >> 3:
|
|
printf("A%s%02X", op, MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
case MONITOR_BREAKPOINT_S >> 3:
|
|
printf("S%s%02X", op, MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
case MONITOR_BREAKPOINT_READ >> 3:
|
|
printf("READ%s%04X", op, MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
case MONITOR_BREAKPOINT_WRITE >> 3:
|
|
printf("WRITE%s%04X", op, MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
case MONITOR_BREAKPOINT_ACCESS >> 3:
|
|
printf("ACCESS%s%04X", op, MONITOR_breakpoint_table[i].value);
|
|
break;
|
|
default:
|
|
printf("???");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
putchar('\n');
|
|
}
|
|
return;
|
|
}
|
|
if (strcmp(t, "?") == 0) {
|
|
printf(
|
|
"B - print breakpoint table\n"
|
|
"B ? - this help\n"
|
|
"B C - clear breakpoint table\n"
|
|
"B D pos - delete one entry\n"
|
|
"B ON - enable breakpoints\n"
|
|
"B OFF - disable breakpoints\n"
|
|
"B ON pos1... - enable specified breakpoints\n"
|
|
"B OFF pos1... - disable specified breakpoints\n"
|
|
"B [pos] cond1... - insert breakpoints (at the specified position)\n"
|
|
" cond is: TYPE OPERATOR VALUE (without spaces)\n"
|
|
" or: SETFLAG, CLRFLAG where FLAG is: N, V, D, I, Z, C\n");
|
|
printf(
|
|
" TYPE is: PC, A, X, Y, S, READ, WRITE, ACCESS (read or write)\n"
|
|
"OPERATOR is: <, <=, =, ==, >, >=, !=, <>\n"
|
|
" VALUE is a hex number\n"
|
|
"Breakpoint conditions are connected by AND operator\n"
|
|
"unless you explicitly use OR.\n"
|
|
"Examples:\n"
|
|
"B PC>=203f A<3a OR PC=3a7f X<>0 - creates 5 new entries\n"
|
|
"B 2 Y<5 - adds a new entry at position 2\n"
|
|
"B D 1 - deletes the entry at position 1\n"
|
|
"B OR SETD - appends 2 new entries\n");
|
|
return;
|
|
}
|
|
Util_strupper(t);
|
|
if (strcmp(t, "C") == 0) {
|
|
MONITOR_breakpoint_table_size = 0;
|
|
printf("Breakpoint table cleared\n");
|
|
}
|
|
else if (strcmp(t, "D") == 0) {
|
|
int i;
|
|
if (get_dec(&i) && /*i >= 0 &&*/ i < MONITOR_breakpoint_table_size) {
|
|
MONITOR_breakpoint_table_size--;
|
|
while (i < MONITOR_breakpoint_table_size) {
|
|
MONITOR_breakpoint_table[i] = MONITOR_breakpoint_table[i + 1];
|
|
i++;
|
|
}
|
|
printf("Entry deleted\n");
|
|
}
|
|
else
|
|
printf("Missing or bad argument\n");
|
|
}
|
|
else if (strcmp(t, "ON") == 0) {
|
|
breakpoints_set(TRUE);
|
|
}
|
|
else if (strcmp(t, "OFF") == 0) {
|
|
breakpoints_set(FALSE);
|
|
}
|
|
else {
|
|
int i;
|
|
if (t[0] >= '0' && t[0] <= '9') {
|
|
i = Util_sscandec(t);
|
|
if (i < 0 || i > MONITOR_breakpoint_table_size) {
|
|
printf("Bad argument\n");
|
|
return;
|
|
}
|
|
t = get_token();
|
|
if (t == NULL) {
|
|
printf("Missing arguments\n");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
i = MONITOR_breakpoint_table_size;
|
|
while (MONITOR_breakpoint_table_size < MONITOR_BREAKPOINT_TABLE_MAX) {
|
|
UBYTE condition;
|
|
int value;
|
|
int j;
|
|
if (strcmp(t, "OR") == 0) {
|
|
condition = MONITOR_BREAKPOINT_OR;
|
|
value = 0;
|
|
}
|
|
else if (strncmp(t, "CLR", 3) == 0) {
|
|
condition = MONITOR_BREAKPOINT_FLAG_CLEAR;
|
|
value = breakpoint_scan_flag(t[3]);
|
|
}
|
|
else if (strncmp(t, "SET", 3) == 0) {
|
|
condition = MONITOR_BREAKPOINT_FLAG_SET;
|
|
value = breakpoint_scan_flag(t[3]);
|
|
}
|
|
else {
|
|
condition = 0;
|
|
switch (t[0]) {
|
|
case 'A':
|
|
if (strncmp(t, "ACCESS", 6) == 0) {
|
|
condition = MONITOR_BREAKPOINT_ACCESS;
|
|
t += 6;
|
|
}
|
|
else {
|
|
condition = MONITOR_BREAKPOINT_A;
|
|
t++;
|
|
}
|
|
break;
|
|
case 'X':
|
|
condition = MONITOR_BREAKPOINT_X;
|
|
t++;
|
|
break;
|
|
case 'Y':
|
|
condition = MONITOR_BREAKPOINT_Y;
|
|
t++;
|
|
break;
|
|
case 'P':
|
|
if (t[1] == 'C') {
|
|
condition = MONITOR_BREAKPOINT_PC;
|
|
t += 2;
|
|
}
|
|
break;
|
|
case 'R':
|
|
if (strncmp(t, "READ", 4) == 0) {
|
|
condition = MONITOR_BREAKPOINT_READ;
|
|
t += 4;
|
|
}
|
|
break;
|
|
case 'S':
|
|
condition = MONITOR_BREAKPOINT_S;
|
|
t++;
|
|
break;
|
|
case 'W':
|
|
if (strncmp(t, "WRITE", 5) == 0) {
|
|
condition = MONITOR_BREAKPOINT_WRITE;
|
|
t += 5;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (t[0] == '!' && t[1] == '=') {
|
|
condition += MONITOR_BREAKPOINT_LESS | MONITOR_BREAKPOINT_GREATER;
|
|
t += 2;
|
|
}
|
|
else {
|
|
if (*t == '<') {
|
|
condition += MONITOR_BREAKPOINT_LESS;
|
|
t++;
|
|
}
|
|
if (*t == '>') {
|
|
condition += MONITOR_BREAKPOINT_GREATER;
|
|
t++;
|
|
}
|
|
if (*t == '=') {
|
|
condition += MONITOR_BREAKPOINT_EQUAL;
|
|
t++;
|
|
if (*t == '=')
|
|
t++;
|
|
}
|
|
}
|
|
if ((condition >> 3) == 0 || (condition & 7) == 0) {
|
|
printf("Bad argument\n");
|
|
return;
|
|
}
|
|
{
|
|
UWORD tmp;
|
|
if (parse_hex(t, &tmp))
|
|
value = tmp;
|
|
else
|
|
value = -1;
|
|
}
|
|
}
|
|
if (value < 0 || value > 0xffff) {
|
|
printf("Bad argument\n");
|
|
return;
|
|
}
|
|
for (j = MONITOR_breakpoint_table_size; j > i; j--)
|
|
MONITOR_breakpoint_table[j] = MONITOR_breakpoint_table[j - 1];
|
|
MONITOR_breakpoint_table[i].enabled = TRUE;
|
|
MONITOR_breakpoint_table[i].condition = condition;
|
|
MONITOR_breakpoint_table[i].value = (UWORD) value;
|
|
i++;
|
|
MONITOR_breakpoint_table_size++;
|
|
t = get_token();
|
|
if (t == NULL) {
|
|
printf("Breakpoint(s) added\n");
|
|
return;
|
|
}
|
|
Util_strupper(t);
|
|
}
|
|
printf("Breakpoint table full\n");
|
|
}
|
|
}
|
|
|
|
#endif /* MONITOR_BREAKPOINTS */
|
|
|
|
int MONITOR_Run(void)
|
|
{
|
|
UWORD addr;
|
|
|
|
#ifdef __PLUS
|
|
if (!Misc_AllocMonitorConsole(&mon_output, &mon_input))
|
|
return TRUE;
|
|
#endif
|
|
|
|
addr = CPU_regPC;
|
|
|
|
CPU_GetStatus();
|
|
|
|
if (CPU_cim_encountered) {
|
|
printf("(CIM encountered)\n");
|
|
CPU_cim_encountered = FALSE;
|
|
}
|
|
|
|
#ifdef MONITOR_BREAK
|
|
if (break_over) {
|
|
/* "O" command was active */
|
|
MONITOR_break_addr = 0xd000;
|
|
break_over = FALSE;
|
|
}
|
|
else if (CPU_regPC == MONITOR_break_addr)
|
|
printf("(breakpoint at %04X)\n", (unsigned int) MONITOR_break_addr);
|
|
else if (ANTIC_ypos == ANTIC_break_ypos)
|
|
printf("(breakpoint at scanline %d)\n", ANTIC_break_ypos);
|
|
else if (MONITOR_break_ret && MONITOR_ret_nesting <= 0)
|
|
printf("(returned)\n");
|
|
MONITOR_break_step = FALSE;
|
|
MONITOR_break_ret = FALSE;
|
|
#endif /* MONITOR_BREAK */
|
|
|
|
show_state();
|
|
|
|
for (;;) {
|
|
char s[128];
|
|
static char old_s[128] = "";
|
|
char *t;
|
|
|
|
printf("> ");
|
|
safe_gets(s, sizeof(s));
|
|
if (s[0] != '\0')
|
|
strcpy(old_s, s);
|
|
else {
|
|
/* if no command is given, restart the last one, but remove all
|
|
* arguments, so after a 'm 600' we will see 'm 700' ... */
|
|
int i;
|
|
strcpy(s, old_s);
|
|
for (i = 0; i < (int) sizeof(s); i++)
|
|
if (s[i] == ' ') {
|
|
s[i] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
#ifdef HAVE_SYSTEM
|
|
if (s[0] == '!') {
|
|
system(s + 1);
|
|
continue;
|
|
}
|
|
#endif
|
|
token_ptr = s;
|
|
t = get_token();
|
|
if (t == NULL)
|
|
continue;
|
|
|
|
/* uppercase the command */
|
|
Util_strupper(t);
|
|
|
|
if (strcmp(t, "CONT") == 0) {
|
|
#ifdef MONITOR_PROFILE
|
|
memset(CPU_instruction_count, 0, sizeof(CPU_instruction_count));
|
|
#endif
|
|
PLUS_EXIT_MONITOR;
|
|
return TRUE;
|
|
}
|
|
#ifdef MONITOR_BREAK
|
|
else if (strcmp(t, "BBRK") == 0) {
|
|
t = get_token();
|
|
if (t == NULL)
|
|
printf("Break on BRK is %sabled\n", MONITOR_break_brk ? "en" : "dis");
|
|
else if (Util_stricmp(t, "ON") == 0)
|
|
MONITOR_break_brk = TRUE;
|
|
else if (Util_stricmp(t, "OFF") == 0)
|
|
MONITOR_break_brk = FALSE;
|
|
else
|
|
printf("Invalid argument. Usage: BBRK ON or OFF\n");
|
|
}
|
|
else if (strcmp(t, "BPC") == 0) {
|
|
get_hex(&MONITOR_break_addr);
|
|
if (MONITOR_break_addr >= 0xd000 && MONITOR_break_addr <= 0xd7ff)
|
|
printf("PC breakpoint disabled\n");
|
|
else
|
|
printf("Breakpoint at PC=%04X\n", MONITOR_break_addr);
|
|
}
|
|
else if (strcmp(t, "HISTORY") == 0 || strcmp(t, "H") == 0) {
|
|
int i;
|
|
for (i = 0; i < CPU_REMEMBER_PC_STEPS; i++) {
|
|
int j;
|
|
j = CPU_remember_xpos[(CPU_remember_PC_curpos + i) % CPU_REMEMBER_PC_STEPS];
|
|
printf("%3d %3d ", j >> 8, j & 0xff);
|
|
show_instruction(stdout, CPU_remember_PC[(CPU_remember_PC_curpos + i) % CPU_REMEMBER_PC_STEPS]);
|
|
}
|
|
}
|
|
else if (strcmp(t, "JUMPS") == 0) {
|
|
int i;
|
|
for (i = 0; i < CPU_REMEMBER_JMP_STEPS; i++)
|
|
show_instruction(stdout, CPU_remember_JMP[(CPU_remember_jmp_curpos + i) % CPU_REMEMBER_JMP_STEPS]);
|
|
}
|
|
#endif
|
|
#if defined(MONITOR_BREAK) || !defined(NO_YPOS_BREAK_FLICKER)
|
|
else if (strcmp(t, "BLINE") == 0) {
|
|
get_dec(&ANTIC_break_ypos);
|
|
if (ANTIC_break_ypos >= 1008 && ANTIC_break_ypos <= 1247)
|
|
printf("Blinking scanline %d\n", ANTIC_break_ypos - 1000);
|
|
#ifdef MONITOR_BREAK
|
|
else if (ANTIC_break_ypos >= 0 && ANTIC_break_ypos <= 311)
|
|
printf("Breakpoint set at scanline %d\n", ANTIC_break_ypos);
|
|
#endif
|
|
else
|
|
printf("BLINE disabled\n");
|
|
}
|
|
#endif
|
|
else if (strcmp(t, "DLIST") == 0) {
|
|
#if 0
|
|
/* one instruction per line */
|
|
UWORD tdlist = dlist;
|
|
int nlines = 0;
|
|
get_hex(&tdlist);
|
|
for (;;) {
|
|
UBYTE IR;
|
|
|
|
printf("%04X: ", tdlist);
|
|
IR = ANTIC_GetDLByte(&tdlist);
|
|
|
|
if (IR & 0x80)
|
|
printf("DLI ");
|
|
|
|
if ((IR & 0x0f) == 0)
|
|
printf("%c BLANK\n", ((IR >> 4) & 0x07) + '1');
|
|
else if ((IR & 0x0f) == 1) {
|
|
tdlist = ANTIC_GetDLWord(&tdlist);
|
|
if (IR & 0x40) {
|
|
printf("JVB %04X\n", tdlist);
|
|
break;
|
|
}
|
|
printf("JMP %04X\n", tdlist);
|
|
}
|
|
else {
|
|
if (IR & 0x40)
|
|
printf("LMS %04X ", ANTIC_GetDLWord(&tdlist));
|
|
if (IR & 0x20)
|
|
printf("VSCROL ");
|
|
if (IR & 0x10)
|
|
printf("HSCROL ");
|
|
printf("MODE %X\n", IR & 0x0f);
|
|
}
|
|
|
|
if (++nlines == 24) {
|
|
if (pager())
|
|
break;
|
|
nlines = 0;
|
|
}
|
|
}
|
|
#else
|
|
/* group identical instructions */
|
|
UWORD tdlist = ANTIC_dlist;
|
|
UWORD new_tdlist;
|
|
UBYTE IR;
|
|
int scrnaddr = -1;
|
|
int nlines = 0;
|
|
get_hex(&tdlist);
|
|
new_tdlist = tdlist;
|
|
IR = ANTIC_GetDLByte(&new_tdlist);
|
|
for (;;) {
|
|
printf("%04X: ", tdlist);
|
|
if ((IR & 0x0f) == 0) {
|
|
UBYTE new_IR;
|
|
tdlist = new_tdlist;
|
|
new_IR = ANTIC_GetDLByte(&new_tdlist);
|
|
if (new_IR == IR) {
|
|
int count = 1;
|
|
do {
|
|
count++;
|
|
tdlist = new_tdlist;
|
|
new_IR = ANTIC_GetDLByte(&new_tdlist);
|
|
} while (new_IR == IR && count < 240);
|
|
printf("%dx ", count);
|
|
}
|
|
if (IR & 0x80)
|
|
printf("DLI ");
|
|
printf("%c BLANK\n", ((IR >> 4) & 0x07) + '1');
|
|
IR = new_IR;
|
|
}
|
|
else if ((IR & 0x0f) == 1) {
|
|
tdlist = ANTIC_GetDLWord(&new_tdlist);
|
|
if (IR & 0x80)
|
|
printf("DLI ");
|
|
if (IR & 0x40) {
|
|
printf("JVB %04X\n", tdlist);
|
|
break;
|
|
}
|
|
printf("JMP %04X\n", tdlist);
|
|
new_tdlist = tdlist;
|
|
IR = ANTIC_GetDLByte(&new_tdlist);
|
|
}
|
|
else {
|
|
UBYTE new_IR;
|
|
int new_scrnaddr;
|
|
int count;
|
|
if ((IR & 0x40) && scrnaddr < 0)
|
|
scrnaddr = ANTIC_GetDLWord(&new_tdlist);
|
|
for (count = 1; ; count++) {
|
|
tdlist = new_tdlist;
|
|
new_IR = ANTIC_GetDLByte(&new_tdlist);
|
|
if (new_IR != IR || count >= 240) {
|
|
new_scrnaddr = -1;
|
|
break;
|
|
}
|
|
if (IR & 0x40) {
|
|
new_scrnaddr = ANTIC_GetDLWord(&new_tdlist);
|
|
if (new_scrnaddr != scrnaddr)
|
|
break;
|
|
}
|
|
}
|
|
if (count > 1)
|
|
printf("%dx ", count);
|
|
if (IR & 0x80)
|
|
printf("DLI ");
|
|
if (IR & 0x40)
|
|
printf("LMS %04X ", scrnaddr);
|
|
if (IR & 0x20)
|
|
printf("VSCROL ");
|
|
if (IR & 0x10)
|
|
printf("HSCROL ");
|
|
printf("MODE %X\n", IR & 0x0f);
|
|
scrnaddr = new_scrnaddr;
|
|
IR = new_IR;
|
|
}
|
|
|
|
if (++nlines == 24) {
|
|
if (pager())
|
|
break;
|
|
nlines = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else if (strcmp(t, "SETPC") == 0)
|
|
get_uword(&CPU_regPC);
|
|
else if (strcmp(t, "SETS") == 0)
|
|
get_ubyte(&CPU_regS);
|
|
else if (strcmp(t, "SETA") == 0)
|
|
get_ubyte(&CPU_regA);
|
|
else if (strcmp(t, "SETX") == 0)
|
|
get_ubyte(&CPU_regX);
|
|
else if (strcmp(t, "SETY") == 0)
|
|
get_ubyte(&CPU_regY);
|
|
else if (strcmp(t, "SETN") == 0) {
|
|
int val = get_bool();
|
|
if (val == 0)
|
|
CPU_ClrN;
|
|
else if (val == 1)
|
|
CPU_SetN;
|
|
}
|
|
else if (strcmp(t, "SETV") == 0) {
|
|
int val = get_bool();
|
|
if (val == 0)
|
|
CPU_ClrV;
|
|
else if (val == 1)
|
|
CPU_SetV;
|
|
}
|
|
else if (strcmp(t, "SETD") == 0) {
|
|
int val = get_bool();
|
|
if (val == 0)
|
|
CPU_ClrD;
|
|
else if (val == 1)
|
|
CPU_SetD;
|
|
}
|
|
else if (strcmp(t, "SETI") == 0) {
|
|
int val = get_bool();
|
|
if (val == 0)
|
|
CPU_ClrI;
|
|
else if (val == 1)
|
|
CPU_SetI;
|
|
}
|
|
else if (strcmp(t, "SETZ") == 0) {
|
|
int val = get_bool();
|
|
if (val == 0)
|
|
CPU_ClrZ;
|
|
else if (val == 1)
|
|
CPU_SetZ;
|
|
}
|
|
else if (strcmp(t, "SETC") == 0) {
|
|
int val = get_bool();
|
|
if (val == 0)
|
|
CPU_ClrC;
|
|
else if (val == 1)
|
|
CPU_SetC;
|
|
}
|
|
#ifdef MONITOR_TRACE
|
|
else if (strcmp(t, "TRACE") == 0) {
|
|
const char *filename = get_token();
|
|
if (MONITOR_trace_file != NULL) {
|
|
fclose(MONITOR_trace_file);
|
|
printf("Trace file closed\n");
|
|
MONITOR_trace_file = NULL;
|
|
}
|
|
if (filename != NULL) {
|
|
MONITOR_trace_file = fopen(filename, "w");
|
|
if (MONITOR_trace_file != NULL)
|
|
printf("Trace file open\n");
|
|
else
|
|
perror(filename);
|
|
}
|
|
}
|
|
#endif /* MONITOR_TRACE */
|
|
#ifdef MONITOR_PROFILE
|
|
else if (strcmp(t, "PROFILE") == 0) {
|
|
int i;
|
|
for (i = 0; i < 24; i++) {
|
|
int max, instr;
|
|
int j;
|
|
max = CPU_instruction_count[0];
|
|
instr = 0;
|
|
for (j = 1; j < 256; j++) {
|
|
if (CPU_instruction_count[j] > max) {
|
|
max = CPU_instruction_count[j];
|
|
instr = j;
|
|
}
|
|
}
|
|
if (max <= 0)
|
|
break;
|
|
CPU_instruction_count[instr] = 0;
|
|
printf("Opcode %02X: %-9s has been executed %d times\n",
|
|
instr, instr6502[instr], max);
|
|
}
|
|
}
|
|
#endif /* MONITOR_PROFILE */
|
|
else if (strcmp(t, "SHOW") == 0)
|
|
show_state();
|
|
else if (strcmp(t, "STACK") == 0) {
|
|
int ts;
|
|
for (ts = 0x101 + CPU_regS; ts < 0x200; ) {
|
|
if (ts < 0x1ff) {
|
|
UWORD ta = (UWORD) (MEMORY_dGetWord(ts) - 2);
|
|
if (MEMORY_dGetByte(ta) == 0x20) {
|
|
printf("%04X: %02X %02X %04X: JSR %04X\n",
|
|
ts, MEMORY_dGetByte(ts), MEMORY_dGetByte(ts + 1), ta,
|
|
MEMORY_dGetWord(ta + 1));
|
|
ts += 2;
|
|
continue;
|
|
}
|
|
}
|
|
printf("%04X: %02X\n", ts, MEMORY_dGetByte(ts));
|
|
ts++;
|
|
}
|
|
}
|
|
else if (strcmp(t, "ROM") == 0) {
|
|
UWORD addr1;
|
|
UWORD addr2;
|
|
if (get_attrib_range(&addr1, &addr2)) {
|
|
MEMORY_SetROM(addr1, addr2);
|
|
printf("Changed memory from %04X to %04X into ROM\n",
|
|
addr1, addr2);
|
|
}
|
|
}
|
|
else if (strcmp(t, "RAM") == 0) {
|
|
UWORD addr1;
|
|
UWORD addr2;
|
|
if (get_attrib_range(&addr1, &addr2)) {
|
|
MEMORY_SetRAM(addr1, addr2);
|
|
printf("Changed memory from %04X to %04X into RAM\n",
|
|
addr1, addr2);
|
|
}
|
|
}
|
|
#ifndef PAGED_ATTRIB
|
|
else if (strcmp(t, "HARDWARE") == 0) {
|
|
UWORD addr1;
|
|
UWORD addr2;
|
|
if (get_attrib_range(&addr1, &addr2)) {
|
|
MEMORY_SetHARDWARE(addr1, addr2);
|
|
printf("Changed memory from %04X to %04X into HARDWARE\n",
|
|
addr1, addr2);
|
|
}
|
|
}
|
|
#endif
|
|
else if (strcmp(t, "COLDSTART") == 0) {
|
|
Atari800_Coldstart();
|
|
PLUS_EXIT_MONITOR;
|
|
return TRUE; /* perform reboot immediately */
|
|
}
|
|
else if (strcmp(t, "WARMSTART") == 0) {
|
|
Atari800_Warmstart();
|
|
PLUS_EXIT_MONITOR;
|
|
return TRUE; /* perform reboot immediately */
|
|
}
|
|
#ifndef PAGED_MEM
|
|
else if (strcmp(t, "READ") == 0) {
|
|
const char *filename;
|
|
filename = get_token();
|
|
if (filename != NULL) {
|
|
UWORD nbytes;
|
|
if (get_hex2(&addr, &nbytes) && addr + nbytes <= 0x10000) {
|
|
FILE *f = fopen(filename, "rb");
|
|
if (f == NULL)
|
|
perror(filename);
|
|
else {
|
|
if (fread(&MEMORY_mem[addr], 1, nbytes, f) == 0)
|
|
perror(filename);
|
|
fclose(f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (strcmp(t, "WRITE") == 0) {
|
|
UWORD addr1;
|
|
UWORD addr2;
|
|
if (get_hex2(&addr1, &addr2) && addr1 <= addr2) {
|
|
const char *filename;
|
|
FILE *f;
|
|
filename = get_token();
|
|
if (filename == NULL)
|
|
filename = "memdump.dat";
|
|
f = fopen(filename, "wb");
|
|
if (f == NULL)
|
|
perror(filename);
|
|
else {
|
|
size_t nbytes = addr2 - addr1 + 1;
|
|
if (fwrite(&MEMORY_mem[addr1], 1, addr2 - addr1 + 1, f) < nbytes)
|
|
perror(filename);
|
|
fclose(f);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
else if (strcmp(t, "SUM") == 0) {
|
|
UWORD addr1;
|
|
UWORD addr2;
|
|
if (get_hex2(&addr1, &addr2)) {
|
|
int sum = 0;
|
|
int i;
|
|
for (i = addr1; i <= addr2; i++)
|
|
sum += MEMORY_dGetByte(i);
|
|
printf("SUM: %X\n", sum);
|
|
}
|
|
}
|
|
else if (strcmp(t, "M") == 0) {
|
|
int count = 16;
|
|
get_hex(&addr);
|
|
do {
|
|
int i;
|
|
printf("%04X: ", addr);
|
|
for (i = 0; i < 16; i++)
|
|
printf("%02X ", MEMORY_GetByte((UWORD) (addr + i)));
|
|
putchar(' ');
|
|
for (i = 0; i < 16; i++) {
|
|
UBYTE c;
|
|
c = MEMORY_GetByte(addr);
|
|
addr++;
|
|
putchar((c >= ' ' && c <= 'z' && c != '\x60') ? c : '.');
|
|
}
|
|
putchar('\n');
|
|
} while (--count > 0);
|
|
}
|
|
#ifndef PAGED_MEM
|
|
else if (strcmp(t, "F") == 0) {
|
|
UWORD addr1;
|
|
UWORD addr2;
|
|
UWORD hexval;
|
|
if (get_hex3(&addr1, &addr2, &hexval)) {
|
|
/* use int to avoid endless loop with addr2==0xffff */
|
|
int a;
|
|
for (a = addr1; a <= addr2; a++)
|
|
MEMORY_dPutByte(a, (UBYTE) hexval);
|
|
}
|
|
}
|
|
#endif
|
|
else if (strcmp(t, "S") == 0) {
|
|
/* static, so "S" without arguments repeats last search */
|
|
static int n = 0;
|
|
static UWORD addr1;
|
|
static UWORD addr2;
|
|
static UBYTE tab[64];
|
|
UWORD hexval;
|
|
if (get_hex3(&addr1, &addr2, &hexval)) {
|
|
n = 0;
|
|
do {
|
|
tab[n++] = (UBYTE) hexval;
|
|
if (hexval > 0xff && n < 64)
|
|
tab[n++] = (UBYTE) (hexval >> 8);
|
|
} while (n < 64 && get_hex(&hexval));
|
|
}
|
|
if (n > 0) {
|
|
int a;
|
|
for (a = addr1; a <= addr2; a++) {
|
|
int i = 0;
|
|
while (MEMORY_GetByte((UWORD) (a + i)) == tab[i]) {
|
|
i++;
|
|
if (i >= n) {
|
|
printf("Found at %04X\n", a);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifndef PAGED_MEM
|
|
else if (strcmp(t, "C") == 0) {
|
|
UWORD temp = 0;
|
|
get_hex(&addr);
|
|
while (get_hex(&temp)) {
|
|
#ifdef PAGED_ATTRIB
|
|
if (MEMORY_writemap[addr >> 8] != NULL && MEMORY_writemap[addr >> 8] != MEMORY_ROM_PutByte)
|
|
(*MEMORY_writemap[addr >> 8])(addr, (UBYTE) temp);
|
|
#else
|
|
if (MEMORY_attrib[addr] == MEMORY_HARDWARE)
|
|
MEMORY_HwPutByte(addr, (UBYTE) temp);
|
|
#endif
|
|
else /* RAM, ROM */
|
|
MEMORY_dPutByte(addr, (UBYTE) temp);
|
|
addr++;
|
|
if (temp > 0xff) {
|
|
#ifdef PAGED_ATTRIB
|
|
if (MEMORY_writemap[addr >> 8] != NULL && MEMORY_writemap[addr >> 8] != MEMORY_ROM_PutByte)
|
|
(*MEMORY_writemap[addr >> 8])(addr, (UBYTE) (temp >> 8));
|
|
#else
|
|
if (MEMORY_attrib[addr] == MEMORY_HARDWARE)
|
|
MEMORY_HwPutByte(addr, (UBYTE) (temp >> 8));
|
|
#endif
|
|
else /* RAM, ROM */
|
|
MEMORY_dPutByte(addr, (UBYTE) (temp >> 8));
|
|
addr++;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef MONITOR_BREAK
|
|
else if (strcmp(t, "G") == 0) {
|
|
MONITOR_break_step = TRUE;
|
|
PLUS_EXIT_MONITOR;
|
|
return TRUE;
|
|
}
|
|
else if (strcmp(t, "R") == 0 ) {
|
|
MONITOR_break_ret = TRUE;
|
|
MONITOR_ret_nesting = 1;
|
|
PLUS_EXIT_MONITOR;
|
|
return TRUE;
|
|
}
|
|
else if (strcmp(t, "O") == 0) {
|
|
UBYTE opcode = MEMORY_dGetByte(CPU_regPC);
|
|
if ((opcode & 0x1f) == 0x10 || opcode == 0x20) {
|
|
/* branch or JSR: set breakpoint after it */
|
|
MONITOR_break_addr = CPU_regPC + (MONITOR_optype6502[MEMORY_dGetByte(CPU_regPC)] & 0x3);
|
|
break_over = TRUE;
|
|
}
|
|
else
|
|
MONITOR_break_step = TRUE;
|
|
PLUS_EXIT_MONITOR;
|
|
return TRUE;
|
|
}
|
|
#endif /* MONITOR_BREAK */
|
|
#ifdef MONITOR_BREAKPOINTS
|
|
else if (strcmp(t, "B") == 0)
|
|
monitor_breakpoints();
|
|
#endif
|
|
else if (strcmp(t, "D") == 0) {
|
|
get_hex(&addr);
|
|
addr = disassemble(addr);
|
|
}
|
|
else if (strcmp(t, "LOOP") == 0) {
|
|
int caddr;
|
|
get_hex(&addr);
|
|
caddr = addr;
|
|
for (;;) {
|
|
UBYTE opcode;
|
|
if (caddr > (UWORD) (addr + 0x7e)) {
|
|
printf("Conditional loop containing instruction at %04X not detected\n", addr);
|
|
break;
|
|
}
|
|
opcode = MEMORY_dGetByte(caddr);
|
|
if ((opcode & 0x1f) == 0x10) {
|
|
/* branch */
|
|
UWORD target = caddr + 2 + (SBYTE) MEMORY_dGetByte(caddr + 1);
|
|
if (target <= addr) {
|
|
addr = disassemble(target);
|
|
break;
|
|
}
|
|
}
|
|
caddr += MONITOR_optype6502[opcode] & 3;
|
|
}
|
|
}
|
|
#ifdef MONITOR_HINTS
|
|
else if (strcmp(t, "LABELS") == 0) {
|
|
char *cmd = get_token();
|
|
if (cmd == NULL) {
|
|
printf("Built-in labels are %sabled.\n", symtable_builtin_enable ? "en" : "dis");
|
|
if (symtable_user_size > 0)
|
|
printf("Using %d user-defined label%s.\n",
|
|
symtable_user_size, (symtable_user_size > 1) ? "s" : "");
|
|
else
|
|
printf("There are no user-defined labels.\n");
|
|
printf(
|
|
"Labels are displayed in disassembly listings.\n"
|
|
"You may also use them as command arguments"
|
|
#ifdef MONITOR_ASSEMBLER
|
|
" and in the built-in assembler"
|
|
#endif
|
|
".\n"
|
|
"Usage:\n"
|
|
"LABELS OFF - no labels\n"
|
|
"LABELS BUILTIN - use only built-in labels\n"
|
|
"LABELS LOAD filename - use only labels loaded from file\n"
|
|
"LABELS ADD filename - use built-in and loaded labels\n"
|
|
"LABELS SET name value - define a label\n"
|
|
"LABELS LIST - list user-defined labels\n"
|
|
);
|
|
}
|
|
else {
|
|
Util_strupper(cmd);
|
|
if (strcmp(cmd, "OFF") == 0) {
|
|
symtable_builtin_enable = FALSE;
|
|
free_user_labels();
|
|
}
|
|
else if (strcmp(cmd, "BUILTIN") == 0) {
|
|
symtable_builtin_enable = TRUE;
|
|
free_user_labels();
|
|
}
|
|
else if (strcmp(cmd, "LOAD") == 0) {
|
|
symtable_builtin_enable = FALSE;
|
|
load_user_labels(get_token());
|
|
}
|
|
else if (strcmp(cmd, "ADD") == 0) {
|
|
symtable_builtin_enable = TRUE;
|
|
load_user_labels(get_token());
|
|
}
|
|
else if (strcmp(cmd, "SET") == 0) {
|
|
const char *name = get_token();
|
|
if (name != NULL && get_hex(&addr)) {
|
|
symtable_rec *p = find_user_label(name);
|
|
if (p != NULL) {
|
|
if (p->addr != addr) {
|
|
printf("%s redefined (previous value: %04X)\n", name, p->addr);
|
|
p->addr = addr;
|
|
}
|
|
}
|
|
else
|
|
add_user_label(name, addr);
|
|
}
|
|
else
|
|
printf("Missing or bad arguments\n");
|
|
}
|
|
else if (strcmp(cmd, "LIST") == 0) {
|
|
int i;
|
|
int nlines = 0;
|
|
for (i = 0; i < symtable_user_size; i++) {
|
|
if (++nlines == 24) {
|
|
if (pager())
|
|
break;
|
|
nlines = 0;
|
|
}
|
|
printf("%04X %s\n", symtable_user[i].addr, symtable_user[i].name);
|
|
}
|
|
}
|
|
else
|
|
printf("Invalid command, type \"LABELS\" for help\n");
|
|
}
|
|
}
|
|
#endif
|
|
else if (strcmp(t, "ANTIC") == 0) {
|
|
printf("DMACTL=%02X CHACTL=%02X DLISTL=%02X "
|
|
"DLISTH=%02X HSCROL=%02X VSCROL=%02X\n",
|
|
ANTIC_DMACTL, ANTIC_CHACTL, ANTIC_dlist & 0xff, ANTIC_dlist >> 8, ANTIC_HSCROL, ANTIC_VSCROL);
|
|
printf("PMBASE=%02X CHBASE=%02X VCOUNT=%02X "
|
|
"NMIEN= %02X ypos=%4d\n",
|
|
ANTIC_PMBASE, ANTIC_CHBASE, ANTIC_GetByte(ANTIC_OFFSET_VCOUNT), ANTIC_NMIEN, ANTIC_ypos);
|
|
}
|
|
else if (strcmp(t, "PIA") == 0) {
|
|
printf("PACTL= %02X PBCTL= %02X PORTA= %02X "
|
|
"PORTB= %02X\n", PIA_PACTL, PIA_PBCTL, PIA_PORTA, PIA_PORTB);
|
|
}
|
|
else if (strcmp(t, "GTIA") == 0) {
|
|
printf("HPOSP0=%02X HPOSP1=%02X HPOSP2=%02X HPOSP3=%02X\n",
|
|
GTIA_HPOSP0, GTIA_HPOSP1, GTIA_HPOSP2, GTIA_HPOSP3);
|
|
printf("HPOSM0=%02X HPOSM1=%02X HPOSM2=%02X HPOSM3=%02X\n",
|
|
GTIA_HPOSM0, GTIA_HPOSM1, GTIA_HPOSM2, GTIA_HPOSM3);
|
|
printf("SIZEP0=%02X SIZEP1=%02X SIZEP2=%02X SIZEP3=%02X SIZEM= %02X\n",
|
|
GTIA_SIZEP0, GTIA_SIZEP1, GTIA_SIZEP2, GTIA_SIZEP3, GTIA_SIZEM);
|
|
printf("GRAFP0=%02X GRAFP1=%02X GRAFP2=%02X GRAFP3=%02X GRAFM= %02X\n",
|
|
GTIA_GRAFP0, GTIA_GRAFP1, GTIA_GRAFP2, GTIA_GRAFP3, GTIA_GRAFM);
|
|
printf("COLPM0=%02X COLPM1=%02X COLPM2=%02X COLPM3=%02X\n",
|
|
GTIA_COLPM0, GTIA_COLPM1, GTIA_COLPM2, GTIA_COLPM3);
|
|
printf("COLPF0=%02X COLPF1=%02X COLPF2=%02X COLPF3=%02X COLBK= %02X\n",
|
|
GTIA_COLPF0, GTIA_COLPF1, GTIA_COLPF2, GTIA_COLPF3, GTIA_COLBK);
|
|
printf("PRIOR= %02X VDELAY=%02X GRACTL=%02X\n",
|
|
GTIA_PRIOR, GTIA_VDELAY, GTIA_GRACTL);
|
|
}
|
|
else if (strcmp(t, "POKEY") == 0) {
|
|
printf("AUDF1= %02X AUDF2= %02X AUDF3= %02X AUDF4= %02X AUDCTL=%02X KBCODE=%02X\n",
|
|
POKEY_AUDF[POKEY_CHAN1], POKEY_AUDF[POKEY_CHAN2], POKEY_AUDF[POKEY_CHAN3], POKEY_AUDF[POKEY_CHAN4], POKEY_AUDCTL[0], POKEY_KBCODE);
|
|
printf("AUDC1= %02X AUDC2= %02X AUDC3= %02X AUDC4= %02X IRQEN= %02X IRQST= %02X\n",
|
|
POKEY_AUDC[POKEY_CHAN1], POKEY_AUDC[POKEY_CHAN2], POKEY_AUDC[POKEY_CHAN3], POKEY_AUDC[POKEY_CHAN4], POKEY_IRQEN, POKEY_IRQST);
|
|
printf("SKSTAT=%02X SKCTL= %02X\n", POKEY_SKSTAT, POKEY_SKCTL);
|
|
#ifdef STEREO_SOUND
|
|
if (POKEYSND_stereo_enabled) {
|
|
printf("Second chip:\n");
|
|
printf("AUDF1= %02X AUDF2= %02X AUDF3= %02X AUDF4= %02X AUDCTL=%02X\n",
|
|
POKEY_AUDF[POKEY_CHAN1 + POKEY_CHIP2], POKEY_AUDF[POKEY_CHAN2 + POKEY_CHIP2], POKEY_AUDF[POKEY_CHAN3 + POKEY_CHIP2], POKEY_AUDF[POKEY_CHAN4 + POKEY_CHIP2], POKEY_AUDCTL[1]);
|
|
printf("AUDC1= %02X AUDC2= %02X AUDC3= %02X AUDC4= %02X\n",
|
|
POKEY_AUDC[POKEY_CHAN1 + POKEY_CHIP2], POKEY_AUDC[POKEY_CHAN2 + POKEY_CHIP2], POKEY_AUDC[POKEY_CHAN3 + POKEY_CHIP2], POKEY_AUDC[POKEY_CHAN4 + POKEY_CHIP2]);
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef MONITOR_ASSEMBLER
|
|
else if (strcmp(t, "A") == 0) {
|
|
get_hex(&addr);
|
|
addr = assembler(addr);
|
|
}
|
|
#endif
|
|
else if (strcmp(t, "HELP") == 0 || strcmp(t, "?") == 0) {
|
|
printf(
|
|
"CONT - Continue emulation\n"
|
|
"SHOW - Show registers\n"
|
|
"STACK - Show stack\n"
|
|
"SET{PC,A,X,Y,S} hexval - Set register value\n"
|
|
"SET{N,V,D,I,Z,C} 0 or 1 - Set flag value\n"
|
|
"C startaddr hexval... - Change memory\n"
|
|
"D [startaddr] - Disassemble memory\n"
|
|
"F startaddr endaddr hexval - Fill memory\n"
|
|
"M [startaddr] - Memory list\n"
|
|
"S startaddr endaddr hexval... - Search memory\n");
|
|
/* split into several printfs to avoid gcc -pedantic warning: "string length 'xxx'
|
|
is greater than the length '509' ISO C89 compilers are required to support" */
|
|
printf(
|
|
"LOOP [inneraddr] - Disassemble a loop that contains inneraddr\n"
|
|
"RAM startaddr endaddr - Convert memory block into RAM\n"
|
|
"ROM startaddr endaddr - Convert memory block into ROM\n"
|
|
"HARDWARE startaddr endaddr - Convert memory block into HARDWARE\n"
|
|
"READ filename startaddr nbytes - Read file into memory\n"
|
|
"WRITE startaddr endaddr [file] - Write memory block to a file (memdump.dat)\n"
|
|
"SUM startaddr endaddr - Print sum of specified memory range\n");
|
|
#ifdef MONITOR_TRACE
|
|
printf(
|
|
"TRACE [filename] - Output 6502 trace on/off\n");
|
|
#endif
|
|
#ifdef MONITOR_BREAK
|
|
printf(
|
|
"BPC [addr] - Set breakpoint at address\n"
|
|
"BLINE [ypos] or [1000+ypos] - Break at scanline or blink scanline\n"
|
|
"BBRK ON or OFF - Breakpoint on BRK on/off\n"
|
|
"HISTORY or H - List last %d executed instructions\n", CPU_REMEMBER_PC_STEPS);
|
|
printf(
|
|
"JUMPS - List last %d executed JMP/JSR\n", CPU_REMEMBER_JMP_STEPS);
|
|
printf("Press return to continue: ");
|
|
{
|
|
char buf[100];
|
|
safe_gets(buf, sizeof(buf));
|
|
}
|
|
printf(
|
|
"G - Execute one instruction\n"
|
|
"O - Step over the instruction\n"
|
|
"R - Execute until return\n");
|
|
#elif !defined(NO_YPOS_BREAK_FLICKER)
|
|
printf(
|
|
"BLINE [1000+ypos] - Blink scanline (8<=ypos<=247)\n");
|
|
#endif
|
|
printf(
|
|
#ifdef MONITOR_BREAKPOINTS
|
|
"B [argument...] - Manage breakpoints (\"B ?\" for help)\n"
|
|
#endif
|
|
#ifdef MONITOR_ASSEMBLER
|
|
"A [startaddr] - Start simple assembler\n"
|
|
#endif
|
|
"ANTIC, GTIA, PIA, POKEY - Display hardware registers\n"
|
|
"DLIST [startaddr] - Show Display List\n");
|
|
printf(
|
|
#ifdef MONITOR_PROFILE
|
|
"PROFILE - Display profiling statistics\n"
|
|
#endif
|
|
#ifdef MONITOR_HINTS
|
|
"LABELS [command] [filename] - Configure labels\n"
|
|
#endif
|
|
"COLDSTART, WARMSTART - Perform system coldstart/warmstart\n"
|
|
#ifdef HAVE_SYSTEM
|
|
"!command - Execute shell command\n"
|
|
#endif
|
|
"QUIT or EXIT - Quit emulator\n"
|
|
"HELP or ? - This text\n");
|
|
}
|
|
else if (strcmp(t, "QUIT") == 0 || strcmp(t, "EXIT") == 0) {
|
|
PLUS_EXIT_MONITOR;
|
|
return FALSE;
|
|
}
|
|
else
|
|
printf("Invalid command!\n");
|
|
}
|
|
}
|