1 // license: BSD-3-Clause
2 // copyright-holders: Aaron Giles
3 /***************************************************************************
4 
5     Cheap Squeak Deluxe / Artificial Artist Sound Board
6 
7 ***************************************************************************/
8 
9 #include "emu.h"
10 #include "csd.h"
11 
12 
13 //**************************************************************************
14 //  DEVICE DEFINITIONS
15 //**************************************************************************
16 
17 DEFINE_DEVICE_TYPE(MIDWAY_CHEAP_SQUEAK_DELUXE, midway_cheap_squeak_deluxe_device, "midcsd", "Cheap Squeak Deluxe Sound Board")
18 
19 //-------------------------------------------------
20 //  audio cpu map
21 //-------------------------------------------------
22 
23 // address map determined by PAL; verified
csdeluxe_map(address_map & map)24 void midway_cheap_squeak_deluxe_device::csdeluxe_map(address_map &map)
25 {
26 	map.unmap_value_high();
27 	map.global_mask(0x1ffff);
28 	map(0x00000, 0x07fff).rom();
29 	map(0x18000, 0x18007).mirror(0x3ff8).rw("pia", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt)).umask16(0xff00); // Spy Hunter accesses the MSB
30 	map(0x18000, 0x18007).mirror(0x3ff8).rw("pia", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt)).umask16(0x00ff); // Turbo Tag access via the LSB
31 	map(0x1c000, 0x1cfff).ram();
32 }
33 
34 //-------------------------------------------------
35 //  machine configuration
36 //-------------------------------------------------
37 
device_add_mconfig(machine_config & config)38 void midway_cheap_squeak_deluxe_device::device_add_mconfig(machine_config &config)
39 {
40 	M68000(config, m_cpu, DERIVED_CLOCK(1, 2));
41 	m_cpu->set_addrmap(AS_PROGRAM, &midway_cheap_squeak_deluxe_device::csdeluxe_map);
42 
43 	PIA6821(config, m_pia, 0);
44 	m_pia->writepa_handler().set(FUNC(midway_cheap_squeak_deluxe_device::porta_w));
45 	m_pia->writepb_handler().set(FUNC(midway_cheap_squeak_deluxe_device::portb_w));
46 	m_pia->irqa_handler().set(FUNC(midway_cheap_squeak_deluxe_device::irq_w));
47 	m_pia->irqb_handler().set(FUNC(midway_cheap_squeak_deluxe_device::irq_w));
48 
49 	AD7533(config, m_dac, 0).add_route(ALL_OUTPUTS, *this, 1.0);
50 }
51 
52 //-------------------------------------------------
53 //  rom_region - device-specific ROM region
54 //-------------------------------------------------
55 
56 ROM_START( csd )
57 	ROM_REGION(0x4a, "pal", 0)
58 	ROM_LOAD("0304-00803-0052.u15", 0x00, 0x4a, CRC(8b401aee) SHA1(360f3f59877f0bc25b4154782a2011963dd80a52)) // address decoding pal CSD002R0 (PAL14L8)
59 ROM_END
60 
device_rom_region() const61 const tiny_rom_entry *midway_cheap_squeak_deluxe_device::device_rom_region() const
62 {
63 	return ROM_NAME( csd );
64 }
65 
66 //-------------------------------------------------
67 //  midway_cheap_squeak_deluxe_device - constructor
68 //-------------------------------------------------
69 
midway_cheap_squeak_deluxe_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)70 midway_cheap_squeak_deluxe_device::midway_cheap_squeak_deluxe_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
71 	device_t(mconfig, MIDWAY_CHEAP_SQUEAK_DELUXE, tag, owner, clock),
72 	device_mixer_interface(mconfig, *this),
73 	m_cpu(*this, "cpu"),
74 	m_pia(*this, "pia"),
75 	m_dac(*this, "dac"),
76 	m_status(0),
77 	m_dacval(0)
78 {
79 }
80 
81 //-------------------------------------------------
82 //  device_start - device-specific startup
83 //-------------------------------------------------
84 
device_start()85 void midway_cheap_squeak_deluxe_device::device_start()
86 {
87 	save_item(NAME(m_status));
88 	save_item(NAME(m_dacval));
89 }
90 
91 //-------------------------------------------------
92 //  device_timer - timer callbacks
93 //-------------------------------------------------
94 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)95 void midway_cheap_squeak_deluxe_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
96 {
97 	m_pia->ca1_w(param);
98 
99 	// oftentimes games will write one nibble at a time; the sync on this is very
100 	// important, so we boost the interleave briefly while this happens
101 	machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(100));
102 }
103 
104 //-------------------------------------------------
105 //  suspend_cpu
106 //-------------------------------------------------
107 
suspend_cpu()108 void midway_cheap_squeak_deluxe_device::suspend_cpu()
109 {
110 	m_cpu->suspend(SUSPEND_REASON_DISABLE, 1);
111 }
112 
113 //-------------------------------------------------
114 //  stat_r - return the status value
115 //-------------------------------------------------
116 
stat_r()117 u8 midway_cheap_squeak_deluxe_device::stat_r()
118 {
119 	return m_status;
120 }
121 
122 //-------------------------------------------------
123 //  sr_w - external 4-bit write to the input latch
124 //-------------------------------------------------
125 
sr_w(u8 data)126 void midway_cheap_squeak_deluxe_device::sr_w(u8 data)
127 {
128 	m_pia->portb_w(data & 0x0f);
129 }
130 
131 //-------------------------------------------------
132 //  sirq_w - external irq write
133 //-------------------------------------------------
134 
WRITE_LINE_MEMBER(midway_cheap_squeak_deluxe_device::sirq_w)135 WRITE_LINE_MEMBER( midway_cheap_squeak_deluxe_device::sirq_w )
136 {
137 	synchronize(0, !state);
138 }
139 
140 //-------------------------------------------------
141 //  reset_write - write to the reset line
142 //-------------------------------------------------
143 
WRITE_LINE_MEMBER(midway_cheap_squeak_deluxe_device::reset_w)144 WRITE_LINE_MEMBER( midway_cheap_squeak_deluxe_device::reset_w )
145 {
146 	m_cpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE);
147 	m_cpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
148 }
149 
150 //-------------------------------------------------
151 //  porta_w - PIA port A writes
152 //-------------------------------------------------
153 
porta_w(uint8_t data)154 void midway_cheap_squeak_deluxe_device::porta_w(uint8_t data)
155 {
156 	m_dacval = (data << 2) | (m_dacval & 3);
157 	m_dac->write(m_dacval);
158 }
159 
160 //-------------------------------------------------
161 //  portb_w - PIA port B writes
162 //-------------------------------------------------
163 
portb_w(uint8_t data)164 void midway_cheap_squeak_deluxe_device::portb_w(uint8_t data)
165 {
166 	// bit 4-5, status
167 	uint8_t z_mask = m_pia->port_b_z_mask();
168 	if (~z_mask & 0x10)  m_status = (m_status & ~1) | ((data >> 4) & 1);
169 	if (~z_mask & 0x20)  m_status = (m_status & ~2) | ((data >> 4) & 2);
170 
171 	// bit 6-7, dac data
172 	m_dacval = (m_dacval & ~3) | (data >> 6);
173 	m_dac->write(m_dacval);
174 }
175 
176 //-------------------------------------------------
177 //  irq_w - IRQ line state changes
178 //-------------------------------------------------
179 
WRITE_LINE_MEMBER(midway_cheap_squeak_deluxe_device::irq_w)180 WRITE_LINE_MEMBER( midway_cheap_squeak_deluxe_device::irq_w )
181 {
182 	int combined_state = m_pia->irq_a_state() | m_pia->irq_b_state();
183 	m_cpu->set_input_line(4, combined_state ? ASSERT_LINE : CLEAR_LINE);
184 }
185