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