1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#ifndef DEBUGGER_HXX
19#define DEBUGGER_HXX
20
21class OSystem;
22class Console;
23class EventHandler;
24class TiaInfoWidget;
25class TiaOutputWidget;
26class TiaZoomWidget;
27class EditTextWidget;
28class RomWidget;
29class Expression;
30class BreakpointMap;
31class TrapArray;
32class PromptWidget;
33class ButtonWidget;
34
35class M6502;
36class System;
37class CartDebug;
38class CpuDebug;
39class RiotDebug;
40class TIADebug;
41class DebuggerParser;
42class RewindManager;
43
44#include <map>
45
46#include "Base.hxx"
47#include "DialogContainer.hxx"
48#include "DebuggerDialog.hxx"
49#include "FrameBufferConstants.hxx"
50#include "bspf.hxx"
51
52/**
53 The base dialog for all debugging widgets in Stella. Also acts as the parent
54 for all debugging operations in Stella (parser, 6502 debugger, etc).
55
56 @author Stephen Anthony
57*/
58class Debugger : public DialogContainer
59{
60 // Make these friend classes, to ease communications with the debugger
61 // Although it isn't enforced, these classes should use accessor methods
62 // directly, and not touch the instance variables
63 friend class DebuggerParser;
64 friend class EventHandler;
65 friend class M6502;
66
67 public:
68 using FunctionMap = std::map<string, unique_ptr<Expression>>;
69 using FunctionDefMap = std::map<string, string>;
70
71 /**
72 Create a new debugger parent object
73 */
74 Debugger(OSystem& osystem, Console& console);
75 virtual ~Debugger();
76
77 private:
78 static const Int8 ANY_BANK = -1;
79
80 public:
81 /**
82 Initialize the debugger dialog container.
83 */
84 void initialize();
85
86 /**
87 Initialize the video subsystem wrt this class.
88 */
89 FBInitStatus initializeVideo();
90
91 /**
92 Wrapper method for EventHandler::enterDebugMode() for those classes
93 that don't have access to EventHandler.
94
95 @param message Message to display when entering debugger
96 @param address An address associated with the message
97 */
98 bool start(const string& message = "", int address = -1, bool read = true);
99 bool startWithFatalError(const string& message = "");
100
101 /**
102 Wrapper method for EventHandler::leaveDebugMode() for those classes
103 that don't have access to EventHandler.
104 */
105 void quit(bool exitrom);
106
107 bool addFunction(const string& name, const string& def,
108 Expression* exp, bool builtin = false);
109 bool isBuiltinFunction(const string& name);
110 bool delFunction(const string& name);
111 const Expression& getFunction(const string& name) const;
112
113 const string& getFunctionDef(const string& name) const;
114 const FunctionDefMap getFunctionDefMap() const;
115 string builtinHelp() const;
116
117 /**
118 Methods used by the command parser for tab-completion
119 In this case, return completions from the function list
120 */
121 void getCompletions(const char* in, StringList& list) const;
122
123 /**
124 The dialog/GUI associated with the debugger
125 */
126 Dialog& dialog() const { return *myDialog; }
127
128 /**
129 The debugger subsystem responsible for all CPU state
130 */
131 CpuDebug& cpuDebug() const { return *myCpuDebug; }
132
133 /**
134 The debugger subsystem responsible for all Cart RAM/ROM state
135 */
136 CartDebug& cartDebug() const { return *myCartDebug; }
137
138 /**
139 The debugger subsystem responsible for all RIOT state
140 */
141 RiotDebug& riotDebug() const { return *myRiotDebug; }
142
143 /**
144 The debugger subsystem responsible for all TIA state
145 */
146 TIADebug& tiaDebug() const { return *myTiaDebug; }
147
148 const GUI::Font& lfont() const { return myDialog->lfont(); }
149 const GUI::Font& nlfont() const { return myDialog->nfont(); }
150 DebuggerParser& parser() const { return *myParser; }
151 PromptWidget& prompt() const { return myDialog->prompt(); }
152 RomWidget& rom() const { return myDialog->rom(); }
153 TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); }
154
155 BreakpointMap& breakPoints() const;
156
157 TrapArray& readTraps() const;
158 TrapArray& writeTraps() const;
159
160 /**
161 Sets a breakpoint.
162
163 Returns true if successfully set
164 */
165 bool setBreakPoint(uInt16 addr, uInt8 bank = ANY_BANK,
166 uInt32 flags = 0);
167
168 /**
169 Clears a breakpoint.
170
171 Returns true if successfully cleared
172 */
173 bool clearBreakPoint(uInt16 addr, uInt8 bank);
174
175 /**
176 Toggles a breakpoint
177
178 Returns new state of breakpoint
179 */
180 bool toggleBreakPoint(uInt16 addr, uInt8 bank);
181
182 /**
183 Checks for a breakpoint.
184
185 Returns true if existing, else false
186 */
187 bool checkBreakPoint(uInt16 addr, uInt8 bank);
188
189 /**
190 Run the debugger command and return the result.
191 */
192 const string run(const string& command);
193
194 string autoExec(StringList* history);
195
196 string showWatches();
197
198 /**
199 Convert between string->integer and integer->string, taking into
200 account the current base format.
201 */
202 int stringToValue(const string& stringval);
203
204 /* Convenience methods to get/set bit(s) in an 8-bit register */
205 static uInt8 set_bit(uInt8 input, uInt8 bit, bool on)
206 {
207 if(on)
208 return uInt8(input | (1 << bit));
209 else
210 return uInt8(input & ~(1 << bit));
211 }
212 static void set_bits(uInt8 reg, BoolArray& bits)
213 {
214 bits.clear();
215 for(int i = 0; i < 8; ++i)
216 {
217 if(reg & (1<<(7-i)))
218 bits.push_back(true);
219 else
220 bits.push_back(false);
221 }
222 }
223 static uInt8 get_bits(const BoolArray& bits)
224 {
225 uInt8 result = 0x0;
226 for(int i = 0; i < 8; ++i)
227 if(bits[i])
228 result |= (1<<(7-i));
229 return result;
230 }
231
232 /** Invert given input if it differs from its previous value */
233 const string invIfChanged(int reg, int oldReg);
234
235 /**
236 This is used when we want the debugger from a class that can't
237 receive the debugger object in any other way.
238
239 It's basically a hack to prevent the need to pass debugger objects
240 everywhere, but I feel it's better to place it here then in
241 YaccParser (which technically isn't related to it at all).
242 */
243 static Debugger& debugger() { return *myStaticDebugger; }
244
245 /** Convenience methods to access peek/poke from System */
246 uInt8 peek(uInt16 addr, uInt8 flags = 0);
247 uInt16 dpeek(uInt16 addr, uInt8 flags = 0);
248 void poke(uInt16 addr, uInt8 value, uInt8 flags = 0);
249
250 /** Convenience method to access the 6502 from System */
251 M6502& m6502() const;
252
253 /** These are now exposed so Expressions can use them. */
254 int peekAsInt(int addr, uInt8 flags = 0);
255 int dpeekAsInt(int addr, uInt8 flags = 0);
256 int getAccessFlags(uInt16 addr) const;
257 void setAccessFlags(uInt16 addr, uInt8 flags);
258
259 uInt32 getBaseAddress(uInt32 addr, bool read);
260
261 bool patchROM(uInt16 addr, uInt8 value);
262
263 /**
264 Normally, accessing RAM or ROM during emulation can possibly trigger
265 bankswitching or other inadvertent changes. However, when we're in
266 the debugger, we'd like to inspect values without restriction. The
267 read/write state must therefore be locked before accessing values,
268 and unlocked for normal emulation to occur.
269 */
270 void lockSystem();
271 void unlockSystem();
272
273 /**
274 Answers whether the debugger can be exited. Currently this only
275 happens when no other dialogs are active.
276 */
277 bool canExit() const;
278
279 /**
280 Return (and possibly create) the bottom-most dialog of this container.
281 */
282 Dialog* baseDialog() override { return myDialog; }
283
284 static const Int32 NOT_FOUND = -1;
285
286 private:
287 /**
288 Save state of each debugger subsystem and, by default, mark all
289 pages as clean (ie, turn off the dirty flag).
290 */
291 void saveOldState(bool clearDirtyPages = true);
292
293 /**
294 Saves a rewind state with the given message.
295 */
296 void addState(string rewindMsg);
297
298 /**
299 Set initial state before entering the debugger.
300 */
301 void setStartState();
302
303 /**
304 Set final state before leaving the debugger.
305 */
306 void setQuitState();
307
308 int step();
309 int trace();
310 void nextScanline(int lines);
311 void nextFrame(int frames);
312 uInt16 rewindStates(const uInt16 numStates, string& message);
313 uInt16 unwindStates(const uInt16 numStates, string& message);
314
315 void clearAllBreakPoints();
316
317 void addReadTrap(uInt16 t);
318 void addWriteTrap(uInt16 t);
319 void addTrap(uInt16 t);
320 void removeReadTrap(uInt16 t);
321 void removeWriteTrap(uInt16 t);
322 void removeTrap(uInt16 t);
323 bool readTrap(uInt16 t);
324 bool writeTrap(uInt16 t);
325 void clearAllTraps();
326
327 // Set a bunch of RAM locations at once
328 string setRAM(IntArray& args);
329
330 void reset();
331
332 void saveState(int state);
333 void saveAllStates();
334 void loadState(int state);
335 void loadAllStates();
336
337 private:
338 Console& myConsole;
339 System& mySystem;
340
341 DebuggerDialog* myDialog;
342 unique_ptr<DebuggerParser> myParser;
343 unique_ptr<CartDebug> myCartDebug;
344 unique_ptr<CpuDebug> myCpuDebug;
345 unique_ptr<RiotDebug> myRiotDebug;
346 unique_ptr<TIADebug> myTiaDebug;
347
348 static Debugger* myStaticDebugger;
349
350 FunctionMap myFunctions;
351 FunctionDefMap myFunctionDefs;
352
353 // Dimensions of the entire debugger window
354 uInt32 myWidth;
355 uInt32 myHeight;
356
357 // Various builtin functions and operations
358 struct BuiltinFunction {
359 string name, defn, help;
360 };
361 struct PseudoRegister {
362 string name, help;
363 };
364 static std::array<BuiltinFunction, 18> ourBuiltinFunctions;
365 static std::array<PseudoRegister, 11> ourPseudoRegisters;
366
367 private:
368 // rewind/unwind n states
369 uInt16 windStates(uInt16 numStates, bool unwind, string& message);
370 // update the rewind/unwind button state
371 void updateRewindbuttons(const RewindManager& r);
372
373 // Following constructors and assignment operators not supported
374 Debugger() = delete;
375 Debugger(const Debugger&) = delete;
376 Debugger(Debugger&&) = delete;
377 Debugger& operator=(const Debugger&) = delete;
378 Debugger& operator=(Debugger&&) = delete;
379};
380
381#endif
382