--- hatari/src/debug/debugcpu.c 2019/04/09 08:55:33 1.1.1.7 +++ hatari/src/debug/debugcpu.c 2019/04/09 08:59:17 1.1.1.10 @@ -11,6 +11,7 @@ const char DebugCpu_fileid[] = "Hatari d #include #include +#include #include "config.h" @@ -33,6 +34,7 @@ const char DebugCpu_fileid[] = "Hatari d #include "68kDisass.h" #include "console.h" #include "options.h" +#include "vars.h" #define MEMDUMP_COLS 16 /* memdump, number of bytes per row */ @@ -40,6 +42,8 @@ const char DebugCpu_fileid[] = "Hatari d static Uint32 disasm_addr; /* disasm address */ static Uint32 memdump_addr; /* memdump address */ +static Uint32 fake_regs[8]; /* virtual debugger "registers" */ +static bool bFakeRegsUsed; /* whether to show virtual regs */ static bool bCpuProfiling; /* Whether CPU profiling is activated */ static int nCpuActiveCBs = 0; /* Amount of active conditional breakpoints */ @@ -142,12 +146,18 @@ static int DebugCpu_SaveBin(int nArgc, c /** * Check whether given address matches any CPU symbol and whether * there's profiling information available for it. If yes, show it. + * + * @return true if symbol was shown, false otherwise */ -static void DebugCpu_ShowAddressInfo(Uint32 addr) +static bool DebugCpu_ShowAddressInfo(Uint32 addr, FILE *fp) { - const char *symbol = Symbols_GetByCpuAddress(addr); + const char *symbol = Symbols_GetByCpuAddress(addr, SYMTYPE_ALL); if (symbol) - fprintf(debugOutput, "%s:\n", symbol); + { + fprintf(fp, "%s:\n", symbol); + return true; + } + return false; } /** @@ -156,7 +166,7 @@ static void DebugCpu_ShowAddressInfo(Uin int DebugCpu_DisAsm(int nArgc, char *psArgs[]) { Uint32 disasm_upper = 0; - int insts, max_insts; + int shown, lines = INT_MAX; uaecptr nextpc; if (nArgc > 1) @@ -182,20 +192,17 @@ int DebugCpu_DisAsm(int nArgc, char *psA } /* limit is topmost address or instruction count */ - if (disasm_upper) - { - max_insts = INT_MAX; - } - else + if (!disasm_upper) { disasm_upper = 0xFFFFFFFF; - max_insts = ConfigureParams.Debugger.nDisasmLines; + lines = DebugUI_GetPageLines(ConfigureParams.Debugger.nDisasmLines, 8); } /* output a range */ - for (insts = 0; insts < max_insts && disasm_addr < disasm_upper; insts++) + for (shown = 0; shown < lines && disasm_addr < disasm_upper; shown++) { - DebugCpu_ShowAddressInfo(disasm_addr); + if (DebugCpu_ShowAddressInfo(disasm_addr, debugOutput)) + shown++; Disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1); disasm_addr = nextpc; } @@ -212,35 +219,90 @@ int DebugCpu_DisAsm(int nArgc, char *psA */ static char *DebugCpu_MatchRegister(const char *text, int state) { - static const char* regs[] = { + static const char* regs_000[] = { "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", - "pc", "sr" + "isp", "usp", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7" }; - return DebugUI_MatchHelper(regs, ARRAYSIZE(regs), text, state); + static const char* regs_020[] = { + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "caar", "cacr", + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "dfc", "isp", "msp", "pc", "sfc", "sr", "usp", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "vbr" + }; + if (ConfigureParams.System.nCpuLevel < 2) + return DebugUI_MatchHelper(regs_000, ARRAY_SIZE(regs_000), text, state); + else + return DebugUI_MatchHelper(regs_020, ARRAY_SIZE(regs_020), text, state); } /** * Set address of the named 32-bit register to given argument. - * Return register size in bits or zero for uknown register name. - * Handles D0-7 data and A0-7 address registers, but not PC & SR - * registers as they need to be accessed using UAE accessors. + * Handles V0-7 fake registers, D0-7 data, A0-7 address and several + * special registers except for PC & SR registers because they need + * to be accessed using UAE accessors. + * + * Return register size in bits or zero for unknown register name. */ int DebugCpu_GetRegisterAddress(const char *reg, Uint32 **addr) { - char r0, r1; - if (!reg[0] || !reg[1] || reg[2]) + char r0; + int r1; + + if (!reg[0] || !reg[1]) return 0; - + + /* 3-4 letter reg? */ + if (reg[2]) + { + if (strcasecmp(reg, "ISP") == 0) + { + *addr = ®s.isp; + return 32; + } + if (strcasecmp(reg, "USP") == 0) + { + *addr = ®s.usp; + return 32; + } + if (ConfigureParams.System.nCpuLevel >= 2) + { + static const struct { + const char name[5]; + Uint32 *addr; + } reg_020[] = { + { "CAAR", ®s.caar }, + { "CACR", ®s.cacr }, + { "DFC", ®s.dfc }, + { "MSP", ®s.msp }, + { "SFC", ®s.sfc }, + { "VBR", ®s.vbr } + }; + for (int i = 0; i < ARRAY_SIZE(reg_020); i++) + { + if (strcasecmp(reg, reg_020[i].name) == 0) + { + *addr = reg_020[i].addr; + return 32; + } + } + } + return 0; + } + + /* 2-letter reg */ r0 = toupper((unsigned char)reg[0]); - r1 = toupper((unsigned char)reg[1]); + r1 = toupper((unsigned char)reg[1]) - '0'; if (r0 == 'D') /* Data regs? */ { - if (r1 >= '0' && r1 <= '7') + if (r1 >= 0 && r1 <= 7) { - *addr = &(Regs[REG_D0 + r1 - '0']); + *addr = &(regs.regs[REG_D0 + r1]); return 32; } fprintf(stderr,"\tBad data register, valid values are 0-7\n"); @@ -248,14 +310,25 @@ int DebugCpu_GetRegisterAddress(const ch } if(r0 == 'A') /* Address regs? */ { - if (r1 >= '0' && r1 <= '7') + if (r1 >= 0 && r1 <= 7) { - *addr = &(Regs[REG_A0 + r1 - '0']); + *addr = &(regs.regs[REG_A0 + r1]); return 32; } fprintf(stderr,"\tBad address register, valid values are 0-7\n"); return 0; } + if(r0 == 'V') /* Virtual regs? */ + { + if (r1 >= 0 && r1 < ARRAY_SIZE(fake_regs)) + { + *addr = &fake_regs[r1]; + bFakeRegsUsed = true; + return 32; + } + fprintf(stderr,"\tBad virtual register, valid values are 0-7\n"); + return 0; + } return 0; } @@ -265,21 +338,35 @@ int DebugCpu_GetRegisterAddress(const ch */ int DebugCpu_Register(int nArgc, char *psArgs[]) { - char reg[3], *assign; + char *arg, *assign; Uint32 value; - char *arg; /* If no parameter has been given, simply dump all registers */ if (nArgc == 1) { uaecptr nextpc; + int idx; + /* use the UAE function instead */ #ifdef WINUAE_FOR_HATARI - m68k_dumpstate_file(debugOutput, &nextpc); + m68k_dumpstate_file(debugOutput, &nextpc, 0xffffffff); #else m68k_dumpstate(debugOutput, &nextpc); #endif fflush(debugOutput); + if (!bFakeRegsUsed) + return DEBUGGER_CMDDONE; + + fputs("Virtual registers:\n", debugOutput); + for (idx = 0; idx < ARRAY_SIZE(fake_regs); idx++) + { + if (idx && idx % 4 == 0) + fputs("\n", debugOutput); + fprintf(debugOutput, " V%c %08x", + '0' + idx, fake_regs[idx]); + } + fputs("\n", debugOutput); + fflush(debugOutput); return DEBUGGER_CMDDONE; } @@ -298,20 +385,17 @@ int DebugCpu_Register(int nArgc, char *p } arg = Str_Trim(arg); - if (strlen(arg) != 2) + if (strlen(arg) < 2) { goto error_msg; } - 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. */ - if (reg[0] == 'S' && reg[1] == 'R') + if (strcasecmp("SR", arg) == 0) { M68000_SetSR(value); } - else if (reg[0] == 'P' && reg[1] == 'C') /* set PC? */ + else if (strcasecmp("PC", arg) == 0) /* set PC */ { M68000_SetPC(value); } @@ -319,7 +403,7 @@ int DebugCpu_Register(int nArgc, char *p { Uint32 *regaddr; /* check&set data and address registers */ - if (DebugCpu_GetRegisterAddress(reg, ®addr)) + if (DebugCpu_GetRegisterAddress(arg, ®addr)) { *regaddr = value; } @@ -331,7 +415,10 @@ int DebugCpu_Register(int nArgc, char *p return DEBUGGER_CMDDONE; error_msg: - fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR.\n"); + fprintf(stderr,"\tError, usage: r or r xx=yyyy\n" + "\tWhere: xx=A0-A7, D0-D7, PC, SR, ISP, USP\n" + "\t020+: CAAR, CACR, DFC, SFC, MSP, VBR\n" + "\tor V0-V7 (virtual).\n"); return DEBUGGER_CMDDONE; } @@ -368,13 +455,44 @@ static int DebugCpu_Profile(int nArgc, c */ int DebugCpu_MemDump(int nArgc, char *psArgs[]) { - int i; - char c; - Uint32 memdump_upper = 0; - + char c, mode; + int i, arg, size; + Uint32 value, memdump_upper = 0; + + arg = 1; + mode = 0; + size = 1; if (nArgc > 1) + mode = tolower(psArgs[arg][0]); + + if (!mode || isdigit(psArgs[arg][0]) || psArgs[arg][1]) + { + /* no args, single digit or multiple chars -> default mode */ + mode = 'b'; + } + else if (mode == 'b') + { + arg += 1; + } + else if (mode == 'w') + { + arg += 1; + size = 2; + } + else if (mode == 'l') + { + arg += 1; + size = 4; + } + else + { + fprintf(stderr, "Invalid width mode (not b|w|l)!\n"); + return DEBUGGER_CMDDONE; + } + + if (nArgc > arg) { - switch (Eval_Range(psArgs[1], &memdump_addr, &memdump_upper, false)) + switch (Eval_Range(psArgs[arg], &memdump_addr, &memdump_upper, false)) { case -1: /* invalid value(s) */ @@ -386,19 +504,52 @@ int DebugCpu_MemDump(int nArgc, char *ps /* range */ break; } - } /* continue */ + arg++; + + if (nArgc > arg) + { + int count = atoi(psArgs[arg]); + if (!count) + { + fprintf(stderr, "Invalid count %d!\n", count); + return DEBUGGER_CMDDONE; + } + memdump_upper = memdump_addr + count * size; + } + } if (!memdump_upper) { - memdump_upper = memdump_addr + MEMDUMP_COLS * ConfigureParams.Debugger.nMemdumpLines; + int lines = DebugUI_GetPageLines(ConfigureParams.Debugger.nMemdumpLines, 8); + memdump_upper = memdump_addr + MEMDUMP_COLS * lines; } while (memdump_addr < memdump_upper) { - fprintf(debugOutput, "%8.8X: ", memdump_addr); /* print address */ - for (i = 0; i < MEMDUMP_COLS; i++) /* print hex data */ - fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++)); - fprintf(debugOutput, " "); /* print ASCII data */ + fprintf(debugOutput, "%08X: ", memdump_addr); + + /* print HEX data */ + for (i = 0; i < MEMDUMP_COLS/size; i++) + { + switch (mode) + { + case 'l': + value = STMemory_ReadLong(memdump_addr); + break; + case 'w': + value = STMemory_ReadWord(memdump_addr); + break; + case 'b': + default: + value = STMemory_ReadByte(memdump_addr); + break; + } + fprintf(debugOutput, "%0*x ", 2*size, value); + memdump_addr += size; + } + + /* print ASCII data */ + fprintf(debugOutput, " "); for (i = 0; i < MEMDUMP_COLS; i++) { c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i); @@ -406,8 +557,8 @@ int DebugCpu_MemDump(int nArgc, char *ps c = NON_PRINT_CHAR; /* non-printable as dots */ fprintf(debugOutput,"%c", c); } - fprintf(debugOutput, "\n"); /* newline */ - } /* while */ + fprintf(debugOutput, "\n"); + } fflush(debugOutput); return DEBUGGER_CMDCONT; @@ -415,45 +566,122 @@ int DebugCpu_MemDump(int nArgc, char *ps /** - * Command: Write to memory, arg = starting address, followed by bytes. + * Command: Write to memory, optional arg for value lenghts, + * followed by starting address and the values. */ static int DebugCpu_MemWrite(int nArgc, char *psArgs[]) { - int i, numBytes; + int i, arg, values, max_values; Uint32 write_addr, d; - unsigned char bytes[256]; /* store bytes */ + union { + Uint8 bytes[256]; + Uint16 words[128]; + Uint32 longs[64]; + } store; + char mode; if (nArgc < 3) { return DebugUI_PrintCmdHelp(psArgs[0]); } + arg = 1; + mode = tolower(psArgs[arg][0]); + max_values = ARRAY_SIZE(store.bytes); + + if (!mode || isdigit(psArgs[arg][0]) || psArgs[arg][1]) + { + /* no args, single digit or multiple chars -> default mode */ + mode = 'b'; + } + else if (mode == 'b') + { + arg += 1; + } + else if (mode == 'w') + { + max_values = ARRAY_SIZE(store.words); + arg += 1; + } + else if (mode == 'l') + { + max_values = ARRAY_SIZE(store.longs); + arg += 1; + } + else + { + fprintf(stderr, "Invalid width mode (not b|w|l)!\n"); + return DEBUGGER_CMDDONE; + } /* Read address */ - if (!Eval_Number(psArgs[1], &write_addr)) + if (!Eval_Number(psArgs[arg++], &write_addr)) { fprintf(stderr, "Bad address!\n"); return DEBUGGER_CMDDONE; } - numBytes = 0; + if (nArgc - arg > max_values) + { + fprintf(stderr, "Too many values (%d) given for mode '%c' (max %d)!\n", + nArgc - arg, mode, max_values); + return DEBUGGER_CMDDONE; + } - /* get bytes data */ - for (i = 2; i < nArgc; i++) + /* get the data */ + values = 0; + for (i = arg; i < nArgc; i++) { - if (!Eval_Number(psArgs[i], &d) || d > 255) + if (!Eval_Number(psArgs[i], &d)) { - fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]); + fprintf(stderr, "Bad value '%s'!\n", psArgs[i]); return DEBUGGER_CMDDONE; } - - bytes[numBytes] = d & 0x0FF; - numBytes++; + switch(mode) + { + case 'b': + if (d > 0xff) + { + fprintf(stderr, "Illegal byte argument: 0x%x!\n", d); + return DEBUGGER_CMDDONE; + } + store.bytes[values] = (Uint8)d; + break; + case 'w': + if (d > 0xffff) + { + fprintf(stderr, "Illegal word argument: 0x%x!\n", d); + return DEBUGGER_CMDDONE; + } + store.words[values] = (Uint16)d; + break; + case 'l': + store.longs[values] = d; + break; + } + values++; } /* write the data */ - for (i = 0; i < numBytes; i++) - STMemory_WriteByte(write_addr + i, bytes[i]); - + for (i = 0; i < values; i++) + { + switch(mode) + { + case 'b': + STMemory_WriteByte(write_addr + i, store.bytes[i]); + break; + case 'w': + STMemory_WriteWord(write_addr + i*2, store.words[i]); + break; + case 'l': + STMemory_WriteLong(write_addr + i*4, store.longs[i]); + break; + } + } + if (values > 1) + { + fprintf(stderr, "Wrote %d '%c' values starting from 0x%x.\n", + values, mode, write_addr); + } return DEBUGGER_CMDDONE; } @@ -500,7 +728,7 @@ static char *DebugCpu_MatchNext(const ch static const char* ntypes[] = { "branch", "exception", "exreturn", "return", "subcall", "subreturn" }; - return DebugUI_MatchHelper(ntypes, ARRAYSIZE(ntypes), text, state); + return DebugUI_MatchHelper(ntypes, ARRAY_SIZE(ntypes), text, state); } /** @@ -537,15 +765,25 @@ static int DebugCpu_Next(int nArgc, char Uint32 optype, nextpc; optype = DebugCpu_OpcodeType(); - /* can this instruction be stepped normally? */ - if (optype != CALL_SUBROUTINE && optype != CALL_EXCEPTION) + /* should this instruction be stepped normally, or is it + * - subroutine call + * - exception + * - loop branch backwards + */ + if (optype == CALL_SUBROUTINE || + optype == CALL_EXCEPTION || + (optype == CALL_BRANCH && + (STMemory_ReadWord(M68000_GetPC()) & 0xf0f8) == 0x50c8 && + (Sint16)STMemory_ReadWord(M68000_GetPC()+SIZE_WORD) < 0)) + { + nextpc = Disasm_GetNextPC(M68000_GetPC()); + sprintf(command, "pc=$%x :once :quiet\n", nextpc); + } + else { 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)) @@ -617,7 +855,16 @@ void DebugCpu_Check(void) } if (LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS))) { - DebugCpu_ShowAddressInfo(M68000_GetPC()); + DebugCpu_ShowAddressInfo(M68000_GetPC(), TraceFile); + } + if (LOG_TRACE_LEVEL(TRACE_CPU_REGS)) + { + uaecptr nextpc; +#ifdef WINUAE_FOR_HATARI + m68k_dumpstate_file(TraceFile, &nextpc, 0xffffffff); +#else + m68k_dumpstate(TraceFile, &nextpc); +#endif } if (nCpuActiveCBs) { @@ -658,14 +905,14 @@ void DebugCpu_SetDebugging(void) nCpuActiveCBs = BreakCond_CpuBreakPointCount(); if (nCpuActiveCBs || nCpuSteps || bCpuProfiling || History_TrackCpu() - || LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS)) + || LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS|TRACE_CPU_REGS)) || ConOutDevice != CONOUT_DEVICE_NONE) { - M68000_SetSpecial(SPCFLAG_DEBUGGER); + M68000_SetDebugger(true); nCpuInstructions = 0; } else - M68000_UnsetSpecial(SPCFLAG_DEBUGGER); + M68000_SetDebugger(false); } @@ -678,7 +925,7 @@ static const dbgcommand_t cpucommands[] "set CPU PC address breakpoints", BreakAddr_Description, true }, - { DebugCpu_BreakCond, BreakCond_MatchCpuVariable, + { DebugCpu_BreakCond, Vars_MatchCpuVariable, "breakpoint", "b", "set/remove/list conditional CPU breakpoints", BreakCond_Description, @@ -705,15 +952,19 @@ static const dbgcommand_t cpucommands[] { DebugCpu_MemDump, Symbols_MatchCpuDataAddress, "memdump", "m", "dump memory", - "[[-]]\n" - "\tdump memory at address or continue dump from previous address.", + "[b|w|l] [[-| ]]\n" + "\tdump memory at address or continue dump from previous address.\n" + "\tBy default memory output is done as bytes, with 'w' or 'l'\n" + "\toption, it will be done as words/longs instead. Output amount\n" + "\tcan be given either as a count or an address range.", false }, { DebugCpu_MemWrite, Symbols_MatchCpuAddress, "memwrite", "w", - "write bytes to memory", - "address byte1 [byte2 ...]\n" - "\tWrite bytes to a memory address, bytes are space separated\n" - "\tvalues in current number base.", + "write bytes/words/longs to memory", + "[b|w|l] address value1 [value2 ...]\n" + "\tWrite space separate values (in current number base) to given\n" + "\tmemory address. By default writes are done as bytes, with\n" + "\t'w' or 'l' option they will be done as words/longs instead", false }, { DebugCpu_LoadBin, NULL, "loadbin", "l", @@ -774,7 +1025,7 @@ int DebugCpu_Init(const dbgcommand_t **t disasm_addr = 0; *table = cpucommands; - return ARRAYSIZE(cpucommands); + return ARRAY_SIZE(cpucommands); } /**