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*/
38class 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