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