summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2015-07-26 13:25:31 -0700
committerMichael Pavone <pavone@retrodev.com>2015-07-26 13:25:31 -0700
commit3372e57c62e3ff5f93c5541ef5b969229d132463 (patch)
treedf1a91e13ebef01d2ad636bd940c7e514a6919ff
parent4755aa94deb0a8fb90bf74033d370e9370d69ca2 (diff)
parentbee8b42029900ca034675c54d98813a61ca4407a (diff)
Merge
-rw-r--r--Makefile14
-rw-r--r--blastem.c68
-rw-r--r--config.c8
-rw-r--r--debug.c18
-rw-r--r--gdb_remote.c16
-rw-r--r--gen.c4
-rw-r--r--gen_arm.c3
-rw-r--r--gen_x86.c58
-rw-r--r--m68k_core.c16
-rw-r--r--m68k_core_x86.c7
-rw-r--r--menu.s684
-rw-r--r--render.h4
-rwxr-xr-xrender_sdl.c28
-rw-r--r--romdb.c41
-rw-r--r--stateview.c7
-rw-r--r--termhelper.c44
-rw-r--r--terminal.c65
-rw-r--r--terminal.h9
-rw-r--r--terminal_win.c13
-rw-r--r--tern.c4
-rw-r--r--util.c88
-rw-r--r--util.h6
-rw-r--r--vgmplay.c4
-rw-r--r--z80_to_x86.c17
24 files changed, 362 insertions, 184 deletions
diff --git a/Makefile b/Makefile
index 5b4fd5e..efca97d 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ GLEW32S_LIB=glew32s.lib
endif
MEM:=mem_win.o
+TERMINAL:=terminal_win.o
BLASTEM:=blastem.exe
CC:=wine gcc.exe
CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"$(SDL2_PREFIX)/include/SDL2" -DGLEW_STATIC
@@ -20,6 +21,7 @@ CPU:=i686
else
MEM:=mem.o
+TERMINAL:=terminal.o
BLASTEM:=blastem
ifeq ($(OS),Darwin)
@@ -105,7 +107,7 @@ Z80OBJS=z80inst.o z80_to_x86.o
AUDIOOBJS=ym2612.o psg.o wave.o
CONFIGOBJS=config.o tern.o util.o
-MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS)
+MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS)
ifeq ($(CPU),x86_64)
CFLAGS+=-DX86_64 -m64
@@ -123,7 +125,13 @@ else
MAINOBJS+= $(Z80OBJS)
endif
-all : dis zdis stateview vgmplay $(BLASTEM)
+ifeq ($(OS),Windows)
+ALL=$(BLASTEM)
+else
+ALL= dis zdis stateview vgmplay blastem termhelper
+endif
+
+all : $(ALL)
$(BLASTEM) : $(MAINOBJS)
$(CC) -o $(BLASTEM) $(MAINOBJS) $(LDFLAGS)
@@ -190,4 +198,4 @@ vos_prog_info : vos_prog_info.o vos_program_module.o
vasmz80_mot -Fbin -spaces -o $@ $<
clean :
- rm -rf dis trans stateview test_x86 gen_fib *.o
+ rm -rf $(ALL) trans ztestrun ztestgen *.o
diff --git a/blastem.c b/blastem.c
index baa4343..29d6f05 100644
--- a/blastem.c
+++ b/blastem.c
@@ -91,8 +91,7 @@ int load_rom(char * filename)
return 0;
}
if (sizeof(header) != fread(header, 1, sizeof(header), f)) {
- fprintf(stderr, "Error reading from %s\n", filename);
- exit(1);
+ fatal_error("Error reading from %s\n", filename);
}
fseek(f, 0, SEEK_END);
long filesize = ftell(f);
@@ -106,16 +105,14 @@ int load_rom(char * filename)
}
if (i == 8) {
if (header[2]) {
- fprintf(stderr, "%s is a split SMD ROM which is not currently supported", filename);
- exit(1);
+ fatal_error("%s is a split SMD ROM which is not currently supported", filename);
}
return load_smd_rom(filesize, f);
}
}
cart = malloc(nearest_pow2(filesize));
if (filesize != fread(cart, 1, filesize, f)) {
- fprintf(stderr, "Error reading from %s\n", filename);
- exit(1);
+ fatal_error("Error reading from %s\n", filename);
}
fclose(f);
return filesize;
@@ -289,8 +286,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value)
{
if (vdp_port & 0x2700E0) {
- printf("machine freeze due to write to address %X\n", 0xC00000 | vdp_port);
- exit(1);
+ fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port);
}
vdp_port &= 0x1F;
//printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle);
@@ -339,8 +335,7 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_
adjust_int_cycle(context, v_context);
}
} else {
- printf("Illegal write to HV Counter port %X\n", vdp_port);
- exit(1);
+ fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
}
if (v_context->cycles != before_cycle) {
//printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle);
@@ -369,8 +364,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value)
genesis_context * gen = context->system;
vdp_port &= 0xFF;
if (vdp_port & 0xE0) {
- printf("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port);
- exit(1);
+ fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port);
}
if (vdp_port < 0x10) {
//These probably won't currently interact well with the 68K accessing the VDP
@@ -380,8 +374,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value)
} else if (vdp_port < 8) {
vdp_control_port_write(gen->vdp, value << 8 | value);
} else {
- printf("Illegal write to HV Counter port %X\n", vdp_port);
- exit(1);
+ fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
}
} else if (vdp_port < 0x18) {
sync_sound(gen, context->current_cycle);
@@ -395,8 +388,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value)
uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
{
if (vdp_port & 0x2700E0) {
- printf("machine freeze due to read from address %X\n", 0xC00000 | vdp_port);
- exit(1);
+ fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port);
}
vdp_port &= 0x1F;
uint16_t value;
@@ -413,8 +405,7 @@ uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
//printf("HV Counter: %X at cycle %d\n", value, v_context->cycles);
}
} else if (vdp_port < 0x18){
- printf("Illegal read from PSG port %X\n", vdp_port);
- exit(1);
+ fatal_error("Illegal read from PSG port %X\n", vdp_port);
} else {
value = vdp_test_port_read(v_context);
}
@@ -444,8 +435,7 @@ uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
{
z80_context * context = vcontext;
if (vdp_port & 0xE0) {
- printf("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port);
- exit(1);
+ fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port);
}
genesis_context * gen = context->system;
//VDP access goes over the 68K bus like a bank area access
@@ -467,8 +457,7 @@ uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
} else if (vdp_port < 8) {
ret = vdp_control_port_read(gen->vdp);
} else {
- printf("Illegal write to HV Counter port %X\n", vdp_port);
- exit(1);
+ fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
}
} else {
//TODO: Figure out the correct value today
@@ -507,8 +496,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value
gen->z80->mem_pointers[1] = NULL;
}
} else {
- printf("68K write to unhandled Z80 address %X\n", location);
- exit(1);
+ fatal_error("68K write to unhandled Z80 address %X\n", location);
}
}
} else {
@@ -847,8 +835,7 @@ void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char
if (statefile) {
uint32_t pc = load_gst(gen, statefile);
if (!pc) {
- fprintf(stderr, "Failed to load save state %s\n", statefile);
- exit(1);
+ fatal_error("Failed to load save state %s\n", statefile);
}
printf("Loaded %s\n", statefile);
if (debugger) {
@@ -907,10 +894,6 @@ const memmap_chunk z80_map[] = {
int main(int argc, char ** argv)
{
- if (argc < 2) {
- fputs("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n", stderr);
- return 1;
- }
set_exe_str(argv[0]);
config = load_config();
int width = -1;
@@ -931,8 +914,7 @@ int main(int argc, char ** argv)
case 'b':
i++;
if (i >= argc) {
- fputs("-b must be followed by a frame count\n", stderr);
- return 1;
+ fatal_error("-b must be followed by a frame count\n");
}
headless = 1;
exit_after = atoi(argv[i]);
@@ -954,7 +936,7 @@ int main(int argc, char ** argv)
address_log = fopen("address.log", "w");
break;
case 'v':
- printf("blastem %s\n", BLASTEM_VERSION);
+ info_message("blastem %s\n", BLASTEM_VERSION);
return 0;
break;
case 'n':
@@ -963,20 +945,17 @@ int main(int argc, char ** argv)
case 'r':
i++;
if (i >= argc) {
- fputs("-r must be followed by region (J, U or E)\n", stderr);
- return 1;
+ fatal_error("-r must be followed by region (J, U or E)\n");
}
force_version = translate_region_char(toupper(argv[i][0]));
if (!force_version) {
- fprintf(stderr, "'%c' is not a valid region character for the -r option\n", argv[i][0]);
- return 1;
+ fatal_error("'%c' is not a valid region character for the -r option\n", argv[i][0]);
}
break;
case 's':
i++;
if (i >= argc) {
- fputs("-s must be followed by a savestate filename\n", stderr);
- return 1;
+ fatal_error("-s must be followed by a savestate filename\n");
}
statefile = argv[i];
break;
@@ -984,7 +963,7 @@ int main(int argc, char ** argv)
ym_log = 1;
break;
case 'h':
- puts(
+ info_message(
"Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n"
"Options:\n"
" -h Print this help text\n"
@@ -1000,13 +979,11 @@ int main(int argc, char ** argv)
);
return 0;
default:
- fprintf(stderr, "Unrecognized switch %s\n", argv[i]);
- return 1;
+ fatal_error("Unrecognized switch %s\n", argv[i]);
}
} else if (!loaded) {
if (!(rom_size = load_rom(argv[i]))) {
- fprintf(stderr, "Failed to open %s for reading\n", argv[i]);
- return 1;
+ fatal_error("Failed to open %s for reading\n", argv[i]);
}
romfname = argv[i];
loaded = 1;
@@ -1017,8 +994,7 @@ int main(int argc, char ** argv)
}
}
if (!loaded) {
- fputs("You must specify a ROM filename!\n", stderr);
- return 1;
+ fatal_error("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n");
}
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]));
diff --git a/config.c b/config.c
index 16091b0..c434a43 100644
--- a/config.c
+++ b/config.c
@@ -59,8 +59,7 @@ tern_node * parse_config_int(char **state, int started, int *line)
if (started) {
return head;
}
- fprintf(stderr, "unexpected } on line %d\n", *line);
- exit(1);
+ fatal_error("unexpected } on line %d\n", *line);
}
char * end = curline + len - 1;
@@ -141,7 +140,8 @@ success:
return ret;
}
no_config:
- fputs("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n", stderr);
- exit(1);
+ fatal_error("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n");
+ //this will never get reached, but the compiler doesn't know that. Let's make it happy
+ return NULL;
}
diff --git a/debug.c b/debug.c
index 74e076b..5fedb73 100644
--- a/debug.c
+++ b/debug.c
@@ -7,6 +7,8 @@
#include <sys/select.h>
#endif
#include "render.h"
+#include "util.h"
+#include "terminal.h"
static bp_def * breakpoints = NULL;
static bp_def * zbreakpoints = NULL;
@@ -286,6 +288,7 @@ z80_context * zdebugger(z80_context * context, uint16_t address)
static uint16_t branch_t;
static uint16_t branch_f;
z80inst inst;
+ init_terminal();
//Check if this is a user set breakpoint, or just a temporary one
bp_def ** this_bp = find_breakpoint(&zbreakpoints, address);
if (*this_bp) {
@@ -298,15 +301,12 @@ z80_context * zdebugger(z80_context * context, uint16_t address)
pc = z80_ram + (address & 0x1FFF);
} else if (address >= 0x8000) {
if (context->bank_reg < (0x400000 >> 15)) {
- fprintf(stderr, "Entered Z80 debugger in banked memory address %X, which is not yet supported\n", address);
- exit(1);
+ fatal_error("Entered Z80 debugger in banked memory address %X, which is not yet supported\n", address);
} else {
- fprintf(stderr, "Entered Z80 debugger in banked memory address %X, but the bank is not pointed to a cartridge address\n", address);
- exit(1);
+ fatal_error("Entered Z80 debugger in banked memory address %X, but the bank is not pointed to a cartridge address\n", address);
}
} else {
- fprintf(stderr, "Entered Z80 debugger at address %X\n", address);
- exit(1);
+ fatal_error("Entered Z80 debugger at address %X\n", address);
}
for (disp_def * cur = zdisplays; cur; cur = cur->next) {
zdebugger_print(context, cur->format_char, cur->param);
@@ -475,6 +475,9 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
static uint32_t branch_t;
static uint32_t branch_f;
m68kinst inst;
+
+ init_terminal();
+
sync_components(context, 0);
//probably not necessary, but let's play it safe
address &= 0xFFFFFF;
@@ -504,8 +507,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
} else if(address > 0xE00000) {
pc = ram + (address & 0xFFFF)/2;
} else {
- fprintf(stderr, "Entered 68K debugger at address %X\n", address);
- exit(1);
+ fatal_error("Entered 68K debugger at address %X\n", address);
}
uint16_t * after_pc = m68k_decode(pc, &inst, address);
m68k_disasm(&inst, input_buf);
diff --git a/gdb_remote.c b/gdb_remote.c
index 764cf83..0ea20c0 100644
--- a/gdb_remote.c
+++ b/gdb_remote.c
@@ -6,6 +6,7 @@
#include "gdb_remote.h"
#include "68kinst.h"
#include "debug.h"
+#include "util.h"
#include <unistd.h>
#include <fcntl.h>
#include <stddef.h>
@@ -76,8 +77,7 @@ void gdb_calc_checksum(char * command, char *out)
void write_or_die(int fd, const void *buf, size_t count)
{
if (write(fd, buf, count) < count) {
- fputs("Error writing to stdout\n", stderr);
- exit(1);
+ fatal_error("Error writing to stdout\n");
}
}
@@ -186,8 +186,7 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command)
} else if(pc > 0xE00000) {
pc_ptr = ram + (pc & 0xFFFF)/2;
} else {
- fprintf(stderr, "Entered gdb remote debugger stub at address %X\n", pc);
- exit(1);
+ fatal_error("Entered gdb remote debugger stub at address %X\n", pc);
}
uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF);
uint32_t after = pc + (after_pc-pc_ptr)*2;
@@ -407,8 +406,7 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command)
} else if(pc > 0xE00000) {
pc_ptr = ram + (pc & 0xFFFF)/2;
} else {
- fprintf(stderr, "Entered gdb remote debugger stub at address %X\n", pc);
- exit(1);
+ fatal_error("Entered gdb remote debugger stub at address %X\n", pc);
}
uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF);
uint32_t after = pc + (after_pc-pc_ptr)*2;
@@ -452,8 +450,7 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command)
}
return;
not_impl:
- fprintf(stderr, "Command %s is not implemented, exiting...\n", command);
- exit(1);
+ fatal_error("Command %s is not implemented, exiting...\n", command);
}
m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc)
@@ -516,8 +513,7 @@ m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc)
*curbuf = 0;
//send acknowledgement
if (write(STDOUT_FILENO, "+", 1) < 1) {
- fputs("Error writing to stdout\n", stderr);
- exit(1);
+ fatal_error("Error writing to stdout\n");
}
gdb_run_command(context, pc, start);
curbuf += 2;
diff --git a/gen.c b/gen.c
index 8f1b5f5..52be6a0 100644
--- a/gen.c
+++ b/gen.c
@@ -2,14 +2,14 @@
#include <stdlib.h>
#include "gen.h"
#include "mem.h"
+#include "util.h"
void init_code_info(code_info *code)
{
size_t size = CODE_ALLOC_SIZE;
code->cur = alloc_code(&size);
if (!code->cur) {
- fputs("Failed to allocate memory for generated code\n", stderr);
- exit(1);
+ fatal_error("Failed to allocate memory for generated code\n");
}
code->last = code->cur + size/sizeof(code_word) - RESERVE_WORDS;
}
diff --git a/gen_arm.c b/gen_arm.c
index 1534ee2..33eccaf 100644
--- a/gen_arm.c
+++ b/gen_arm.c
@@ -76,8 +76,7 @@ void check_alloc_code(code_info *code)
size_t size = CODE_ALLOC_SIZE;
uint32_t *next_code = alloc_code(&size);
if (!next_code) {
- fputs("Failed to allocate memory for generated code\n", stderr);
- exit(1);
+ fatal_error("Failed to allocate memory for generated code\n");
}
if (next_code = code->last + RESERVE_WORDS) {
//new chunk is contiguous with the current one
diff --git a/gen_x86.c b/gen_x86.c
index 2bec3e8..3860236 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -5,6 +5,7 @@
*/
#include "gen_x86.h"
#include "mem.h"
+#include "util.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -187,8 +188,7 @@ void jmp_nocheck(code_info *code, code_ptr dest)
disp >>= 8;
*(out++) = disp;
} else {
- fprintf(stderr, "jmp: %p - %p = %lX\n", dest, out + 6, (long)disp);
- exit(1);
+ fatal_error("jmp: %p - %p = %l which is out of range of a 32-bit displacementX\n", dest, out + 6, (long)disp);
}
}
code->cur = out;
@@ -200,8 +200,7 @@ void check_alloc_code(code_info *code, uint32_t inst_size)
size_t size = CODE_ALLOC_SIZE;
code_ptr next_code = alloc_code(&size);
if (!next_code) {
- fputs("Failed to allocate memory for generated code\n", stderr);
- exit(1);
+ fatal_error("Failed to allocate memory for generated code\n");
}
if (next_code != code->last + RESERVE_WORDS) {
//new chunk is not contiguous with the current one
@@ -231,8 +230,7 @@ void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst,
#ifdef X86_64
*out = PRE_REX;
if (src >= AH && src <= BH || dst >= AH && dst <= BH) {
- fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
- exit(1);
+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
}
if (size == SZ_Q) {
*out |= REX_QUAD;
@@ -247,8 +245,7 @@ void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst,
}
out++;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, src: %s, dst: %s, size: %s\n", opcode, x86_reg_names[src], x86_reg_names[dst], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, src: %s, dst: %s, size: %s\n", opcode, x86_reg_names[src], x86_reg_names[dst], x86_sizes[size]);
#endif
}
if (size == SZ_B) {
@@ -284,8 +281,7 @@ void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t b
#ifdef X86_64
*out = PRE_REX;
if (reg >= AH && reg <= BH) {
- fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
- exit(1);
+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
}
if (size == SZ_Q) {
*out |= REX_QUAD;
@@ -300,8 +296,7 @@ void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t b
}
out++;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
#endif
}
if (size == SZ_B) {
@@ -349,8 +344,7 @@ void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t bas
#ifdef X86_64
*out = PRE_REX;
if (reg >= AH && reg <= BH) {
- fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
- exit(1);
+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
}
if (size == SZ_Q) {
*out |= REX_QUAD;
@@ -365,8 +359,7 @@ void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t bas
}
out++;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
#endif
}
if (size == SZ_B) {
@@ -405,8 +398,7 @@ void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t b
#ifdef X86_64
*out = PRE_REX;
if (reg >= AH && reg <= BH) {
- fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
- exit(1);
+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
}
if (size == SZ_Q) {
*out |= REX_QUAD;
@@ -425,8 +417,7 @@ void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t b
}
out++;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
#endif
}
if (size == SZ_B) {
@@ -461,8 +452,7 @@ void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint
#ifdef X86_64
*out = PRE_REX;
if (dst >= AH && dst <= BH) {
- fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
- exit(1);
+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
}
if (size == SZ_Q) {
*out |= REX_QUAD;
@@ -473,8 +463,7 @@ void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint
}
out++;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]);
#endif
}
if (size == SZ_B) {
@@ -509,8 +498,7 @@ void x86_rdisp_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst,
}
out++;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]);
#endif
}
if (size != SZ_B) {
@@ -549,8 +537,7 @@ void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, i
#ifdef X86_64
*out = PRE_REX | REX_QUAD;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, size: %s\n", al_opcode, x86_reg_names[dst], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, size: %s\n", al_opcode, x86_reg_names[dst], x86_sizes[size]);
#endif
}
}
@@ -568,8 +555,7 @@ void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, i
}
out++;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]);
#endif
}
if (dst >= AH && dst <= BH) {
@@ -620,8 +606,7 @@ void x86_irdisp(code_info *code, uint8_t opcode, uint8_t op_ex, int32_t val, uin
}
out++;
#else
- fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]);
- exit(1);
+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]);
#endif
}
if (size != SZ_B) {
@@ -1921,8 +1906,7 @@ void jcc(code_info *code, uint8_t cc, code_ptr dest)
disp >>= 8;
*(out++) = disp;
} else {
- fprintf(stderr, "jcc: %p - %p = %lX\n", dest, out + 6, (long)disp);
- exit(1);
+ fatal_error("jcc: %p - %p = %lX which is out of range for a 32-bit displacement\n", dest, out + 6, (long)disp);
}
}
code->cur = out;
@@ -1948,8 +1932,7 @@ void jmp(code_info *code, code_ptr dest)
disp >>= 8;
*(out++) = disp;
} else {
- fprintf(stderr, "jmp: %p - %p = %lX\n", dest, out + 6, (long)disp);
- exit(1);
+ fatal_error("jmp: %p - %p = %lX which is out of range for a 32-bit displacement\n", dest, out + 6, (long)disp);
}
}
code->cur = out;
@@ -1997,8 +1980,7 @@ void call(code_info *code, code_ptr fun)
*(out++) = disp;
} else {
//TODO: Implement far call???
- fprintf(stderr, "%p - %p = %lX\n", fun, out + 5, (long)disp);
- exit(1);
+ fatal_error("call: %p - %p = %lX which is out of range for a 32-bit displacement\n", fun, out + 5, (long)disp);
}
code->cur = out;
}
diff --git a/m68k_core.c b/m68k_core.c
index 6b48080..e087f2f 100644
--- a/m68k_core.c
+++ b/m68k_core.c
@@ -8,6 +8,7 @@
#include "68kinst.h"
#include "backend.h"
#include "gen.h"
+#include "util.h"
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
@@ -174,8 +175,7 @@ void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst)
break;
default:
m68k_disasm(inst, disasm_buf);
- printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
- exit(1);
+ fatal_error("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
}
if (inst->op == M68K_PEA) {
subi_areg(opts, 4, 7);
@@ -283,8 +283,7 @@ void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst)
break;
default:
m68k_disasm(inst, disasm_buf);
- printf("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp");
- exit(1);
+ fatal_error("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp");
}
}
@@ -410,8 +409,7 @@ void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
break;
default:
m68k_disasm(inst, disasm_buf);
- printf("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
- exit(1);
+ fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
}
if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
reg = 15;
@@ -481,8 +479,7 @@ void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
break;
default:
m68k_disasm(inst, disasm_buf);
- printf("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
- exit(1);
+ fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
}
cycles(&opts->gen, early_cycles);
for(reg = 0; reg < 16; reg ++) {
@@ -830,8 +827,7 @@ void translate_m68k(m68k_options * opts, m68kinst * inst)
translate_m68k_unary(opts, inst, info->impl.flag_mask, inst->dst.addr_mode != MODE_UNUSED ? &dst_op : &src_op);
} else {
m68k_disasm(inst, disasm_buf);
- printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op);
- exit(1);
+ fatal_error("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op);
}
}
diff --git a/m68k_core_x86.c b/m68k_core_x86.c
index 5429bfd..c0b527c 100644
--- a/m68k_core_x86.c
+++ b/m68k_core_x86.c
@@ -9,6 +9,7 @@
#include "68kinst.h"
#include "mem.h"
#include "backend.h"
+#include "util.h"
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
@@ -507,8 +508,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8
return;
default:
m68k_disasm(inst, disasm_buf);
- printf("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src");
- exit(1);
+ fatal_error("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src");
}
if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
if (ea->mode == MODE_REG_DIRECT) {
@@ -684,8 +684,7 @@ void translate_m68k_move(m68k_options * opts, m68kinst * inst)
break;
default:
m68k_disasm(inst, disasm_buf);
- printf("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
- exit(1);
+ fatal_error("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
}
if (inst->dst.addr_mode != MODE_AREG) {
diff --git a/menu.s68 b/menu.s68
index 65dd1d2..f603ebf 100644
--- a/menu.s68
+++ b/menu.s68
@@ -196,7 +196,7 @@ print_string:
move.w d1, (a0)
addq #1, d2
move.l d2, d1
- ;add.w d1, d1
+ ;switch to other plane
and.w #$FFFE, d1
swap d1
eor.l #$20000000, d3
@@ -205,7 +205,9 @@ print_string:
bra .loop
.newline
moveq #0, d2
+ ;switch back to plane A
and.l #$DFFFFFFF, d3
+ ;skip to next row
add.l #$00800000, d3
move.l d3, (a1)
bra .loop
diff --git a/render.h b/render.h
index 9445448..cdae018 100644
--- a/render.h
+++ b/render.h
@@ -50,7 +50,9 @@ int render_joystick_num_buttons(int joystick);
int render_joystick_num_hats(int joystick);
int render_num_joysticks();
void process_events();
-
+void render_errorbox(char *title, char *message);
+void render_warnbox(char *title, char *message);
+void render_infobox(char *title, char *message);
#endif //RENDER_H_
diff --git a/render_sdl.c b/render_sdl.c
index b20808e..8a4b20d 100755
--- a/render_sdl.c
+++ b/render_sdl.c
@@ -220,15 +220,14 @@ static void render_quit()
#ifdef DISABLE_OPENGL
SDL_DestroyTexture(main_texture);
#endif
- SDL_Quit();
}
void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen)
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) {
- fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
- exit(1);
+ fatal_error("Unable to init SDL: %s\n", SDL_GetError());
}
+ atexit(SDL_Quit);
printf("width: %d, height: %d\n", width, height);
uint32_t flags = 0;
@@ -255,15 +254,12 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
main_window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
if (!main_window) {
- fprintf(stderr, "Unable to create SDL window: %s\n", SDL_GetError());
- SDL_Quit();
- exit(1);
+ fatal_error("Unable to create SDL window: %s\n", SDL_GetError());
}
main_context = SDL_GL_CreateContext(main_window);
GLenum res = glewInit();
if (res != GLEW_OK) {
fprintf(stderr, "Initialization of GLEW failed with code %d\n", res);
- SDL_DestroyWindow(main_window);
}
if (GLEW_VERSION_2_0) {
@@ -361,9 +357,7 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full
desired.userdata = NULL;
if (SDL_OpenAudio(&desired, &actual) < 0) {
- fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError());
- SDL_Quit();
- exit(1);
+ fatal_error("Unable to open SDL audio: %s\n", SDL_GetError());
}
buffer_samples = actual.samples;
sample_rate = actual.freq;
@@ -640,4 +634,18 @@ uint32_t render_sample_rate()
return sample_rate;
}
+void render_errorbox(char *title, char *message)
+{
+ SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, NULL);
+}
+
+void render_warnbox(char *title, char *message)
+{
+ SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, title, message, NULL);
+}
+
+void render_infobox(char *title, char *message)
+{
+ SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, title, message, NULL);
+}
diff --git a/romdb.c b/romdb.c
index 925fcd1..8ccd76b 100644
--- a/romdb.c
+++ b/romdb.c
@@ -317,8 +317,7 @@ void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value)
genesis_context *gen = ((m68k_context *)context)->system;
eeprom_map *map = find_eeprom_map(address, gen);
if (!map) {
- fprintf(stderr, "Could not find EEPROM map for address %X\n", address);
- exit(1);
+ fatal_error("Could not find EEPROM map for address %X\n", address);
}
if (map->scl_mask) {
set_scl(&gen->eeprom, (value & map->scl_mask) != 0);
@@ -334,8 +333,7 @@ void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value)
genesis_context *gen = ((m68k_context *)context)->system;
eeprom_map *map = find_eeprom_map(address, gen);
if (!map) {
- fprintf(stderr, "Could not find EEPROM map for address %X\n", address);
- exit(1);
+ fatal_error("Could not find EEPROM map for address %X\n", address);
}
uint16_t expanded, mask;
@@ -360,8 +358,7 @@ uint16_t read_eeprom_i2c_w(uint32_t address, void * context)
genesis_context *gen = ((m68k_context *)context)->system;
eeprom_map *map = find_eeprom_map(address, gen);
if (!map) {
- fprintf(stderr, "Could not find EEPROM map for address %X\n", address);
- exit(1);
+ fatal_error("Could not find EEPROM map for address %X\n", address);
}
uint16_t ret = 0;
if (map->sda_read_bit < 16) {
@@ -375,8 +372,7 @@ uint8_t read_eeprom_i2c_b(uint32_t address, void * context)
genesis_context *gen = ((m68k_context *)context)->system;
eeprom_map *map = find_eeprom_map(address, gen);
if (!map) {
- fprintf(stderr, "Could not find EEPROM map for address %X\n", address);
- exit(1);
+ fatal_error("Could not find EEPROM map for address %X\n", address);
}
uint8_t bit = address & 1 ? map->sda_read_bit : map->sda_read_bit - 8;
uint8_t ret = 0;
@@ -390,14 +386,13 @@ tern_node *load_rom_db()
{
char *exe_dir = get_exe_dir();
if (!exe_dir) {
- fputs("Failed to find executable path\n", stderr);
- exit(1);
+ fatal_error("Failed to find executable path\n");
}
char *path = alloc_concat(exe_dir, "/rom.db");
tern_node *db = parse_config_file(path);
free(path);
if (!db) {
- fputs("Failed to load ROM DB\n", stderr);
+ fatal_error("Failed to load ROM DB\n");
}
return db;
}
@@ -615,13 +610,11 @@ void process_sram_def(char *key, map_iter_state *state)
if (!state->info->save_size) {
char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval;
if (!size) {
- fprintf(stderr, "ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key);
- exit(1);
+ fatal_error("ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key);
}
state->info->save_size = atoi(size);
if (!state->info->save_size) {
- fprintf(stderr, "SRAM size %s is invalid\n", size);
- exit(1);
+ fatal_error("SRAM size %s is invalid\n", size);
}
state->info->save_mask = nearest_pow2(state->info->save_size)-1;
state->info->save_buffer = malloc(state->info->save_size);
@@ -642,13 +635,11 @@ void process_eeprom_def(char * key, map_iter_state *state)
if (!state->info->save_size) {
char * size = tern_find_path(state->root, "EEPROM\0size\0").ptrval;
if (!size) {
- fprintf(stderr, "ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key);
- exit(1);
+ fatal_error("ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key);
}
state->info->save_size = atoi(size);
if (!state->info->save_size) {
- fprintf(stderr, "EEPROM size %s is invalid\n", size);
- exit(1);
+ fatal_error("EEPROM size %s is invalid\n", size);
}
char *etype = tern_find_path(state->root, "EEPROM\0type\0").ptrval;
if (!etype) {
@@ -657,8 +648,7 @@ void process_eeprom_def(char * key, map_iter_state *state)
if (!strcmp(etype, "i2c")) {
state->info->save_type = SAVE_I2C;
} else {
- fprintf(stderr, "EEPROM type %s is invalid\n", etype);
- exit(1);
+ fatal_error("EEPROM type %s is invalid\n", etype);
}
state->info->save_buffer = malloc(state->info->save_size);
memset(state->info->save_buffer, 0xFF, state->info->save_size);
@@ -690,14 +680,12 @@ void map_iter_fun(char *key, tern_val val, void *data)
map_iter_state *state = data;
tern_node *node = tern_get_node(val);
if (!node) {
- fprintf(stderr, "ROM DB map entry %d with address %s is not a node\n", state->index, key);
- exit(1);
+ fatal_error("ROM DB map entry %d with address %s is not a node\n", state->index, key);
}
uint32_t start = strtol(key, NULL, 16);
uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16);
if (!end || end < start) {
- fprintf(stderr, "'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key);
- exit(1);
+ fatal_error("'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key);
}
char * dtype = tern_find_ptr_default(node, "device", "ROM");
uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 16);
@@ -769,8 +757,7 @@ void map_iter_fun(char *key, tern_val val, void *data)
map->write_16 = (write_16_fun)write_bank_reg_w;
map->write_8 = (write_8_fun)write_bank_reg_b;
} else {
- fprintf(stderr, "Invalid device type for ROM DB map entry %d with address %s\n", state->index, key);
- exit(1);
+ fatal_error("Invalid device type for ROM DB map entry %d with address %s\n", state->index, key);
}
state->index++;
}
diff --git a/stateview.c b/stateview.c
index 751d2af..3f860e7 100644
--- a/stateview.c
+++ b/stateview.c
@@ -7,6 +7,7 @@
#include <stdio.h>
#include "vdp.h"
#include "render.h"
+#include "util.h"
#include "blastem.h"
//not used, but referenced by the renderer since it handles input
@@ -61,13 +62,11 @@ int headless = 0;
int main(int argc, char ** argv)
{
if (argc < 2) {
- fprintf(stderr, "Usage: stateview FILENAME\n");
- exit(1);
+ fatal_error("Usage: stateview FILENAME\n");
}
FILE * state_file = fopen(argv[1], "rb");
if (!state_file) {
- fprintf(stderr, "Failed to open %s\n", argv[1]);
- exit(1);
+ fatal_error("Failed to open %s\n", argv[1]);
}
config = load_config(argv[0]);
int width = -1;
diff --git a/termhelper.c b/termhelper.c
new file mode 100644
index 0000000..a5cf17c
--- /dev/null
+++ b/termhelper.c
@@ -0,0 +1,44 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "terminal.h"
+
+char buf[4096];
+
+void copy_data(int to, int from)
+{
+ ssize_t bytes = read(from, buf, sizeof(buf));
+ while (bytes > 0)
+ {
+ ssize_t written = write(to, buf, bytes);
+ if (written == -1) {
+ exit(1);
+ }
+ bytes -= written;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ //these will block so order is important
+ int input_fd = open(INPUT_PATH, O_WRONLY);
+ int output_fd = open(OUTPUT_PATH, O_RDONLY);
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ for (;;)
+ {
+ FD_SET(STDIN_FILENO, &read_fds);
+ FD_SET(output_fd, &read_fds);
+ select(output_fd+1, &read_fds, NULL, NULL, NULL);
+
+ if (FD_ISSET(STDIN_FILENO, &read_fds)) {
+ copy_data(input_fd, STDIN_FILENO);
+ }
+ if (FD_ISSET(output_fd, &read_fds)) {
+ copy_data(STDOUT_FILENO, output_fd);
+ }
+ }
+ return 0;
+}
diff --git a/terminal.c b/terminal.c
new file mode 100644
index 0000000..0e952f2
--- /dev/null
+++ b/terminal.c
@@ -0,0 +1,65 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+#include "util.h"
+#include "terminal.h"
+
+pid_t child;
+
+void cleanup_terminal()
+{
+ kill(child, SIGKILL);
+ unlink(INPUT_PATH);
+ unlink(OUTPUT_PATH);
+}
+
+void init_terminal()
+{
+ static char init_done;
+ if (!init_done) {
+ if (!(isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))) {
+#ifndef __APPLE__
+ //check to see if x-terminal-emulator exists, just use xterm if it doesn't
+ char *term = system("which x-terminal-emulator > /dev/null") ? "xterm" : "x-terminal-emulator";
+#endif
+ //get rid of FIFO's if they already exist
+ unlink(INPUT_PATH);
+ unlink(OUTPUT_PATH);
+ //create FIFOs for talking to helper process in terminal app
+ mkfifo(INPUT_PATH, 0666);
+ mkfifo(OUTPUT_PATH, 0666);
+
+ //close existing file descriptors
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ child = fork();
+ if (child == -1) {
+ //error, oh well
+ warning("Failed to fork for terminal spawn");
+ } else if (!child) {
+ //child process, exec our terminal emulator
+#ifdef __APPLE__
+ execlp("open", "open", "./termhelper", NULL);
+#else
+ execlp(term, term, "-title", "BlastEm Debugger", "-e", "./termhelper", NULL);
+#endif
+ } else {
+ //connect to the FIFOs, these will block so order is important
+ open(INPUT_PATH, O_RDONLY);
+ open(OUTPUT_PATH, O_WRONLY);
+ atexit(cleanup_terminal);
+ if (-1 == dup(STDOUT_FILENO)) {
+ fatal_error("failed to dup STDOUT to STDERR after terminal fork");
+ }
+ }
+ }
+
+ init_done = 1;
+ }
+}
diff --git a/terminal.h b/terminal.h
new file mode 100644
index 0000000..08986c2
--- /dev/null
+++ b/terminal.h
@@ -0,0 +1,9 @@
+#ifndef TERMINAL_H_
+#define TERMINAL_H_
+
+void init_terminal();
+
+#define INPUT_PATH "/tmp/blastem_input"
+#define OUTPUT_PATH "/tmp/blastem_output"
+
+#endif //TERMINAL_H_
diff --git a/terminal_win.c b/terminal_win.c
new file mode 100644
index 0000000..120a086
--- /dev/null
+++ b/terminal_win.c
@@ -0,0 +1,13 @@
+#include <windows.h>
+#include <stdio.h>
+
+void init_terminal()
+{
+ static init_done;
+ if (!init_done) {
+ AllocConsole();
+ freopen("CONIN$", "r", stdin);
+ freopen("CONOUT$", "w", stdout);
+ freopen("CONOUT$", "w", stderr);
+ }
+}
diff --git a/tern.c b/tern.c
index e4f80f8..dda6497 100644
--- a/tern.c
+++ b/tern.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include "util.h"
tern_node * tern_insert(tern_node * head, char * key, tern_val value)
{
@@ -190,8 +191,7 @@ void tern_foreach_int(tern_node *head, iter_fun fun, void *data, char *keybuf, i
}
if (head->el) {
if (pos == MAX_ITER_KEY) {
- fputs("exceeded maximum key size", stderr);
- exit(1);
+ fatal_error("tern_foreach_int: exceeded maximum key size");
}
keybuf[pos] = head->el;
tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1);
diff --git a/util.c b/util.c
index 9722d3e..76b0e14 100644
--- a/util.c
+++ b/util.c
@@ -8,6 +8,9 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "blastem.h" //for headless global
+#include "render.h" //for render_errorbox
+
char * alloc_concat(char * first, char * second)
{
int flen = strlen(first);
@@ -86,6 +89,91 @@ void set_exe_str(char * str)
exe_str = str;
}
+void fatal_error(char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ if (!headless) {
+ //take a guess at the final size
+ size_t size = strlen(format) * 2;
+ char *buf = malloc(size);
+ size_t actual = vsnprintf(buf, size, format, args);
+ if (actual >= size) {
+ actual++;
+ free(buf);
+ buf = malloc(actual);
+ va_end(args);
+ va_start(args, format);
+ vsnprintf(buf, actual, format, args);
+ }
+ fputs(buf, stderr);
+ render_errorbox("Fatal Error", buf);
+ free(buf);
+ } else {
+ vfprintf(stderr, format, args);
+ }
+ va_end(args);
+ exit(1);
+}
+
+void warning(char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+#ifndef _WIN32
+ if (headless || (isatty(STDERR_FILENO) && isatty(STDIN_FILENO))) {
+ vfprintf(stderr, format, args);
+ } else {
+#endif
+ size_t size = strlen(format) * 2;
+ char *buf = malloc(size);
+ size_t actual = vsnprintf(buf, size, format, args);
+ if (actual >= size) {
+ actual++;
+ free(buf);
+ buf = malloc(actual);
+ va_end(args);
+ va_start(args, format);
+ vsnprintf(buf, actual, format, args);
+ }
+ fputs(buf, stderr);
+ render_infobox("BlastEm Info", buf);
+ free(buf);
+#ifndef _WIN32
+ }
+#endif
+ va_end(args);
+}
+
+void info_message(char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+#ifndef _WIN32
+ if (headless || (isatty(STDOUT_FILENO) && isatty(STDIN_FILENO))) {
+ vprintf(format, args);
+ } else {
+#endif
+ size_t size = strlen(format) * 2;
+ char *buf = malloc(size);
+ size_t actual = vsnprintf(buf, size, format, args);
+ if (actual >= size) {
+ actual++;
+ free(buf);
+ buf = malloc(actual);
+ va_end(args);
+ va_start(args, format);
+ vsnprintf(buf, actual, format, args);
+ }
+ fputs(buf, stdout);
+ render_infobox("BlastEm Info", buf);
+ free(buf);
+#ifndef _WIN32
+ }
+#endif
+ va_end(args);
+}
+
#ifdef _WIN32
#include <windows.h>
#include <shlobj.h>
diff --git a/util.h b/util.h
index 85b0c8f..ffa3385 100644
--- a/util.h
+++ b/util.h
@@ -25,5 +25,11 @@ char * get_exe_dir();
char * get_home_dir();
//Returns the contents of a symlink in a newly allocated string
char * readlink_alloc(char * path);
+//Prints an error message to stderr and to a message box if not in headless mode and then exits
+void fatal_error(char *format, ...);
+//Prints an information message to stdout and to a message box if not in headless mode and not attached to a console
+void info_message(char *format, ...);
+//Prints an information message to stderr and to a message box if not in headless mode and not attached to a console
+void warning(char *format, ...);
#endif //UTIL_H_
diff --git a/vgmplay.c b/vgmplay.c
index 879a399..f87c570 100644
--- a/vgmplay.c
+++ b/vgmplay.c
@@ -7,6 +7,7 @@
#include "ym2612.h"
#include "psg.h"
#include "config.h"
+#include "util.h"
#include <stdint.h>
#include <stdio.h>
@@ -282,8 +283,7 @@ int main(int argc, char ** argv)
wait(&y_context, &p_context, &current_cycle, wait_time);
}
} else {
- printf("unimplemented command: %X at offset %X\n", cmd, (unsigned int)(cur - data - 1));
- exit(1);
+ fatal_error("unimplemented command: %X at offset %X\n", cmd, (unsigned int)(cur - data - 1));
}
}
}
diff --git a/z80_to_x86.c b/z80_to_x86.c
index 23b19b8..7205d16 100644
--- a/z80_to_x86.c
+++ b/z80_to_x86.c
@@ -7,6 +7,7 @@
#include "z80_to_x86.h"
#include "gen_x86.h"
#include "mem.h"
+#include "util.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -256,8 +257,7 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t
ea->mode = MODE_UNUSED;
break;
default:
- fprintf(stderr, "Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F);
- exit(1);
+ fatal_error("Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F);
}
}
@@ -1939,11 +1939,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address,
default: {
char disbuf[80];
z80_disasm(inst, disbuf, address);
- fprintf(stderr, "unimplemented instruction: %s at %X\n", disbuf, address);
FILE * f = fopen("zram.bin", "wb");
fwrite(context->mem_pointers[0], 1, 8 * 1024, f);
fclose(f);
- exit(1);
+ fatal_error("unimplemented Z80 instruction: %s at %X\nZ80 RAM has been saved to zram.bin for debugging", disbuf, address);
}
}
}
@@ -1952,8 +1951,7 @@ uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context)
{
if (!context->interp_code[opcode]) {
if (opcode == 0xCB || (opcode >= 0xDD && (opcode & 0xF) == 0xD)) {
- fprintf(stderr, "Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc);
- exit(1);
+ fatal_error("Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc);
}
uint8_t codebuf[8];
memset(codebuf, 0, sizeof(codebuf));
@@ -1961,8 +1959,7 @@ uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context)
z80inst inst;
uint8_t * after = z80_decode(codebuf, &inst);
if (after - codebuf > 1) {
- fprintf(stderr, "Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc);
- exit(1);
+ fatal_error("Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc);
}
z80_options * opts = context->options;
@@ -2243,7 +2240,7 @@ void translate_z80_stream(z80_context * context, uint32_t address)
if (opts->gen.deferred) {
address = opts->gen.deferred->address;
dprintf("defferred address: %X\n", address);
- }
+ }
} while (opts->gen.deferred);
}
@@ -2749,6 +2746,6 @@ void zremove_breakpoint(z80_context * context, uint16_t address)
opts->gen.code.last = native + 16;
check_cycles_int(&opts->gen, address);
opts->gen.code = tmp_code;
-}
+ }
}