1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     midway.cpp
6 
7     Functions to emulate general the various Midway sound cards.
8 
9     TODO: the "Turbo Cheap Squeak" and "Sounds Good" boards are nearly identical
10       in function, but use different CPUs and Memory maps (The PIA hookup, DAC
11       and Filter are all exactly the same), so these should probably be combined
12       into one base class with two subclass device implementations to reduce
13       duplicated code.
14       The "Cheap Squeak Deluxe" board in /audio/csd.cpp is also almost identical
15       to the "Sounds Good" board, and should also be a member of any future
16       combined class/device implementation.
17 
18 ***************************************************************************/
19 
20 #include "emu.h"
21 #include "includes/mcr.h"
22 #include "audio/midway.h"
23 #include "audio/williams.h"
24 
25 #include <algorithm>
26 
27 
28 //**************************************************************************
29 //  GLOBAL VARIABLES
30 //**************************************************************************
31 
32 DEFINE_DEVICE_TYPE(MIDWAY_SSIO,               midway_ssio_device,               "midssio", "Midway SSIO Sound Board")
33 DEFINE_DEVICE_TYPE(MIDWAY_SOUNDS_GOOD,        midway_sounds_good_device,        "midsg",   "Midway Sounds Good Sound Board")
34 DEFINE_DEVICE_TYPE(MIDWAY_TURBO_CHEAP_SQUEAK, midway_turbo_cheap_squeak_device, "midtcs",  "Midway Turbo Cheap Squeak Sound Board")
35 
36 
37 //**************************************************************************
38 //  SUPER SOUND I/O BOARD (SSIO)
39 //**************************************************************************
40 
41 //-------------------------------------------------
42 //  midway_ssio_device - constructor
43 //-------------------------------------------------
44 
midway_ssio_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)45 midway_ssio_device::midway_ssio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
46 	: device_t(mconfig, MIDWAY_SSIO, tag, owner, clock)
47 	, device_mixer_interface(mconfig, *this, 2)
48 	, m_cpu(*this, "cpu")
49 	, m_ay0(*this, "ay0")
50 	, m_ay1(*this, "ay1")
51 	, m_ports(*this, "IP%u", 0U)
52 	, m_status(0)
53 	, m_14024_count(0)
54 	, m_mute(0)
55 	, m_custom_input_mask{ 0U, 0U, 0U, 0U, 0U }
56 	, m_custom_input(*this)
57 	, m_custom_output_mask{ 0U, 0U }
58 	, m_custom_output(*this)
59 {
60 	std::fill(std::begin(m_data), std::end(m_data), 0);
61 	std::fill(std::begin(m_overall), std::end(m_overall), 0);
62 	for (auto &duty_cycle : m_duty_cycle)
63 		std::fill(std::begin(duty_cycle), std::end(duty_cycle), 0);
64 	std::fill(std::begin(m_ayvolume_lookup), std::end(m_ayvolume_lookup), 0);
65 }
66 
67 
68 //-------------------------------------------------
69 //  suspend_cpu
70 //-------------------------------------------------
71 
suspend_cpu()72 void midway_ssio_device::suspend_cpu()
73 {
74 	m_cpu->suspend(SUSPEND_REASON_DISABLE, 1);
75 }
76 
77 //-------------------------------------------------
78 //  read - return the status value
79 //-------------------------------------------------
80 
read()81 uint8_t midway_ssio_device::read()
82 {
83 	return m_status;
84 }
85 
86 
87 //-------------------------------------------------
88 //  write - handle an external write to one of the
89 //  input latches
90 //-------------------------------------------------
91 
write(offs_t offset,uint8_t data)92 void midway_ssio_device::write(offs_t offset, uint8_t data)
93 {
94 	synchronize(0, (offset << 8) | (data & 0xff));
95 }
96 
97 
98 //-------------------------------------------------
99 //  reset_write - write to the reset line
100 //-------------------------------------------------
101 
WRITE_LINE_MEMBER(midway_ssio_device::reset_write)102 WRITE_LINE_MEMBER(midway_ssio_device::reset_write)
103 {
104 	if (state)
105 	{
106 		// going high halts the CPU
107 		device_reset();
108 		m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
109 	}
110 	else
111 	{
112 		// going low resets and reactivates the CPU
113 		m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
114 	}
115 }
116 
117 
118 //-------------------------------------------------
119 //  ioport_read - read from one of the I/O ports
120 //  on the device
121 //-------------------------------------------------
122 
ioport_read(offs_t offset)123 uint8_t midway_ssio_device::ioport_read(offs_t offset)
124 {
125 	uint8_t result = m_ports[offset].read_safe(0xff);
126 	if (!m_custom_input[offset].isnull())
127 		result = (result & ~m_custom_input_mask[offset]) |
128 					(m_custom_input[offset]() & m_custom_input_mask[offset]);
129 	return result;
130 }
131 
132 
133 //-------------------------------------------------
134 //  ioport_write - write to one of the I/O ports
135 //  on the device
136 //-------------------------------------------------
137 
ioport_write(offs_t offset,uint8_t data)138 void midway_ssio_device::ioport_write(offs_t offset, uint8_t data)
139 {
140 	int which = offset >> 2;
141 	if (!m_custom_output[which].isnull())
142 		m_custom_output[which](data & m_custom_output_mask[which]);
143 }
144 
145 
146 //-------------------------------------------------
147 //  compute_ay8910_modulation - precompute
148 //  volume modulation tables based on the duty
149 //  cycle described by the PROMs
150 //-------------------------------------------------
151 
compute_ay8910_modulation()152 void midway_ssio_device::compute_ay8910_modulation()
153 {
154 	//
155 	// AY-8910 modulation:
156 	//
157 	// Starts with a 16MHz oscillator
158 	//  /2 via 7474 flip-flip @ F11
159 	//
160 	// This signal clocks the binary counter @ E11 which
161 	// cascades into the decade counter @ D11. This combo
162 	// effectively counts from 0-159 and then wraps. The
163 	// value from these counters is input to an 82S123 PROM,
164 	// which appears to be standard on all games.
165 	//
166 	// One bit at a time from this PROM is clocked at a time
167 	// and the resulting inverted signal becomes a clock for
168 	// the down counters at F3, F4, F5, F8, F9, and F10. The
169 	// value in these down counters are reloaded after the 160
170 	// counts from the binary/decade counter combination.
171 	//
172 	// When these down counters are loaded, the TC signal is
173 	// clear, which mutes the voice. When the down counters
174 	// cross through 0, the TC signal goes high and the 4016
175 	// multiplexers allow the AY-8910 voice to go through.
176 	// Thus, writing a 0 to the counters will enable the
177 	// voice for the longest period of time, while writing
178 	// a 15 enables it for the shortest period of time.
179 	// This creates an effective duty cycle for the voice.
180 	//
181 	// Given that the down counters are reset 50000 times per
182 	// second (SSIO_CLOCK/2/160), which is above the typical
183 	// frequency of sound output. So we simply apply a volume
184 	// adjustment to each voice according to the duty cycle.
185 	//
186 
187 	// loop over all possible values of the duty cycle
188 	uint8_t *prom = memregion("proms")->base();
189 	for (int volval = 0; volval < 16; volval++)
190 	{
191 		// loop over all the clocks until we run out; look up in the PROM
192 		// to find out when the next clock should fire
193 		int remaining_clocks = volval;
194 		int cur = 0, prev = 1;
195 		int curclock;
196 		for (curclock = 0; curclock < 160 && remaining_clocks; curclock++)
197 		{
198 			cur = prom[curclock / 8] & (0x80 >> (curclock % 8));
199 
200 			// check for a high -> low transition
201 			if (cur == 0 && prev != 0)
202 				remaining_clocks--;
203 
204 			prev = cur;
205 		}
206 
207 		// treat the duty cycle as a volume
208 		m_ayvolume_lookup[15 - volval] = curclock * 100 / 160;
209 	}
210 }
211 
212 
213 //-------------------------------------------------
214 //  clock_14024 - periodic timer to clock the
215 //  7-bit async counter at C12
216 //-------------------------------------------------
217 
INTERRUPT_GEN_MEMBER(midway_ssio_device::clock_14024)218 INTERRUPT_GEN_MEMBER(midway_ssio_device::clock_14024)
219 {
220 	//
221 	//  /SINT is generated as follows:
222 	//
223 	//  Starts with a 16MHz oscillator
224 	//      /2 via 7474 flip-flop @ F11
225 	//      /16 via 74161 binary counter @ E11
226 	//      /10 via 74190 decade counter @ D11
227 	//
228 	//  Bit 3 of the decade counter clocks a 14024 7-bit async counter @ C12.
229 	//  This routine is called to clock this 7-bit counter.
230 	//  Bit 6 of the output is inverted and connected to /SINT.
231 	//
232 	m_14024_count = (m_14024_count + 1) & 0x7f;
233 
234 	// if the low 5 bits clocked to 0, bit 6 has changed state
235 	if ((m_14024_count & 0x3f) == 0)
236 		m_cpu->set_input_line(0, (m_14024_count & 0x40) ? ASSERT_LINE : CLEAR_LINE);
237 }
238 
239 
240 //-------------------------------------------------
241 //  irq_clear - reset the IRQ state and 14024 count
242 //-------------------------------------------------
243 
irq_clear()244 uint8_t midway_ssio_device::irq_clear()
245 {
246 	// a read here asynchronously resets the 14024 count, clearing /SINT
247 	if (!machine().side_effects_disabled())
248 	{
249 		m_14024_count = 0;
250 		m_cpu->set_input_line(0, CLEAR_LINE);
251 	}
252 	return 0xff;
253 }
254 
255 
256 //-------------------------------------------------
257 //  status_w - set the outgoing status value
258 //-------------------------------------------------
259 
status_w(uint8_t data)260 void midway_ssio_device::status_w(uint8_t data)
261 {
262 	m_status = data;
263 }
264 
265 
266 //-------------------------------------------------
267 //  data_r - read incoming data latches
268 //-------------------------------------------------
269 
data_r(offs_t offset)270 uint8_t midway_ssio_device::data_r(offs_t offset)
271 {
272 	return m_data[offset];
273 }
274 
275 
276 //-------------------------------------------------
277 //  porta0_w - handle writes to AY-8910 #0 port A
278 //-------------------------------------------------
279 
porta0_w(uint8_t data)280 void midway_ssio_device::porta0_w(uint8_t data)
281 {
282 	m_duty_cycle[0][0] = data & 15;
283 	m_duty_cycle[0][1] = data >> 4;
284 	update_volumes();
285 }
286 
287 
288 //-------------------------------------------------
289 //  portb0_w - handle writes to AY-8910 #0 port B
290 //-------------------------------------------------
291 
portb0_w(uint8_t data)292 void midway_ssio_device::portb0_w(uint8_t data)
293 {
294 	m_duty_cycle[0][2] = data & 15;
295 	m_overall[0] = (data >> 4) & 7;
296 	update_volumes();
297 }
298 
299 
300 //-------------------------------------------------
301 //  porta1_w - handle writes to AY-8910 #1 port A
302 //-------------------------------------------------
303 
porta1_w(uint8_t data)304 void midway_ssio_device::porta1_w(uint8_t data)
305 {
306 	m_duty_cycle[1][0] = data & 15;
307 	m_duty_cycle[1][1] = data >> 4;
308 	update_volumes();
309 }
310 
311 
312 //-------------------------------------------------
313 //  portb1_w - handle writes to AY-8910 #1 port B
314 //-------------------------------------------------
315 
portb1_w(uint8_t data)316 void midway_ssio_device::portb1_w(uint8_t data)
317 {
318 	m_duty_cycle[1][2] = data & 15;
319 	m_overall[1] = (data >> 4) & 7;
320 	m_mute = data & 0x80;
321 	update_volumes();
322 }
323 
324 
325 //-------------------------------------------------
326 //  update_volumes - update the volumes of each
327 //  AY-8910 channel based on modulation and mute
328 //-------------------------------------------------
329 
update_volumes()330 void midway_ssio_device::update_volumes()
331 {
332 	m_ay0->set_volume(0, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[0][0]]);
333 	m_ay0->set_volume(1, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[0][1]]);
334 	m_ay0->set_volume(2, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[0][2]]);
335 	m_ay1->set_volume(0, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[1][0]]);
336 	m_ay1->set_volume(1, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[1][1]]);
337 	m_ay1->set_volume(2, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[1][2]]);
338 }
339 
340 //-------------------------------------------------
341 //  audio CPU map
342 //-------------------------------------------------
343 
344 // address map verified from schematics
ssio_map(address_map & map)345 void midway_ssio_device::ssio_map(address_map &map)
346 {
347 	map.unmap_value_high();
348 	map(0x0000, 0x3fff).rom();
349 	map(0x8000, 0x83ff).mirror(0x0c00).ram();
350 	map(0x9000, 0x9003).mirror(0x0ffc).r(FUNC(midway_ssio_device::data_r));
351 	map(0xa000, 0xa000).mirror(0x0ffc).w("ay0", FUNC(ay8910_device::address_w));
352 	map(0xa001, 0xa001).mirror(0x0ffc).r("ay0", FUNC(ay8910_device::data_r));
353 	map(0xa002, 0xa002).mirror(0x0ffc).w("ay0", FUNC(ay8910_device::data_w));
354 	map(0xb000, 0xb000).mirror(0x0ffc).w("ay1", FUNC(ay8910_device::address_w));
355 	map(0xb001, 0xb001).mirror(0x0ffc).r("ay1", FUNC(ay8910_device::data_r));
356 	map(0xb002, 0xb002).mirror(0x0ffc).w("ay1", FUNC(ay8910_device::data_w));
357 	map(0xc000, 0xcfff).nopr().w(FUNC(midway_ssio_device::status_w));
358 	map(0xd000, 0xdfff).nopw();    // low bit controls yellow LED
359 	map(0xe000, 0xefff).r(FUNC(midway_ssio_device::irq_clear));
360 	map(0xf000, 0xffff).portr("DIP");    // 6 DIP switches
361 }
362 
363 
364 //-------------------------------------------------
365 //  default ports map
366 //-------------------------------------------------
367 
ssio_input_ports(address_map & map,const char * ssio)368 void midway_ssio_device::ssio_input_ports(address_map &map, const char *ssio)
369 {
370 	map(0x00, 0x04).mirror(0x18).r(ssio, FUNC(midway_ssio_device::ioport_read));
371 	map(0x07, 0x07).mirror(0x18).r(ssio, FUNC(midway_ssio_device::read));
372 	map(0x00, 0x07).w(ssio, FUNC(midway_ssio_device::ioport_write));
373 	map(0x1c, 0x1f).w(ssio, FUNC(midway_ssio_device::write));
374 }
375 
376 
377 //-------------------------------------------------
378 //  ROM definitions
379 //-------------------------------------------------
380 
381 ROM_START( midway_ssio )
382 	ROM_REGION( 0x0020, "proms", 0 )
CRC(e1281ee9)383 	ROM_LOAD( "82s123.12d",   0x0000, 0x0020, CRC(e1281ee9) SHA1(9ac9b01d24affc0ee9227a4364c4fd8f8290343a) )    /* from shollow, assuming it's the same */
384 ROM_END
385 
386 
387 //-------------------------------------------------
388 //  device_rom_region - return a pointer to the
389 //  the device's ROM definitions
390 //-------------------------------------------------
391 
392 const tiny_rom_entry *midway_ssio_device::device_rom_region() const
393 {
394 	return ROM_NAME(midway_ssio);
395 }
396 
397 
398 //-------------------------------------------------
399 // device_add_mconfig - add device configuration
400 //-------------------------------------------------
401 
device_add_mconfig(machine_config & config)402 void midway_ssio_device::device_add_mconfig(machine_config &config)
403 {
404 	Z80(config, m_cpu, DERIVED_CLOCK(1, 2*4));
405 	m_cpu->set_addrmap(AS_PROGRAM, &midway_ssio_device::ssio_map);
406 	if (clock())
407 		m_cpu->set_periodic_int(DEVICE_SELF, FUNC(midway_ssio_device::clock_14024), attotime::from_hz(clock() / (2*16*10)));
408 
409 	AY8910(config, m_ay0, DERIVED_CLOCK(1, 2*4));
410 	m_ay0->port_a_write_callback().set(FUNC(midway_ssio_device::porta0_w));
411 	m_ay0->port_b_write_callback().set(FUNC(midway_ssio_device::portb0_w));
412 	m_ay0->add_route(ALL_OUTPUTS, *this, 0.33, AUTO_ALLOC_INPUT, 0);
413 
414 	AY8910(config, m_ay1, DERIVED_CLOCK(1, 2*4));
415 	m_ay1->port_a_write_callback().set(FUNC(midway_ssio_device::porta1_w));
416 	m_ay1->port_b_write_callback().set(FUNC(midway_ssio_device::portb1_w));
417 	m_ay1->add_route(ALL_OUTPUTS, *this, 0.33, AUTO_ALLOC_INPUT, 1);
418 }
419 
420 
421 //-------------------------------------------------
422 //  device_input_ports - return a pointer to
423 //  the device's I/O ports
424 //-------------------------------------------------
425 
device_input_ports() const426 ioport_constructor midway_ssio_device::device_input_ports() const
427 {
428 	return nullptr;
429 //  return INPUT_PORTS_NAME( midway_ssio );
430 }
431 
432 
433 //-------------------------------------------------
434 //  device_start - device-specific startup
435 //-------------------------------------------------
436 
device_start()437 void midway_ssio_device::device_start()
438 {
439 	compute_ay8910_modulation();
440 	save_item(NAME(m_data));
441 	save_item(NAME(m_status));
442 	save_item(NAME(m_14024_count));
443 	save_item(NAME(m_mute));
444 	save_item(NAME(m_overall));
445 	save_item(NAME(m_duty_cycle));
446 }
447 
448 
449 //-------------------------------------------------
450 //  device_reset - device-specific reset
451 //-------------------------------------------------
452 
device_reset()453 void midway_ssio_device::device_reset()
454 {
455 	// latches also get reset
456 	memset(m_data, 0, sizeof(m_data));
457 	m_status = 0;
458 	m_14024_count = 0;
459 }
460 
461 
462 //-------------------------------------------------
463 //  device_timer - timer callbacks
464 //-------------------------------------------------
465 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)466 void midway_ssio_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
467 {
468 	m_data[param >> 8] = param & 0xff;
469 }
470 
471 
472 
473 //**************************************************************************
474 //  SOUNDS GOOD BOARD
475 //**************************************************************************
476 
477 //-------------------------------------------------
478 //  midway_sounds_good_device - constructor
479 //-------------------------------------------------
480 
midway_sounds_good_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)481 midway_sounds_good_device::midway_sounds_good_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
482 	: device_t(mconfig, MIDWAY_SOUNDS_GOOD, tag, owner, clock)
483 		, device_mixer_interface(mconfig, *this)
484 		, m_cpu(*this, "cpu")
485 		, m_pia(*this, "pia")
486 		, m_dac(*this, "dac")
487 		, m_dac_filter(*this, "dac_filter%u", 0U)
488 		, m_status(0)
489 		, m_dacval(0)
490 {
491 }
492 
493 
494 //-------------------------------------------------
495 //  read - return the status value
496 //-------------------------------------------------
497 
read()498 uint8_t midway_sounds_good_device::read()
499 {
500 	return m_status;
501 }
502 
503 
504 //-------------------------------------------------
505 //  write - handle an external write to the input
506 //  latch
507 //-------------------------------------------------
508 
write(uint8_t data)509 void midway_sounds_good_device::write(uint8_t data)
510 {
511 	synchronize(0, data);
512 }
513 
514 
515 //-------------------------------------------------
516 //  reset_write - write to the reset line
517 //-------------------------------------------------
518 
WRITE_LINE_MEMBER(midway_sounds_good_device::reset_write)519 WRITE_LINE_MEMBER(midway_sounds_good_device::reset_write)
520 {
521 //if (state) osd_printf_debug("SG Reset\n");
522 	m_cpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE);
523 }
524 
525 
526 //-------------------------------------------------
527 //  porta_w - PIA port A writes
528 //-------------------------------------------------
529 
porta_w(uint8_t data)530 void midway_sounds_good_device::porta_w(uint8_t data)
531 {
532 	m_dacval = (data << 2) | (m_dacval & 3);
533 	m_dac->write(m_dacval);
534 }
535 
536 
537 //-------------------------------------------------
538 //  portb_w - PIA port B writes
539 //-------------------------------------------------
540 
portb_w(uint8_t data)541 void midway_sounds_good_device::portb_w(uint8_t data)
542 {
543 	uint8_t z_mask = m_pia->port_b_z_mask();
544 
545 	m_dacval = (m_dacval & ~3) | (data >> 6);
546 	m_dac->write(m_dacval);
547 
548 	if (~z_mask & 0x10)  m_status = (m_status & ~1) | ((data >> 4) & 1);
549 	if (~z_mask & 0x20)  m_status = (m_status & ~2) | ((data >> 4) & 2);
550 }
551 
552 
553 //-------------------------------------------------
554 //  irq_w - IRQ line state changes
555 //-------------------------------------------------
556 
WRITE_LINE_MEMBER(midway_sounds_good_device::irq_w)557 WRITE_LINE_MEMBER(midway_sounds_good_device::irq_w)
558 {
559 	int combined_state = m_pia->irq_a_state() | m_pia->irq_b_state();
560 	m_cpu->set_input_line(4, combined_state ? ASSERT_LINE : CLEAR_LINE);
561 }
562 
563 
564 //-------------------------------------------------
565 //  audio CPU map
566 //-------------------------------------------------
567 
568 // address map determined by PAL20L10 @U15; not dumped/verified yet
569 //Address map (x = ignored; * = selects address within this range)
570 //68k address map known for certain:
571 //a23 a22 a21 a20 a19 a18 a17 a16 a15 a14 a13 a12 a11 a10 a9  a8  a7  a6  a5  a4  a3  a2  a1  (a0 via UDS/LDS)
572 //x   x   x   x   x   *   *   *   ?   ?   ?   ?   ?   ?   ?   ?   ?   ?   ?   ?   ?   ?   ?   ?       RW PAL@
573 //BEGIN 68k map guesses (until we have a pal dump):
574 //x   x   x   x   x   0  [a] [b]  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   ->      R   ROM U7, U17
575 //x   x   x   x   x   0  [c] [d]  *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   ->      R   ROM U8, U18
576 //x   x   x   x   x   1   1   0   x   x   x   x   x   x   x   x   x   x   x   x   0  *e* *f*  1       RW  PIA U9 (e goes to PIA RS0, f goes to PIA RS1, D8-D15 go to PIA D0-D7)
577 //x   x   x   x   x   1   1   1   x   x   x   x   *   *   *   *   *   *   *   *   *   *   *   ?       RW  RAM U6, U16
578 //The ROMTYPE PAL line, is pulled low if JW1 is present, and this presumably controls [a] [b] [c] [d] as such:
579 //When ROMTYPE is HIGH/JW1 absent, 27256 roms: (JW3 should be present, JW2 absent)
580 //x   x   x   x   x   0   0?  0   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   ->      R   ROM U7, U17
581 //x   x   x   x   x   0   0?  1   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   ->      R   ROM U8, U18
582 //When ROMTYPE is LOW/JW1 present, 27512 roms: (JW3 should be absent, JW2 present)
583 //x   x   x   x   x   0   0   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   ->      R   ROM U7, U17
584 //x   x   x   x   x   0   1   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   ->      R   ROM U8, U18
585 //JW2 and JW3 are mutually exclusive, and control whether 68k a16 connects to the EPROM pin 1 line (JW2 present), or whether it is tied high (JW3 present).
586 //EPROM pin 1 is A15 on 27512, and VPP(usually an active high enable) on 27256
587 //END guesses
588 
589 
590 
soundsgood_map(address_map & map)591 void midway_sounds_good_device::soundsgood_map(address_map &map)
592 {
593 	map.unmap_value_high();
594 	map.global_mask(0x7ffff);
595 	map(0x000000, 0x03ffff).rom();
596 	map(0x060000, 0x060007).mirror(0x00fff0).rw(m_pia, FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt)).umask16(0xff00); // RS0 connects to A2, RS1 connects to A1, hence the "alt" functions are used.
597 	map(0x070000, 0x070fff).mirror(0x00f000).ram();
598 }
599 
600 
601 //-------------------------------------------------
602 // device_add_mconfig - add device configuration
603 //-------------------------------------------------
604 
device_add_mconfig(machine_config & config)605 void midway_sounds_good_device::device_add_mconfig(machine_config &config)
606 {
607 	M68000(config, m_cpu, DERIVED_CLOCK(1, 2));
608 	m_cpu->set_addrmap(AS_PROGRAM, &midway_sounds_good_device::soundsgood_map);
609 
610 	PIA6821(config, m_pia, 0);
611 	m_pia->writepa_handler().set(FUNC(midway_sounds_good_device::porta_w));
612 	m_pia->writepb_handler().set(FUNC(midway_sounds_good_device::portb_w));
613 	m_pia->irqa_handler().set(FUNC(midway_sounds_good_device::irq_w));
614 	m_pia->irqb_handler().set(FUNC(midway_sounds_good_device::irq_w));
615 
616 	AD7533(config, m_dac, 0); /// ad7533jn.u10
617 
618 	// The DAC filters here are identical to those on the "Turbo Cheap Squeak" and "Cheap Squeak Deluxe" boards.
619 	//LM359 @U2.2, 2nd order MFB low-pass (fc = 5404.717733, Q = 0.625210, gain = -1.000000)
620 	FILTER_BIQUAD(config, m_dac_filter[2]).opamp_mfb_lowpass_setup(RES_K(150), RES_K(82), RES_K(150), CAP_P(470), CAP_P(150)); // R115, R109, R108, C112, C111
621 	m_dac_filter[2]->add_route(ALL_OUTPUTS, *this, 1.0);
622 	//LM359 @U3.2, 2nd order MFB low-pass (fc = 5310.690763, Q = 1.608630, gain = -1.000000)
623 	FILTER_BIQUAD(config, m_dac_filter[1]).opamp_mfb_lowpass_setup(RES_K(33), RES_K(18), RES_K(33), CAP_P(5600), CAP_P(270)); // R113, R117, R116, C115, C118
624 	m_dac_filter[1]->add_route(ALL_OUTPUTS, m_dac_filter[2], 1.0);
625 	//LM359 @U3.1, 1st order MFB low-pass (fc = 4912.189602, Q = 0.707107(ignored), gain = -1.000000)
626 	FILTER_BIQUAD(config, m_dac_filter[0]).opamp_mfb_lowpass_setup(RES_K(120), RES_K(0), RES_K(120), CAP_P(0), CAP_P(270)); // R112, <short>, R111, <nonexistent>, C113
627 	m_dac_filter[0]->add_route(ALL_OUTPUTS, m_dac_filter[1], 1.0);
628 	m_dac->add_route(ALL_OUTPUTS, m_dac_filter[0], 1.0);
629 }
630 
631 
632 //-------------------------------------------------
633 //  device_start - device-specific startup
634 //-------------------------------------------------
635 
device_start()636 void midway_sounds_good_device::device_start()
637 {
638 	save_item(NAME(m_status));
639 	save_item(NAME(m_dacval));
640 }
641 
642 
643 //-------------------------------------------------
644 //  device_reset - device-specific reset
645 //-------------------------------------------------
646 
device_reset()647 void midway_sounds_good_device::device_reset()
648 {
649 }
650 
651 
652 //-------------------------------------------------
653 //  device_timer - timer callbacks
654 //-------------------------------------------------
655 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)656 void midway_sounds_good_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
657 {
658 	m_pia->portb_w((param >> 1) & 0x0f);
659 	m_pia->ca1_w(~param & 0x01);
660 
661 	// oftentimes games will write one nibble at a time; the sync on this is very
662 	// important, so we boost the interleave briefly while this happens
663 	machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(250));
664 }
665 
666 
667 
668 //**************************************************************************
669 //  TURBO CHEAP SQUEAK BOARD
670 //**************************************************************************
671 
672 //-------------------------------------------------
673 //  midway_turbo_cheap_squeak_device - constructor
674 //-------------------------------------------------
675 
midway_turbo_cheap_squeak_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)676 midway_turbo_cheap_squeak_device::midway_turbo_cheap_squeak_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
677 	: device_t(mconfig, MIDWAY_TURBO_CHEAP_SQUEAK, tag, owner, clock),
678 		device_mixer_interface(mconfig, *this)
679 		, m_cpu(*this, "cpu")
680 		, m_pia(*this, "pia")
681 		, m_dac(*this, "dac")
682 		, m_dac_filter(*this, "dac_filter%u", 0U)
683 		, m_status(0)
684 		, m_dacval(0)
685 {
686 }
687 
688 
689 //-------------------------------------------------
690 //  read - return the status value
691 //-------------------------------------------------
692 
read()693 uint8_t midway_turbo_cheap_squeak_device::read()
694 {
695 	return m_status;
696 }
697 
698 
699 //-------------------------------------------------
700 //  write - handle an external write to the input
701 //  latch
702 //-------------------------------------------------
703 
write(uint8_t data)704 void midway_turbo_cheap_squeak_device::write(uint8_t data)
705 {
706 	synchronize(0, data);
707 }
708 
709 
710 //-------------------------------------------------
711 //  reset_write - write to the reset line
712 //-------------------------------------------------
713 
WRITE_LINE_MEMBER(midway_turbo_cheap_squeak_device::reset_write)714 WRITE_LINE_MEMBER(midway_turbo_cheap_squeak_device::reset_write)
715 {
716 	m_cpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE);
717 }
718 
719 
720 //-------------------------------------------------
721 //  porta_w - PIA port A writes
722 //-------------------------------------------------
723 
porta_w(uint8_t data)724 void midway_turbo_cheap_squeak_device::porta_w(uint8_t data)
725 {
726 	m_dacval = (data << 2) | (m_dacval & 3);
727 	m_dac->write(m_dacval);
728 }
729 
730 
731 //-------------------------------------------------
732 //  portb_w - PIA port B writes
733 //-------------------------------------------------
734 
portb_w(uint8_t data)735 void midway_turbo_cheap_squeak_device::portb_w(uint8_t data)
736 {
737 	m_dacval = (m_dacval & ~3) | (data >> 6);
738 	m_dac->write(m_dacval);
739 	m_status = (data >> 4) & 3;
740 }
741 
742 
743 //-------------------------------------------------
744 //  irq_w - IRQ line state changes
745 //-------------------------------------------------
746 
WRITE_LINE_MEMBER(midway_turbo_cheap_squeak_device::irq_w)747 WRITE_LINE_MEMBER(midway_turbo_cheap_squeak_device::irq_w)
748 {
749 	int combined_state = m_pia->irq_a_state() | m_pia->irq_b_state();
750 	m_cpu->set_input_line(M6809_IRQ_LINE, combined_state ? ASSERT_LINE : CLEAR_LINE);
751 }
752 
753 
754 //-------------------------------------------------
755 //  audio CPU map
756 //-------------------------------------------------
757 
758 // address map verified from schematics
turbocs_map(address_map & map)759 void midway_turbo_cheap_squeak_device::turbocs_map(address_map &map)
760 {
761 	map.unmap_value_high();
762 	map(0x0000, 0x07ff).mirror(0x3800).ram();
763 	map(0x4000, 0x4003).mirror(0x3ffc).rw("pia", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt));
764 	map(0x8000, 0xffff).rom();
765 }
766 
767 
768 //-------------------------------------------------
769 // device_add_mconfig - add device configuration
770 //-------------------------------------------------
771 
device_add_mconfig(machine_config & config)772 void midway_turbo_cheap_squeak_device::device_add_mconfig(machine_config &config)
773 {
774 	MC6809E(config, m_cpu, DERIVED_CLOCK(1, 4));
775 	m_cpu->set_addrmap(AS_PROGRAM, &midway_turbo_cheap_squeak_device::turbocs_map);
776 
777 	PIA6821(config, m_pia, 0);
778 	m_pia->writepa_handler().set(FUNC(midway_turbo_cheap_squeak_device::porta_w));
779 	m_pia->writepb_handler().set(FUNC(midway_turbo_cheap_squeak_device::portb_w));
780 	m_pia->irqa_handler().set(FUNC(midway_turbo_cheap_squeak_device::irq_w));
781 	m_pia->irqb_handler().set(FUNC(midway_turbo_cheap_squeak_device::irq_w));
782 
783 	AD7533(config, m_dac, 0); /// ad7533jn.u11
784 
785 	// The DAC filters here are identical to those on the "Sounds Good" and "Cheap Squeak Deluxe" boards.
786 	//LM359 @U14.2, 2nd order MFB low-pass (fc = 5404.717733, Q = 0.625210, gain = -1.000000)
787 	FILTER_BIQUAD(config, m_dac_filter[2]).opamp_mfb_lowpass_setup(RES_K(150), RES_K(82), RES_K(150), CAP_P(470), CAP_P(150)); // R36, R37, R39, C19, C20
788 	m_dac_filter[2]->add_route(ALL_OUTPUTS, *this, 1.0);
789 	//LM359 @U13.2, 2nd order MFB low-pass (fc = 5310.690763, Q = 1.608630, gain = -1.000000)
790 	FILTER_BIQUAD(config, m_dac_filter[1]).opamp_mfb_lowpass_setup(RES_K(33), RES_K(18), RES_K(33), CAP_P(5600), CAP_P(270)); // R32, R33, R35, C16, C17
791 	m_dac_filter[1]->add_route(ALL_OUTPUTS, m_dac_filter[2], 1.0);
792 	//LM359 @U13.1, 1st order MFB low-pass (fc = 4912.189602, Q = 0.707107(ignored), gain = -1.000000)
793 	FILTER_BIQUAD(config, m_dac_filter[0]).opamp_mfb_lowpass_setup(RES_K(120), RES_K(0), RES_K(120), CAP_P(0), CAP_P(270)); // R27, <short>, R31, <nonexistent>, C14
794 	m_dac_filter[0]->add_route(ALL_OUTPUTS, m_dac_filter[1], 1.0);
795 	m_dac->add_route(ALL_OUTPUTS, m_dac_filter[0], 1.0);
796 }
797 
798 
799 //-------------------------------------------------
800 //  device_start - device-specific startup
801 //-------------------------------------------------
802 
device_start()803 void midway_turbo_cheap_squeak_device::device_start()
804 {
805 	save_item(NAME(m_status));
806 	save_item(NAME(m_dacval));
807 }
808 
809 
810 //-------------------------------------------------
811 //  device_reset - device-specific reset
812 //-------------------------------------------------
813 
device_reset()814 void midway_turbo_cheap_squeak_device::device_reset()
815 {
816 }
817 
818 
819 //-------------------------------------------------
820 //  device_timer - timer callbacks
821 //-------------------------------------------------
822 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)823 void midway_turbo_cheap_squeak_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
824 {
825 	m_pia->portb_w((param >> 1) & 0x0f);
826 	m_pia->ca1_w(~param & 0x01);
827 
828 	// oftentimes games will write one nibble at a time; the sync on this is very
829 	// important, so we boost the interleave briefly while this happens
830 	machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(100));
831 }
832