changeset 883:9f149f0e98b7

It is now possible to switch back and forth between the menu ROM and the game
author Michael Pavone <pavone@retrodev.com>
date Fri, 13 Nov 2015 19:15:37 -0800
parents 75453bf2ffac
children 252dfd29831d
files Makefile arena.c arena.h blastem.c blastem.h io.c m68k_core.c m68k_core.h m68k_core_x86.c mem.c util.c
diffstat 11 files changed, 208 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Nov 09 22:34:36 2015 -0800
+++ b/Makefile	Fri Nov 13 19:15:37 2015 -0800
@@ -91,7 +91,7 @@
 CPU:=$(shell uname -m)
 endif
 
-TRANSOBJS=gen.o backend.o $(MEM)
+TRANSOBJS=gen.o backend.o $(MEM) arena.o
 M68KOBJS=68kinst.o m68k_core.o
 ifeq ($(CPU),x86_64)
 M68KOBJS+= m68k_core_x86.o
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arena.c	Fri Nov 13 19:15:37 2015 -0800
@@ -0,0 +1,81 @@
+/*
+ Copyright 2015 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#include <stdlib.h>
+#include <stdint.h>
+#include "arena.h"
+
+struct arena {
+	void **used_blocks;
+	void **free_blocks;
+
+	size_t used_count;
+	size_t used_storage;
+	size_t free_count;
+	size_t free_storage;
+};
+
+static arena *current_arena;
+
+arena *get_current_arena()
+{
+	if (!current_arena) {
+		current_arena = calloc(1, sizeof(arena));
+	}
+	return current_arena;
+}
+
+arena *set_current_arena(arena *a)
+{
+	arena *tmp = current_arena;
+	current_arena = a;
+	return tmp;
+}
+
+arena *start_new_arena()
+{
+	arena *tmp = current_arena;
+	current_arena = NULL;
+	return tmp;
+}
+
+void track_block(void *block)
+{
+	arena *cur = get_current_arena();
+	if (cur->used_count == cur->used_storage) {
+		cur->used_storage *= 2;
+		cur->used_blocks = realloc(cur->used_blocks, cur->used_storage * sizeof(void *));
+	}
+	cur->used_blocks[cur->used_count++] = block;
+}
+
+void mark_all_free()
+{
+	arena *cur = get_current_arena();
+	if (!cur->free_blocks) {
+		cur->free_blocks = cur->used_blocks;
+		cur->free_storage = cur->used_storage;
+		cur->free_count = cur->used_count;
+		cur->used_count = cur->used_storage = 0;
+		cur->used_blocks = NULL;
+	} else {
+		if (cur->free_storage < cur->used_count + cur->free_count) {
+			cur->free_storage = cur->used_count + cur->free_count;
+			cur->free_blocks = realloc(cur->free_blocks, cur->free_storage * sizeof(void*));
+		}
+		for (; cur->used_count > 0; cur->used_count--)
+		{
+			cur->free_blocks[cur->free_count++] = cur->used_blocks[cur->used_count-1];
+		}
+	}
+}
+
+void *try_alloc_arena()
+{
+	if (!current_arena || !current_arena->free_count) {
+		return NULL;
+	}
+	return current_arena->free_blocks[--current_arena->free_count];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/arena.h	Fri Nov 13 19:15:37 2015 -0800
@@ -0,0 +1,18 @@
+/*
+ Copyright 2015 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#ifndef ARENA_H_
+#define ARENA_H_
+
+typedef struct arena arena;
+
+arena *get_current_arena();
+arena *set_current_arena(arena *a);
+arena *start_new_arena();
+void track_block(void *block);
+void mark_all_free();
+void *try_alloc_arena();
+
+#endif //ARENA_H_
--- a/blastem.c	Mon Nov 09 22:34:36 2015 -0800
+++ b/blastem.c	Fri Nov 13 19:15:37 2015 -0800
@@ -3,6 +3,11 @@
  This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
 #include "68kinst.h"
 #include "m68k_core.h"
 #include "z80_to_x86.h"
@@ -15,10 +20,7 @@
 #include "util.h"
 #include "romdb.h"
 #include "terminal.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
+#include "arena.h"
 
 #define BLASTEM_VERSION "0.3.X"
 
@@ -44,7 +46,7 @@
 #endif
 
 uint16_t *cart;
-uint16_t ram[RAM_WORDS];
+uint16_t *ram;
 uint8_t z80_ram[Z80_RAM_BYTES];
 
 int headless = 0;
@@ -784,17 +786,6 @@
 	psg_adjust_master_clock(context->psg, context->master_clock);
 }
 
-const memmap_chunk base_map[] = {
-		{0xE00000, 0x1000000, 0xFFFF,   0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram,
-		           NULL,          NULL,         NULL,            NULL},
-		{0xC00000, 0xE00000,  0x1FFFFF, 0, 0,                                  NULL,
-		           (read_16_fun)vdp_port_read,  (write_16_fun)vdp_port_write,
-		           (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
-		{0xA00000, 0xA12000,  0x1FFFF,  0, 0,                                  NULL,
-		           (read_16_fun)io_read_w,      (write_16_fun)io_write_w,
-		           (read_8_fun)io_read,         (write_8_fun)io_write}
-	};
-
 char * save_filename;
 genesis_context *genesis;
 genesis_context *menu_context;
@@ -850,6 +841,7 @@
 	gen->z80->mem_pointers[0] = z80_ram;
 	gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)cart;
 
+	gen->cart = cart;
 	gen->work_ram = ram;
 	gen->zram = z80_ram;
 	setup_io_devices(config, gen->ports);
@@ -1080,6 +1072,17 @@
 
 		loaded = 1;
 	}
+	ram = malloc(RAM_WORDS * sizeof(uint16_t));
+	memmap_chunk base_map[] = {
+		{0xE00000, 0x1000000, 0xFFFF,   0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram,
+		           NULL,          NULL,         NULL,            NULL},
+		{0xC00000, 0xE00000,  0x1FFFFF, 0, 0,                                  NULL,
+		           (read_16_fun)vdp_port_read,  (write_16_fun)vdp_port_write,
+		           (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
+		{0xA00000, 0xA12000,  0x1FFFF,  0, 0,                                  NULL,
+		           (read_16_fun)io_read_w,      (write_16_fun)io_write_w,
+		           (read_8_fun)io_read,         (write_8_fun)io_write}
+	};
 	tern_node *rom_db = load_rom_db();
 	rom_info info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
 	byteswap_rom(rom_size);
@@ -1127,33 +1130,67 @@
 	}
 
 	start_genesis(genesis, menu ? NULL : statefile, menu ? NULL : debuggerfun);
-	if (menu && menu_context->next_rom) {
-		//TODO: Allow returning to menu
-		if (!(rom_size = load_rom(menu_context->next_rom))) {
-			fatal_error("Failed to open %s for reading\n", menu_context->next_rom);
+	for(;;)
+	{
+		if (menu && menu_context->next_rom) {
+			if (!(rom_size = load_rom(menu_context->next_rom))) {
+				fatal_error("Failed to open %s for reading\n", menu_context->next_rom);
+			}
+			base_map[0].buffer = ram = malloc(RAM_WORDS * sizeof(uint16_t));
+			info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
+			byteswap_rom(rom_size);
+			set_region(&info, force_version);
+			update_title(info.name);
+			fname_size = strlen(romfname);
+			ext = info.save_type == SAVE_I2C ? "eeprom" : "sram";
+			save_filename = malloc(fname_size+strlen(ext) + 2);
+			memcpy(save_filename, romfname, fname_size);
+			for (i = fname_size-1; fname_size >= 0; --i) {
+				if (save_filename[i] == '.') {
+					strcpy(save_filename + i + 1, ext);
+					break;
+				}
+			}
+			if (i < 0) {
+				save_filename[fname_size] = '.';
+				strcpy(save_filename + fname_size + 1, ext);
+			}
+			if (!game_context) {
+				//start a new arena and save old one in suspended genesis context
+				genesis->arena = start_new_arena();
+				//allocate new genesis context
+				game_context = alloc_init_genesis(&info, fps, ym_log ? YM_OPT_WAVE_LOG : 0);
+			} else {
+				//TODO: hard reset of context with new ROM
+			}
+			free(menu_context->next_rom);
+			menu_context->next_rom = NULL;
+			menu = 0;
+			genesis = game_context;
+			genesis->m68k->options->address_log = address_log;
+			start_genesis(genesis, statefile, debuggerfun);
 		}
-		info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
-		byteswap_rom(rom_size);
-		set_region(&info, force_version);
-		update_title(info.name);
-		fname_size = strlen(romfname);
-		ext = info.save_type == SAVE_I2C ? "eeprom" : "sram";
-		save_filename = malloc(fname_size+strlen(ext) + 2);
-		memcpy(save_filename, romfname, fname_size);
-		for (i = fname_size-1; fname_size >= 0; --i) {
-			if (save_filename[i] == '.') {
-				strcpy(save_filename + i + 1, ext);
-				break;
-			}
+		else if (menu && game_context) {
+			puts("Switching back to game context");
+			genesis->arena = set_current_arena(game_context->arena);
+			genesis = game_context;
+			cart = genesis->cart;
+			ram = genesis->work_ram;
+			menu = 0;
+			set_keybindings(genesis->ports);
+			resume_68k(genesis->m68k);
+		} else if (!menu && menu_context) {
+			puts("Switching back to menu context");
+			genesis->arena = set_current_arena(menu_context->arena);
+			genesis = menu_context;
+			cart = genesis->cart;
+			ram = genesis->work_ram;
+			menu = 1;
+			set_keybindings(genesis->ports);
+			resume_68k(genesis->m68k);
+		} else {
+			break;
 		}
-		if (i < 0) {
-			save_filename[fname_size] = '.';
-			strcpy(save_filename + fname_size + 1, ext);
-		}
-		game_context = alloc_init_genesis(&info, fps, ym_log ? YM_OPT_WAVE_LOG : 0);
-		genesis->m68k->options->address_log = address_log;
-		genesis = game_context;
-		start_genesis(genesis, statefile, debuggerfun);
 	}
 
 	return 0;
--- a/blastem.h	Mon Nov 09 22:34:36 2015 -0800
+++ b/blastem.h	Fri Nov 13 19:15:37 2015 -0800
@@ -15,6 +15,7 @@
 #include "io.h"
 #include "config.h"
 #include "romdb.h"
+#include "arena.h"
 
 typedef struct {
 	m68k_context   *m68k;
@@ -22,9 +23,11 @@
 	vdp_context    *vdp;
 	ym2612_context *ym;
 	psg_context    *psg;
+	uint16_t       *cart;
 	uint16_t       *work_ram;
 	uint8_t        *zram;
 	void           *extra;
+	arena          *arena;
 	char           *next_rom;
 	uint8_t        *save_storage;
 	eeprom_map     *eeprom_map;
@@ -53,7 +56,7 @@
 #define Z80_RAM_BYTES 8 * 1024
 
 extern uint16_t *cart;
-extern uint16_t ram[RAM_WORDS];
+extern uint16_t *ram;
 extern uint8_t z80_ram[Z80_RAM_BYTES];
 
 uint16_t read_dma_value(uint32_t address);
--- a/io.c	Mon Nov 09 22:34:36 2015 -0800
+++ b/io.c	Fri Nov 13 19:15:37 2015 -0800
@@ -293,7 +293,7 @@
 			}
 			break;
 		case UI_EXIT:
-			exit(0);
+			genesis->m68k->should_return = 1;
 		}
 		break;
 	}
@@ -609,7 +609,7 @@
 				close(ports[i].device.stream.listen_fd);
 				ports[i].device_type = IO_NONE;
 			}
-		} else 
+		} else
 #endif
 		if (ports[i].device_type == IO_GAMEPAD3 || ports[i].device_type == IO_GAMEPAD6) {
 			printf("IO port %s connected to gamepad #%d with type '%s'\n", io_name(i), ports[i].device.pad.gamepad_num + 1, device_type_names[ports[i].device_type]);
@@ -672,7 +672,7 @@
 	if (pads) {
 		for (int i = 0; i < 100 && i < render_num_joysticks(); i++)
 		{
-		
+
 			if (i < 10) {
 				numstr[0] = i + '0';
 				numstr[1] = 0;
--- a/m68k_core.c	Mon Nov 09 22:34:36 2015 -0800
+++ b/m68k_core.c	Fri Nov 13 19:15:37 2015 -0800
@@ -983,6 +983,16 @@
 {
 	code_ptr addr = get_native_address_trans(context, address);
 	m68k_options * options = context->options;
+	context->should_return = 0;
+	options->start_context(addr, context);
+}
+
+void resume_68k(m68k_context *context)
+{
+	code_ptr addr = context->resume_pc;
+	context->resume_pc = NULL;
+	m68k_options * options = context->options;
+	context->should_return = 0;
 	options->start_context(addr, context);
 }
 
--- a/m68k_core.h	Mon Nov 09 22:34:36 2015 -0800
+++ b/m68k_core.h	Fri Nov 13 19:15:37 2015 -0800
@@ -58,7 +58,7 @@
 	uint32_t        int_cycle;
 	uint32_t        int_num;
 	uint16_t        *mem_pointers[NUM_MEM_AREAS];
-	void            *resume_pc;
+	code_ptr        resume_pc;
 	native_map_slot *native_code_map;
 	m68k_options    *options;
 	void            *system;
@@ -70,6 +70,7 @@
 void translate_m68k(m68k_options * opts, struct m68kinst * inst);
 void translate_m68k_stream(uint32_t address, m68k_context * context);
 void start_68k_context(m68k_context * context, uint32_t address);
+void resume_68k(m68k_context *context);
 void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider);
 m68k_context * init_68k_context(m68k_options * opts);
 void m68k_reset(m68k_context * context);
--- a/m68k_core_x86.c	Mon Nov 09 22:34:36 2015 -0800
+++ b/m68k_core_x86.c	Fri Nov 13 19:15:37 2015 -0800
@@ -2515,8 +2515,8 @@
 	retn(code);
 	*do_ret = code->cur - (do_ret+1);
 	pop_r(code, opts->gen.scratch1);
+	mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, resume_pc), SZ_PTR);
 	retn(code);
-	mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, resume_pc), SZ_PTR);
 	*do_int = code->cur - (do_int+1);
 	//implement 1 instruction latency
 	cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
--- a/mem.c	Mon Nov 09 22:34:36 2015 -0800
+++ b/mem.c	Fri Nov 13 19:15:37 2015 -0800
@@ -1,6 +1,6 @@
 /*
  Copyright 2013 Michael Pavone
- This file is part of BlastEm. 
+ This file is part of BlastEm.
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include <sys/mman.h>
@@ -12,6 +12,7 @@
 #include <stdio.h>
 
 #include "mem.h"
+#include "arena.h"
 #ifndef MAP_ANONYMOUS
 #define MAP_ANONYMOUS MAP_ANON
 #endif
@@ -25,8 +26,12 @@
 	//start at the 1GB mark to allow plenty of room for sbrk based malloc implementations
 	//while still keeping well within 32-bit displacement range for calling code compiled into the executable
 	static uint8_t *next = (uint8_t *)0x40000000;
+	uint8_t *ret = try_alloc_arena();
+	if (ret) {
+		return ret;
+	}
 	*size += PAGE_SIZE - (*size & (PAGE_SIZE - 1));
-	uint8_t *ret = mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
+	ret = mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
 	if (ret == MAP_FAILED) {
 		perror("alloc_code");
 		return NULL;
--- a/util.c	Mon Nov 09 22:34:36 2015 -0800
+++ b/util.c	Fri Nov 13 19:15:37 2015 -0800
@@ -23,9 +23,9 @@
 #define warning_puts(msg) fputs(stderr, msg);
 #define fatal_puts(msg) fputs(stderr, msg);
 
-#define info_printf(msg, args vprintf(msg, args)
-#define warning_printf(msg, args vfprintf(stderr, msg, args)
-#define fatal_printf(msg, args vfprintf(stderr, msg, args)
+#define info_printf(msg, args) vprintf(msg, args)
+#define warning_printf(msg, args) vfprintf(stderr, msg, args)
+#define fatal_printf(msg, args) vfprintf(stderr, msg, args)
 #endif
 
 #include "blastem.h" //for headless global