1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles,Paul Leaman
3 /***************************************************************************
4
5 Cinemat/Leland driver
6
7 Leland sound hardware
8 driver by Aaron Giles and Paul Leaman
9
10 -------------------------------------------------------------------
11
12 1st generation sound hardware was controlled by the master Z80.
13 It drove either an AY-8910/AY-8912 for music. It also had two DACs
14 that were driven by the video refresh. At the end of each scanline
15 there are 8-bit DAC samples that can be enabled via the output
16 ports on the AY-8910. The DACs run at a fixed frequency of 15.3kHz,
17 since they are clocked once each scanline.
18
19 -------------------------------------------------------------------
20
21 2nd generation sound hardware was used in Redline Racer. It
22 consisted of an 80186 microcontroller driving 8 8-bit DACs. The
23 frequency of the DACs were controlled by one of 3 Intel 8254
24 programmable interval timers (PITs):
25
26 DAC number Clock source
27 ---------- -----------------
28 0 8254 PIT 1 output 0
29 1 8254 PIT 1 output 1
30 2 8254 PIT 1 output 2
31 3 8254 PIT 2 output 0
32 4 8254 PIT 2 output 1
33 5-7 8254 PIT 3 output 0
34
35 The clock outputs for each DAC can be read, and are polled to
36 determine when data should be updated on the chips. The 80186's
37 two DMA channels are generally used to drive the first two DACs,
38 with the remaining 6 DACs being fed manually via polling.
39
40 -------------------------------------------------------------------
41
42 3rd generation sound hardware appeared in the football games
43 (Quarterback, AAFB) and the later games up through Pigout. This
44 variant is closely based on the Redline Racer sound system, but
45 they took out two of the DACs and replaced them with a higher
46 resolution (10-bit) DAC. The driving clocks have been rearranged
47 a bit, and the number of PITs reduced from 3 to 2:
48
49 DAC number Clock source
50 ---------- -----------------
51 0 8254 PIT 1 output 0
52 1 8254 PIT 1 output 1
53 2 8254 PIT 1 output 2
54 3 8254 PIT 2 output 0
55 4 8254 PIT 2 output 1
56 5 8254 PIT 2 output 2
57 10-bit 80186 timer 0
58
59 Like the 2nd generation board, the first two DACs are driven via
60 the DMA channels, and the remaining 5 DACs are polled.
61
62 -------------------------------------------------------------------
63
64 4th generation sound hardware showed up in Ataxx, Indy Heat, and
65 World Soccer Finals. For this variant, they removed one more PIT
66 and 3 of the 8-bit DACs, and added a YM2151 music chip and an
67 externally-fed 8-bit DAC.
68
69 DAC number Clock source
70 ---------- -----------------
71 0 8254 PIT 1 output 0
72 1 8254 PIT 1 output 1
73 2 8254 PIT 1 output 2
74 10-bit 80186 timer 0
75 ext 80186 timer 1
76
77 The externally driven DACs have registers for a start/stop address
78 and triggers to control the clocking.
79
80 ***************************************************************************/
81
82 #include "emu.h"
83 #include "audio/leland.h"
84
85 #include "cpu/z80/z80.h"
86 #include "speaker.h"
87
88 #define LOG_COMM 0
89 #define LOG_EXTERN 0
90
91 /*************************************
92 *
93 * 2nd-4th generation sound
94 *
95 *************************************/
96
WRITE_LINE_MEMBER(leland_80186_sound_device::pit0_2_w)97 WRITE_LINE_MEMBER(leland_80186_sound_device::pit0_2_w)
98 {
99 set_clock_line(2, state);
100 }
101
WRITE_LINE_MEMBER(leland_80186_sound_device::pit1_0_w)102 WRITE_LINE_MEMBER(leland_80186_sound_device::pit1_0_w)
103 {
104 set_clock_line(3, state);
105 }
106
WRITE_LINE_MEMBER(leland_80186_sound_device::pit1_1_w)107 WRITE_LINE_MEMBER(leland_80186_sound_device::pit1_1_w)
108 {
109 set_clock_line(4, state);
110 }
111
WRITE_LINE_MEMBER(leland_80186_sound_device::pit1_2_w)112 WRITE_LINE_MEMBER(leland_80186_sound_device::pit1_2_w)
113 {
114 set_clock_line(5, state);
115 }
116
WRITE_LINE_MEMBER(leland_80186_sound_device::i80186_tmr0_w)117 WRITE_LINE_MEMBER(leland_80186_sound_device::i80186_tmr0_w)
118 {
119 set_clock_line(6, state);
120 }
121
WRITE_LINE_MEMBER(leland_80186_sound_device::i80186_tmr1_w)122 WRITE_LINE_MEMBER(leland_80186_sound_device::i80186_tmr1_w)
123 {
124 if (m_ext_base != nullptr)
125 {
126 if (state)
127 {
128 if (m_ext_active && (m_ext_start < m_ext_stop))
129 {
130 m_dac[3]->write(m_ext_base[m_ext_start]);
131 m_ext_start++;
132 }
133 }
134 }
135 set_clock_line(7, state);
136 }
137
device_add_mconfig(machine_config & config)138 void leland_80186_sound_device::device_add_mconfig(machine_config &config)
139 {
140 I80186(config, m_audiocpu, 16_MHz_XTAL);
141 m_audiocpu->set_addrmap(AS_PROGRAM, &leland_80186_sound_device::leland_80186_map_program);
142 m_audiocpu->set_addrmap(AS_IO, &leland_80186_sound_device::leland_80186_map_io);
143 m_audiocpu->chip_select_callback().set(FUNC(leland_80186_sound_device::peripheral_ctrl));
144 m_audiocpu->tmrout0_handler().set(FUNC(leland_80186_sound_device::i80186_tmr0_w));
145
146 SPEAKER(config, "speaker").front_center();
147 for (int i = 0; i < 6; i++)
148 {
149 AD7524(config, m_dac[i], 0).add_route(ALL_OUTPUTS, "speaker", 0.2); // 74hc374.u31..6 + ad7524.u46..51
150 DAC_8BIT_BINARY_WEIGHTED(config, m_dacvol[i], 0).set_output_range(0, 1); // 74hc374.u17..22 + rX2-rX9 (24k,12k,6.2k,3k,1.5k,750,360,160) where X is 0..5
151 m_dacvol[i]->add_route(0, m_dac[i], 1.0, DAC_INPUT_RANGE_HI);
152 m_dacvol[i]->add_route(0, m_dac[i], -1.0, DAC_INPUT_RANGE_LO);
153 }
154 AD7533(config, "dac9", 0).add_route(ALL_OUTPUTS, "speaker", 1.0); // ad7533.u64
155
156 PIT8254(config, m_pit[0], 0);
157 m_pit[0]->set_clk<0>(4000000);
158 m_pit[0]->out_handler<0>().set(m_audiocpu, FUNC(i80186_cpu_device::drq0_w));
159 m_pit[0]->set_clk<1>(4000000);
160 m_pit[0]->out_handler<1>().set(m_audiocpu, FUNC(i80186_cpu_device::drq1_w));
161 m_pit[0]->set_clk<2>(4000000);
162 m_pit[0]->out_handler<2>().set(FUNC(leland_80186_sound_device::pit0_2_w));
163
164 PIT8254(config, m_pit[1], 0);
165 m_pit[1]->set_clk<0>(4000000);
166 m_pit[1]->out_handler<0>().set(FUNC(leland_80186_sound_device::pit1_0_w));
167 m_pit[1]->set_clk<1>(4000000);
168 m_pit[1]->out_handler<1>().set(FUNC(leland_80186_sound_device::pit1_1_w));
169 m_pit[1]->set_clk<2>(4000000);
170 m_pit[1]->out_handler<2>().set(FUNC(leland_80186_sound_device::pit1_2_w));
171
172 GENERIC_LATCH_16(config, m_soundlatch);
173 }
174
device_add_mconfig(machine_config & config)175 void redline_80186_sound_device::device_add_mconfig(machine_config &config)
176 {
177 I80186(config, m_audiocpu, 16_MHz_XTAL);
178 m_audiocpu->set_addrmap(AS_PROGRAM, &redline_80186_sound_device::leland_80186_map_program);
179 m_audiocpu->set_addrmap(AS_IO, &redline_80186_sound_device::redline_80186_map_io);
180 m_audiocpu->chip_select_callback().set(FUNC(leland_80186_sound_device::peripheral_ctrl));
181
182 SPEAKER(config, "speaker").front_center();
183 for (int i = 0; i < 8; i++)
184 {
185 AD7524(config, m_dac[i], 0).add_route(ALL_OUTPUTS, "speaker", 0.2); // unknown DAC
186 DAC_8BIT_BINARY_WEIGHTED(config, m_dacvol[i], 0).set_output_range(0, 1);
187 m_dacvol[i]->add_route(0, m_dac[i], 1.0, DAC_INPUT_RANGE_HI);
188 m_dacvol[i]->add_route(0, m_dac[i], -1.0, DAC_INPUT_RANGE_LO); // unknown DAC
189 }
190
191 PIT8254(config, m_pit[0], 0);
192 m_pit[0]->set_clk<0>(7000000);
193 m_pit[0]->out_handler<0>().set(m_audiocpu, FUNC(i80186_cpu_device::drq0_w));
194 m_pit[0]->set_clk<1>(7000000);
195 m_pit[0]->out_handler<1>().set(m_audiocpu, FUNC(i80186_cpu_device::drq1_w));
196 m_pit[0]->set_clk<2>(7000000);
197 m_pit[0]->out_handler<2>().set(FUNC(leland_80186_sound_device::pit0_2_w));
198
199 PIT8254(config, m_pit[1], 0);
200 m_pit[1]->set_clk<0>(7000000);
201 m_pit[1]->out_handler<0>().set(FUNC(leland_80186_sound_device::pit1_0_w));
202 m_pit[1]->set_clk<1>(7000000);
203 m_pit[1]->out_handler<1>().set(FUNC(leland_80186_sound_device::pit1_1_w));
204 m_pit[1]->set_clk<2>(7000000);
205
206 PIT8254(config, m_pit[2], 0);
207 m_pit[2]->set_clk<0>(7000000);
208 m_pit[2]->out_handler<0>().set(FUNC(leland_80186_sound_device::pit1_2_w));
209 m_pit[2]->set_clk<1>(7000000);
210 m_pit[2]->set_clk<2>(7000000);
211
212 GENERIC_LATCH_16(config, m_soundlatch);
213 }
214
device_add_mconfig(machine_config & config)215 void ataxx_80186_sound_device::device_add_mconfig(machine_config &config)
216 {
217 I80186(config, m_audiocpu, 16_MHz_XTAL);
218 m_audiocpu->set_addrmap(AS_PROGRAM, &ataxx_80186_sound_device::leland_80186_map_program);
219 m_audiocpu->set_addrmap(AS_IO, &ataxx_80186_sound_device::ataxx_80186_map_io);
220 m_audiocpu->chip_select_callback().set(FUNC(leland_80186_sound_device::peripheral_ctrl));
221 m_audiocpu->tmrout0_handler().set(FUNC(leland_80186_sound_device::i80186_tmr0_w));
222
223 SPEAKER(config, "speaker").front_center();
224 for (int i = 0; i < 4; i++)
225 {
226 AD7524(config, m_dac[i], 0).add_route(ALL_OUTPUTS, "speaker", 0.2); // unknown DAC
227 DAC_8BIT_BINARY_WEIGHTED(config, m_dacvol[i], 0).set_output_range(0, 1); // unknown DAC
228 m_dacvol[i]->add_route(0, m_dac[i], 1.0, DAC_INPUT_RANGE_HI);
229 m_dacvol[i]->add_route(0, m_dac[i], -1.0, DAC_INPUT_RANGE_LO);
230 }
231 AD7533(config, "dac9", 0).add_route(ALL_OUTPUTS, "speaker", 1.0); // unknown DAC
232
233 PIT8254(config, m_pit[0], 0);
234 m_pit[0]->set_clk<0>(4000000);
235 m_pit[0]->out_handler<0>().set(m_audiocpu, FUNC(i80186_cpu_device::drq0_w));
236 m_pit[0]->set_clk<1>(4000000);
237 m_pit[0]->out_handler<1>().set(m_audiocpu, FUNC(i80186_cpu_device::drq1_w));
238 m_pit[0]->set_clk<2>(4000000);
239 m_pit[0]->out_handler<2>().set(FUNC(leland_80186_sound_device::pit0_2_w));
240
241 GENERIC_LATCH_16(config, m_soundlatch);
242 }
243
device_add_mconfig(machine_config & config)244 void wsf_80186_sound_device::device_add_mconfig(machine_config &config)
245 {
246 I80186(config, m_audiocpu, 16_MHz_XTAL);
247 m_audiocpu->set_addrmap(AS_PROGRAM, &wsf_80186_sound_device::leland_80186_map_program);
248 m_audiocpu->set_addrmap(AS_IO, &wsf_80186_sound_device::ataxx_80186_map_io);
249 m_audiocpu->chip_select_callback().set(FUNC(leland_80186_sound_device::peripheral_ctrl));
250 m_audiocpu->tmrout0_handler().set(FUNC(leland_80186_sound_device::i80186_tmr0_w));
251 m_audiocpu->tmrout1_handler().set(FUNC(leland_80186_sound_device::i80186_tmr1_w));
252
253 SPEAKER(config, "speaker").front_center();
254 for (int i = 0; i < 4; i++)
255 {
256 AD7524(config, m_dac[i], 0).add_route(ALL_OUTPUTS, "speaker", 0.2); // unknown DAC
257 DAC_8BIT_BINARY_WEIGHTED(config, m_dacvol[i], 0).set_output_range(0, 1); // unknown DAC
258 m_dacvol[i]->add_route(0, m_dac[i], 1.0, DAC_INPUT_RANGE_HI);
259 m_dacvol[i]->add_route(0, m_dac[i], -1.0, DAC_INPUT_RANGE_LO); // unknown DAC
260 }
261 AD7533(config, "dac9", 0).add_route(ALL_OUTPUTS, "speaker", 1.0); // unknown DAC
262
263 /* sound hardware */
264 YM2151(config, m_ymsnd, 4000000);
265 m_ymsnd->add_route(0, "speaker", 0.40);
266 m_ymsnd->add_route(1, "speaker", 0.40);
267
268 PIT8254(config, m_pit[0], 0);
269 m_pit[0]->set_clk<0>(4000000);
270 m_pit[0]->out_handler<0>().set(m_audiocpu, FUNC(i80186_cpu_device::drq0_w));
271 m_pit[0]->set_clk<1>(4000000);
272 m_pit[0]->out_handler<1>().set(m_audiocpu, FUNC(i80186_cpu_device::drq1_w));
273 m_pit[0]->set_clk<2>(4000000);
274 m_pit[0]->out_handler<2>().set(FUNC(leland_80186_sound_device::pit0_2_w));
275
276 GENERIC_LATCH_16(config, m_soundlatch);
277 }
278
279
leland_80186_map_program(address_map & map)280 void leland_80186_sound_device::leland_80186_map_program(address_map &map)
281 {
282 map(0x00000, 0x03fff).mirror(0x1c000).ram();
283 map(0x20000, 0xfffff).rom().region("audiocpu", 0x20000);
284 }
285
ataxx_80186_map_io(address_map & map)286 void leland_80186_sound_device::ataxx_80186_map_io(address_map &map)
287 {
288 }
289
redline_80186_map_io(address_map & map)290 void redline_80186_sound_device::redline_80186_map_io(address_map &map)
291 {
292 map(0x0000, 0xffff).w(FUNC(redline_80186_sound_device::redline_dac_w));
293 }
294
295
leland_80186_map_io(address_map & map)296 void leland_80186_sound_device::leland_80186_map_io(address_map &map)
297 {
298 map(0x0000, 0xffff).w(FUNC(leland_80186_sound_device::dac_w));
299 }
300
301 /*************************************
302 *
303 * Sound initialization
304 *
305 *************************************/
306
device_start()307 void leland_80186_sound_device::device_start()
308 {
309 // register for savestates
310 save_item(NAME(m_peripheral));
311 save_item(NAME(m_last_control));
312 save_item(NAME(m_clock_active));
313 save_item(NAME(m_clock_tick));
314 save_item(NAME(m_sound_command));
315 save_item(NAME(m_sound_response));
316 save_item(NAME(m_ext_start));
317 save_item(NAME(m_ext_stop));
318 save_item(NAME(m_ext_active));
319
320 // zerofill
321 m_peripheral = 0;
322 m_last_control = 0;
323 m_clock_active = 0;
324 m_clock_tick = 0;
325 m_sound_command = 0;
326 m_sound_response = 0;
327 m_ext_start = 0;
328 m_ext_stop = 0;
329 m_ext_active = 0;
330 }
331
device_reset()332 void leland_80186_sound_device::device_reset()
333 {
334 m_last_control = 0xf8;
335 m_clock_active = 0;
336 m_clock_tick = 0;
337 m_ext_start = 0;
338 m_ext_stop = 0;
339 m_ext_active = 0;
340 if (m_type == TYPE_WSF)
341 m_dacvol[3]->write(0xff); //TODO: determine how to set this if at all
342 }
343
344 DEFINE_DEVICE_TYPE(LELAND_80186, leland_80186_sound_device, "leland_80186_sound", "80186 DAC (Leland)")
345
leland_80186_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)346 leland_80186_sound_device::leland_80186_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
347 : leland_80186_sound_device(mconfig, LELAND_80186, tag, owner, clock)
348 {
349 m_type = TYPE_LELAND;
350 }
351
leland_80186_sound_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,u32 clock)352 leland_80186_sound_device::leland_80186_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
353 : device_t(mconfig, type, tag, owner, clock)
354 , m_soundlatch(*this, "soundlatch")
355 , m_dac(*this, "dac%u", 1U)
356 , m_dac9(*this, "dac9")
357 , m_dacvol(*this, "dac%uvol", 1U)
358 , m_pit(*this, "pit%u", 0U)
359 , m_audiocpu(*this, "audiocpu")
360 , m_ymsnd(*this, "ymsnd")
361 , m_master(*this, finder_base::DUMMY_TAG)
362 , m_ext_base(*this, "ext")
363 {
364 }
365
366 DEFINE_DEVICE_TYPE(REDLINE_80186, redline_80186_sound_device, "redline_80186_sound", "80186 DAC (Redline Racer)")
367
redline_80186_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)368 redline_80186_sound_device::redline_80186_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
369 : leland_80186_sound_device(mconfig, REDLINE_80186, tag, owner, clock)
370 {
371 m_type = TYPE_REDLINE;
372 }
373
374 DEFINE_DEVICE_TYPE(ATAXX_80186, ataxx_80186_sound_device, "ataxx_80186_sound", "80186 DAC (Ataxx)")
375
ataxx_80186_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)376 ataxx_80186_sound_device::ataxx_80186_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
377 : leland_80186_sound_device(mconfig, ATAXX_80186, tag, owner, clock)
378 {
379 m_type = TYPE_ATAXX;
380 }
381
382 DEFINE_DEVICE_TYPE(WSF_80186, wsf_80186_sound_device, "wsf_80186_sound", "80186 DAC (WSF)")
383
wsf_80186_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)384 wsf_80186_sound_device::wsf_80186_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
385 : leland_80186_sound_device(mconfig, WSF_80186, tag, owner, clock)
386 {
387 m_type = TYPE_WSF;
388 }
389
peripheral_ctrl(offs_t offset,u16 data)390 void leland_80186_sound_device::peripheral_ctrl(offs_t offset, u16 data)
391 {
392 switch (offset)
393 {
394 case 2:
395 m_peripheral = data;
396 break;
397
398 case 4:
399 {
400 u32 temp = (m_peripheral & 0xffc0) << 4;
401 if (data & 0x0040)
402 {
403 m_audiocpu->space(AS_PROGRAM).install_readwrite_handler(temp, temp + 0x2ff, read16s_delegate(*this, FUNC(leland_80186_sound_device::peripheral_r)), write16s_delegate(*this, FUNC(leland_80186_sound_device::peripheral_w)));
404 }
405 else
406 {
407 temp &= 0xffff;
408 m_audiocpu->space(AS_IO).install_readwrite_handler(temp, temp + 0x2ff, read16s_delegate(*this, FUNC(leland_80186_sound_device::peripheral_r)), write16s_delegate(*this, FUNC(leland_80186_sound_device::peripheral_w)));
409 }
410 break;
411 }
412
413 default:
414 break;
415 }
416 }
417
418 /*************************************
419 *
420 * External 80186 control
421 *
422 *************************************/
423
leland_80186_control_w(u8 data)424 void leland_80186_sound_device::leland_80186_control_w(u8 data)
425 {
426 /* see if anything changed */
427 int diff = (m_last_control ^ data) & 0xf8;
428 if (diff == 0)
429 return;
430 m_last_control = data;
431
432 if (LOG_COMM)
433 {
434 logerror("%s:80186 control = %02X", machine().describe_context(), data);
435 if (!(data & 0x80)) logerror(" /RESET");
436 if (!(data & 0x40)) logerror(" ZNMI");
437 if (!(data & 0x20)) logerror(" INT0");
438 if (!(data & 0x10)) logerror(" /TEST");
439 if (!(data & 0x08)) logerror(" INT1");
440 logerror("\n");
441 }
442
443 /* /RESET */
444 m_audiocpu->set_input_line(INPUT_LINE_RESET, (data & 0x80) ? CLEAR_LINE : ASSERT_LINE);
445 m_audiocpu->set_input_line(INPUT_LINE_TEST, (data & 0x10) ? CLEAR_LINE : ASSERT_LINE);
446
447 /* /NMI */
448 /* If the master CPU doesn't get a response by the time it's ready to send
449 the next command, it uses an NMI to force the issue; unfortunately, this
450 seems to really screw up the sound system. It turns out it's better to
451 just wait for the original interrupt to occur naturally */
452 /* m_audiocpu->set_input_line(INPUT_LINE_NMI, (data & 0x40) ? CLEAR_LINE : ASSERT_LINE);*/
453
454 /* INT0 */
455 m_audiocpu->int0_w(data & 0x20);
456 /* INT1 */
457 m_audiocpu->int1_w(data & 0x08);
458 /* handle reset here */
459 if ((diff & 0x80) && (data & 0x80))
460 reset();
461 }
462
463
464
465 /*************************************
466 *
467 * Sound command handling
468 *
469 *************************************/
470
command_lo_w(u8 data)471 void leland_80186_sound_device::command_lo_w(u8 data)
472 {
473 if (LOG_COMM) logerror("%s:Write sound command latch lo = %02X\n", machine().describe_context(), data);
474 m_sound_command = (m_sound_command & 0xff00) | data;
475 m_soundlatch->write(m_sound_command);
476 }
477
478
command_hi_w(u8 data)479 void leland_80186_sound_device::command_hi_w(u8 data)
480 {
481 if (LOG_COMM) logerror("%s:Write sound command latch hi = %02X\n", machine().describe_context(), data);
482 m_sound_command = (m_sound_command & 0x00ff) | (data << 8);
483 m_soundlatch->write(m_sound_command);
484 }
485
486
487
488
489 /*************************************
490 *
491 * Sound response handling
492 *
493 *************************************/
494
delayed_response_r(void * ptr,int param)495 void leland_80186_sound_device::delayed_response_r(void *ptr, int param)
496 {
497 int checkpc = param;
498 int pc = m_master->pc();
499 int oldaf = m_master->state_int(Z80_AF);
500
501 /* This is pretty cheesy, but necessary. Since the CPUs run in round-robin order,
502 synchronizing on the write to this register from the slave side does nothing.
503 In order to make sure the master CPU get the real response, we synchronize on
504 the read. However, the value we returned the first time around may not be
505 accurate, so after the system has synced up, we go back into the master CPUs
506 state and put the proper value into the A register. */
507 if (pc == checkpc)
508 {
509 if (LOG_COMM) logerror("(Updated sound response latch to %02X)\n", m_sound_response);
510
511 oldaf = (oldaf & 0x00ff) | (m_sound_response << 8);
512 m_master->set_state_int(Z80_AF, oldaf);
513 }
514 else if(LOG_COMM)
515 logerror("ERROR: delayed_response_r - current PC = %04X, checkPC = %04X\n", pc, checkpc);
516 }
517
518
response_r()519 u8 leland_80186_sound_device::response_r()
520 {
521 offs_t pc = m_master->pcbase();
522
523 if (LOG_COMM) logerror("%04X:Read sound response latch = %02X\n", pc, m_sound_response);
524
525 /* synchronize the response */
526 machine().scheduler().synchronize(timer_expired_delegate(FUNC(leland_80186_sound_device::delayed_response_r), this), pc + 2);
527 return m_sound_response;
528 }
529
530
531
532 /*************************************
533 *
534 * Low-level DAC I/O
535 *
536 *************************************/
537
dac_w(offs_t offset,u16 data,u16 mem_mask)538 void leland_80186_sound_device::dac_w(offs_t offset, u16 data, u16 mem_mask)
539 {
540 int dac = offset & 7;
541
542 /* handle value changes */
543 if (ACCESSING_BITS_0_7)
544 {
545 if ((offset & 0x60) == 0x40)
546 m_audiocpu->drq0_w(CLEAR_LINE);
547 else if ((offset & 0x60) == 0x60)
548 m_audiocpu->drq1_w(CLEAR_LINE);
549
550 m_dac[dac]->write(data & 0xff);
551
552 set_clock_line(dac, 0);
553 }
554
555 /* handle volume changes */
556 if (ACCESSING_BITS_8_15)
557 {
558 m_dacvol[dac]->write(data >> 8);
559 }
560 }
561
562
redline_dac_w(offs_t offset,u16 data)563 void redline_80186_sound_device::redline_dac_w(offs_t offset, u16 data)
564 {
565 data = (data & 0xff) | (offset << 8);
566 offset = ((offset >> 8) & 7) | ((offset & 0x2000) ? 0x40 : 0) | ((offset & 0x800) ? 0x20 : 0);
567 dac_w(offset, data, 0xffff);
568 }
569
ataxx_dac_control(offs_t offset,u16 data,u16 mem_mask)570 void leland_80186_sound_device::ataxx_dac_control(offs_t offset, u16 data, u16 mem_mask)
571 {
572 if (ACCESSING_BITS_0_7)
573 {
574 /* handle common offsets */
575 switch (offset & 0x1f)
576 {
577 case 0x00:
578 dac_w(0x40, data, 0x00ff);
579 return;
580 case 0x01:
581 dac_w(0x61, data, 0x00ff);
582 return;
583 case 0x02:
584 dac_w(2, data, 0x00ff);
585 return;
586 case 0x03:
587 m_dacvol[0]->write((data & 7) << 5);
588 m_dacvol[1]->write(((data >> 3) & 7) << 5);
589 m_dacvol[2]->write(((data >> 6) & 3) << 6);
590 return;
591 }
592 }
593
594 /* if we have a YM2151 (and an external DAC), handle those offsets */
595 switch (m_type)
596 {
597 case TYPE_WSF:
598 switch (offset)
599 {
600 case 0x04:
601 m_ext_active = 1;
602 if (LOG_EXTERN) logerror("External DAC active\n");
603 return;
604 case 0x05:
605 m_ext_active = 0;
606 if (LOG_EXTERN) logerror("External DAC inactive\n");
607 return;
608 case 0x06:
609 m_ext_start >>= 4;
610 COMBINE_DATA(&m_ext_start);
611 m_ext_start <<= 4;
612 if (LOG_EXTERN) logerror("External DAC start = %05X\n", m_ext_start);
613 return;
614 case 0x07:
615 m_ext_stop >>= 4;
616 COMBINE_DATA(&m_ext_stop);
617 m_ext_stop <<= 4;
618 if (LOG_EXTERN) logerror("External DAC stop = %05X\n", m_ext_stop);
619 return;
620 }
621 break;
622 }
623
624 logerror("%s:Unexpected peripheral write %d/%02X = %02X\n", machine().describe_context(), 5, offset, data);
625 }
626
627
628
629 /*************************************
630 *
631 * Peripheral chip dispatcher
632 *
633 *************************************/
634
peripheral_r(offs_t offset,u16 mem_mask)635 u16 leland_80186_sound_device::peripheral_r(offs_t offset, u16 mem_mask)
636 {
637 int select = offset / 0x40;
638 offset &= 0x3f;
639
640 switch (select)
641 {
642 case 0:
643 /* we have to return 0 periodically so that they handle interrupts */
644 //if ((++m_clock_tick & 7) == 0)
645 // return 0;
646
647 /* if we've filled up all the active channels, we can give this CPU a rest */
648 /* until the next interrupt */
649 if (m_type != TYPE_REDLINE)
650 return ((m_clock_active >> 1) & 0x3e);
651 else
652 return ((m_clock_active << 1) & 0x7e);
653
654 case 1:
655 if (LOG_COMM) logerror("%s:Read sound command latch = %02X\n", machine().describe_context(), m_soundlatch->read());
656 return m_soundlatch->read();
657
658 case 2:
659 if (ACCESSING_BITS_0_7)
660 return m_pit[0]->read(offset & 3);
661 break;
662
663 case 3:
664 if (m_type <= TYPE_REDLINE)
665 {
666 if (ACCESSING_BITS_0_7)
667 return m_pit[1]->read(offset & 3);
668 }
669 else if (m_type == TYPE_WSF)
670 return m_ymsnd->read(offset);
671 break;
672
673 case 4:
674 if (m_type == TYPE_REDLINE)
675 {
676 if (ACCESSING_BITS_0_7)
677 return m_pit[2]->read(offset & 3);
678 }
679 else
680 logerror("%s:Unexpected peripheral read %d/%02X\n", machine().describe_context(), select, offset*2);
681 break;
682
683 default:
684 logerror("%s:Unexpected peripheral read %d/%02X\n", machine().describe_context(), select, offset*2);
685 break;
686 }
687 return 0xffff;
688 }
689
690
peripheral_w(offs_t offset,u16 data,u16 mem_mask)691 void leland_80186_sound_device::peripheral_w(offs_t offset, u16 data, u16 mem_mask)
692 {
693 int select = offset / 0x40;
694 offset &= 0x3f;
695
696 switch (select)
697 {
698 case 1:
699 if (LOG_COMM) logerror("%s:Write sound response latch = %02X\n", machine().describe_context(), data);
700 m_sound_response = data;
701 break;
702
703 case 2:
704 if (ACCESSING_BITS_0_7)
705 m_pit[0]->write(offset & 3, data);
706 break;
707
708 case 3:
709 if (m_type <= TYPE_REDLINE)
710 {
711 if (ACCESSING_BITS_0_7)
712 m_pit[1]->write(offset & 3, data);
713 }
714 else if(m_type == TYPE_WSF)
715 m_ymsnd->write(offset, data);
716 break;
717
718 case 4:
719 if (m_type == TYPE_REDLINE)
720 {
721 if (ACCESSING_BITS_0_7)
722 m_pit[2]->write(offset & 3, data);
723 }
724 else if (mem_mask == 0xffff)
725 {
726 m_dac9->write(data);
727 set_clock_line(6, 0);
728 }
729 break;
730
731 case 5: /* Ataxx/WSF/Indy Heat only */
732 if (m_type > TYPE_REDLINE)
733 ataxx_dac_control(offset, data, mem_mask);
734 break;
735
736 default:
737 logerror("%s:Unexpected peripheral write %d/%02X = %02X\n", machine().describe_context(), select, offset, data);
738 break;
739 }
740 }
741
742
743
744 /*************************************
745 *
746 * Game-specific handlers
747 *
748 *************************************/
749
ataxx_80186_control_w(u8 data)750 void leland_80186_sound_device::ataxx_80186_control_w(u8 data)
751 {
752 /* compute the bit-shuffled variants of the bits and then write them */
753 int modified = ((data & 0x01) << 7) |
754 ((data & 0x02) << 5) |
755 ((data & 0x04) << 3) |
756 ((data & 0x08) << 1);
757 leland_80186_control_w(modified);
758 }
759