summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--genesis.c8
-rw-r--r--ym2612.c40
-rw-r--r--ym2612.h7
3 files changed, 48 insertions, 7 deletions
diff --git a/genesis.c b/genesis.c
index 73a920d..a4cfba4 100644
--- a/genesis.c
+++ b/genesis.c
@@ -875,7 +875,7 @@ static uint8_t io_read(uint32_t location, m68k_context * context)
value = gen->zram[location & 0x1FFF];
} else if (location < 0x6000) {
sync_sound(gen, context->current_cycle);
- value = ym_read_status(gen->ym, context->current_cycle);
+ value = ym_read_status(gen->ym, context->current_cycle, location);
} else {
value = 0xFF;
}
@@ -988,7 +988,7 @@ static uint8_t z80_read_ym(uint32_t location, void * vcontext)
z80_context * context = vcontext;
genesis_context * gen = context->system;
sync_sound(gen, context->Z80_CYCLE);
- return ym_read_status(gen->ym, context->Z80_CYCLE);
+ return ym_read_status(gen->ym, context->Z80_CYCLE, location);
}
static uint8_t z80_read_bank(uint32_t location, void * vcontext)
@@ -1420,6 +1420,10 @@ genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on
render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
gen->ym = malloc(sizeof(ym2612_context));
+ char *fm = tern_find_ptr_default(model, "fm", "discrete 2612");
+ if (!strcmp(fm + strlen(fm) -4, "3834")) {
+ system_opts |= YM_OPT_3834;
+ }
ym_init(gen->ym, gen->master_clock, MCLKS_PER_YM, system_opts);
gen->psg = malloc(sizeof(psg_context));
diff --git a/ym2612.c b/ym2612.c
index d65e885..ec527a6 100644
--- a/ym2612.c
+++ b/ym2612.c
@@ -133,6 +133,12 @@ void ym_adjust_cycles(ym2612_context *context, uint32_t deduction)
} else {
context->busy_start = CYCLE_NEVER;
}
+ if (context->last_status_cycle != CYCLE_NEVER && context->last_status_cycle >= deduction) {
+ context->last_status_cycle -= deduction;
+ } else {
+ context->last_status = 0;
+ context->last_status_cycle = CYCLE_NEVER;
+ }
}
#ifdef __ANDROID__
@@ -188,6 +194,9 @@ void ym_init(ym2612_context * context, uint32_t master_clock, uint32_t clock_div
context->clock_inc = clock_div * 6;
context->busy_cycles = BUSY_CYCLES * context->clock_inc;
context->audio = render_audio_source(master_clock, context->clock_inc * NUM_OPERATORS, 2);
+ //TODO: pick a randomish high initial value and lower it over time
+ context->invalid_status_decay = 225000 * context->clock_inc;
+ context->status_address_mask = (options & YM_OPT_3834) ? 0 : 3;
//some games seem to expect that the LR flags start out as 1
for (int i = 0; i < NUM_CHANNELS; i++) {
@@ -1117,13 +1126,25 @@ void ym_data_write(ym2612_context * context, uint8_t value)
}
}
-uint8_t ym_read_status(ym2612_context * context, uint32_t cycle)
+uint8_t ym_read_status(ym2612_context * context, uint32_t cycle, uint32_t port)
{
- uint8_t status = context->status;
- if (cycle >= context->busy_start && cycle < context->busy_start + context->busy_cycles) {
- status |= 0x80;
+ uint8_t status;
+ port &= context->status_address_mask;
+ if (port) {
+ if (context->last_status_cycle != CYCLE_NEVER && cycle - context->last_status_cycle > context->invalid_status_decay) {
+ context->last_status = 0;
+ }
+ status = context->last_status;
+ } else {
+ status = context->status;
+ if (cycle >= context->busy_start && cycle < context->busy_start + context->busy_cycles) {
+ status |= 0x80;
+ }
+ context->last_status = status;
+ context->last_status_cycle = cycle;
}
return status;
+
}
void ym_print_channel_info(ym2612_context *context, int channel)
@@ -1236,6 +1257,9 @@ void ym_serialize(ym2612_context *context, serialize_buffer *buf)
save_int32(buf, context->current_cycle);
save_int32(buf, context->write_cycle);
save_int32(buf, context->busy_start);
+ save_int32(buf, context->last_status_cycle);
+ save_int32(buf, context->invalid_status_decay);
+ save_int8(buf, context->last_status);
}
void ym_deserialize(deserialize_buffer *buf, void *vcontext)
@@ -1311,4 +1335,12 @@ void ym_deserialize(deserialize_buffer *buf, void *vcontext)
context->current_cycle = load_int32(buf);
context->write_cycle = load_int32(buf);
context->busy_start = load_int32(buf);
+ if (buf->size > buf->cur_pos) {
+ context->last_status_cycle = load_int32(buf);
+ context->invalid_status_decay = load_int32(buf);
+ context->last_status = load_int8(buf);
+ } else {
+ context->last_status = context->status;
+ context->last_status_cycle = context->write_cycle;
+ }
}
diff --git a/ym2612.h b/ym2612.h
index 8694b3a..130c729 100644
--- a/ym2612.h
+++ b/ym2612.h
@@ -16,6 +16,7 @@
#define NUM_OPERATORS (4*NUM_CHANNELS)
#define YM_OPT_WAVE_LOG 1
+#define YM_OPT_3834 2
typedef struct {
int16_t *mod_src[2];
@@ -72,6 +73,9 @@ typedef struct {
uint32_t write_cycle;
uint32_t busy_start;
uint32_t busy_cycles;
+ uint32_t last_status_cycle;
+ uint32_t invalid_status_decay;
+ uint32_t status_address_mask;
int32_t volume_mult;
int32_t volume_div;
ym_operator operators[NUM_OPERATORS];
@@ -97,6 +101,7 @@ typedef struct {
uint8_t lfo_pm_step;
uint8_t csm_keyon;
uint8_t status;
+ uint8_t last_status;
uint8_t selected_reg;
uint8_t selected_part;
uint8_t part1_regs[YM_PART1_REGS];
@@ -139,7 +144,7 @@ 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);
void ym_data_write(ym2612_context * context, uint8_t value);
-uint8_t ym_read_status(ym2612_context * context, uint32_t cycle);
+uint8_t ym_read_status(ym2612_context * context, uint32_t cycle, uint32_t port);
uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile);
uint8_t ym_save_gst(ym2612_context * context, FILE * gstfile);
void ym_print_channel_info(ym2612_context *context, int channel);