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