Annotation of hatari/src/debug/debugcpu.c, revision 1.1.1.6

1.1       root        1: /*
                      2:   Hatari - debugcpu.c
                      3: 
1.1.1.5   root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
                      7:   debugcpu.c - function needed for the CPU debugging tasks like memory
                      8:   and register dumps.
                      9: */
                     10: const char DebugCpu_fileid[] = "Hatari debugcpu.c : " __DATE__ " " __TIME__;
                     11: 
                     12: #include <stdio.h>
1.1.1.6 ! root       13: #include <ctype.h>
1.1       root       14: 
                     15: #include "config.h"
                     16: 
                     17: #include "main.h"
                     18: #include "breakcond.h"
                     19: #include "configuration.h"
                     20: #include "debugui.h"
                     21: #include "debug_priv.h"
                     22: #include "debugcpu.h"
                     23: #include "evaluate.h"
                     24: #include "hatari-glue.h"
1.1.1.3   root       25: #include "history.h"
1.1       root       26: #include "log.h"
                     27: #include "m68000.h"
                     28: #include "memorySnapShot.h"
1.1.1.2   root       29: #include "profile.h"
1.1       root       30: #include "stMemory.h"
                     31: #include "str.h"
                     32: #include "symbols.h"
1.1.1.2   root       33: #include "68kDisass.h"
1.1.1.5   root       34: #include "console.h"
                     35: #include "options.h"
                     36: 
1.1       root       37: 
                     38: #define MEMDUMP_COLS   16      /* memdump, number of bytes per row */
                     39: #define NON_PRINT_CHAR '.'     /* character to display for non-printables */
                     40: 
                     41: static Uint32 disasm_addr;     /* disasm address */
                     42: static Uint32 memdump_addr;    /* memdump address */
                     43: 
1.1.1.2   root       44: static bool bCpuProfiling;     /* Whether CPU profiling is activated */
1.1       root       45: static int nCpuActiveCBs = 0;  /* Amount of active conditional breakpoints */
                     46: static int nCpuSteps = 0;      /* Amount of steps for CPU single-stepping */
                     47: 
                     48: 
                     49: /**
                     50:  * Load a binary file to a memory address.
                     51:  */
                     52: static int DebugCpu_LoadBin(int nArgc, char *psArgs[])
                     53: {
                     54:        FILE *fp;
                     55:        unsigned char c;
                     56:        Uint32 address;
                     57:        int i=0;
                     58: 
                     59:        if (nArgc < 3)
                     60:        {
1.1.1.6 ! root       61:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root       62:        }
                     63: 
                     64:        if (!Eval_Number(psArgs[2], &address))
                     65:        {
                     66:                fprintf(stderr, "Invalid address!\n");
                     67:                return DEBUGGER_CMDDONE;
                     68:        }
                     69:        address &= 0x00FFFFFF;
                     70: 
                     71:        if ((fp = fopen(psArgs[1], "rb")) == NULL)
                     72:        {
                     73:                fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]);
                     74:                return DEBUGGER_CMDDONE;
                     75:        }
                     76: 
                     77:        c = fgetc(fp);
                     78:        while (!feof(fp))
                     79:        {
                     80:                i++;
                     81:                STMemory_WriteByte(address++, c);
                     82:                c = fgetc(fp);
                     83:        }
                     84:        fprintf(stderr,"  Read 0x%x bytes.\n", i);
                     85:        fclose(fp);
                     86: 
                     87:        return DEBUGGER_CMDDONE;
                     88: }
                     89: 
                     90: 
                     91: /**
                     92:  * Dump memory from an address to a binary file.
                     93:  */
                     94: static int DebugCpu_SaveBin(int nArgc, char *psArgs[])
                     95: {
                     96:        FILE *fp;
                     97:        unsigned char c;
                     98:        Uint32 address;
                     99:        Uint32 bytes, i = 0;
                    100: 
                    101:        if (nArgc < 4)
                    102:        {
1.1.1.6 ! root      103:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root      104:        }
                    105: 
                    106:        if (!Eval_Number(psArgs[2], &address))
                    107:        {
                    108:                fprintf(stderr, "  Invalid address!\n");
                    109:                return DEBUGGER_CMDDONE;
                    110:        }
                    111:        address &= 0x00FFFFFF;
                    112: 
                    113:        if (!Eval_Number(psArgs[3], &bytes))
                    114:        {
                    115:                fprintf(stderr, "  Invalid length!\n");
                    116:                return DEBUGGER_CMDDONE;
                    117:        }
                    118: 
                    119:        if ((fp = fopen(psArgs[1], "wb")) == NULL)
                    120:        {
                    121:                fprintf(stderr,"  Cannot open file '%s'!\n", psArgs[1]);
                    122:                return DEBUGGER_CMDDONE;
                    123:        }
                    124: 
                    125:        while (i < bytes)
                    126:        {
                    127:                c = STMemory_ReadByte(address++);
                    128:                fputc(c, fp);
                    129:                i++;
                    130:        }
                    131:        fclose(fp);
                    132:        fprintf(stderr, "  Wrote 0x%x bytes.\n", bytes);
                    133: 
                    134:        return DEBUGGER_CMDDONE;
                    135: }
                    136: 
                    137: 
                    138: /**
1.1.1.2   root      139:  * Check whether given address matches any CPU symbol and whether
                    140:  * there's profiling information available for it.  If yes, show it.
1.1       root      141:  */
1.1.1.2   root      142: static void DebugCpu_ShowAddressInfo(Uint32 addr)
1.1       root      143: {
1.1.1.4   root      144:        const char *symbol = Symbols_GetByCpuAddress(addr);
1.1       root      145:        if (symbol)
1.1.1.4   root      146:                fprintf(debugOutput, "%s:\n", symbol);
1.1       root      147: }
                    148: 
                    149: /**
                    150:  * Dissassemble - arg = starting address, or PC.
                    151:  */
                    152: int DebugCpu_DisAsm(int nArgc, char *psArgs[])
                    153: {
                    154:        Uint32 disasm_upper = 0;
                    155:        int insts, max_insts;
                    156:        uaecptr nextpc;
                    157: 
                    158:        if (nArgc > 1)
                    159:        {
1.1.1.2   root      160:                switch (Eval_Range(psArgs[1], &disasm_addr, &disasm_upper, false))
1.1       root      161:                {
                    162:                case -1:
                    163:                        /* invalid value(s) */
                    164:                        return DEBUGGER_CMDDONE;
                    165:                case 0:
                    166:                        /* single value */
                    167:                        break;
                    168:                case 1:
                    169:                        /* range */
                    170:                        disasm_upper &= 0x00FFFFFF;
                    171:                        break;
                    172:                }
                    173:        }
                    174:        else
                    175:        {
                    176:                /* continue */
                    177:                if(!disasm_addr)
                    178:                        disasm_addr = M68000_GetPC();
                    179:        }
                    180:        disasm_addr &= 0x00FFFFFF;
                    181: 
                    182:        /* limit is topmost address or instruction count */
                    183:        if (disasm_upper)
                    184:        {
                    185:                max_insts = INT_MAX;
                    186:        }
                    187:        else
                    188:        {
                    189:                disasm_upper = 0x00FFFFFF;
                    190:                max_insts = ConfigureParams.Debugger.nDisasmLines;
                    191:        }
                    192: 
                    193:        /* output a range */
                    194:        for (insts = 0; insts < max_insts && disasm_addr < disasm_upper; insts++)
                    195:        {
1.1.1.2   root      196:                DebugCpu_ShowAddressInfo(disasm_addr);
1.1.1.5   root      197:                Disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1);
1.1       root      198:                disasm_addr = nextpc;
                    199:        }
                    200:        fflush(debugOutput);
                    201: 
                    202:        return DEBUGGER_CMDCONT;
                    203: }
                    204: 
                    205: 
                    206: /**
                    207:  * Readline match callback to list register names usable within debugger.
                    208:  * STATE = 0 -> different text from previous one.
                    209:  * Return next match or NULL if no matches.
                    210:  */
                    211: static char *DebugCpu_MatchRegister(const char *text, int state)
                    212: {
1.1.1.6 ! root      213:        static const char* regs[] = {
1.1       root      214:                "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
                    215:                "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
                    216:                "pc", "sr"
                    217:        };
1.1.1.6 ! root      218:        return DebugUI_MatchHelper(regs, ARRAYSIZE(regs), text, state);
1.1       root      219: }
                    220: 
                    221: 
                    222: /**
1.1.1.5   root      223:  * Set address of the named 32-bit register to given argument.
1.1       root      224:  * Return register size in bits or zero for uknown register name.
                    225:  * Handles D0-7 data and A0-7 address registers, but not PC & SR
                    226:  * registers as they need to be accessed using UAE accessors.
                    227:  */
                    228: int DebugCpu_GetRegisterAddress(const char *reg, Uint32 **addr)
                    229: {
                    230:        char r0, r1;
                    231:        if (!reg[0] || !reg[1] || reg[2])
                    232:                return 0;
                    233:        
1.1.1.6 ! root      234:        r0 = toupper((unsigned char)reg[0]);
        !           235:        r1 = toupper((unsigned char)reg[1]);
1.1       root      236: 
                    237:        if (r0 == 'D')  /* Data regs? */
                    238:        {
                    239:                if (r1 >= '0' && r1 <= '7')
                    240:                {
                    241:                        *addr = &(Regs[REG_D0 + r1 - '0']);
                    242:                        return 32;
                    243:                }
                    244:                fprintf(stderr,"\tBad data register, valid values are 0-7\n");
                    245:                return 0;
                    246:        }
                    247:        if(r0 == 'A')  /* Address regs? */
                    248:        {
                    249:                if (r1 >= '0' && r1 <= '7')
                    250:                {
                    251:                        *addr = &(Regs[REG_A0 + r1 - '0']);
                    252:                        return 32;
                    253:                }
                    254:                fprintf(stderr,"\tBad address register, valid values are 0-7\n");
                    255:                return 0;
                    256:        }
                    257:        return 0;
                    258: }
                    259: 
                    260: 
                    261: /**
                    262:  * Dump or set CPU registers
                    263:  */
                    264: int DebugCpu_Register(int nArgc, char *psArgs[])
                    265: {
                    266:        char reg[3], *assign;
                    267:        Uint32 value;
                    268:        char *arg;
                    269: 
                    270:        /* If no parameter has been given, simply dump all registers */
                    271:        if (nArgc == 1)
                    272:        {
                    273:                uaecptr nextpc;
                    274:                /* use the UAE function instead */
                    275:                m68k_dumpstate(debugOutput, &nextpc);
                    276:                fflush(debugOutput);
                    277:                return DEBUGGER_CMDDONE;
                    278:        }
                    279: 
                    280:        arg = psArgs[1];
                    281: 
                    282:        assign = strchr(arg, '=');
                    283:        if (!assign)
                    284:        {
                    285:                goto error_msg;
                    286:        }
                    287: 
                    288:        *assign++ = '\0';
                    289:        if (!Eval_Number(Str_Trim(assign), &value))
                    290:        {
                    291:                goto error_msg;
                    292:        }
                    293: 
                    294:        arg = Str_Trim(arg);
                    295:        if (strlen(arg) != 2)
                    296:        {
                    297:                goto error_msg;
                    298:        }
1.1.1.6 ! root      299:        reg[0] = toupper((unsigned char)arg[0]);
        !           300:        reg[1] = toupper((unsigned char)arg[1]);
1.1       root      301:        reg[2] = '\0';
                    302:        
                    303:        /* set SR and update conditional flags for the UAE CPU core. */
                    304:        if (reg[0] == 'S' && reg[1] == 'R')
                    305:        {
                    306:                M68000_SetSR(value);
                    307:        }
                    308:        else if (reg[0] == 'P' && reg[1] == 'C')   /* set PC? */
                    309:        {
                    310:                M68000_SetPC(value);
                    311:        }
                    312:        else
                    313:        {
                    314:                Uint32 *regaddr;
                    315:                /* check&set data and address registers */
                    316:                if (DebugCpu_GetRegisterAddress(reg, &regaddr))
                    317:                {
                    318:                        *regaddr = value;
                    319:                }
                    320:                else
                    321:                {
                    322:                        goto error_msg;
                    323:                }
                    324:        }
                    325:        return DEBUGGER_CMDDONE;
                    326: 
                    327: error_msg:
                    328:        fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR.\n");
                    329:        return DEBUGGER_CMDDONE;
                    330: }
                    331: 
                    332: 
                    333: /**
1.1.1.2   root      334:  * CPU wrapper for BreakAddr_Command().
1.1       root      335:  */
                    336: static int DebugCpu_BreakAddr(int nArgc, char *psArgs[])
                    337: {
                    338:        BreakAddr_Command(psArgs[1], false);
                    339:        return DEBUGGER_CMDDONE;
                    340: }
                    341: 
                    342: /**
1.1.1.2   root      343:  * CPU wrapper for BreakCond_Command().
1.1       root      344:  */
                    345: static int DebugCpu_BreakCond(int nArgc, char *psArgs[])
                    346: {
                    347:        BreakCond_Command(psArgs[1], false);
                    348:        return DEBUGGER_CMDDONE;
                    349: }
                    350: 
1.1.1.2   root      351: /**
                    352:  * CPU wrapper for Profile_Command().
                    353:  */
                    354: static int DebugCpu_Profile(int nArgc, char *psArgs[])
                    355: {
1.1.1.5   root      356:        return Profile_Command(nArgc, psArgs, false);
1.1.1.2   root      357: }
                    358: 
1.1       root      359: 
                    360: /**
                    361:  * Do a memory dump, args = starting address.
                    362:  */
                    363: int DebugCpu_MemDump(int nArgc, char *psArgs[])
                    364: {
                    365:        int i;
                    366:        char c;
                    367:        Uint32 memdump_upper = 0;
                    368: 
                    369:        if (nArgc > 1)
                    370:        {
1.1.1.2   root      371:                switch (Eval_Range(psArgs[1], &memdump_addr, &memdump_upper, false))
1.1       root      372:                {
                    373:                case -1:
                    374:                        /* invalid value(s) */
                    375:                        return DEBUGGER_CMDDONE;
                    376:                case 0:
                    377:                        /* single value */
                    378:                        break;
                    379:                case 1:
                    380:                        /* range */
                    381:                        break;
                    382:                }
                    383:        } /* continue */
                    384:        memdump_addr &= 0x00FFFFFF;
                    385: 
                    386:        if (!memdump_upper)
                    387:        {
                    388:                memdump_upper = memdump_addr + MEMDUMP_COLS * ConfigureParams.Debugger.nMemdumpLines;
                    389:        }
                    390:        memdump_upper &= 0x00FFFFFF;
                    391: 
                    392:        while (memdump_addr < memdump_upper)
                    393:        {
                    394:                fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
                    395:                for (i = 0; i < MEMDUMP_COLS; i++)               /* print hex data */
                    396:                        fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
                    397:                fprintf(debugOutput, "  ");                     /* print ASCII data */
                    398:                for (i = 0; i < MEMDUMP_COLS; i++)
                    399:                {
                    400:                        c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
                    401:                        if(!isprint((unsigned)c))
                    402:                                c = NON_PRINT_CHAR;             /* non-printable as dots */
                    403:                        fprintf(debugOutput,"%c", c);
                    404:                }
                    405:                fprintf(debugOutput, "\n");            /* newline */
                    406:        } /* while */
                    407:        fflush(debugOutput);
                    408: 
                    409:        return DEBUGGER_CMDCONT;
                    410: }
                    411: 
                    412: 
                    413: /**
                    414:  * Command: Write to memory, arg = starting address, followed by bytes.
                    415:  */
                    416: static int DebugCpu_MemWrite(int nArgc, char *psArgs[])
                    417: {
                    418:        int i, numBytes;
                    419:        Uint32 write_addr, d;
                    420:        unsigned char bytes[256]; /* store bytes */
                    421: 
                    422:        if (nArgc < 3)
                    423:        {
1.1.1.6 ! root      424:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root      425:        }
                    426: 
                    427:        /* Read address */
                    428:        if (!Eval_Number(psArgs[1], &write_addr))
                    429:        {
                    430:                fprintf(stderr, "Bad address!\n");
                    431:                return DEBUGGER_CMDDONE;
                    432:        }
                    433: 
                    434:        write_addr &= 0x00FFFFFF;
                    435:        numBytes = 0;
                    436: 
                    437:        /* get bytes data */
                    438:        for (i = 2; i < nArgc; i++)
                    439:        {
                    440:                if (!Eval_Number(psArgs[i], &d) || d > 255)
                    441:                {
                    442:                        fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]);
                    443:                        return DEBUGGER_CMDDONE;
                    444:                }
                    445: 
                    446:                bytes[numBytes] = d & 0x0FF;
                    447:                numBytes++;
                    448:        }
                    449: 
                    450:        /* write the data */
                    451:        for (i = 0; i < numBytes; i++)
                    452:                STMemory_WriteByte(write_addr + i, bytes[i]);
                    453: 
                    454:        return DEBUGGER_CMDDONE;
                    455: }
                    456: 
                    457: 
                    458: /**
                    459:  * Command: Continue CPU emulation / single-stepping
                    460:  */
                    461: static int DebugCpu_Continue(int nArgc, char *psArgv[])
                    462: {
                    463:        int steps = 0;
                    464:        
                    465:        if (nArgc > 1)
                    466:        {
                    467:                steps = atoi(psArgv[1]);
                    468:        }
                    469:        if (steps <= 0)
                    470:        {
                    471:                nCpuSteps = 0;
                    472:                fprintf(stderr,"Returning to emulation...\n");
                    473:                return DEBUGGER_END;
                    474:        }
                    475:        nCpuSteps = steps;
                    476:        fprintf(stderr,"Returning to emulation for %i CPU instructions...\n", steps);
                    477:        return DEBUGGER_END;
                    478: }
                    479: 
1.1.1.5   root      480: /**
                    481:  * Command: Single-step CPU
                    482:  */
                    483: static int DebugCpu_Step(int nArgc, char *psArgv[])
                    484: {
                    485:        nCpuSteps = 1;
                    486:        return DEBUGGER_END;
                    487: }
                    488: 
1.1.1.6 ! root      489: 
        !           490: /**
        !           491:  * Readline match callback to list next command opcode types.
        !           492:  * STATE = 0 -> different text from previous one.
        !           493:  * Return next match or NULL if no matches.
        !           494:  */
        !           495: static char *DebugCpu_MatchNext(const char *text, int state)
        !           496: {
        !           497:        static const char* ntypes[] = {
        !           498:                "branch", "exception", "exreturn", "return", "subcall", "subreturn"
        !           499:        };
        !           500:        return DebugUI_MatchHelper(ntypes, ARRAYSIZE(ntypes), text, state);
        !           501: }
        !           502: 
1.1.1.5   root      503: /**
                    504:  * Command: Step CPU, but proceed through subroutines
                    505:  * Does this by temporary conditional breakpoint
                    506:  */
                    507: static int DebugCpu_Next(int nArgc, char *psArgv[])
                    508: {
1.1.1.6 ! root      509:        char command[40];
        !           510:        if (nArgc > 1)
        !           511:        {
        !           512:                int optype;
        !           513:                if(strcmp(psArgv[1], "branch") == 0)
        !           514:                        optype = CALL_BRANCH;
        !           515:                else if(strcmp(psArgv[1], "exception") == 0)
        !           516:                        optype = CALL_EXCEPTION;
        !           517:                else if(strcmp(psArgv[1], "exreturn") == 0)
        !           518:                        optype = CALL_EXCRETURN;
        !           519:                else if(strcmp(psArgv[1], "subcall") == 0)
        !           520:                        optype = CALL_SUBROUTINE;
        !           521:                else if (strcmp(psArgv[1], "subreturn") == 0)
        !           522:                        optype = CALL_SUBRETURN;
        !           523:                else if (strcmp(psArgv[1], "return") == 0)
        !           524:                        optype = CALL_SUBRETURN | CALL_EXCRETURN;
        !           525:                else
        !           526:                {
        !           527:                        fprintf(stderr, "Unrecognized opcode type given!\n");
        !           528:                        return DEBUGGER_CMDDONE;
        !           529:                }
        !           530:                sprintf(command, "CpuOpcodeType & $%x > 0 :once :quiet\n", optype);
        !           531:        }
        !           532:        else
        !           533:        {
        !           534:                Uint32 optype, nextpc;
        !           535: 
        !           536:                optype = DebugCpu_OpcodeType();
        !           537:                /* can this instruction be stepped normally? */
        !           538:                if (optype != CALL_SUBROUTINE && optype != CALL_EXCEPTION)
        !           539:                {
        !           540:                        nCpuSteps = 1;
        !           541:                        return DEBUGGER_END;
        !           542:                }
        !           543: 
        !           544:                nextpc = Disasm_GetNextPC(M68000_GetPC());
        !           545:                sprintf(command, "pc=$%x :once :quiet\n", nextpc);
        !           546:        }
        !           547:        /* use breakpoint, not steps */
        !           548:        if (BreakCond_Command(command, false))
        !           549:        {
        !           550:                nCpuSteps = 0;
1.1.1.5   root      551:                return DEBUGGER_END;
                    552:        }
                    553:        return DEBUGGER_CMDDONE;
                    554: }
                    555: 
1.1.1.6 ! root      556: /* helper to get instruction type */
        !           557: Uint32 DebugCpu_OpcodeType(void)
        !           558: {
        !           559:        /* cannot use OpcodeFamily like profiler does,
        !           560:         * as that's for previous instructions
        !           561:         */
        !           562:        Uint16 opcode = STMemory_ReadWord(M68000_GetPC());
        !           563: 
        !           564:        if (opcode == 0x4e74 ||                 /* RTD */
        !           565:            opcode == 0x4e75 ||                 /* RTS */
        !           566:            opcode == 0x4e77)                   /* RTR */
        !           567:                return CALL_SUBRETURN;
        !           568: 
        !           569:        if (opcode == 0x4e73)                   /* RTE */
        !           570:                return CALL_EXCRETURN;
        !           571: 
        !           572:        /* NOTE: BSR needs to be matched before BRA/BCC! */
        !           573:        if ((opcode & 0xff00) == 0x6100 ||      /* BSR */
        !           574:            (opcode & 0xffc0) == 0x4e80)        /* JSR */
        !           575:                return CALL_SUBROUTINE;
        !           576: 
        !           577:        /* TODO: ftrapcc, chk2? */
        !           578:        if (opcode == 0x4e72 ||                 /* STOP */
        !           579:            opcode == 0x4afc ||                 /* ILLEGAL */
        !           580:            opcode == 0x4e76 ||                 /* TRAPV */
        !           581:            (opcode & 0xfff0) == 0x4e40 ||      /* TRAP */
        !           582:            (opcode & 0xf1c0) == 0x4180 ||      /* CHK */
        !           583:            (opcode & 0xfff8) == 0x4848)        /* BKPT */
        !           584:                return CALL_EXCEPTION;
        !           585: 
        !           586:        /* TODO: fbcc, fdbcc */
        !           587:        if ((opcode & 0xf000) == 0x6000 ||      /* BRA / BCC */
        !           588:            (opcode & 0xffc0) == 0x4ec0 ||      /* JMP */
        !           589:            (opcode & 0xf080) == 0x50c8)        /* DBCC */
        !           590:                return CALL_BRANCH;
        !           591: 
        !           592:        return CALL_UNKNOWN;
        !           593: }
        !           594: 
        !           595: 
        !           596: /**
        !           597:  * CPU instructions since continuing emulation
        !           598:  */
        !           599: static Uint32 nCpuInstructions;
        !           600: Uint32 DebugCpu_InstrCount(void)
        !           601: {
        !           602:        return nCpuInstructions;
        !           603: }
1.1       root      604: 
                    605: /**
                    606:  * This function is called after each CPU instruction when debugging is enabled.
                    607:  */
                    608: void DebugCpu_Check(void)
                    609: {
1.1.1.6 ! root      610:        nCpuInstructions++;
1.1.1.2   root      611:        if (bCpuProfiling)
                    612:        {
                    613:                Profile_CpuUpdate();
                    614:        }
1.1.1.4   root      615:        if (LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS)))
1.1       root      616:        {
1.1.1.2   root      617:                DebugCpu_ShowAddressInfo(M68000_GetPC());
1.1       root      618:        }
                    619:        if (nCpuActiveCBs)
                    620:        {
                    621:                if (BreakCond_MatchCpu())
1.1.1.5   root      622:                {
1.1.1.3   root      623:                        DebugUI(REASON_CPU_BREAKPOINT);
1.1.1.5   root      624:                        /* make sure we don't decrease step count
                    625:                         * below, before even even getting out of here
                    626:                         */
                    627:                        if (nCpuSteps)
                    628:                                nCpuSteps++;
                    629:                }
1.1       root      630:        }
                    631:        if (nCpuSteps)
                    632:        {
1.1.1.5   root      633:                nCpuSteps--;
1.1       root      634:                if (nCpuSteps == 0)
1.1.1.3   root      635:                        DebugUI(REASON_CPU_STEPS);
                    636:        }
1.1.1.5   root      637:        if (History_TrackCpu())
1.1.1.3   root      638:        {
                    639:                History_AddCpu();
1.1       root      640:        }
1.1.1.5   root      641:        if (ConOutDevice != CONOUT_DEVICE_NONE)
                    642:        {
                    643:                Console_Check();
                    644:        }
1.1       root      645: }
                    646: 
                    647: /**
                    648:  * Should be called before returning back emulation to tell the CPU core
                    649:  * to call us after each instruction if "real-time" debugging like
                    650:  * breakpoints has been set.
                    651:  */
                    652: void DebugCpu_SetDebugging(void)
                    653: {
1.1.1.2   root      654:        bCpuProfiling = Profile_CpuStart();
1.1       root      655:        nCpuActiveCBs = BreakCond_BreakPointCount(false);
1.1.1.2   root      656: 
1.1.1.5   root      657:        if (nCpuActiveCBs || nCpuSteps || bCpuProfiling || History_TrackCpu()
                    658:            || LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS))
                    659:            || ConOutDevice != CONOUT_DEVICE_NONE)
1.1.1.6 ! root      660:        {
1.1       root      661:                M68000_SetSpecial(SPCFLAG_DEBUGGER);
1.1.1.6 ! root      662:                nCpuInstructions = 0;
        !           663:        }       
1.1       root      664:        else
                    665:                M68000_UnsetSpecial(SPCFLAG_DEBUGGER);
                    666: }
                    667: 
                    668: 
                    669: static const dbgcommand_t cpucommands[] =
                    670: {
                    671:        { NULL, NULL, "CPU commands", NULL, NULL, NULL, false },
                    672:        /* NULL as match function will complete file names */
                    673:        { DebugCpu_BreakAddr, Symbols_MatchCpuCodeAddress,
                    674:          "address", "a",
                    675:          "set CPU PC address breakpoints",
                    676:          BreakAddr_Description,
                    677:          true  },
                    678:        { DebugCpu_BreakCond, BreakCond_MatchCpuVariable,
                    679:          "breakpoint", "b",
                    680:          "set/remove/list conditional CPU breakpoints",
                    681:          BreakCond_Description,
                    682:          true },
                    683:        { DebugCpu_DisAsm, Symbols_MatchCpuCodeAddress,
                    684:          "disasm", "d",
                    685:          "disassemble from PC, or given address",
                    686:          "[<start address>[-<end address>]]\n"
                    687:          "\tIf no address is given, this command disassembles from the last\n"
                    688:          "\tposition or from current PC if no last position is available.",
                    689:          false },
1.1.1.2   root      690:        { DebugCpu_Profile, Profile_Match,
                    691:          "profile", "",
                    692:          "profile CPU code",
                    693:          Profile_Description,
                    694:          false },
1.1       root      695:        { DebugCpu_Register, DebugCpu_MatchRegister,
                    696:          "cpureg", "r",
                    697:          "dump register values or set register to value",
                    698:          "[REG=value]\n"
                    699:          "\tSet CPU register to value or dumps all register if no parameter\n"
                    700:          "\thas been specified.",
                    701:          true },
                    702:        { DebugCpu_MemDump, Symbols_MatchCpuDataAddress,
                    703:          "memdump", "m",
                    704:          "dump memory",
                    705:          "[<start address>[-<end address>]]\n"
                    706:          "\tdump memory at address or continue dump from previous address.",
                    707:          false },
                    708:        { DebugCpu_MemWrite, Symbols_MatchCpuAddress,
                    709:          "memwrite", "w",
                    710:          "write bytes to memory",
                    711:          "address byte1 [byte2 ...]\n"
                    712:          "\tWrite bytes to a memory address, bytes are space separated\n"
1.1.1.5   root      713:          "\tvalues in current number base.",
1.1       root      714:          false },
                    715:        { DebugCpu_LoadBin, NULL,
                    716:          "loadbin", "l",
                    717:          "load a file into memory",
                    718:          "filename address\n"
                    719:          "\tLoad the file <filename> into memory starting at <address>.",
                    720:          false },
                    721:        { DebugCpu_SaveBin, NULL,
1.1.1.5   root      722:          "savebin", "",
1.1       root      723:          "save memory to a file",
                    724:          "filename address length\n"
                    725:          "\tSave the memory block at <address> with given <length> to\n"
                    726:          "\tthe file <filename>.",
                    727:          false },
1.1.1.6 ! root      728:        { Symbols_Command, Symbols_MatchCommand,
1.1       root      729:          "symbols", "",
                    730:          "load CPU symbols & their addresses",
                    731:          Symbols_Description,
                    732:          false },
1.1.1.5   root      733:        { DebugCpu_Step, NULL,
                    734:          "step", "s",
                    735:          "single-step CPU",
                    736:          "\n"
                    737:          "\tExecute next CPU instruction (equals 'c 1')",
                    738:          false },
1.1.1.6 ! root      739:        { DebugCpu_Next, DebugCpu_MatchNext,
1.1.1.5   root      740:          "next", "n",
1.1.1.6 ! root      741:          "step CPU through subroutine calls / to given instruction type",
        !           742:          "[instruction type]\n"
        !           743:          "\tSame as 'step' command if there are no subroutine calls.\n"
        !           744:           "\tWhen there are, those calls are treated as one instruction.\n"
        !           745:          "\tIf argument is given, continues until instruction of given\n"
        !           746:          "\ttype is encountered.",
1.1.1.5   root      747:          false },
1.1       root      748:        { DebugCpu_Continue, NULL,
                    749:          "cont", "c",
                    750:          "continue emulation / CPU single-stepping",
                    751:          "[steps]\n"
                    752:          "\tLeave debugger and continue emulation for <steps> CPU instructions\n"
                    753:          "\tor forever if no steps have been specified.",
                    754:          false }
                    755: };
                    756: 
                    757: 
                    758: /**
                    759:  * Should be called when debugger is first entered to initialize
                    760:  * CPU debugging variables.
                    761:  * 
                    762:  * if you want disassembly or memdumping to start/continue from
                    763:  * specific address, you can set them here.  If disassembly
                    764:  * address is zero, disassembling starts from PC.
                    765:  * 
                    766:  * returns number of CPU commands and pointer to array of them.
                    767:  */
                    768: int DebugCpu_Init(const dbgcommand_t **table)
                    769: {
                    770:        memdump_addr = 0;
                    771:        disasm_addr = 0;
                    772:        
                    773:        *table = cpucommands;
                    774:        return ARRAYSIZE(cpucommands);
                    775: }
                    776: 
                    777: /**
                    778:  * Should be called when debugger is re-entered to reset
                    779:  * relevant CPU debugging variables.
                    780:  */
                    781: void DebugCpu_InitSession(void)
                    782: {
                    783:        disasm_addr = M68000_GetPC();
1.1.1.2   root      784:        Profile_CpuStop();
1.1       root      785: }

unix.superglobalmegacorp.com

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