|
|
1.1 ! root 1: /* ! 2: Hatari - vars.c ! 3: ! 4: Copyright (c) 2016 by Eero Tamminen ! 5: ! 6: This file is distributed under the GNU General Public License, version 2 ! 7: or at your option any later version. Read the file gpl.txt for details. ! 8: ! 9: vars.c - Hatari internal variable value and OS call number accessors ! 10: for conditional breakpoint and evaluate commands. ! 11: */ ! 12: const char Vars_fileid[] = "Hatari vars.c : " __DATE__ " " __TIME__; ! 13: ! 14: #include <stdio.h> ! 15: #include <stdlib.h> ! 16: #include "main.h" ! 17: #include "configuration.h" ! 18: #include "stMemory.h" ! 19: #include "m68000.h" ! 20: #include "screen.h" /* for defines needed by video.h */ ! 21: #include "video.h" /* for Hatari video variable addresses */ ! 22: ! 23: #include "debugInfo.h" ! 24: #include "debugcpu.h" ! 25: #include "debugdsp.h" ! 26: #include "debugui.h" ! 27: #include "symbols.h" ! 28: #include "68kDisass.h" ! 29: #include "vars.h" ! 30: ! 31: ! 32: /* Accessor functions for calculated Hatari values */ ! 33: static Uint32 GetLineCycles(void) ! 34: { ! 35: int dummy1, dummy2, lcycles; ! 36: Video_GetPosition(&dummy1, &dummy2 , &lcycles); ! 37: return lcycles; ! 38: } ! 39: static Uint32 GetFrameCycles(void) ! 40: { ! 41: int dummy1, dummy2, fcycles; ! 42: Video_GetPosition(&fcycles, &dummy1, &dummy2); ! 43: return fcycles; ! 44: } ! 45: ! 46: /* helpers for TOS OS call opcode accessor functions */ ! 47: #define INVALID_OPCODE 0xFFFFu ! 48: ! 49: static inline Uint16 getLineOpcode(Uint8 line) ! 50: { ! 51: Uint32 pc; ! 52: Uint16 instr; ! 53: pc = M68000_GetPC(); ! 54: instr = STMemory_ReadWord(pc); ! 55: /* for opcode X, Line-A = 0xA00X, Line-F = 0xF00X */ ! 56: if ((instr >> 12) == line) { ! 57: return instr & 0xFF; ! 58: } ! 59: return INVALID_OPCODE; ! 60: } ! 61: static inline bool isTrap(Uint8 trap) ! 62: { ! 63: Uint32 pc; ! 64: Uint16 instr; ! 65: pc = M68000_GetPC(); ! 66: instr = STMemory_ReadWord(pc); ! 67: return (instr == (Uint16)0x4e40u + trap); ! 68: } ! 69: static inline Uint16 getControlOpcode(void) ! 70: { ! 71: /* Control[] address from D1, opcode in Control[0] */ ! 72: return STMemory_ReadWord(STMemory_ReadLong(Regs[REG_D1])); ! 73: } ! 74: static inline Uint16 getStackOpcode(void) ! 75: { ! 76: return STMemory_ReadWord(Regs[REG_A7]); ! 77: } ! 78: ! 79: /* Actual TOS OS call opcode accessor functions */ ! 80: static Uint32 GetLineAOpcode(void) ! 81: { ! 82: return getLineOpcode(0xA); ! 83: } ! 84: static Uint32 GetLineFOpcode(void) ! 85: { ! 86: return getLineOpcode(0xF); ! 87: } ! 88: static Uint32 GetGemdosOpcode(void) ! 89: { ! 90: if (isTrap(1)) { ! 91: return getStackOpcode(); ! 92: } ! 93: return INVALID_OPCODE; ! 94: } ! 95: static Uint32 GetBiosOpcode(void) ! 96: { ! 97: if (isTrap(13)) { ! 98: return getStackOpcode(); ! 99: } ! 100: return INVALID_OPCODE; ! 101: } ! 102: static Uint32 GetXbiosOpcode(void) ! 103: { ! 104: if (isTrap(14)) { ! 105: return getStackOpcode(); ! 106: } ! 107: return INVALID_OPCODE; ! 108: } ! 109: static Uint32 GetAesOpcode(void) ! 110: { ! 111: if (isTrap(2)) { ! 112: Uint16 d0 = Regs[REG_D0]; ! 113: if (d0 == 0xC8) { ! 114: return getControlOpcode(); ! 115: } else if (d0 == 0xC9) { ! 116: /* same as appl_yield() */ ! 117: return 0x11; ! 118: } ! 119: } ! 120: return INVALID_OPCODE; ! 121: } ! 122: static Uint32 GetVdiOpcode(void) ! 123: { ! 124: if (isTrap(2)) { ! 125: Uint16 d0 = Regs[REG_D0]; ! 126: if (d0 == 0x73) { ! 127: return getControlOpcode(); ! 128: } else if (d0 == 0xFFFE) { ! 129: /* -2 = vq_[v]gdos() */ ! 130: return 0xFFFE; ! 131: } ! 132: } ! 133: return INVALID_OPCODE; ! 134: } ! 135: ! 136: static Uint32 GetNextPC(void) ! 137: { ! 138: return Disasm_GetNextPC(M68000_GetPC()); ! 139: } ! 140: ! 141: /* sorted by variable name so that this can be bisected */ ! 142: static const var_addr_t hatari_vars[] = { ! 143: { "AesOpcode", (Uint32*)GetAesOpcode, VALUE_TYPE_FUNCTION32, 16, "$FFFF when not on AES trap" }, ! 144: { "Basepage", (Uint32*)DebugInfo_GetBASEPAGE, VALUE_TYPE_FUNCTION32, 0, "invalid before Desktop is up" }, ! 145: { "BiosOpcode", (Uint32*)GetBiosOpcode, VALUE_TYPE_FUNCTION32, 16, "$FFFF when not on BIOS trap" }, ! 146: { "BSS", (Uint32*)DebugInfo_GetBSS, VALUE_TYPE_FUNCTION32, 0, "invalid before Desktop is up" }, ! 147: { "CpuInstr", (Uint32*)DebugCpu_InstrCount, VALUE_TYPE_FUNCTION32, 0, "CPU instructions count" }, ! 148: { "CpuOpcodeType", (Uint32*)DebugCpu_OpcodeType, VALUE_TYPE_FUNCTION32, 0, "internal CPU instruction type" }, ! 149: { "DATA", (Uint32*)DebugInfo_GetDATA, VALUE_TYPE_FUNCTION32, 0, "invalid before Desktop is up" }, ! 150: #if ENABLE_DSP_EMU ! 151: { "DspInstr", (Uint32*)DebugDsp_InstrCount, VALUE_TYPE_FUNCTION32, 0, "DSP instructions count" }, ! 152: { "DspOpcodeType", (Uint32*)DebugDsp_OpcodeType, VALUE_TYPE_FUNCTION32, 0, "internal DSP instruction type" }, ! 153: #endif ! 154: { "FrameCycles", (Uint32*)GetFrameCycles, VALUE_TYPE_FUNCTION32, 0, NULL }, ! 155: { "GemdosOpcode", (Uint32*)GetGemdosOpcode, VALUE_TYPE_FUNCTION32, 16, "$FFFF when not on GEMDOS trap" }, ! 156: { "HBL", (Uint32*)&nHBL, VALUE_TYPE_VAR32, sizeof(nHBL)*8, NULL }, ! 157: { "LineAOpcode", (Uint32*)GetLineAOpcode, VALUE_TYPE_FUNCTION32, 16, "$FFFF when not on Line-A opcode" }, ! 158: { "LineCycles", (Uint32*)GetLineCycles, VALUE_TYPE_FUNCTION32, 0, "is always divisable by 4" }, ! 159: { "LineFOpcode", (Uint32*)GetLineFOpcode, VALUE_TYPE_FUNCTION32, 16, "$FFFF when not on Line-F opcode" }, ! 160: { "NextPC", (Uint32*)GetNextPC, VALUE_TYPE_FUNCTION32, 0, NULL }, ! 161: { "TEXT", (Uint32*)DebugInfo_GetTEXT, VALUE_TYPE_FUNCTION32, 0, "invalid before Desktop is up" }, ! 162: { "TEXTEnd", (Uint32*)DebugInfo_GetTEXTEnd, VALUE_TYPE_FUNCTION32, 0, "invalid before Desktop is up" }, ! 163: { "VBL", (Uint32*)&nVBLs, VALUE_TYPE_VAR32, sizeof(nVBLs)*8, NULL }, ! 164: { "VdiOpcode", (Uint32*)GetVdiOpcode, VALUE_TYPE_FUNCTION32, 16, "$FFFF when not on VDI trap" }, ! 165: { "XbiosOpcode", (Uint32*)GetXbiosOpcode, VALUE_TYPE_FUNCTION32, 16, "$FFFF when not on XBIOS trap" } ! 166: }; ! 167: ! 168: ! 169: /** ! 170: * Readline match callback for Hatari variable and CPU variable/symbol name completion. ! 171: * STATE = 0 -> different text from previous one. ! 172: * Return next match or NULL if no matches. ! 173: */ ! 174: char *Vars_MatchCpuVariable(const char *text, int state) ! 175: { ! 176: static int i, len; ! 177: const char *name; ! 178: ! 179: if (!state) { ! 180: /* first match */ ! 181: len = strlen(text); ! 182: i = 0; ! 183: } ! 184: /* next match */ ! 185: while (i < ARRAY_SIZE(hatari_vars)) { ! 186: name = hatari_vars[i++].name; ! 187: if (strncasecmp(name, text, len) == 0) ! 188: return (strdup(name)); ! 189: } ! 190: /* no variable match, check all CPU symbols */ ! 191: return Symbols_MatchCpuAddress(text, state); ! 192: } ! 193: ! 194: ! 195: /** ! 196: * If given string matches Hatari variable name, return its struct pointer, ! 197: * otherwise return NULL. ! 198: */ ! 199: const var_addr_t *Vars_ParseVariable(const char *name) ! 200: { ! 201: const var_addr_t *hvar; ! 202: /* left, right, middle, direction */ ! 203: int l, r, m, dir; ! 204: ! 205: /* bisect */ ! 206: l = 0; ! 207: r = ARRAY_SIZE(hatari_vars) - 1; ! 208: do { ! 209: m = (l+r) >> 1; ! 210: hvar = hatari_vars + m; ! 211: dir = strcasecmp(name, hvar->name); ! 212: if (dir == 0) { ! 213: return hvar; ! 214: } ! 215: if (dir < 0) { ! 216: r = m-1; ! 217: } else { ! 218: l = m+1; ! 219: } ! 220: } while (l <= r); ! 221: return NULL; ! 222: } ! 223: ! 224: ! 225: /** ! 226: * Return Uint32 value from given Hatari variable struct* ! 227: */ ! 228: Uint32 Vars_GetValue(const var_addr_t *hvar) ! 229: { ! 230: switch (hvar->vtype) { ! 231: case VALUE_TYPE_FUNCTION32: ! 232: return ((Uint32(*)(void))(hvar->addr))(); ! 233: case VALUE_TYPE_VAR32: ! 234: return *(hvar->addr); ! 235: default: ! 236: fprintf(stderr, "ERROR: variable '%s' has unsupported type '%d'\n", ! 237: hvar->name, hvar->vtype); ! 238: exit(-1); ! 239: } ! 240: } ! 241: ! 242: ! 243: /** ! 244: * If given string is a Hatari variable name, set value to given ! 245: * variable's value and return true, otherwise return false. ! 246: */ ! 247: bool Vars_GetVariableValue(const char *name, Uint32 *value) ! 248: { ! 249: const var_addr_t *hvar; ! 250: ! 251: if (!(hvar = Vars_ParseVariable(name))) { ! 252: return false; ! 253: } ! 254: *value = Vars_GetValue(hvar); ! 255: return true; ! 256: } ! 257: ! 258: ! 259: /** ! 260: * List Hatari variable names & current values ! 261: */ ! 262: int Vars_List(int nArgc, char *psArgv[]) ! 263: { ! 264: Uint32 value; ! 265: int i; ! 266: fputs("Hatari debugger builtin symbols and their values are:\n", stderr); ! 267: for (i = 0; i < ARRAY_SIZE(hatari_vars); i++) { ! 268: const var_addr_t *hvar = hatari_vars + i; ! 269: value = Vars_GetValue(hvar); ! 270: fprintf(stderr, " - %s: $%X / #%d", hvar->name, value, value); ! 271: if (hvar->info) { ! 272: fprintf(stderr, " -- %s\n", hvar->info); ! 273: } else { ! 274: fprintf(stderr, "\n"); ! 275: } ! 276: } ! 277: return DEBUGGER_CMDDONE; ! 278: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.