--- hatari/src/debug/debugcpu.c 2019/04/09 08:53:03 1.1.1.5 +++ hatari/src/debug/debugcpu.c 2019/04/09 08:54:20 1.1.1.6 @@ -10,6 +10,7 @@ const char DebugCpu_fileid[] = "Hatari debugcpu.c : " __DATE__ " " __TIME__; #include +#include #include "config.h" @@ -57,8 +58,7 @@ static int DebugCpu_LoadBin(int nArgc, c if (nArgc < 3) { - DebugUI_PrintCmdHelp(psArgs[0]); - return DEBUGGER_CMDDONE; + return DebugUI_PrintCmdHelp(psArgs[0]); } if (!Eval_Number(psArgs[2], &address)) @@ -100,8 +100,7 @@ static int DebugCpu_SaveBin(int nArgc, c if (nArgc < 4) { - DebugUI_PrintCmdHelp(psArgs[0]); - return DEBUGGER_CMDDONE; + return DebugUI_PrintCmdHelp(psArgs[0]); } if (!Eval_Number(psArgs[2], &address)) @@ -211,27 +210,12 @@ int DebugCpu_DisAsm(int nArgc, char *psA */ static char *DebugCpu_MatchRegister(const char *text, int state) { - static const char regs[][3] = { + static const char* regs[] = { "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "pc", "sr" }; - static int i, len; - - if (!state) - { - /* first match */ - i = 0; - len = strlen(text); - if (len > 2) - return NULL; - } - /* next match */ - while (i < ARRAYSIZE(regs)) { - if (strncasecmp(regs[i++], text, len) == 0) - return (strdup(regs[i-1])); - } - return NULL; + return DebugUI_MatchHelper(regs, ARRAYSIZE(regs), text, state); } @@ -247,8 +231,8 @@ int DebugCpu_GetRegisterAddress(const ch if (!reg[0] || !reg[1] || reg[2]) return 0; - r0 = toupper(reg[0]); - r1 = toupper(reg[1]); + r0 = toupper((unsigned char)reg[0]); + r1 = toupper((unsigned char)reg[1]); if (r0 == 'D') /* Data regs? */ { @@ -312,8 +296,8 @@ int DebugCpu_Register(int nArgc, char *p { goto error_msg; } - reg[0] = toupper(arg[0]); - reg[1] = toupper(arg[1]); + reg[0] = toupper((unsigned char)arg[0]); + reg[1] = toupper((unsigned char)arg[1]); reg[2] = '\0'; /* set SR and update conditional flags for the UAE CPU core. */ @@ -437,8 +421,7 @@ static int DebugCpu_MemWrite(int nArgc, if (nArgc < 3) { - DebugUI_PrintCmdHelp(psArgs[0]); - return DEBUGGER_CMDDONE; + return DebugUI_PrintCmdHelp(psArgs[0]); } /* Read address */ @@ -503,28 +486,128 @@ static int DebugCpu_Step(int nArgc, char return DEBUGGER_END; } + +/** + * Readline match callback to list next command opcode types. + * STATE = 0 -> different text from previous one. + * Return next match or NULL if no matches. + */ +static char *DebugCpu_MatchNext(const char *text, int state) +{ + static const char* ntypes[] = { + "branch", "exception", "exreturn", "return", "subcall", "subreturn" + }; + return DebugUI_MatchHelper(ntypes, ARRAYSIZE(ntypes), text, state); +} + /** * Command: Step CPU, but proceed through subroutines * Does this by temporary conditional breakpoint */ static int DebugCpu_Next(int nArgc, char *psArgv[]) { - char command[32]; - Uint32 nextpc = Disasm_GetNextPC(M68000_GetPC()); - sprintf(command, "pc=$%x :once :quiet\n", nextpc); - if (BreakCond_Command(command, false)) { - nCpuSteps = 0; /* using breakpoint, not steps */ + char command[40]; + if (nArgc > 1) + { + int optype; + if(strcmp(psArgv[1], "branch") == 0) + optype = CALL_BRANCH; + else if(strcmp(psArgv[1], "exception") == 0) + optype = CALL_EXCEPTION; + else if(strcmp(psArgv[1], "exreturn") == 0) + optype = CALL_EXCRETURN; + else if(strcmp(psArgv[1], "subcall") == 0) + optype = CALL_SUBROUTINE; + else if (strcmp(psArgv[1], "subreturn") == 0) + optype = CALL_SUBRETURN; + else if (strcmp(psArgv[1], "return") == 0) + optype = CALL_SUBRETURN | CALL_EXCRETURN; + else + { + fprintf(stderr, "Unrecognized opcode type given!\n"); + return DEBUGGER_CMDDONE; + } + sprintf(command, "CpuOpcodeType & $%x > 0 :once :quiet\n", optype); + } + else + { + Uint32 optype, nextpc; + + optype = DebugCpu_OpcodeType(); + /* can this instruction be stepped normally? */ + if (optype != CALL_SUBROUTINE && optype != CALL_EXCEPTION) + { + nCpuSteps = 1; + return DEBUGGER_END; + } + + nextpc = Disasm_GetNextPC(M68000_GetPC()); + sprintf(command, "pc=$%x :once :quiet\n", nextpc); + } + /* use breakpoint, not steps */ + if (BreakCond_Command(command, false)) + { + nCpuSteps = 0; return DEBUGGER_END; } return DEBUGGER_CMDDONE; } +/* helper to get instruction type */ +Uint32 DebugCpu_OpcodeType(void) +{ + /* cannot use OpcodeFamily like profiler does, + * as that's for previous instructions + */ + Uint16 opcode = STMemory_ReadWord(M68000_GetPC()); + + if (opcode == 0x4e74 || /* RTD */ + opcode == 0x4e75 || /* RTS */ + opcode == 0x4e77) /* RTR */ + return CALL_SUBRETURN; + + if (opcode == 0x4e73) /* RTE */ + return CALL_EXCRETURN; + + /* NOTE: BSR needs to be matched before BRA/BCC! */ + if ((opcode & 0xff00) == 0x6100 || /* BSR */ + (opcode & 0xffc0) == 0x4e80) /* JSR */ + return CALL_SUBROUTINE; + + /* TODO: ftrapcc, chk2? */ + if (opcode == 0x4e72 || /* STOP */ + opcode == 0x4afc || /* ILLEGAL */ + opcode == 0x4e76 || /* TRAPV */ + (opcode & 0xfff0) == 0x4e40 || /* TRAP */ + (opcode & 0xf1c0) == 0x4180 || /* CHK */ + (opcode & 0xfff8) == 0x4848) /* BKPT */ + return CALL_EXCEPTION; + + /* TODO: fbcc, fdbcc */ + if ((opcode & 0xf000) == 0x6000 || /* BRA / BCC */ + (opcode & 0xffc0) == 0x4ec0 || /* JMP */ + (opcode & 0xf080) == 0x50c8) /* DBCC */ + return CALL_BRANCH; + + return CALL_UNKNOWN; +} + + +/** + * CPU instructions since continuing emulation + */ +static Uint32 nCpuInstructions; +Uint32 DebugCpu_InstrCount(void) +{ + return nCpuInstructions; +} /** * This function is called after each CPU instruction when debugging is enabled. */ void DebugCpu_Check(void) { + nCpuInstructions++; if (bCpuProfiling) { Profile_CpuUpdate(); @@ -574,7 +657,10 @@ void DebugCpu_SetDebugging(void) if (nCpuActiveCBs || nCpuSteps || bCpuProfiling || History_TrackCpu() || LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS)) || ConOutDevice != CONOUT_DEVICE_NONE) + { M68000_SetSpecial(SPCFLAG_DEBUGGER); + nCpuInstructions = 0; + } else M68000_UnsetSpecial(SPCFLAG_DEBUGGER); } @@ -639,7 +725,7 @@ static const dbgcommand_t cpucommands[] "\tSave the memory block at
with given to\n" "\tthe file .", false }, - { Symbols_Command, NULL, + { Symbols_Command, Symbols_MatchCommand, "symbols", "", "load CPU symbols & their addresses", Symbols_Description, @@ -650,12 +736,14 @@ static const dbgcommand_t cpucommands[] "\n" "\tExecute next CPU instruction (equals 'c 1')", false }, - { DebugCpu_Next, NULL, + { DebugCpu_Next, DebugCpu_MatchNext, "next", "n", - "step CPU, proceeding through subroutine calls", - "\n" - "\tLike the 'step' command as long as subroutine calls do not\n" - "\thappen. When they do, the call is treated as one instruction.", + "step CPU through subroutine calls / to given instruction type", + "[instruction type]\n" + "\tSame as 'step' command if there are no subroutine calls.\n" + "\tWhen there are, those calls are treated as one instruction.\n" + "\tIf argument is given, continues until instruction of given\n" + "\ttype is encountered.", false }, { DebugCpu_Continue, NULL, "cont", "c",