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 CARTRIDGECM_HXX
19#define CARTRIDGECM_HXX
20
21class CompuMate;
22class System;
23
24#include "bspf.hxx"
25#include "Cart.hxx"
26#ifdef DEBUGGER_SUPPORT
27 #include "CartCMWidget.hxx"
28#endif
29
30/**
31 FIXME: This scheme is not yet fully implemented. In particular, loading
32 from and saving to the cassette is completely missing.
33
34 Cartridge class used for SpectraVideo CompuMate bankswitched games.
35
36 This is more than just a cartridge mapper - it's also a "computer" add-on.
37 There's two 8K EPROMs soldered on top of each other. There's two short
38 wires with DB-9's on them which you plug into the two controller ports.
39 A 42 or so key membrane keyboard with audio in and audio out, and 2K of RAM.
40
41 There are 4 4K banks selectable at $1000 - $1FFF, and 2K RAM at
42 $1800 - $1FFF (R/W 'line' is available at SWCHA D5, so there's no separate
43 read and write ports).
44
45 Bankswitching is done though the controller ports
46 SWCHA: D7 = Audio input from tape player
47 D6 = Audio out to tape player and 4017 CLK
48 1 -> increase key column (0 to 9)
49 D5 = 4017 RST, and RAM direction. (high = write, low = read)
50 1 -> reset key column to 0 (if D4 = 0)
51 0 -> enable RAM writing (if D4 = 1)
52 D4 = RAM enable: 1 = disable RAM, 0 = enable RAM
53 D3 = keyboard row 3 input (0 = key pressed)
54 D2 = keyboard row 1 input (0 = key pressed)
55 D1 = bank select high bit
56 D0 = bank select low bit
57
58 INPT0: D7 = FUNC key input (0 on startup / 1 = key pressed)
59 INPT1: D7 = always HIGH input (pulled high thru 20K resistor)
60 INPT2: D7 = always HIGH input (pulled high thru 20K resistor)
61 INPT3: D7 = SHIFT key input (0 on startup / 1 = key pressed)
62 INPT4: D7 = keyboard row 0 input (0 = key pressed)
63 INPT5: D7 = keyboard row 2 input (0 = key pressed)
64
65 The keyboard's composed of a 4017 1 of 10 counter, driving the 10 columns of
66 the keyboard. It has 4 rows. The 4 row outputs are buffered by inverters.
67
68 Bit 5 of portA controls the reset line on the 4017. Pulling it high will reset
69 scanning to column 0. Pulling it low will allow the counter to be clocked.
70
71 Bit 6 of portA clocks the 4017. Each rising edge advances the column one
72 count.
73
74 There's 10 columns labelled 0-9, and 4 rows, labelled 0-3.
75
76 Column
77
78 0 1 2 3 4 5 6 7 8 9
79 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
80 | 7 | | 6 | | 8 | | 2 | | 3 | | 0 | | 9 | | 5 | | 1 | | 4 | 0
81 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
82 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
83 | U | | Y | | I | | W | | E | | P | | O | | T | | Q | | R | 1
84 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ Row
85 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
86 | J | | H | | K | | S | | D | |ent| | L | | G | | A | | F | 2
87 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
88 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
89 | M | | N | | < | | X | | C | |spc| | > | | B | | Z | | V | 3
90 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+
91
92 Function and Shift are separate keys that are read by 2 of the paddle inputs.
93 These two buttons pull the specific paddle input low when pressed.
94
95 Because the inputs are inverted, a low indicates a pressed button, and a high
96 is an unpressed one.
97
98 The audio input/output are designed to drive a tape player. The audio output is
99 buffered through an inverter and 2 resistors and a capacitor to reduce the level
100 to feed it into the tape player.
101
102 The audio input is passed through a .1uf capacitor and is pulled to 1/2 supply
103 by two 20K resistors, then it goes through a hex inverting schmitt trigger to
104 square it up. This then runs into bit 7 of portA.
105
106 This code was heavily borrowed from z26.
107
108 @author Stephen Anthony & z26 team
109*/
110class CartridgeCM : public Cartridge
111{
112 friend class CartridgeCMWidget;
113
114 public:
115 /**
116 Create a new cartridge using the specified image
117
118 @param image Pointer to the ROM image
119 @param size The size of the ROM image
120 @param md5 The md5sum of the ROM image
121 @param settings A reference to the various settings (read-only)
122 */
123 CartridgeCM(const ByteBuffer& image, size_t size, const string& md5,
124 const Settings& settings);
125 virtual ~CartridgeCM() = default;
126
127 public:
128 /**
129 Reset device to its power-on state
130 */
131 void reset() override;
132
133 /**
134 Install cartridge in the specified system. Invoked by the system
135 when the cartridge is attached to it.
136
137 @param system The system the device should install itself in
138 */
139 void install(System& system) override;
140
141 /**
142 Install pages for the specified bank in the system.
143
144 @param bank The bank that should be installed in the system
145 */
146 bool bank(uInt16 bank) override;
147
148 /**
149 Get the current bank.
150
151 @param address The address to use when querying the bank
152 */
153 uInt16 getBank(uInt16 address = 0) const override;
154
155 /**
156 Query the number of banks supported by the cartridge.
157 */
158 uInt16 bankCount() const override;
159
160 /**
161 Patch the cartridge ROM.
162
163 @param address The ROM address to patch
164 @param value The value to place into the address
165 @return Success or failure of the patch operation
166 */
167 bool patch(uInt16 address, uInt8 value) override;
168
169 /**
170 Access the internal ROM image for this cartridge.
171
172 @param size Set to the size of the internal ROM image data
173 @return A pointer to the internal ROM image data
174 */
175 const uInt8* getImage(size_t& size) const override;
176
177 /**
178 Save the current state of this cart to the given Serializer.
179
180 @param out The Serializer object to use
181 @return False on any errors, else true
182 */
183 bool save(Serializer& out) const override;
184
185 /**
186 Load the current state of this cart from the given Serializer.
187
188 @param in The Serializer object to use
189 @return False on any errors, else true
190 */
191 bool load(Serializer& in) override;
192
193 /**
194 Get a descriptor for the device name (used in error checking).
195
196 @return The name of the object
197 */
198 string name() const override { return "CartridgeCM"; }
199
200 #ifdef DEBUGGER_SUPPORT
201 /**
202 Get debugger widget responsible for accessing the inner workings
203 of the cart.
204 */
205 CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont,
206 const GUI::Font& nfont, int x, int y, int w, int h) override
207 {
208 return new CartridgeCMWidget(boss, lfont, nfont, x, y, w, h, *this);
209 }
210 #endif
211
212 public:
213 /**
214 Get the byte at the specified address.
215
216 @return The byte at the specified address
217 */
218 uInt8 peek(uInt16 address) override;
219
220 /**
221 Change the byte at the specified address to the given value
222
223 @param address The address where the value should be stored
224 @param value The value to be stored at the address
225 @return True if the poke changed the device address space, else false
226 */
227 bool poke(uInt16 address, uInt8 value) override;
228
229 /**
230 Inform the cartridge about the parent CompuMate controller
231 */
232 void setCompuMate(shared_ptr<CompuMate>& cmate) { myCompuMate = cmate; }
233
234 /**
235 Get the current keyboard column
236
237 @return The column referenced by SWCHA D6 and D5
238 */
239 uInt8 column() const;
240
241 private:
242 // The CompuMate device which interacts with this cartridge
243 shared_ptr<CompuMate> myCompuMate;
244
245 // The 16K ROM image of the cartridge
246 std::array<uInt8, 16_KB> myImage;
247
248 // The 2K of RAM
249 std::array<uInt8, 2_KB> myRAM;
250
251 // Current copy of SWCHA (controls ROM/RAM accesses)
252 uInt8 mySWCHA;
253
254 // Indicates the offset into the ROM image (aligns to current bank)
255 uInt16 myBankOffset;
256
257private:
258 // Following constructors and assignment operators not supported
259 CartridgeCM() = delete;
260 CartridgeCM(const CartridgeCM&) = delete;
261 CartridgeCM(CartridgeCM&&) = delete;
262 CartridgeCM& operator=(const CartridgeCM&) = delete;
263 CartridgeCM& operator=(CartridgeCM&&) = delete;
264};
265
266#endif
267