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 CARTRIDGEFE_HXX |
19 | #define CARTRIDGEFE_HXX |
20 | |
21 | class System; |
22 | |
23 | #include "bspf.hxx" |
24 | #include "Cart.hxx" |
25 | #ifdef DEBUGGER_SUPPORT |
26 | #include "CartFEWidget.hxx" |
27 | #endif |
28 | |
29 | /** |
30 | Bankswitching method used by Activision's Robot Tank and Decathlon. |
31 | |
32 | This scheme was originally designed to have up to 8 4K banks, and is |
33 | triggered by monitoring the address bus for address $01FE. All released |
34 | carts had only two banks, and this implementation assumes that (ie, ROM |
35 | is always 8K, and there are two 4K banks). |
36 | |
37 | The following is paraphrased from the original patent by David Crane, |
38 | European Patent Application # 84300730.3, dated 06.02.84: |
39 | |
40 | --------------------------------------------------------------------------- |
41 | The twelve line address bus is connected to a plurality of 4K by eight bit |
42 | memories. |
43 | |
44 | The eight line data bus is connected to each of the banks of memory, also. |
45 | An address comparator is connected to the bus for detecting the presence of |
46 | the 01FE address. Actually, the comparator will detect only the lowest 12 |
47 | bits of 1FE, because of the twelve bit limitation of the address bus. Upon |
48 | detection of the 01FE address, a one cycle delay is activated which then |
49 | actuates latch connected to the data bus. The three most significant bits |
50 | on the data bus are latched and provide the address bits A13, A14, and A15 |
51 | which are then applied to a 3 to 8 de-multiplexer. The 3 bits A13-A15 |
52 | define a code for selecting one of the eight banks of memory which is used |
53 | to enable one of the banks of memory by applying a control signal to the |
54 | enable, EN, terminal thereof. Accordingly, memory bank selection is |
55 | accomplished from address codes on the data bus following a particular |
56 | program instruction, such as a jump to subroutine. |
57 | --------------------------------------------------------------------------- |
58 | |
59 | Note that in the general scheme, we use D7, D6 and D5 for the bank number |
60 | (3 bits, so 8 possible banks). However, the scheme as used historically |
61 | by Activision only uses two banks. Furthermore, the two banks it uses |
62 | are actually indicated by binary 110 and 111, and translated as follows: |
63 | |
64 | binary 110 -> decimal 6 -> Upper 4K ROM (bank 1) @ $D000 - $DFFF |
65 | binary 111 -> decimal 7 -> Lower 4K ROM (bank 0) @ $F000 - $FFFF |
66 | |
67 | Since the actual bank numbers (0 and 1) do not map directly to their |
68 | respective bitstrings (7 and 6), we simply test for D5 being 0 or 1. |
69 | This is the significance of the test '(value & 0x20) ? 0 : 1' in the code. |
70 | |
71 | NOTE: Consult the patent application for more specific information, in |
72 | particular *why* the address $01FE will be placed on the address |
73 | bus after both the JSR and RTS opcodes. |
74 | |
75 | @author Stephen Anthony; with ideas/research from Christian Speckner and |
76 | alex_79 and TomSon (of AtariAge) |
77 | */ |
78 | class CartridgeFE : public Cartridge |
79 | { |
80 | friend class CartridgeFEWidget; |
81 | |
82 | public: |
83 | /** |
84 | Create a new cartridge using the specified image |
85 | |
86 | @param image Pointer to the ROM image |
87 | @param size The size of the ROM image |
88 | @param md5 The md5sum of the ROM image |
89 | @param settings A reference to the various settings (read-only) |
90 | */ |
91 | CartridgeFE(const ByteBuffer& image, size_t size, const string& md5, |
92 | const Settings& settings); |
93 | virtual ~CartridgeFE() = default; |
94 | |
95 | public: |
96 | /** |
97 | Reset device to its power-on state |
98 | */ |
99 | void reset() override; |
100 | |
101 | /** |
102 | Install cartridge in the specified system. Invoked by the system |
103 | when the cartridge is attached to it. |
104 | |
105 | @param system The system the device should install itself in |
106 | */ |
107 | void install(System& system) override; |
108 | |
109 | /** |
110 | Install pages for the specified bank in the system. |
111 | |
112 | @param bank The bank that should be installed in the system |
113 | */ |
114 | bool bank(uInt16 bank) override; |
115 | |
116 | /** |
117 | Get the current bank. |
118 | |
119 | @param address The address to use when querying the bank |
120 | */ |
121 | uInt16 getBank(uInt16 address = 0) const override; |
122 | |
123 | /** |
124 | Query the number of banks supported by the cartridge. |
125 | */ |
126 | uInt16 bankCount() const override; |
127 | |
128 | /** |
129 | Patch the cartridge ROM. |
130 | |
131 | @param address The ROM address to patch |
132 | @param value The value to place into the address |
133 | @return Success or failure of the patch operation |
134 | */ |
135 | bool patch(uInt16 address, uInt8 value) override; |
136 | |
137 | /** |
138 | Access the internal ROM image for this cartridge. |
139 | |
140 | @param size Set to the size of the internal ROM image data |
141 | @return A pointer to the internal ROM image data |
142 | */ |
143 | const uInt8* getImage(size_t& size) const override; |
144 | |
145 | /** |
146 | Save the current state of this cart to the given Serializer. |
147 | |
148 | @param out The Serializer object to use |
149 | @return False on any errors, else true |
150 | */ |
151 | bool save(Serializer& out) const override; |
152 | |
153 | /** |
154 | Load the current state of this cart from the given Serializer. |
155 | |
156 | @param in The Serializer object to use |
157 | @return False on any errors, else true |
158 | */ |
159 | bool load(Serializer& in) override; |
160 | |
161 | /** |
162 | Get a descriptor for the device name (used in error checking). |
163 | |
164 | @return The name of the object |
165 | */ |
166 | string name() const override { return "CartridgeFE" ; } |
167 | |
168 | #ifdef DEBUGGER_SUPPORT |
169 | /** |
170 | Get debugger widget responsible for accessing the inner workings |
171 | of the cart. |
172 | */ |
173 | CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, |
174 | const GUI::Font& nfont, int x, int y, int w, int h) override |
175 | { |
176 | return new CartridgeFEWidget(boss, lfont, nfont, x, y, w, h, *this); |
177 | } |
178 | #endif |
179 | |
180 | public: |
181 | /** |
182 | Get the byte at the specified address. |
183 | |
184 | @return The byte at the specified address |
185 | */ |
186 | uInt8 peek(uInt16 address) override; |
187 | |
188 | /** |
189 | Change the byte at the specified address to the given value. |
190 | |
191 | @param address The address where the value should be stored |
192 | @param value The value to be stored at the address |
193 | @return True if the poke changed the device address space, else false |
194 | */ |
195 | bool poke(uInt16 address, uInt8 value) override; |
196 | |
197 | private: |
198 | /** |
199 | Perform bankswitch when necessary, by monitoring for $01FE |
200 | on the address bus and getting the bank number from the data bus. |
201 | */ |
202 | void checkBankSwitch(uInt16 address, uInt8 value); |
203 | |
204 | private: |
205 | // The 8K ROM image of the cartridge |
206 | std::array<uInt8, 8_KB> myImage; |
207 | |
208 | // Indicates the offset into the ROM image (aligns to current bank) |
209 | uInt16 myBankOffset; |
210 | |
211 | // Whether previous address by peek/poke equals $01FE (hotspot) |
212 | bool myLastAccessWasFE; |
213 | |
214 | private: |
215 | // Following constructors and assignment operators not supported |
216 | CartridgeFE() = delete; |
217 | CartridgeFE(const CartridgeFE&) = delete; |
218 | CartridgeFE(CartridgeFE&&) = delete; |
219 | CartridgeFE& operator=(const CartridgeFE&) = delete; |
220 | CartridgeFE& operator=(CartridgeFE&&) = delete; |
221 | }; |
222 | |
223 | #endif |
224 | |