Mercurial > repos > blastem
comparison ym2612.c @ 364:62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 29 May 2013 00:57:19 -0700 |
parents | b7c3facee762 |
children | 3ba3b6656fff |
comparison
equal
deleted
inserted
replaced
363:c708dea45f8b | 364:62177cc39049 |
---|---|
1 #include <string.h> | 1 #include <string.h> |
2 #include <math.h> | 2 #include <math.h> |
3 #include <stdio.h> | 3 #include <stdio.h> |
4 #include <stdlib.h> | |
4 #include "ym2612.h" | 5 #include "ym2612.h" |
6 #include "render.h" | |
5 | 7 |
6 #define BUSY_CYCLES 17 | 8 #define BUSY_CYCLES 17 |
7 #define TIMERA_UPDATE_PERIOD 144 | 9 #define OP_UPDATE_PERIOD 144 |
8 | 10 |
9 enum { | 11 enum { |
10 REG_TIMERA_HIGH = 0x24, | 12 REG_TIMERA_HIGH = 0x24, |
11 REG_TIMERA_LOW, | 13 REG_TIMERA_LOW, |
12 REG_TIMERB, | 14 REG_TIMERB, |
73 }; | 75 }; |
74 | 76 |
75 uint16_t rate_table[64]; | 77 uint16_t rate_table[64]; |
76 | 78 |
77 #define MAX_ENVELOPE 0xFFC | 79 #define MAX_ENVELOPE 0xFFC |
78 | 80 #define YM_DIVIDER 2 |
79 | 81 |
80 uint16_t round_fixed_point(double value, int dec_bits) | 82 uint16_t round_fixed_point(double value, int dec_bits) |
81 { | 83 { |
82 return value * (1 << dec_bits) + 0.5; | 84 return value * (1 << dec_bits) + 0.5; |
83 } | 85 } |
84 | 86 |
85 void ym_init(ym2612_context * context) | 87 void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t sample_limit) |
86 { | 88 { |
87 memset(context, 0, sizeof(*context)); | 89 memset(context, 0, sizeof(*context)); |
90 context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); | |
91 context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); | |
92 context->buffer_inc = (double)sample_rate / (double)(clock_rate/OP_UPDATE_PERIOD); | |
93 context->sample_limit = sample_limit*2; | |
88 for (int i = 0; i < NUM_OPERATORS; i++) { | 94 for (int i = 0; i < NUM_OPERATORS; i++) { |
89 context->operators[i].envelope = MAX_ENVELOPE; | 95 context->operators[i].envelope = MAX_ENVELOPE; |
90 context->operators[i].env_phase = PHASE_RELEASE; | 96 context->operators[i].env_phase = PHASE_RELEASE; |
91 } | 97 } |
92 if (!did_tbl_init) { | 98 if (!did_tbl_init) { |
132 void ym_run(ym2612_context * context, uint32_t to_cycle) | 138 void ym_run(ym2612_context * context, uint32_t to_cycle) |
133 { | 139 { |
134 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); | 140 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); |
135 //TODO: Fix channel update order OR remap channels in register write | 141 //TODO: Fix channel update order OR remap channels in register write |
136 for (; context->current_cycle < to_cycle; context->current_cycle += 6) { | 142 for (; context->current_cycle < to_cycle; context->current_cycle += 6) { |
137 uint32_t update_cyc = context->current_cycle % 144; | |
138 //Update timers at beginning of 144 cycle period | 143 //Update timers at beginning of 144 cycle period |
139 if (!update_cyc && context->timer_control & BIT_TIMERA_ENABLE) { | 144 if (!context->current_op && context->timer_control & BIT_TIMERA_ENABLE) { |
140 if (context->timer_a) { | 145 if (context->timer_a) { |
141 context->timer_a--; | 146 context->timer_a--; |
142 } else { | 147 } else { |
143 if (context->timer_control & BIT_TIMERA_OVEREN) { | 148 if (context->timer_control & BIT_TIMERA_OVEREN) { |
144 context->status |= BIT_STATUS_TIMERA; | 149 context->status |= BIT_STATUS_TIMERA; |
145 } | 150 } |
146 context->timer_a = context->timer_a_load; | 151 context->timer_a = context->timer_a_load; |
147 } | 152 } |
148 if (context->timer_control & BIT_TIMERB_ENABLE) { | 153 if (context->timer_control & BIT_TIMERB_ENABLE) { |
149 uint32_t b_cyc = (context->current_cycle / 144) % 16; | 154 uint32_t b_cyc = (context->current_cycle / OP_UPDATE_PERIOD) % 16; |
150 if (!b_cyc) { | 155 if (!b_cyc) { |
151 if (context->timer_b) { | 156 if (context->timer_b) { |
152 context->timer_b--; | 157 context->timer_b--; |
153 } else { | 158 } else { |
154 if (context->timer_control & BIT_TIMERB_OVEREN) { | 159 if (context->timer_control & BIT_TIMERB_OVEREN) { |
158 } | 163 } |
159 } | 164 } |
160 } | 165 } |
161 } | 166 } |
162 //Update Envelope Generator | 167 //Update Envelope Generator |
163 if (update_cyc == 0 || update_cyc == 72) { | 168 if (!(context->current_op % 3)) { |
164 uint32_t env_cyc = context->current_cycle / 72; | 169 uint32_t env_cyc = context->env_counter; |
165 uint32_t op = env_cyc % 24; | 170 uint32_t op = context->current_env_op; |
166 env_cyc /= 24; | |
167 ym_operator * operator = context->operators + op; | 171 ym_operator * operator = context->operators + op; |
168 ym_channel * channel = context->channels + op/4; | 172 ym_channel * channel = context->channels + op/4; |
169 uint8_t rate; | 173 uint8_t rate; |
170 for(;;) { | 174 for(;;) { |
171 rate = operator->rates[operator->env_phase]; | 175 rate = operator->rates[operator->env_phase]; |
212 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { | 216 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { |
213 operator->envelope = operator->sustain_level; | 217 operator->envelope = operator->sustain_level; |
214 operator->env_phase = PHASE_SUSTAIN; | 218 operator->env_phase = PHASE_SUSTAIN; |
215 } | 219 } |
216 } | 220 } |
217 | 221 } |
218 | 222 context->current_env_op++; |
223 if (context->current_env_op == NUM_OPERATORS) { | |
224 context->current_env_op = 0; | |
225 context->env_counter++; | |
219 } | 226 } |
220 } | 227 } |
221 | 228 |
222 //Update Phase Generator | 229 //Update Phase Generator |
223 uint32_t channel = update_cyc / 24; | 230 uint32_t channel = context->current_op / 4; |
224 if (channel != 5 || !context->dac_enable) { | 231 if (channel != 5 || !context->dac_enable) { |
225 uint32_t op = (update_cyc) / 6; | 232 uint32_t op = context->current_op; |
226 //printf("updating operator %d of channel %d\n", op, channel); | 233 //printf("updating operator %d of channel %d\n", op, channel); |
227 ym_operator * operator = context->operators + op; | 234 ym_operator * operator = context->operators + op; |
228 ym_channel * chan = context->channels + channel; | 235 ym_channel * chan = context->channels + channel; |
229 //TODO: Modulate phase by LFO if necessary | 236 //TODO: Modulate phase by LFO if necessary |
230 operator->phase_counter += operator->phase_inc; | 237 operator->phase_counter += operator->phase_inc; |
301 chan->output = output; | 308 chan->output = output; |
302 } | 309 } |
303 } | 310 } |
304 //puts("operator update done"); | 311 //puts("operator update done"); |
305 } | 312 } |
313 context->current_op++; | |
314 if (context->current_op == NUM_OPERATORS) { | |
315 context->current_op = 0; | |
316 context->buffer_fraction += context->buffer_inc; | |
317 if (context->buffer_fraction > 1.0) { | |
318 context->buffer_fraction -= 1.0; | |
319 context->audio_buffer[context->buffer_pos] = 0; | |
320 context->audio_buffer[context->buffer_pos + 1] = 0; | |
321 for (int i = 0; i < NUM_CHANNELS; i++) { | |
322 uint16_t value = context->channels[i].output & 0x3FE0; | |
323 if (value & 0x2000) { | |
324 value |= 0xC000; | |
325 } | |
326 if (context->channels[i].lr & 0x80) { | |
327 context->audio_buffer[context->buffer_pos] += value / 2; | |
328 } | |
329 if (context->channels[i].lr & 0x40) { | |
330 context->audio_buffer[context->buffer_pos+1] += value / 2; | |
331 } | |
332 } | |
333 context->buffer_pos += 2; | |
334 if (context->buffer_pos == context->sample_limit) { | |
335 render_wait_ym(context); | |
336 } | |
337 } | |
338 } | |
306 } | 339 } |
307 if (context->current_cycle >= context->write_cycle + BUSY_CYCLES) { | 340 if (context->current_cycle >= context->write_cycle + BUSY_CYCLES) { |
308 context->status &= 0x7F; | 341 context->status &= 0x7F; |
309 } | 342 } |
310 //printf("Done running YM2612 at cycle %d\n", context->current_cycle, to_cycle); | 343 //printf("Done running YM2612 at cycle %d\n", context->current_cycle, to_cycle); |
311 } | 344 } |
312 | 345 |
313 void ym_address_write_part1(ym2612_context * context, uint8_t address) | 346 void ym_address_write_part1(ym2612_context * context, uint8_t address) |
314 { | 347 { |
348 //printf("address_write_part1: %X\n", address); | |
315 context->selected_reg = address; | 349 context->selected_reg = address; |
316 context->selected_part = 0; | 350 context->selected_part = 0; |
317 } | 351 } |
318 | 352 |
319 void ym_address_write_part2(ym2612_context * context, uint8_t address) | 353 void ym_address_write_part2(ym2612_context * context, uint8_t address) |
320 { | 354 { |
355 //printf("address_write_part2: %X\n", address); | |
321 context->selected_reg = address; | 356 context->selected_reg = address; |
322 context->selected_part = 1; | 357 context->selected_part = 1; |
323 } | 358 } |
324 | 359 |
325 uint8_t fnum_to_keycode[] = { | 360 uint8_t fnum_to_keycode[] = { |
391 inc *= operator->multiple; | 426 inc *= operator->multiple; |
392 } else { | 427 } else { |
393 //0.5 | 428 //0.5 |
394 inc >>= 1; | 429 inc >>= 1; |
395 } | 430 } |
431 operator->phase_inc = inc; | |
396 } | 432 } |
397 | 433 |
398 void ym_data_write(ym2612_context * context, uint8_t value) | 434 void ym_data_write(ym2612_context * context, uint8_t value) |
399 { | 435 { |
400 if (context->selected_reg < 0x21 || context->selected_reg > 0xB6 || (context->selected_reg < 0x30 && context->selected_part)) { | 436 if (context->selected_reg < 0x21 || context->selected_reg > 0xB6 || (context->selected_reg < 0x30 && context->selected_part)) { |
438 break; | 474 break; |
439 } | 475 } |
440 case REG_DAC: | 476 case REG_DAC: |
441 if (context->dac_enable) { | 477 if (context->dac_enable) { |
442 context->channels[5].output = (((int16_t)value) - 0x80) << 6; | 478 context->channels[5].output = (((int16_t)value) - 0x80) << 6; |
479 //printf("DAC Write %X(%d)\n", context->channels[5].output, context->channels[5].output); | |
443 } | 480 } |
444 break; | 481 break; |
445 case REG_DAC_ENABLE: | 482 case REG_DAC_ENABLE: |
483 //printf("DAC Enable: %X\n", value); | |
446 context->dac_enable = value & 0x80; | 484 context->dac_enable = value & 0x80; |
447 break; | 485 break; |
448 } | 486 } |
449 } else if (context->selected_reg < 0xA0) { | 487 } else if (context->selected_reg < 0xA0) { |
450 //part | 488 //part |