|
|
1.1 root 1: /*
2: * Hatari - history.c
3: *
4: * Copyright (C) 2011 by Eero Tamminen
5: *
6: * This file is distributed under the GNU Public License, version 2 or at
7: * your option any later version. Read the file gpl.txt for details.
8: *
9: * history.c - functions for debugger entry & breakpoint history
10: */
11: const char History_fileid[] = "Hatari history.c : " __DATE__ " " __TIME__;
12:
13: #include <assert.h>
14:
15: #include "main.h"
16: #include "debugui.h"
17: #include "debug_priv.h"
18: #include "dsp.h"
19: #include "dsp_core.h"
20: #include "evaluate.h"
21: #include "history.h"
22: #include "m68000.h"
23: #include "68kDisass.h"
24:
25: bool bHistoryEnabled;
26:
27: #define HISTORY_ITEMS 256
28:
29: typedef struct {
30: bool shown:1;
31: bool valid:1;
32: bool for_dsp:1;
33: /* reason for debugger entry/breakpoint hit */
34: debug_reason_t reason:8;
35: union {
36: Uint16 dsp;
37: Uint32 cpu;
38: } pc;
39: } hist_item_t;
40:
41: static struct {
42: unsigned idx; /* index to current history item */
43: unsigned count; /* how many items of history are collected */
44: hist_item_t item[HISTORY_ITEMS]; /* ring-buffer */
45: } History;
46:
47:
48: /**
49: * Convert debugger entry/breakpoint entry reason to a string
50: */
51: const char* History_ReasonStr(debug_reason_t reason)
52: {
53: switch(reason) {
54: case REASON_CPU_EXCEPTION:
55: return "CPU exception";
56: case REASON_CPU_BREAKPOINT:
57: return "CPU breakpoint";
58: case REASON_DSP_BREAKPOINT:
59: return "DSP breakpoint";
60: case REASON_CPU_STEPS:
61: return "CPU steps";
62: case REASON_DSP_STEPS:
63: return "DSP steps";
64: case REASON_USER:
65: return "User break";
66: default:
67: return "Unknown reason";
68: }
69: }
70:
71:
72: /**
73: * Enable/disable history collecting.
74: * Clear history on disabling as data wouldn't
75: * then be anymore valid.
76: */
77: void History_Enable(bool enable)
78: {
79: if (!enable) {
80: memset(&History, 0, sizeof(History));
81: }
82: bHistoryEnabled = enable;
83: }
84:
85: /**
86: * Advance & initialize next history item in ring buffer
87: */
88: static void History_Advance(void)
89: {
90: History.idx++;
91: History.idx %= HISTORY_ITEMS;
92: History.item[History.idx].valid = true;
93: History.item[History.idx].shown = false;
94: History.item[History.idx].reason = REASON_NONE;
95: History.count++;
96: }
97:
98: /**
99: * Add CPU PC to history
100: */
101: void History_AddCpu(void)
102: {
103: Uint32 pc = M68000_GetPC();
104:
105: History_Advance();
106: History.item[History.idx].for_dsp = false;
107: History.item[History.idx].pc.cpu = pc;
108: }
109:
110: /**
111: * Add DSP PC to history
112: */
113: void History_AddDsp(void)
114: {
115: Uint16 pc = DSP_GetPC();
116:
117: History_Advance();
118: History.item[History.idx].for_dsp = true;
119: History.item[History.idx].pc.dsp = pc;
120: }
121:
122: /**
123: * Flag last history entry as debugger entry point, with given reason
124: */
125: void History_Mark(debug_reason_t reason)
126: {
127: History.item[History.idx].reason = reason;
128: }
129:
130: /**
131: * Show collected CPU/DSP debugger/breakpoint history
132: */
133: void History_Show(Uint32 count)
134: {
135: bool show_all;
136: int i;
137:
138: if (History.count > HISTORY_ITEMS) {
139: History.count = HISTORY_ITEMS;
140: }
141: if (count > History.count) {
142: count = History.count;
143: } else {
144: if (!count) {
145: /* default to all */
146: count = History.count;
147: }
148: }
149: if (count <= 0) {
150: fprintf(stderr, "No history items to show.\n");
151: return;
152: }
153:
154: i = History.idx;
155: show_all = false;
156: if (History.item[i].shown) {
157: /* even last item already shown, show all again */
158: show_all = true;
159: }
160: i = (i + HISTORY_ITEMS - count) % HISTORY_ITEMS;
161:
162: while (count-- > 0) {
163: i++;
164: i %= HISTORY_ITEMS;
165: if (!History.item[i].valid) {
166: fprintf(stderr, "ERROR: invalid history item %d!", count);
167: }
168: if (History.item[i].shown && !show_all) {
169: continue;
170: }
171: History.item[i].shown = true;
172:
173: if (History.item[i].for_dsp) {
174: Uint16 pc = History.item[i].pc.dsp;
175: DSP_DisasmAddress(pc, pc);
176: } else {
177: Uint32 dummy;
178: Disasm(stderr, History.item[i].pc.cpu, &dummy, 1, DISASM_ENGINE_EXT);
179: }
180: if (History.item[i].reason != REASON_NONE) {
181: fprintf(stderr, "Debugger: *%s*\n", History_ReasonStr(History.item[i].reason));
182: }
183: }
184: }
185:
186: /**
187: * Command: Show collected CPU/DSP debugger/breakpoint history
188: */
189: int History_Parse(int nArgc, char *psArgs[])
190: {
191: int count;
192:
193: if (nArgc != 2) {
194: DebugUI_PrintCmdHelp(psArgs[0]);
195: return DEBUGGER_CMDDONE;
196: }
197:
198: count = atoi(psArgs[1]);
199: if (count <= 0 || count > HISTORY_ITEMS) {
200: /* no count -> enable or disable? */
201: if (strcmp(psArgs[1], "on") == 0) {
202: History_Enable(true);
203: return DEBUGGER_CMDDONE;
204: }
205: if (strcmp(psArgs[1], "off") == 0) {
206: History_Enable(false);
207: return DEBUGGER_CMDDONE;
208: }
209: fprintf(stderr, "History range is 1-%d!\n", HISTORY_ITEMS);
210: DebugUI_PrintCmdHelp(psArgs[0]);
211: return DEBUGGER_CMDDONE;
212: }
213:
214: History_Show(count);
215: return DEBUGGER_CMDDONE;
216: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.