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-2014 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 // $Id: CartDebug.hxx 2838 2014-01-17 23:34:03Z stephena $
18 //============================================================================
19 
20 #ifndef CART_DEBUG_HXX
21 #define CART_DEBUG_HXX
22 
23 class Settings;
24 class CartDebugWidget;
25 
26 #include <map>
27 #include <set>
28 #include <list>
29 
30 #include "bspf.hxx"
31 #include "Array.hxx"
32 #include "Base.hxx"
33 #include "Cart.hxx"
34 #include "DebuggerSystem.hxx"
35 #include "System.hxx"
36 
37 // pointer types for CartDebug instance methods
38 class CartDebug;
39 typedef int (CartDebug::*CARTDEBUG_INT_METHOD)();
40 
41 // call the pointed-to method on the (global) CPU debugger object.
42 #define CALL_CARTDEBUG_METHOD(method) ( ( Debugger::debugger().cartDebug().*method)() )
43 
44 class CartState : public DebuggerState
45 {
46   public:
47     IntArray ram;    // The actual data values
48     IntArray rport;  // Address for reading from RAM
49     IntArray wport;  // Address for writing to RAM
50     string bank;     // Current banking layout
51 };
52 
53 class CartDebug : public DebuggerSystem
54 {
55   // The disassembler needs special access to this class
56   friend class DiStella;
57 
58   public:
59     enum DisasmType {
60       NONE        = 0,
61       REFERENCED  = 1 << 0, /* code somewhere in the program references it,
62                                i.e. LDA $F372 referenced $F372 */
63       VALID_ENTRY = 1 << 1, /* addresses that can have a label placed in front of it.
64                                A good counterexample would be "FF00: LDA $FE00"; $FF01
65                                would be in the middle of a multi-byte instruction, and
66                                therefore cannot be labelled. */
67 
68       // The following correspond to specific types that can be set within the
69       // debugger, or specified in a Distella cfg file, and are listed in order
70       // of decreasing hierarchy
71       //
72       CODE   = 1 << 7,  // disassemble-able code segments
73       TCODE  = 1 << 6,  // (tentative) disassemble-able code segments
74       GFX    = 1 << 5,  // addresses loaded into GRPx registers
75       PGFX   = 1 << 4,  // addresses loaded into PFx registers
76       DATA   = 1 << 3,  // addresses loaded into registers other than GRPx / PFx
77       ROW    = 1 << 2   // all other addresses
78     };
79     struct DisassemblyTag {
80       DisasmType type;
81       uInt16 address;
82       string label;
83       string disasm;
84       string ccount;
85       string bytes;
86       bool hllabel;
87     };
88     typedef Common::Array<DisassemblyTag> DisassemblyList;
89     struct Disassembly {
90       DisassemblyList list;
91       int fieldwidth;
92     };
93 
94   public:
95     CartDebug(Debugger& dbg, Console& console, const OSystem& osystem);
96     virtual ~CartDebug();
97 
98     const DebuggerState& getState();
getOldState()99     const DebuggerState& getOldState() { return myOldState; }
100 
101     void saveOldState();
102     string toString();
103 
104     // Used to get/set the debug widget, which contains cart-specific
105     // functionality
getDebugWidget() const106     CartDebugWidget* getDebugWidget() const { return myDebugWidget; }
setDebugWidget(CartDebugWidget * w)107     void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; }
108 
109     // The following assume that the given addresses are using the
110     // correct read/write port ranges; no checking will be done to
111     // confirm this.
peek(uInt16 addr)112     uInt8 peek(uInt16 addr)   { return mySystem.peek(addr); }
dpeek(uInt16 addr)113     uInt16 dpeek(uInt16 addr) { return mySystem.peek(addr) | (mySystem.peek(addr+1) << 8); }
poke(uInt16 addr,uInt8 value)114     void poke(uInt16 addr, uInt8 value) { mySystem.poke(addr, value); }
115 
116     // Indicate that a read from write port has occurred at the specified
117     // address.
118     void triggerReadFromWritePort(uInt16 address);
119 
120     // Return the address at which an invalid read was performed in a
121     // write port area.
122     int readFromWritePort();
123 
124     /**
125       Let the Cart debugger subsystem treat this area as addressable memory.
126 
127       @param start    The beginning of the RAM area (0x0000 - 0x2000)
128       @param size     Total number of bytes of area
129       @param roffset  Offset to use when reading from RAM (read port)
130       @param woffset  Offset to use when writing to RAM (write port)
131     */
132     void addRamArea(uInt16 start, uInt16 size, uInt16 roffset, uInt16 woffset);
133 
134     // The following two methods are meant to be used together
135     // First, a call is made to disassemble(), which updates the disassembly
136     // list; it will figure out when an actual complete disassembly is
137     // required, and when the previous results can be used
138     //
139     // Later, successive calls to disassemblyList() simply return the
140     // previous results; no disassembly is done in this case
141     /**
142       Disassemble from the given address using the Distella disassembler
143       Address-to-label mappings (and vice-versa) are also determined here
144 
145       @param force  Force a re-disassembly, even if the state hasn't changed
146 
147       @return  True if disassembly changed from previous call, else false
148     */
149     bool disassemble(bool force = false);
150 
151     /**
152       Get the results from the most recent call to disassemble()
153     */
disassembly() const154     const Disassembly& disassembly() const { return myDisassembly; }
155 
156     /**
157       Determine the line in the disassembly that corresponds to the given address.
158 
159       @param address  The address to search for
160 
161       @return Line number of the address, else -1 if no such address exists
162     */
163     int addressToLine(uInt16 address) const;
164 
165     /**
166       Disassemble from the starting address the specified number of lines.
167       Note that automatic code determination is turned off for this method;
168 
169       @param start  The start address for disassembly
170       @param lines  The number of disassembled lines to generate
171 
172       @return  The disassembly represented as a string
173     */
174     string disassemble(uInt16 start, uInt16 lines) const;
175 
176     /**
177       Add a directive to the disassembler.  Directives are basically overrides
178       for the automatic code determination algorithm in Distella, since some
179       things can't be automatically determined.  For now, these directives
180       have exactly the same syntax as in a distella configuration file.
181 
182       @param type   Currently, CODE/DATA/GFX are supported
183       @param start  The start address (inclusive) to mark with the given type
184       @param end    The end address (inclusive) to mark with the given type
185       @param bank   Bank to which these directive apply (0 indicated current bank)
186 
187       @return  True if directive was added, else false if it was removed
188     */
189     bool addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end,
190                       int bank = -1);
191 
192     // The following are convenience methods that query the cartridge object
193     // for the desired information.
194     /**
195       Get the current bank in use by the cartridge.
196     */
197     int getBank();  // non-const because of use in YaccParser
198 
199     /**
200       Get the total number of banks supported by the cartridge.
201     */
202     int bankCount() const;
203 
204     /**
205       Get the name/type of the cartridge.
206     */
207     string getCartType() const;
208 
209     /**
210       Add a label and associated address.
211       Labels that reference either TIA or RIOT spaces will not be processed.
212     */
213     bool addLabel(const string& label, uInt16 address);
214 
215     /**
216       Remove the given label and its associated address.
217       Labels that reference either TIA or RIOT spaces will not be processed.
218     */
219     bool removeLabel(const string& label);
220 
221     /**
222       Accessor methods for labels and addresses
223 
224       The mapping from address to label can be one-to-many (ie, an
225       address can have different labels depending on its context, and
226       whether its being read or written; if isRead is true, the context
227       is a read, else it's a write
228       If places is not -1 and a label hasn't been defined, return a
229       formatted hexidecimal address
230     */
231     bool getLabel(ostream& buf, uInt16 addr, bool isRead, int places = -1) const;
232     string getLabel(uInt16 addr, bool isRead, int places = -1) const;
233     int getAddress(const string& label) const;
234 
235     /**
236       Load constants from list file (as generated by DASM).
237     */
238     string loadListFile();
239 
240     /**
241       Load user equates from symbol file (as generated by DASM).
242     */
243     string loadSymbolFile();
244 
245     /**
246       Load/save Distella config files (Distella directives)
247     */
248     string loadConfigFile();
249     string saveConfigFile();
250 
251     /**
252       Save disassembly and ROM file
253     */
254     string saveDisassembly();
255     string saveRom();
256 
257     /**
258       Show Distella directives (both set by the user and determined by Distella)
259       for the given bank (or all banks, if no bank is specified).
260     */
261     string listConfig(int bank = -1);
262 
263     /**
264       Clear Distella directives (set by the user) for the given bank
265       (or all banks, if no bank is specified.)
266     */
267     string clearConfig(int bank = -1);
268 
269     /**
270       Methods used by the command parser for tab-completion
271       In this case, return completions from the equate list(s)
272     */
273     void getCompletions(const char* in, StringList& list) const;
274 
275     // Convert given address to corresponding disassembly type and append to buf
276     void addressTypeAsString(ostream& buf, uInt16 addr) const;
277 
278   private:
279     typedef map<uInt16, string> AddrToLabel;
280     typedef map<string, uInt16> LabelToAddr;
281 
282     // Determine 'type' of address (ie, what part of the system accessed)
283     enum AddrType {
284       ADDR_TIA,
285       ADDR_IO,
286       ADDR_ZPRAM,
287       ADDR_ROM
288     };
289     AddrType addressType(uInt16 addr) const;
290 
291     struct DirectiveTag {
292       DisasmType type;
293       uInt16 start;
294       uInt16 end;
295     };
296     typedef list<uInt16> AddressList;
297     typedef list<DirectiveTag> DirectiveList;
298 
299     struct BankInfo {
300       uInt16 start;                // start of address space
301       uInt16 end;                  // end of address space
302       uInt16 offset;               // ORG value
303       uInt16 size;                 // size of a bank (in bytes)
304       AddressList addressList;     // addresses which PC has hit
305       DirectiveList directiveList; // overrides for automatic code determination
306 
BankInfoCartDebug::BankInfo307       BankInfo() : start(0), end(0), offset(0), size(0) { }
308 #if 0
309       friend ostream& operator<<(ostream& os, const BankInfo& b)
310       {
311         os << "start=$" << HEX4 << b.start << ", end=$" << HEX4 << b.end
312            << ", offset=$" << HEX4 << b.offset << ", size=" << dec << b.size
313            << endl
314            << "addrlist: ";
315         AddressList::const_iterator i;
316         for(i = b.addressList.begin(); i != b.addressList.end(); ++i)
317           os << HEX4 << *i << " ";
318         return os;
319       }
320 #endif
321     };
322 
323     // Address type information determined by Distella
324     uInt8 myDisLabels[0x1000], myDisDirectives[0x1000];
325 
326     // Information on equates used in the disassembly
327     struct ReservedEquates {
328       bool TIARead[16];
329       bool TIAWrite[64];
330       bool IOReadWrite[24];
331       bool ZPRAM[128];
332       AddrToLabel Label;
333     };
334     ReservedEquates myReserved;
335 
336     // Actually call DiStella to fill the DisassemblyList structure
337     // Return whether the search address was actually in the list
338     bool fillDisassemblyList(BankInfo& bankinfo, uInt16 search);
339 
340     // Analyze of bank of ROM, generating a list of Distella directives
341     // based on its disassembly
342     void getBankDirectives(ostream& buf, BankInfo& info) const;
343 
344     // Get disassembly enum type from 'flags', taking precendence into account
345     DisasmType disasmTypeAbsolute(uInt8 flags) const;
346 
347     // Convert disassembly enum type to corresponding string and append to buf
348     void disasmTypeAsString(ostream& buf, DisasmType type) const;
349 
350     // Convert all disassembly types in 'flags' to corresponding string and
351     // append to buf
352     void disasmTypeAsString(ostream& buf, uInt8 flags) const;
353 
354   private:
355     const OSystem& myOSystem;
356 
357     CartState myState;
358     CartState myOldState;
359 
360     CartDebugWidget* myDebugWidget;
361 
362     // A complete record of relevant diassembly information for each bank
363     Common::Array<BankInfo> myBankInfo;
364 
365     // Used for the disassembly display, and mapping from addresses
366     // to corresponding lines of text in that display
367     Disassembly myDisassembly;
368     map<uInt16, int> myAddrToLineList;
369     bool myAddrToLineIsROM;
370 
371     // Mappings from label to address (and vice versa) for items
372     // defined by the user (either through a DASM symbol file or manually
373     // from the commandline in the debugger)
374     AddrToLabel myUserLabels;
375     LabelToAddr myUserAddresses;
376 
377     // Mappings from label to address (and vice versa) for constants
378     // defined through a DASM lst file
379     AddrToLabel myUserCLabels;
380     // LabelToAddr myUserCAddresses;
381 
382     // Mappings for labels to addresses for system-defined equates
383     // Because system equate addresses can have different names
384     // (depending on access in read vs. write mode), we can only create
385     // a mapping from labels to addresses; addresses to labels are
386     // handled differently
387     LabelToAddr mySystemAddresses;
388 
389     // Holds address at which the most recent read from a write port
390     // occurred
391     uInt16 myRWPortAddress;
392 
393     // The maximum length of all labels currently defined
394     uInt16 myLabelLength;
395 
396     // Filenames to use for various I/O (currently these are hardcoded)
397     string myListFile, mySymbolFile, myCfgFile, myDisasmFile, myRomFile;
398 
399     /// Table of instruction mnemonics
400     static const char* ourTIAMnemonicR[16]; // read mode
401     static const char* ourTIAMnemonicW[64]; // write mode
402     static const char* ourIOMnemonic[24];
403     static const char* ourZPMnemonic[128];
404 };
405 
406 #endif
407