Annotation of hatari/src/debugui.c, revision 1.1.1.11

1.1       root        1: /*
1.1.1.6   root        2:   Hatari - debugui.c
1.1       root        3: 
1.1.1.4   root        4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
1.1.1.6   root        7:   debugui.c - this is the code for the mini-debugger. When the pause button is
                      8:   pressed, the emulator is (hopefully) halted and this little CLI can be used
                      9:   (in the terminal box) for debugging tasks like memory and register dumps.
1.1       root       10: */
1.1.1.10  root       11: const char DebugUI_fileid[] = "Hatari debugui.c : " __DATE__ " " __TIME__;
1.1       root       12: 
                     13: #include <ctype.h>
1.1.1.8   root       14: #include <stdio.h>
                     15: 
                     16: #include "config.h"
                     17: 
                     18: #if HAVE_LIBREADLINE
                     19: #include <readline/readline.h>
                     20: #include <readline/history.h>
                     21: #endif
1.1       root       22: 
                     23: #include "main.h"
1.1.1.9   root       24: #include "change.h"
1.1       root       25: #include "configuration.h"
1.1.1.11! root       26: #include "memorySnapShot.h"
1.1.1.9   root       27: #include "file.h"
1.1       root       28: #include "reset.h"
                     29: #include "m68000.h"
1.1.1.9   root       30: #include "str.h"
1.1.1.3   root       31: #include "stMemory.h"
1.1       root       32: #include "sound.h"
                     33: #include "tos.h"
1.1.1.11! root       34: #include "options.h"
1.1.1.4   root       35: #include "debugui.h"
1.1.1.11! root       36: #include "breakcond.h"
1.1.1.8   root       37: #include "hatari-glue.h"
1.1.1.11! root       38: #include "screen.h"
        !            39: #include "statusbar.h"
        !            40: #include "video.h"
        !            41: 
        !            42: int bExceptionDebugging;
1.1       root       43: 
                     44: #define MEMDUMP_COLS   16      /* memdump, number of bytes per row */
                     45: #define MEMDUMP_ROWS   4       /* memdump, number of rows */
1.1.1.2   root       46: #define NON_PRINT_CHAR '.'     /* character to display for non-printables */
1.1       root       47: #define DISASM_INSTS   5       /* disasm - number of instructions */
                     48: 
1.1.1.11! root       49: static Uint32 disasm_addr;        /* disasm address */
        !            50: static Uint32 memdump_addr;       /* memdump address */
        !            51: 
        !            52: static Uint16 dsp_disasm_addr;    /* DSP disasm address */
        !            53: static Uint16 dsp_memdump_addr;   /* DSP memdump address */
        !            54: static char dsp_mem_space = 'P';  /* X, Y, P */
1.1.1.6   root       55: 
1.1.1.9   root       56: static FILE *debugOutput;
1.1.1.2   root       57: 
1.1.1.11! root       58: static Uint32 CpuBreakPoint[16];  /* 68k breakpoints */
        !            59: static int nCpuActiveBPs = 0;     /* Amount of active breakpoints */
        !            60: static int nCpuActiveCBs = 0;     /* Amount of active conditional breakpoints */
        !            61: static int nCpuSteps = 0;         /* Amount of steps for CPU single-stepping */
        !            62: 
        !            63: static Uint16 DspBreakPoint[16];  /* DSP breakpoints */
        !            64: static int nDspActiveBPs = 0;     /* Amount of active breakpoints */
        !            65: static int nDspActiveCBs = 0;     /* Amount of active conditional breakpoints */
        !            66: static int nDspSteps = 0;         /* Amount of steps for DSP single-stepping */
1.1.1.2   root       67: 
1.1.1.11! root       68: static int DebugUI_Help(int nArgc, char *psArgv[]);
        !            69: static void DebugUI_PrintCmdHelp(const char *psCmd);
1.1.1.6   root       70: 
                     71: 
1.1.1.8   root       72: /**
1.1.1.11! root       73:  * Save/Restore snapshot of debugging session variables
1.1.1.8   root       74:  */
1.1.1.11! root       75: void DebugUI_MemorySnapShot_Capture(bool bSave)
1.1.1.6   root       76: {
1.1.1.11! root       77:        MemorySnapShot_Store(&disasm_addr, sizeof(disasm_addr));
        !            78:        MemorySnapShot_Store(&memdump_addr, sizeof(memdump_addr));
        !            79:        MemorySnapShot_Store(&dsp_disasm_addr, sizeof(dsp_disasm_addr));
        !            80:        MemorySnapShot_Store(&dsp_memdump_addr, sizeof(dsp_memdump_addr));
        !            81:        MemorySnapShot_Store(&dsp_mem_space, sizeof(dsp_mem_space));
        !            82:        
        !            83:        MemorySnapShot_Store(&CpuBreakPoint, sizeof(CpuBreakPoint));
        !            84:        MemorySnapShot_Store(&nCpuActiveBPs, sizeof(nCpuActiveBPs));
        !            85:        MemorySnapShot_Store(&nCpuActiveCBs, sizeof(nCpuActiveCBs));
        !            86:        MemorySnapShot_Store(&DspBreakPoint, sizeof(DspBreakPoint));
        !            87:        MemorySnapShot_Store(&nDspActiveBPs, sizeof(nDspActiveBPs));
        !            88:        MemorySnapShot_Store(&nDspActiveCBs, sizeof(nDspActiveCBs));
        !            89:        
        !            90:        BreakCond_MemorySnapShot_Capture(bSave);
1.1.1.9   root       91: }
                     92: 
                     93: 
                     94: /**
                     95:  * Close a log file if open, and set it to default stream.
                     96:  */
                     97: static void DebugUI_SetLogDefault(void)
                     98: {
                     99:        if (debugOutput != stderr)
                    100:        {
                    101:                if (debugOutput)
                    102:                {
                    103:                        File_Close(debugOutput);
                    104:                        fprintf(stderr, "Debug log closed.\n");
                    105:                }
                    106:                debugOutput = stderr;
                    107:        }
1.1.1.2   root      108: }
                    109: 
1.1.1.6   root      110: 
1.1.1.11! root      111: /**
        !           112:  * Open (or close) given log file.
        !           113:  */
        !           114: static int DebugUI_SetLogFile(int nArgc, char *psArgs[])
        !           115: {
        !           116:        File_Close(debugOutput);
        !           117:        debugOutput = NULL;
        !           118: 
        !           119:        if (nArgc > 1)
        !           120:                debugOutput = File_Open(psArgs[1], "w");
        !           121: 
        !           122:        if (debugOutput)
        !           123:                fprintf(stderr, "Debug log '%s' opened.\n", psArgs[1]);
        !           124:        else
        !           125:                debugOutput = stderr;
        !           126: 
        !           127:        return DEBUGGER_CMDDONE;
        !           128: }
        !           129: 
        !           130: 
1.1.1.8   root      131: /**
                    132:  * Load a binary file to a memory address.
                    133:  */
1.1.1.11! root      134: static int DebugUI_LoadBin(int nArgc, char *psArgs[])
1.1.1.6   root      135: {
                    136:        FILE *fp;
                    137:        unsigned char c;
1.1.1.11! root      138:        Uint32 address;
1.1.1.6   root      139:        int i=0;
                    140: 
1.1.1.11! root      141:        if (nArgc < 3)
        !           142:        {
        !           143:                DebugUI_PrintCmdHelp(psArgs[0]);
        !           144:                return DEBUGGER_CMDDONE;
        !           145:        }
        !           146: 
        !           147:        if (!Str_GetNumber(psArgs[2], &address))
1.1.1.6   root      148:        {
1.1.1.11! root      149:                fprintf(stderr, "Invalid address!\n");
        !           150:                return DEBUGGER_CMDDONE;
1.1.1.6   root      151:        }
                    152:        address &= 0x00FFFFFF;
1.1.1.11! root      153: 
        !           154:        if ((fp = fopen(psArgs[1], "rb")) == NULL)
1.1.1.6   root      155:        {
1.1.1.11! root      156:                fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]);
        !           157:                return DEBUGGER_CMDDONE;
1.1.1.6   root      158:        }
                    159: 
                    160:        c = fgetc(fp);
                    161:        while (!feof(fp))
                    162:        {
                    163:                i++;
                    164:                STMemory_WriteByte(address++, c);
                    165:                c = fgetc(fp);
                    166:        }
                    167:        fprintf(stderr,"  Read 0x%x bytes.\n", i);
                    168:        fclose(fp);
1.1.1.11! root      169: 
        !           170:        return DEBUGGER_CMDDONE;
1.1       root      171: }
                    172: 
1.1.1.6   root      173: 
1.1.1.8   root      174: /**
                    175:  * Dump memory from an address to a binary file.
                    176:  */
1.1.1.11! root      177: static int DebugUI_SaveBin(int nArgc, char *psArgs[])
1.1.1.6   root      178: {
                    179:        FILE *fp;
                    180:        unsigned char c;
1.1.1.11! root      181:        Uint32 address;
        !           182:        Uint32 bytes, i = 0;
1.1.1.6   root      183: 
1.1.1.11! root      184:        if (nArgc < 4)
1.1.1.6   root      185:        {
1.1.1.11! root      186:                DebugUI_PrintCmdHelp(psArgs[0]);
        !           187:                return DEBUGGER_CMDDONE;
        !           188:        }
        !           189: 
        !           190:        if (!Str_GetNumber(psArgs[2], &address))
        !           191:        {
        !           192:                fprintf(stderr, "  Invalid address!\n");
        !           193:                return DEBUGGER_CMDDONE;
1.1.1.6   root      194:        }
                    195:        address &= 0x00FFFFFF;
1.1.1.11! root      196: 
        !           197:        if (!Str_GetNumber(psArgs[3], &bytes))
1.1.1.6   root      198:        {
1.1.1.11! root      199:                fprintf(stderr, "  Invalid length!\n");
        !           200:                return DEBUGGER_CMDDONE;
        !           201:        }
        !           202: 
        !           203:        if ((fp = fopen(psArgs[1], "wb")) == NULL)
        !           204:        {
        !           205:                fprintf(stderr,"  Cannot open file '%s'!\n", psArgs[1]);
        !           206:                return DEBUGGER_CMDDONE;
1.1.1.6   root      207:        }
                    208: 
                    209:        while (i < bytes)
                    210:        {
                    211:                c = STMemory_ReadByte(address++);
                    212:                fputc(c, fp);
                    213:                i++;
                    214:        }
                    215:        fclose(fp);
1.1.1.11! root      216:        fprintf(stderr, "  Wrote 0x%x bytes.\n", bytes);
        !           217: 
        !           218:        return DEBUGGER_CMDDONE;
1.1       root      219: }
                    220: 
1.1.1.6   root      221: 
1.1.1.11! root      222: #if ENABLE_DSP_EMU
        !           223: 
        !           224: #include "dsp.h"
        !           225: 
1.1.1.8   root      226: /**
1.1.1.11! root      227:  * Command: Dump or set a DSP register
1.1.1.8   root      228:  */
1.1.1.11! root      229: static int DebugUI_DspRegister(int nArgc, char *psArgs[])
1.1       root      230: {
1.1.1.11! root      231:        int i;
        !           232:        char reg[4], *assign;
        !           233:        Uint32 value;
        !           234:        char *arg;
        !           235: 
        !           236:        if (!bDspEnabled)
        !           237:        {
        !           238:                printf("DSP isn't present or initialized.\n");
        !           239:                return DEBUGGER_CMDDONE;
        !           240:        }
        !           241: 
        !           242:        if (nArgc == 1)
        !           243:        {
        !           244:                /* No parameter - dump all registers */
        !           245:                DSP_DisasmRegisters();
        !           246:                return DEBUGGER_CMDDONE;
        !           247:        }
        !           248: 
        !           249:        arg = psArgs[1];
        !           250:        assign = strchr(arg, '=');
        !           251:        /* has '=' and reg name is max. 3 letters that fit to string */
        !           252:        if (!assign || assign - arg > 3+1)
        !           253:                goto error_msg;
        !           254: 
        !           255:        *assign++ = '\0';
        !           256:        if (!Str_GetNumber(assign, &value))
        !           257:                goto error_msg;
        !           258: 
        !           259:        for (i = 0; i < 3 && arg[i]; i++)
        !           260:                reg[i] = toupper(arg[i]);
        !           261: 
        !           262:        DSP_Disasm_SetRegister(reg, value);
        !           263:        return DEBUGGER_CMDDONE;
        !           264: 
        !           265:        error_msg:
        !           266:        fprintf(stderr,"\tError, usage: dr or dr xx=yyyy\n"
        !           267:                "\tWhere: xx=A0-A2, B0-B2, X0, X1, Y0, Y1, R0-R7,\n"
        !           268:                "\t       N0-N7, M0-M7, LA, LC, PC, SR, SP, OMR, SSH, SSL\n"
        !           269:                "\tand yyyy is a hex value.\n");
        !           270: 
        !           271:        return DEBUGGER_CMDDONE;
1.1       root      272: }
                    273: 
                    274: 
1.1.1.8   root      275: /**
1.1.1.11! root      276:  * DSP dissassemble - arg = starting address/range, or PC.
1.1.1.8   root      277:  */
1.1.1.11! root      278: static int DebugUI_DspDisAsm(int nArgc, char *psArgs[])
1.1.1.6   root      279: {
1.1.1.11! root      280:        Uint32 lower, upper;
        !           281:        Uint16 dsp_disasm_upper = 0;
1.1.1.6   root      282: 
1.1.1.11! root      283:        if (!bDspEnabled)
1.1.1.6   root      284:        {
1.1.1.11! root      285:                printf("DSP isn't present or initialized.\n");
        !           286:                return DEBUGGER_CMDDONE;
        !           287:        }
1.1.1.6   root      288: 
1.1.1.11! root      289:        if (nArgc > 1)
        !           290:        {
        !           291:                switch (Str_ParseRange(psArgs[1], &lower, &upper))
        !           292:                {
        !           293:                        case -1:
        !           294:                                /* invalid value(s) */
        !           295:                                return DEBUGGER_CMDDONE;
        !           296:                        case 0:
        !           297:                                /* single value */
        !           298:                                break;
        !           299:                        case 1:
        !           300:                                /* range */
        !           301:                                if (upper > 0xFFFF)
        !           302:                                {
        !           303:                                        fprintf(stderr,"Invalid address '%x'!\n", upper);
        !           304:                                        return DEBUGGER_CMDDONE;
        !           305:                                }
        !           306:                                dsp_disasm_upper = upper;
        !           307:                                break;
        !           308:                }
        !           309: 
        !           310:                if (lower > 0xFFFF)
        !           311:                {
        !           312:                        fprintf(stderr,"Invalid address '%x'!\n", lower);
        !           313:                        return DEBUGGER_CMDDONE;
        !           314:                }
        !           315:                dsp_disasm_addr = lower;
        !           316:        }
        !           317:        else
        !           318:        {
        !           319:                /* continue */
        !           320:                if(!dsp_disasm_addr)
        !           321:                {
        !           322:                        dsp_disasm_addr = DSP_GetPC();
        !           323:                }
        !           324:        }
        !           325:        if (!dsp_disasm_upper)
        !           326:        {
        !           327:                if ( dsp_disasm_addr < (0xFFFF - 8))
        !           328:                        dsp_disasm_upper = dsp_disasm_addr + 8;
        !           329:                else
        !           330:                        dsp_disasm_upper = 0xFFFF;
        !           331:        }
        !           332:        printf("DSP disasm %hx-%hx:\n", dsp_disasm_addr, dsp_disasm_upper);
        !           333:        dsp_disasm_addr = DSP_DisasmAddress(dsp_disasm_addr, dsp_disasm_upper);
1.1.1.6   root      334: 
1.1.1.11! root      335:        return DEBUGGER_CMDCONT;
        !           336: }
        !           337: 
        !           338: 
        !           339: /**
        !           340:  * Do a DSP memory dump, args = starting address or range.
        !           341:  * <x|y|p> <address>: dump from X, Y or P, starting from given address,
        !           342:  * e.g. "x 200" or "p 200-300"
        !           343:  */
        !           344: static int DebugUI_DspMemDump(int nArgc, char *psArgs[])
        !           345: {
        !           346:        Uint32 lower, upper;
        !           347:        Uint16 dsp_memdump_upper = 0;
        !           348:        char space;
        !           349: 
        !           350:        if (!bDspEnabled)
        !           351:        {
        !           352:                printf("DSP isn't present or initialized.\n");
        !           353:                return DEBUGGER_CMDDONE;
        !           354:        }
        !           355:        if (nArgc == 2)
        !           356:        {
        !           357:                fprintf(stderr,"Memory space or address/range missing\n");
        !           358:                return DEBUGGER_CMDDONE;
        !           359:        }
        !           360: 
        !           361:        if (nArgc == 3)
        !           362:        {
        !           363:                space = toupper(psArgs[1][0]);
        !           364:                switch (space)
        !           365:                {
        !           366:                case 'X':
        !           367:                case 'Y':
        !           368:                case 'P':
        !           369:                        break;
        !           370:                default:
        !           371:                        fprintf(stderr,"Invalid DSP address space '%c'!\n", space);
        !           372:                        return DEBUGGER_CMDDONE;
        !           373:                }
        !           374:                switch (Str_ParseRange(psArgs[2], &lower, &upper))
        !           375:                {
        !           376:                case -1:
        !           377:                        /* invalid value(s) */
        !           378:                        return DEBUGGER_CMDDONE;
        !           379:                case 0:
        !           380:                        /* single value */
        !           381:                        break;
        !           382:                case 1:
        !           383:                        /* range */
        !           384:                        if (upper > 0xFFFF)
1.1.1.6   root      385:                        {
1.1.1.11! root      386:                                fprintf(stderr,"Invalid address '%x'!\n", upper);
        !           387:                                return DEBUGGER_CMDDONE;
1.1.1.6   root      388:                        }
1.1.1.11! root      389:                        dsp_memdump_upper = upper;
        !           390:                        break;
        !           391:                }
        !           392:                if (lower > 0xFFFF)
1.1.1.6   root      393:                {
1.1.1.11! root      394:                        fprintf(stderr,"Invalid address '%x'!\n", lower);
        !           395:                        return DEBUGGER_CMDDONE;
1.1.1.6   root      396:                }
1.1.1.11! root      397:                dsp_memdump_addr = lower;
        !           398:                dsp_mem_space = space;
        !           399:        } /* continue */
        !           400: 
        !           401:        if (!dsp_memdump_upper)
        !           402:        {
        !           403:                if ( dsp_memdump_addr < (0xFFFF - 7))
        !           404:                        dsp_memdump_upper = dsp_memdump_addr + 7;
1.1.1.6   root      405:                else
1.1.1.11! root      406:                        dsp_memdump_upper = 0xFFFF;
        !           407:        }
        !           408: 
        !           409: 
        !           410:        printf("DSP memdump from %hx in '%c' address space\n", dsp_memdump_addr, dsp_mem_space);
        !           411:        DSP_DisasmMemory(dsp_memdump_addr, dsp_memdump_upper, dsp_mem_space);
        !           412:        dsp_memdump_addr = dsp_memdump_upper + 1;
        !           413: 
        !           414:        return DEBUGGER_CMDCONT;
        !           415: }
        !           416: 
        !           417: /**
        !           418:  * Toggle or list DSP breakpoints.
        !           419:  */
        !           420: static int DebugUI_DspBreakPoint(int nArgc, char *psArgs[])
        !           421: {
        !           422:        int i;
        !           423:        Uint16 addr;
        !           424:        Uint32 BreakAddr;
        !           425: 
        !           426:        /* List breakpoints? */
        !           427:        if (nArgc == 1)
        !           428:        {
        !           429:                /* No arguments - so list available breakpoints */
        !           430:                if (!nDspActiveBPs)
        !           431:                {
        !           432:                        fputs("No DSP breakpoints set.\n", stderr);
        !           433:                        return DEBUGGER_CMDDONE;
        !           434:                }
        !           435: 
        !           436:                fputs("Currently active DSP breakpoints:\n", stderr);
        !           437:                for (i = 0; i < nDspActiveBPs; i++)
        !           438:                {
        !           439:                        addr = DspBreakPoint[i];
        !           440:                        DSP_DisasmAddress(addr, addr);
        !           441:                }
        !           442: 
        !           443:                return DEBUGGER_CMDDONE;
        !           444:        }
        !           445: 
        !           446:        /* Parse parameter as breakpoint value */
        !           447:        if (!Str_GetNumber(psArgs[1], &BreakAddr) || BreakAddr > 0xFFFF)
        !           448:        {
        !           449:                fputs("Not a valid value for a DSP breakpoint!\n", stderr);
        !           450:                return DEBUGGER_CMDDONE;
        !           451:        }
        !           452: 
        !           453:        /* Is the breakpoint already in the list? Then disable it! */
        !           454:        for (i = 0; i < nDspActiveBPs; i++)
        !           455:        {
        !           456:                if (BreakAddr == DspBreakPoint[i])
        !           457:                {
        !           458:                        DspBreakPoint[i] = DspBreakPoint[nDspActiveBPs-1];
        !           459:                        nDspActiveBPs -= 1;
        !           460:                        fprintf(stderr, "DSP breakpoint at %x deleted.\n", BreakAddr);
        !           461:                        return DEBUGGER_CMDDONE;
        !           462:                }
        !           463:        }
        !           464: 
        !           465:        /* Is there at least one free slot available? */
        !           466:        if (nDspActiveBPs == ARRAYSIZE(DspBreakPoint))
        !           467:        {
        !           468:                fputs("No more available free DSP breakpoints!\n", stderr);
        !           469:                return DEBUGGER_CMDDONE;
        !           470:        }
        !           471: 
        !           472:        /* Add new breakpoint */
        !           473:        DspBreakPoint[nDspActiveBPs] = BreakAddr;
        !           474:        nDspActiveBPs += 1;
        !           475:        fprintf(stderr, "DSP breakpoint added at %x.\n", BreakAddr);
        !           476: 
        !           477:        return DEBUGGER_CMDDONE;
        !           478: }
        !           479: 
        !           480: /**
        !           481:  * DSP wrapper for BreakCond_Command/BreakPointCount, returns DEBUGGER_END
        !           482:  */
        !           483: static int DebugUI_BreakCondDsp(int nArgc, char *psArgs[])
        !           484: {
        !           485:        BreakCond_Command((const char *)psArgs[1], true);
        !           486:        nDspActiveCBs = BreakCond_BreakPointCount(true);
        !           487:        return DEBUGGER_CMDDONE;
        !           488: }
        !           489: 
        !           490: /**
        !           491:  * Check if we hit a DSP breakpoint
        !           492:  */
        !           493: static void DebugUI_CheckDspBreakpoints(void)
        !           494: {
        !           495:        Uint16 pc = DSP_GetPC();
        !           496:        int i;
        !           497: 
        !           498:        for (i = 0; i < nDspActiveBPs; i++)
        !           499:        {
        !           500:                if (pc == DspBreakPoint[i])
        !           501:                {
        !           502:                        fprintf(stderr, "\nDSP breakpoint at %x ...", pc);
        !           503:                        DebugUI();
        !           504:                        break;
        !           505:                }
        !           506:        }
        !           507: }
        !           508: 
        !           509: 
        !           510: /**
        !           511:  * This function is called after each DSP instruction when debugging is enabled.
        !           512:  */
        !           513: void DebugUI_DspCheck(void)
        !           514: {
        !           515:        if (nDspActiveBPs)
        !           516:        {
        !           517:                DebugUI_CheckDspBreakpoints();
        !           518:        }
        !           519:        if (nDspActiveCBs)
        !           520:        {
        !           521:                if (BreakCond_MatchDsp())
        !           522:                        DebugUI();
        !           523:        }
        !           524:        if (nDspSteps)
        !           525:        {
        !           526:                nDspSteps -= 1;
        !           527:                if (nDspSteps == 0)
        !           528:                        DebugUI();
        !           529:        }
        !           530: }
        !           531: 
        !           532: #endif /* ENABLE_DSP_EMU */
        !           533: 
        !           534: 
        !           535: 
        !           536: /**
        !           537:  * Dissassemble - arg = starting address, or PC.
        !           538:  */
        !           539: static int DebugUI_DisAsm(int nArgc, char *psArgs[])
        !           540: {
        !           541:        Uint32 disasm_upper = 0;
        !           542:        uaecptr nextpc;
        !           543: 
        !           544:        if (nArgc > 1)
        !           545:        {
        !           546:                switch (Str_ParseRange(psArgs[1], &disasm_addr, &disasm_upper))
        !           547:                {
        !           548:                case -1:
        !           549:                        /* invalid value(s) */
        !           550:                        return DEBUGGER_CMDDONE;
        !           551:                case 0:
        !           552:                        /* single value */
        !           553:                        break;
        !           554:                case 1:
        !           555:                        /* range */
1.1.1.6   root      556:                        disasm_upper &= 0x00FFFFFF;
1.1.1.11! root      557:                        break;
1.1.1.6   root      558:                }
                    559:        }
1.1.1.11! root      560:        else
        !           561:        {
        !           562:                /* continue */
1.1.1.6   root      563:                if(!disasm_addr)
1.1.1.8   root      564:                        disasm_addr = M68000_GetPC();
1.1.1.11! root      565:        }
1.1.1.6   root      566:        disasm_addr &= 0x00FFFFFF;
                    567: 
                    568:        /* output a single block. */
1.1.1.11! root      569:        if (!disasm_upper)
1.1.1.6   root      570:        {
1.1.1.9   root      571:                m68k_disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, DISASM_INSTS);
1.1.1.6   root      572:                disasm_addr = nextpc;
1.1.1.9   root      573:                fflush(debugOutput);
1.1.1.11! root      574:                return DEBUGGER_CMDCONT;
1.1.1.6   root      575:        }
                    576: 
                    577:        /* output a range */
                    578:        while (disasm_addr < disasm_upper)
                    579:        {
1.1.1.9   root      580:                m68k_disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1);
1.1.1.6   root      581:                disasm_addr = nextpc;
                    582:        }
1.1.1.9   root      583:        fflush(debugOutput);
1.1.1.11! root      584: 
        !           585:        return DEBUGGER_CMDCONT;
1.1.1.2   root      586: }
                    587: 
1.1.1.6   root      588: 
1.1.1.8   root      589: /**
1.1.1.11! root      590:  * Set address of the named register to given argument.
        !           591:  * Return register size in bits or zero for uknown register name.
        !           592:  * Handles D0-7 data and A0-7 address registers, but not PC & SR
        !           593:  * registers as they need to be accessed using UAE accessors.
1.1.1.8   root      594:  */
1.1.1.11! root      595: int DebugUI_GetCpuRegisterAddress(const char *reg, Uint32 **addr)
1.1.1.6   root      596: {
1.1.1.11! root      597:        char r0, r1;
        !           598:        if (!reg[0] || !reg[1] || reg[2])
        !           599:                return 0;
        !           600:        
        !           601:        r0 = toupper(reg[0]);
        !           602:        r1 = toupper(reg[1]);
        !           603: 
        !           604:        if (r0 == 'D')  /* Data regs? */
1.1.1.6   root      605:        {
1.1.1.11! root      606:                if (r1 >= '0' && r1 <= '7')
1.1.1.6   root      607:                {
1.1.1.11! root      608:                        *addr = &(Regs[REG_D0 + r1 - '0']);
        !           609:                        return 32;
1.1.1.6   root      610:                }
1.1.1.11! root      611:                fprintf(stderr,"\tBad data register, valid values are 0-7\n");
        !           612:                return 0;
        !           613:        }
        !           614:        if(r0 == 'A')  /* Address regs? */
        !           615:        {
        !           616:                if (r1 >= '0' && r1 <= '7')
        !           617:                {
        !           618:                        *addr = &(Regs[REG_A0 + r1 - '0']);
        !           619:                        return 32;
        !           620:                }
        !           621:                fprintf(stderr,"\tBad address register, valid values are 0-7\n");
        !           622:                return 0;
1.1.1.6   root      623:        }
1.1.1.11! root      624:        return 0;
        !           625: }
        !           626: 
        !           627: 
        !           628: /**
        !           629:  * Dump or set CPU registers
        !           630:  */
        !           631: static int DebugUI_CpuRegister(int nArgc, char *psArgs[])
        !           632: {
        !           633:        int i;
        !           634:        char reg[3], *assign;
        !           635:        Uint32 value;
        !           636:        char *arg;
        !           637: 
        !           638:        /* If no parameter has been given, simply dump all registers */
        !           639:        if (nArgc == 1)
        !           640:        {
        !           641:                uaecptr nextpc;
        !           642:                /* use the UAE function instead */
        !           643:                m68k_dumpstate(debugOutput, &nextpc);
        !           644:                fflush(debugOutput);
        !           645:                return DEBUGGER_CMDDONE;
        !           646:        }
        !           647: 
        !           648:        arg =  psArgs[1];
1.1.1.6   root      649: 
1.1.1.11! root      650:        assign = strchr(arg, '=');
        !           651:        /* has '=' and reg name is max. 2 letters that fit to string */
        !           652:        if (!assign || assign - arg > 2+1)
1.1.1.6   root      653:        {
                    654:                fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR and yyyy is a hex value.\n");
1.1.1.11! root      655:                return DEBUGGER_CMDDONE;
1.1.1.6   root      656:        }
                    657: 
1.1.1.11! root      658:        *assign++ = '\0';
        !           659:        if (!Str_GetNumber(assign, &value))
1.1.1.6   root      660:        {
                    661:                fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR and yyyy is a hex value.\n");
1.1.1.11! root      662:                return DEBUGGER_CMDDONE;
1.1.1.6   root      663:        }
1.1.1.11! root      664:        
        !           665:        for (i = 0; i < 2 && arg[i]; i++)
        !           666:        {
        !           667:                reg[i] = toupper(arg[i]);
        !           668:        }
        !           669:        
1.1.1.6   root      670:        /* set SR and update conditional flags for the UAE CPU core. */
                    671:        if (reg[0] == 'S' && reg[1] == 'R')
                    672:        {
1.1.1.8   root      673:                M68000_SetSR(value);
1.1.1.6   root      674:        }
                    675:        else if (reg[0] == 'P' && reg[1] == 'C')   /* set PC? */
                    676:        {
1.1.1.8   root      677:                M68000_SetPC(value);
1.1.1.6   root      678:        }
1.1.1.11! root      679:        else
1.1.1.6   root      680:        {
1.1.1.11! root      681:                Uint32 *regaddr;
        !           682:                /* check&set data and address registers */
        !           683:                if (DebugUI_GetCpuRegisterAddress(reg, &regaddr))
1.1.1.6   root      684:                {
1.1.1.11! root      685:                        *regaddr = value;
        !           686:                }
        !           687:                else
        !           688:                {
        !           689:                        fprintf(stderr, "\t Bad register!\n");
1.1.1.6   root      690:                }
                    691:        }
1.1.1.11! root      692:        return DEBUGGER_CMDDONE;
        !           693: }
        !           694: 
        !           695: 
        !           696: /**
        !           697:  * Toggle or list CPU breakpoints.
        !           698:  */
        !           699: static int DebugUI_CpuBreakPoint(int nArgc, char *psArgs[])
        !           700: {
        !           701:        int i;
        !           702:        uaecptr nextpc;
        !           703:        Uint32 BreakAddr;
        !           704: 
        !           705:        /* List breakpoints? */
        !           706:        if (nArgc == 1)
1.1.1.6   root      707:        {
1.1.1.11! root      708:                /* No arguments - so list available breakpoints */
        !           709:                if (!nCpuActiveBPs)
1.1.1.6   root      710:                {
1.1.1.11! root      711:                        fputs("No CPU breakpoints set.\n", stderr);
        !           712:                        return DEBUGGER_CMDDONE;
        !           713:                }
1.1.1.6   root      714: 
1.1.1.11! root      715:                fputs("Currently active CPU breakpoints:\n", stderr);
        !           716:                for (i = 0; i < nCpuActiveBPs; i++)
        !           717:                {
        !           718:                        m68k_disasm(stderr, (uaecptr)CpuBreakPoint[i], &nextpc, 1);
1.1.1.6   root      719:                }
1.1.1.11! root      720: 
        !           721:                return DEBUGGER_CMDDONE;
1.1.1.6   root      722:        }
1.1.1.11! root      723: 
        !           724:        /* Parse parameter as breakpoint value */
        !           725:        if (!Str_GetNumber(psArgs[1], &BreakAddr)
        !           726:            || (BreakAddr > STRamEnd && BreakAddr < 0xe00000)
        !           727:            || BreakAddr > 0xff0000)
1.1.1.6   root      728:        {
1.1.1.11! root      729:                fputs("Not a valid value for a CPU breakpoint!\n", stderr);
        !           730:                return DEBUGGER_CMDDONE;
1.1.1.6   root      731:        }
1.1.1.11! root      732: 
        !           733:        /* Is the breakpoint already in the list? Then disable it! */
        !           734:        for (i = 0; i < nCpuActiveBPs; i++)
        !           735:        {
        !           736:                if (BreakAddr == CpuBreakPoint[i])
        !           737:                {
        !           738:                        CpuBreakPoint[i] = CpuBreakPoint[nCpuActiveBPs-1];
        !           739:                        nCpuActiveBPs -= 1;
        !           740:                        fprintf(stderr, "CPU breakpoint at %x deleted.\n", BreakAddr);
        !           741:                        return DEBUGGER_CMDDONE;
        !           742:                }
        !           743:        }
        !           744: 
        !           745:        /* Is there at least one free slot available? */
        !           746:        if (nCpuActiveBPs == ARRAYSIZE(CpuBreakPoint))
        !           747:        {
        !           748:                fputs("No more available free CPU breakpoints!\n", stderr);
        !           749:                return DEBUGGER_CMDDONE;
        !           750:        }
        !           751: 
        !           752:        /* Add new breakpoint */
        !           753:        CpuBreakPoint[nCpuActiveBPs] = BreakAddr;
        !           754:        nCpuActiveBPs += 1;
        !           755:        fprintf(stderr, "CPU breakpoint added at %x.\n", BreakAddr);
        !           756: 
        !           757:        return DEBUGGER_CMDDONE;
1.1       root      758: }
                    759: 
1.1.1.11! root      760: /**
        !           761:  * CPU wrapper for BreakCond_Command/BreakPointCount, returns DEBUGGER_END
        !           762:  */
        !           763: static int DebugUI_BreakCondCpu(int nArgc, char *psArgs[])
        !           764: {
        !           765:        BreakCond_Command((const char*)psArgs[1], false);
        !           766:        nCpuActiveCBs = BreakCond_BreakPointCount(false);
        !           767:        return DEBUGGER_CMDDONE;
        !           768: }
1.1.1.6   root      769: 
1.1.1.8   root      770: /**
                    771:  * Do a memory dump, args = starting address.
                    772:  */
1.1.1.11! root      773: static int DebugUI_MemDump(int nArgc, char *psArgs[])
1.1.1.6   root      774: {
                    775:        int i,j;
                    776:        char c;
1.1.1.11! root      777:        Uint32 memdump_upper = 0;
1.1.1.2   root      778: 
1.1.1.11! root      779:        if (nArgc > 1)
1.1.1.6   root      780:        {
1.1.1.11! root      781:                switch (Str_ParseRange(psArgs[1], &memdump_addr, &memdump_upper))
1.1.1.6   root      782:                {
1.1.1.11! root      783:                case -1:
        !           784:                        /* invalid value(s) */
        !           785:                        return DEBUGGER_CMDDONE;
        !           786:                case 0:
        !           787:                        /* single value */
        !           788:                        break;
        !           789:                case 1:
        !           790:                        /* range */
1.1.1.6   root      791:                        memdump_upper &= 0x00FFFFFF;
1.1.1.11! root      792:                        break;
1.1.1.6   root      793:                }
                    794:        } /* continue */
                    795:        memdump_addr &= 0x00FFFFFF;
                    796: 
1.1.1.11! root      797:        if (!memdump_upper)
1.1.1.6   root      798:        {
                    799:                for (j=0;j<MEMDUMP_ROWS;j++)
                    800:                {
1.1.1.11! root      801:                        fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
1.1.1.6   root      802:                        for (i = 0; i < MEMDUMP_COLS; i++)               /* print hex data */
1.1.1.9   root      803:                                fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
                    804:                        fprintf(debugOutput, "  ");                     /* print ASCII data */
1.1.1.6   root      805:                        for (i = 0; i < MEMDUMP_COLS; i++)
                    806:                        {
                    807:                                c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
1.1.1.8   root      808:                                if (!isprint((unsigned)c))
1.1.1.6   root      809:                                        c = NON_PRINT_CHAR;         /* non-printable as dots */
1.1.1.9   root      810:                                fprintf(debugOutput,"%c", c);
1.1.1.6   root      811:                        }
1.1.1.9   root      812:                        fprintf(debugOutput, "\n");        /* newline */
1.1.1.6   root      813:                }
1.1.1.9   root      814:                fflush(debugOutput);
1.1.1.11! root      815:                return DEBUGGER_CMDCONT;
1.1.1.6   root      816:        } /* not a range */
                    817: 
                    818:        while (memdump_addr < memdump_upper)
                    819:        {
1.1.1.11! root      820:                fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
1.1.1.6   root      821:                for (i = 0; i < MEMDUMP_COLS; i++)               /* print hex data */
1.1.1.9   root      822:                        fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
                    823:                fprintf(debugOutput, "  ");                     /* print ASCII data */
1.1.1.6   root      824:                for (i = 0; i < MEMDUMP_COLS; i++)
                    825:                {
                    826:                        c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
1.1.1.8   root      827:                        if(!isprint((unsigned)c))
1.1.1.6   root      828:                                c = NON_PRINT_CHAR;             /* non-printable as dots */
1.1.1.9   root      829:                        fprintf(debugOutput,"%c", c);
1.1.1.6   root      830:                }
1.1.1.9   root      831:                fprintf(debugOutput, "\n");            /* newline */
1.1.1.6   root      832:        } /* while */
1.1.1.9   root      833:        fflush(debugOutput);
1.1.1.11! root      834: 
        !           835:        return DEBUGGER_CMDCONT;
        !           836: }
1.1       root      837: 
1.1.1.6   root      838: 
1.1.1.8   root      839: /**
1.1.1.11! root      840:  * Command: Write to memory, arg = starting address, followed by bytes.
1.1.1.8   root      841:  */
1.1.1.11! root      842: static int DebugUI_MemWrite(int nArgc, char *psArgs[])
1.1       root      843: {
1.1.1.11! root      844:        int i, numBytes;
        !           845:        Uint32 write_addr, d;
        !           846:        unsigned char bytes[256]; /* store bytes */
1.1.1.6   root      847: 
1.1.1.11! root      848:        if (nArgc < 3)
        !           849:        {
        !           850:                DebugUI_PrintCmdHelp(psArgs[0]);
        !           851:                return DEBUGGER_CMDDONE;
        !           852:        }
1.1.1.6   root      853: 
1.1.1.11! root      854:        /* Read address */
        !           855:        if (!Str_GetNumber(psArgs[1], &write_addr))
1.1.1.6   root      856:        {
                    857:                fprintf(stderr, "Bad address!\n");
1.1.1.11! root      858:                return DEBUGGER_CMDDONE;
1.1.1.6   root      859:        }
                    860: 
                    861:        write_addr &= 0x00FFFFFF;
1.1.1.11! root      862:        numBytes = 0;
1.1.1.6   root      863: 
                    864:        /* get bytes data */
1.1.1.11! root      865:        for (i = 2; i < nArgc; i++)
1.1.1.6   root      866:        {
1.1.1.11! root      867:                if (!Str_GetNumber(psArgs[i], &d) || d > 255)
1.1.1.6   root      868:                {
1.1.1.11! root      869:                        fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]);
        !           870:                        return DEBUGGER_CMDDONE;
1.1.1.6   root      871:                }
                    872: 
1.1.1.11! root      873:                bytes[numBytes] = d & 0x0FF;
1.1.1.6   root      874:                numBytes++;
                    875:        }
                    876: 
                    877:        /* write the data */
                    878:        for (i = 0; i < numBytes; i++)
                    879:                STMemory_WriteByte(write_addr + i, bytes[i]);
1.1       root      880: 
1.1.1.11! root      881:        return DEBUGGER_CMDDONE;
        !           882: }
1.1.1.6   root      883: 
1.1.1.8   root      884: /**
1.1.1.11! root      885:  * Command: Show given value in bin/dec/hex number bases or change number base
1.1.1.8   root      886:  */
1.1.1.11! root      887: static int DebugUI_ShowValue(int argc, char *argv[])
1.1       root      888: {
1.1.1.11! root      889:        static const struct {
        !           890:                const char name[4];
        !           891:                int base;
        !           892:        } bases[] = {
        !           893:                { "bin", 2 },
        !           894:                { "dec", 10 },
        !           895:                { "hex", 16 }
        !           896:        };
        !           897:        bool one, ones;
        !           898:        Uint32 value;
        !           899:        int bit, i;
        !           900:        
        !           901:        if (argc < 2)
        !           902:        {
        !           903:                DebugUI_PrintCmdHelp(argv[0]);
        !           904:                return DEBUGGER_CMDDONE;
        !           905:        }
        !           906:        
        !           907:        for (i = 0; i < ARRAYSIZE(bases); i++)
        !           908:        {
        !           909:                if (strcasecmp(bases[i].name, argv[1]) == 0)
        !           910:                {
        !           911:                        if (ConfigureParams.Log.nNumberBase != bases[i].base)
        !           912:                        {
        !           913:                                fprintf(stderr, "Switched default number base from %d to %d-based (%s) values\n",
        !           914:                                        ConfigureParams.Log.nNumberBase,
        !           915:                                        bases[i].base, bases[i].name);
        !           916:                                ConfigureParams.Log.nNumberBase = bases[i].base;
        !           917:                        } else {
        !           918:                                fprintf(stderr, "Already in '%s' mode\n", bases[i].name);
        !           919:                        }
        !           920:                        return DEBUGGER_CMDDONE;
        !           921:                }
        !           922:        }
        !           923:        
        !           924:        if (!Str_GetNumber(argv[1], &value))
        !           925:                return DEBUGGER_CMDDONE;
        !           926: 
        !           927:        fprintf(stderr, "'%s' = %%", argv[1]);
        !           928:        ones = false;
        !           929:        for (bit = 31; bit >= 0; bit--)
        !           930:        {
        !           931:                one = value & (1<<bit);
        !           932:                if (one || ones)
        !           933:                {
        !           934:                        fputc(one ? '1':'0', stderr);
        !           935:                        ones = true;
        !           936:                }
        !           937:        }
        !           938:        if (!ones)
        !           939:                fputc('0', stderr);
        !           940:        fprintf(stderr, " (bin), #%u (dec), $%x (hex)\n", value, value);
        !           941:        return DEBUGGER_CMDDONE;
1.1       root      942: }
                    943: 
1.1.1.9   root      944: 
1.1.1.8   root      945: /**
1.1.1.11! root      946:  * Command: Set options
1.1.1.8   root      947:  */
1.1.1.11! root      948: static int DebugUI_SetOptions(int argc, char *argv[])
1.1.1.6   root      949: {
1.1.1.11! root      950:        CNF_PARAMS current;
1.1.1.6   root      951: 
1.1.1.11! root      952:        /* get configuration changes */
        !           953:        current = ConfigureParams;
1.1       root      954: 
1.1.1.11! root      955:        /* Parse and apply options */
        !           956:        if (Opt_ParseParameters(argc, (const char**)argv))
1.1.1.6   root      957:        {
1.1.1.11! root      958:                ConfigureParams.Screen.bFullScreen = false;
        !           959:                Change_CopyChangedParamsToConfiguration(&current, &ConfigureParams, false);
1.1.1.6   root      960:        }
1.1.1.11! root      961:        else
        !           962:        {
        !           963:                ConfigureParams = current;
        !           964:        }
        !           965: 
        !           966:        return DEBUGGER_CMDDONE;
        !           967: }
        !           968: 
        !           969: 
        !           970: /**
        !           971:  * Command: Continue emulation / single-stepping
        !           972:  */
        !           973: static int DebugUI_Continue(int nArgc, char *psArgv[], bool bStepDsp)
        !           974: {
        !           975:        const char *chip;
        !           976:        int steps = 0;
        !           977:        
        !           978:        if (nArgc > 1)
        !           979:        {
        !           980:                steps = atoi(psArgv[1]);
        !           981:        }
        !           982:        /* at most one should be active at the same time */
        !           983:        nDspSteps = 0;
        !           984:        nCpuSteps = 0;
        !           985:        if (steps <= 0)
        !           986:        {
        !           987:                fprintf(stderr,"Returning to emulation...\n------------------------------\n\n");
        !           988:                return DEBUGGER_END;
        !           989:        }
        !           990:        if (bStepDsp)
        !           991:        {
        !           992:                nDspSteps = steps;
        !           993: #if ENABLE_DSP_EMU
        !           994:                chip = "DSP";
        !           995: #else
        !           996:                chip = "<NONE>";
        !           997: #endif
        !           998:        } else {
        !           999:                nCpuSteps = steps;
        !          1000:                chip = "CPU";
1.1.1.9   root     1001:        }
1.1.1.11! root     1002:        fprintf(stderr,"Returning to emulation for %i %s instructions...\n", steps, chip);
        !          1003:        return DEBUGGER_END;
        !          1004: }
        !          1005: 
        !          1006: /**
        !          1007:  * Command: Continue emulation / single-stepping CPU wrapper
        !          1008:  */
        !          1009: static int DebugUI_CpuContinue(int nArgc, char *psArgv[])
        !          1010: {
        !          1011:        return DebugUI_Continue(nArgc, psArgv, false);
        !          1012: }
        !          1013: /**
        !          1014:  * Command: Continue emulation / single-stepping DSP wrapper
        !          1015:  */
        !          1016: static int DebugUI_DspContinue(int nArgc, char *psArgv[])
        !          1017: {
        !          1018:        return DebugUI_Continue(nArgc, psArgv, true);
        !          1019: }
1.1.1.6   root     1020: 
1.1.1.8   root     1021: 
1.1.1.11! root     1022: /**
        !          1023:  * Command: Quit emulator
        !          1024:  */
        !          1025: static int DebugUI_QuitEmu(int nArgc, char *psArgv[])
        !          1026: {
        !          1027:        bQuitProgram = true;
        !          1028:        M68000_SetSpecial(SPCFLAG_BRK);   /* Assure that CPU core shuts down */
        !          1029:        return DEBUGGER_END;
        !          1030: }
        !          1031: 
        !          1032: 
        !          1033: typedef struct
        !          1034: {
        !          1035:        int (*pFunction)(int argc, char *argv[]);
        !          1036:        const char *sLongName;
        !          1037:        const char *sShortName;
        !          1038:        const char *sShortDesc;
        !          1039:        const char *sUsage;
        !          1040:        bool bNoParsing;
        !          1041: } dbgcommand_t;
        !          1042: 
        !          1043: dbgcommand_t commandtab[] =
        !          1044: {
        !          1045: #if ENABLE_DSP_EMU
        !          1046:        { DebugUI_DspBreakPoint, "dspaddress", "da",
        !          1047:          "toggle or list (traditional) DSP address breakpoints",
        !          1048:          "[address]\n"
        !          1049:          "\tToggle breakpoint at <address> or list all breakpoints when\n"
        !          1050:          "\tno address is given.",
        !          1051:          false },
        !          1052:        { DebugUI_BreakCondDsp, "dspbreak", "db",
        !          1053:          "set/remove/list DSP register/RAM condition breakpoints",
        !          1054:          "[help | all | <breakpoint index> | <breakpoint condition>]\n"
        !          1055:          "\tSet breakpoint with given condition, remove breakpoint with\n"
        !          1056:          "\tgiven index or list all breakpoints when no args are given.\n"
        !          1057:          "\t'help' outputs breakpoint condition syntax help, 'all' removes\n"
        !          1058:          "\tall conditional breakpoints",
        !          1059:          true },
        !          1060:        { DebugUI_DspDisAsm, "dspdisasm", "dd",
        !          1061:          "disassemble DSP code",
        !          1062:          "[address]\n"
        !          1063:          "\tDisassemble from DSP-PC, otherwise at given address.",
        !          1064:          false },
        !          1065:        { DebugUI_DspMemDump, "dspmemdump", "dm",
        !          1066:          "dump DSP memory",
        !          1067:          "<x|y|p> [address]\n"
        !          1068:          "\tdump DSP memory at address, or continue from previous address if not\n"
        !          1069:          "\tspecified.",
        !          1070:          false },
        !          1071:        { DebugUI_DspRegister, "dspreg", "dr",
        !          1072:          "read/write DSP registers",
        !          1073:          "[REG=value]"
        !          1074:          "\tSet or dump contents of DSP registers.",
        !          1075:          false },
        !          1076:        { DebugUI_DspContinue, "dspcont", "dc",
        !          1077:          "continue emulation / DSP single-stepping",
        !          1078:          "[steps]\n"
        !          1079:          "\tLeave debugger and continue emulation for <steps> DSP instructions\n"
        !          1080:          "\tor forever if no steps have been specified.",
        !          1081:          false },
        !          1082: #endif
        !          1083:        { DebugUI_CpuBreakPoint, "address", "a",
        !          1084:          "toggle or list (traditional) CPU address breakpoints",
        !          1085:          "[address]\n"
        !          1086:          "\tToggle breakpoint at <address> or list all breakpoints when\n"
        !          1087:          "\tno address is given.",
        !          1088:          false },
        !          1089:        { DebugUI_BreakCondCpu, "breakpoint", "b",
        !          1090:          "set/remove/list register/RAM condition breakpoints",
        !          1091:          "[help | all | <breakpoint index> | <breakpoint condition>]\n"
        !          1092:          "\tSet breakpoint with given condition, remove breakpoint with\n"
        !          1093:          "\tgiven index or list all breakpoints when no args are given.\n"
        !          1094:          "\t'help' outputs breakpoint condition syntax help, 'all' removes\n"
        !          1095:          "\tall conditional breakpoints",
        !          1096:          true },
        !          1097:        { DebugUI_DisAsm, "disasm", "d",
        !          1098:          "disassemble from PC, or given address",
        !          1099:          "[address]\n"
        !          1100:          "\tIf no address is given, this command disassembles from the last\n"
        !          1101:          "\tposition or from current PC if no last postition is available.",
        !          1102:          false },
        !          1103:        { DebugUI_CpuRegister, "cpureg", "r",
        !          1104:          "dump register values or set register to value",
        !          1105:          "[REG=value]\n"
        !          1106:          "\tSet CPU register to value or dumps all register if no parameter\n"
        !          1107:          "\thas been specified.",
        !          1108:          false },
        !          1109:        { DebugUI_MemDump, "memdump", "m",
        !          1110:          "dump memory",
        !          1111:          "[address]\n"
        !          1112:          "\tdump memory at address or continue dump from previous address.",
        !          1113:          false },
        !          1114:        { DebugUI_MemWrite, "memwrite", "w",
        !          1115:          "write bytes to memory",
        !          1116:          "address byte1 [byte2 ...]\n"
        !          1117:          "\tWrite bytes to a memory address, bytes are space separated\n"
        !          1118:          "\thexadecimals.",
        !          1119:          false },
        !          1120:        { DebugUI_SetLogFile, "logfile", "f",
        !          1121:          "open or close log file",
        !          1122:          "[filename]\n"
        !          1123:          "\tOpen log file, no argument closes the log file. Output of\n"
        !          1124:          "\tregister & memory dumps and disassembly will be written to it.",
        !          1125:          false },
        !          1126:        { DebugUI_LoadBin, "loadbin", "l",
        !          1127:          "load a file into memory",
        !          1128:          "filename address\n"
        !          1129:          "\tLoad the file <filename> into memory starting at <address>.",
        !          1130:          false },
        !          1131:        { DebugUI_SaveBin, "savebin", "s",
        !          1132:          "save memory to a file",
        !          1133:          "filename address length\n"
        !          1134:          "\tSave the memory block at <address> with given <length> to\n"
        !          1135:          "\tthe file <filename>.",
        !          1136:          false },
        !          1137:        { DebugUI_SetOptions, "setopt", "o",
        !          1138:          "set Hatari command line options",
        !          1139:          "[command line parameters]\n"
        !          1140:          "\tSet options like command line parameters. For example to"
        !          1141:          "\tenable CPU disasm tracing:  setopt --trace cpu_disasm",
        !          1142:          false },
        !          1143:        { DebugUI_ShowValue, "value", "v",
        !          1144:          "set number base / show value in other number bases",
        !          1145:          "<bin|dec|hex|value>\n"
        !          1146:          "\tHelper to change the default number base and to see given values\n"
        !          1147:          "\tin all the supported bin/dec/hex number bases.",
        !          1148:          false },
        !          1149:        { DebugUI_CpuContinue, "cont", "c",
        !          1150:          "continue emulation / CPU single-stepping",
        !          1151:          "[steps]\n"
        !          1152:          "\tLeave debugger and continue emulation for <steps> CPU instructions\n"
        !          1153:          "\tor forever if no steps have been specified.",
        !          1154:          false },
        !          1155:        { DebugUI_QuitEmu, "quit", "q",
        !          1156:          "quit emulator",
        !          1157:          "\n"
        !          1158:          "\tLeave debugger and quit emulator.",
        !          1159:          false },
        !          1160:        { DebugUI_Help, "help", "h",
        !          1161:          "print help",
        !          1162:          "[command]"
        !          1163:          "\tPrint help text for available commands.",
        !          1164:          false },
        !          1165: };
        !          1166: 
        !          1167: 
        !          1168: /**
        !          1169:  * Print help text for one command
        !          1170:  */
        !          1171: static void DebugUI_PrintCmdHelp(const char *psCmd)
        !          1172: {
        !          1173:        int i;
        !          1174: 
        !          1175:        /* Search the command ... */
        !          1176:        for (i = 0; i < ARRAYSIZE(commandtab); i++)
1.1.1.6   root     1177:        {
1.1.1.11! root     1178:                if (!strcmp(psCmd, commandtab[i].sLongName)
        !          1179:                    || !strcmp(psCmd, commandtab[i].sShortName))
        !          1180:                {
        !          1181:                        /* ... and print help text */
        !          1182:                        fprintf(stderr, "'%s' or '%s' - %s\n",
        !          1183:                                commandtab[i].sLongName, commandtab[i].sShortName,
        !          1184:                                commandtab[i].sShortDesc);
        !          1185:                        fprintf(stderr, "Usage:  %s %s\n", commandtab[i].sShortName,
        !          1186:                                commandtab[i].sUsage);
        !          1187:                        return;
1.1.1.6   root     1188:                }
1.1.1.11! root     1189:        }
1.1.1.6   root     1190: 
1.1.1.11! root     1191:        fprintf(stderr, "Unknown command '%s'\n", psCmd);
        !          1192: }
1.1.1.6   root     1193: 
                   1194: 
1.1.1.11! root     1195: /**
        !          1196:  * Command: Print debugger help screen.
        !          1197:  */
        !          1198: static int DebugUI_Help(int nArgc, char *psArgs[])
        !          1199: {
        !          1200:        int i;
        !          1201: 
        !          1202:        if (nArgc > 1)
        !          1203:        {
        !          1204:                DebugUI_PrintCmdHelp(psArgs[1]);
        !          1205:                return DEBUGGER_CMDDONE;
        !          1206:        }
        !          1207: 
        !          1208:        fputs("Available commands:\n", stderr);
        !          1209:        for (i = 0; i < ARRAYSIZE(commandtab); i++)
        !          1210:        {
        !          1211:                fprintf(stderr, " %12s (%2s) : %s\n", commandtab[i].sLongName,
        !          1212:                        commandtab[i].sShortName, commandtab[i].sShortDesc);
        !          1213:        }
        !          1214: 
        !          1215:        fprintf(stderr,
        !          1216:                "If value is prefixed with '$', it's a hexadecimal, if with '#', it's\n"
        !          1217:                "a normal decimal, if with '%%', it's a binary decimal. Prefix can\n"
        !          1218:                "be skipped for numbers in the default number base (currently %d).\n"
        !          1219:                "Adresses may be given as a range like '$fc0000-$fc0100'.\n"
        !          1220:                "'h <command>' gives more help.\n", ConfigureParams.Log.nNumberBase);
        !          1221:        return DEBUGGER_CMDDONE;
        !          1222: }
        !          1223: 
        !          1224: 
        !          1225: /**
        !          1226:  * Parse debug command and execute it.
        !          1227:  */
        !          1228: int DebugUI_ParseCommand(char *input)
        !          1229: {
        !          1230:        char *psArgs[64];
        !          1231:        const char *delim;
        !          1232:        static char sLastCmd[80] = { '\0' };
        !          1233:        int nArgc, cmd = -1;
        !          1234:        int i, retval;
1.1.1.6   root     1235: 
1.1.1.11! root     1236:        psArgs[0] = strtok(input, " \t");
        !          1237: 
        !          1238:        if (psArgs[0] == NULL)
        !          1239:        {
        !          1240:                if (strlen(sLastCmd) > 0)
        !          1241:                        psArgs[0] = sLastCmd;
1.1.1.8   root     1242:                else
1.1.1.11! root     1243:                        return DEBUGGER_CMDDONE;
        !          1244:        }
        !          1245: 
        !          1246:        /* Search the command ... */
        !          1247:        for (i = 0; i < ARRAYSIZE(commandtab); i++)
        !          1248:        {
        !          1249:                if (!strcmp(psArgs[0], commandtab[i].sLongName)
        !          1250:                    || !strcmp(psArgs[0], commandtab[i].sShortName))
        !          1251:                {
        !          1252:                        cmd = i;
        !          1253:                        break;
        !          1254:                }
        !          1255:        }
        !          1256:        if (cmd == -1)
        !          1257:        {
        !          1258:                fprintf(stderr, "Command '%s' not found.\n"
        !          1259:                        "Use 'help' to view a list of available commands.\n",
        !          1260:                        psArgs[0]);
        !          1261:                return DEBUGGER_CMDDONE;
        !          1262:        }
        !          1263: 
        !          1264:        if (commandtab[cmd].bNoParsing)
        !          1265:                delim = "";
        !          1266:        else
        !          1267:                delim = " \t";
        !          1268: 
        !          1269:        /* Separate arguments and put the pointers into psArgs */
        !          1270:        for (nArgc = 1; nArgc < ARRAYSIZE(psArgs); nArgc++)
        !          1271:        {
        !          1272:                psArgs[nArgc] = strtok(NULL, delim);
        !          1273:                if (psArgs[nArgc] == NULL)
        !          1274:                        break;
        !          1275:        }
1.1.1.6   root     1276: 
1.1.1.11! root     1277:        if (!debugOutput) {
        !          1278:                /* make sure also calls from control.c work */
        !          1279:                DebugUI_SetLogDefault();
1.1.1.6   root     1280:        }
                   1281: 
1.1.1.11! root     1282:        /* ... and execute the function */
        !          1283:        retval = commandtab[i].pFunction(nArgc, psArgs);
        !          1284:        /* Save commando string if it can be repeated */
        !          1285:        if (retval == DEBUGGER_CMDCONT)
        !          1286:                strncpy(sLastCmd, psArgs[0], sizeof(sLastCmd));
        !          1287:        else
        !          1288:                sLastCmd[0] = '\0';
1.1.1.9   root     1289:        return retval;
                   1290: }
                   1291: 
1.1.1.11! root     1292: 
1.1.1.9   root     1293: /**
1.1.1.11! root     1294:  * Read a command line from the keyboard and return a pointer to the string.
        !          1295:  * @return     Pointer to the string which should be deallocated free()
        !          1296:  *              after use. Returns NULL when error occured.
1.1.1.9   root     1297:  */
1.1.1.11! root     1298: static char *DebugUI_GetCommand(void)
1.1.1.9   root     1299: {
                   1300:        char *input;
1.1.1.8   root     1301: 
1.1.1.9   root     1302: #if HAVE_LIBREADLINE
                   1303:        input = readline("> ");
                   1304:        if (!input)
1.1.1.11! root     1305:                return NULL;
1.1.1.9   root     1306:        if (input[0] != 0)
                   1307:                add_history(input);
                   1308: #else
                   1309:        fprintf(stderr, "> ");
                   1310:        input = malloc(256);
                   1311:        if (!input)
1.1.1.11! root     1312:                return NULL;
1.1.1.9   root     1313:        input[0] = '\0';
1.1.1.11! root     1314:        if (fgets(input, 256, stdin) == NULL)
        !          1315:        {
        !          1316:                free(input);
        !          1317:                return NULL;
        !          1318:        }
1.1.1.9   root     1319: #endif
1.1.1.11! root     1320:        input = Str_Trim(input);
1.1.1.9   root     1321: 
1.1.1.11! root     1322:        return input;
        !          1323: }
        !          1324: 
        !          1325: 
        !          1326: /**
        !          1327:  * Texts shown when entering the debugger on first and successive times
        !          1328:  */
        !          1329: static void DebugUI_WelcomeText(void)
        !          1330: {
        !          1331:        int hbl, fcycles, lcycles;
        !          1332:        static const char *welcome =
        !          1333:                "\n----------------------------------------------------------------------"
        !          1334:                "\nYou have entered debug mode. Type c to continue emulation, h for help.\n";
        !          1335:        if (welcome)
        !          1336:        {
        !          1337:                fputs(welcome, stderr);
        !          1338:                welcome = NULL;
        !          1339:        }
        !          1340:        Video_GetPosition(&fcycles, &hbl, &lcycles);
        !          1341:        fprintf(stderr, "\nCPU=$%x, VBL=%d, FrameCycles=%d, HBL=%d, LineCycles=%d, DSP=",
        !          1342:                M68000_GetPC(), nVBLs, fcycles, hbl, lcycles);
        !          1343:        if (bDspEnabled)
        !          1344:                fprintf(stderr, "$%x\n", DSP_GetPC());
        !          1345:        else
        !          1346:                fprintf(stderr, "N/A\n");
1.1       root     1347: }
                   1348: 
                   1349: 
1.1.1.8   root     1350: /**
1.1.1.11! root     1351:  * Debugger user interface main function.
1.1.1.8   root     1352:  */
1.1.1.4   root     1353: void DebugUI(void)
1.1       root     1354: {
1.1.1.11! root     1355:        int cmdret;
        !          1356: 
        !          1357:        /* if you want disassembly or memdumping to start/continue from
        !          1358:         * specific address, you can set them here.  If disassembly
        !          1359:         * address is zero, disassembling starts from PC.
        !          1360:         */
        !          1361: #if ENABLE_DSP_EMU
        !          1362:        dsp_disasm_addr = 0;
        !          1363:        dsp_memdump_addr = 0;
        !          1364:        dsp_mem_space = 'P';
        !          1365: #endif
        !          1366:        memdump_addr = 0;
1.1.1.6   root     1367:        disasm_addr = 0;
1.1.1.2   root     1368: 
1.1.1.11! root     1369:        if (bInFullScreen)
        !          1370:                Screen_ReturnFromFullScreen();
        !          1371: 
        !          1372:        DebugUI_WelcomeText();
        !          1373:        
        !          1374:        /* override paused message so that user knows to look into console
        !          1375:         * on how to continue in case he invoked the debugger by accident.
        !          1376:         */
        !          1377:        Statusbar_AddMessage("Console Debugger", 100);
        !          1378:        Statusbar_Update(sdlscrn);
        !          1379: 
        !          1380:        do
        !          1381:        {
        !          1382:                char *psCmd;
        !          1383: 
        !          1384:                /* Read command from the keyboard */
        !          1385:                psCmd = DebugUI_GetCommand();
        !          1386: 
        !          1387:                if (psCmd)
        !          1388:                {
        !          1389:                        /* Parse and execute the command string */
        !          1390:                        cmdret = DebugUI_ParseCommand(psCmd);
        !          1391:                        free(psCmd);
        !          1392:                }
        !          1393:                else
        !          1394:                {
        !          1395:                        cmdret = DEBUGGER_END;
        !          1396:                }
        !          1397:        }
        !          1398:        while (cmdret != DEBUGGER_END);
        !          1399: 
1.1.1.9   root     1400:        DebugUI_SetLogDefault();
1.1.1.11! root     1401: 
        !          1402:        /* If "real-time" debugging like breakpoints has been set, we've
        !          1403:         * got to tell the CPU core to call us after each instruction! */
        !          1404:        if (nCpuActiveBPs || nCpuActiveCBs || nCpuSteps)
        !          1405:                M68000_SetSpecial(SPCFLAG_DEBUGGER);
        !          1406:        else
        !          1407:                M68000_UnsetSpecial(SPCFLAG_DEBUGGER);
        !          1408:        /* ...and DSP core */
        !          1409:        if (nDspActiveBPs || nDspActiveCBs || nDspSteps)
        !          1410:                DSP_SetDebugging(true);
        !          1411:        else
        !          1412:                DSP_SetDebugging(false);
        !          1413: }
        !          1414: 
        !          1415: 
        !          1416: /**
        !          1417:  * Check if we hit a CPU breakpoint
        !          1418:  */
        !          1419: static void DebugUI_CheckCpuBreakpoints(void)
        !          1420: {
        !          1421:        Uint32 pc = M68000_GetPC();
        !          1422:        int i;
        !          1423: 
        !          1424:        for (i = 0; i < nCpuActiveBPs; i++)
        !          1425:        {
        !          1426:                if (pc == CpuBreakPoint[i])
        !          1427:                {
        !          1428:                        fprintf(stderr, "\nCPU breakpoint at %x ...", pc);
        !          1429:                        DebugUI();
        !          1430:                        break;
        !          1431:                }
        !          1432:        }
        !          1433: }
        !          1434: 
        !          1435: 
        !          1436: /**
        !          1437:  * This function is called after each CPU instruction when debugging is enabled.
        !          1438:  */
        !          1439: void DebugUI_CpuCheck(void)
        !          1440: {
        !          1441:        if (nCpuActiveBPs)
        !          1442:        {
        !          1443:                DebugUI_CheckCpuBreakpoints();
        !          1444:        }
        !          1445:        if (nCpuActiveCBs)
        !          1446:        {
        !          1447:                if (BreakCond_MatchCpu())
        !          1448:                        DebugUI();
        !          1449:        }
        !          1450:        if (nCpuSteps)
        !          1451:        {
        !          1452:                nCpuSteps -= 1;
        !          1453:                if (nCpuSteps == 0)
        !          1454:                        DebugUI();
        !          1455:        }
1.1       root     1456: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.