@@ -1,190 +1,42 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Released under the terms of the MIT License. See LICENSE for details. */ | |||
#include <dirent.h> | |||
#include <errno.h> | |||
#include <stdbool.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/types.h> | |||
#include "src/errors.h" | |||
#include "src/config.h" | |||
#include "src/logging.h" | |||
#include "src/rom.h" | |||
#include "src/version.h" | |||
#define ROMS_DIR "roms" | |||
/* Print command-line help/usage. */ | |||
static void print_help(const char *arg1) | |||
{ | |||
printf("%s [-h] [-v] [-f] [-s <n>] [<rom_path>] ...\n" | |||
"\n" | |||
"basic options:\n" | |||
" -h, --help show this help message and exit\n" | |||
" -v, --version show crater's version number and exit\n" | |||
" -f, --fullscreen enable fullscreen mode\n" | |||
" -s, --scale <n> scale the game screen by an integer factor\n" | |||
" (applies to windowed mode only)\n" | |||
" <rom_path> path to the rom file to execute; if not given, will look\n" | |||
" in the roms/ directory and prompt the user\n" | |||
"\n" | |||
"advanced options:\n" | |||
" -g, --debug display information about emulation state while running,\n" | |||
" including register and memory values; can also pause\n" | |||
" emulation, set breakpoints, and change state\n" | |||
" -a, --assemble <in> <out> convert z80 assembly source code into a\n" | |||
" binary file that can be run by crater\n" | |||
" -d, --disassemble <in> <out> convert a binary file into z80 assembly code\n", | |||
arg1); | |||
} | |||
/* Print crater's version. */ | |||
static void print_version() | |||
{ | |||
printf("crater %s\n", CRATER_VERSION); | |||
} | |||
/* Parse the command-line arguments for any special flags. */ | |||
static void parse_args(int argc, char *argv[]) | |||
{ | |||
char *arg; | |||
int i; | |||
for (i = 1; i < argc; i++) { | |||
arg = argv[i]; | |||
if (arg[0] != '-') | |||
continue; | |||
do | |||
arg++; | |||
while (arg[0] == '-'); | |||
if (!strcmp(arg, "h") || !strcmp(arg, "help")) { | |||
print_help(argv[0]); | |||
exit(0); | |||
} else if (!strcmp(arg, "v") || !strcmp(arg, "version")) { | |||
print_version(); | |||
exit(0); | |||
// f fullscreen | |||
// s scale | |||
// g debug | |||
// a assemble | |||
// d disassemble | |||
} else { | |||
FATAL("unknown argument: %s", argv[i]) | |||
} | |||
} | |||
} | |||
/* Return whether the given string ends with the given suffix. */ | |||
static bool ends_with(const char *input, const char *suffix) | |||
{ | |||
size_t ilen = strlen(input), slen = strlen(suffix); | |||
if (ilen < slen) | |||
return false; | |||
return strcmp(input + (ilen - slen), suffix) == 0; | |||
} | |||
/* Load all potential ROM files in roms/ into a data structure. */ | |||
static int get_rom_paths(char ***path_ptr) | |||
{ | |||
DIR *dirp; | |||
struct dirent *entry; | |||
char **paths = NULL, *path; | |||
int psize = 8, npaths = 0; | |||
dirp = opendir(ROMS_DIR); | |||
if (dirp) { | |||
paths = malloc(sizeof(char*) * psize); | |||
if (!paths) | |||
OUT_OF_MEMORY() | |||
while ((entry = readdir(dirp))) { | |||
path = entry->d_name; | |||
if (ends_with(path, ".gg") || ends_with(path, ".bin")) { | |||
if (npaths >= psize) { | |||
paths = realloc(paths, sizeof(char*) * (psize *= 2)); | |||
if (!paths) | |||
OUT_OF_MEMORY() | |||
} | |||
paths[npaths] = malloc(sizeof(char*) * | |||
(strlen(path) + strlen(ROMS_DIR) + 1)); | |||
if (!paths[npaths]) | |||
OUT_OF_MEMORY() | |||
strcpy(paths[npaths], ROMS_DIR "/"); | |||
strcat(paths[npaths], path); | |||
npaths++; | |||
} | |||
} | |||
closedir(dirp); | |||
} else { | |||
WARN_ERRNO("couldn't open 'roms/'") | |||
} | |||
*path_ptr = paths; | |||
return npaths; | |||
} | |||
/* Find all potential ROM files in the roms/ directory, then ask the user which | |||
one they want to run. */ | |||
static char* get_rom_path_from_user() | |||
{ | |||
char **paths, *path, *input = NULL; | |||
int npaths, i; | |||
long int index; | |||
size_t size = 0; | |||
ssize_t len; | |||
npaths = get_rom_paths(&paths); | |||
for (i = 0; i < npaths; i++) | |||
printf("[%2d] %s\n", i + 1, paths[i]); | |||
if (npaths) | |||
printf("Enter a ROM number from above, or the path to a ROM image: "); | |||
else | |||
printf("Enter the path to a ROM image: "); | |||
len = getline(&input, &size, stdin); | |||
if (!input) | |||
OUT_OF_MEMORY() | |||
if (len > 0 && input[len - 1] == '\n') | |||
input[len - 1] = '\0'; | |||
index = strtol(input, NULL, 10); | |||
if (index < 1 || index > npaths) | |||
path = input; | |||
else | |||
path = paths[index - 1]; | |||
for (i = 0; i < npaths; i++) { | |||
if (paths[i] != path) | |||
free(paths[i]); | |||
} | |||
if (paths) | |||
free(paths); | |||
return path; | |||
} | |||
/* | |||
Main function. | |||
*/ | |||
int main(int argc, char *argv[]) | |||
{ | |||
char *rom_path; | |||
rom_type *rom; | |||
Config *config; | |||
ROM *rom; | |||
int retval; | |||
retval = config_create(&config, argc, argv); | |||
if (retval != CONFIG_OK) | |||
return retval == CONFIG_EXIT_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; | |||
parse_args(argc, argv); | |||
printf("crater: a Sega Game Gear emulator\n\n"); | |||
rom_path = argc > 1 ? argv[1] : get_rom_path_from_user(); | |||
if (rom_path[0] == '\0') | |||
FATAL("no image given") | |||
if (!(rom = rom_open(rom_path))) { | |||
#ifdef DEBUG_MODE | |||
config_dump_args(config); | |||
#endif | |||
if (!(rom = rom_open(config->rom_path))) { | |||
if (errno == ENOMEM) | |||
OUT_OF_MEMORY() | |||
else | |||
FATAL_ERRNO("couldn't load ROM image '%s'", rom_path) | |||
FATAL_ERRNO("couldn't load ROM image '%s'", config->rom_path) | |||
} | |||
if (argc <= 1) | |||
free(rom_path); | |||
printf("Loaded ROM image: %s.\n", rom->name); | |||
// TODO: start from here | |||
rom_close(rom); | |||
return 0; | |||
config_destroy(config); | |||
return EXIT_SUCCESS; | |||
} |
@@ -0,0 +1,340 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Released under the terms of the MIT License. See LICENSE for details. */ | |||
#include <dirent.h> | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/types.h> | |||
#include "config.h" | |||
#include "logging.h" | |||
#include "version.h" | |||
#define ROMS_DIR "roms" | |||
/* | |||
Print command-line help/usage. | |||
*/ | |||
static void print_help(const char *arg1) | |||
{ | |||
printf("%s [-h] [-v] [-f] [-s <n>] [<rom_path>] ...\n" | |||
"\n" | |||
"basic options:\n" | |||
" -h, --help show this help message and exit\n" | |||
" -v, --version show crater's version number and exit\n" | |||
" -f, --fullscreen enable fullscreen mode\n" | |||
" -s, --scale <n> scale the game screen by an integer factor\n" | |||
" (applies to windowed mode only)\n" | |||
" <rom_path> path to the rom file to execute; if not given, will look\n" | |||
" in the roms/ directory and prompt the user\n" | |||
"\n" | |||
"advanced options:\n" | |||
" -g, --debug display information about emulation state while running,\n" | |||
" including register and memory values; can also pause\n" | |||
" emulation, set breakpoints, and change state\n" | |||
" -a, --assemble <in> <out> convert z80 assembly source code into a\n" | |||
" binary file that can be run by crater\n" | |||
" -d, --disassemble <in> <out> convert a binary file into z80 assembly code\n", | |||
arg1); | |||
} | |||
/* | |||
Print crater's version. | |||
*/ | |||
static void print_version() | |||
{ | |||
printf("crater %s\n", CRATER_VERSION); | |||
} | |||
/* | |||
Return whether the given string ends with the given suffix. | |||
*/ | |||
static bool ends_with(const char *input, const char *suffix) | |||
{ | |||
size_t ilen = strlen(input), slen = strlen(suffix); | |||
if (ilen < slen) | |||
return false; | |||
return strcmp(input + (ilen - slen), suffix) == 0; | |||
} | |||
/* | |||
Load all potential ROM files in roms/ into a data structure. | |||
*/ | |||
static int get_rom_paths(char ***path_ptr) | |||
{ | |||
DIR *dirp; | |||
struct dirent *entry; | |||
char **paths = NULL, *path; | |||
int psize = 8, npaths = 0; | |||
dirp = opendir(ROMS_DIR); | |||
if (dirp) { | |||
paths = malloc(sizeof(char*) * psize); | |||
if (!paths) | |||
OUT_OF_MEMORY() | |||
while ((entry = readdir(dirp))) { | |||
path = entry->d_name; | |||
if (ends_with(path, ".gg") || ends_with(path, ".bin")) { | |||
if (npaths >= psize) { | |||
paths = realloc(paths, sizeof(char*) * (psize *= 2)); | |||
if (!paths) | |||
OUT_OF_MEMORY() | |||
} | |||
paths[npaths] = malloc(sizeof(char*) * | |||
(strlen(path) + strlen(ROMS_DIR) + 1)); | |||
if (!paths[npaths]) | |||
OUT_OF_MEMORY() | |||
strcpy(paths[npaths], ROMS_DIR "/"); | |||
strcat(paths[npaths], path); | |||
npaths++; | |||
} | |||
} | |||
closedir(dirp); | |||
} else { | |||
WARN_ERRNO("couldn't open 'roms/'") | |||
} | |||
*path_ptr = paths; | |||
return npaths; | |||
} | |||
/* | |||
Find all potential ROM files in the roms/ directory, then ask the user | |||
which one they want to run. | |||
*/ | |||
static char* get_rom_path_from_user() | |||
{ | |||
char **paths, *path, *input = NULL; | |||
int npaths, i; | |||
long int index; | |||
size_t size = 0; | |||
ssize_t len; | |||
npaths = get_rom_paths(&paths); | |||
for (i = 0; i < npaths; i++) | |||
printf("[%2d] %s\n", i + 1, paths[i]); | |||
if (npaths) | |||
printf("Enter a ROM number from above, or the path to a ROM image: "); | |||
else | |||
printf("Enter the path to a ROM image: "); | |||
len = getline(&input, &size, stdin); | |||
if (!input) | |||
OUT_OF_MEMORY() | |||
if (len > 0 && input[len - 1] == '\n') | |||
input[len - 1] = '\0'; | |||
index = strtol(input, NULL, 10); | |||
if (index < 1 || index > npaths) | |||
path = input; | |||
else | |||
path = paths[index - 1]; | |||
for (i = 0; i < npaths; i++) { | |||
if (paths[i] != path) | |||
free(paths[i]); | |||
} | |||
if (paths) | |||
free(paths); | |||
return path; | |||
} | |||
/* | |||
Parse the command-line arguments for any special flags. | |||
*/ | |||
static int parse_args(Config *config, int argc, char *argv[]) | |||
{ | |||
char *arg, *path; | |||
int i, paths_read = 0; | |||
for (i = 1; i < argc; i++) { | |||
arg = argv[i]; | |||
if (arg[0] != '-') { | |||
// Parsing a path or other variable: | |||
if (paths_read >= 2) { | |||
ERROR("too many arguments given - emulator mode accepts one " | |||
"ROM file,\nand assembler mode accepts one input file " | |||
"and one output file") | |||
return CONFIG_EXIT_FAILURE; | |||
} | |||
path = malloc(sizeof(char) * (strlen(arg) + 1)); | |||
strcpy(path, arg); | |||
if (paths_read == 1) { | |||
/* If this is the second path given, it can only be an output | |||
file for the assembler. If the assembler is not enabled by | |||
subsequent arguments, we'll throw an error. */ | |||
config->dst_path = path; | |||
} else { | |||
/* Otherwise, put the argument in the expected place. If we put | |||
it in rom_path and the assembler is enabled by later | |||
arguments, we'll move it. */ | |||
if (config->assemble || config->disassemble) | |||
config->src_path = path; | |||
else | |||
config->rom_path = path; | |||
} | |||
paths_read++; | |||
continue; | |||
} | |||
// Parsing an option: | |||
do | |||
arg++; | |||
while (arg[0] == '-'); | |||
if (!strcmp(arg, "h") || !strcmp(arg, "help")) { | |||
print_help(argv[0]); | |||
return CONFIG_EXIT_SUCCESS; | |||
} else if (!strcmp(arg, "v") || !strcmp(arg, "version")) { | |||
print_version(); | |||
return CONFIG_EXIT_SUCCESS; | |||
} else if (!strcmp(arg, "f") || !strcmp(arg, "fullscreen")) { | |||
config->fullscreen = true; | |||
} else if (!strcmp(arg, "s") || !strcmp(arg, "scale")) { | |||
if (i++ >= argc) { | |||
ERROR("the scale option requires an argument") | |||
return CONFIG_EXIT_FAILURE; | |||
} | |||
arg = argv[i]; | |||
long scale = strtol(arg, NULL, 10); | |||
if (scale <= 0 || scale > SCALE_MAX) { | |||
ERROR("scale factor of %s is not an integer or is out of range", arg) | |||
return CONFIG_EXIT_FAILURE; | |||
} | |||
} else if (!strcmp(arg, "g") || !strcmp(arg, "debug")) { | |||
config->debug = true; | |||
} else if (!strcmp(arg, "a") || !strcmp(arg, "assemble")) { | |||
if (paths_read >= 1) { | |||
config->src_path = config->rom_path; | |||
config->rom_path = NULL; | |||
} | |||
config->assemble = true; | |||
} else if (!strcmp(arg, "d") || !strcmp(arg, "disassemble")) { | |||
if (paths_read >= 1) { | |||
config->src_path = config->rom_path; | |||
config->rom_path = NULL; | |||
} | |||
config->disassemble = true; | |||
} else { | |||
ERROR("unknown argument: %s", argv[i]) | |||
return CONFIG_EXIT_FAILURE; | |||
} | |||
} | |||
if (!config->assemble && !config->disassemble && paths_read >= 2) { | |||
ERROR("too many arguments given - emulator mode accepts one ROM file") | |||
return CONFIG_EXIT_FAILURE; | |||
} | |||
if (!config->assemble && !config->disassemble && paths_read == 0) { | |||
path = get_rom_path_from_user(); | |||
if (path[0] == '\0') { | |||
ERROR("no ROM image given") | |||
return CONFIG_EXIT_FAILURE; | |||
} | |||
config->rom_path = path; | |||
} | |||
return CONFIG_OK; | |||
} | |||
/* | |||
Ensure that the combination of arguments in a config object are valid. | |||
*/ | |||
bool sanity_check(Config* config) | |||
{ | |||
if (config->fullscreen && config->scale) { | |||
ERROR("cannot specify a scale in fullscreen mode") | |||
return false; | |||
} else if (config->assemble && config->disassemble) { | |||
ERROR("cannot assemble and disassemble at the same time") | |||
return false; | |||
} else if ((config->assemble || config->disassemble) && | |||
(config->debug || config->fullscreen || config->scale)) { | |||
ERROR("cannot specify emulator options in assembler mode") | |||
return false; | |||
} else if ((config->assemble || config->disassemble) && | |||
!(config->src_path && config->dst_path)) { | |||
ERROR("assembler mode requires both an input and an output file") | |||
return false; | |||
} | |||
return true; | |||
} | |||
/* | |||
Create a new config object and load default values into it. | |||
*/ | |||
int config_create(Config** config_ptr, int argc, char* argv[]) | |||
{ | |||
Config *config; | |||
int retval; | |||
if (!(config = malloc(sizeof(Config)))) { | |||
OUT_OF_MEMORY() | |||
return CONFIG_EXIT_FAILURE; | |||
} | |||
config->debug = false; | |||
config->assemble = false; | |||
config->disassemble = false; | |||
config->fullscreen = false; | |||
config->scale = 1; | |||
config->rom_path = NULL; | |||
config->src_path = NULL; | |||
config->dst_path = NULL; | |||
retval = parse_args(config, argc, argv); | |||
if (retval == CONFIG_OK && !sanity_check(config)) | |||
retval = CONFIG_EXIT_FAILURE; | |||
if (retval != CONFIG_OK) { | |||
config_destroy(config); | |||
return retval; | |||
} | |||
*config_ptr = config; | |||
return CONFIG_OK; | |||
} | |||
/* | |||
Destroy a config object previously created with config_create(). | |||
*/ | |||
void config_destroy(Config *config) | |||
{ | |||
if (config->rom_path) | |||
free(config->rom_path); | |||
if (config->src_path) | |||
free(config->src_path); | |||
if (config->dst_path) | |||
free(config->dst_path); | |||
free(config); | |||
} | |||
#ifdef DEBUG_MODE | |||
/* | |||
DEBUG FUNCTION: Print out all config arguments to stdout. | |||
*/ | |||
void config_dump_args(Config* config) | |||
{ | |||
DEBUG("Dumping arguments:") | |||
DEBUG("- fullscreen: %d", config->fullscreen) | |||
DEBUG("- scale: %d", config->scale) | |||
DEBUG("- debug: %d", config->debug) | |||
DEBUG("- assemble: %d", config->assemble) | |||
DEBUG("- disassemble: %d", config->disassemble) | |||
if (config->rom_path) | |||
DEBUG("- rom_path: %s", config->rom_path) | |||
else | |||
DEBUG("- rom_path: NULL") | |||
if (config->src_path) | |||
DEBUG("- src_path: %s", config->src_path) | |||
else | |||
DEBUG("- src_path: NULL") | |||
if (config->dst_path) | |||
DEBUG("- dst_path: %s", config->dst_path) | |||
else | |||
DEBUG("- dst_path: NULL") | |||
} | |||
#endif |
@@ -0,0 +1,38 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Released under the terms of the MIT License. See LICENSE for details. */ | |||
#pragma once | |||
#include <stdbool.h> | |||
#define CONFIG_OK 0 | |||
#define CONFIG_EXIT_SUCCESS 1 | |||
#define CONFIG_EXIT_FAILURE 2 | |||
/* | |||
We need some sort of maximum scale - with a native resolution of 160 x 144, | |||
a scale factor of 1024 will let us go up to 163,840 x 147,456 pixels. | |||
No one has a screen this large. | |||
*/ | |||
#define SCALE_MAX 1024 | |||
/* Structs */ | |||
typedef struct { | |||
bool debug; | |||
bool assemble; | |||
bool disassemble; | |||
bool fullscreen; | |||
unsigned scale; | |||
char *rom_path; | |||
char *src_path; | |||
char *dst_path; | |||
} Config; | |||
/* Functions */ | |||
int config_create(Config**, int, char*[]); | |||
void config_destroy(Config*); | |||
#ifdef DEBUG_MODE | |||
void config_dump_args(Config*); | |||
#endif |
@@ -1,27 +0,0 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Released under the terms of the MIT License. See LICENSE for details. */ | |||
#pragma once | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
/* Internal usage only */ | |||
#define LOG_MSG(level, extra, after, ...) { \ | |||
fprintf(stderr, level ": " __VA_ARGS__); \ | |||
extra; \ | |||
fprintf(stderr, ".\n"); \ | |||
after; \ | |||
} | |||
#define PRINT_ERRNO() fprintf(stderr, ": %s", strerror(errno)) | |||
/* Public error logging macros */ | |||
#define FATAL(...) LOG_MSG("Error", {}, exit(EXIT_FAILURE), __VA_ARGS__) | |||
#define FATAL_ERRNO(...) LOG_MSG("Error", PRINT_ERRNO(), exit(EXIT_FAILURE), __VA_ARGS__) | |||
#define WARN(...) LOG_MSG("Warning", {}, {}, __VA_ARGS__) | |||
#define WARN_ERRNO(...) LOG_MSG("Warning", PRINT_ERRNO(), {}, __VA_ARGS__) | |||
#define OUT_OF_MEMORY() FATAL("couldn't allocate enough memory") |
@@ -0,0 +1,35 @@ | |||
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Released under the terms of the MIT License. See LICENSE for details. */ | |||
#pragma once | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
/* Internal usage only */ | |||
#define LOG_MSG(level, extra, tail, after, ...) { \ | |||
fprintf(stderr, level ": " __VA_ARGS__); \ | |||
extra; \ | |||
fprintf(stderr, tail ? ".\n" : "\n"); \ | |||
after; \ | |||
} | |||
#define PRINT_ERRNO() fprintf(stderr, ": %s", strerror(errno)) | |||
/* Public logging macros */ | |||
#define FATAL(...) LOG_MSG("Error", {}, 1, exit(EXIT_FAILURE), __VA_ARGS__) | |||
#define FATAL_ERRNO(...) LOG_MSG("Error", PRINT_ERRNO(), 1, exit(EXIT_FAILURE), __VA_ARGS__) | |||
#define ERROR(...) LOG_MSG("Error", {}, 1, {}, __VA_ARGS__) | |||
#define ERROR_ERRNO(...) LOG_MSG("Error", PRINT_ERRNO(), 1, {}, __VA_ARGS__) | |||
#define WARN(...) LOG_MSG("Warning", {}, 1, {}, __VA_ARGS__) | |||
#define WARN_ERRNO(...) LOG_MSG("Warning", PRINT_ERRNO(), 1, {}, __VA_ARGS__) | |||
#ifdef DEBUG_MODE | |||
#define DEBUG(...) LOG_MSG("[DEBUG]", {}, 0, {}, __VA_ARGS__) | |||
#define DEBUG_ERRNO(...) LOG_MSG("[DEBUG]", PRINT_ERRNO(), 0, {}, __VA_ARGS__) | |||
#endif | |||
#define OUT_OF_MEMORY() FATAL("couldn't allocate enough memory") |
@@ -9,11 +9,13 @@ | |||
#include "rom.h" | |||
/* Create and return a ROM object located at the given path. Return NULL if | |||
there was an error; errno will be set appropriately. */ | |||
rom_type* rom_open(const char *path) | |||
/* | |||
Create and return a ROM object located at the given path. Return NULL if | |||
there was an error; errno will be set appropriately. | |||
*/ | |||
ROM* rom_open(const char *path) | |||
{ | |||
rom_type *rom; | |||
ROM *rom; | |||
FILE* fp; | |||
struct stat s; | |||
@@ -31,7 +33,7 @@ rom_type* rom_open(const char *path) | |||
return NULL; | |||
} | |||
if (!(rom = malloc(sizeof(rom_type)))) { | |||
if (!(rom = malloc(sizeof(ROM)))) { | |||
fclose(fp); | |||
return NULL; | |||
} | |||
@@ -44,8 +46,10 @@ rom_type* rom_open(const char *path) | |||
return rom; | |||
} | |||
/* Free a ROM object previously created with rom_open(). */ | |||
void rom_close(rom_type *rom) | |||
/* | |||
Free a ROM object previously created with rom_open(). | |||
*/ | |||
void rom_close(ROM *rom) | |||
{ | |||
free(rom); | |||
} |
@@ -8,9 +8,9 @@ | |||
typedef struct { | |||
char* name; | |||
char* data; | |||
} rom_type; | |||
} ROM; | |||
/* Functions */ | |||
rom_type* rom_open(const char*); | |||
void rom_close(rom_type*); | |||
ROM* rom_open(const char*); | |||
void rom_close(ROM*); |
@@ -10,4 +10,4 @@ | |||
typedef struct { | |||
int pc; | |||
} z80_type; | |||
} Z80; |