changeset 2194:01ff005b08f6

Very rudimentary support for Game Gear VDP emulation
author Michael Pavone <pavone@retrodev.com>
date Sun, 21 Aug 2022 22:29:47 -0700
parents d00fb9c6a6a2
children 40290a923886
files gen_player.c genesis.c sms.c vdp.c vdp.h
diffstat 5 files changed, 48 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/gen_player.c	Sun Aug 21 16:41:22 2022 -0700
+++ b/gen_player.c	Sun Aug 21 22:29:47 2022 -0700
@@ -12,7 +12,7 @@
 #ifdef IS_LIB
 #define MAX_SOUND_CYCLES (MCLKS_PER_YM*NUM_OPERATORS*6*4)
 #else
-#define MAX_SOUND_CYCLES 100000	
+#define MAX_SOUND_CYCLES 100000
 #endif
 
 static void sync_sound(gen_player *gen, uint32_t target)
@@ -92,7 +92,7 @@
 			vdp_replay_event(player->vdp, event, &player->reader);
 		}
 		}
-			
+
 		}
 		if (!player->reader.socket) {
 			reader_ensure_data(&player->reader, 1);
@@ -136,17 +136,17 @@
 	uint8_t name_len = load_int8(&player->reader.buffer);
 	player->header.info.name = calloc(1, name_len + 1);
 	load_buffer8(&player->reader.buffer, player->header.info.name, name_len);
-	
-	player->vdp = init_vdp_context(vid_std == VID_PAL, 0);
+
+	player->vdp = init_vdp_context(vid_std == VID_PAL, 0, VDP_GENESIS);
 	render_set_video_standard(vid_std);
 	uint32_t master_clock = vid_std == VID_NTSC ? MCLKS_NTSC : MCLKS_PAL;
-	
+
 	player->ym = malloc(sizeof(ym2612_context));
 	ym_init(player->ym, master_clock, MCLKS_PER_YM, 0);
-	
+
 	player->psg = malloc(sizeof(psg_context));
 	psg_init(player->psg, master_clock, MCLKS_PER_PSG);
-	
+
 	player->header.start_context = start_context;
 	player->header.gamepad_down = gamepad_down;
 	player->header.gamepad_up = gamepad_up;
--- a/genesis.c	Sun Aug 21 16:41:22 2022 -0700
+++ b/genesis.c	Sun Aug 21 22:29:47 2022 -0700
@@ -1873,7 +1873,7 @@
 	}
 
 	uint8_t max_vsram = !strcmp(tern_find_ptr_default(model, "vsram", "40"), "64");
-	gen->vdp = init_vdp_context(gen->version_reg & 0x40, max_vsram);
+	gen->vdp = init_vdp_context(gen->version_reg & 0x40, max_vsram, VDP_GENESIS);
 	gen->vdp->system = &gen->header;
 	gen->frame_end = vdp_cycles_to_frame_end(gen->vdp);
 	char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval;
--- a/sms.c	Sun Aug 21 16:41:22 2022 -0700
+++ b/sms.c	Sun Aug 21 22:29:47 2022 -0700
@@ -397,7 +397,7 @@
 					system->enter_debugger_frames -= elapsed;
 				}
 			}
-			
+
 			if(exit_after){
 				if (elapsed >= exit_after) {
 					exit(0);
@@ -650,7 +650,7 @@
 
 	set_gain_config(sms);
 
-	sms->vdp = init_vdp_context(0, 0);
+	sms->vdp = init_vdp_context(0, 0, strcasecmp(media->extension, "gg") ? VDP_GENESIS : VDP_GAMEGEAR);
 	sms->vdp->system = &sms->header;
 
 	sms->header.info.save_type = SAVE_NONE;
--- a/vdp.c	Sun Aug 21 16:41:22 2022 -0700
+++ b/vdp.c	Sun Aug 21 22:29:47 2022 -0700
@@ -146,7 +146,7 @@
 
 static uint8_t color_map_init_done;
 
-vdp_context *init_vdp_context(uint8_t region_pal, uint8_t has_max_vsram)
+vdp_context *init_vdp_context(uint8_t region_pal, uint8_t has_max_vsram, uint8_t type)
 {
 	vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE);
 	if (headless) {
@@ -161,6 +161,7 @@
 	context->fifo_read = -1;
 	context->regs[REG_HINT] = context->hint_counter = 0xFF;
 	context->vsram_size = has_max_vsram ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE;
+	context->type = type;
 
 	if (!color_map_init_done) {
 		uint8_t b,g,r;
@@ -174,9 +175,16 @@
 				g = levels[((color >> 5) & 0x7) + 7];
 				r = levels[((color >> 1) & 0x7) + 7];
 			} else if(color & FBUF_MODE4) {
-				b = levels[(color >> 4 & 0xC) | (color >> 6 & 0x2)];
-				g = levels[(color >> 2 & 0x8) | (color >> 1 & 0x4) | (color >> 4 & 0x2)];
-				r = levels[(color << 1 & 0xC) | (color >> 1 & 0x2)];
+				if (type == VDP_GAMEGEAR) {
+					b = (color >> 8 & 0xF) * 0x11;
+					g = (color >> 4 & 0xF) * 0x11;
+					r = (color & 0xF) * 0x11;
+				} else {
+					//TODO: Mode 4 has a separate DAC tap so this isn't quite correct
+					b = levels[(color >> 4 & 0xC) | (color >> 6 & 0x2)];
+					g = levels[(color >> 2 & 0x8) | (color >> 1 & 0x4) | (color >> 4 & 0x2)];
+					r = levels[(color << 1 & 0xC) | (color >> 1 & 0x2)];
+				}
 			} else {
 				b = levels[(color >> 8) & 0xE];
 				g = levels[(color >> 4) & 0xE];
@@ -805,7 +813,11 @@
 	context->colors[index] = color_map[value & CRAM_BITS];
 	context->colors[index + SHADOW_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_SHADOW];
 	context->colors[index + HIGHLIGHT_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_HILIGHT];
-	context->colors[index + MODE4_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_MODE4];
+	if (context->type == VDP_GAMEGEAR) {
+		context->colors[index + MODE4_OFFSET] = color_map[(value & 0xFFF) | FBUF_MODE4];
+	} else {
+		context->colors[index + MODE4_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_MODE4];
+	}
 }
 
 void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value)
@@ -819,6 +831,8 @@
 	uint16_t addr;
 	if (context->regs[REG_MODE_2] & BIT_MODE_5) {
 		addr = (address/2) & (CRAM_SIZE-1);
+	} else if (context->type == VDP_GAMEGEAR) {
+		addr = (address/2) & 31;
 	} else {
 		addr = address & 0x1F;
 		value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00);
@@ -940,7 +954,14 @@
 			//printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1));
 			uint16_t val;
 			if (start->partial == 3) {
-				if ((start->address & 1) && (context->regs[REG_MODE_2] & BIT_MODE_5)) {
+				if (context->type == VDP_GAMEGEAR) {
+					if (start->address & 1) {
+						val = start->value << 8 | context->cram_latch;
+					} else {
+						context->cram_latch = start->value;
+						break;
+					}
+				} else if ((start->address & 1) && (context->regs[REG_MODE_2] & BIT_MODE_5)) {
 					val = (context->cram[start->address >> 1 & (CRAM_SIZE-1)] & 0xFF) | start->value << 8;
 				} else {
 					uint16_t address = (context->regs[REG_MODE_2] & BIT_MODE_5) ? start->address >> 1 & (CRAM_SIZE-1) : start->address & 0x1F;
--- a/vdp.h	Sun Aug 21 16:41:22 2022 -0700
+++ b/vdp.h	Sun Aug 21 22:29:47 2022 -0700
@@ -163,6 +163,14 @@
 	VDP_NUM_DEBUG_TYPES
 };
 
+enum {
+	VDP_GENESIS,
+	VDP_GAMEGEAR,
+	VDP_SMS2,
+	VDP_SMS,
+	VDP_TMS9918A
+};
+
 typedef struct {
 	system_header  *system;
 	//pointer to current line in framebuffer
@@ -245,12 +253,14 @@
 	uint8_t        debug_fb_indices[VDP_NUM_DEBUG_TYPES];
 	uint8_t        debug_modes[VDP_NUM_DEBUG_TYPES];
 	uint8_t        pushed_frame;
+	uint8_t        type;
+	uint8_t        cram_latch;
 	uint8_t        vdpmem[];
 } vdp_context;
 
 
 
-vdp_context *init_vdp_context(uint8_t region_pal, uint8_t has_max_vsram);
+vdp_context *init_vdp_context(uint8_t region_pal, uint8_t has_max_vsram, uint8_t type);
 void vdp_free(vdp_context *context);
 void vdp_run_context_full(vdp_context * context, uint32_t target_cycles);
 void vdp_run_context(vdp_context * context, uint32_t target_cycles);