1 /**********************************************************************************************
2 *
3 * Yamaha YMZ280B driver
4 * by Aaron Giles
5 *
6 **********************************************************************************************/
7
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12
13 #include "driver.h"
14 #include "adpcm.h"
15 #include "osinline.h"
16
17 #define MAX_SAMPLE_CHUNK 10000
18
19 #define FRAC_BITS 14
20 #define FRAC_ONE (1 << FRAC_BITS)
21 #define FRAC_MASK (FRAC_ONE - 1)
22
23
24 /* struct describing a single playing ADPCM voice */
25 struct YMZ280BVoice
26 {
27 UINT8 playing; /* 1 if we are actively playing */
28
29 UINT8 keyon; /* 1 if the key is on */
30 UINT8 looping; /* 1 if looping is enabled */
31 UINT8 mode; /* current playback mode */
32 UINT16 fnum; /* frequency */
33 UINT8 level; /* output level */
34 UINT8 pan; /* panning */
35
36 UINT32 start; /* start address, in nibbles */
37 UINT32 stop; /* stop address, in nibbles */
38 UINT32 loop_start; /* loop start address, in nibbles */
39 UINT32 loop_end; /* loop end address, in nibbles */
40 UINT32 position; /* current position, in nibbles */
41
42 INT32 signal; /* current ADPCM signal */
43 INT32 step; /* current ADPCM step */
44
45 INT32 loop_signal; /* signal at loop start */
46 INT32 loop_step; /* step at loop start */
47 UINT32 loop_count; /* number of loops so far */
48
49 INT32 output_left; /* output volume (left) */
50 INT32 output_right; /* output volume (right) */
51 INT32 output_step; /* step value for frequency conversion */
52 INT32 output_pos; /* current fractional position */
53 INT16 last_sample; /* last sample output */
54 INT16 curr_sample; /* current sample target */
55 };
56
57 struct YMZ280BChip
58 {
59 int stream; /* which stream are we using */
60 UINT8 *region_base; /* pointer to the base of the region */
61 UINT8 current_register; /* currently accessible register */
62 UINT8 status_register; /* current status register */
63 UINT8 irq_state; /* current IRQ state */
64 UINT8 irq_mask; /* current IRQ mask */
65 UINT8 irq_enable; /* current IRQ enable */
66 UINT8 keyon_enable; /* key on enable */
67 float master_clock; /* master clock frequency */
68 void (*irq_callback)(int); /* IRQ callback */
69 struct YMZ280BVoice voice[8]; /* the 8 voices */
70 };
71
72 static struct YMZ280BChip ymz280b[MAX_YMZ280B];
73 static INT32 *accumulator;
74 static INT16 *scratch;
75
76 /* step size index shift table */
77 static int index_scale[8] = { 0x0e6, 0x0e6, 0x0e6, 0x0e6, 0x133, 0x199, 0x200, 0x266 };
78
79 /* lookup table for the precomputed difference */
80 static int diff_lookup[16];
81
82
83
update_irq_state(struct YMZ280BChip * chip)84 static INLINE void update_irq_state(struct YMZ280BChip *chip)
85 {
86 int irq_bits = chip->status_register & chip->irq_mask;
87
88 /* always off if the enable is off */
89 if (!chip->irq_enable)
90 irq_bits = 0;
91
92 /* update the state if changed */
93 if (irq_bits && !chip->irq_state)
94 {
95 chip->irq_state = 1;
96 if (chip->irq_callback)
97 (*chip->irq_callback)(1);
98 }
99 else if (!irq_bits && chip->irq_state)
100 {
101 chip->irq_state = 0;
102 if (chip->irq_callback)
103 (*chip->irq_callback)(0);
104 }
105 }
106
107
update_step(struct YMZ280BChip * chip,struct YMZ280BVoice * voice)108 static INLINE void update_step(struct YMZ280BChip *chip, struct YMZ280BVoice *voice)
109 {
110 float frequency;
111
112 /* handle the sound-off case */
113 if (Machine->sample_rate == 0)
114 {
115 voice->output_step = 0;
116 return;
117 }
118
119 /* compute the frequency */
120 if (voice->mode == 1)
121 frequency = chip->master_clock * (float)((voice->fnum & 0x0ff) + 1) * (1.0 / 256.0);
122 else
123 frequency = chip->master_clock * (float)((voice->fnum & 0x1ff) + 1) * (1.0 / 256.0);
124 voice->output_step = (UINT32)(frequency * (float)FRAC_ONE / (float)Machine->sample_rate);
125 }
126
127
update_volumes(struct YMZ280BVoice * voice)128 static INLINE void update_volumes(struct YMZ280BVoice *voice)
129 {
130 if (voice->pan == 8)
131 {
132 voice->output_left = voice->level;
133 voice->output_right = voice->level;
134 }
135 else if (voice->pan < 8)
136 {
137 voice->output_left = voice->level;
138 voice->output_right = voice->level * voice->pan / 8;
139 }
140 else
141 {
142 voice->output_left = voice->level * (15 - voice->pan) / 8;
143 voice->output_right = voice->level;
144 }
145 }
146
147
148 /**********************************************************************************************
149
150 compute_tables -- compute the difference tables
151
152 ***********************************************************************************************/
153
compute_tables(void)154 static void compute_tables(void)
155 {
156 int nib;
157
158 /* loop over all nibbles and compute the difference */
159 for (nib = 0; nib < 16; nib++)
160 {
161 int value = (nib & 0x07) * 2 + 1;
162 diff_lookup[nib] = (nib & 0x08) ? -value : value;
163 }
164 }
165
166
167
168 /**********************************************************************************************
169
170 generate_adpcm -- general ADPCM decoding routine
171
172 ***********************************************************************************************/
173
generate_adpcm(struct YMZ280BVoice * voice,UINT8 * base,INT16 * buffer,int samples)174 static int generate_adpcm(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples)
175 {
176 int position = voice->position;
177 int signal = voice->signal;
178 int step = voice->step;
179 int val;
180
181 /* two cases: first cases is non-looping */
182 if (!voice->looping)
183 {
184 /* loop while we still have samples to generate */
185 while (samples)
186 {
187 /* compute the new amplitude and update the current step */
188 val = base[position / 2] >> ((~position & 1) << 2);
189 signal += (step * diff_lookup[val & 15]) / 8;
190
191 /* clamp to the maximum */
192 #ifndef clip_short
193 if (signal > 32767)
194 signal = 32767;
195 else if (signal < -32768)
196 signal = -32768;
197 #else
198 clip_short(signal);
199 #endif
200 /* adjust the step size and clamp */
201 step = (step * index_scale[val & 7]) >> 8;
202 if (step > 0x6000)
203 step = 0x6000;
204 else if (step < 0x7f)
205 step = 0x7f;
206
207 /* output to the buffer, scaling by the volume */
208 *buffer++ = signal;
209 samples--;
210
211 /* next! */
212 position++;
213 if (position >= voice->stop)
214 break;
215 }
216 }
217
218 /* second case: looping */
219 else
220 {
221 /* loop while we still have samples to generate */
222 while (samples)
223 {
224 /* compute the new amplitude and update the current step */
225 val = base[position / 2] >> ((~position & 1) << 2);
226 signal += (step * diff_lookup[val & 15]) / 8;
227
228 /* clamp to the maximum */
229 #ifndef clip_short
230 if (signal > 32767)
231 signal = 32767;
232 else if (signal < -32768)
233 signal = -32768;
234 #else
235 clip_short(signal);
236 #endif
237
238 /* adjust the step size and clamp */
239 step = (step * index_scale[val & 7]) >> 8;
240 if (step > 0x6000)
241 step = 0x6000;
242 else if (step < 0x7f)
243 step = 0x7f;
244
245 /* output to the buffer, scaling by the volume */
246 *buffer++ = signal;
247 samples--;
248
249 /* next! */
250 position++;
251 if (position == voice->loop_start && voice->loop_count == 0)
252 {
253 voice->loop_signal = signal;
254 voice->loop_step = step;
255 }
256 if (position >= voice->loop_end)
257 {
258 if (voice->keyon)
259 {
260 position = voice->loop_start;
261 signal = voice->loop_signal;
262 step = voice->loop_step;
263 voice->loop_count++;
264 }
265 }
266 if (position >= voice->stop)
267 break;
268 }
269 }
270
271 /* update the parameters */
272 voice->position = position;
273 voice->signal = signal;
274 voice->step = step;
275
276 return samples;
277 }
278
279
280
281 /**********************************************************************************************
282
283 generate_pcm8 -- general 8-bit PCM decoding routine
284
285 ***********************************************************************************************/
286
generate_pcm8(struct YMZ280BVoice * voice,UINT8 * base,INT16 * buffer,int samples)287 static int generate_pcm8(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples)
288 {
289 int position = voice->position;
290 int val;
291
292 /* two cases: first cases is non-looping */
293 if (!voice->looping)
294 {
295 /* loop while we still have samples to generate */
296 while (samples)
297 {
298 /* fetch the current value */
299 val = base[position / 2];
300
301 /* output to the buffer, scaling by the volume */
302 *buffer++ = (INT8)val * 256;
303 samples--;
304
305 /* next! */
306 position += 2;
307 if (position >= voice->stop)
308 break;
309 }
310 }
311
312 /* second case: looping */
313 else
314 {
315 /* loop while we still have samples to generate */
316 while (samples)
317 {
318 /* fetch the current value */
319 val = base[position / 2];
320
321 /* output to the buffer, scaling by the volume */
322 *buffer++ = (INT8)val * 256;
323 samples--;
324
325 /* next! */
326 position += 2;
327 if (position >= voice->loop_end)
328 {
329 if (voice->keyon)
330 position = voice->loop_start;
331 }
332 if (position >= voice->stop)
333 break;
334 }
335 }
336
337 /* update the parameters */
338 voice->position = position;
339
340 return samples;
341 }
342
343
344
345 /**********************************************************************************************
346
347 generate_pcm16 -- general 16-bit PCM decoding routine
348
349 ***********************************************************************************************/
350
generate_pcm16(struct YMZ280BVoice * voice,UINT8 * base,INT16 * buffer,int samples)351 static int generate_pcm16(struct YMZ280BVoice *voice, UINT8 *base, INT16 *buffer, int samples)
352 {
353 int position = voice->position;
354 int val;
355
356 /* two cases: first cases is non-looping */
357 if (!voice->looping)
358 {
359 /* loop while we still have samples to generate */
360 while (samples)
361 {
362 /* fetch the current value */
363 val = (INT16)((base[position / 2 + 1] << 8) + base[position / 2]);
364
365 /* output to the buffer, scaling by the volume */
366 *buffer++ = val;
367 samples--;
368
369 /* next! */
370 position += 4;
371 if (position >= voice->stop)
372 break;
373 }
374 }
375
376 /* second case: looping */
377 else
378 {
379 /* loop while we still have samples to generate */
380 while (samples)
381 {
382 /* fetch the current value */
383 val = (INT16)((base[position / 2 + 1] << 8) + base[position / 2]);
384
385 /* output to the buffer, scaling by the volume */
386 *buffer++ = val;
387 samples--;
388
389 /* next! */
390 position += 4;
391 if (position >= voice->loop_end)
392 {
393 if (voice->keyon)
394 position = voice->loop_start;
395 }
396 if (position >= voice->stop)
397 break;
398 }
399 }
400
401 /* update the parameters */
402 voice->position = position;
403
404 return samples;
405 }
406
407
408
409 /**********************************************************************************************
410
411 ymz280b_update -- update the sound chip so that it is in sync with CPU execution
412
413 ***********************************************************************************************/
414
ymz280b_update(int num,INT16 ** buffer,int length)415 static void ymz280b_update(int num, INT16 **buffer, int length)
416 {
417 struct YMZ280BChip *chip = &ymz280b[num];
418 INT32 *lacc = accumulator;
419 INT32 *racc = accumulator + length;
420 int v;
421
422 /* clear out the accumulator */
423 memset(accumulator, 0, 2 * length * sizeof(accumulator[0]));
424
425 /* loop over voices */
426 for (v = 0; v < 8; v++)
427 {
428 struct YMZ280BVoice *voice = &chip->voice[v];
429 INT16 prev = voice->last_sample;
430 INT16 curr = voice->curr_sample;
431 INT16 *curr_data = scratch;
432 INT32 *ldest = lacc;
433 INT32 *rdest = racc;
434 UINT32 new_samples, samples_left;
435 UINT32 final_pos;
436 int remaining = length;
437 int lvol = voice->output_left;
438 int rvol = voice->output_right;
439
440 /* quick out if we're not playing and we're at 0 */
441 if (!voice->playing && curr == 0)
442 continue;
443
444 /* finish off the current sample */
445 if (voice->output_pos > 0)
446 {
447 /* interpolate */
448 while (remaining > 0 && voice->output_pos < FRAC_ONE)
449 {
450 int interp_sample = (((INT32)prev * (FRAC_ONE - voice->output_pos)) + ((INT32)curr * voice->output_pos)) >> FRAC_BITS;
451 *ldest++ += interp_sample * lvol;
452 *rdest++ += interp_sample * rvol;
453 voice->output_pos += voice->output_step;
454 remaining--;
455 }
456
457 /* if we're over, continue; otherwise, we're done */
458 if (voice->output_pos >= FRAC_ONE)
459 voice->output_pos -= FRAC_ONE;
460 else
461 continue;
462 }
463
464 /* compute how many new samples we need */
465 final_pos = voice->output_pos + remaining * voice->output_step;
466 new_samples = (final_pos + FRAC_ONE - 1) >> FRAC_BITS;
467 if (new_samples > MAX_SAMPLE_CHUNK)
468 new_samples = MAX_SAMPLE_CHUNK;
469 samples_left = new_samples;
470
471 /* generate them into our buffer */
472 if (voice->playing)
473 {
474 switch (voice->mode)
475 {
476 case 1: samples_left = generate_adpcm(voice, chip->region_base, scratch, new_samples); break;
477 case 2: samples_left = generate_pcm8(voice, chip->region_base, scratch, new_samples); break;
478 case 3: samples_left = generate_pcm16(voice, chip->region_base, scratch, new_samples); break;
479 default:
480 case 0: samples_left = 0; memset(scratch, 0, new_samples * sizeof(scratch[0])); break;
481 }
482 }
483
484 /* if there are leftovers, ramp back to 0 */
485 if (samples_left)
486 {
487 int base = new_samples - samples_left;
488 int i, t = (base == 0) ? curr : scratch[base - 1];
489 for (i = 0; i < samples_left; i++)
490 {
491 if (t < 0) t = -((-t * 15) >> 4);
492 else if (t > 0) t = (t * 15) >> 4;
493 scratch[base + i] = t;
494 }
495
496 /* if we hit the end and IRQs are enabled, signal it */
497 if (base != 0)
498 {
499 voice->playing = 0;
500 chip->status_register |= 1 << v;
501 update_irq_state(chip);
502 }
503 }
504
505 /* advance forward one sample */
506 prev = curr;
507 curr = *curr_data++;
508
509 /* then sample-rate convert with linear interpolation */
510 while (remaining > 0)
511 {
512 /* interpolate */
513 while (remaining > 0 && voice->output_pos < FRAC_ONE)
514 {
515 int interp_sample = (((INT32)prev * (FRAC_ONE - voice->output_pos)) + ((INT32)curr * voice->output_pos)) >> FRAC_BITS;
516 *ldest++ += interp_sample * lvol;
517 *rdest++ += interp_sample * rvol;
518 voice->output_pos += voice->output_step;
519 remaining--;
520 }
521
522 /* if we're over, grab the next samples */
523 if (voice->output_pos >= FRAC_ONE)
524 {
525 voice->output_pos -= FRAC_ONE;
526 prev = curr;
527 curr = *curr_data++;
528 }
529 }
530
531 /* remember the last samples */
532 voice->last_sample = prev;
533 voice->curr_sample = curr;
534 }
535
536 /* mix and clip the result */
537 for (v = 0; v < length; v++)
538 {
539 int lsamp = lacc[v] / 256;
540 int rsamp = racc[v] / 256;
541
542 #ifndef clip_short
543 if (lsamp < -32768) lsamp = -32768;
544 else if (lsamp > 32767) lsamp = 32767;
545 if (rsamp < -32768) rsamp = -32768;
546 else if (rsamp > 32767) rsamp = 32767;
547 #else
548 clip_short(lsamp);
549 clip_short(rsamp);
550 #endif
551 buffer[0][v] = lsamp;
552 buffer[1][v] = rsamp;
553 }
554 }
555
556
557
558 /**********************************************************************************************
559
560 YMZ280B_sh_start -- start emulation of the YMZ280B
561
562 ***********************************************************************************************/
563
YMZ280B_sh_start(const struct MachineSound * msound)564 int YMZ280B_sh_start(const struct MachineSound *msound)
565 {
566 const struct YMZ280Binterface *intf = (const struct YMZ280Binterface *)msound->sound_interface;
567 char stream_name[2][40];
568 const char *stream_name_ptrs[2];
569 int vol[2];
570 int i;
571
572 /* compute ADPCM tables */
573 compute_tables();
574
575 /* initialize the voices */
576 memset(&ymz280b, 0, sizeof(ymz280b));
577 for (i = 0; i < intf->num; i++)
578 {
579 /* generate the name and create the stream */
580 sprintf(stream_name[0], "%s #%d (Left)", sound_name(msound), i);
581 sprintf(stream_name[1], "%s #%d (Right)", sound_name(msound), i);
582 stream_name_ptrs[0] = stream_name[0];
583 stream_name_ptrs[1] = stream_name[1];
584
585 /* set the volumes */
586 vol[0] = MIXER(intf->mixing_level[i], MIXER_PAN_LEFT);
587 vol[1] = MIXER(intf->mixing_level[i], MIXER_PAN_RIGHT);
588
589 /* create the stream */
590 ymz280b[i].stream = stream_init_multi(2, stream_name_ptrs, vol, Machine->sample_rate, i, ymz280b_update);
591 if (ymz280b[i].stream == -1)
592 return 1;
593
594 /* initialize the rest of the structure */
595 ymz280b[i].master_clock = (float)intf->baseclock[i] / 384.0;
596 ymz280b[i].region_base = memory_region(intf->region[i]);
597 ymz280b[i].irq_callback = intf->irq_callback[i];
598 }
599
600 /* allocate memory */
601 accumulator = (INT32*)malloc(sizeof(accumulator[0]) * 2 * MAX_SAMPLE_CHUNK);
602 scratch = (INT16*)malloc(sizeof(scratch[0]) * MAX_SAMPLE_CHUNK);
603 if (!accumulator || !scratch)
604 return 1;
605
606 /* success */
607 return 0;
608 }
609
610
611
612 /**********************************************************************************************
613
614 YMZ280B_sh_stop -- stop emulation of the YMZ280B
615
616 ***********************************************************************************************/
617
YMZ280B_sh_stop(void)618 void YMZ280B_sh_stop(void)
619 {
620 /* free memory */
621 if (accumulator)
622 free(accumulator);
623 accumulator = NULL;
624
625 if (scratch)
626 free(scratch);
627 scratch = NULL;
628 }
629
630
631
632 /**********************************************************************************************
633
634 write_to_register -- handle a write to the current register
635
636 ***********************************************************************************************/
637
write_to_register(struct YMZ280BChip * chip,int data)638 static void write_to_register(struct YMZ280BChip *chip, int data)
639 {
640 struct YMZ280BVoice *voice;
641 int i;
642
643 /* force an update */
644 #ifndef MAME_FASTSOUND
645 stream_update(chip->stream, 0);
646 #else
647 {
648 extern int fast_sound;
649 if (!fast_sound) stream_update(chip->stream, 0);
650 }
651 #endif
652
653 /* lower registers follow a pattern */
654 if (chip->current_register < 0x80)
655 {
656 voice = &chip->voice[(chip->current_register >> 2) & 7];
657
658 switch (chip->current_register & 0xe3)
659 {
660 case 0x00: /* pitch low 8 bits */
661 voice->fnum = (voice->fnum & 0x100) | (data & 0xff);
662 update_step(chip, voice);
663 break;
664
665 case 0x01: /* pitch upper 1 bit, loop, key on, mode */
666 voice->fnum = (voice->fnum & 0xff) | ((data & 0x01) << 8);
667 voice->looping = (data & 0x10) >> 4;
668 voice->mode = (data & 0x60) >> 5;
669 if (!voice->keyon && (data & 0x80) && chip->keyon_enable)
670 {
671 voice->playing = 1;
672 voice->position = voice->start;
673 voice->signal = voice->loop_signal = 0;
674 voice->step = voice->loop_step = 0x7f;
675 voice->loop_count = 0;
676 }
677 if (voice->keyon && !(data & 0x80) && !voice->looping)
678 voice->playing = 0;
679 voice->keyon = (data & 0x80) >> 7;
680 update_step(chip, voice);
681 break;
682
683 case 0x02: /* total level */
684 voice->level = data;
685 update_volumes(voice);
686 break;
687
688 case 0x03: /* pan */
689 voice->pan = data & 0x0f;
690 update_volumes(voice);
691 break;
692
693 case 0x20: /* start address high */
694 voice->start = (voice->start & (0x00ffff << 1)) | (data << 17);
695 break;
696
697 case 0x21: /* loop start address high */
698 voice->loop_start = (voice->loop_start & (0x00ffff << 1)) | (data << 17);
699 break;
700
701 case 0x22: /* loop end address high */
702 voice->loop_end = (voice->loop_end & (0x00ffff << 1)) | (data << 17);
703 break;
704
705 case 0x23: /* stop address high */
706 voice->stop = (voice->stop & (0x00ffff << 1)) | (data << 17);
707 break;
708
709 case 0x40: /* start address middle */
710 voice->start = (voice->start & (0xff00ff << 1)) | (data << 9);
711 break;
712
713 case 0x41: /* loop start address middle */
714 voice->loop_start = (voice->loop_start & (0xff00ff << 1)) | (data << 9);
715 break;
716
717 case 0x42: /* loop end address middle */
718 voice->loop_end = (voice->loop_end & (0xff00ff << 1)) | (data << 9);
719 break;
720
721 case 0x43: /* stop address middle */
722 voice->stop = (voice->stop & (0xff00ff << 1)) | (data << 9);
723 break;
724
725 case 0x60: /* start address low */
726 voice->start = (voice->start & (0xffff00 << 1)) | (data << 1);
727 break;
728
729 case 0x61: /* loop start address low */
730 voice->loop_start = (voice->loop_start & (0xffff00 << 1)) | (data << 1);
731 break;
732
733 case 0x62: /* loop end address low */
734 voice->loop_end = (voice->loop_end & (0xffff00 << 1)) | (data << 1);
735 break;
736
737 case 0x63: /* stop address low */
738 voice->stop = (voice->stop & (0xffff00 << 1)) | (data << 1);
739 break;
740
741 default:
742 logerror("YMZ280B: unknown register write %02X = %02X\n", chip->current_register, data);
743 break;
744 }
745 }
746
747 /* upper registers are special */
748 else
749 {
750 switch (chip->current_register)
751 {
752 case 0xfe: /* IRQ mask */
753 chip->irq_mask = data;
754 update_irq_state(chip);
755 break;
756
757 case 0xff: /* IRQ enable, test, etc */
758 chip->irq_enable = (data & 0x10) >> 4;
759 update_irq_state(chip);
760 chip->keyon_enable = (data & 0x80) >> 7;
761 if (!chip->keyon_enable)
762 for (i = 0; i < 8; i++)
763 chip->voice[i].playing = 0;
764 break;
765
766 default:
767 logerror("YMZ280B: unknown register write %02X = %02X\n", chip->current_register, data);
768 break;
769 }
770 }
771 }
772
773
774
775 /**********************************************************************************************
776
777 compute_status -- determine the status bits
778
779 ***********************************************************************************************/
780
compute_status(struct YMZ280BChip * chip)781 static int compute_status(struct YMZ280BChip *chip)
782 {
783 UINT8 result = chip->status_register;
784
785 /* force an update */
786 #ifndef MAME_FASTSOUND
787 stream_update(chip->stream, 0);
788 #else
789 {
790 extern int fast_sound;
791 if (!fast_sound) stream_update(chip->stream, 0);
792 }
793 #endif
794
795 /* clear the IRQ state */
796 chip->status_register = 0;
797 update_irq_state(chip);
798
799 return result;
800 }
801
802
803
804 /**********************************************************************************************
805
806 YMZ280B_status_0_r/YMZ280B_status_1_r -- handle a read from the status register
807
808 ***********************************************************************************************/
809
READ_HANDLER(YMZ280B_status_0_r)810 READ_HANDLER( YMZ280B_status_0_r )
811 {
812 return compute_status(&ymz280b[0]);
813 }
814
READ_HANDLER(YMZ280B_status_1_r)815 READ_HANDLER( YMZ280B_status_1_r )
816 {
817 return compute_status(&ymz280b[1]);
818 }
819
820
821
822 /**********************************************************************************************
823
824 YMZ280B_register_0_w/YMZ280B_register_1_w -- handle a write to the register select
825
826 ***********************************************************************************************/
827
WRITE_HANDLER(YMZ280B_register_0_w)828 WRITE_HANDLER( YMZ280B_register_0_w )
829 {
830 ymz280b[0].current_register = data;
831 }
832
WRITE_HANDLER(YMZ280B_register_1_w)833 WRITE_HANDLER( YMZ280B_register_1_w )
834 {
835 ymz280b[1].current_register = data;
836 }
837
838
839
840 /**********************************************************************************************
841
842 YMZ280B_data_0_w/YMZ280B_data_1_w -- handle a write to the current register
843
844 ***********************************************************************************************/
845
WRITE_HANDLER(YMZ280B_data_0_w)846 WRITE_HANDLER( YMZ280B_data_0_w )
847 {
848 write_to_register(&ymz280b[0], data);
849 }
850
WRITE_HANDLER(YMZ280B_data_1_w)851 WRITE_HANDLER( YMZ280B_data_1_w )
852 {
853 write_to_register(&ymz280b[1], data);
854 }
855