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