changeset 2281:b9fed07f19e4

Implement BRAM cart support
author Michael Pavone <pavone@retrodev.com>
date Sun, 08 Jan 2023 23:30:28 -0800
parents 9ead0fe69d9b
children a6a68c33cce7
files genesis.c segacd.c segacd.h
diffstat 3 files changed, 134 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/genesis.c	Sun Jan 08 14:42:24 2023 -0800
+++ b/genesis.c	Sun Jan 08 23:30:28 2023 -0800
@@ -1542,6 +1542,17 @@
 			printf("Saved internal BRAM to %s\n", bram_name);
 		}
 		free(bram_name);
+		if (cd->bram_cart_id < 8) {
+			bram_name = path_append(system->save_dir, "cart.bram");
+			f = fopen(bram_name, "wb");
+			if (f) {
+				long configured_size = 0x2000 << cd->bram_cart_id;
+				fwrite(cd->bram_cart, 1, configured_size, f);
+				fclose(f);
+				printf("Saved BRAM cart to %s\n", bram_name);
+			}
+			free(bram_name);
+		}
 	}
 	if (gen->save_type == SAVE_NONE) {
 		return;
@@ -1588,6 +1599,31 @@
 			}
 		}
 		free(bram_name);
+		bram_name = path_append(system->save_dir, "cart.bram");
+		f = fopen(bram_name, "rb");
+		if (f) {
+			long existing_size = nearest_pow2(file_size(f));
+			if (existing_size > 1 * 1024 * 1024) {
+				existing_size = 1 * 1024 * 1024;
+			}
+			long configured_size = 0x2000 << cd->bram_cart_id;
+			if (existing_size != configured_size) {
+				if (existing_size > configured_size) {
+					free(cd->bram_cart);
+					cd->bram_cart = calloc(existing_size, 1);
+				}
+				cd->bram_cart_id = 0;
+				while (existing_size > (0x2000 <<cd->bram_cart_id)) {
+					cd->bram_cart_id++;
+				}
+			}
+			uint32_t read = fread(cd->bram_cart, 1, existing_size, f);
+			fclose(f);
+			if (read > 0) {
+				printf("Loaded BRAM cart from %s\n", bram_name);
+			}
+		}
+		free(bram_name);
 	}
 }
 
--- a/segacd.c	Sun Jan 08 14:42:24 2023 -0800
+++ b/segacd.c	Sun Jan 08 23:30:28 2023 -0800
@@ -440,6 +440,80 @@
 	return pcm_write8(address+1, vcontext, value);
 }
 
+static uint16_t cart_area_read16(uint32_t address, void *vcontext)
+{
+	m68k_context *m68k = vcontext;
+	genesis_context *gen = m68k->system;
+	segacd_context *cd = gen->expansion;
+	uint16_t open_bus = read_word(m68k->last_prefetch_address, (void **)m68k->mem_pointers, &m68k->options->gen, m68k);
+	if (cd->bram_cart_id > 7) {
+		// No cart, just return open bus
+		return open_bus;
+	}
+	address &= 0x3FFFFF;
+	if (address < 0x200000) {
+		if (address < 0x100000) {
+			return (open_bus & 0xFF00) | cd->bram_cart_id;
+		}
+		return open_bus;
+	} else {
+		address &= 0x1FFFFF;
+		uint32_t end = 0x2000 << (1 + cd->bram_cart_id);
+		if (address >= end) {
+			return open_bus;
+		}
+		return (open_bus & 0xFF00) | cd->bram_cart[address >> 1];
+	}
+}
+
+static uint8_t cart_area_read8(uint32_t address, void *vcontext)
+{
+	m68k_context *m68k = vcontext;
+	genesis_context *gen = m68k->system;
+	segacd_context *cd = gen->expansion;
+	if (!(address & 1) || cd->bram_cart_id > 7) {
+		//open bus
+		return read_byte(m68k->last_prefetch_address | (address & 1), (void **)m68k->mem_pointers, &m68k->options->gen, m68k);
+	}
+	address &= 0x3FFFFF;
+	if (address < 0x200000) {
+		if (address < 0x100000) {
+			return cd->bram_cart_id;
+		}
+		return read_byte(m68k->last_prefetch_address | 1, (void **)m68k->mem_pointers, &m68k->options->gen, m68k);
+	} else {
+		address &= 0x1FFFFF;
+		uint32_t end = 0x2000 << (1 + cd->bram_cart_id);
+		if (address >= end) {
+			return read_byte(m68k->last_prefetch_address | 1, (void **)m68k->mem_pointers, &m68k->options->gen, m68k);
+		}
+		return cd->bram_cart[address >> 1];
+	}
+}
+
+static void *cart_area_write8(uint32_t address, void *vcontext, uint8_t value)
+{
+	m68k_context *m68k = vcontext;
+	genesis_context *gen = m68k->system;
+	segacd_context *cd = gen->expansion;
+	if (!(address & 1) || cd->bram_cart_id > 7 || address < 0x600000) {
+		return vcontext;
+	}
+	address &= 0x1FFFFF;
+	uint32_t end = 0x2000 << (1 + cd->bram_cart_id);
+	if (address < end && cd->bram_cart_write_enabled) {
+		cd->bram_cart[address >> 1] = value;
+	}
+	if (address == 0x1FFFFF || (cd->bram_cart_id < 7 && address > 0x100000)) {
+		cd->bram_cart_write_enabled = value & 1;
+	}
+	return vcontext;
+}
+
+static void *cart_area_write16(uint32_t address, void *vcontext, uint16_t value)
+{
+	return cart_area_write8(address | 1, vcontext, value);
+}
 
 static void timers_run(segacd_context *cd, uint32_t cycle)
 {
@@ -1460,7 +1534,17 @@
 	cd->prog_ram = calloc(512*1024, 1);
 	cd->word_ram = calloc(256*1024, 1);
 	cd->bram = calloc(8*1024, 1);
-
+	char *bram_size_id = tern_find_path_default(config, "system\0bram_cart_size_id\0", (tern_val){.ptrval = "4"}, TVAL_PTR).ptrval;
+	cd->bram_cart_id = 0xFF;
+	cd->bram_cart = NULL;
+	if (strcmp(bram_size_id, "none")) {
+		char *end;
+		long id = strtol(bram_size_id, &end, 10);
+		if (end != bram_size_id && id < 8) {
+			cd->bram_cart_id = id;
+			cd->bram_cart = calloc(0x2000 << id, 1);
+		}
+	}
 
 	sub_cpu_map[0].buffer = sub_cpu_map[1].buffer = cd->prog_ram;
 	sub_cpu_map[4].buffer = cd->bram;
@@ -1538,6 +1622,7 @@
 		save_int8(buf, cd->main_swap_request);
 		save_int8(buf, cd->bank_toggle);
 		save_int8(buf, cd->sub_paused_wordram);
+		save_int8(buf, cd->bram_cart_write_enabled);
 		end_section(buf);
 
 		start_section(buf, SECTION_CDD_MCU);
@@ -1594,6 +1679,7 @@
 	cd->main_swap_request = load_int8(buf);
 	cd->bank_toggle = load_int8(buf);
 	cd->sub_paused_wordram = load_int8(buf);
+	cd->bram_cart_write_enabled = load_int8(buf);
 
 	if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) {
 		//1M mode
@@ -1645,11 +1731,16 @@
 			.read_16 = unmapped_word_read16, .write_16 = unmapped_word_write16, .read_8 = unmapped_word_read8, .write_8 = unmapped_word_write8},
 		{0x220000, 0x240000, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 2,
 			.read_16 = cell_image_read16, .write_16 = cell_image_write16, .read_8 = cell_image_read8, .write_8 = cell_image_write8},
-		{0xA12000, 0xA13000, 0xFFFFFF, .read_16 = main_gate_read16, .write_16 = main_gate_write16, .read_8 = main_gate_read8, .write_8 = main_gate_write8}
+		{0xA12000, 0xA13000, 0xFFFFFF, .read_16 = main_gate_read16, .write_16 = main_gate_write16, .read_8 = main_gate_read8, .write_8 = main_gate_write8},
+		{0x400000, 0x800000, 0xFFFFFF, .read_16 = cart_area_read16, .write_16 = cart_area_write16, .read_8 = cart_area_read8, .write_8 = cart_area_write8}
 	};
-	for (int i = 0; i < sizeof(main_cpu_map) / sizeof(*main_cpu_map); i++)
+	*num_chunks = sizeof(main_cpu_map) / sizeof(*main_cpu_map);
+	if (cart_boot) {
+		*num_chunks--;
+	}
+	for (int i = 0; i < *num_chunks; i++)
 	{
-		if (main_cpu_map[i].start < 0x800000) {
+		if (main_cpu_map[i].start < 0x400000) {
 			if (cart_boot) {
 				main_cpu_map[i].start  |= 0x400000;
 				main_cpu_map[i].end  |= 0x400000;
@@ -1659,13 +1750,11 @@
 			}
 		}
 	}
-	//TODO: support BRAM cart
 	main_cpu_map[0].buffer = cd->rom_mut;
 	main_cpu_map[2].buffer = cd->rom;
 	main_cpu_map[1].buffer = cd->prog_ram;
 	main_cpu_map[3].buffer = cd->word_ram;
 	main_cpu_map[4].buffer = cd->word_ram + 0x10000;
-	*num_chunks = sizeof(main_cpu_map) / sizeof(*main_cpu_map);
 	return main_cpu_map;
 }
 
--- a/segacd.h	Sun Jan 08 14:42:24 2023 -0800
+++ b/segacd.h	Sun Jan 08 23:30:28 2023 -0800
@@ -16,6 +16,7 @@
 	uint16_t        *prog_ram;
 	uint16_t        *word_ram;
 	uint8_t         *bram;
+	uint8_t         *bram_cart;
 	uint32_t        stopwatch_cycle;
 	uint32_t        int2_cycle;
 	uint32_t        graphics_int_cycle;
@@ -47,6 +48,8 @@
 	uint8_t         main_swap_request;
 	uint8_t         bank_toggle;
 	uint8_t         sub_paused_wordram;
+	uint8_t         bram_cart_write_enabled;
+	uint8_t         bram_cart_id;
 	rf5c164         pcm;
 	lc8951          cdc;
 	cdd_mcu         cdd;