summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);