1 // license:BSD-3-Clause
2 // copyright-holders:Bryan McPhail, Aaron Giles, R. Belmont, Philip Bennett
3 /***************************************************************************
4 
5     Taito Ensoniq ES5505-based sound hardware
6 
7     TODO:
8 
9     * ES5510 ESP emulation is not perfect
10     * ES5510 Input Clock and ES5505 Output channels are same in other PCBs?
11       (Currently these are verified from Gun Buster schematics)
12     * Where does the MB8421 go? Taito F3 (and Super Chase) have 2 of them on
13       the sound area, Taito JC has one.
14 
15 ****************************************************************************/
16 
17 #include "emu.h"
18 #include "taito_en.h"
19 #include <algorithm>
20 
21 
22 DEFINE_DEVICE_TYPE(TAITO_EN, taito_en_device, "taito_en", "Taito Ensoniq Sound System")
23 
taito_en_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)24 taito_en_device::taito_en_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
25 	: device_t(mconfig, TAITO_EN, tag, owner, clock)
26 	, device_mixer_interface(mconfig, *this, 2)
27 	, m_audiocpu(*this, "audiocpu")
28 	, m_ensoniq(*this, "ensoniq")
29 	, m_esp(*this, "esp")
30 	, m_pump(*this, "pump")
31 	, m_duart68681(*this, "duart68681")
32 	, m_mb87078(*this, "mb87078")
33 	, m_osram(*this, "osram")
34 	, m_otisbank(*this, "otisbank")
35 	, m_otisrom(*this, "ensoniq")
36 	, m_osrom(*this, "audiocpu")
37 	, m_cpubank(*this, "cpubank%u", 1)
38 {
39 }
40 
41 //-------------------------------------------------
42 //  device_start - device-specific startup
43 //-------------------------------------------------
44 
device_start()45 void taito_en_device::device_start()
46 {
47 	// tell the pump about the ESP chips
48 	uint8_t *ROM = m_osrom->base();
49 	uint32_t max = (m_osrom->bytes() - 0x100000) / 0x20000;
50 	for (int i = 0; i < 3; i++)
51 		m_cpubank[i]->configure_entries(0, max, &ROM[0x100000], 0x20000);
52 
53 	m_bankmask = ((m_otisrom.bytes()) / 0x200000) - 1;
54 
55 	// initialize precalculated ES5505 bank table
56 	const size_t otisbank_size = m_otisbank.bytes() / 2;
57 	m_calculated_otisbank = make_unique_clear<offs_t[]>(otisbank_size);
58 
59 	save_item(NAME(m_old_clock));
60 	save_pointer(NAME(m_calculated_otisbank), otisbank_size);
61 }
62 
63 
64 //-------------------------------------------------
65 //  device_reset - device-specific reset
66 //-------------------------------------------------
67 
device_reset()68 void taito_en_device::device_reset()
69 {
70 	/* Sound cpu program loads to 0xc00000 so we use a bank */
71 	uint32_t max = (m_osrom->bytes() - 0x100000) / 0x20000;
72 	for (int i = 0; i < 3; i++)
73 		m_cpubank[i]->set_entry(i % max);
74 
75 	uint16_t *ROM = (uint16_t *)m_osrom->base();
76 	std::copy(&ROM[0x80000], &ROM[0x80004], &m_osram[0]); /* Stack and Reset vectors */
77 }
78 
79 
80 /*************************************
81  *
82  *  Handlers
83  *
84  *************************************/
85 
en_es5505_bank_w(offs_t offset,uint16_t data)86 void taito_en_device::en_es5505_bank_w(offs_t offset, uint16_t data)
87 {
88 	/* mask out unused bits */
89 	m_otisbank[offset] = data;
90 	m_calculated_otisbank[offset] = (m_otisbank[offset] & m_bankmask) << 20;
91 }
92 
en_volume_w(offs_t offset,uint8_t data)93 void taito_en_device::en_volume_w(offs_t offset, uint8_t data)
94 {
95 	m_mb87078->data_w(offset ^ 1, data);
96 }
97 
98 
99 /*************************************
100  *
101  *  68000 memory map
102  *
103  *************************************/
104 
en_sound_map(address_map & map)105 void taito_en_device::en_sound_map(address_map &map)
106 {
107 	map(0x000000, 0x00ffff).ram().mirror(0x30000).share("osram");
108 	map(0x140000, 0x140fff).rw("dpram", FUNC(mb8421_device::right_r), FUNC(mb8421_device::right_w)).umask16(0xff00);
109 	map(0x200000, 0x20001f).rw("ensoniq", FUNC(es5505_device::read), FUNC(es5505_device::write));
110 	map(0x260000, 0x2601ff).rw("esp", FUNC(es5510_device::host_r), FUNC(es5510_device::host_w)).umask16(0x00ff);
111 	map(0x280000, 0x28001f).rw("duart68681", FUNC(mc68681_device::read), FUNC(mc68681_device::write)).umask16(0x00ff);
112 	map(0x300000, 0x30003f).w(FUNC(taito_en_device::en_es5505_bank_w)).share("otisbank");
113 	map(0x340000, 0x340003).w(FUNC(taito_en_device::en_volume_w)).umask16(0xff00);
114 	map(0xc00000, 0xc1ffff).bankr("cpubank1");
115 	map(0xc20000, 0xc3ffff).bankr("cpubank2");
116 	map(0xc40000, 0xc7ffff).bankr("cpubank3");
117 	map(0xff0000, 0xffffff).ram().share("osram");  // mirror
118 }
119 
fc7_map(address_map & map)120 void taito_en_device::fc7_map(address_map &map)
121 {
122 	map(0xfffffd, 0xfffffd).r(m_duart68681, FUNC(mc68681_device::get_irq_vector));
123 }
124 
125 
126 /*************************************
127  *
128  *  ES5505 memory map
129  *
130  *************************************/
131 
en_otis_map(address_map & map)132 void taito_en_device::en_otis_map(address_map &map)
133 {
134 	map(0x000000, 0x0fffff).lr16(
135 		[this](offs_t offset) -> u16 { return m_otisrom[(m_calculated_otisbank[m_ensoniq->get_voice_index()] + offset) & m_otisrom.mask()]; }, "banked_otisrom");
136 }
137 
138 
139 /*************************************
140  *
141  *  MB87078 callback
142  *
143  *************************************/
144 
mb87078_gain_changed(offs_t offset,uint8_t data)145 void taito_en_device::mb87078_gain_changed(offs_t offset, uint8_t data)
146 {
147 	if (offset > 1)
148 	{
149 		// TODO : ES5505 Volume control is correct?
150 		m_ensoniq->set_output_gain(offset & 1, data / 32.0);
151 		m_ensoniq->set_output_gain(2|(offset & 1), data / 32.0);
152 		m_ensoniq->set_output_gain(4|(offset & 1), data / 32.0);
153 		m_ensoniq->set_output_gain(6|(offset & 1), data / 32.0);
154 		m_pump->set_output_gain(offset & 1, data / 32.0);
155 	}
156 }
157 
158 
159 /*************************************
160  *
161  *  ES5510 callback
162  *
163  *************************************/
164 
es5505_clock_changed(u32 data)165 void taito_en_device::es5505_clock_changed(u32 data)
166 {
167 	if (m_old_clock != data)
168 	{
169 		m_pump->set_unscaled_clock(data);
170 		m_old_clock = data;
171 	}
172 }
173 
174 
175 /*************************************
176  *
177  *  Device interfaces
178  *
179  *************************************/
180 
181 /*
182     68681 I/O pin assignments
183     (according to Gun Buster schematics):
184 
185     IP0: 5V         OP0-OP5: N/C
186     IP1: 5V         OP6: ESPHALT
187     IP2: 1MHz       OP7: N/C
188     IP3: 0.5MHz
189     IP4: 0.5MHz
190     IP5: 1MHz
191 */
192 
duart_output(uint8_t data)193 void taito_en_device::duart_output(uint8_t data)
194 {
195 	if (data & 0x40)
196 	{
197 		if (!m_pump->get_esp_halted())
198 		{
199 			logerror("Asserting ESPHALT\n");
200 			m_pump->set_esp_halted(true);
201 		}
202 	}
203 	else
204 	{
205 		if (m_pump->get_esp_halted())
206 		{
207 			logerror("Clearing ESPHALT\n");
208 			m_pump->set_esp_halted(false);
209 		}
210 	}
211 }
212 
213 //-------------------------------------------------
214 // device_add_mconfig - add device configuration
215 //-------------------------------------------------
216 
device_add_mconfig(machine_config & config)217 void taito_en_device::device_add_mconfig(machine_config &config)
218 {
219 	/* basic machine hardware */
220 	M68000(config, m_audiocpu, XTAL(30'476'180) / 2);
221 	m_audiocpu->set_addrmap(AS_PROGRAM, &taito_en_device::en_sound_map);
222 	m_audiocpu->set_addrmap(m68000_device::AS_CPU_SPACE, &taito_en_device::fc7_map);
223 
224 	ES5510(config, m_esp, XTAL(10'000'000)); // from Gun Buster schematics
225 	m_esp->set_disable();
226 
227 	MC68681(config, m_duart68681, XTAL(16'000'000) / 4);
228 	m_duart68681->set_clocks(XTAL(16'000'000)/2/8, XTAL(16'000'000)/2/16, XTAL(16'000'000)/2/16, XTAL(16'000'000)/2/8);
229 	m_duart68681->irq_cb().set_inputline(m_audiocpu, M68K_IRQ_6);
230 	m_duart68681->outport_cb().set(FUNC(taito_en_device::duart_output));
231 
232 	MB87078(config, m_mb87078);
233 	m_mb87078->gain_changed().set(FUNC(taito_en_device::mb87078_gain_changed));
234 
235 	MB8421(config, "dpram", 0); // host accesses this from the other side
236 
237 	/* sound hardware */
238 	ESQ_5505_5510_PUMP(config, m_pump, XTAL(30'476'180) / (2 * 16 * 32));
239 	m_pump->set_esp(m_esp);
240 	m_pump->add_route(0, *this, 0.5, AUTO_ALLOC_INPUT, 0);
241 	m_pump->add_route(1, *this, 0.5, AUTO_ALLOC_INPUT, 1);
242 
243 	ES5505(config, m_ensoniq, XTAL(30'476'180) / 2);
244 	m_ensoniq->sample_rate_changed().set(FUNC(taito_en_device::es5505_clock_changed));
245 	m_ensoniq->set_addrmap(0, &taito_en_device::en_otis_map);
246 	m_ensoniq->set_addrmap(1, &taito_en_device::en_otis_map);
247 	m_ensoniq->set_channels(4);
248 	m_ensoniq->add_route(0, "pump", 0.18, 0);
249 	m_ensoniq->add_route(1, "pump", 0.18, 1);
250 	m_ensoniq->add_route(2, "pump", 0.18, 2);
251 	m_ensoniq->add_route(3, "pump", 0.18, 3);
252 	m_ensoniq->add_route(4, "pump", 0.18, 4);
253 	m_ensoniq->add_route(5, "pump", 0.18, 5);
254 	m_ensoniq->add_route(6, "pump", 0.18, 6);
255 	m_ensoniq->add_route(7, "pump", 0.18, 7);
256 }
257