1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 Hard Drivin' sound hardware
6
7 ****************************************************************************/
8
9 #include "emu.h"
10 #include "includes/harddriv.h"
11
12 #include "cpu/tms32010/tms32010.h"
13 #include "speaker.h"
14
15
16 #define BIO_FREQUENCY (1000000 / 50)
17 #define CYCLES_PER_BIO (5000000 / BIO_FREQUENCY)
18
19
20 //**************************************************************************
21 // LIVE DEVICE
22 //**************************************************************************
23
24 //-------------------------------------------------
25 // harddriv_sound_board_device - constructor
26 //-------------------------------------------------
27
28 DEFINE_DEVICE_TYPE(HARDDRIV_SOUND_BOARD, harddriv_sound_board_device, "harddriv_sound", "Hard Drivin' Sound Board")
29
harddriv_sound_board_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)30 harddriv_sound_board_device::harddriv_sound_board_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
31 device_t(mconfig, HARDDRIV_SOUND_BOARD, tag, owner, clock),
32 m_soundcpu(*this, "soundcpu"),
33 m_latch(*this, "latch"),
34 m_dac(*this, "dac"),
35 m_sounddsp(*this, "sounddsp"),
36 m_sounddsp_ram(*this, "sounddsp_ram"),
37 m_sound_rom(*this, "serialroms"),
38 m_soundflag(0),
39 m_mainflag(0),
40 m_sounddata(0),
41 m_maindata(0),
42 m_cramen(0),
43 m_irq68k(0),
44 m_sound_rom_offs(0),
45 m_last_bio_cycles(0)
46 {
47 memset(m_comram, 0 , sizeof(m_comram));
48 }
49
50
51 //-------------------------------------------------
52 // device_start - device-specific startup
53 //-------------------------------------------------
54
device_start()55 void harddriv_sound_board_device::device_start()
56 {
57 }
58
59 //-------------------------------------------------
60 // device_reset - device-specific reset
61 //-------------------------------------------------
62
device_reset()63 void harddriv_sound_board_device::device_reset()
64 {
65 m_last_bio_cycles = 0;
66 m_sounddsp->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
67 }
68
69 /*************************************
70 *
71 * Update flags
72 *
73 *************************************/
74
update_68k_interrupts()75 void harddriv_sound_board_device::update_68k_interrupts()
76 {
77 m_soundcpu->set_input_line(1, m_mainflag ? ASSERT_LINE : CLEAR_LINE);
78 m_soundcpu->set_input_line(3, m_irq68k ? ASSERT_LINE : CLEAR_LINE);
79 }
80
81
82
83 /*************************************
84 *
85 * I/O from main CPU side
86 *
87 *************************************/
88
hd68k_snd_data_r()89 uint16_t harddriv_sound_board_device::hd68k_snd_data_r()
90 {
91 m_soundflag = 0;
92 logerror("%s:main read from sound=%04X\n", machine().describe_context(), m_sounddata);
93 return m_sounddata;
94 }
95
96
hd68k_snd_status_r()97 uint16_t harddriv_sound_board_device::hd68k_snd_status_r()
98 {
99 return (m_mainflag << 15) | (m_soundflag << 14) | 0x1fff;
100 }
101
102
TIMER_CALLBACK_MEMBER(harddriv_sound_board_device::delayed_68k_w)103 TIMER_CALLBACK_MEMBER( harddriv_sound_board_device::delayed_68k_w )
104 {
105 m_maindata = param;
106 m_mainflag = 1;
107 update_68k_interrupts();
108 }
109
110
hd68k_snd_data_w(uint16_t data)111 void harddriv_sound_board_device::hd68k_snd_data_w(uint16_t data)
112 {
113 machine().scheduler().synchronize(timer_expired_delegate(FUNC(harddriv_sound_board_device::delayed_68k_w), this), data);
114 logerror("%s:main write to sound=%04X\n", machine().describe_context(), data);
115 }
116
117
hd68k_snd_reset_w(uint16_t data)118 void harddriv_sound_board_device::hd68k_snd_reset_w(uint16_t data)
119 {
120 m_soundcpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
121 m_soundcpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
122 m_mainflag = m_soundflag = 0;
123 update_68k_interrupts();
124 logerror("%s:Reset sound\n", machine().describe_context());
125 }
126
127
128
129 /*************************************
130 *
131 * I/O from sound CPU side
132 *
133 *************************************/
134
hdsnd68k_data_r()135 uint16_t harddriv_sound_board_device::hdsnd68k_data_r()
136 {
137 m_mainflag = 0;
138 update_68k_interrupts();
139 logerror("%s:sound read from main=%04X\n", machine().describe_context(), m_maindata);
140 return m_maindata;
141 }
142
143
hdsnd68k_data_w(offs_t offset,uint16_t data,uint16_t mem_mask)144 void harddriv_sound_board_device::hdsnd68k_data_w(offs_t offset, uint16_t data, uint16_t mem_mask)
145 {
146 COMBINE_DATA(&m_sounddata);
147 m_soundflag = 1;
148 logerror("%s:sound write to main=%04X\n", machine().describe_context(), data);
149 }
150
151
152
153 /*************************************
154 *
155 * Misc. 68k inputs
156 *
157 *************************************/
158
hdsnd68k_switches_r(offs_t offset)159 uint16_t harddriv_sound_board_device::hdsnd68k_switches_r(offs_t offset)
160 {
161 logerror("%s:hdsnd68k_switches_r(%04X)\n", machine().describe_context(), offset);
162 return 0;
163 }
164
165
hdsnd68k_320port_r(offs_t offset)166 uint16_t harddriv_sound_board_device::hdsnd68k_320port_r(offs_t offset)
167 {
168 logerror("%s:hdsnd68k_320port_r(%04X)\n", machine().describe_context(), offset);
169 return 0;
170 }
171
172
hdsnd68k_status_r()173 uint16_t harddriv_sound_board_device::hdsnd68k_status_r()
174 {
175 //FFFF 3000 R READSTAT Read Status
176 // D15 = 'Main Flag'
177 // D14 = 'Sound Flag'
178 // D13 = Test Switch
179 // D12 = 5220 Ready Flag (0=Ready)
180 //logerror("%s:hdsnd68k_status_r(%04X)\n", machine().describe_context(), offset);
181 return (m_mainflag << 15) | (m_soundflag << 14) | 0x2000 | 0;//((ioport("IN0")->read() & 0x0020) << 8) | 0;
182 }
183
184
185
186 /*************************************
187 *
188 * Misc. 68k outputs
189 *
190 *************************************/
191
hdsnd68k_latches_w(offs_t offset,uint16_t data)192 void harddriv_sound_board_device::hdsnd68k_latches_w(offs_t offset, uint16_t data)
193 {
194 // bit 3 selects the value; data is ignored
195 // low 3 bits select the function
196 m_latch->write_bit(offset & 7, (offset >> 3) & 1);
197 }
198
199
WRITE_LINE_MEMBER(harddriv_sound_board_device::speech_write_w)200 WRITE_LINE_MEMBER(harddriv_sound_board_device::speech_write_w)
201 {
202 // data == 0 means high, 1 means low
203 logerror("%06X:SPWR=%d\n", m_soundcpu->pcbase(), state);
204 }
205
206
WRITE_LINE_MEMBER(harddriv_sound_board_device::speech_reset_w)207 WRITE_LINE_MEMBER(harddriv_sound_board_device::speech_reset_w)
208 {
209 // data == 0 means low, 1 means high
210 logerror("%06X:SPRES=%d\n", m_soundcpu->pcbase(), state);
211 }
212
213
WRITE_LINE_MEMBER(harddriv_sound_board_device::speech_rate_w)214 WRITE_LINE_MEMBER(harddriv_sound_board_device::speech_rate_w)
215 {
216 // data == 0 means 8kHz, 1 means 10kHz
217 logerror("%06X:SPRATE=%d\n", m_soundcpu->pcbase(), state);
218 }
219
220
WRITE_LINE_MEMBER(harddriv_sound_board_device::cram_enable_w)221 WRITE_LINE_MEMBER(harddriv_sound_board_device::cram_enable_w)
222 {
223 // data == 0 means disable 68k access to COM320, 1 means enable
224 m_cramen = state;
225 }
226
227
WRITE_LINE_MEMBER(harddriv_sound_board_device::led_w)228 WRITE_LINE_MEMBER(harddriv_sound_board_device::led_w)
229 {
230 }
231
232
hdsnd68k_speech_w(offs_t offset,uint16_t data)233 void harddriv_sound_board_device::hdsnd68k_speech_w(offs_t offset, uint16_t data)
234 {
235 logerror("%s:hdsnd68k_speech_w(%04X)=%04X\n", machine().describe_context(), offset, data);
236 }
237
238
hdsnd68k_irqclr_w(uint16_t data)239 void harddriv_sound_board_device::hdsnd68k_irqclr_w(uint16_t data)
240 {
241 m_irq68k = 0;
242 update_68k_interrupts();
243 }
244
245
246
247 /*************************************
248 *
249 * TMS32010 access
250 *
251 *************************************/
252
hdsnd68k_320ram_r(offs_t offset)253 uint16_t harddriv_sound_board_device::hdsnd68k_320ram_r(offs_t offset)
254 {
255 return m_sounddsp_ram[offset & 0xfff];
256 }
257
258
hdsnd68k_320ram_w(offs_t offset,uint16_t data,uint16_t mem_mask)259 void harddriv_sound_board_device::hdsnd68k_320ram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
260 {
261 COMBINE_DATA(&m_sounddsp_ram[offset & 0xfff]);
262 }
263
264
hdsnd68k_320ports_r(offs_t offset)265 uint16_t harddriv_sound_board_device::hdsnd68k_320ports_r(offs_t offset)
266 {
267 return m_sounddsp->space(AS_IO).read_word(offset & 7);
268 }
269
270
hdsnd68k_320ports_w(offs_t offset,uint16_t data)271 void harddriv_sound_board_device::hdsnd68k_320ports_w(offs_t offset, uint16_t data)
272 {
273 m_sounddsp->space(AS_IO).write_word(offset & 7, data);
274 }
275
276
hdsnd68k_320com_r(offs_t offset)277 uint16_t harddriv_sound_board_device::hdsnd68k_320com_r(offs_t offset)
278 {
279 if (m_cramen)
280 return m_comram[offset & 0x1ff];
281
282 logerror("%s:hdsnd68k_320com_r(%04X) -- not allowed\n", machine().describe_context(), offset);
283 return 0xffff;
284 }
285
286
hdsnd68k_320com_w(offs_t offset,uint16_t data,uint16_t mem_mask)287 void harddriv_sound_board_device::hdsnd68k_320com_w(offs_t offset, uint16_t data, uint16_t mem_mask)
288 {
289 if (m_cramen)
290 COMBINE_DATA(&m_comram[offset & 0x1ff]);
291 else
292 logerror("%s:hdsnd68k_320com_w(%04X)=%04X -- not allowed\n", machine().describe_context(), offset, data);
293 }
294
295
296
297 /*************************************
298 *
299 * TMS32010 interrupts
300 *
301 *************************************/
302
READ_LINE_MEMBER(harddriv_sound_board_device::hdsnddsp_get_bio)303 READ_LINE_MEMBER(harddriv_sound_board_device::hdsnddsp_get_bio)
304 {
305 uint64_t cycles_since_last_bio = m_sounddsp->total_cycles() - m_last_bio_cycles;
306 int32_t cycles_until_bio = CYCLES_PER_BIO - cycles_since_last_bio;
307
308 /* if we're not at the next BIO yet, advance us there */
309 if (cycles_until_bio > 0)
310 {
311 m_sounddsp->adjust_icount(-cycles_until_bio);
312 m_last_bio_cycles += CYCLES_PER_BIO;
313 }
314 else
315 m_last_bio_cycles = m_sounddsp->total_cycles();
316 return ASSERT_LINE;
317 }
318
319
320
321 /*************************************
322 *
323 * TMS32010 ports
324 *
325 *************************************/
326
hdsnddsp_dac_w(uint16_t data)327 void harddriv_sound_board_device::hdsnddsp_dac_w(uint16_t data)
328 {
329 /* /DACL */
330 m_dac->write((data >> 4) ^ 0x800); // schematics show d0-3 are ignored & the msb is inverted
331 }
332
333
hdsnddsp_comport_w(uint16_t data)334 void harddriv_sound_board_device::hdsnddsp_comport_w(uint16_t data)
335 {
336 /* COM port TD0-7 */
337 logerror("%s:hdsnddsp_comport_w=%d\n", machine().describe_context(), data);
338 }
339
340
hdsnddsp_mute_w(uint16_t data)341 void harddriv_sound_board_device::hdsnddsp_mute_w(uint16_t data)
342 {
343 /* mute DAC audio, D0=1 */
344 logerror("%s:mute DAC=%d\n", machine().describe_context(), data);
345 }
346
347
hdsnddsp_gen68kirq_w(uint16_t data)348 void harddriv_sound_board_device::hdsnddsp_gen68kirq_w(uint16_t data)
349 {
350 /* generate 68k IRQ */
351 m_irq68k = 1;
352 update_68k_interrupts();
353 }
354
355
hdsnddsp_soundaddr_w(offs_t offset,uint16_t data)356 void harddriv_sound_board_device::hdsnddsp_soundaddr_w(offs_t offset, uint16_t data)
357 {
358 if (offset == 0)
359 {
360 /* select sound ROM block */
361 m_sound_rom_offs = (m_sound_rom_offs & 0xffff) | ((data & 15) << 16);
362 }
363 else
364 {
365 /* sound memory address */
366 m_sound_rom_offs = (m_sound_rom_offs & ~0xffff) | (data & 0xffff);
367 }
368 }
369
370
hdsnddsp_rom_r()371 uint16_t harddriv_sound_board_device::hdsnddsp_rom_r()
372 {
373 if (m_sound_rom_offs < m_sound_rom.length())
374 return m_sound_rom[m_sound_rom_offs++] << 7;
375 m_sound_rom_offs++;
376 return 0;
377 }
378
379
hdsnddsp_comram_r()380 uint16_t harddriv_sound_board_device::hdsnddsp_comram_r()
381 {
382 return m_comram[m_sound_rom_offs++ & 0x1ff];
383 }
384
385
hdsnddsp_compare_r(offs_t offset)386 uint16_t harddriv_sound_board_device::hdsnddsp_compare_r(offs_t offset)
387 {
388 logerror("%s:hdsnddsp_compare_r(%04X)\n", machine().describe_context(), offset);
389 return 0;
390 }
391
driversnd_68k_map(address_map & map)392 void harddriv_sound_board_device::driversnd_68k_map(address_map &map)
393 {
394 map.unmap_value_high();
395 map(0x000000, 0x01ffff).rom();
396 map(0xff0000, 0xff0fff).rw(FUNC(harddriv_sound_board_device::hdsnd68k_data_r), FUNC(harddriv_sound_board_device::hdsnd68k_data_w));
397 map(0xff1000, 0xff1fff).rw(FUNC(harddriv_sound_board_device::hdsnd68k_switches_r), FUNC(harddriv_sound_board_device::hdsnd68k_latches_w));
398 map(0xff2000, 0xff2fff).rw(FUNC(harddriv_sound_board_device::hdsnd68k_320port_r), FUNC(harddriv_sound_board_device::hdsnd68k_speech_w));
399 map(0xff3000, 0xff3fff).rw(FUNC(harddriv_sound_board_device::hdsnd68k_status_r), FUNC(harddriv_sound_board_device::hdsnd68k_irqclr_w));
400 map(0xff4000, 0xff5fff).rw(FUNC(harddriv_sound_board_device::hdsnd68k_320ram_r), FUNC(harddriv_sound_board_device::hdsnd68k_320ram_w));
401 map(0xff6000, 0xff7fff).rw(FUNC(harddriv_sound_board_device::hdsnd68k_320ports_r), FUNC(harddriv_sound_board_device::hdsnd68k_320ports_w));
402 map(0xff8000, 0xffbfff).rw(FUNC(harddriv_sound_board_device::hdsnd68k_320com_r), FUNC(harddriv_sound_board_device::hdsnd68k_320com_w));
403 map(0xffc000, 0xffffff).ram();
404 }
405
406
driversnd_dsp_program_map(address_map & map)407 void harddriv_sound_board_device::driversnd_dsp_program_map(address_map &map)
408 {
409 map.unmap_value_high();
410 map(0x000, 0xfff).ram().share("sounddsp_ram");
411 }
412
413
414 /* $000 - 08F TMS32010 Internal Data RAM in Data Address Space */
415
driversnd_dsp_io_map(address_map & map)416 void harddriv_sound_board_device::driversnd_dsp_io_map(address_map &map)
417 {
418 map(0, 0).r(FUNC(harddriv_sound_board_device::hdsnddsp_rom_r)).w(FUNC(harddriv_sound_board_device::hdsnddsp_dac_w));
419 map(1, 1).r(FUNC(harddriv_sound_board_device::hdsnddsp_comram_r));
420 map(2, 2).r(FUNC(harddriv_sound_board_device::hdsnddsp_compare_r));
421 map(1, 2).nopw();
422 map(3, 3).w(FUNC(harddriv_sound_board_device::hdsnddsp_comport_w));
423 map(4, 4).w(FUNC(harddriv_sound_board_device::hdsnddsp_mute_w));
424 map(5, 5).w(FUNC(harddriv_sound_board_device::hdsnddsp_gen68kirq_w));
425 map(6, 7).w(FUNC(harddriv_sound_board_device::hdsnddsp_soundaddr_w));
426 }
427
428
429 //-------------------------------------------------
430 // device_add_mconfig - add device configuration
431 //-------------------------------------------------
432
device_add_mconfig(machine_config & config)433 void harddriv_sound_board_device::device_add_mconfig(machine_config &config)
434 {
435 /* basic machine hardware */
436 M68000(config, m_soundcpu, 16_MHz_XTAL/2);
437 m_soundcpu->set_addrmap(AS_PROGRAM, &harddriv_sound_board_device::driversnd_68k_map);
438
439 LS259(config, m_latch, 0); // 80R
440 m_latch->q_out_cb<0>().set(FUNC(harddriv_sound_board_device::speech_write_w)); // SPWR - 5220 write strobe
441 m_latch->q_out_cb<1>().set(FUNC(harddriv_sound_board_device::speech_reset_w)); // SPRES - 5220 hard reset
442 m_latch->q_out_cb<2>().set(FUNC(harddriv_sound_board_device::speech_rate_w)); // SPRATE
443 m_latch->q_out_cb<3>().set(FUNC(harddriv_sound_board_device::cram_enable_w)); // CRAMEN
444 m_latch->q_out_cb<4>().set_inputline(m_sounddsp, INPUT_LINE_HALT).invert(); // RES320
445 m_latch->q_out_cb<7>().set(FUNC(harddriv_sound_board_device::led_w));
446
447 TMS32010(config, m_sounddsp, XTAL(20'000'000));
448 m_sounddsp->set_addrmap(AS_PROGRAM, &harddriv_sound_board_device::driversnd_dsp_program_map);
449 /* Data Map is internal to the CPU */
450 m_sounddsp->set_addrmap(AS_IO, &harddriv_sound_board_device::driversnd_dsp_io_map);
451 m_sounddsp->bio().set(FUNC(harddriv_sound_board_device::hdsnddsp_get_bio));
452
453 /* sound hardware */
454 SPEAKER(config, "speaker").front_center();
455
456 AM6012(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.5); // ls374d.75e + ls374d.90e + am6012
457 }
458