1 // license:???
2 // copyright-holders:Alex Marshall,nimitz,austere
3 //ICS2115 by Raiden II team (c) 2010
4 //members: austere, nimitz, Alex Marshal
5 //
6 //Original driver by O. Galibert, ElSemi
7 //
8 //Use tab size = 4 for your viewing pleasure.
9
10 //Ported from MAME git, 13/07/2015
11
12 // jan_klaasen was here: added interpolators for rendering at any samplerate (44.1/48kHz tested)
13 // added panning
14 // many changes -- fixed bugs and brought in line with ics2115 datasheet
15 // and AMD interwave patent details (where applicable)
16
17
18 #include "burnint.h"
19 //#include <cmath>
20
21 #include "timer.h"
22
23
24 // if defined, comform to hardware limits: wavetable increase at 33.075, use 1024-step linear interpolator
25 // otherwise, wavetable increase at final samplerate, allow the use of a more precise cubic interpolator
26 // #define INTERPOLATE_AS_HARDWARE
27
28 // if defined, ramp down the volume when a sample stops and exclude the voice from processing
29 // N.B. the hardware doesn't do this, which may result in a DC offset
30 #define RAMP_DOWN
31 #define RAMP_BITS 6 // ~2ms ay 33.075kHz
32
33 // if defined, honour each voice's pan register (N.B. PGM has a monophonic speaker connection only)
34 // #define DO_PANNING
35
36 // if defined, use both lo- and hi-bytes for volume envelope increase -- the Cave games get this wrong,
37 // but ddp2 at least seems to (sort-of) expect the volume envelopes to work anyway, despite the error
38 #define CAVE_HACK
39
40
41 static UINT8* m_rom = NULL; // ics2115 rom
42 static INT32 m_rom_len;
43 static void (*m_irq_cb)(INT32) = NULL;// cpu irq callback
44
45 struct ics2115_voice {
46 struct {
47 INT32 left;
48 UINT32 acc, start, end;
49 UINT16 fc;
50 UINT8 ctl, saddr;
51 UINT8 vmode; // reserved, write 0
52 } osc;
53
54 struct {
55 INT32 left;
56 UINT32 add;
57 UINT32 start, end;
58 UINT32 acc;
59 UINT8 incr, inc_lo, inc_hi; // separate hi- and lo-byte for cave hack
60 UINT8 pan, mode;
61 } vol;
62
63 union {
64 struct {
65 UINT8 ulaw : 1;
66 UINT8 stop : 1; // stops wave + vol envelope
67 UINT8 eightbit : 1;
68 UINT8 loop : 1;
69 UINT8 loop_bidir : 1;
70 UINT8 irq : 1; // enable IRQ generation
71 UINT8 invert : 1;
72 UINT8 irq_pending: 1; // writable on ultrasound/interwave; writing 1 triggers IRQ, 0 clears
73 } bitflags;
74 UINT8 value;
75 } osc_conf;
76
77 union {
78 struct {
79 UINT8 done : 1; // indicates envelope status (hardware modifies this)
80 UINT8 stop : 1; // stops the envelope
81 UINT8 rollover : 1;
82 UINT8 loop : 1;
83 UINT8 loop_bidir : 1;
84 UINT8 irq : 1; // enable IRQ generation
85 UINT8 invert : 1;
86 UINT8 irq_pending: 1; // writable on ultrasound/interwave; writing 1 triggers IRQ, 0 clears
87 } bitflags;
88 UINT8 value;
89 } vol_ctrl;
90
91 // variables used by the interpolator
92
93 UINT32 prev_addr;
94 INT32 int_fc;
95 INT32 int_buf[4];
96
97 UINT8 ramp; // see definition of RAMP_DOWN above
98
99 inline bool process_sample();
100
101 bool update_volume_envelope();
102 bool update_oscillator();
103 void update_ramp();
104 };
105
106 static const UINT16 revision = 0x1;
107
108 static INT16 m_ulaw[256];
109 static UINT16 m_volume[4096];
110 #if defined DO_PANNING
111 static UINT16 m_panlaw[256];
112 #endif
113 static const INT32 volume_bits = 15;
114
115 static ics2115_voice m_voice[32];
116 struct timer_struct {
117 UINT8 scale, preset;
118 UINT64 period; /* in fba timer ticks */
119 };
120 static timer_struct m_timer[2];
121
122 static UINT32 m_sample_rate;
123 static INT32 m_chip_volume;
124
125 static UINT8 m_active_osc;
126 static UINT8 m_osc_select;
127 static UINT8 m_reg_select;
128 static UINT8 m_timer_irq_enabled, m_timer_irq_pending;
129
130 static bool m_irq_on;
131 static UINT8 m_vmode;
132
133 // internal register helper functions
134 void ics2115_recalc_timer(INT32 timer);
135 void ics2115_recalc_irq();
136
137 INT32 ics2115_timer_cb(INT32 n, INT32 c);
138
139 static INT32 stream_pos;
140 static INT32 output_sample_rate;
141
142 static UINT32 sample_size;
143 static UINT32 sample_count;
144 static INT32* buffer;
145
146
147 static INT32 (*get_sample)(ics2115_voice& voice);
148
149
150 #if 0
151 static INT32 get_stream_pos()
152 {
153 return (INT64)(BurnTimerCPUTotalCycles()) * nBurnSoundRate / BurnTimerCPUClockspeed;
154 }
155 #endif
156
set_internal_sample_rate()157 static void set_internal_sample_rate()
158 {
159 m_sample_rate = (m_active_osc > 24) ? 33075 : 44100;
160 sample_size = (UINT32)(((UINT64)(m_sample_rate) << 32) / output_sample_rate);
161 }
162
ics_2115_set_volume(double volume)163 void ics_2115_set_volume(double volume)
164 {
165 #if defined DO_PANNING
166
167 // adjust by +3dB to account for center pan value when panning is enabled
168
169 #endif
170
171 m_chip_volume = (INT32)((double)(1 << 14) / volume);
172 }
173
ics2115_init(void (* cpu_irq_cb)(INT32),UINT8 * sample_rom,INT32 sample_rom_size)174 void ics2115_init(void (*cpu_irq_cb)(INT32), UINT8 *sample_rom, INT32 sample_rom_size)
175 {
176 DebugSnd_ICS2115Initted = 1;
177
178 m_irq_cb = cpu_irq_cb;
179 m_rom = sample_rom;
180 m_rom_len = sample_rom_size;
181
182 // compute volume table
183 for (INT32 i = 0; i < 4096; i++)
184 m_volume[i] = ((0x100 | (i & 0xff)) << (volume_bits - 9)) >> (15 - (i >> 8));
185
186 #if defined DO_PANNING
187
188 // compute pan law table
189 for (INT32 i = 1; i < 256; i++)
190 m_panlaw[i] = (UINT16)(log2(1.0L / ((double)(i) / 255.0) * 128));
191
192 m_panlaw[0] = 4095;
193
194 #endif
195
196 ics_2115_set_volume(1.0L);
197
198 // u-Law table as per MIL-STD-188-113
199 UINT16 lut[8];
200 UINT16 lut_initial = 33 << 2; // shift up 2-bits for 16-bit range.
201 for (INT32 i = 0; i < 8; i++)
202 lut[i] = (lut_initial << i) - lut_initial;
203 for (INT32 i = 0; i < 256; i++)
204 {
205 UINT8 exponent = (~i >> 4) & 0x07;
206 UINT8 mantissa = ~i & 0x0f;
207 INT16 value = lut[exponent] + (mantissa << (exponent + 3));
208 m_ulaw[i] = (i & 0x80) ? -value : value;
209 }
210
211 buffer = NULL;
212
213 output_sample_rate = nBurnSoundRate;
214 if (output_sample_rate == 0)
215 output_sample_rate = 44100;
216 else
217 buffer = (INT32*)(BurnMalloc(output_sample_rate /*/ 50*/ * 2 * sizeof(INT32)));
218
219 BurnTimerInit(&ics2115_timer_cb, NULL);
220
221 sample_count = stream_pos = 0;
222
223 #if defined INTERPOLATE_AS_HARDWARE
224
225 static INT32 get_sample_hardware(ics2115_voice& voice);
226
227 get_sample = get_sample_hardware;
228
229 #endif
230
231 }
232
ics2115_exit()233 void ics2115_exit()
234 {
235 #if defined FBA_DEBUG
236 if (!DebugSnd_ICS2115Initted) bprintf(PRINT_ERROR, _T("ics2115_exit called without init\n"));
237 #endif
238
239 if (!DebugSnd_ICS2115Initted) return;
240
241 m_rom = NULL;
242 m_rom_len = 0;
243 m_irq_cb = NULL;
244
245 BurnFree(buffer);
246
247 DebugSnd_ICS2115Initted = 0;
248 }
249
ics2115_reset()250 void ics2115_reset()
251 {
252 #if defined FBA_DEBUG
253 if (!DebugSnd_ICS2115Initted) bprintf(PRINT_ERROR, _T("ics2115_reset called without init\n"));
254 #endif
255
256 m_timer_irq_enabled = m_timer_irq_pending = 0;
257
258 //possible re-suss
259 m_active_osc = 31;
260 m_osc_select = 0;
261 m_reg_select = 0;
262 m_vmode = 0;
263 m_irq_on = false;
264
265 memset(m_voice, 0, sizeof(m_voice));
266
267 for(INT32 i = 0; i < 2; i++)
268 {
269 m_timer[i].period = 0;
270 m_timer[i].scale = 0;
271 m_timer[i].preset = 0;
272 }
273
274 for(INT32 i = 0; i < 32; i++)
275 {
276 m_voice[i].osc_conf.value = 2;
277 m_voice[i].osc.fc = 0;
278 m_voice[i].osc.acc = 0;
279 m_voice[i].osc.start = 0;
280 m_voice[i].osc.end = 0;
281 m_voice[i].osc.ctl = 0;
282 m_voice[i].osc.saddr = 0;
283 m_voice[i].vol.acc = 0;
284 m_voice[i].vol.incr = m_voice[i].vol.inc_lo = m_voice[i].vol.inc_hi = 0;
285 m_voice[i].vol.start = 0;
286 m_voice[i].vol.end = 0;
287 m_voice[i].vol.pan = 0x7F;
288 m_voice[i].vol_ctrl.value = 1;
289 m_voice[i].vol.mode = 0;
290 m_voice[i].ramp = 0;
291 }
292
293 set_internal_sample_rate();
294
295 BurnTimerReset();
296 }
297
update_volume_envelope()298 bool ics2115_voice::update_volume_envelope()
299 {
300 if (vol_ctrl.bitflags.done || vol_ctrl.bitflags.stop)
301 return false;
302
303 if (vol.add == 0)
304 return false;
305
306 if (vol_ctrl.bitflags.invert)
307 {
308 vol.acc -= vol.add;
309
310 vol.left = vol.acc - vol.start;
311 }
312 else
313 {
314 vol.acc += vol.add;
315
316 vol.left = vol.end - vol.acc;
317 }
318
319 if (vol.left > 0)
320 return false;
321
322 if (vol_ctrl.bitflags.irq)
323 vol_ctrl.bitflags.irq_pending = true;
324
325 if (osc_conf.bitflags.eightbit)
326 return vol_ctrl.bitflags.irq_pending;
327
328 if (vol_ctrl.bitflags.loop)
329 {
330 if (osc_conf.bitflags.loop_bidir)
331 vol_ctrl.bitflags.invert = !vol_ctrl.bitflags.invert;
332
333 if (osc_conf.bitflags.invert)
334 vol.acc = vol.end + vol.left;
335 else
336 vol.acc = vol.start - vol.left;
337 }
338 else
339 vol_ctrl.bitflags.done = true;
340
341 return vol_ctrl.bitflags.irq_pending;
342 }
343
update_oscillator()344 bool ics2115_voice::update_oscillator()
345 {
346 if (osc_conf.bitflags.stop || osc.ctl != 0)
347 return false;
348
349 #if defined INTERPOLATE_AS_HARDWARE
350
351 // run wavetable addresssing at hardware samplerate
352
353 if (osc_conf.bitflags.invert)
354 {
355 osc.acc -= osc.fc << 2;
356
357 osc.left = osc.acc - osc.start;
358 }
359 else
360 {
361 osc.acc += osc.fc << 2;
362
363 osc.left = osc.end - osc.acc;
364 }
365
366 if (osc.left > 0)
367 return false;
368
369 #else
370
371 // run wavetable addresssing at full samplerate
372
373 if (osc_conf.bitflags.invert)
374 {
375 osc.acc -= int_fc;
376
377 osc.left = osc.acc - osc.start;
378 }
379 else
380 {
381 osc.acc += int_fc;
382
383 osc.left = osc.end - osc.acc;
384 }
385
386 if (osc.left > 0)
387 return false;
388
389 #endif
390
391 /* if (vol_ctrl.bitflags.rollover && (osc.left + (osc.fc << 2) >= 0))
392 return false; */
393
394 if (osc_conf.bitflags.irq)
395 osc_conf.bitflags.irq_pending = true;
396
397 if (osc_conf.bitflags.loop)
398 {
399 if (osc_conf.bitflags.loop_bidir)
400 osc_conf.bitflags.invert = !osc_conf.bitflags.invert;
401
402 if (osc_conf.bitflags.invert)
403 osc.acc = osc.end + osc.left;
404 else
405 osc.acc = osc.start - osc.left;
406 }
407 else
408 osc_conf.bitflags.stop = vol_ctrl.bitflags.done = true;
409
410 return osc_conf.bitflags.irq_pending;
411 }
412
read_wavetable(ics2115_voice & voice,const UINT32 curr_addr)413 static inline INT32 read_wavetable(ics2115_voice& voice, const UINT32 curr_addr)
414 {
415 if (voice.osc_conf.bitflags.ulaw || voice.osc_conf.bitflags.eightbit)
416 {
417 if (voice.osc_conf.bitflags.ulaw)
418 return m_ulaw[m_rom[curr_addr]];
419
420 return ((INT8)(m_rom[curr_addr]) << 8) | ((m_rom[curr_addr] & 0x7F) << 1);
421 }
422
423 return ((INT8)(m_rom[curr_addr + 1]) << 8) | m_rom[curr_addr + 0];
424 }
425
426 #if defined INTERPOLATE_AS_HARDWARE
427
428 // interpolate sample the same way the hardware does
get_sample_hardware(ics2115_voice & voice)429 static INT32 get_sample_hardware(ics2115_voice& voice)
430 {
431 UINT32 curr_addr = ((voice.osc.saddr << 20) & 0x00FFFFFF) | (voice.osc.acc >> 12);
432
433 INT32 sample_1 = read_wavetable(voice, curr_addr + 0);
434 INT32 sample_2 = read_wavetable(voice, curr_addr + ((voice.osc_conf.bitflags.ulaw || voice.osc_conf.bitflags.eightbit) ? 1 : 2));
435
436 INT32 diff = sample_2 - sample_1;
437 UINT16 fract = ((voice.osc_conf.bitflags.invert ? ~voice.osc.acc : voice.osc.acc) & 0x0FFF) >> 2;
438
439 return sample_1 + ((diff * fract) >> 10);
440 }
441
442 #else
443
update_int_buf(ics2115_voice & voice)444 static inline void update_int_buf(ics2115_voice& voice)
445 {
446 UINT32 curr_addr = ((voice.osc.saddr << 20) & 0x00FFFFFF) | (voice.osc.acc >> 12);
447
448 if (curr_addr == voice.prev_addr)
449 return;
450
451 voice.int_buf[0] = voice.int_buf[1];
452 voice.int_buf[1] = voice.int_buf[2];
453 voice.int_buf[2] = voice.int_buf[3];
454
455 voice.prev_addr = curr_addr;
456
457 voice.int_buf[3] = read_wavetable(voice, curr_addr);
458 }
459
460 // interpolate sample at playback rate using linear interpolator
get_sample_linear(ics2115_voice & voice)461 static INT32 get_sample_linear(ics2115_voice& voice)
462 {
463 update_int_buf(voice);
464
465 INT32 diff = voice.int_buf[3] - voice.int_buf[2];
466 UINT16 fract = (voice.osc_conf.bitflags.invert ? ~voice.osc.acc : voice.osc.acc) & 0x0FFF;
467
468 return voice.int_buf[2] + ((diff * fract) >> 12);
469 }
470
471 // interpolate sample at playback rate using a cubic interpolator
get_sample_cubic(ics2115_voice & voice)472 static INT32 get_sample_cubic(ics2115_voice& voice)
473 {
474 update_int_buf(voice);
475
476 const INT32 fract = (voice.osc_conf.bitflags.invert ? ~voice.osc.acc : voice.osc.acc) & 0x0FFF;
477
478 return INTERPOLATE4PS_16BIT(fract, voice.int_buf[0], voice.int_buf[1], voice.int_buf[2], voice.int_buf[3]);
479 }
480
481 #endif
482
483 #if defined RAMP_DOWN
484
process_sample()485 inline bool ics2115_voice::process_sample()
486 {
487 return !osc.ctl && ramp;
488 }
489
update_ramp()490 inline void ics2115_voice::update_ramp()
491 {
492 if (ramp && (osc_conf.bitflags.stop || osc.ctl))
493 {
494 ramp--;
495
496 if (ramp == 0)
497 memset(int_buf, 0, sizeof(int_buf));
498 }
499 }
500
501 #else
502
process_sample()503 inline bool ics2115_voice::process_sample()
504 {
505 #if 1
506
507 // exclude the voice only if it is disabled
508
509 return !osc.ctl;
510
511 #else
512
513 // exclude the voice if the wavetable address isn't incrementing
514
515 return !(osc.ctl || osc_conf.bitflags.stop);
516
517 #endif
518 }
519
update_ramp()520 inline void ics2115_voice::update_ramp()
521 {
522 }
523
524 #endif
525
526
ics2115_fill_output(ics2115_voice & voice,INT32 * outputs,INT32 samples)527 static bool ics2115_fill_output(ics2115_voice& voice, INT32* outputs, INT32 samples)
528 {
529 bool irq_invalid = false;
530
531 #if !defined INTERPOLATE_AS_HARDWARE
532
533 UINT32 count = sample_count;
534
535 #endif
536
537 if (outputs == 0)
538 {
539 // no need to compute the output, just update state
540
541 for (INT32 i = 0; i < samples; i++)
542 {
543 if (!voice.process_sample())
544 continue;
545
546 irq_invalid |= voice.update_volume_envelope();
547 irq_invalid |= voice.update_oscillator();
548 }
549
550 return irq_invalid;
551 }
552
553 for (INT32 i = 0; i < samples; i++)
554 {
555 if (voice.process_sample())
556 {
557 INT32 volacc = (voice.vol.acc >> 14) & 0x00000FFF;
558
559 #if defined DO_PANNING
560
561 #if defined RAMP_DOWN
562
563 INT32 vleft = volacc - m_panlaw[255 - voice.vol.pan]; vleft = vleft > 0 ? (m_volume[vleft] * voice.ramp >> RAMP_BITS) : 0;
564 INT32 vright = volacc - m_panlaw[ voice.vol.pan]; vright = vright > 0 ? (m_volume[vright] * voice.ramp >> RAMP_BITS) : 0;
565
566 #else
567
568 INT32 vleft = volacc - m_panlaw[255 - voice.vol.pan]; vleft = vleft > 0 ? m_volume[vleft] : 0;
569 INT32 vright = volacc - m_panlaw[ voice.vol.pan]; vright = vright > 0 ? m_volume[vright] : 0;
570
571 #endif
572
573 if (vleft || vright)
574 {
575 INT32 sample = get_sample(voice);
576
577 outputs[0] += ((sample * vleft) >> (5 + volume_bits - 16));
578 outputs[1] += ((sample * vright) >> (5 + volume_bits - 16));
579 }
580
581 outputs += 2;
582
583 #else
584
585 #if defined RAMP_DOWN
586
587 UINT16 volume = ((UINT32)(m_volume[volacc]) * voice.ramp) >> RAMP_BITS;
588
589 #else
590
591 UINT16 volume = m_volume[volacc];
592
593 #endif
594 if (volume)
595 *outputs += (get_sample(voice) * volume) >> (5 + volume_bits - 16);
596
597 outputs++;
598 #endif
599
600 }
601
602 #if !defined INTERPOLATE_AS_HARDWARE
603
604 count += sample_size;
605 if (count <= sample_size)
606
607 #endif
608
609 {
610 voice.update_ramp();
611
612 if (voice.process_sample())
613 irq_invalid |= voice.update_volume_envelope();
614 }
615
616 irq_invalid |= voice.update_oscillator();
617 }
618
619 return irq_invalid;
620 }
621
ics2115_render(INT16 * outputs,INT32 samples)622 static void ics2115_render(INT16* outputs, INT32 samples)
623 {
624 #if defined DO_PANNING
625
626 if (buffer)
627 memset(buffer, 0, samples * sizeof(INT32) * 2);
628
629 #else
630
631 if (buffer)
632 memset(buffer, 0, samples * sizeof(INT32));
633
634 #endif
635
636 #if !defined INTERPOLATE_AS_HARDWARE
637
638 get_sample = (nInterpolation < 3) ? get_sample_linear : get_sample_cubic;
639
640 #endif
641
642 bool irq_invalid = false;
643
644 for (INT32 osc = 0; osc <= m_active_osc; osc++)
645 irq_invalid |= ics2115_fill_output(m_voice[osc], buffer, samples);
646
647 if (nBurnSoundRate)
648 {
649
650 #if defined DO_PANNING
651
652 for (INT32 i = (samples - 1) << 1; i >= 0; i -= 2)
653 {
654 outputs[i ] = BURN_SND_CLIP(buffer[i ] / m_chip_volume);
655 outputs[i + 1] = BURN_SND_CLIP(buffer[i + 1] / m_chip_volume);
656 }
657
658 #else
659
660 for (INT32 i = samples - 1; i >= 0; i--)
661 outputs[i << 1] = outputs[(i << 1) + 1] = BURN_SND_CLIP(buffer[i] / m_chip_volume);
662
663 #endif
664
665 }
666
667 if (irq_invalid)
668 ics2115_recalc_irq();
669
670 sample_count += sample_count * samples;
671 }
672
673 #if defined INTERPOLATE_AS_HARDWARE
674
675 #include <exception>
676
ics2115_update(INT32 segment_length)677 void ics2115_update(INT32 segment_length)
678 {
679
680 // not implemented!
681
682 throw std::exception("resampling for rendering at hardware rate not implemented!");
683 }
684
685 #else
686
ics2115_update(INT32 segment_length)687 void ics2115_update(INT32 segment_length)
688 {
689 #if defined FBA_DEBUG
690 if (!DebugSnd_ICS2115Initted) bprintf(PRINT_ERROR, _T("ics2115_update called without init\n"));
691 #endif
692
693 if (pBurnSoundOut == NULL)
694 return;
695
696 if (segment_length >= nBurnSoundLen)
697 segment_length = nBurnSoundLen;
698
699 if (segment_length <= stream_pos)
700 return;
701
702 // bprintf(0, _T(" ICS2115 rendering %03i - %03i (%03i)\n"), stream_pos, segment_length, nBurnSoundLen);
703 ics2115_render(pBurnSoundOut + stream_pos * 2, segment_length - stream_pos);
704
705 stream_pos = segment_length;
706 if (stream_pos >= nBurnSoundLen)
707 stream_pos -= nBurnSoundLen;
708
709 }
710
711 #endif
712
713
ics2115_reg_read()714 static UINT16 ics2115_reg_read()
715 {
716 UINT16 ret;
717
718 ics2115_voice& voice = m_voice[m_osc_select];
719
720 switch(m_reg_select)
721 {
722 case 0x00: // [osc] Oscillator Configuration
723 ret = voice.osc_conf.value << 8;
724 break;
725
726 case 0x01: // [osc] Wavesample frequency
727 ret = voice.osc.fc;
728 break;
729
730 case 0x02: // [osc] Wavesample loop start high
731 ret = (voice.osc.start >> 16) & 0xffff;
732 break;
733
734 case 0x03: // [osc] Wavesample loop start low
735 ret = (voice.osc.start >> 0) & 0xff00;
736 break;
737
738 case 0x04: // [osc] Wavesample loop end high
739 ret = (voice.osc.end >> 16) & 0xffff;
740 break;
741
742 case 0x05: // [osc] Wavesample loop end low
743 ret = (voice.osc.end >> 0) & 0xff00;
744 break;
745
746 case 0x06: // [osc] Volume Increment
747 ret = voice.vol.incr;
748 break;
749
750 case 0x07: // [osc] Volume Start
751 ret = voice.vol.start >> (10 + 8);
752 break;
753
754 case 0x08: // [osc] Volume End
755 ret = voice.vol.end >> (10 + 8);
756 break;
757
758 case 0x09: // [osc] Volume accumulator
759
760 //ics2115_update(get_stream_pos());
761
762 ret = voice.vol.acc >> 10;
763 break;
764
765 case 0x0A: // [osc] Wavesample address
766
767 //ics2115_update(get_stream_pos());
768
769 ret = (voice.osc.acc >> 16) & 0xffff;
770 break;
771
772 case 0x0B: // [osc] Wavesample address
773
774 //ics2115_update(get_stream_pos());
775
776 ret = (voice.osc.acc >> 0) & 0xfff8;
777 break;
778
779
780 case 0x0C: // [osc] Pan
781 ret = voice.vol.pan << 8;
782 break;
783
784 case 0x0D: // [osc] Volume Envelope Control
785
786 //ics2115_update(get_stream_pos());
787
788 ret = voice.vol_ctrl.value << 8;
789 break;
790
791 case 0x0E: // Active Voices
792 ret = m_active_osc;
793 break;
794
795 case 0x0F: // [osc] Interrupt source/oscillator
796
797 //ics2115_update(get_stream_pos());
798
799 ret = 0xFF;
800 for (INT32 i = 0; i <= m_active_osc; i++)
801 {
802 ics2115_voice& v = m_voice[i];
803
804 if (v.osc_conf.bitflags.irq_pending || v.vol_ctrl.bitflags.irq_pending)
805 {
806 ret = i | 0xE0;
807
808 if (v.osc_conf.bitflags.irq_pending)
809 {
810 v.osc_conf.bitflags.irq_pending = 0;
811 ret &= ~0x80;
812 }
813 if (v.vol_ctrl.bitflags.irq_pending)
814 {
815 v.vol_ctrl.bitflags.irq_pending = 0;
816 ret &= ~0x40;
817 }
818
819 ics2115_recalc_irq();
820
821 break;
822 }
823 }
824
825 ret <<= 8;
826 break;
827
828 case 0x10: // [osc] Oscillator Control
829
830 //ics2115_update(get_stream_pos());
831
832 ret = voice.osc.ctl << 8;
833 break;
834
835 case 0x11: // [osc] Wavesample static address 27-20
836 ret = voice.osc.saddr << 8;
837 break;
838
839 case 0x12: // [osc] vmode (reserved, write 0)
840 ret = voice.osc.vmode << 8;
841 break;
842
843
844 // general purpose registers
845
846
847 case 0x40: // Timer 0 clear irq
848 case 0x41: // Timer 1 clear irq
849 //TODO: examine this suspect code
850
851 //ics2115_update(get_stream_pos());
852
853 ret = m_timer[m_reg_select & 0x1].preset;
854 m_timer_irq_pending &= ~(1 << (m_reg_select & 0x1));
855
856 ics2115_recalc_irq();
857 break;
858
859 case 0x43: // Timer status
860
861 //ics2115_update(get_stream_pos());
862
863 ret = m_timer_irq_pending & 3;
864 break;
865
866 case 0x4A: // IRQ Pending
867
868 //ics2115_update(get_stream_pos());
869
870 ret = m_timer_irq_pending;
871 break;
872
873 case 0x4B: // Address of Interrupting Oscillator
874 // bprintf(0, _T("IntOscAddr read\n"));
875
876 ret = 0xFF;
877
878 if (m_irq_on)
879 {
880 for (INT32 i = 0; i <= m_active_osc; i++)
881 {
882 ics2115_voice& v = m_voice[i];
883
884 if (v.osc_conf.bitflags.irq_pending || v.vol_ctrl.bitflags.irq_pending)
885 {
886 ret = i | 0xE0;
887
888 // should this be here?
889
890 /* if (v.osc_conf.bitflags.irq_pending)
891 ret &= ~0x80;
892
893 if (v.vol_ctrl.bitflags.irq_pending)
894 ret &= ~0x40; */
895
896 break;
897 }
898 }
899 }
900
901 ret <<= 8;
902 break;
903
904 case 0x4C: // Chip Revision
905 ret = revision;
906 break;
907
908 default:
909 /* if (m_reg_select < 0x40)
910 bprintf(PRINT_ERROR, _T(" ICS2115 voice %02X RESERVED register %02X read\n"), m_osc_select, m_reg_select);
911 else
912 bprintf(PRINT_ERROR, _T(" ICS2115 general purpose register %02X read\n"), m_reg_select); */
913
914 ret = 0;
915 break;
916 }
917
918 return ret;
919 }
920
ics2115_reg_write(UINT8 data,bool msb)921 static void ics2115_reg_write(UINT8 data, bool msb) {
922 ics2115_voice& voice = m_voice[m_osc_select];
923
924 //if (m_reg_select <= 0x12)
925 // ics2115_update(get_stream_pos());
926
927 switch(m_reg_select)
928 {
929 case 0x00: // [osc] Oscillator Configuration
930 if (msb)
931 {
932 // bprintf(0, _T(" ICS2115 voice %02X osc conf -> %02X\n"), m_osc_select, data);
933
934 if (~data & 0x20)
935 {
936 /* if (voice.osc_conf.bitflags.irq)
937 bprintf(0, _T(" ICS2115 voice %02X wavetable irq disabled\n"), m_osc_select); */
938
939 voice.osc_conf.value = data & 0x7F;
940
941 if (m_irq_on)
942 ics2115_recalc_irq();
943 }
944 else
945 {
946 /* if (!voice.osc_conf.bitflags.irq)
947 bprintf(0, _T(" ICS2115 voice %02X wavetable irq enabled\n"), m_osc_select); */
948
949 voice.osc_conf.value = data;
950
951 if ((voice.vol_ctrl.value & 0x80) != (data & 0x80))
952 ics2115_recalc_irq();
953 }
954 }
955 break;
956
957 case 0x01: // [osc] Wavesample frequency
958
959 // freq = fc * 33075 / 1024 in 32 voices mode
960 // fc * 44100 / 1024 in 24 voices mode
961
962 if (msb)
963 voice.osc.fc = (voice.osc.fc & 0x00ff) | (data << 8);
964 else
965 voice.osc.fc = (voice.osc.fc & 0xff00) | (data & 0xFE);
966
967 #if !defined INTERPOLATE_AS_HARDWARE
968
969 voice.int_fc = (UINT32)((UINT64)(voice.osc.fc) * 0x8000 * m_sample_rate / nBurnSoundRate >> 13);
970
971 /* if (voice.int_fc > (1 << 14))
972 bprintf(0, _T(" ICS2115 voice %02X skipping samples (fc: %08X)!\n"), m_osc_select, voice.osc.fc); */
973
974 #endif
975 break;
976
977 case 0x02: // [osc] Wavesample loop start high (16 bits integer)
978 if (msb)
979 voice.osc.start = (voice.osc.start & 0x00ffffff) | (data << 24);
980 else
981 voice.osc.start = (voice.osc.start & 0xff00ffff) | (data << 16);
982 break;
983
984 case 0x03: // [osc] Wavesample loop start low (4 bits integer, 4 fraction)
985 if (msb)
986 voice.osc.start = (voice.osc.start & 0xffff00ff) | (data << 8);
987 /* else
988 voice.osc.start = (voice.osc.start & 0xffffff00) | data; */
989 break;
990
991 case 0x04: // [osc] Wavesample loop end high (16 bits integer)
992 if (msb)
993 voice.osc.end = (voice.osc.end & 0x00ffffff) | (data << 24);
994 else
995 voice.osc.end = (voice.osc.end & 0xff00ffff) | (data << 16);
996 break;
997
998 case 0x05: // [osc] Wavesample loop end low (4 bits integer, 4 fraction)
999 if (msb)
1000 voice.osc.end = (voice.osc.end & 0xffff00ff) | (data << 8);
1001 /* else
1002 voice.osc.end = (voice.osc.end & 0xffffff00) | data; */
1003 break;
1004
1005 case 0x06: // [osc] Volume Increment
1006
1007 #if defined CAVE_HACK
1008
1009 if (msb)
1010 voice.vol.inc_hi = data;
1011 else
1012 voice.vol.inc_lo = data;
1013
1014 voice.vol.incr = voice.vol.inc_lo | voice.vol.inc_hi;
1015
1016 #else
1017
1018 if (msb)
1019 voice.vol.incr = data;
1020
1021 #endif
1022
1023 voice.vol.add = (voice.vol.incr & 0x3F) <<
1024 (10 - (1 << (3 * (voice.vol.incr >> 6))));
1025
1026 /* if (msb)
1027 bprintf(0, _T(" ICS2115 voice %02X vol inc msb -> %02X\n"), m_osc_select, data);
1028 else
1029 bprintf(0, _T(" ICS2115 voice %02X vol inc lsb -> %02X\n"), m_osc_select, data); */
1030
1031 break;
1032
1033 case 0x07: // [osc] Volume Start (8 bits according to datasheet, though games use 12)
1034 if (msb)
1035 voice.vol.start = (voice.vol.start & 0x003FC00) | (data << (10 + 8));
1036 /* else
1037 voice.vol.start = (voice.vol.start & 0x3FC0000) | (data << 10); */
1038
1039 /* if (msb)
1040 bprintf(0, _T(" ICS2115 voice %02X vol start msb -> %02X\n"), m_osc_select, data);
1041 else
1042 bprintf(0, _T(" ICS2115 voice %02X vol start lsb -> %02X\n"), m_osc_select, data); */
1043
1044 break;
1045
1046 case 0x08: // [osc] Volume End (8 bits according to datasheet, though games use 12)
1047 if (msb)
1048 voice.vol.end = (voice.vol.end & 0x003FC00) | (data << (10 + 8));
1049 /* else
1050 voice.vol.end = (voice.vol.end & 0x3FC0000) | (data << 10); */
1051
1052 /* if (msb)
1053 bprintf(0, _T(" ICS2115 voice %02X vol end msb -> %02X\n"), m_osc_select, data);
1054 else
1055 bprintf(0, _T(" ICS2115 voice %02X vol end lsb -> %02X\n"), m_osc_select, data); */
1056
1057 break;
1058
1059 case 0x09: // [osc] Volume accumulator
1060 if (msb)
1061 voice.vol.acc = (voice.vol.acc & 0x003FC00) | (data << (10 + 8));
1062 else
1063 voice.vol.acc = (voice.vol.acc & 0x3FC0000) | (data << 10);
1064
1065 /* if (msb)
1066 bprintf(0, _T(" ICS2115 voice %02X vol acc msb -> %02X\n"), m_osc_select, data);
1067 else
1068 bprintf(0, _T(" ICS2115 voice %02X vol acc lsb -> %02X\n"), m_osc_select, data); */
1069
1070 break;
1071
1072 case 0x0A: // [osc] Wavesample address high (16 bits integer)
1073 if (msb)
1074 voice.osc.acc = (voice.osc.acc & 0x00ffffff) | (data << 24);
1075 else
1076 voice.osc.acc = (voice.osc.acc & 0xff00ffff) | (data << 16);
1077 break;
1078
1079 case 0x0B: // [osc] Wavesample address low (4 bits integer, 9 fraction)
1080 if (msb)
1081 voice.osc.acc = (voice.osc.acc & 0xffff00ff) | (data << 8);
1082 else
1083 voice.osc.acc = (voice.osc.acc & 0xffffff00) | (data & 0xF8);
1084 break;
1085
1086 case 0x0C: // [osc] Pan
1087 if (msb)
1088 voice.vol.pan = data;
1089
1090 // bprintf(0, _T(" ICS2115 voice %02X pan %02X\n"), m_osc_select, data);
1091
1092 break;
1093
1094 case 0x0D: // [osc] Volume Envelope Control
1095 if (msb)
1096 {
1097 /* if ((voice.vol_ctrl.value & 3) && (data & 3) == 0)
1098 bprintf(0, _T(" ICS2115 voice %02X vol env enabled, %s - [data: %02X]\n"), m_osc_select, (data & 64) ? _T("<<--") : _T("-->>"), data);
1099 else if((voice.vol_ctrl.value & 3) == 0 && (data & 3))
1100 bprintf(0, _T(" ICS2115 voice %02X vol env disabled\n"), m_osc_select); */
1101
1102 if (~data & 0x20)
1103 {
1104 /* if (voice.vol_ctrl.bitflags.irq)
1105 bprintf(0, _T(" ICS2115 voice %02X volume irq disabled\n"), m_osc_select); */
1106
1107 voice.vol_ctrl.value = data & 0x7F;
1108
1109 if (m_irq_on)
1110 ics2115_recalc_irq();
1111 }
1112 else
1113 {
1114 /* if (!voice.vol_ctrl.bitflags.irq)
1115 bprintf(0, _T(" ICS2115 voice %02X volume irq enabled\n"), m_osc_select); */
1116
1117 voice.vol_ctrl.value = data;
1118
1119 if ((voice.vol_ctrl.value & 0x80) != (data & 0x80))
1120 ics2115_recalc_irq();
1121 }
1122 }
1123 break;
1124
1125 case 0x0E: // Active Voices
1126 if (msb)
1127 {
1128 m_active_osc = data & 0x1F;
1129
1130 set_internal_sample_rate();
1131 }
1132 break;
1133
1134 case 0x10: // [osc] Oscillator Control
1135 if (msb)
1136 {
1137 voice.osc.ctl = data;
1138
1139 if (!data)
1140 {
1141 voice.ramp = 1 << RAMP_BITS;
1142 voice.prev_addr = ~0;
1143
1144 /* if (voice.vol_ctrl.bitflags.rollover)
1145 bprintf(PRINT_ERROR, _T("*** ICS2115 ROLLOVER used - voice %02X enabled: %06X -> %06X\n"), m_osc_select, voice.osc.acc >> 8, voice.osc.end >> 8);
1146 else if (voice.vol_ctrl.bitflags.loop)
1147 bprintf(0, _T(" ICS2115 voice %02X enabled: %06X, %06X -> %06X\n"), m_osc_select, voice.osc.acc >> 6, voice.osc.start >> 8, voice.osc.end >> 8);
1148 else
1149 bprintf(0, _T(" ICS2115 voice %02X enabled: %06X -> %06X\n"), m_osc_select, voice.osc.acc >> 8, voice.osc.end >> 8); */
1150 }
1151 else if (data == 0x0F) // guessing here
1152 {
1153 // bprintf(0, _T(" ICS2115 voice %02X disabled\n"), m_osc_select);
1154
1155 voice.osc_conf.bitflags.stop = true;
1156 voice.vol_ctrl.bitflags.done = true;
1157 }
1158 }
1159 break;
1160
1161 case 0x11: // [osc] Wavesample static address 27-20
1162 if (msb)
1163 voice.osc.saddr = data;
1164 break;
1165
1166 case 0x12: // [osc] vmode (reserved, write 0)
1167 if (msb)
1168 voice.osc.vmode = data;
1169
1170 /* if (data)
1171 bprintf(PRINT_ERROR, _T(" ICS2115 voice %02X VMode -> %02X\n"), m_osc_select, data); */
1172
1173 break;
1174
1175
1176 // general purpose registers
1177
1178
1179 case 0x40: // Timer 1 Preset
1180 //case 0x41: // Timer 2 Preset
1181 if (!msb)
1182 {
1183 m_timer[m_reg_select & 0x1].preset = data;
1184 ics2115_recalc_timer(m_reg_select & 0x1);
1185 }
1186 break;
1187
1188 case 0x42: // Timer 1 Prescale
1189 //case 0x43: // Timer 2 Prescale
1190 if (!msb)
1191 {
1192 m_timer[m_reg_select & 0x1].scale = data;
1193 ics2115_recalc_timer(m_reg_select & 0x1);
1194 }
1195 break;
1196
1197 case 0x4A: // IRQ Enable
1198 if (!msb)
1199 {
1200 //ics2115_update(get_stream_pos());
1201
1202 m_timer_irq_enabled = data;
1203 ics2115_recalc_irq();
1204 }
1205 break;
1206
1207 case 0x4F: // Oscillator Address being Programmed
1208 if (!msb)
1209 m_osc_select = data & 0x1F;
1210
1211 break;
1212
1213 default:
1214 /* if (m_reg_select < 0x40)
1215 bprintf(PRINT_ERROR, _T(" ICS2115 voice %02X RESERVED register %02X -> %02X\n"), m_osc_select, m_reg_select, data);
1216 else
1217 bprintf(PRINT_ERROR, _T(" ICS2115 general purpose register %02X -> %02X\n"), m_reg_select, data); */
1218
1219 break;
1220 }
1221 }
1222
ics2115read(UINT8 offset)1223 UINT8 ics2115read(UINT8 offset)
1224 {
1225 #if defined FBA_DEBUG
1226 if (!DebugSnd_ICS2115Initted) bprintf(PRINT_ERROR, _T("ics2115read called without init\n"));
1227 #endif
1228
1229 UINT8 ret = 0;
1230
1231 switch(offset & 3)
1232 {
1233 case 0:
1234 //ics2115_update(get_stream_pos());
1235
1236 if (m_irq_on)
1237 {
1238 ret |= 0x80;
1239
1240 if (m_timer_irq_enabled && (m_timer_irq_pending & 3))
1241 ret |= 1;
1242
1243 for (INT32 i = 0; i <= m_active_osc; i++)
1244 {
1245 if (m_voice[i].osc_conf.bitflags.irq_pending || m_voice[i].vol_ctrl.bitflags.irq_pending)
1246 {
1247 ret |= 2;
1248 break;
1249 }
1250 }
1251 }
1252
1253 break;
1254 case 1:
1255 ret = m_reg_select;
1256 break;
1257 case 2:
1258 ret = (UINT8)(ics2115_reg_read());
1259 break;
1260 case 3:
1261 ret = ics2115_reg_read() >> 8;
1262 break;
1263 default:
1264 break;
1265 }
1266 return ret;
1267 }
1268
ics2115write(UINT8 offset,UINT8 data)1269 void ics2115write(UINT8 offset, UINT8 data)
1270 {
1271 #if defined FBA_DEBUG
1272 if (!DebugSnd_ICS2115Initted) bprintf(PRINT_ERROR, _T("ics2115write called without init\n"));
1273 #endif
1274
1275 switch(offset & 3) {
1276 case 1:
1277 m_reg_select = data;
1278 break;
1279 case 2:
1280 ics2115_reg_write(data, 0);
1281 break;
1282 case 3:
1283 ics2115_reg_write(data, 1);
1284 break;
1285 default:
1286 break;
1287 }
1288 }
1289
ics2115_recalc_irq()1290 void ics2115_recalc_irq()
1291 {
1292 bool irq = (m_timer_irq_pending & m_timer_irq_enabled);
1293
1294 for (INT32 i = 0; (!irq) && (i < 32); i++)
1295 irq |= m_voice[i].vol_ctrl.bitflags.irq_pending || m_voice[i].osc_conf.bitflags.irq_pending;
1296
1297 m_irq_on = irq;
1298
1299 if (m_irq_cb)
1300 m_irq_cb(irq ? CPU_IRQSTATUS_ACK : CPU_IRQSTATUS_NONE);
1301 }
1302
ics2115_timer_cb(INT32,INT32 c)1303 INT32 ics2115_timer_cb(INT32 /* n */, INT32 c)
1304 {
1305 m_timer_irq_pending |= 1 << c;
1306
1307 ics2115_recalc_irq();
1308
1309 return m_irq_on ? 1 : 0;
1310 }
1311
ics2115_recalc_timer(INT32 timer)1312 void ics2115_recalc_timer(INT32 timer)
1313 {
1314 // adjusted from nsecs -> fba timer ticks/sec
1315 UINT64 period = ((m_timer[timer].scale & 0x1f) + 1) * (m_timer[timer].preset + 1);
1316 period = (period << (4 + (m_timer[timer].scale >> 5))) * 160000 / 2646;
1317
1318 if (m_timer[timer].period == period)
1319 return;
1320
1321 m_timer[timer].period = period;
1322 BurnTimerSetRetrig(timer, period);
1323
1324 /* UINT64 period = ((m_timer[timer].scale & 0x1f) + 1) * (m_timer[timer].preset + 1);
1325 period = (period << (4 + (m_timer[timer].scale >> 5))) * 78125 / 2646; */
1326 }
1327
1328
ics2115_scan(INT32 nAction,INT32 * pnMin)1329 void ics2115_scan(INT32 nAction, INT32* pnMin)
1330 {
1331 #if defined FBA_DEBUG
1332 if (!DebugSnd_ICS2115Initted) bprintf(PRINT_ERROR, _T("ics2115_scan called without init\n"));
1333 #endif
1334
1335 if (pnMin)
1336 *pnMin = 0x029743;
1337
1338 BurnTimerScan(nAction, pnMin);
1339
1340 if (nAction & ACB_DRIVER_DATA)
1341 {
1342 SCAN_VAR(m_timer_irq_enabled);
1343 SCAN_VAR(m_timer_irq_pending);
1344 SCAN_VAR(m_active_osc);
1345 SCAN_VAR(m_osc_select);
1346 SCAN_VAR(m_reg_select);
1347 SCAN_VAR(m_vmode);
1348 SCAN_VAR(m_irq_on);
1349
1350 SCAN_VAR(m_voice);
1351
1352 for (INT32 i = 0; i < 2; i++)
1353 {
1354 SCAN_VAR(m_timer[i].period);
1355 SCAN_VAR(m_timer[i].scale);
1356 SCAN_VAR(m_timer[i].preset);
1357 }
1358
1359 for (INT32 i = 0; i < 32; i++)
1360 {
1361 SCAN_VAR(m_voice[i].osc_conf.value);
1362 SCAN_VAR(m_voice[i].osc.fc);
1363 SCAN_VAR(m_voice[i].osc.acc);
1364 SCAN_VAR(m_voice[i].osc.start);
1365 SCAN_VAR(m_voice[i].osc.end);
1366 SCAN_VAR(m_voice[i].osc.ctl);
1367 SCAN_VAR(m_voice[i].osc.saddr);
1368 SCAN_VAR(m_voice[i].vol.acc);
1369 SCAN_VAR(m_voice[i].vol.incr); SCAN_VAR(m_voice[i].vol.inc_lo); SCAN_VAR(m_voice[i].vol.inc_hi);
1370 SCAN_VAR(m_voice[i].vol.start);
1371 SCAN_VAR(m_voice[i].vol.end);
1372 SCAN_VAR(m_voice[i].vol.pan);
1373 SCAN_VAR(m_voice[i].vol_ctrl.value);
1374 SCAN_VAR(m_voice[i].vol.mode);
1375 SCAN_VAR(m_voice[i].ramp);
1376
1377 SCAN_VAR(m_voice[i].prev_addr);
1378 SCAN_VAR(m_voice[i].int_buf);
1379 }
1380
1381 if (nAction & ACB_WRITE)
1382 set_internal_sample_rate();
1383 }
1384 }
1385