1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4
5 Commodore Magic Voice cartridge emulation
6
7 **********************************************************************/
8
9 /*
10
11 LA05-123 Pinout
12 ---------------
13 _____ _____
14 NEXTP 1 |* \_/ | 28 +5V
15 PD0 2 | | 27 _ROML2
16 PD1 3 | | 26 _ROML
17 PD2 4 | | 25 _I/O2
18 PD3 5 | | 24 _GAME
19 CLEAR 6 | | 23 PHI2
20 _RAM/EPROM 7 | LA05-123 | 22 _ROMH2
21 PB5 8 | LA05-124 | 21 _ROMH
22 PB6 9 | | 20 CLOCK
23 _6525 10 | | 19 SDO
24 _EPROM 11 | | 18 NEXTS
25 CA12 12 | | 17 _DA/CA
26 CA14 13 | | 16 CA15
27 GND 14 |_____________| 15 CA13
28
29
30 http://www.stefan-uhlmann.de/cbm/MVM/index.html
31
32 */
33
34 /*
35
36 TODO:
37
38 - T6721A speech synthesis
39
40 */
41
42 #include "emu.h"
43 #include "magic_voice.h"
44 #include "speaker.h"
45
46
47
48 //**************************************************************************
49 // MACROS / CONSTANTS
50 //**************************************************************************
51
52 #define T6721A_TAG "u5"
53 #define MOS6525_TAG "u2"
54 #define CD40105_TAG "u1"
55
56 #define A12 BIT(offset, 12)
57 #define A13 BIT(offset, 13)
58 #define A14 BIT(offset, 14)
59 #define A15 BIT(offset, 15)
60 #define PB5 BIT(m_tpi_pb, 5)
61 #define PB6 BIT(m_tpi_pb, 6)
62
63
64
65 //**************************************************************************
66 // DEVICE DEFINITIONS
67 //**************************************************************************
68
69 DEFINE_DEVICE_TYPE(C64_MAGIC_VOICE, c64_magic_voice_cartridge_device, "c64_magic_voice", "C64 Magic Voice cartridge")
70
71
72 //-------------------------------------------------
73 // tpi6525_interface tpi_intf
74 //-------------------------------------------------
75
WRITE_LINE_MEMBER(c64_magic_voice_cartridge_device::tpi_irq_w)76 WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::tpi_irq_w )
77 {
78 m_slot->nmi_w(state);
79 }
80
tpi_pa_r()81 uint8_t c64_magic_voice_cartridge_device::tpi_pa_r()
82 {
83 /*
84
85 bit description
86
87 0
88 1
89 2
90 3
91 4
92 5 J1 _GAME
93 6 T6721 _EOS
94 7 FIFO DIR
95
96 */
97
98 uint8_t data = 0;
99
100 data |= m_exp->game_r(get_offset(m_ca), 1, 1, 1, 0, 0) << 5;
101 data |= m_vslsi->eos_r() << 6;
102 data |= m_fifo->dir_r() << 7;
103
104 return data;
105 }
106
tpi_pa_w(uint8_t data)107 void c64_magic_voice_cartridge_device::tpi_pa_w(uint8_t data)
108 {
109 /*
110
111 bit description
112
113 0 FIFO D0
114 1 FIFO D1
115 2 FIFO D2
116 3 FIFO D3
117 4 FIFO SI
118 5
119 6
120 7
121
122 */
123
124 m_fifo->write(data & 0x0f);
125 m_fifo->si_w(BIT(data, 4));
126 }
127
tpi_pb_r()128 uint8_t c64_magic_voice_cartridge_device::tpi_pb_r()
129 {
130 /*
131
132 bit description
133
134 0
135 1
136 2
137 3
138 4
139 5
140 6
141 7 J1 _EXROM
142
143 */
144
145 uint8_t data = 0;
146
147 data |= m_exp->exrom_r(get_offset(m_ca), 1, 1, 1, 0, 0) << 7;
148
149 return data;
150 }
151
tpi_pb_w(uint8_t data)152 void c64_magic_voice_cartridge_device::tpi_pb_w(uint8_t data)
153 {
154 /*
155
156 bit description
157
158 0 T6721 D0
159 1 T6721 D1
160 2 T6721 D2
161 3 T6721 D3
162 4 T6721 _WR
163 5 LA05-124 pin 8 (DA/CA)
164 6 LA05-124 pin 9 (passthru)
165 7
166
167 */
168
169 if (!BIT(m_tpi_pb, 4) && BIT(data, 4))
170 {
171 m_vslsi->write(data & 0x0f);
172 }
173
174 m_tpi_pb = data;
175 }
176
WRITE_LINE_MEMBER(c64_magic_voice_cartridge_device::tpi_ca_w)177 WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::tpi_ca_w )
178 {
179 m_tpi_pc6 = state;
180 }
181
WRITE_LINE_MEMBER(c64_magic_voice_cartridge_device::tpi_cb_w)182 WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::tpi_cb_w )
183 {
184 m_exrom = state;
185 }
186
187 //-------------------------------------------------
188 // t6721_interface
189 //-------------------------------------------------
190
WRITE_LINE_MEMBER(c64_magic_voice_cartridge_device::phi2_w)191 WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::phi2_w )
192 {
193 if (state)
194 {
195 m_vslsi->di_w(m_pd & 0x01);
196
197 m_pd >>= 1;
198 }
199 }
200
WRITE_LINE_MEMBER(c64_magic_voice_cartridge_device::dtrd_w)201 WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::dtrd_w )
202 {
203 m_fifo->so_w(!state);
204
205 m_pd = m_fifo->read();
206 }
207
WRITE_LINE_MEMBER(c64_magic_voice_cartridge_device::apd_w)208 WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::apd_w )
209 {
210 if (state)
211 {
212 m_fifo->reset();
213 m_pd = 0;
214 }
215 }
216
217
218 //-------------------------------------------------
219 // device_add_mconfig - add device configuration
220 //-------------------------------------------------
221
device_add_mconfig(machine_config & config)222 void c64_magic_voice_cartridge_device::device_add_mconfig(machine_config &config)
223 {
224 TPI6525(config, m_tpi, 0);
225 m_tpi->out_irq_cb().set(FUNC(c64_magic_voice_cartridge_device::tpi_irq_w));
226 m_tpi->in_pa_cb().set(FUNC(c64_magic_voice_cartridge_device::tpi_pa_r));
227 m_tpi->out_pa_cb().set(FUNC(c64_magic_voice_cartridge_device::tpi_pa_w));
228 m_tpi->in_pb_cb().set(FUNC(c64_magic_voice_cartridge_device::tpi_pb_r));
229 m_tpi->out_pb_cb().set(FUNC(c64_magic_voice_cartridge_device::tpi_pb_w));
230 m_tpi->out_ca_cb().set(FUNC(c64_magic_voice_cartridge_device::tpi_ca_w));
231 m_tpi->out_cb_cb().set(FUNC(c64_magic_voice_cartridge_device::tpi_cb_w));
232
233 CD40105(config, m_fifo, 0);
234 m_fifo->in_ready_cb().set(m_tpi, FUNC(tpi6525_device::i3_w));
235
236 SPEAKER(config, "mono").front_center();
237 T6721A(config, m_vslsi, XTAL(640'000));
238 m_vslsi->eos_handler().set(m_tpi, FUNC(tpi6525_device::i2_w));
239 m_vslsi->phi2_handler().set(FUNC(c64_magic_voice_cartridge_device::phi2_w));
240 m_vslsi->dtrd_handler().set(FUNC(c64_magic_voice_cartridge_device::dtrd_w));
241 m_vslsi->apd_handler().set(FUNC(c64_magic_voice_cartridge_device::apd_w));
242 m_vslsi->add_route(ALL_OUTPUTS, "mono", 0.25);
243
244 C64_EXPANSION_SLOT(config, m_exp, DERIVED_CLOCK(1, 1), c64_expansion_cards, nullptr);
245 m_exp->set_passthrough();
246 }
247
248
249
250 //**************************************************************************
251 // LIVE DEVICE
252 //**************************************************************************
253
254 //-------------------------------------------------
255 // c64_magic_voice_cartridge_device - constructor
256 //-------------------------------------------------
257
c64_magic_voice_cartridge_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)258 c64_magic_voice_cartridge_device::c64_magic_voice_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
259 device_t(mconfig, C64_MAGIC_VOICE, tag, owner, clock),
260 device_c64_expansion_card_interface(mconfig, *this),
261 m_vslsi(*this, T6721A_TAG),
262 m_tpi(*this, MOS6525_TAG),
263 m_fifo(*this, CD40105_TAG),
264 m_exp(*this, "exp"),
265 m_ca(0),
266 m_tpi_pb(0x60),
267 m_tpi_pc6(1),
268 m_pd(0)
269 {
270 }
271
272
273 //-------------------------------------------------
274 // device_start - device-specific startup
275 //-------------------------------------------------
276
device_start()277 void c64_magic_voice_cartridge_device::device_start()
278 {
279 // state saving
280 save_item(NAME(m_tpi_pb));
281 save_item(NAME(m_tpi_pc6));
282 save_item(NAME(m_pd));
283 }
284
285
286 //-------------------------------------------------
287 // device_reset - device-specific reset
288 //-------------------------------------------------
289
device_reset()290 void c64_magic_voice_cartridge_device::device_reset()
291 {
292 m_tpi->reset();
293
294 m_exrom = 1;
295
296 m_tpi_pb = 0x60;
297 m_tpi_pc6 = 1;
298 m_pd = 0;
299 }
300
301
302 //-------------------------------------------------
303 // c64_cd_r - cartridge data read
304 //-------------------------------------------------
305
c64_cd_r(offs_t offset,uint8_t data,int sphi2,int ba,int roml,int romh,int io1,int io2)306 uint8_t c64_magic_voice_cartridge_device::c64_cd_r(offs_t offset, uint8_t data, int sphi2, int ba, int roml, int romh, int io1, int io2)
307 {
308 if (!io2 && sphi2)
309 {
310 m_ca = offset;
311 data = m_tpi->read(offset & 0x07);
312 }
313
314 if (PB6 && A13 && A15)
315 {
316 data = m_romh[(A14 << 13) | (offset & 0x1fff)];
317 }
318
319 int roml2 = !(!roml || (roml && !PB5 && A12 && A13 && !A14 && A15));
320 int romh2 = !((!romh && !PB6) || (!PB5 && A12 && A13 && !A14 && !A15));
321
322 data = m_exp->cd_r(get_offset(offset), data, sphi2, ba, roml2, romh2, io1, 1);
323
324 return data;
325 }
326
327
328 //-------------------------------------------------
329 // c64_cd_w - cartridge data write
330 //-------------------------------------------------
331
c64_cd_w(offs_t offset,uint8_t data,int sphi2,int ba,int roml,int romh,int io1,int io2)332 void c64_magic_voice_cartridge_device::c64_cd_w(offs_t offset, uint8_t data, int sphi2, int ba, int roml, int romh, int io1, int io2)
333 {
334 if (!io2 && sphi2)
335 {
336 m_tpi->write(offset & 0x07, data);
337 }
338
339 int roml2 = !(!roml || (roml && !PB5 && A12 && A13 && !A14 && A15));
340 int romh2 = !((!romh && !PB6) || (!PB5 && A12 && A13 && !A14 && !A15));
341
342 m_exp->cd_w(get_offset(offset), data, sphi2, ba, roml2, romh2, io1, 1);
343 }
344
345
346 //-------------------------------------------------
347 // c64_game_r - GAME read
348 //-------------------------------------------------
349
c64_game_r(offs_t offset,int sphi2,int ba,int rw)350 int c64_magic_voice_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw)
351 {
352 return !((m_tpi_pc6 && sphi2) || (!m_tpi_pc6 && sphi2 && !PB5 && A12 && A13 && !A14));
353 }
354
355
356 //-------------------------------------------------
357 // get_offset -
358 //-------------------------------------------------
359
get_offset(offs_t offset)360 offs_t c64_magic_voice_cartridge_device::get_offset(offs_t offset)
361 {
362 if (!PB5 && A12 && A13 && !A14)
363 {
364 offset = ((m_tpi_pb & 0x0f) << 12) | (offset & 0xfff);
365 }
366
367 return offset;
368 }
369