changeset 2325:26597f9805b4

Initial Codemasters mapper support
author Michael Pavone <pavone@retrodev.com>
date Tue, 18 Jul 2023 21:46:09 -0700
parents 2eda5f81f91e
children e734bfae80c7
files romdb.c romdb.h sms.c
diffstat 3 files changed, 114 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/romdb.c	Thu Jun 15 09:36:11 2023 -0700
+++ b/romdb.c	Tue Jul 18 21:46:09 2023 -0700
@@ -1170,6 +1170,9 @@
 
 void *sms_sega_mapper_write(uint32_t location, void *vcontext, uint8_t value);
 void *sms_cart_ram_write(uint32_t location, void *vcontext, uint8_t value);
+void *sms_codemasters_bank0_write(uint32_t location, void *vcontext, uint8_t value);
+void *sms_codemasters_bank1_write(uint32_t location, void *vcontext, uint8_t value);
+void *sms_codemasters_bank2_write(uint32_t location, void *vcontext, uint8_t value);
 void map_iter_fun_sms(char *key, tern_val val, uint8_t valtype, void *data)
 {
 	map_iter_state *state = data;
@@ -1228,6 +1231,30 @@
 	}
 }
 
+uint8_t has_codemasters_header(uint8_t *rom, uint32_t rom_size)
+{
+	if (rom_size < 0x8000) {
+		return 0;
+	}
+	//Date and time fields should be valid BCD
+	for (uint32_t i = 0x7FE1; i < 0x7FE6; i++)
+	{
+		if ((rom[i] & 0xF0) > 0x90) {
+			return 0;
+		}
+		if ((rom[i] & 0xF) > 0x9) {
+			return 0;
+		}
+	}
+	uint16_t checksum = rom[0x7FE6] | rom[0x7FE7] << 8;
+	uint16_t complement = rom[0x7FE8] | rom[0x7FE9] << 8;
+	if (complement != (0x10000 - checksum)) {
+		return 0;
+	}
+	puts("Detected codemasters mapper");
+	return 1;
+}
+
 void sms_memmap_heuristics(rom_info *info, memmap_chunk const *base_map, uint32_t num_base_chunks)
 {
 	uint32_t num_chunks = num_base_chunks + (info->rom_size > 0xC000 ? 5 : 1);
@@ -1235,40 +1262,63 @@
 	info->map = chunks;
 	info->map_chunks = num_chunks;
 	if (info->rom_size > 0xC000) {
-		//TODO: codemasters header
-		info->mapper_type = MAPPER_SMS_SEGA;
-		memcpy(chunks + 4, base_map, sizeof(memmap_chunk) * num_base_chunks);
-		chunks[0].start = 0;
-		chunks[0].end = 0x400;
-		chunks[0].mask = 0xFFFF;
-		chunks[0].flags = MMAP_READ;
-		chunks[0].buffer = info->rom;
-		chunks[1].start = 0x400;
-		chunks[1].end = 0x4000;
-		chunks[1].mask = 0x3FFF;
-		chunks[1].ptr_index = 0;
-		chunks[1].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
-		chunks[2].start = 0x4000;
-		chunks[2].end = 0x8000;
-		chunks[2].mask = 0x3FFF;
-		chunks[2].ptr_index = 1;
-		chunks[2].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
-		chunks[3].start = 0x8000;
-		chunks[3].end = 0xC000;
-		chunks[3].mask = 0x3FFF;
-		chunks[3].ptr_index = 2;
-		chunks[3].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
-		chunks[3].write_8 = sms_cart_ram_write;
-		chunks[num_chunks - 1].start = 0xFFFC;
-		chunks[num_chunks - 1].end = 0x10000;
-		chunks[num_chunks - 1].mask = 3;
-		chunks[num_chunks - 1].flags = MMAP_READ;
-		chunks[num_chunks - 1].write_8 = sms_sega_mapper_write;
-		for (uint32_t i = 4; i < num_chunks - 1; i++)
-		{
-			if (chunks[i].end > 0xFFFC) {
-				//mapper regs overlap RAM from base map
-				chunks[i].end = 0xFFFC;
+		if (has_codemasters_header(info->rom, info->rom_size)) {
+			info->mapper_type = MAPPER_SMS_CODEMASTERS;
+			memcpy(chunks + 3, base_map, sizeof(memmap_chunk) * num_base_chunks);
+			num_chunks--;
+			chunks[0].start = 0;
+			chunks[0].end = 0x4000;
+			chunks[0].mask = 0x3FFF;
+			chunks[0].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
+			chunks[0].ptr_index = 0;
+			chunks[0].write_8 = sms_codemasters_bank0_write;
+			chunks[1].start = 0x4000;
+			chunks[1].end = 0x8000;
+			chunks[1].mask = 0x3FFF;
+			chunks[1].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
+			chunks[1].ptr_index = 1;
+			chunks[1].write_8 = sms_codemasters_bank1_write;
+			chunks[2].start = 0x8000;
+			chunks[2].end = 0xC000;
+			chunks[2].mask = 0x3FFF;
+			chunks[2].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
+			chunks[2].ptr_index = 2;
+			chunks[2].write_8 = sms_codemasters_bank2_write;
+		} else {
+			info->mapper_type = MAPPER_SMS_SEGA;
+			memcpy(chunks + 4, base_map, sizeof(memmap_chunk) * num_base_chunks);
+			chunks[0].start = 0;
+			chunks[0].end = 0x400;
+			chunks[0].mask = 0xFFFF;
+			chunks[0].flags = MMAP_READ;
+			chunks[0].buffer = info->rom;
+			chunks[1].start = 0x400;
+			chunks[1].end = 0x4000;
+			chunks[1].mask = 0x3FFF;
+			chunks[1].ptr_index = 0;
+			chunks[1].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
+			chunks[2].start = 0x4000;
+			chunks[2].end = 0x8000;
+			chunks[2].mask = 0x3FFF;
+			chunks[2].ptr_index = 1;
+			chunks[2].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
+			chunks[3].start = 0x8000;
+			chunks[3].end = 0xC000;
+			chunks[3].mask = 0x3FFF;
+			chunks[3].ptr_index = 2;
+			chunks[3].flags = MMAP_READ|MMAP_PTR_IDX|MMAP_CODE;
+			chunks[3].write_8 = sms_cart_ram_write;
+			chunks[num_chunks - 1].start = 0xFFFC;
+			chunks[num_chunks - 1].end = 0x10000;
+			chunks[num_chunks - 1].mask = 3;
+			chunks[num_chunks - 1].flags = MMAP_READ;
+			chunks[num_chunks - 1].write_8 = sms_sega_mapper_write;
+			for (uint32_t i = 4; i < num_chunks - 1; i++)
+			{
+				if (chunks[i].end > 0xFFFC) {
+					//mapper regs overlap RAM from base map
+					chunks[i].end = 0xFFFC;
+				}
 			}
 		}
 	} else {
--- a/romdb.h	Thu Jun 15 09:36:11 2023 -0700
+++ b/romdb.h	Tue Jul 18 21:46:09 2023 -0700
@@ -51,7 +51,8 @@
 	MAPPER_JCART,
 	MAPPER_SEGA_MED_V2,
 	MAPPER_SFT_WUKONG,
-	MAPPER_SMS_SEGA
+	MAPPER_SMS_SEGA,
+	MAPPER_SMS_CODEMASTERS
 };
 
 
--- a/sms.c	Thu Jun 15 09:36:11 2023 -0700
+++ b/sms.c	Tue Jul 18 21:46:09 2023 -0700
@@ -178,6 +178,34 @@
 	return vcontext;
 }
 
+static z80_context *codemasters_write(uint8_t bank, z80_context *z80, uint8_t value)
+{
+	sms_context *sms = z80->system;
+	if (value != sms->bank_regs[bank]) {
+		sms->bank_regs[bank] = value;
+		value &= 0x7F;
+		z80->mem_pointers[bank] = sms->rom + (value << 14 & (sms->rom_size-1));
+		z80_invalidate_code_range(z80, bank * 0x4000, bank * 0x4000 + 0x4000);
+	}
+	return z80;
+}
+
+void *sms_codemasters_bank0_write(uint32_t location, void *vcontext, uint8_t value)
+{
+	return codemasters_write(0, vcontext, value);
+}
+
+void *sms_codemasters_bank1_write(uint32_t location, void *vcontext, uint8_t value)
+{
+	return codemasters_write(1, vcontext, value);
+}
+
+void *sms_codemasters_bank2_write(uint32_t location, void *vcontext, uint8_t value)
+{
+	//TODO: Handle Ernie Els Golf cart RAM
+	return codemasters_write(2, vcontext, value);
+}
+
 uint8_t debug_commands(system_header *system, char *input_buf)
 {
 	sms_context *sms = (sms_context *)system;