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 CARTRIDGE4A50_HXX
19#define CARTRIDGE4A50_HXX
20
21class System;
22
23#include "bspf.hxx"
24#include "Cart.hxx"
25#ifdef DEBUGGER_SUPPORT
26 #include "Cart4A50Widget.hxx"
27#endif
28
29/**
30 Bankswitching method as defined/created by John Payson (aka Supercat),
31 documented at https://stella-emu.github.io/4A50.html.
32
33 In this bankswitching scheme the 2600's 4K cartridge address space
34 is broken into four segments. The first 2K segment accesses any 2K
35 region of RAM, or of the first 32K of ROM. The second 1.5K segment
36 accesses the first 1.5K of any 2K region of RAM, or of the last 32K
37 of ROM. The 3rd 256 byte segment points to any 256 byte page of
38 RAM or ROM. The last 256 byte segment always points to the last 256
39 bytes of ROM.
40
41 Because of the complexity of this scheme, the cart reports having
42 only one actual bank, in which pieces of it can be swapped out in
43 many different ways. It contains so many hotspots and possibilities
44 for the ROM address space to change that we just consider the bank to
45 have changed on every poke operation (for any RAM) or an actual bankswitch.
46
47 NOTE: This scheme hasn't been fully implemented, and may never be (there
48 is only one test ROM, and it hasn't been extended any further).
49 In particular, the following functionality is missing:
50 - hires helper functions
51 - 1E00 page wrap
52
53 @author Eckhard Stolberg & Stephen Anthony
54*/
55class Cartridge4A50 : public Cartridge
56{
57 friend class Cartridge4A50Widget;
58
59 public:
60 /**
61 Create a new cartridge using the specified image
62
63 @param image Pointer to the ROM image
64 @param size The size of the ROM image
65 @param md5 The md5sum of the ROM image
66 @param settings A reference to the various settings (read-only)
67 */
68 Cartridge4A50(const ByteBuffer& image, size_t size, const string& md5,
69 const Settings& settings);
70 virtual ~Cartridge4A50() = default;
71
72 public:
73 /**
74 Reset cartridge to its power-on state
75 */
76 void reset() override;
77
78 /**
79 Install cartridge in the specified system. Invoked by the system
80 when the cartridge is attached to it.
81
82 @param system The system the device should install itself in
83 */
84 void install(System& system) override;
85
86 /**
87 Patch the cartridge ROM.
88
89 @param address The ROM address to patch
90 @param value The value to place into the address
91 @return Success or failure of the patch operation
92 */
93 bool patch(uInt16 address, uInt8 value) override;
94
95 /**
96 Access the internal ROM image for this cartridge.
97
98 @param size Set to the size of the internal ROM image data
99 @return A pointer to the internal ROM image data
100 */
101 const uInt8* getImage(size_t& size) const override;
102
103 /**
104 Save the current state of this cart to the given Serializer.
105
106 @param out The Serializer object to use
107 @return False on any errors, else true
108 */
109 bool save(Serializer& out) const override;
110
111 /**
112 Load the current state of this cart from the given Serializer.
113
114 @param in The Serializer object to use
115 @return False on any errors, else true
116 */
117 bool load(Serializer& in) override;
118
119 /**
120 Get a descriptor for the device name (used in error checking).
121
122 @return The name of the object
123 */
124 string name() const override { return "Cartridge4A50"; }
125
126 #ifdef DEBUGGER_SUPPORT
127 /**
128 Get debugger widget responsible for accessing the inner workings
129 of the cart.
130 */
131 CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont,
132 const GUI::Font& nfont, int x, int y, int w, int h) override
133 {
134 return new Cartridge4A50Widget(boss, lfont, nfont, x, y, w, h, *this);
135 }
136 #endif
137
138 public:
139 /**
140 Get the byte at the specified address.
141
142 @return The byte at the specified address
143 */
144 uInt8 peek(uInt16 address) override;
145
146 /**
147 Change the byte at the specified address to the given value
148
149 @param address The address where the value should be stored
150 @param value The value to be stored at the address
151 @return True if the poke changed the device address space, else false
152 */
153 bool poke(uInt16 address, uInt8 value) override;
154
155 private:
156 /**
157 Query the given address type for the associated disassembly flags.
158
159 @param address The address to query
160 */
161 uInt8 getAccessFlags(uInt16 address) const override;
162 /**
163 Change the given address to use the given disassembly flags.
164
165 @param address The address to modify
166 @param flags A bitfield of DisasmType directives for the given address
167 */
168 void setAccessFlags(uInt16 address, uInt8 flags) override;
169
170 /**
171 Check all possible hotspots
172 */
173 void checkBankSwitch(uInt16 address, uInt8 value);
174
175 /**
176 Methods to perform all the ways that banks can be switched
177 */
178 inline void bankROMLower(uInt16 value)
179 {
180 myIsRomLow = true;
181 mySliceLow = value << 11;
182 myBankChanged = true;
183 }
184
185 inline void bankRAMLower(uInt16 value)
186 {
187 myIsRomLow = false;
188 mySliceLow = value << 11;
189 myBankChanged = true;
190 }
191
192 inline void bankROMMiddle(uInt16 value)
193 {
194 myIsRomMiddle = true;
195 mySliceMiddle = value << 11;
196 myBankChanged = true;
197 }
198
199 inline void bankRAMMiddle(uInt16 value)
200 {
201 myIsRomMiddle = false;
202 mySliceMiddle = value << 11;
203 myBankChanged = true;
204 }
205
206 inline void bankROMHigh(uInt16 value)
207 {
208 myIsRomHigh = true;
209 mySliceHigh = value << 8;
210 myBankChanged = true;
211 }
212
213 inline void bankRAMHigh(uInt16 value)
214 {
215 myIsRomHigh = false;
216 mySliceHigh = value << 8;
217 myBankChanged = true;
218 }
219
220 private:
221 // The 128K ROM image of the cartridge
222 std::array<uInt8, 128_KB> myImage;
223
224 // The 32K of RAM on the cartridge
225 std::array<uInt8, 32_KB> myRAM;
226
227 // (Actual) Size of the ROM image
228 size_t mySize;
229
230 // Indicates the slice mapped into each of the three segments
231 uInt16 mySliceLow; /* index pointer for $1000-$17ff slice */
232 uInt16 mySliceMiddle; /* index pointer for $1800-$1dff slice */
233 uInt16 mySliceHigh; /* index pointer for $1e00-$1eff slice */
234
235 // Indicates whether the given slice is mapped to ROM or RAM
236 bool myIsRomLow; /* true = ROM -- false = RAM at $1000-$17ff */
237 bool myIsRomMiddle; /* true = ROM -- false = RAM at $1800-$1dff */
238 bool myIsRomHigh; /* true = ROM -- false = RAM at $1e00-$1eFF */
239
240 // The previous address and data values (from peek and poke)
241 uInt16 myLastAddress;
242 uInt8 myLastData;
243
244 private:
245 // Following constructors and assignment operators not supported
246 Cartridge4A50() = delete;
247 Cartridge4A50(const Cartridge4A50&) = delete;
248 Cartridge4A50(Cartridge4A50&&) = delete;
249 Cartridge4A50& operator=(const Cartridge4A50&) = delete;
250 Cartridge4A50& operator=(Cartridge4A50&&) = delete;
251};
252
253#endif
254