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