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 CARTRIDGE_DPC_PLUS_HXX |
19 | #define CARTRIDGE_DPC_PLUS_HXX |
20 | |
21 | class System; |
22 | |
23 | #include "Thumbulator.hxx" |
24 | #ifdef DEBUGGER_SUPPORT |
25 | #include "CartDPCPlusWidget.hxx" |
26 | #endif |
27 | |
28 | #include "bspf.hxx" |
29 | #include "Cart.hxx" |
30 | |
31 | /** |
32 | Cartridge class used for DPC+, derived from Pitfall II. There are six 4K |
33 | program banks, a 4K display bank, 1K frequency table and the DPC chip. |
34 | DPC chip access is mapped to $1000 - $1080 ($1000 - $103F is read port, |
35 | $1040 - $107F is write port). |
36 | Program banks are accessible by read/write to $1FF6 - $1FFB. |
37 | |
38 | FIXME: THIS NEEDS TO BE UPDATED |
39 | |
40 | For complete details on the DPC chip see David P. Crane's United States |
41 | Patent Number 4,644,495. |
42 | |
43 | @authors Darrell Spice Jr, Fred Quimby, Stephen Anthony, Bradford W. Mott |
44 | */ |
45 | class CartridgeDPCPlus : public Cartridge |
46 | { |
47 | friend class CartridgeDPCPlusWidget; |
48 | friend class CartridgeRamDPCPlusWidget; |
49 | |
50 | public: |
51 | /** |
52 | Create a new cartridge using the specified image |
53 | |
54 | @param image Pointer to the ROM image |
55 | @param size The size of the ROM image |
56 | @param md5 The md5sum of the ROM image |
57 | @param settings A reference to the various settings (read-only) |
58 | */ |
59 | CartridgeDPCPlus(const ByteBuffer& image, size_t size, const string& md5, |
60 | const Settings& settings); |
61 | virtual ~CartridgeDPCPlus() = default; |
62 | |
63 | public: |
64 | /** |
65 | Reset device to its power-on state |
66 | */ |
67 | void reset() override; |
68 | |
69 | /** |
70 | Notification method invoked by the system when the console type |
71 | has changed. We need this to inform the Thumbulator that the |
72 | timing has changed. |
73 | |
74 | @param timing Enum representing the new console type |
75 | */ |
76 | void consoleChanged(ConsoleTiming timing) 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 | Install pages for the specified bank in the system. |
88 | |
89 | @param bank The bank that should be installed in the system |
90 | */ |
91 | bool bank(uInt16 bank) override; |
92 | |
93 | /** |
94 | Get the current bank. |
95 | |
96 | @param address The address to use when querying the bank |
97 | */ |
98 | uInt16 getBank(uInt16 address = 0) const override; |
99 | |
100 | /** |
101 | Query the number of banks supported by the cartridge. |
102 | */ |
103 | uInt16 bankCount() const override; |
104 | |
105 | /** |
106 | Patch the cartridge ROM. |
107 | |
108 | @param address The ROM address to patch |
109 | @param value The value to place into the address |
110 | @return Success or failure of the patch operation |
111 | */ |
112 | bool patch(uInt16 address, uInt8 value) override; |
113 | |
114 | /** |
115 | Access the internal ROM image for this cartridge. |
116 | |
117 | @param size Set to the size of the internal ROM image data |
118 | @return A pointer to the internal ROM image data |
119 | */ |
120 | const uInt8* getImage(size_t& size) const override; |
121 | |
122 | /** |
123 | Save the current state of this cart to the given Serializer. |
124 | |
125 | @param out The Serializer object to use |
126 | @return False on any errors, else true |
127 | */ |
128 | bool save(Serializer& out) const override; |
129 | |
130 | /** |
131 | Load the current state of this cart from the given Serializer. |
132 | |
133 | @param in The Serializer object to use |
134 | @return False on any errors, else true |
135 | */ |
136 | bool load(Serializer& in) override; |
137 | |
138 | /** |
139 | Get a descriptor for the device name (used in error checking). |
140 | |
141 | @return The name of the object |
142 | */ |
143 | string name() const override { return "CartridgeDPC+" ; } |
144 | |
145 | #ifdef DEBUGGER_SUPPORT |
146 | /** |
147 | Get debugger widget responsible for accessing the inner workings |
148 | of the cart. |
149 | */ |
150 | CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, |
151 | const GUI::Font& nfont, int x, int y, int w, int h) override |
152 | { |
153 | return new CartridgeDPCPlusWidget(boss, lfont, nfont, x, y, w, h, *this); |
154 | } |
155 | #endif |
156 | |
157 | public: |
158 | /** |
159 | Get the byte at the specified address. |
160 | |
161 | @return The byte at the specified address |
162 | */ |
163 | uInt8 peek(uInt16 address) override; |
164 | |
165 | /** |
166 | Change the byte at the specified address to the given value |
167 | |
168 | @param address The address where the value should be stored |
169 | @param value The value to be stored at the address |
170 | @return True if the poke changed the device address space, else false |
171 | */ |
172 | bool poke(uInt16 address, uInt8 value) override; |
173 | |
174 | private: |
175 | /** |
176 | Sets the initial state of the DPC pointers and RAM |
177 | */ |
178 | void setInitialState(); |
179 | |
180 | /** |
181 | Clocks the random number generator to move it to its next state |
182 | */ |
183 | void clockRandomNumberGenerator(); |
184 | |
185 | /** |
186 | Clocks the random number generator to move it to its prior state |
187 | */ |
188 | void priorClockRandomNumberGenerator(); |
189 | |
190 | /** |
191 | Updates any data fetchers in music mode based on the number of |
192 | CPU cycles which have passed since the last update. |
193 | */ |
194 | void updateMusicModeDataFetchers(); |
195 | |
196 | /** |
197 | Call Special Functions |
198 | */ |
199 | void callFunction(uInt8 value); |
200 | |
201 | private: |
202 | // The ROM image and size |
203 | std::array<uInt8, 32_KB> myImage; |
204 | size_t mySize; |
205 | |
206 | // Pointer to the 24K program ROM image of the cartridge |
207 | uInt8* myProgramImage; |
208 | |
209 | // Pointer to the 4K display ROM image of the cartridge |
210 | uInt8* myDisplayImage; |
211 | |
212 | // The DPC 8k RAM image, used as: |
213 | // 3K DPC+ driver |
214 | // 4K Display Data |
215 | // 1K Frequency Data |
216 | std::array<uInt8, 8_KB> myDPCRAM; |
217 | |
218 | // Pointer to the Thumb ARM emulator object |
219 | unique_ptr<Thumbulator> myThumbEmulator; |
220 | |
221 | // Pointer to the 1K frequency table |
222 | uInt8* myFrequencyImage; |
223 | |
224 | // The top registers for the data fetchers |
225 | std::array<uInt8, 8> myTops; |
226 | |
227 | // The bottom registers for the data fetchers |
228 | std::array<uInt8, 8> myBottoms; |
229 | |
230 | // The counter registers for the data fetchers |
231 | std::array<uInt16, 8> myCounters; |
232 | |
233 | // The counter registers for the fractional data fetchers |
234 | std::array<uInt32, 8> myFractionalCounters; |
235 | |
236 | // The fractional increments for the data fetchers |
237 | std::array<uInt8, 8> myFractionalIncrements; |
238 | |
239 | // The Fast Fetcher Enabled flag |
240 | bool myFastFetch; |
241 | |
242 | // Flags that last byte peeked was A9 (LDA #) |
243 | bool myLDAimmediate; |
244 | |
245 | // Parameter for special functions |
246 | std::array<uInt8, 8> myParameter; |
247 | |
248 | // Parameter pointer for special functions |
249 | uInt8 myParameterPointer; |
250 | |
251 | // The music mode counters |
252 | std::array<uInt32, 3> myMusicCounters; |
253 | |
254 | // The music frequency |
255 | std::array<uInt32, 3> myMusicFrequencies; |
256 | |
257 | // The music waveforms |
258 | std::array<uInt16, 3> myMusicWaveforms; |
259 | |
260 | // The random number generator register |
261 | uInt32 myRandomNumber; |
262 | |
263 | // System cycle count from when the last update to music data fetchers occurred |
264 | uInt64 myAudioCycles; |
265 | |
266 | // System cycle count when the last Thumbulator::run() occurred |
267 | uInt64 myARMCycles; |
268 | |
269 | // Fractional DPC music OSC clocks unused during the last update |
270 | double myFractionalClocks; |
271 | |
272 | // Indicates the offset into the ROM image (aligns to current bank) |
273 | uInt16 myBankOffset; |
274 | |
275 | // Older DPC+ driver code had different behaviour wrt the mask used |
276 | // to retrieve 'DFxFRACLOW' (fractional data pointer low byte) |
277 | // ROMs built with an old DPC+ driver and using the newer mask can |
278 | // result in 'jittering' in the playfield display |
279 | // For current versions, this is 0x0F00FF; older versions need 0x0F0000 |
280 | uInt32 myFractionalLowMask; |
281 | |
282 | private: |
283 | // Following constructors and assignment operators not supported |
284 | CartridgeDPCPlus() = delete; |
285 | CartridgeDPCPlus(const CartridgeDPCPlus&) = delete; |
286 | CartridgeDPCPlus(CartridgeDPCPlus&&) = delete; |
287 | CartridgeDPCPlus& operator=(const CartridgeDPCPlus&) = delete; |
288 | CartridgeDPCPlus& operator=(CartridgeDPCPlus&&) = delete; |
289 | }; |
290 | |
291 | #endif |
292 | |