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 CARTRIDGEWD_HXX |
19 | #define CARTRIDGEWD_HXX |
20 | |
21 | class System; |
22 | |
23 | #include "bspf.hxx" |
24 | #include "Cart.hxx" |
25 | #ifdef DEBUGGER_SUPPORT |
26 | #include "CartWDWidget.hxx" |
27 | #endif |
28 | |
29 | /** |
30 | This is the cartridge class for a "Wickstead Design" prototype cart. |
31 | The ROM has 64 bytes of RAM. |
32 | In this bankswitching scheme the 2600's 4K cartridge address space |
33 | is broken into four 1K segments. The desired arrangement of 1K slices |
34 | is selected by accessing $30 - $3F of TIA address space. The slices |
35 | are mapped into all 4 segments at once as follows: |
36 | |
37 | $0030, $0038: 0,0,1,3 |
38 | $0031, $0039: 0,1,2,3 |
39 | $0032, $003A: 4,5,6,7 |
40 | $0033, $003B: 7,4,2,3 |
41 | |
42 | $0034, $003C: 0,0,6,7 |
43 | $0035, $003D: 0,1,7,6 |
44 | $0036, $003E: 2,3,4,5 |
45 | $0037, $003F: 6,0,5,1 |
46 | |
47 | |
48 | In the uppermost (third) segment, the byte at $3FC is overwritten by 0. |
49 | |
50 | The 64 bytes of RAM are accessible at $1000 - $103F (read port) and |
51 | $1040 - $107F (write port). Because the RAM takes 128 bytes of address |
52 | space, the range $1000 - $107F of segment 0 ROM will never be available. |
53 | |
54 | @author Stephen Anthony |
55 | */ |
56 | class CartridgeWD : public Cartridge |
57 | { |
58 | friend class CartridgeWDWidget; |
59 | |
60 | public: |
61 | /** |
62 | Create a new cartridge using the specified image |
63 | |
64 | @param image Pointer to the ROM image |
65 | @param size The size of the ROM image |
66 | @param md5 The md5sum of the ROM image |
67 | @param settings A reference to the various settings (read-only) |
68 | */ |
69 | CartridgeWD(const ByteBuffer& image, size_t size, const string& md5, |
70 | const Settings& settings); |
71 | virtual ~CartridgeWD() = default; |
72 | |
73 | public: |
74 | /** |
75 | Reset device to its power-on state |
76 | */ |
77 | void reset() override; |
78 | |
79 | /** |
80 | Install cartridge in the specified system. Invoked by the system |
81 | when the cartridge is attached to it. |
82 | |
83 | @param system The system the device should install itself in |
84 | */ |
85 | void install(System& system) override; |
86 | |
87 | /** |
88 | Install pages for the specified bank in the system. |
89 | |
90 | @param bank The bank that should be installed in the system |
91 | */ |
92 | bool bank(uInt16 bank) override; |
93 | |
94 | /** |
95 | Get the current bank. |
96 | |
97 | @param address The address to use when querying the bank |
98 | */ |
99 | uInt16 getBank(uInt16 address = 0) const override; |
100 | |
101 | /** |
102 | Query the number of banks supported by the cartridge. |
103 | */ |
104 | uInt16 bankCount() const override; |
105 | |
106 | /** |
107 | Patch the cartridge ROM. |
108 | |
109 | @param address The ROM address to patch |
110 | @param value The value to place into the address |
111 | @return Success or failure of the patch operation |
112 | */ |
113 | bool patch(uInt16 address, uInt8 value) override; |
114 | |
115 | /** |
116 | Access the internal ROM image for this cartridge. |
117 | |
118 | @param size Set to the size of the internal ROM image data |
119 | @return A pointer to the internal ROM image data |
120 | */ |
121 | const uInt8* getImage(size_t& size) const override; |
122 | |
123 | /** |
124 | Save the current state of this cart to the given Serializer. |
125 | |
126 | @param out The Serializer object to use |
127 | @return False on any errors, else true |
128 | */ |
129 | bool save(Serializer& out) const override; |
130 | |
131 | /** |
132 | Load the current state of this cart from the given Serializer. |
133 | |
134 | @param in The Serializer object to use |
135 | @return False on any errors, else true |
136 | */ |
137 | bool load(Serializer& in) override; |
138 | |
139 | /** |
140 | Get a descriptor for the device name (used in error checking). |
141 | |
142 | @return The name of the object |
143 | */ |
144 | string name() const override { return "CartridgeWD" ; } |
145 | |
146 | #ifdef DEBUGGER_SUPPORT |
147 | /** |
148 | Get debugger widget responsible for accessing the inner workings |
149 | of the cart. |
150 | */ |
151 | CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, |
152 | const GUI::Font& nfont, int x, int y, int w, int h) override |
153 | { |
154 | return new CartridgeWDWidget(boss, lfont, nfont, x, y, w, h, *this); |
155 | } |
156 | #endif |
157 | |
158 | public: |
159 | /** |
160 | Get the byte at the specified address. |
161 | |
162 | @return The byte at the specified address |
163 | */ |
164 | uInt8 peek(uInt16 address) override; |
165 | |
166 | /** |
167 | Change the byte at the specified address to the given value. |
168 | |
169 | @param address The address where the value should be stored |
170 | @param value The value to be stored at the address |
171 | @return True if the poke changed the device address space, else false |
172 | */ |
173 | bool poke(uInt16 address, uInt8 value) override; |
174 | |
175 | private: |
176 | /** |
177 | Install the specified slice for segment zero. |
178 | |
179 | @param slice The slice to map into the segment |
180 | */ |
181 | void segmentZero(uInt8 slice); |
182 | |
183 | /** |
184 | Install the specified slice for segment one. |
185 | |
186 | @param slice The slice to map into the segment |
187 | */ |
188 | void segmentOne(uInt8 slice); |
189 | |
190 | /** |
191 | Install the specified slice for segment two. |
192 | |
193 | @param slice The slice to map into the segment |
194 | */ |
195 | void segmentTwo(uInt8 slice); |
196 | |
197 | /** |
198 | Install the specified slice for segment three. |
199 | Note that this method also takes care of setting one byte to 0. |
200 | |
201 | @param slice The slice to map into the segment |
202 | */ |
203 | void segmentThree(uInt8 slice); |
204 | |
205 | private: |
206 | // The 8K ROM image of the cartridge |
207 | std::array<uInt8, 8_KB> myImage; |
208 | |
209 | // Indicates the actual size of the ROM image (either 8K or 8K + 3) |
210 | size_t mySize; |
211 | |
212 | // The 64 bytes RAM of the cartridge |
213 | std::array<uInt8, 64> myRAM; |
214 | |
215 | // The 1K ROM mirror of segment 3 (sometimes contains extra 3 bytes) |
216 | std::array<uInt8, 1_KB> mySegment3; |
217 | |
218 | // Indicates the offset for each of the four segments |
219 | std::array<uInt16, 4> myOffset; |
220 | |
221 | // Indicates the cycle at which a bankswitch was initiated |
222 | uInt64 myCyclesAtBankswitchInit; |
223 | |
224 | // Indicates the bank we wish to switch to in the future |
225 | uInt16 myPendingBank; |
226 | |
227 | // Indicates which bank is currently active |
228 | uInt16 myCurrentBank; |
229 | |
230 | // The arrangement of banks to use on each hotspot read |
231 | struct BankOrg { |
232 | uInt8 zero, one, two, three; |
233 | }; |
234 | static BankOrg ourBankOrg[8]; |
235 | |
236 | private: |
237 | // Following constructors and assignment operators not supported |
238 | CartridgeWD() = delete; |
239 | CartridgeWD(const CartridgeWD&) = delete; |
240 | CartridgeWD(CartridgeWD&&) = delete; |
241 | CartridgeWD& operator=(const CartridgeWD&) = delete; |
242 | CartridgeWD& operator=(CartridgeWD&&) = delete; |
243 | }; |
244 | |
245 | #endif |
246 | |