comparison ymz263b.c @ 2466:b5640ac9aea9

Initial stab at PCM/ADPCM support in YMZ263B emulation
author Michael Pavone <pavone@retrodev.com>
date Sat, 24 Feb 2024 20:41:02 -0800
parents a25e8f304343
children bf8a77a8ddc4
comparison
equal deleted inserted replaced
2465:b0408f38f464 2466:b5640ac9aea9
34 34
35 #define TIMER_RUN_MASK (BIT_ST0|BIT_ST1|BIT_ST2) 35 #define TIMER_RUN_MASK (BIT_ST0|BIT_ST1|BIT_ST2)
36 #define TIMER_INT_MASK (BIT_T0_MSK|BIT_T1_MSK|BIT_T2_MSK) 36 #define TIMER_INT_MASK (BIT_T0_MSK|BIT_T1_MSK|BIT_T2_MSK)
37 37
38 //YMZ_PCM_PLAY_CTRL 38 //YMZ_PCM_PLAY_CTRL
39 #define BIT_ADP_ST 0x01
40 #define BIT_PLY_REC 0x02
41 #define BIT_PCM 0x04
42 #define BIT_PAN_L 0x20
43 #define BIT_PAN_R 0x40
39 #define BIT_ADP_RST 0x80 44 #define BIT_ADP_RST 0x80
45
46 //YMZ_PCM_FIFO_CTRL
47 #define BIT_DMA_ENB 0x01
48 #define BIT_MSK_FIF 0x02
49 #define BIT_DMA_MOD 0x80
40 50
41 //YMZ_MIDI_CTRL 51 //YMZ_MIDI_CTRL
42 #define BIT_MSK_RRQ 0x01 52 #define BIT_MSK_RRQ 0x01
43 #define BIT_MRC_RST 0x02 53 #define BIT_MRC_RST 0x02
44 #define BIT_MSK_TRQ 0x04 54 #define BIT_MSK_TRQ 0x04
53 #define STATUS_T0 0x10 63 #define STATUS_T0 0x10
54 #define STATUS_T1 0x20 64 #define STATUS_T1 0x20
55 #define STATUS_T2 0x40 65 #define STATUS_T2 0x40
56 #define STATUS_OV 0x80 66 #define STATUS_OV 0x80
57 67
68 #define TIMER_DIVIDER 32
58 #define MIDI_BYTE_DIVIDER 170 69 #define MIDI_BYTE_DIVIDER 170
70 #define PCM_BASE_DIVIDER 12
59 71
60 #define FIFO_EMPTY 255 72 #define FIFO_EMPTY 255
61 void ymz263b_init(ymz263b *ymz, uint32_t clock_divider) 73 void ymz263b_init(ymz263b *ymz, uint32_t master_clock, uint32_t clock_divider)
62 { 74 {
63 memset(ymz, 0, sizeof(*ymz)); 75 memset(ymz, 0, sizeof(*ymz));
64 ymz->clock_inc = clock_divider * 32; 76 ymz->clock_inc = clock_divider * TIMER_DIVIDER;
77 ymz->audio = render_audio_source("YMZ263B", master_clock, ymz->clock_inc * PCM_BASE_DIVIDER, 2);
65 ymz->base_regs[YMZ_SELT] = 1; 78 ymz->base_regs[YMZ_SELT] = 1;
66 ymz->pcm[0].regs[0] = BIT_ADP_RST; 79 ymz->pcm[0].regs[0] = BIT_ADP_RST;
67 ymz->pcm[1].regs[0] = BIT_ADP_RST; 80 ymz->pcm[1].regs[0] = BIT_ADP_RST;
81 ymz->pcm[0].counter = 1;
82 ymz->pcm[0].fifo_read = FIFO_EMPTY;
83 ymz->pcm[1].counter = 1;
84 ymz->pcm[1].fifo_read = FIFO_EMPTY;
68 ymz->midi_regs[0] = BIT_MTR_RST | BIT_MRC_RST; 85 ymz->midi_regs[0] = BIT_MTR_RST | BIT_MRC_RST;
69 ymz->midi_trs.read = ymz->midi_rcv.read = FIFO_EMPTY; 86 ymz->midi_trs.read = ymz->midi_rcv.read = FIFO_EMPTY;
70 ymz->status = 0; 87 ymz->status = 0;
88 ymz->pcm_counter = PCM_BASE_DIVIDER;
71 } 89 }
72 90
73 static uint8_t fifo_empty(ymz_midi_fifo *fifo) 91 static uint8_t fifo_empty(ymz_midi_fifo *fifo)
74 { 92 {
75 return fifo->read == FIFO_EMPTY; 93 return fifo->read == FIFO_EMPTY;
103 } 121 }
104 if (fifo->read == fifo->write) { 122 if (fifo->read == fifo->write) {
105 return 16; 123 return 16;
106 } 124 }
107 return (fifo->write - fifo->read) & 15; 125 return (fifo->write - fifo->read) & 15;
126 }
127
128 static uint8_t pcm_fifo_empty(ymz263b_pcm *pcm)
129 {
130 return pcm->fifo_read == FIFO_EMPTY;
131 }
132
133 static uint16_t pcm_fifo_read(ymz263b_pcm *pcm, uint8_t nibbles)
134 {
135 uint16_t ret = 0;
136 for (; nibbles && !pcm_fifo_empty(pcm); nibbles--)
137 {
138 ret <<= 4;
139 if (pcm->nibble) {
140 ret |= pcm->fifo[pcm->fifo_read++] & 0xF;
141 pcm->fifo_read &= sizeof(pcm->fifo) - 1;
142 pcm->nibble = 0;
143 if (pcm->fifo_read == pcm->fifo_write) {
144 pcm->fifo_read = FIFO_EMPTY;
145 }
146 } else {
147 ret |= pcm->fifo[pcm->fifo_read] >> 4;
148 pcm->nibble = 1;
149 }
150 }
151 return ret;
152 }
153
154 static uint8_t pcm_fifo_write(ymz263b_pcm *pcm, uint8_t nibbles, uint16_t value)
155 {
156 uint8_t overflow = 0;
157 value <<= (4 - nibbles) * 4;
158 for (; nibbles; nibbles--)
159 {
160 if (pcm->nibble_write) {
161 pcm->fifo[pcm->fifo_write++] |= value >> 12;
162 pcm->fifo_write &= sizeof(pcm->fifo) - 1;
163 pcm->nibble_write = 0;
164 } else {
165 if (pcm->fifo_read == FIFO_EMPTY) {
166 pcm->fifo_read = pcm->fifo_write;
167 } else if (pcm->fifo_read == pcm->fifo_write) {
168 overflow = 1;
169 }
170 pcm->fifo[pcm->fifo_write] = value >> 8 & 0xF0;
171 pcm->nibble_write = 1;
172 }
173 value <<= 4;
174 }
175 return overflow;
176 }
177
178 static uint8_t pcm_fifo_free(ymz263b_pcm *pcm)
179 {
180 if (pcm->fifo_read == FIFO_EMPTY) {
181 return sizeof(pcm->fifo);
182 }
183 return (pcm->fifo_read - pcm->fifo_write) & (sizeof(pcm->fifo) - 1);
184 }
185
186 static uint8_t pcm_dividers[] = {1, 2, 4, 6, 8};
187 static void ymz263b_pcm_run(ymz263b *ymz, ymz263b_pcm *pcm, int16_t *output)
188 {
189 if ((pcm->regs[0] & (BIT_ADP_RST|BIT_ADP_ST)) != BIT_ADP_ST) {
190 //PCM channel is either in reset or not started
191 return;
192 }
193 pcm->counter--;
194 if (!pcm->counter) {
195 uint8_t fs = pcm->regs[0] >> 3 & 3;
196 if (!(pcm->regs[0] & BIT_PCM)) {
197 //ADPCM can't use 44.1 kHz, but gains 5.5125 kHz
198 fs++;
199 }
200 pcm->counter = pcm_dividers[fs];
201 uint8_t nibbles = (pcm->regs[3] >> 5 & 3) + 2;
202 if (nibbles > 4) {
203 //4-bit format is encoded as the highest value for some reason
204 nibbles = 1;
205 }
206 //adlib driver suggests that FMT should be 3 for 4-bit ADPCM, but Copera games seem to use zero
207 //maybe FMT is ignored for ADPCM mode?
208 if (!(pcm->regs[0] & BIT_PCM)) {
209 nibbles = 1;
210 }
211 //adlib driver sets SELF to 5 for playback to trigger int "when less than 32 bytes in fifo" aka 96 bytes free
212 //adlib driver sets SELF to 3 for recording to trigger int "when more than 64 bytes in fifo" aka 64 bytes free
213 uint8_t fifo_threshold = ((pcm->regs[3] >> 2 & 7) + 1) << 4;
214 if (pcm->regs[0] & BIT_PLY_REC) {
215 //Playback mode
216 uint16_t sample = pcm_fifo_read(pcm, nibbles);
217 if (pcm->regs[0] & BIT_PCM) {
218 //TODO: Presumably SELT bit impacts this
219 if (sample & (1 << (nibbles * 4 - 1))) {
220 sample |= 0xFFF << (nibbles * 4);
221 }
222 switch (nibbles)
223 {
224 case 1:
225 sample <<= 8;
226 break;
227 case 2:
228 sample <<= 4;
229 break;
230 case 4:
231 //PCem's code seems to imply the "hole" is in the middle
232 //but that's ugly so hoping it's incorrect
233 sample >>= 4;
234 break;
235 }
236 pcm->output = sample;
237 } else {
238 //Values taken from YMFM 2610 ADPCM-A implementation
239 //They are almost certainly wrong for YMZ263B
240 static const int16_t mults[49] = {
241 16, 17, 19, 21, 23, 25, 28,
242 31, 34, 37, 41, 45, 50, 55,
243 60, 66, 73, 80, 88, 97, 107,
244 118, 130, 143, 157, 173, 190, 209,
245 230, 253, 279, 307, 337, 371, 408,
246 449, 494, 544, 598, 658, 724, 796,
247 876, 963, 1060, 1166, 1282, 1411, 1552
248 };
249 static const int8_t index_deltas[8] = {
250 -1, -1, -1, -1, 2, 5, 7, 9
251 };
252 uint16_t mag = sample & 7;
253 int16_t delta = (((mag << 1) + 1) * mults[pcm->adpcm_mul_index]) >> 3;
254 if (sample & 8) {
255 delta = -delta;
256 }
257 uint8_t old_index = pcm->adpcm_mul_index;
258 pcm->output += delta;
259 if (pcm->adpcm_mul_index || mag > 3) {
260 pcm->adpcm_mul_index += index_deltas[mag];
261 if (pcm->adpcm_mul_index >= sizeof(mults)) {
262 pcm->adpcm_mul_index = sizeof(mults) - 1;
263 }
264 }
265 int16_t output = pcm->output;
266 //Supposedly the YM2610 and YM2608 wrap around rather than clamp
267 //but since my tables have the wrong values I need to clamp
268 //in order to get something resembling the correct output
269 if (output > 0x7FF) {
270 pcm->output = 0x7FF;
271 } else if (output < -0x800) {
272 pcm->output = -0x800;
273 }
274 //printf("Sample %X, mag %X, delta %d, old index %d, new index %d, out %d\n", sample, mag, delta, old_index, pcm->adpcm_mul_index, (int16_t)pcm->output);
275 }
276 if (pcm->output & 0x800) {
277 pcm->output |= 0xF000;
278 } else {
279 pcm->output &= 0x0FFF;
280 }
281 if (pcm_fifo_free(pcm) > fifo_threshold) {
282 ymz->status |= pcm == &ymz->pcm[0] ? STATUS_FIF1 : STATUS_FIF2;
283 }
284 } else {
285 //Recording mode
286 //TODO: support recording actual audio input
287 if (pcm_fifo_write(pcm, nibbles, 0)) {
288 ymz->status |= STATUS_OV;
289 }
290 if (pcm_fifo_free(pcm) < fifo_threshold) {
291 ymz->status |= pcm == &ymz->pcm[0] ? STATUS_FIF1 : STATUS_FIF2;
292 }
293 }
294
295 }
296
297 if (pcm->regs[0] & BIT_PLY_REC) {
298 //TODO: Volume
299 if (pcm->regs[0] & BIT_PAN_L) {
300 output[0] += pcm->output;
301 }
302 if (pcm->regs[0] & BIT_PAN_R) {
303 output[1] += pcm->output;
304 }
305 }
108 } 306 }
109 307
110 void ymz263b_run(ymz263b *ymz, uint32_t target_cycle) 308 void ymz263b_run(ymz263b *ymz, uint32_t target_cycle)
111 { 309 {
112 uint8_t timer_ctrl = ymz->base_regs[YMZ_TIMER_CTRL]; 310 uint8_t timer_ctrl = ymz->base_regs[YMZ_TIMER_CTRL];
153 if (fifo_empty(&ymz->midi_trs)) { 351 if (fifo_empty(&ymz->midi_trs)) {
154 ymz->status |= STATUS_TRQ; 352 ymz->status |= STATUS_TRQ;
155 } 353 }
156 } 354 }
157 } 355 }
158 } 356 ymz->pcm_counter--;
357 if (!ymz->pcm_counter) {
358 ymz->pcm_counter = PCM_BASE_DIVIDER;
359 int16_t output[2] = {0, 0};
360 ymz263b_pcm_run(ymz, &ymz->pcm[0], output);
361 ymz263b_pcm_run(ymz, &ymz->pcm[1], output);
362 render_put_stereo_sample(ymz->audio, output[0], output[1]);
363 }
364 }
365 }
366
367 static uint32_t predict_fifo_thres(ymz263b *ymz, ymz263b_pcm *pcm)
368 {
369 if ((pcm->regs[0] & (BIT_ADP_RST|BIT_ADP_ST)) != BIT_ADP_ST) {
370 //PCM channel is either in reset or not started
371 return CYCLE_NEVER;
372 }
373 uint32_t next_pcm_cycle = ymz->cycle + ymz->pcm_counter * ymz->clock_inc;
374 next_pcm_cycle += (pcm->counter - 1) * PCM_BASE_DIVIDER * ymz->clock_inc;
375 uint32_t fifo_free = pcm_fifo_free(pcm);
376 //convert to nibbles
377 fifo_free <<= 1;
378 uint32_t fifo_threshold = ((pcm->regs[3] >> 2 & 7) + 1) << 5;
379 uint32_t diff;
380 if (pcm->regs[0] & BIT_PLY_REC) {
381 if (pcm->nibble) {
382 fifo_free++;
383 }
384 diff = fifo_threshold - fifo_free + 1;
385 } else {
386 if (pcm->nibble_write) {
387 fifo_free--;
388 }
389 diff = fifo_free - fifo_threshold + 1;
390 }
391 uint32_t nibbles_per_samp = (pcm->regs[3] >> 5 & 3) + 2;
392 if (nibbles_per_samp > 4) {
393 //4-bit format is encoded as the highest value for some reason
394 nibbles_per_samp = 1;
395 }
396 uint8_t fs = pcm->regs[0] >> 3 & 3;
397 if (!(pcm->regs[0] & BIT_PCM)) {
398 //ADPCM can't use 44.1 kHz, but gains 5.5125 kHz
399 fs++;
400 //see note in PCM playback code
401 nibbles_per_samp = 1;
402 }
403 diff /= nibbles_per_samp;
404
405 next_pcm_cycle += diff * PCM_BASE_DIVIDER * pcm_dividers[fs] * ymz->clock_inc;
406 return next_pcm_cycle;
159 } 407 }
160 408
161 uint32_t ymz263b_next_int(ymz263b *ymz) 409 uint32_t ymz263b_next_int(ymz263b *ymz)
162 { 410 {
163 //TODO: Handle FIFO and MIDI receive interrupts 411 //TODO: Handle MIDI receive interrupts
164 uint8_t enabled_ints = (~ymz->base_regs[YMZ_TIMER_CTRL]) & TIMER_INT_MASK; 412 uint8_t enabled_ints = (~ymz->base_regs[YMZ_TIMER_CTRL]) & TIMER_INT_MASK;
165 if (!(ymz->base_regs[YMZ_MIDI_CTRL] & (BIT_MTR_RST|BIT_MSK_TRQ))) { 413 if (!(ymz->base_regs[YMZ_MIDI_CTRL] & (BIT_MTR_RST|BIT_MSK_TRQ))) {
166 enabled_ints |= STATUS_TRQ; 414 enabled_ints |= STATUS_TRQ;
167 } 415 }
416 if (!(ymz->pcm[0].regs[3] & BIT_MSK_FIF)) {
417 enabled_ints |= STATUS_FIF1;
418 }
419 if (!(ymz->pcm[1].regs[3] & BIT_MSK_FIF)) {
420 enabled_ints |= STATUS_FIF2;
421 }
168 if (!enabled_ints) { 422 if (!enabled_ints) {
169 return CYCLE_NEVER; 423 return CYCLE_NEVER;
170 } 424 }
171 //Handle currently pending interrupts 425 //Handle currently pending interrupts
172 if (enabled_ints & ymz->status) { 426 if (enabled_ints & ymz->status) {
173 return ymz->cycle; 427 return ymz->cycle;
174 } 428 }
429
175 uint32_t ret = CYCLE_NEVER; 430 uint32_t ret = CYCLE_NEVER;
176 if (enabled_ints & STATUS_TRQ) { 431 if (enabled_ints & STATUS_TRQ) {
177 uint8_t bytes = fifo_size(&ymz->midi_trs); 432 uint8_t bytes = fifo_size(&ymz->midi_trs);
178 if (bytes) { 433 if (bytes) {
179 ret = ymz->cycle + (ymz->midi_transmit + 1) * ymz->clock_inc; 434 ret = ymz->cycle + (ymz->midi_transmit + 1) * ymz->clock_inc;
180 if (bytes > 1) { 435 if (bytes > 1) {
181 ret += MIDI_BYTE_DIVIDER * ymz->clock_inc * (bytes - 1); 436 ret += MIDI_BYTE_DIVIDER * ymz->clock_inc * (bytes - 1);
182 } 437 }
183 } 438 }
184 } 439 }
440
441 if (enabled_ints & STATUS_FIF1) {
442 uint32_t next_pcm = predict_fifo_thres(ymz, &ymz->pcm[0]);
443 if (next_pcm < ret) {
444 ret = next_pcm;
445 }
446 }
447 if (enabled_ints & STATUS_FIF2) {
448 uint32_t next_pcm = predict_fifo_thres(ymz, &ymz->pcm[1]);
449 if (next_pcm < ret) {
450 ret = next_pcm;
451 }
452 }
453
185 enabled_ints >>= 4; 454 enabled_ints >>= 4;
186 //If timers aren't already expired, interrupts can't fire unless the timers are enabled 455 //If timers aren't already expired, interrupts can't fire unless the timers are enabled
187 enabled_ints &= ymz->base_regs[YMZ_TIMER_CTRL]; 456 enabled_ints &= ymz->base_regs[YMZ_TIMER_CTRL];
188 if (!(ymz->base_regs[YMZ_TIMER_CTRL] & BIT_STBC)) { 457 if (!(ymz->base_regs[YMZ_TIMER_CTRL] & BIT_STBC)) {
189 //Timer 1 and Timer 2 depend on the base timer 458 //Timer 1 and Timer 2 depend on the base timer
226 495
227 void ymz263b_data_write(ymz263b *ymz, uint32_t channel, uint8_t value) 496 void ymz263b_data_write(ymz263b *ymz, uint32_t channel, uint8_t value)
228 { 497 {
229 if (channel) { 498 if (channel) {
230 if (ymz->address >= YMZ_PCM_PLAY_CTRL && ymz->address < YMZ_MIDI_CTRL) { 499 if (ymz->address >= YMZ_PCM_PLAY_CTRL && ymz->address < YMZ_MIDI_CTRL) {
500 if (ymz->address == YMZ_PCM_PLAY_CTRL) {
501 if (((value ^ ymz->pcm[1].regs[0]) & ymz->pcm[1].regs[0]) & BIT_ADP_RST) {
502 //Perform reset on falling edge of reset bit
503 ymz->pcm[1].counter = 1;
504 ymz->pcm[1].fifo_read = FIFO_EMPTY;
505 ymz->pcm[1].nibble = ymz->pcm[1].nibble_write = 0;
506 ymz->pcm[1].output = 0;
507 ymz->pcm[1].adpcm_mul_index = 0;
508 }
509 }
231 ymz->pcm[1].regs[ymz->address - YMZ_PCM_PLAY_CTRL] = value; 510 ymz->pcm[1].regs[ymz->address - YMZ_PCM_PLAY_CTRL] = value;
511 if (ymz->address == YMZ_PCM_DATA) {
512 pcm_fifo_write(&ymz->pcm[1], 2, value);
513 //Does an overflow here set the overflow statu sflag?
514 }
232 } 515 }
233 } else { 516 } else {
234 if (ymz->address < YMZ_PCM_PLAY_CTRL) { 517 if (ymz->address < YMZ_PCM_PLAY_CTRL) {
235 ymz->base_regs[ymz->address] = value; 518 ymz->base_regs[ymz->address] = value;
236 } else if (ymz->address < YMZ_MIDI_CTRL) { 519 } else if (ymz->address < YMZ_MIDI_CTRL) {
520 if (((value ^ ymz->pcm[0].regs[0]) & ymz->pcm[1].regs[0]) & BIT_ADP_RST) {
521 //Perform reset on falling edge of reset bit
522 ymz->pcm[0].counter = 1;
523 ymz->pcm[0].fifo_read = FIFO_EMPTY;
524 ymz->pcm[0].nibble = ymz->pcm[1].nibble_write = 0;
525 ymz->pcm[0].output = 0;
526 ymz->pcm[0].adpcm_mul_index = 0;
527 }
237 ymz->pcm[0].regs[ymz->address - YMZ_PCM_PLAY_CTRL] = value; 528 ymz->pcm[0].regs[ymz->address - YMZ_PCM_PLAY_CTRL] = value;
529 if (ymz->address == YMZ_PCM_DATA) {
530 pcm_fifo_write(&ymz->pcm[0], 2, value);
531 //Does an overflow here set the overflow statu sflag?
532 }
238 } else { 533 } else {
239 ymz->midi_regs[ymz->address - YMZ_MIDI_CTRL] = value; 534 ymz->midi_regs[ymz->address - YMZ_MIDI_CTRL] = value;
240 if (ymz->address == YMZ_MIDI_DATA) { 535 if (ymz->address == YMZ_MIDI_DATA) {
241 ymz->status &= ~STATUS_TRQ; 536 ymz->status &= ~STATUS_TRQ;
242 if (fifo_empty(&ymz->midi_trs)) { 537 if (fifo_empty(&ymz->midi_trs)) {
251 uint8_t ymz263b_data_read(ymz263b *ymz, uint32_t channel) 546 uint8_t ymz263b_data_read(ymz263b *ymz, uint32_t channel)
252 { 547 {
253 //TODO: Supposedly only a few registers are actually readable 548 //TODO: Supposedly only a few registers are actually readable
254 if (channel) { 549 if (channel) {
255 if (ymz->address >= YMZ_PCM_PLAY_CTRL && ymz->address < YMZ_MIDI_CTRL) { 550 if (ymz->address >= YMZ_PCM_PLAY_CTRL && ymz->address < YMZ_MIDI_CTRL) {
551 if (ymz->address == YMZ_PCM_DATA) {
552 return pcm_fifo_read(&ymz->pcm[1], 2);
553 }
256 return ymz->pcm[1].regs[ymz->address - YMZ_PCM_PLAY_CTRL]; 554 return ymz->pcm[1].regs[ymz->address - YMZ_PCM_PLAY_CTRL];
257 } 555 }
258 } else { 556 } else {
259 if (ymz->address < YMZ_PCM_PLAY_CTRL) { 557 if (ymz->address < YMZ_PCM_PLAY_CTRL) {
260 return ymz->base_regs[ymz->address]; 558 return ymz->base_regs[ymz->address];
261 } else if (ymz->address < YMZ_MIDI_CTRL) { 559 } else if (ymz->address < YMZ_MIDI_CTRL) {
560 if (ymz->address == YMZ_PCM_DATA) {
561 return pcm_fifo_read(&ymz->pcm[0], 2);
562 }
262 return ymz->pcm[0].regs[ymz->address - YMZ_PCM_PLAY_CTRL]; 563 return ymz->pcm[0].regs[ymz->address - YMZ_PCM_PLAY_CTRL];
263 } else { 564 } else {
264 return ymz->midi_regs[ymz->address - YMZ_MIDI_CTRL]; 565 return ymz->midi_regs[ymz->address - YMZ_MIDI_CTRL];
265 } 566 }
266 } 567 }