summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--arena.c81
-rw-r--r--arena.h18
-rw-r--r--blastem.c117
-rw-r--r--blastem.h5
-rw-r--r--io.c6
-rw-r--r--m68k_core.c10
-rw-r--r--m68k_core.h3
-rw-r--r--m68k_core_x86.c2
-rw-r--r--mem.c9
-rw-r--r--util.c6
11 files changed, 207 insertions, 52 deletions
diff --git a/Makefile b/Makefile
index aad5962..fd7f004 100644
--- a/Makefile
+++ b/Makefile
@@ -91,7 +91,7 @@ ifndef CPU
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
diff --git a/arena.c b/arena.c
new file mode 100644
index 0000000..6bc50e0
--- /dev/null
+++ b/arena.c
@@ -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];
+}
diff --git a/arena.h b/arena.h
new file mode 100644
index 0000000..26a9555
--- /dev/null
+++ b/arena.h
@@ -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_
diff --git a/blastem.c b/blastem.c
index 2520ef9..354197f 100644
--- a/blastem.c
+++ b/blastem.c
@@ -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 @@ void set_speed_percent(genesis_context * context, uint32_t percent)
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 @@ genesis_context *alloc_init_genesis(rom_info *rom, int fps, uint32_t ym_opts)
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 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
}
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);
- }
- 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;
+ 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);
}
- if (i < 0) {
- save_filename[fname_size] = '.';
- strcpy(save_filename + fname_size + 1, ext);
+ 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;
}
- 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;
diff --git a/blastem.h b/blastem.h
index a4e2d1f..c5150a4 100644
--- a/blastem.h
+++ b/blastem.h
@@ -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 @@ typedef struct {
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 @@ extern tern_node * config;
#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);
diff --git a/io.c b/io.c
index 6199af0..0debbd2 100644
--- a/io.c
+++ b/io.c
@@ -293,7 +293,7 @@ void handle_binding_up(keybinding * binding)
}
break;
case UI_EXIT:
- exit(0);
+ genesis->m68k->should_return = 1;
}
break;
}
@@ -609,7 +609,7 @@ cleanup_sock:
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 @@ void set_keybindings(io_port *ports)
if (pads) {
for (int i = 0; i < 100 && i < render_num_joysticks(); i++)
{
-
+
if (i < 10) {
numstr[0] = i + '0';
numstr[1] = 0;
diff --git a/m68k_core.c b/m68k_core.c
index 02463c9..877327e 100644
--- a/m68k_core.c
+++ b/m68k_core.c
@@ -983,6 +983,16 @@ void start_68k_context(m68k_context * context, uint32_t address)
{
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);
}
diff --git a/m68k_core.h b/m68k_core.h
index 20cd6b1..07a1fb0 100644
--- a/m68k_core.h
+++ b/m68k_core.h
@@ -58,7 +58,7 @@ typedef struct {
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 @@ typedef struct {
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);
diff --git a/m68k_core_x86.c b/m68k_core_x86.c
index fca07b5..9a43f01 100644
--- a/m68k_core_x86.c
+++ b/m68k_core_x86.c
@@ -2515,8 +2515,8 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu
retn(code);
*do_ret = code->cur - (do_ret+1);
pop_r(code, opts->gen.scratch1);
- retn(code);
mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, resume_pc), SZ_PTR);
+ retn(code);
*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);
diff --git a/mem.c b/mem.c
index c9bb75a..b801bea 100644
--- a/mem.c
+++ b/mem.c
@@ -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 @@ void * alloc_code(size_t *size)
//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;
diff --git a/util.c b/util.c
index 5bb6191..697ba1b 100644
--- a/util.c
+++ b/util.c
@@ -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