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: DiStella.hxx 2838 2014-01-17 23:34:03Z stephena $
18 //============================================================================
19 
20 #ifndef DISTELLA_HXX
21 #define DISTELLA_HXX
22 
23 #include <queue>
24 #include <sstream>
25 
26 #include "Array.hxx"
27 #include "Base.hxx"
28 #include "CartDebug.hxx"
29 #include "bspf.hxx"
30 
31 /**
32   This class is a wrapper around the Distella code.  Much of the code remains
33   exactly the same, except that generated data is now redirected to a
34   DisassemblyList structure rather than being printed.
35 
36   All 7800-related stuff has been removed, as well as all commandline options.
37   Over time, some of the configurability of Distella may be added again.
38 
39   @author  Stephen Anthony
40 */
41 class DiStella
42 {
43   public:
44     // A list of options that can be applied to the disassembly
45     // This will eventually grow to include all options supported by
46     // standalone Distella
47     typedef struct {
48       Common::Base::Format gfx_format;
49       bool resolve_code;    // Attempt to detect code vs. data sections
50       bool show_addresses;  // Show PC addresses (always off for external output)
51       bool aflag;  // Turns 'A' off in accumulator instructions (-a in Distella)
52       bool fflag;  // Forces correct address length (-f in Distella)
53       bool rflag;  // Relocate calls out of address range (-r in Distella)
54       int bwidth;  // Number of bytes to use per line (with .byte xxx)
55     } Settings;
56     static Settings settings;  // Default settings
57 
58   public:
59     /**
60       Disassemble the current state of the System from the given start address.
61 
62       @param dbg         The CartDebug instance containing all label information
63       @param list        The results of the disassembly are placed here
64       @param info        Various info about the current bank
65       @param settings    The various distella flags/options to use
66       @param labels      Array storing label info determined by Distella
67       @param directives  Array storing directive info determined by Distella
68       @param reserved    The TIA/RIOT addresses referenced in the disassembled code
69     */
70     DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
71              CartDebug::BankInfo& info, const DiStella::Settings& settings,
72              uInt8* labels, uInt8* directives,
73              CartDebug::ReservedEquates& reserved);
74 
75     ~DiStella();
76 
77   private:
78     // Indicate that a new line of disassembly has been completed
79     // In the original Distella code, this indicated a new line to be printed
80     // Here, we add a new entry to the DisassemblyList
81     void addEntry(CartDebug::DisasmType type);
82 
83     // Process directives given in the list
84     // Directives are basically the contents of a distella configuration file
85     void processDirectives(const CartDebug::DirectiveList& directives);
86 
87     // These functions are part of the original Distella code
88     void disasm(uInt32 distart, int pass);
89     bool check_range(uInt16 start, uInt16 end) const;
90     int mark(uInt32 address, uInt8 mask, bool directive = false);
91     bool check_bit(uInt16 address, uInt8 mask) const;
92 
93     // Convenience methods to generate appropriate labels
labelA12High(stringstream & buf,uInt8 op,uInt16 addr,int labfound)94     inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound)
95     {
96       if(!myDbg.getLabel(buf, addr, true))
97         buf << "L" << Common::Base::HEX4 << addr;
98     }
labelA12Low(stringstream & buf,uInt8 op,uInt16 addr,int labfound)99     inline void labelA12Low(stringstream& buf, uInt8 op, uInt16 addr, int labfound)
100     {
101       myDbg.getLabel(buf, addr, ourLookup[op].rw_mode == READ, 2);
102       if (labfound == 2)
103       {
104         if(ourLookup[op].rw_mode == READ)
105           myReserved.TIARead[addr & 0x0F] = true;
106         else
107           myReserved.TIAWrite[addr & 0x3F] = true;
108       }
109       else if (labfound == 3)
110         myReserved.IOReadWrite[(addr & 0xFF) - 0x80] = true;
111       else if (labfound == 5)
112         myReserved.ZPRAM[(addr & 0xFF) - 0x80] = true;
113     }
114 
115   private:
116     const CartDebug& myDbg;
117     CartDebug::DisassemblyList& myList;
118     const Settings& mySettings;
119     CartDebug::ReservedEquates& myReserved;
120     stringstream myDisasmBuf;
121     queue<uInt16> myAddressQueue;
122     uInt16 myOffset, myPC, myPCBeg, myPCEnd;
123 
124     struct resource {
125       uInt16 start;
126       uInt16 end;
127       uInt16 length;
128     } myAppData;
129 
130     /* Stores info on how each address is marked, both in the general
131        case as well as when manual directives are enabled (in which case
132        the directives take priority
133        The address mark type is defined in CartDebug.hxx
134     */
135     uInt8 *myLabels, *myDirectives;
136 
137     /**
138       Enumeration of the 6502 addressing modes
139     */
140     enum AddressingMode
141     {
142       IMPLIED, ACCUMULATOR, IMMEDIATE,
143       ZERO_PAGE, ZERO_PAGE_X, ZERO_PAGE_Y,
144       ABSOLUTE, ABSOLUTE_X, ABSOLUTE_Y,
145       ABS_INDIRECT, INDIRECT_X, INDIRECT_Y,
146       RELATIVE, ASS_CODE
147     };
148 
149     /**
150       Enumeration of the 6502 access modes
151     */
152     enum AccessMode
153     {
154       M_NONE, M_AC, M_XR, M_YR, M_SP, M_SR, M_PC, M_IMM, M_ZERO, M_ZERX, M_ZERY,
155       M_ABS, M_ABSX, M_ABSY, M_AIND, M_INDX, M_INDY, M_REL, M_FC, M_FD, M_FI,
156       M_FV, M_ADDR, M_,
157 
158       M_ACIM, /* Source: AC & IMMED (bus collision) */
159       M_ANXR, /* Source: AC & XR (bus collision) */
160       M_AXIM, /* Source: (AC | #EE) & XR & IMMED (bus collision) */
161       M_ACNC, /* Dest: M_AC and Carry = Negative */
162       M_ACXR, /* Dest: M_AC, M_XR */
163 
164       M_SABY, /* Source: (ABS_Y & SP) (bus collision) */
165       M_ACXS, /* Dest: M_AC, M_XR, M_SP */
166       M_STH0, /* Dest: Store (src & Addr_Hi+1) to (Addr +0x100) */
167       M_STH1,
168       M_STH2,
169       M_STH3
170     };
171 
172     /**
173       Enumeration of the 6502 read/write mode
174       (if the opcode is reading or writing its operand)
175     */
176     enum ReadWriteMode
177     {
178       READ, WRITE, NONE
179     };
180 
181     struct Instruction_tag {
182       const char*    mnemonic;
183       AddressingMode addr_mode;
184       AccessMode     source;
185       ReadWriteMode  rw_mode;
186       uInt8          cycles;
187     };
188     static const Instruction_tag ourLookup[256];
189 };
190 
191 #endif
192