summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pavone <pavone@retrodev.com>2013-06-03 21:43:38 -0700
committerMike Pavone <pavone@retrodev.com>2013-06-03 21:43:38 -0700
commit8bd4d9e1e46a0e4277e61a7c999de9423df8ef92 (patch)
treeef5cb2916d075c81df0f9e211aa369ae6e3d5d4f
parent46b12a3e87fbe5608da7e4766114b9ccbc3c2f1c (diff)
Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
-rw-r--r--blastem.c51
-rw-r--r--psg.c8
-rw-r--r--psg.h3
-rw-r--r--ym2612.c51
-rw-r--r--ym2612.h3
5 files changed, 66 insertions, 50 deletions
diff --git a/blastem.c b/blastem.c
index 559ba32..e6c6206 100644
--- a/blastem.c
+++ b/blastem.c
@@ -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;
diff --git a/psg.c b/psg.c
index 1052436..815784a 100644
--- a/psg.c
+++ b/psg.c
@@ -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;
}
}
diff --git a/psg.h b/psg.h
index be7ca6a..295a319 100644
--- a/psg.h
+++ b/psg.h
@@ -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);
diff --git a/ym2612.c b/ym2612.c
index 26b5279..0f7fee9 100644
--- a/ym2612.c
+++ b/ym2612.c
@@ -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;
}
diff --git a/ym2612.h b/ym2612.h
index 7c74336..e4b235c 100644
--- a/ym2612.h
+++ b/ym2612.h
@@ -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);