VirtualC64 v5.0 beta
Commodore 64 Emulator
Loading...
Searching...
No Matches
PeddleDebugger.h
1// -----------------------------------------------------------------------------
2// This file is part of Peddle - A MOS 65xx CPU emulator
3//
4// Copyright (C) Dirk W. Hoffmann. www.dirkwhoffmann.de
5// Published under the terms of the MIT License
6// -----------------------------------------------------------------------------
7
8#pragma once
9
10#include "PeddleDebugger.h"
11#include "Peddle.h"
12
13namespace vc64::peddle {
14
15/*
16// Base structure for a single breakpoint or watchpoint
17struct Guard {
18
19 // The observed address
20 u32 addr;
21
22 // Disabled guards never trigger
23 bool enabled;
24
25 // Counts the number of hits
26 long hits;
27
28 // Ignore counter
29 long ignore;
30
31public:
32
33 // Returns true if the guard hits
34 bool eval(u32 addr);
35
36 // Replaces the address by another
37 void moveTo(u32 newAddr);
38};
39*/
40
41// Base class for a collection of guards
42class Guards {
43
44 friend class Debugger;
45
46protected:
47
48 // Reference to the connected CPU
49 class Peddle &cpu;
50
51 // Capacity of the guards array
52 long capacity = 1;
53
54 // Array holding all guards
55 Guard *guards = new Guard[1];
56
57 // Number of currently stored guards
58 long count = 0;
59
60 // Indicates if guard checking is necessary
61 virtual void setNeedsCheck(bool value) = 0;
62
63
64 //
65 // Constructing
66 //
67
68public:
69
70 Guards(Peddle& ref) : cpu(ref) { }
71 virtual ~Guards();
72
73
74 //
75 // Inspecting the guard list
76 //
77
78 long elements() const { return count; }
79 Guard *guardWithNr(long nr) const;
80 Guard *guardAtAddr(u32 addr) const;
81
82 u32 guardAddr(long nr) const { return nr < count ? guards[nr].addr : 0; }
83
84
85 //
86 // Adding or removing guards
87 //
88
89 bool isSet(long nr) const { return guardWithNr(nr) != nullptr; }
90 bool isSetAt(u32 addr) const { return guardAtAddr(addr) != nullptr; }
91
92 void setAt(u32 addr, long ignores = 0);
93 void moveTo(long nr, u32 newAddr);
94
95 void remove(long nr);
96 void removeAt(u32 addr);
97 void removeAll() { count = 0; setNeedsCheck(false); }
98
99
100 //
101 // Enabling or disabling guards
102 //
103
104 bool isEnabled(long nr) const;
105 bool isEnabledAt(u32 addr) const;
106 bool isDisabled(long nr) const;
107 bool isDisabledAt(u32 addr) const;
108
109 void enable(long nr) { setEnable(nr, true); }
110 void enableAt(u32 addr) { setEnableAt(addr, true); }
111 void enableAll() { setEnableAll(true); }
112
113 void disable(long nr) { setEnable(nr, false); }
114 void disableAt(u32 addr) { setEnableAt(addr, false); }
115 void disableAll() { setEnableAll(false); }
116
117 void setEnable(long nr, bool val);
118 void setEnableAt(u32 addr, bool val);
119 void setEnableAll(bool val);
120
121 void ignore(long nr, long count);
122
123
124 //
125 // Checking a guard
126 //
127
128private:
129
130 // Returns true if the guard hits
131 bool eval(u32 addr);
132};
133
134class Breakpoints : public Guards {
135
136public:
137
138 Breakpoints(Peddle& ref) : Guards(ref) { }
139 void setNeedsCheck(bool value) override;
140};
141
142class Watchpoints : public Guards {
143
144public:
145
146 Watchpoints(Peddle& ref) : Guards(ref) { }
147 void setNeedsCheck(bool value) override;
148};
149
150class Debugger {
151
152 friend class Peddle;
153
154 // Reference to the connected CPU
155 class Peddle &cpu;
156
157public:
158
159 // Log buffer
160 RecordedInstruction logBuffer[LOG_BUFFER_CAPACITY];
161
162 // Breakpoint storage
163 Breakpoints breakpoints = Breakpoints(cpu);
164
165 // Watchpoint storage (not yet supported)
166 Watchpoints watchpoints = Watchpoints(cpu);
167
168 // Saved program counters
169 i32 breakpointPC = -1;
170 i32 watchpointPC = -1;
171
172private:
173
174 /* Number of logged instructions.
175 * Note: This variable counts the total number of logged instructions and
176 * eventually exceeds the log buffer capacity. Use 'loggedInstruction()'
177 * to obtain the number of available instructions in the log buffer.
178 */
179 isize logCnt = 0;
180
181 /* Soft breakpoint for implementing single-stepping.
182 * In contrast to a standard (hard) breakpoint, a soft breakpoint is
183 * deleted when reached. The CPU halts if softStop matches the CPU's
184 * program counter (used to implement "step over") or if softStop equals
185 * UINT64_MAX (used to implement "step into"). To disable soft stopping,
186 * simply set softStop to an unreachable memory location such as
187 * UINT64_MAX - 1.
188 */
189 u64 softStop = UINT64_MAX - 1;
190
191
192 //
193 // Initializing
194 //
195
196public:
197
198 Debugger(Peddle& ref) : cpu(ref) { };
199 void reset();
200
201
202 //
203 // Working with breakpoints and watchpoints
204 //
205
206public:
207
208 // Sets a soft breakpoint
209 void setSoftStop(u64 addr);
210 void setSoftStopAtNextInstr();
211
212 // Returns true if a breakpoint hits at the provides address
213 bool breakpointMatches(u32 addr);
214
215 // Returns true if a watchpoint hits at the provides address
216 bool watchpointMatches(u32 addr);
217
218
219 //
220 // Working with the instruction log
221 //
222
223 // Dumps a portion of the log buffer
224 void dumpLogBuffer(std::ostream& os, isize count);
225 void dumpLogBuffer(std::ostream& os);
226
227 // Turns instruction logging on or off
228 void enableLogging();
229 void disableLogging();
230
231 // Returns the number of logged instructions
232 isize loggedInstructions() const;
233
234 // Logs an instruction
235 void logInstruction();
236
237 /* Reads an item from the log buffer
238 *
239 * xxxRel: n == 0 returns the most recently recorded entry
240 * xxxAbs: n == 0 returns the oldest entry
241 */
242 const RecordedInstruction &logEntryRel(isize n) const;
243 const RecordedInstruction &logEntryAbs(isize n) const;
244 u16 loggedPC0Rel(isize n) const;
245 u16 loggedPC0Abs(isize n) const;
246
247 // Disassembles an item from the log buffer
248 isize disassRecorded(char *dst, const char *fmt, isize addr) const;
249
250 // DEPRECATED
251 isize disassembleRecordedInstr(isize i, char *str) const;
252 isize disassembleRecordedBytes(isize i, char *str) const;
253 void disassembleRecordedFlags(isize i, char *str) const;
254 void disassembleRecordedPC(isize i, char *str) const;
255
256 // Clears the log buffer
257 void clearLog() { logCnt = 0; }
258
259
260 //
261 // Changing state
262 //
263
264 // Continues program execution at the specified address
265 void jump(u16 addr);
266};
267
268}