# HG changeset patch # User Michael Pavone # Date 1447470937 28800 # Node ID 9f149f0e98b7ab0f8228ea00d40e5692432f5a6f # Parent 75453bf2ffac968c701c268b35f36f7958cdecc4 It is now possible to switch back and forth between the menu ROM and the game diff -r 75453bf2ffac -r 9f149f0e98b7 Makefile --- 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 diff -r 75453bf2ffac -r 9f149f0e98b7 arena.c --- /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 +#include +#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 -r 75453bf2ffac -r 9f149f0e98b7 arena.h --- /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_ diff -r 75453bf2ffac -r 9f149f0e98b7 blastem.c --- 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 +#include +#include +#include + #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 -#include -#include -#include +#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; diff -r 75453bf2ffac -r 9f149f0e98b7 blastem.h --- 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); diff -r 75453bf2ffac -r 9f149f0e98b7 io.c --- 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; diff -r 75453bf2ffac -r 9f149f0e98b7 m68k_core.c --- 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); } diff -r 75453bf2ffac -r 9f149f0e98b7 m68k_core.h --- 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); diff -r 75453bf2ffac -r 9f149f0e98b7 m68k_core_x86.c --- 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); diff -r 75453bf2ffac -r 9f149f0e98b7 mem.c --- 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 @@ -12,6 +12,7 @@ #include #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; diff -r 75453bf2ffac -r 9f149f0e98b7 util.c --- 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