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
21class 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*/
78class 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