1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 williams.h
6
7 Functions to emulate general the various Williams/Midway sound cards.
8
9 ****************************************************************************
10
11 Midway/Williams Audio Boards
12 ----------------------------
13
14 6809 MEMORY MAP
15
16 Function Address R/W Data
17 ---------------------------------------------------------------
18 Program RAM 0000-07FF R/W D0-D7
19
20 Music (YM-2151) 2000-2001 R/W D0-D7
21
22 6821 PIA 4000-4003 R/W D0-D7
23
24 HC55516 clock low, digit latch 6000 W D0
25 HC55516 clock high 6800 W xx
26
27 Bank select 7800 W D0-D2
28
29 Banked Program ROM 8000-FFFF R D0-D7
30
31 ****************************************************************************/
32
33 #include "emu.h"
34 #include "williams.h"
35 #include "machine/6821pia.h"
36 #include "machine/rescap.h"
37 #include "cpu/m6809/m6809.h"
38 #include "sound/ym2151.h"
39 #include "sound/okim6295.h"
40 #include "sound/hc55516.h"
41 #include "sound/dac.h"
42
43
44 #define NARC_MASTER_CLOCK XTAL(8'000'000)
45 #define NARC_FM_CLOCK XTAL(3'579'545)
46
47 #define CVSD_MASTER_CLOCK XTAL(8'000'000)
48 #define CVSD_FM_CLOCK XTAL(3'579'545)
49
50 #define ADPCM_MASTER_CLOCK XTAL(8'000'000)
51 #define ADPCM_FM_CLOCK XTAL(3'579'545)
52
53
54
55 //**************************************************************************
56 // GLOBAL VARIABLES
57 //**************************************************************************
58
59 DEFINE_DEVICE_TYPE(WILLIAMS_CVSD_SOUND, williams_cvsd_sound_device, "wmscvsd", "Williams CVSD Sound Board")
60 DEFINE_DEVICE_TYPE(WILLIAMS_NARC_SOUND, williams_narc_sound_device, "wmsnarc", "Williams NARC Sound Board")
61 DEFINE_DEVICE_TYPE(WILLIAMS_ADPCM_SOUND, williams_adpcm_sound_device, "wmsadpcm", "Williams ADPCM Sound Board")
62
63
64
65 //**************************************************************************
66 // CVSD SOUND BOARD
67 //**************************************************************************
68
69 //-------------------------------------------------
70 // williams_cvsd_sound_device - constructor
71 //-------------------------------------------------
72
williams_cvsd_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)73 williams_cvsd_sound_device::williams_cvsd_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
74 : device_t(mconfig, WILLIAMS_CVSD_SOUND, tag, owner, clock),
75 device_mixer_interface(mconfig, *this),
76 m_cpu(*this, "cpu"),
77 m_pia(*this, "pia"),
78 m_ym2151(*this, "ym2151"),
79 m_hc55516(*this, "cvsd"),
80 m_rombank(*this, "rombank"),
81 m_talkback(0)
82 {
83 }
84
85
86 //-------------------------------------------------
87 // write - handle an external write to the input
88 // latch
89 //-------------------------------------------------
90
write(u16 data)91 void williams_cvsd_sound_device::write(u16 data)
92 {
93 synchronize(0, data);
94 }
95
96
97 //-------------------------------------------------
98 // reset_write - write to the reset line
99 //-------------------------------------------------
100
WRITE_LINE_MEMBER(williams_cvsd_sound_device::reset_write)101 WRITE_LINE_MEMBER(williams_cvsd_sound_device::reset_write)
102 {
103 // going high halts the CPU
104 if (state)
105 {
106 bank_select_w(0);
107 device_reset();
108 m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
109 }
110
111 // going low resets and reactivates the CPU
112 else
113 m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
114 }
115
116
117 //-------------------------------------------------
118 // bank_select_w - change memory banks
119 //-------------------------------------------------
120
bank_select_w(u8 data)121 void williams_cvsd_sound_device::bank_select_w(u8 data)
122 {
123 m_rombank->set_entry(data & 0x0f);
124 }
125
126
127 //-------------------------------------------------
128 // talkback_w - write to the talkback latch
129 //-------------------------------------------------
130
talkback_w(u8 data)131 void williams_cvsd_sound_device::talkback_w(u8 data)
132 {
133 m_talkback = data;
134 logerror("CVSD Talkback = %02X\n", data);
135 }
136
137
138 //-------------------------------------------------
139 // cvsd_digit_clock_clear_w - clear the clock on
140 // the HC55516 and clock the data
141 //-------------------------------------------------
142
cvsd_digit_clock_clear_w(u8 data)143 void williams_cvsd_sound_device::cvsd_digit_clock_clear_w(u8 data)
144 {
145 m_hc55516->clock_w(0);
146 m_hc55516->digit_w(data&1);
147 }
148
149
150 //-------------------------------------------------
151 // cvsd_clock_set_w - set the clock on the HC55516
152 //-------------------------------------------------
153
cvsd_clock_set_w(u8 data)154 void williams_cvsd_sound_device::cvsd_clock_set_w(u8 data)
155 {
156 m_hc55516->clock_w(1);
157 }
158
159
160 //-------------------------------------------------
161 // audio CPU map
162 //-------------------------------------------------
163
williams_cvsd_map(address_map & map)164 void williams_cvsd_sound_device::williams_cvsd_map(address_map &map)
165 {
166 map(0x0000, 0x07ff).mirror(0x1800).ram();
167 map(0x2000, 0x2001).mirror(0x1ffe).rw("ym2151", FUNC(ym2151_device::read), FUNC(ym2151_device::write));
168 map(0x4000, 0x4003).mirror(0x1ffc).rw("pia", FUNC(pia6821_device::read), FUNC(pia6821_device::write));
169 map(0x6000, 0x6000).mirror(0x07ff).w(FUNC(williams_cvsd_sound_device::cvsd_digit_clock_clear_w));
170 map(0x6800, 0x6800).mirror(0x07ff).w(FUNC(williams_cvsd_sound_device::cvsd_clock_set_w));
171 map(0x7800, 0x7800).mirror(0x07ff).w(FUNC(williams_cvsd_sound_device::bank_select_w));
172 map(0x8000, 0xffff).bankr("rombank");
173 }
174
175
176 //-------------------------------------------------
177 // device_add_mconfig - add device configuration
178 //-------------------------------------------------
179
device_add_mconfig(machine_config & config)180 void williams_cvsd_sound_device::device_add_mconfig(machine_config &config)
181 {
182 MC6809E(config, m_cpu, CVSD_MASTER_CLOCK / 4);
183 m_cpu->set_addrmap(AS_PROGRAM, &williams_cvsd_sound_device::williams_cvsd_map);
184
185 PIA6821(config, m_pia, 0);
186 m_pia->writepa_handler().set("dac", FUNC(dac_byte_interface::data_w));
187 m_pia->writepb_handler().set(FUNC(williams_cvsd_sound_device::talkback_w));
188 m_pia->ca2_handler().set(m_ym2151, FUNC(ym2151_device::reset_w));
189 m_pia->irqa_handler().set_inputline(m_cpu, M6809_FIRQ_LINE);
190 m_pia->irqb_handler().set_inputline(m_cpu, INPUT_LINE_NMI);
191
192 YM2151(config, m_ym2151, CVSD_FM_CLOCK);
193 m_ym2151->irq_handler().set(m_pia, FUNC(pia6821_device::ca1_w)).invert(); // IRQ is not true state
194 m_ym2151->add_route(ALL_OUTPUTS, *this, 0.10);
195
196 MC1408(config, "dac", 0).add_route(ALL_OUTPUTS, *this, 0.25);
197
198 HC55516(config, m_hc55516, 0);
199 m_hc55516->add_route(ALL_OUTPUTS, *this, 0.60);
200 }
201
202
203 //-------------------------------------------------
204 // device_start - device-specific startup
205 //-------------------------------------------------
206
device_start()207 void williams_cvsd_sound_device::device_start()
208 {
209 // configure master CPU banks
210 u8 *rom = memregion("cpu")->base();
211 for (int bank = 0; bank < 16; bank++)
212 {
213 //
214 // D0/D1 -> selects: 0=U4 1=U19 2=U20 3=n/c
215 // D2 -> A15
216 // D3 -> A16
217 //
218 offs_t offset = 0x8000 * ((bank >> 2) & 3) + 0x20000 * (bank & 3);
219 m_rombank->configure_entry(bank, &rom[0x10000 + offset]);
220 }
221 m_rombank->set_entry(0);
222
223 // reset the IRQ state
224 m_pia->ca1_w(1);
225
226 // register for save states
227 save_item(NAME(m_talkback));
228 }
229
230
231 //-------------------------------------------------
232 // device_reset - device-specific reset
233 //-------------------------------------------------
234
device_reset()235 void williams_cvsd_sound_device::device_reset()
236 {
237 // reset interrupt states
238 m_cpu->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE);
239 m_cpu->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
240 m_cpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
241 }
242
243
244 //-------------------------------------------------
245 // device_timer - timer callbacks
246 //-------------------------------------------------
247
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)248 void williams_cvsd_sound_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
249 {
250 // process incoming data write
251 m_pia->portb_w(param & 0xff);
252 m_pia->cb1_w((param >> 8) & 1);
253 m_pia->cb2_w((param >> 9) & 1);
254 }
255
256
257
258 //**************************************************************************
259 // NARC SOUND BOARD
260 //**************************************************************************
261
262 //-------------------------------------------------
263 // williams_narc_sound_device - constructor
264 //-------------------------------------------------
265
williams_narc_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)266 williams_narc_sound_device::williams_narc_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
267 : device_t(mconfig, WILLIAMS_NARC_SOUND, tag, owner, clock),
268 device_mixer_interface(mconfig, *this),
269 m_cpu(*this, "cpu%u", 0U),
270 m_hc55516(*this, "cvsd"),
271 m_masterbank(*this, "masterbank"),
272 m_slavebank(*this, "slavebank"),
273 m_latch(0),
274 m_latch2(0),
275 m_talkback(0),
276 m_audio_sync(0),
277 m_sound_int_state(0)
278 {
279 }
280
281
282 //-------------------------------------------------
283 // read - return the talkback register with the
284 // SYNC bits in bits 8 and 9
285 //-------------------------------------------------
286
read()287 u16 williams_narc_sound_device::read()
288 {
289 return m_talkback | (m_audio_sync << 8);
290 }
291
292
293 //-------------------------------------------------
294 // write - handle an external write to the input
295 // latch
296 //-------------------------------------------------
297
write(u16 data)298 void williams_narc_sound_device::write(u16 data)
299 {
300 synchronize(TID_MASTER_COMMAND, data);
301 }
302
303
304 //-------------------------------------------------
305 // reset_write - write to the reset line
306 //-------------------------------------------------
307
WRITE_LINE_MEMBER(williams_narc_sound_device::reset_write)308 WRITE_LINE_MEMBER(williams_narc_sound_device::reset_write)
309 {
310 // going high halts the CPU
311 if (state)
312 {
313 master_bank_select_w(0);
314 slave_bank_select_w(0);
315 device_reset();
316 m_cpu[0]->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
317 m_cpu[1]->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
318 }
319
320 // going low resets and reactivates the CPU
321 else
322 {
323 m_cpu[0]->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
324 m_cpu[1]->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
325 }
326 }
327
328
329 //-------------------------------------------------
330 // master_bank_select_w - select the bank for the
331 // master CPU
332 //-------------------------------------------------
333
master_bank_select_w(u8 data)334 void williams_narc_sound_device::master_bank_select_w(u8 data)
335 {
336 m_masterbank->set_entry(data & 0x0f);
337 }
338
339
340 //-------------------------------------------------
341 // slave_bank_select_w - select the bank for the
342 // slave CPU
343 //-------------------------------------------------
344
slave_bank_select_w(u8 data)345 void williams_narc_sound_device::slave_bank_select_w(u8 data)
346 {
347 m_slavebank->set_entry(data & 0x0f);
348 }
349
350
351 //-------------------------------------------------
352 // command_r - read command written by external
353 // agent
354 //-------------------------------------------------
355
command_r()356 u8 williams_narc_sound_device::command_r()
357 {
358 m_cpu[0]->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
359 m_sound_int_state = 0;
360 return m_latch;
361 }
362
363
364 //-------------------------------------------------
365 // command2_w - write command from master CPU to
366 // slave CPU
367 //-------------------------------------------------
368
command2_w(u8 data)369 void williams_narc_sound_device::command2_w(u8 data)
370 {
371 synchronize(TID_SLAVE_COMMAND, data);
372 }
373
374
375 //-------------------------------------------------
376 // command2_r - read command written by master
377 // CPU
378 //-------------------------------------------------
379
command2_r()380 u8 williams_narc_sound_device::command2_r()
381 {
382 m_cpu[1]->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE);
383 return m_latch2;
384 }
385
386
387 //-------------------------------------------------
388 // master_talkback_w - handle writes to the
389 // talkback latch from the master CPU
390 //-------------------------------------------------
391
master_talkback_w(u8 data)392 void williams_narc_sound_device::master_talkback_w(u8 data)
393 {
394 m_talkback = data;
395 logerror("Master Talkback = %02X\n", data);
396 }
397
398
399 //-------------------------------------------------
400 // master_sync_w - handle writes to the master
401 // SYNC register
402 //-------------------------------------------------
403
master_sync_w(u8 data)404 void williams_narc_sound_device::master_sync_w(u8 data)
405 {
406 timer_set(attotime::from_double(TIME_OF_74LS123(180000, 0.000001)), TID_SYNC_CLEAR, 0x01);
407 m_audio_sync |= 0x01;
408 logerror("Master sync = %02X\n", data);
409 }
410
411
412 //-------------------------------------------------
413 // slave_talkback_w - handle writes to the
414 // talkback latch from the slave CPU
415 //-------------------------------------------------
416
slave_talkback_w(u8 data)417 void williams_narc_sound_device::slave_talkback_w(u8 data)
418 {
419 logerror("Slave Talkback = %02X\n", data);
420 }
421
422
423 //-------------------------------------------------
424 // slave_sync_w - handle writes to the slave
425 // SYNC register
426 //-------------------------------------------------
427
slave_sync_w(u8 data)428 void williams_narc_sound_device::slave_sync_w(u8 data)
429 {
430 timer_set(attotime::from_double(TIME_OF_74LS123(180000, 0.000001)), TID_SYNC_CLEAR, 0x02);
431 m_audio_sync |= 0x02;
432 logerror("Slave sync = %02X\n", data);
433 }
434
435
436 //-------------------------------------------------
437 // cvsd_digit_clock_clear_w - clear the clk pin on
438 // the HC555xx and clock the data latch
439 //-------------------------------------------------
440
cvsd_digit_clock_clear_w(u8 data)441 void williams_narc_sound_device::cvsd_digit_clock_clear_w(u8 data)
442 {
443 m_hc55516->clock_w(0);
444 m_hc55516->digit_w(data&1);
445 }
446
447
448 //---------------------------------------------------
449 // cvsd_clock_set_w - set the clk pin on the HC555xx
450 //---------------------------------------------------
451
cvsd_clock_set_w(u8 data)452 void williams_narc_sound_device::cvsd_clock_set_w(u8 data)
453 {
454 m_hc55516->clock_w(1);
455 }
456
457
458 //-------------------------------------------------
459 // master CPU map
460 //-------------------------------------------------
461
williams_narc_master_map(address_map & map)462 void williams_narc_sound_device::williams_narc_master_map(address_map &map)
463 {
464 map(0x0000, 0x1fff).ram();
465 map(0x2000, 0x2001).mirror(0x03fe).rw("ym2151", FUNC(ym2151_device::read), FUNC(ym2151_device::write));
466 map(0x2800, 0x2800).mirror(0x03ff).w(FUNC(williams_narc_sound_device::master_talkback_w));
467 map(0x2c00, 0x2c00).mirror(0x03ff).w(FUNC(williams_narc_sound_device::command2_w));
468 map(0x3000, 0x3000).mirror(0x03ff).w("dac1", FUNC(dac_byte_interface::data_w));
469 map(0x3400, 0x3400).mirror(0x03ff).r(FUNC(williams_narc_sound_device::command_r));
470 map(0x3800, 0x3800).mirror(0x03ff).w(FUNC(williams_narc_sound_device::master_bank_select_w));
471 map(0x3c00, 0x3c00).mirror(0x03ff).w(FUNC(williams_narc_sound_device::master_sync_w));
472 map(0x4000, 0xbfff).bankr("masterbank");
473 map(0xc000, 0xffff).bankr("masterupper");
474 }
475
476
477 //-------------------------------------------------
478 // slave CPU map
479 //-------------------------------------------------
480
williams_narc_slave_map(address_map & map)481 void williams_narc_sound_device::williams_narc_slave_map(address_map &map)
482 {
483 map(0x0000, 0x1fff).ram();
484 map(0x2000, 0x2000).mirror(0x03ff).w(FUNC(williams_narc_sound_device::cvsd_clock_set_w));
485 map(0x2400, 0x2400).mirror(0x03ff).w(FUNC(williams_narc_sound_device::cvsd_digit_clock_clear_w));
486 map(0x2800, 0x2800).mirror(0x03ff).w(FUNC(williams_narc_sound_device::slave_talkback_w));
487 map(0x3000, 0x3000).mirror(0x03ff).w("dac2", FUNC(dac_byte_interface::data_w));
488 map(0x3400, 0x3400).mirror(0x03ff).r(FUNC(williams_narc_sound_device::command2_r));
489 map(0x3800, 0x3800).mirror(0x03ff).w(FUNC(williams_narc_sound_device::slave_bank_select_w));
490 map(0x3c00, 0x3c00).mirror(0x03ff).w(FUNC(williams_narc_sound_device::slave_sync_w));
491 map(0x4000, 0xbfff).bankr("slavebank");
492 map(0xc000, 0xffff).bankr("slaveupper");
493 }
494
495
496 //-------------------------------------------------
497 // device_add_mconfig - add device configuration
498 //-------------------------------------------------
499
500
device_add_mconfig(machine_config & config)501 void williams_narc_sound_device::device_add_mconfig(machine_config &config)
502 {
503 MC6809E(config, m_cpu[0], NARC_MASTER_CLOCK / 4);
504 m_cpu[0]->set_addrmap(AS_PROGRAM, &williams_narc_sound_device::williams_narc_master_map);
505
506 MC6809E(config, m_cpu[1], NARC_MASTER_CLOCK / 4);
507 m_cpu[1]->set_addrmap(AS_PROGRAM, &williams_narc_sound_device::williams_narc_slave_map);
508
509 ym2151_device &ym2151(YM2151(config, "ym2151", NARC_FM_CLOCK));
510 ym2151.irq_handler().set_inputline("cpu0", M6809_FIRQ_LINE);
511 ym2151.add_route(ALL_OUTPUTS, *this, 0.10);
512
513 AD7224(config, "dac1", 0).add_route(ALL_OUTPUTS, *this, 0.25);
514 AD7224(config, "dac2", 0).add_route(ALL_OUTPUTS, *this, 0.25);
515
516 HC55516(config, m_hc55516, 0).add_route(ALL_OUTPUTS, *this, 0.60);
517 }
518
519
520 //-------------------------------------------------
521 // device_start - device-specific startup
522 //-------------------------------------------------
523
device_start()524 void williams_narc_sound_device::device_start()
525 {
526 // configure master CPU banks
527 u8 *rom = memregion("cpu0")->base();
528 for (int bank = 0; bank < 16; bank++)
529 {
530 //
531 // D0 -> A15
532 // D1/D2 -> selects: 0=n/c 1=U3 2=U4 3=U5
533 // D3 -> A16
534 //
535 offs_t offset = 0x8000 * (bank & 1) + 0x10000 * ((bank >> 3) & 1) + 0x20000 * ((bank >> 1) & 3);
536 m_masterbank->configure_entry(bank, &rom[0x10000 + offset]);
537 }
538 membank("masterupper")->set_base(&rom[0x10000 + 0x4000 + 0x8000 + 0x10000 + 0x20000 * 3]);
539
540 // configure slave CPU banks
541 rom = memregion("cpu1")->base();
542 for (int bank = 0; bank < 16; bank++)
543 {
544 //
545 // D0 -> A15
546 // D1/D2 -> selects: 0=U35 1=U36 2=U37 3=U38
547 // D3 -> A16
548 //
549 offs_t offset = 0x8000 * (bank & 1) + 0x10000 * ((bank >> 3) & 1) + 0x20000 * ((bank >> 1) & 3);
550 m_slavebank->configure_entry(bank, &rom[0x10000 + offset]);
551 }
552 membank("slaveupper")->set_base(&rom[0x10000 + 0x4000 + 0x8000 + 0x10000 + 0x20000 * 3]);
553
554 // register for save states
555 save_item(NAME(m_latch));
556 save_item(NAME(m_latch2));
557 save_item(NAME(m_talkback));
558 save_item(NAME(m_audio_sync));
559 save_item(NAME(m_sound_int_state));
560 }
561
562
563 //-------------------------------------------------
564 // device_reset - device-specific reset
565 //-------------------------------------------------
566
device_reset()567 void williams_narc_sound_device::device_reset()
568 {
569 // reset interrupt states
570 m_sound_int_state = 0;
571 m_cpu[0]->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE);
572 m_cpu[0]->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
573 m_cpu[0]->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
574 m_cpu[1]->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE);
575 m_cpu[1]->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
576 m_cpu[1]->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
577 }
578
579
580 //-------------------------------------------------
581 // device_timer - timer callbacks
582 //-------------------------------------------------
583
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)584 void williams_narc_sound_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
585 {
586 switch (id)
587 {
588 case TID_MASTER_COMMAND:
589 m_latch = param & 0xff;
590 m_cpu[0]->set_input_line(INPUT_LINE_NMI, (param & 0x100) ? CLEAR_LINE : ASSERT_LINE);
591 if ((param & 0x200) == 0)
592 {
593 m_cpu[0]->set_input_line(M6809_IRQ_LINE, ASSERT_LINE);
594 m_sound_int_state = 1;
595 }
596 break;
597
598 case TID_SLAVE_COMMAND:
599 m_latch2 = param & 0xff;
600 m_cpu[1]->set_input_line(M6809_FIRQ_LINE, ASSERT_LINE);
601 break;
602
603 case TID_SYNC_CLEAR:
604 m_audio_sync &= ~param;
605 break;
606 }
607 }
608
609
610 //**************************************************************************
611 // ADPCM SOUND BOARD
612 //**************************************************************************
613
614 //-------------------------------------------------
615 // williams_adpcm_sound_device - constructor
616 //-------------------------------------------------
617
williams_adpcm_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)618 williams_adpcm_sound_device::williams_adpcm_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
619 : device_t(mconfig, WILLIAMS_ADPCM_SOUND, tag, owner, clock),
620 device_mixer_interface(mconfig, *this),
621 m_cpu(*this, "cpu"),
622 m_rombank(*this, "rombank"),
623 m_okibank(*this, "okibank"),
624 m_latch(0),
625 m_talkback(0),
626 m_sound_int_state(0)
627 {
628 }
629
630
631 //-------------------------------------------------
632 // write - handle an external write to the input
633 // latch
634 //-------------------------------------------------
635
write(u16 data)636 void williams_adpcm_sound_device::write(u16 data)
637 {
638 synchronize(TID_COMMAND, data);
639 }
640
641
642 //-------------------------------------------------
643 // reset_write - write to the reset line
644 //-------------------------------------------------
645
WRITE_LINE_MEMBER(williams_adpcm_sound_device::reset_write)646 WRITE_LINE_MEMBER(williams_adpcm_sound_device::reset_write)
647 {
648 // going high halts the CPU
649 if (state)
650 {
651 bank_select_w(0);
652 device_reset();
653 m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
654 }
655
656 // going low resets and reactivates the CPU
657 else
658 m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
659 }
660
661
662 //-------------------------------------------------
663 // irq_read - read the sound IRQ state
664 //-------------------------------------------------
665
READ_LINE_MEMBER(williams_adpcm_sound_device::irq_read)666 READ_LINE_MEMBER(williams_adpcm_sound_device::irq_read)
667 {
668 return m_sound_int_state;
669 }
670
671
672 //-------------------------------------------------
673 // bank_select_w - select the sound CPU memory
674 // bank
675 //-------------------------------------------------
676
bank_select_w(u8 data)677 void williams_adpcm_sound_device::bank_select_w(u8 data)
678 {
679 m_rombank->set_entry(data & 0x07);
680 }
681
682
683 //-------------------------------------------------
684 // oki6295_bank_select_w - select the OKI6295
685 // memory bank
686 //-------------------------------------------------
687
oki6295_bank_select_w(u8 data)688 void williams_adpcm_sound_device::oki6295_bank_select_w(u8 data)
689 {
690 m_okibank->set_entry(data & 7);
691 }
692
693
694 //-------------------------------------------------
695 // command_r - read the command from the external
696 // latch
697 //-------------------------------------------------
698
command_r()699 u8 williams_adpcm_sound_device::command_r()
700 {
701 m_cpu->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
702
703 // don't clear the external IRQ state for a short while; this allows the
704 // self-tests to pass
705 timer_set(attotime::from_usec(10), TID_IRQ_CLEAR);
706 return m_latch;
707 }
708
709
710 //-------------------------------------------------
711 // talkback_w - write to the talkback latch
712 //-------------------------------------------------
713
talkback_w(u8 data)714 void williams_adpcm_sound_device::talkback_w(u8 data)
715 {
716 m_talkback = data;
717 logerror("ADPCM Talkback = %02X\n", data);
718 }
719
720
721 //-------------------------------------------------
722 // audio CPU map
723 //-------------------------------------------------
724
williams_adpcm_map(address_map & map)725 void williams_adpcm_sound_device::williams_adpcm_map(address_map &map)
726 {
727 map(0x0000, 0x1fff).ram();
728 map(0x2000, 0x2000).mirror(0x03ff).w(FUNC(williams_adpcm_sound_device::bank_select_w));
729 map(0x2400, 0x2401).mirror(0x03fe).rw("ym2151", FUNC(ym2151_device::read), FUNC(ym2151_device::write));
730 map(0x2800, 0x2800).mirror(0x03ff).w("dac", FUNC(dac_byte_interface::data_w));
731 map(0x2c00, 0x2c00).mirror(0x03ff).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write));
732 map(0x3000, 0x3000).mirror(0x03ff).r(FUNC(williams_adpcm_sound_device::command_r));
733 map(0x3400, 0x3400).mirror(0x03ff).w(FUNC(williams_adpcm_sound_device::oki6295_bank_select_w));
734 map(0x3c00, 0x3c00).mirror(0x03ff).w(FUNC(williams_adpcm_sound_device::talkback_w));
735 map(0x4000, 0xbfff).bankr("rombank");
736 map(0xc000, 0xffff).bankr("romupper");
737 }
738
739
740 //-------------------------------------------------
741 // OKI6295 map
742 //-------------------------------------------------
743
williams_adpcm_oki_map(address_map & map)744 void williams_adpcm_sound_device::williams_adpcm_oki_map(address_map &map)
745 {
746 map(0x00000, 0x1ffff).bankr("okibank");
747 map(0x20000, 0x3ffff).rom().region("oki", 0x60000);
748 }
749
750
751 //-------------------------------------------------
752 // device_add_mconfig - add device configuration
753 //-------------------------------------------------
754
device_add_mconfig(machine_config & config)755 void williams_adpcm_sound_device::device_add_mconfig(machine_config &config)
756 {
757 MC6809E(config, m_cpu, ADPCM_MASTER_CLOCK / 4);
758 m_cpu->set_addrmap(AS_PROGRAM, &williams_adpcm_sound_device::williams_adpcm_map);
759
760 ym2151_device &ym2151(YM2151(config, "ym2151", ADPCM_FM_CLOCK));
761 ym2151.irq_handler().set_inputline("cpu", M6809_FIRQ_LINE);
762 ym2151.add_route(ALL_OUTPUTS, *this, 0.10);
763
764 AD7524(config, "dac", 0).add_route(ALL_OUTPUTS, *this, 0.10);
765
766 okim6295_device &oki(OKIM6295(config, "oki", ADPCM_MASTER_CLOCK/8, okim6295_device::PIN7_HIGH)); // clock frequency & pin 7 not verified
767 oki.set_addrmap(0, &williams_adpcm_sound_device::williams_adpcm_oki_map);
768 oki.add_route(ALL_OUTPUTS, *this, 0.15);
769 }
770
771
772 //-------------------------------------------------
773 // device_start - device-specific startup
774 //-------------------------------------------------
775
device_start()776 void williams_adpcm_sound_device::device_start()
777 {
778 // configure banks
779 u8 *rom = memregion("cpu")->base();
780 m_rombank->configure_entries(0, 8, &rom[0x10000], 0x8000);
781 membank("romupper")->set_base(&rom[0x10000 + 0x4000 + 7 * 0x8000]);
782
783 // expand ADPCM data
784 rom = memregion("oki")->base();
785 // it is assumed that U12 is loaded @ 0x00000 and U13 is loaded @ 0x40000
786 m_okibank->configure_entry(0, &rom[0x40000]);
787 m_okibank->configure_entry(1, &rom[0x40000]);
788 m_okibank->configure_entry(2, &rom[0x20000]);
789 m_okibank->configure_entry(3, &rom[0x00000]);
790 m_okibank->configure_entry(4, &rom[0xe0000]);
791 m_okibank->configure_entry(5, &rom[0xc0000]);
792 m_okibank->configure_entry(6, &rom[0xa0000]);
793 m_okibank->configure_entry(7, &rom[0x80000]);
794
795 // register for save states
796 save_item(NAME(m_latch));
797 save_item(NAME(m_talkback));
798 save_item(NAME(m_sound_int_state));
799 }
800
801
802 //-------------------------------------------------
803 // device_reset - device-specific reset
804 //-------------------------------------------------
805
device_reset()806 void williams_adpcm_sound_device::device_reset()
807 {
808 // reset interrupt states
809 m_sound_int_state = 0;
810 m_cpu->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE);
811 m_cpu->set_input_line(M6809_IRQ_LINE, CLEAR_LINE);
812 m_cpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
813 }
814
815
816 //-------------------------------------------------
817 // device_timer - timer callbacks
818 //-------------------------------------------------
819
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)820 void williams_adpcm_sound_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
821 {
822 switch (id)
823 {
824 case TID_COMMAND:
825 m_latch = param & 0xff;
826 if (!(param & 0x200))
827 {
828 m_cpu->set_input_line(M6809_IRQ_LINE, ASSERT_LINE);
829 m_sound_int_state = 1;
830 machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(100));
831 }
832 break;
833
834 case TID_IRQ_CLEAR:
835 m_sound_int_state = 0;
836 break;
837 }
838 }
839