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-2021 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 DISTELLA_HXX 19 #define DISTELLA_HXX 20 21 #include <queue> 22 23 #include "Base.hxx" 24 #include "CartDebug.hxx" 25 #include "Device.hxx" 26 #include "bspf.hxx" 27 28 /** 29 This class is a wrapper around the Distella code. Much of the code remains 30 exactly the same, except that generated data is now redirected to a 31 DisassemblyList structure rather than being printed. 32 33 All 7800-related stuff has been removed, as well as some commandline options. 34 Over time, some of the configurability of Distella may be added again. 35 36 @authors Stephen Anthony and Thomas Jentzsch 37 Original distella developers (http://distella.sf.net) 38 */ 39 class DiStella 40 { 41 public: 42 // A list of options that can be applied to the disassembly 43 // This will eventually grow to include all options supported by 44 // standalone Distella 45 struct Settings { 46 Common::Base::Fmt gfxFormat{Common::Base::Fmt::_2}; 47 bool resolveCode{true}; // Attempt to detect code vs. data sections 48 bool showAddresses{true}; // Show PC addresses (always off for external output) 49 bool aFlag{false}; // Turns 'A' off in accumulator instructions (-a in Distella) 50 bool fFlag{true}; // Forces correct address length (-f in Distella) 51 bool rFlag{false}; // Relocate calls out of address range (-r in Distella) 52 bool bFlag{false}; // Process break routine (-b in Distella) 53 int bytesWidth{8+1}; // Number of bytes to use per line (with .byte xxx) 54 }; 55 static Settings settings; // Default settings 56 57 public: 58 /** 59 Disassemble the current state of the System from the given start address. 60 61 @param dbg The CartDebug instance containing all label information 62 @param list The results of the disassembly are placed here 63 @param info Various info about the current bank 64 @param settings The various distella flags/options to use 65 @param labels Array storing label info determined by Distella 66 @param directives Array storing directive info determined by Distella 67 @param reserved The TIA/RIOT addresses referenced in the disassembled code 68 */ 69 DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, 70 CartDebug::BankInfo& info, const DiStella::Settings& settings, 71 CartDebug::AddrTypeArray& labels, 72 CartDebug::AddrTypeArray& directives, 73 CartDebug::ReservedEquates& reserved); 74 75 private: 76 /** 77 Enumeration of the addressing type (RAM, ROM, RIOT, TIA...) 78 */ 79 enum class AddressType : int 80 { 81 INVALID, 82 ROM, 83 TIA, 84 RIOT, 85 ROM_MIRROR, 86 ZP_RAM 87 }; 88 89 90 private: 91 // Indicate that a new line of disassembly has been completed 92 // In the original Distella code, this indicated a new line to be printed 93 // Here, we add a new entry to the DisassemblyList 94 void addEntry(Device::AccessType type); 95 96 // Process directives given in the list 97 // Directives are basically the contents of a distella configuration file 98 void processDirectives(const CartDebug::DirectiveList& directives); 99 100 // These functions are part of the original Distella code 101 void disasm(uInt32 distart, int pass); 102 void disasmPass1(CartDebug::AddressList& debuggerAddresses); 103 void disasmFromAddress(uInt32 distart); 104 105 bool check_range(uInt16 start, uInt16 end) const; 106 AddressType mark(uInt32 address, uInt16 mask, bool directive = false); 107 bool checkBit(uInt16 address, uInt16 mask, bool useDebugger = true) const; 108 bool checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDebugger = true) const; 109 void outputGraphics(); 110 void outputColors(); 111 void outputBytes(Device::AccessType type); 112 113 // Convenience methods to generate appropriate labels labelA12High(stringstream & buf,uInt8 op,uInt16 addr,AddressType labfound)114 inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, AddressType labfound) 115 { 116 if(!myDbg.getLabel(buf, addr, true)) 117 buf << "L" << Common::Base::HEX4 << addr; 118 } labelA12Low(stringstream & buf,uInt8 op,uInt16 addr,AddressType labfound)119 inline void labelA12Low(stringstream& buf, uInt8 op, uInt16 addr, AddressType labfound) 120 { 121 myDbg.getLabel(buf, addr, ourLookup[op].rw_mode == RWMode::READ, 2); 122 if (labfound == AddressType::TIA) 123 { 124 if(ourLookup[op].rw_mode == RWMode::READ) 125 myReserved.TIARead[addr & 0x0F] = true; 126 else 127 myReserved.TIAWrite[addr & 0x3F] = true; 128 } 129 else if (labfound == AddressType::RIOT) 130 myReserved.IOReadWrite[(addr & 0xFF) - 0x80] = true; 131 else if (labfound == AddressType::ZP_RAM) 132 myReserved.ZPRAM[(addr & 0xFF) - 0x80] = true; 133 } 134 135 private: 136 const CartDebug& myDbg; 137 CartDebug::DisassemblyList& myList; 138 const Settings& mySettings; 139 CartDebug::ReservedEquates& myReserved; 140 stringstream myDisasmBuf; 141 std::queue<uInt16> myAddressQueue; 142 uInt16 myOffset{0}, myPC{0}, myPCEnd{0}; 143 uInt16 mySegType{0}; 144 145 struct resource { 146 uInt16 start{0}; 147 uInt16 end{0}; 148 uInt16 length{0}; 149 } myAppData; 150 151 /* Stores info on how each address is marked, both in the general 152 case as well as when manual directives are enabled (in which case 153 the directives take priority 154 The address mark type is defined in CartDebug.hxx 155 */ 156 CartDebug::AddrTypeArray& myLabels; 157 CartDebug::AddrTypeArray& myDirectives; 158 159 /** 160 Enumeration of the 6502 addressing modes 161 */ 162 enum class AddressingMode : uInt8 163 { 164 IMPLIED, ACCUMULATOR, IMMEDIATE, 165 ZERO_PAGE, ZERO_PAGE_X, ZERO_PAGE_Y, 166 ABSOLUTE, ABSOLUTE_X, ABSOLUTE_Y, 167 ABS_INDIRECT, INDIRECT_X, INDIRECT_Y, 168 RELATIVE, ASS_CODE 169 }; 170 171 /** 172 Enumeration of the 6502 access modes 173 */ 174 enum class AccessMode : uInt8 175 { 176 NONE, AC, XR, YR, SP, SR, PC, IMM, ZERO, ZERX, ZERY, 177 ABS, ABSX, ABSY, AIND, INDX, INDY, REL, FC, FD, FI, 178 FV, ADDR, 179 180 ACIM, /* Source: AC & IMMED (bus collision) */ 181 ANXR, /* Source: AC & XR (bus collision) */ 182 AXIM, /* Source: (AC | #EE) & XR & IMMED (bus collision) */ 183 ACNC, /* Dest: AC and Carry = Negative */ 184 ACXR, /* Dest: AC, XR */ 185 186 SABY, /* Source: (ABS_Y & SP) (bus collision) */ 187 ACXS, /* Dest: AC, XR, SP */ 188 STH0, /* Dest: Store (src & Addr_Hi+1) to (Addr +0x100) */ 189 STH1, 190 STH2, 191 STH3 192 }; 193 194 /** 195 Enumeration of the 6502 read/write mode 196 (if the opcode is reading or writing its operand) 197 */ 198 enum class RWMode : uInt8 199 { 200 READ, WRITE, NONE 201 }; 202 203 struct Instruction_tag { 204 const char* const mnemonic{nullptr}; 205 AddressingMode addr_mode{AddressingMode::IMPLIED}; 206 AccessMode source{AccessMode::NONE}; 207 RWMode rw_mode{RWMode::NONE}; 208 uInt8 cycles{0}; 209 uInt8 bytes{0}; 210 }; 211 static const std::array<Instruction_tag, 256> ourLookup; 212 213 private: 214 // Following constructors and assignment operators not supported 215 DiStella() = delete; 216 DiStella(const DiStella&) = delete; 217 DiStella(DiStella&&) = delete; 218 DiStella& operator=(const DiStella&) = delete; 219 DiStella& operator=(DiStella&&) = delete; 220 }; 221 222 #endif 223