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