1 // license:BSD-3-Clause
2 // copyright-holders:Phil Bennett
3 /***************************************************************************
4
5 Acclaim RAX Sound Board
6
7 ****************************************************************************/
8
9 #include "emu.h"
10 #include "rax.h"
11 #include "speaker.h"
12
13
14 /*************************************
15 *
16 * Constants
17 *
18 *************************************/
19
20 /* These are some of the control registers. We don't use them all */
21 enum
22 {
23 IDMA_CONTROL_REG = 0, /* 3fe0 */
24 BDMA_INT_ADDR_REG, /* 3fe1 */
25 BDMA_EXT_ADDR_REG, /* 3fe2 */
26 BDMA_CONTROL_REG, /* 3fe3 */
27 BDMA_WORD_COUNT_REG, /* 3fe4 */
28 PROG_FLAG_DATA_REG, /* 3fe5 */
29 PROG_FLAG_CONTROL_REG, /* 3fe6 */
30
31 S1_AUTOBUF_REG = 15, /* 3fef */
32 S1_RFSDIV_REG, /* 3ff0 */
33 S1_SCLKDIV_REG, /* 3ff1 */
34 S1_CONTROL_REG, /* 3ff2 */
35 S0_AUTOBUF_REG, /* 3ff3 */
36 S0_RFSDIV_REG, /* 3ff4 */
37 S0_SCLKDIV_REG, /* 3ff5 */
38 S0_CONTROL_REG, /* 3ff6 */
39 S0_MCTXLO_REG, /* 3ff7 */
40 S0_MCTXHI_REG, /* 3ff8 */
41 S0_MCRXLO_REG, /* 3ff9 */
42 S0_MCRXHI_REG, /* 3ffa */
43 TIMER_SCALE_REG, /* 3ffb */
44 TIMER_COUNT_REG, /* 3ffc */
45 TIMER_PERIOD_REG, /* 3ffd */
46 WAITSTATES_REG, /* 3ffe */
47 SYSCONTROL_REG /* 3fff */
48 };
49
50
51 /*************************************
52 *
53 * Interface
54 *
55 *************************************/
56
data_w(uint16_t data)57 void acclaim_rax_device::data_w(uint16_t data)
58 {
59 m_data_in->write(data);
60 m_cpu->set_input_line(ADSP2181_IRQL0, ASSERT_LINE);
61 machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(5));
62 }
63
64
data_r()65 uint16_t acclaim_rax_device::data_r()
66 {
67 m_adsp_snd_pf0 = 1;
68 return m_data_out->read();
69 }
70
71
72 /*************************************
73 *
74 * Internal
75 *
76 *************************************/
77
adsp_control_r(offs_t offset)78 uint16_t acclaim_rax_device::adsp_control_r(offs_t offset)
79 {
80 uint16_t res = 0;
81
82 switch (offset)
83 {
84 case PROG_FLAG_DATA_REG:
85 res = m_adsp_snd_pf0;
86 break;
87 default:
88 res = m_control_regs[offset];
89 }
90
91 return res;
92 }
93
adsp_control_w(offs_t offset,uint16_t data)94 void acclaim_rax_device::adsp_control_w(offs_t offset, uint16_t data)
95 {
96 m_control_regs[offset] = data;
97
98 switch (offset)
99 {
100 case 0x1:
101 m_control_regs[BDMA_INT_ADDR_REG] = data & 0x3fff;
102 break;
103 case 0x2:
104 m_control_regs[BDMA_EXT_ADDR_REG] = data & 0x3fff;
105 break;
106 case 0x3:
107 m_control_regs[BDMA_CONTROL_REG] = data & 0xff0f;
108 break;
109
110 case 0x4:
111 {
112 m_control_regs[BDMA_WORD_COUNT_REG] = data & 0x3fff;
113
114 const uint8_t *adsp_rom = &m_rom[m_rom_bank * 0x400000];
115
116 uint32_t page = (m_control_regs[BDMA_CONTROL_REG] >> 8) & 0xff;
117 uint32_t dir = (m_control_regs[BDMA_CONTROL_REG] >> 2) & 1;
118 uint32_t type = m_control_regs[BDMA_CONTROL_REG] & 3;
119 uint32_t src_addr = (page << 14) | m_control_regs[BDMA_EXT_ADDR_REG];
120
121 uint32_t count = m_control_regs[BDMA_WORD_COUNT_REG];
122
123 address_space* addr_space = (type == 0 ? m_program : m_data);
124
125 if (dir == 0)
126 {
127 if (type == 0)
128 {
129 while (count)
130 {
131 uint32_t src_dword = (adsp_rom[src_addr + 0] << 16) | (adsp_rom[src_addr + 1] << 8) | adsp_rom[src_addr + 2];
132
133 addr_space->write_dword(m_control_regs[BDMA_INT_ADDR_REG], src_dword);
134
135 src_addr += 3;
136 ++m_control_regs[BDMA_INT_ADDR_REG];
137 --count;
138 }
139 }
140 else if (type == 1)
141 {
142 while (count)
143 {
144 uint16_t src_word = (adsp_rom[src_addr + 0] << 8) | adsp_rom[src_addr + 1];
145
146 addr_space->write_word(m_control_regs[BDMA_INT_ADDR_REG], src_word);
147
148 src_addr += 2;
149 ++m_control_regs[BDMA_INT_ADDR_REG];
150 --count;
151 }
152 }
153 else
154 {
155 int shift = type == 2 ? 8 : 0;
156
157 while (count)
158 {
159 uint16_t src_word = adsp_rom[src_addr] << shift;
160
161 addr_space->write_word(m_control_regs[BDMA_INT_ADDR_REG], src_word);
162
163 ++src_addr;
164 ++m_control_regs[BDMA_INT_ADDR_REG];
165 --count;
166 }
167 }
168 }
169 else
170 {
171 // TODO: last stage in Batman Forever!?
172 // page = 0, dir = 1, type = 1, src_addr = 0xfd
173 fatalerror("%s DMA to byte memory!",this->tag());
174 }
175
176 attotime word_period = attotime::from_hz(m_cpu->unscaled_clock());
177 attotime period = word_period * (data & 0x3fff) * 1;
178 m_dma_timer->adjust(period, src_addr, period);
179
180 break;
181 }
182
183 case S1_AUTOBUF_REG:
184 /* autobuffer off: nuke the timer, and disable the DAC */
185 if ((data & 0x0002) == 0)
186 {
187 m_dmadac[1]->enable(0);
188 }
189 break;
190
191 case S0_AUTOBUF_REG:
192 /* autobuffer off: nuke the timer, and disable the DAC */
193 if ((data & 0x0002) == 0)
194 {
195 m_dmadac[0]->enable(0);
196 m_reg_timer->reset();
197 }
198 break;
199
200 case S1_CONTROL_REG:
201 if (((data >> 4) & 3) == 2)
202 fatalerror("DCS: Oh no!, the data is compressed with u-law encoding\n");
203 if (((data >> 4) & 3) == 3)
204 fatalerror("DCS: Oh no!, the data is compressed with A-law encoding\n");
205 break;
206
207 case PROG_FLAG_DATA_REG:
208 logerror("PFLAGS: %x\n", data);
209 break;
210 case PROG_FLAG_CONTROL_REG:
211 logerror("PFLAG CTRL: %x\n", data);
212 break;
213 default:
214 logerror("Unhandled register: %x %x\n", 0x3fe0 + offset, data);
215 }
216 }
217
218
TIMER_DEVICE_CALLBACK_MEMBER(acclaim_rax_device::dma_timer_callback)219 TIMER_DEVICE_CALLBACK_MEMBER( acclaim_rax_device::dma_timer_callback )
220 {
221 /* Update external address count and page */
222 m_control_regs[BDMA_WORD_COUNT_REG] = 0;
223 m_control_regs[BDMA_EXT_ADDR_REG] = param & 0x3fff;
224 m_control_regs[BDMA_CONTROL_REG] &= ~0xff00;
225 m_control_regs[BDMA_CONTROL_REG] |= ((param >> 14) & 0xff) << 8;
226
227 if (m_control_regs[BDMA_CONTROL_REG] & 8)
228 m_cpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero);
229 else
230 m_cpu->pulse_input_line(ADSP2181_BDMA, m_cpu->minimum_quantum_time());
231
232 timer.adjust(attotime::never);
233 }
234
235
update_data_ram_bank()236 void acclaim_rax_device::update_data_ram_bank()
237 {
238 if (m_dmovlay_val == 0)
239 membank("databank")->set_entry(0);
240 else
241 membank("databank")->set_entry(1 + m_data_bank);
242 }
243
ram_bank_w(uint16_t data)244 void acclaim_rax_device::ram_bank_w(uint16_t data)
245 {
246 // Note: The PCB has two unstuffed RAM locations
247 m_data_bank = data & 3;
248 update_data_ram_bank();
249 }
250
rom_bank_w(uint16_t data)251 void acclaim_rax_device::rom_bank_w(uint16_t data)
252 {
253 m_rom_bank = data;
254 }
255
host_r()256 uint16_t acclaim_rax_device::host_r()
257 {
258 m_cpu->set_input_line(ADSP2181_IRQL0, CLEAR_LINE);
259 return m_data_in->read();
260 }
261
host_w(uint16_t data)262 void acclaim_rax_device::host_w(uint16_t data)
263 {
264 m_data_out->write(data);
265 m_adsp_snd_pf0 = 0;
266 }
267
268
269 /*************************************
270 *
271 * CPU memory map & config
272 *
273 *************************************/
274
adsp_program_map(address_map & map)275 void acclaim_rax_device::adsp_program_map(address_map &map)
276 {
277 map.unmap_value_high();
278 map(0x0000, 0x3fff).ram().share("adsp_pram");
279 }
280
adsp_data_map(address_map & map)281 void acclaim_rax_device::adsp_data_map(address_map &map)
282 {
283 map.unmap_value_high();
284 map(0x0000, 0x1fff).bankrw("databank");
285 map(0x2000, 0x3fdf).ram(); // Internal RAM
286 map(0x3fe0, 0x3fff).rw(FUNC(acclaim_rax_device::adsp_control_r), FUNC(acclaim_rax_device::adsp_control_w));
287 }
288
adsp_io_map(address_map & map)289 void acclaim_rax_device::adsp_io_map(address_map &map)
290 {
291 map.unmap_value_high();
292 map(0x0000, 0x0000).w(FUNC(acclaim_rax_device::ram_bank_w));
293 map(0x0001, 0x0001).w(FUNC(acclaim_rax_device::rom_bank_w));
294 map(0x0003, 0x0003).rw(FUNC(acclaim_rax_device::host_r), FUNC(acclaim_rax_device::host_w));
295 }
296
297
device_start()298 void acclaim_rax_device::device_start()
299 {
300 m_program = &m_cpu->space(AS_PROGRAM);
301 m_data = &m_cpu->space(AS_DATA);
302
303 // 1 bank for internal
304 m_banked_ram = make_unique_clear<uint16_t[]>(0x2000 * 5);
305 membank("databank")->configure_entries(0, 5, &m_banked_ram[0], 0x2000*sizeof(uint16_t));
306 }
307
device_reset()308 void acclaim_rax_device::device_reset()
309 {
310 /* Load 32 program words (96 bytes) via BDMA */
311 for (int i = 0; i < 32; i ++)
312 {
313 uint32_t word;
314
315 word = m_rom[i*3 + 0] << 16;
316 word |= m_rom[i*3 + 1] << 8;
317 word |= m_rom[i*3 + 2];
318
319 m_adsp_pram[i] = word;
320 }
321
322 m_adsp_snd_pf0 = 1;
323 m_rom_bank = 0;
324
325 /* initialize our state structure and install the transmit callback */
326 m_size[0] = 0;
327 m_incs[0] = 0;
328 m_ireg[0] = 0;
329
330 /* initialize the ADSP control regs */
331 memset(m_control_regs, 0, sizeof(m_control_regs));
332
333 m_dmovlay_val = 0;
334 m_data_bank = 0;
335 update_data_ram_bank();
336 }
337
338
adsp_irq(int which)339 void acclaim_rax_device::adsp_irq(int which)
340 {
341 if (which != 0)
342 return;
343
344 /* get the index register */
345 int reg = m_cpu->state_int(ADSP2100_I0 + m_ireg[which]);
346
347 /* copy the current data into the buffer */
348 int count = m_size[which] / (4 * (m_incs[which] ? m_incs[which] : 1));
349
350 int16_t buffer[0x100];
351
352 for (uint32_t i = 0; i < count; i++)
353 {
354 buffer[i] = m_data->read_word(reg);
355 reg += m_incs[which];
356 }
357
358 for (int i = 0; i < 2; i++)
359 {
360 m_dmadac[i]->flush();
361 m_dmadac[i]->transfer(i, 1, 2, count/2, buffer);
362 }
363
364 /* check for wrapping */
365 if (reg >= m_ireg_base[which] + m_size[which])
366 {
367 /* reset the base pointer */
368 reg = m_ireg_base[which];
369 }
370
371 m_cpu->set_state_int(ADSP2100_I0 + m_ireg[which], reg);
372 }
373
TIMER_DEVICE_CALLBACK_MEMBER(acclaim_rax_device::adsp_irq0)374 TIMER_DEVICE_CALLBACK_MEMBER( acclaim_rax_device::adsp_irq0 )
375 {
376 adsp_irq(0);
377 }
378
379
380
recompute_sample_rate(int which)381 void acclaim_rax_device::recompute_sample_rate(int which)
382 {
383 /* calculate how long until we generate an interrupt */
384
385 /* frequency the time per each bit sent */
386 attotime sample_period = attotime::from_hz(m_cpu->unscaled_clock()) * (1 * (m_control_regs[which ? S1_SCLKDIV_REG : S0_SCLKDIV_REG] + 1));
387
388 /* now put it down to samples, so we know what the channel frequency has to be */
389 sample_period = sample_period * (16 * 1);
390 for (auto &dmadac : m_dmadac)
391 {
392 dmadac->set_frequency(sample_period.as_hz());
393 dmadac->enable(1);
394 }
395
396 /* fire off a timer which will hit every half-buffer */
397 if (m_incs[which])
398 {
399 attotime period = (sample_period * m_size[which]) / (4 * 2 * m_incs[which]);
400 m_reg_timer->adjust(period, 0, period);
401 }
402 }
403
adsp_sound_tx_callback(offs_t offset,uint32_t data)404 void acclaim_rax_device::adsp_sound_tx_callback(offs_t offset, uint32_t data)
405 {
406 int which = offset;
407
408 if (which != 0)
409 return;
410
411 int autobuf_reg = which ? S1_AUTOBUF_REG : S0_AUTOBUF_REG;
412
413 /* check if SPORT1 is enabled */
414 if (m_control_regs[SYSCONTROL_REG] & (which ? 0x0800 : 0x1000)) /* bit 11 */
415 {
416 /* we only support autobuffer here (which is what this thing uses), bail if not enabled */
417 if (m_control_regs[autobuf_reg] & 0x0002) /* bit 1 */
418 {
419 /* get the autobuffer registers */
420 int mreg, lreg;
421 uint16_t source;
422
423 m_ireg[which] = (m_control_regs[autobuf_reg] >> 9) & 7;
424 mreg = (m_control_regs[autobuf_reg] >> 7) & 3;
425 mreg |= m_ireg[which] & 0x04; /* msb comes from ireg */
426 lreg = m_ireg[which];
427
428 /* now get the register contents in a more legible format */
429 /* we depend on register indexes to be continuous (which is the case in our core) */
430 source = m_cpu->state_int(ADSP2100_I0 + m_ireg[which]);
431 m_incs[which] = m_cpu->state_int(ADSP2100_M0 + mreg);
432 m_size[which] = m_cpu->state_int(ADSP2100_L0 + lreg);
433
434 /* get the base value, since we need to keep it around for wrapping */
435 source -= m_incs[which];
436
437 /* make it go back one so we dont lose the first sample */
438 m_cpu->set_state_int(ADSP2100_I0 + m_ireg[which], source);
439
440 /* save it as it is now */
441 m_ireg_base[which] = source;
442
443 /* recompute the sample rate and timer */
444 recompute_sample_rate(which);
445 return;
446 }
447 else
448 logerror( "ADSP SPORT1: trying to transmit and autobuffer not enabled!\n" );
449 }
450
451 /* if we get there, something went wrong. Disable playing */
452 for (auto &dmadac : m_dmadac)
453 dmadac->enable(0);
454
455 /* remove timer */
456 m_reg_timer->reset();
457 }
458
dmovlay_callback(uint32_t data)459 void acclaim_rax_device::dmovlay_callback(uint32_t data)
460 {
461 if (data < 0 || data > 1)
462 {
463 fatalerror("dmovlay_callback: Error! dmovlay called with value = %X\n", data);
464 }
465 else
466 {
467 m_dmovlay_val = data;
468 update_data_ram_bank();
469 }
470 }
471
472
473 DEFINE_DEVICE_TYPE(ACCLAIM_RAX, acclaim_rax_device, "rax_audio", "Acclaim RAX")
474
475 //-------------------------------------------------
476 // acclaim_rax_device - constructor
477 //-------------------------------------------------
478
acclaim_rax_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)479 acclaim_rax_device::acclaim_rax_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
480 : device_t(mconfig, ACCLAIM_RAX, tag, owner, clock)
481 , m_cpu(*this, "adsp")
482 , m_dmadac(*this, { "dacl", "dacr" })
483 , m_reg_timer(*this, "adsp_reg_timer")
484 , m_dma_timer(*this, "adsp_dma_timer")
485 , m_adsp_pram(*this, "adsp_pram")
486 , m_adsp_data_bank(*this, "databank")
487 , m_rom(*this, DEVICE_SELF)
488 , m_data_in(*this, "data_in")
489 , m_data_out(*this, "data_out")
490 {
491
492 }
493
494 //-------------------------------------------------
495 // device_add_mconfig - add device configuration
496 //-------------------------------------------------
497
device_add_mconfig(machine_config & config)498 void acclaim_rax_device::device_add_mconfig(machine_config &config)
499 {
500 ADSP2181(config, m_cpu, XTAL(16'670'000));
501 m_cpu->sport_tx().set(FUNC(acclaim_rax_device::adsp_sound_tx_callback)); /* callback for serial transmit */
502 m_cpu->dmovlay().set(FUNC(acclaim_rax_device::dmovlay_callback)); /* callback for adsp 2181 dmovlay instruction */
503 m_cpu->set_addrmap(AS_PROGRAM, &acclaim_rax_device::adsp_program_map);
504 m_cpu->set_addrmap(AS_DATA, &acclaim_rax_device::adsp_data_map);
505 m_cpu->set_addrmap(AS_IO, &acclaim_rax_device::adsp_io_map);
506
507 TIMER(config, "adsp_reg_timer").configure_generic(FUNC(acclaim_rax_device::adsp_irq0));
508 TIMER(config, "adsp_dma_timer").configure_generic(FUNC(acclaim_rax_device::dma_timer_callback));
509
510 GENERIC_LATCH_16(config, m_data_in);
511 GENERIC_LATCH_16(config, m_data_out);
512
513 SPEAKER(config, "lspeaker").front_left();
514 SPEAKER(config, "rspeaker").front_right();
515
516 DMADAC(config, "dacl").add_route(ALL_OUTPUTS, "lspeaker", 1.0);
517 DMADAC(config, "dacr").add_route(ALL_OUTPUTS, "rspeaker", 1.0);
518 }
519
520