changeset 1904:8312e574100a

Implement selectable YM2612/YM3834 invalid status port behavior
author Michael Pavone <pavone@retrodev.com>
date Wed, 26 Feb 2020 22:40:37 -0800
parents 62166274e6c0
children 1ec6931d0a49
files genesis.c ym2612.c ym2612.h
diffstat 3 files changed, 48 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/genesis.c	Tue Feb 25 20:03:04 2020 -0800
+++ b/genesis.c	Wed Feb 26 22:40:37 2020 -0800
@@ -875,7 +875,7 @@
 				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 @@
 	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 @@
 	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));
--- a/ym2612.c	Tue Feb 25 20:03:04 2020 -0800
+++ b/ym2612.c	Wed Feb 26 22:40:37 2020 -0800
@@ -133,6 +133,12 @@
 	} 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 @@
 	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 @@
 	}
 }
 
-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 @@
 	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 @@
 	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;
+	}
 }
--- a/ym2612.h	Tue Feb 25 20:03:04 2020 -0800
+++ b/ym2612.h	Wed Feb 26 22:40:37 2020 -0800
@@ -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 @@
 	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 @@
 	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_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);