diff options
-rw-r--r-- | blastem.c | 51 | ||||
-rw-r--r-- | psg.c | 8 | ||||
-rw-r--r-- | psg.h | 3 | ||||
-rw-r--r-- | ym2612.c | 51 | ||||
-rw-r--r-- | ym2612.h | 3 |
5 files changed, 66 insertions, 50 deletions
@@ -12,9 +12,15 @@ #define CARTRIDGE_WORDS 0x200000 #define RAM_WORDS 32 * 1024 #define Z80_RAM_BYTES 8 * 1024 + +#define MCLKS_NTSC 53693175 +#define MCLKS_PAL 53203395 + #define MCLKS_PER_68K 7 +#define MCLKS_PER_YM MCLKS_PER_68K #define MCLKS_PER_Z80 15 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16) + //TODO: Figure out the exact value for this #define CYCLE_NEVER 0xFFFFFFFF #define LINES_NTSC 262 @@ -187,6 +193,16 @@ void sync_z80(z80_context * z_context, uint32_t mclks) z_context->current_cycle = mclks / MCLKS_PER_Z80; } } + +void sync_sound(genesis_context * gen, uint32_t target) +{ + //printf("YM | Cycle: %d, bpos: %d, PSG | Cycle: %d, bpos: %d\n", gen->ym->current_cycle, gen->ym->buffer_pos, gen->psg->cycles, gen->psg->buffer_pos * 2); + psg_run(gen->psg, target); + ym_run(gen->ym, target); + + //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); +} + uint32_t frame=0; m68k_context * sync_components(m68k_context * context, uint32_t address) { @@ -197,15 +213,15 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) uint32_t mclks = context->current_cycle * MCLKS_PER_68K; sync_z80(z_context, mclks); if (mclks >= mclks_per_frame) { - ym_run(gen->ym, context->current_cycle); - gen->ym->current_cycle -= mclks_per_frame/MCLKS_PER_68K; + sync_sound(gen, mclks); + gen->ym->current_cycle -= mclks_per_frame; + gen->psg->cycles -= mclks_per_frame; if (gen->ym->write_cycle != CYCLE_NEVER) { gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0; } //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); vdp_run_context(v_context, mclks_per_frame); - psg_run(gen->psg, mclks/MCLKS_PER_PSG); - gen->psg->cycles -= mclks_per_frame/MCLKS_PER_PSG; + if (!headless) { break_on_sync |= wait_render_frame(v_context, frame_limit); } @@ -234,7 +250,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } else { //printf("running VDP for %d cycles\n", mclks - v_context->cycles); vdp_run_context(v_context, mclks); - psg_run(gen->psg, mclks/MCLKS_PER_PSG); + sync_sound(gen, mclks); } if (context->int_ack) { vdp_int_ack(v_context, context->int_ack); @@ -326,7 +342,7 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ } } else if (vdp_port < 0x18) { genesis_context * gen = context->system; - psg_run(gen->psg, (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_PSG); + sync_sound(gen, context->current_cycle * MCLKS_PER_68K); psg_write(gen->psg, value); } else { //TODO: Implement undocumented test register(s) @@ -358,7 +374,7 @@ z80_context * z80_vdp_port_write(uint16_t vdp_port, z80_context * context, uint8 exit(1); } } else if (vdp_port < 0x18) { - psg_run(gen->psg, (context->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_PSG); + sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); psg_write(gen->psg, value); } else { //TODO: Implement undocumented test register(s) @@ -494,7 +510,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value z80_ram[location & 0x1FFF] = value; z80_handle_code_write(location & 0x1FFF, gen->z80); } else if (location < 0x6000) { - ym_run(gen->ym, context->current_cycle); + sync_sound(gen, context->current_cycle * MCLKS_PER_68K); if (location & 1) { ym_data_write(gen->ym, value); } else if(location & 2) { @@ -594,7 +610,7 @@ m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t va z80_ram[location & 0x1FFE] = value >> 8; z80_handle_code_write(location & 0x1FFE, gen->z80); } else if (location < 0x6000) { - ym_run(gen->ym, context->current_cycle); + sync_sound(gen, context->current_cycle * MCLKS_PER_68K); if (location & 1) { ym_data_write(gen->ym, value >> 8); } else if(location & 2) { @@ -700,7 +716,7 @@ uint8_t io_read(uint32_t location, m68k_context * context) if (location < 0x4000) { value = z80_ram[location & 0x1FFF]; } else if (location < 0x6000) { - ym_run(gen->ym, context->current_cycle); + sync_sound(gen, context->current_cycle * MCLKS_PER_68K); value = ym_read_status(gen->ym); } else { value = 0xFF; @@ -767,7 +783,7 @@ uint16_t io_read_w(uint32_t location, m68k_context * context) if (location < 0x4000) { value = z80_ram[location & 0x1FFE]; } else if (location < 0x6000) { - ym_run(gen->ym, context->current_cycle); + sync_sound(gen, context->current_cycle * MCLKS_PER_68K); value = ym_read_status(gen->ym); } else { value = 0xFF; @@ -830,7 +846,7 @@ uint16_t io_read_w(uint32_t location, m68k_context * context) z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) { genesis_context * gen = context->system; - ym_run(gen->ym, (context->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K); + sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); if (location & 1) { ym_data_write(gen->ym, value); } else if (location & 2) { @@ -844,7 +860,7 @@ z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t val uint8_t z80_read_ym(uint16_t location, z80_context * context) { genesis_context * gen = context->system; - ym_run(gen->ym, (context->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K); + sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); return ym_read_status(gen->ym); } @@ -1810,11 +1826,6 @@ void detect_region() } } -#define PSG_CLKS_NTSC (3579545/16) -#define PSG_CLKS_PAL (3546893/16) -#define YM_CLKS_NTSC 7670454 -#define YM_CLKS_PAL 7600485 - int main(int argc, char ** argv) { if (argc < 2) { @@ -1899,10 +1910,10 @@ int main(int argc, char ** argv) init_vdp_context(&v_context); ym2612_context y_context; - ym_init(&y_context, render_sample_rate(), fps == 60 ? YM_CLKS_NTSC : YM_CLKS_PAL, render_audio_buffer()); + ym_init(&y_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_YM, render_audio_buffer()); psg_context p_context; - psg_init(&p_context, render_sample_rate(), fps == 60 ? PSG_CLKS_NTSC : PSG_CLKS_PAL, render_audio_buffer()); + psg_init(&p_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_PSG, render_audio_buffer()); z80_context z_context; x86_z80_options z_opts; @@ -3,12 +3,14 @@ #include <string.h> #include <stdlib.h> -void psg_init(psg_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t samples_frame) +void psg_init(psg_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t samples_frame) { memset(context, 0, sizeof(*context)); context->audio_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame); context->back_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame); - context->buffer_inc = (double)sample_rate / (double)clock_rate; + double clock_rate = (double)master_clock / (double)clock_div; + context->buffer_inc = ((double)sample_rate / (double)master_clock) * clock_div; + context->clock_inc = clock_div; context->samples_frame = samples_frame; for (int i = 0; i < 4; i++) { context->volume[i] = 0xF; @@ -106,7 +108,7 @@ void psg_run(psg_context * context, uint32_t cycles) render_wait_psg(context); } } - context->cycles++; + context->cycles += context->clock_inc; } } @@ -9,6 +9,7 @@ typedef struct { double buffer_fraction; double buffer_inc; uint32_t buffer_pos; + uint32_t clock_inc; uint32_t cycles; uint32_t samples_frame; uint16_t lsfr; @@ -23,7 +24,7 @@ typedef struct { } psg_context; -void psg_init(psg_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t samples_frame); +void psg_init(psg_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t samples_frame); void psg_write(psg_context * context, uint8_t value); void psg_run(psg_context * context, uint32_t cycles); @@ -97,13 +97,14 @@ uint16_t round_fixed_point(double value, int dec_bits) FILE * debug_file = NULL; uint32_t first_key_on=0; -void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t sample_limit) +void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit) { dfopen(debug_file, "ym_debug.txt", "w"); memset(context, 0, sizeof(*context)); context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); - context->buffer_inc = (double)sample_rate / (double)(clock_rate/OP_UPDATE_PERIOD); + context->buffer_inc = ((double)sample_rate / (double)master_clock) * clock_div * 6; + context->clock_inc = clock_div * 6; context->sample_limit = sample_limit*2; context->write_cycle = CYCLE_NEVER; for (int i = 0; i < NUM_OPERATORS; i++) { @@ -162,7 +163,7 @@ void ym_run(ym2612_context * context, uint32_t to_cycle) { //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); //TODO: Fix channel update order OR remap channels in register write - for (; context->current_cycle < to_cycle; context->current_cycle += 6) { + for (; context->current_cycle < to_cycle; context->current_cycle += context->clock_inc) { //Update timers at beginning of 144 cycle period if (!context->current_op && context->timer_control & BIT_TIMERA_ENABLE) { if (context->timer_a) { @@ -357,33 +358,33 @@ void ym_run(ym2612_context * context, uint32_t to_cycle) //puts("operator update done"); } context->current_op++; - if (context->current_op == NUM_OPERATORS) { - context->current_op = 0; - context->buffer_fraction += context->buffer_inc; - if (context->buffer_fraction > 1.0) { - context->buffer_fraction -= 1.0; - context->audio_buffer[context->buffer_pos] = 0; - context->audio_buffer[context->buffer_pos + 1] = 0; - for (int i = 0; i < NUM_CHANNELS; i++) { - int16_t value = context->channels[i].output & 0x3FE0; - if (value & 0x2000) { - value |= 0xC000; - } - if (context->channels[i].lr & 0x80) { - context->audio_buffer[context->buffer_pos] += value / YM_VOLUME_DIVIDER; - } - if (context->channels[i].lr & 0x40) { - context->audio_buffer[context->buffer_pos+1] += value / YM_VOLUME_DIVIDER; - } + context->buffer_fraction += context->buffer_inc; + if (context->buffer_fraction > 1.0) { + context->buffer_fraction -= 1.0; + context->audio_buffer[context->buffer_pos] = 0; + context->audio_buffer[context->buffer_pos + 1] = 0; + for (int i = 0; i < NUM_CHANNELS; i++) { + int16_t value = context->channels[i].output & 0x3FE0; + if (value & 0x2000) { + value |= 0xC000; + } + if (context->channels[i].lr & 0x80) { + context->audio_buffer[context->buffer_pos] += value / YM_VOLUME_DIVIDER; } - context->buffer_pos += 2; - if (context->buffer_pos == context->sample_limit) { - render_wait_ym(context); + if (context->channels[i].lr & 0x40) { + context->audio_buffer[context->buffer_pos+1] += value / YM_VOLUME_DIVIDER; } } + context->buffer_pos += 2; + if (context->buffer_pos == context->sample_limit) { + render_wait_ym(context); + } + } + if (context->current_op == NUM_OPERATORS) { + context->current_op = 0; } } - if (context->current_cycle >= context->write_cycle + BUSY_CYCLES) { + if (context->current_cycle >= context->write_cycle + (BUSY_CYCLES * context->clock_inc / 6)) { context->status &= 0x7F; context->write_cycle = CYCLE_NEVER; } @@ -39,6 +39,7 @@ typedef struct { int16_t *back_buffer; double buffer_fraction; double buffer_inc; + uint32_t clock_inc; uint32_t buffer_pos; uint32_t sample_limit; uint32_t current_cycle; @@ -59,7 +60,7 @@ typedef struct { uint8_t selected_part; } ym2612_context; -void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t sample_limit); +void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit); void ym_run(ym2612_context * context, uint32_t to_cycle); void ym_address_write_part1(ym2612_context * context, uint8_t address); void ym_address_write_part2(ym2612_context * context, uint8_t address); |