mirror of
https://github.com/libretro/blastem.git
synced 2026-11-07 10:15:58 -10:00
It is now possible to switch back and forth between the menu ROM and the game
This commit is contained in:
1 parent
3834192b16
commit
802454482c
11 files changed
+207
-52
No files matched your search
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
+10
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user