Browse Source

Refactor debug logging as distinct from dev build; add tracing.

master
Ben Kurtovic 8 years ago
parent
commit
a74c4ab405
16 changed files with 171 additions and 144 deletions
  1. +3
    -5
      README.md
  2. +9
    -9
      crater.c
  3. +10
    -7
      makefile
  4. +7
    -6
      src/assembler.c
  5. +1
    -1
      src/assembler/preprocessor.c
  6. +5
    -6
      src/assembler/state.c
  7. +1
    -3
      src/assembler/state.h
  8. +2
    -1
      src/assembler/tokenizer.c
  9. +13
    -15
      src/config.c
  10. +2
    -5
      src/config.h
  11. +5
    -7
      src/iomanager.c
  12. +28
    -20
      src/logging.h
  13. +25
    -14
      src/mmu.c
  14. +41
    -34
      src/rom.c
  15. +18
    -7
      src/z80.c
  16. +1
    -4
      src/z80.h

+ 3
- 5
README.md View File

@@ -28,8 +28,7 @@ Only OS X and Linux are tested. You'll need a modern compiler that supports C11
`brew install sdl2`; using apt, you can `apt-get install libsdl2-dev`. `brew install sdl2`; using apt, you can `apt-get install libsdl2-dev`.


Run `make` to create `./crater`. To build the development version with debug Run `make` to create `./crater`. To build the development version with debug
symbols and extra diagnostic info (they can exist simultaneously), run
`make DEBUG=1`, which creates `./crater-dev`.
symbols and no optimizations, run `make DEBUG=1`, which creates `./crater-dev`.


crater has a number of test cases. Run the entire suite with `make test`; crater has a number of test cases. Run the entire suite with `make test`;
individual components can be tested by doing `make test-{component}`, where individual components can be tested by doing `make test-{component}`, where
@@ -51,9 +50,8 @@ Add or symlink ROMs to `roms/` at your leisure. Note that they must end in
Add `--fullscreen` (`-f`) to enable fullscreen mode, or `--scale <n>` Add `--fullscreen` (`-f`) to enable fullscreen mode, or `--scale <n>`
(`-s <n>`) to scale the game screen by an integer factor. (`-s <n>`) to scale the game screen by an integer factor.


Add `--debug` (`-g`) to display detailed information about emulation state
while running, including register values and memory contents. You can also
pause emulation to set breakpoints and change state.
Add `--debug` (`-g`) to show logging information while running. Pass it twice
(`-g -g`) to show more detailed logs, including an emulator trace.


`./crater -h` gives (fairly basic) command-line usage, and `./crater -v` gives `./crater -h` gives (fairly basic) command-line usage, and `./crater -v` gives
the current version. the current version.


+ 9
- 9
crater.c View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <stdlib.h> #include <stdlib.h>
@@ -24,15 +24,15 @@ int main(int argc, char *argv[])
if (retval != CONFIG_OK) if (retval != CONFIG_OK)
return retval == CONFIG_EXIT_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; return retval == CONFIG_EXIT_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;


#ifdef DEBUG_MODE
config_dump_args(config);
#endif
SET_LOG_LEVEL(config->debug)
if (DEBUG_LEVEL)
config_dump_args(config);


if (config->assemble || config->disassemble) {
if (config->assemble)
retval = assemble_file(config->src_path, config->dst_path);
else
retval = disassemble_file(config->src_path, config->dst_path);
if (config->assemble) {
retval = assemble_file(config->src_path, config->dst_path);
retval = retval ? EXIT_SUCCESS : EXIT_FAILURE;
} else if (config->disassemble) {
retval = disassemble_file(config->src_path, config->dst_path);
retval = retval ? EXIT_SUCCESS : EXIT_FAILURE; retval = retval ? EXIT_SUCCESS : EXIT_FAILURE;
} else { } else {
ROM *rom; ROM *rom;


+ 10
- 7
makefile View File

@@ -8,17 +8,16 @@ DEVEXT = -dev
TESTS = cpu vdp psg asm dis integrate TESTS = cpu vdp psg asm dis integrate


CC = clang CC = clang
FLAGS = -O2 -Wall -Wextra -pedantic -std=c11
FLAGS = -Wall -Wextra -pedantic -std=c11
CFLAGS = $(shell sdl2-config --cflags) CFLAGS = $(shell sdl2-config --cflags)
LIBS = $(shell sdl2-config --libs) LIBS = $(shell sdl2-config --libs)
DFLAGS = -g -DDEBUG_MODE
DFLAGS = -g
RFLAGS = -O2

MKDIR = mkdir -p MKDIR = mkdir -p
RM = rm -rf RM = rm -rf
ASM_UP = scripts/update_asm_instructions.py ASM_UP = scripts/update_asm_instructions.py


MODE = release
BNRY = $(PROGRAM)
FLGS = $(FLAGS)
SDRS = $(shell find $(SOURCES) -type d | xargs echo) SDRS = $(shell find $(SOURCES) -type d | xargs echo)
SRCS = $(filter-out %.inc.c,$(foreach d,. $(SDRS),$(wildcard $(addprefix $(d)/*,.c)))) SRCS = $(filter-out %.inc.c,$(foreach d,. $(SDRS),$(wildcard $(addprefix $(d)/*,.c))))
OBJS = $(patsubst %.c,%.o,$(addprefix $(BUILD)/$(MODE)/,$(SRCS))) OBJS = $(patsubst %.c,%.o,$(addprefix $(BUILD)/$(MODE)/,$(SRCS)))
@@ -27,9 +26,13 @@ DIRS = $(sort $(dir $(OBJS)))
TCPS = $(addprefix test-,$(TESTS)) TCPS = $(addprefix test-,$(TESTS))


ifdef DEBUG ifdef DEBUG
BNRY := $(BNRY)$(DEVEXT)
FLGS += $(DFLAGS)
BNRY := $(PROGRAM)$(DEVEXT)
FLGS += $(DFLAGS) $(FLAGS)
MODE = debug MODE = debug
else
BNRY := $(PROGRAM)
FLGS += $(RFLAGS) $(FLAGS)
MODE = release
endif endif


export CC export CC


+ 7
- 6
src/assembler.c View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <stdlib.h> #include <stdlib.h>
@@ -38,6 +38,7 @@ static size_t bounding_rom_size(size_t size)
*/ */
static ErrorInfo* resolve_defaults(AssemblerState *state) static ErrorInfo* resolve_defaults(AssemblerState *state)
{ {
DEBUG("Resolving defaults")
if (!state->rom_size) { if (!state->rom_size) {
state->rom_size = ROM_SIZE_MIN; state->rom_size = ROM_SIZE_MIN;


@@ -82,6 +83,7 @@ static ErrorInfo* resolve_symbols(AssemblerState *state)
ASMInstruction *inst = state->instructions; ASMInstruction *inst = state->instructions;
const ASMSymbol *symbol; const ASMSymbol *symbol;


DEBUG("Resolving symbols")
while (inst) { while (inst) {
if (inst->symbol) { if (inst->symbol) {
symbol = asm_symtable_find(state->symtable, inst->symbol); symbol = asm_symtable_find(state->symtable, inst->symbol);
@@ -145,6 +147,7 @@ static void write_header(const ASMHeaderInfo *info, uint8_t *binary)
*/ */
static void serialize_binary(const AssemblerState *state, uint8_t *binary) static void serialize_binary(const AssemblerState *state, uint8_t *binary)
{ {
DEBUG("Serializing binary data")
memset(binary, 0xFF, state->rom_size); memset(binary, 0xFF, state->rom_size);


const ASMInstruction *inst = state->instructions; const ASMInstruction *inst = state->instructions;
@@ -188,16 +191,13 @@ size_t assemble(const LineBuffer *source, uint8_t **binary_ptr, ErrorInfo **ei_p


asm_symtable_init(&state.symtable); asm_symtable_init(&state.symtable);


#ifdef DEBUG_MODE
asm_lines_print(state.lines);
#endif
if (TRACE_LEVEL)
asm_lines_print(state.lines);


if ((error_info = tokenize(&state))) if ((error_info = tokenize(&state)))
goto error; goto error;

if ((error_info = resolve_defaults(&state))) if ((error_info = resolve_defaults(&state)))
goto error; goto error;

if ((error_info = resolve_symbols(&state))) if ((error_info = resolve_symbols(&state)))
goto error; goto error;


@@ -240,6 +240,7 @@ bool assemble_file(const char *src_path, const char *dst_path)
return false; return false;
} }


DEBUG("Writing output file")
bool success = write_binary_file(dst_path, binary, size); bool success = write_binary_file(dst_path, binary, size);
free(binary); free(binary);
return success; return success;


+ 1
- 1
src/assembler/preprocessor.c View File

@@ -373,7 +373,7 @@ static inline bool is_header_offset_valid(uint16_t offset)
ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)
{ {
ErrorInfo* ei = NULL; ErrorInfo* ei = NULL;
DEBUG("Running preprocessor:")
DEBUG("Running preprocessor")


if ((ei = build_asm_lines(source, &state->lines, NULL, &state->includes, 0))) if ((ei = build_asm_lines(source, &state->lines, NULL, &state->includes, 0)))
return ei; return ei;


+ 5
- 6
src/assembler/state.c View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <stdlib.h> #include <stdlib.h>
@@ -196,17 +196,16 @@ bool asm_deftable_remove(
return hash_table_remove(tab, key, size); return hash_table_remove(tab, key, size);
} }


#ifdef DEBUG_MODE
/* /*
DEBUG FUNCTION: Print out an ASMLine list to stdout.
@TRACE_LEVEL
Print out an ASMLine list to stdout.
*/ */
void asm_lines_print(const ASMLine *line) void asm_lines_print(const ASMLine *line)
{ {
DEBUG("Dumping ASMLines:")
TRACE("Dumping ASMLines:")
while (line) { while (line) {
DEBUG("- %-40.*s [%s:%02zu]", (int) line->length, line->data,
TRACE("- %-40.*s [%s:%02zu]", (int) line->length, line->data,
line->filename, line->original->lineno) line->filename, line->original->lineno)
line = line->next; line = line->next;
} }
} }
#endif

+ 1
- 3
src/assembler/state.h View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#pragma once #pragma once
@@ -112,6 +112,4 @@ const ASMDefine* asm_deftable_find(const ASMDefineTable*, const char*, size_t);
void asm_deftable_insert(ASMDefineTable*, ASMDefine*); void asm_deftable_insert(ASMDefineTable*, ASMDefine*);
bool asm_deftable_remove(ASMDefineTable*, const char*, size_t); bool asm_deftable_remove(ASMDefineTable*, const char*, size_t);


#ifdef DEBUG_MODE
void asm_lines_print(const ASMLine*); void asm_lines_print(const ASMLine*);
#endif

+ 2
- 1
src/assembler/tokenizer.c View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <stdlib.h> #include <stdlib.h>
@@ -468,6 +468,7 @@ ErrorInfo* tokenize(AssemblerState *state)
const ASMLine *line = state->lines; const ASMLine *line = state->lines;
size_t offset = 0; size_t offset = 0;


DEBUG("Running tokenizer")
init_layout_info(&li, state); init_layout_info(&li, state);
memset(si.slots, -1, MMU_NUM_ROM_BANKS); memset(si.slots, -1, MMU_NUM_ROM_BANKS);




+ 13
- 15
src/config.c View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <dirent.h> #include <dirent.h>
@@ -24,15 +24,14 @@ static void print_help(const char *arg1)
" -h, --help show this help message and exit\n" " -h, --help show this help message and exit\n"
" -v, --version show crater's version number and exit\n" " -v, --version show crater's version number and exit\n"
" -f, --fullscreen enable fullscreen mode\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" " <rom_path> path to the rom file to execute; if not given, will look\n"
" in the roms/ directory and prompt the user\n" " in the roms/ directory and prompt the user\n"
"\n" "\n"
"advanced options:\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"
" -g, --debug show logging information while running; add twice (-g -g)\n"
" to show more detailed logs, including an emulator trace\n"
" -s, --scale <n> scale the game screen by an integer factor\n"
" (applies to windowed mode only)\n"
" -a, --assemble <in> [<out>] convert z80 assembly source code into a\n" " -a, --assemble <in> [<out>] convert z80 assembly source code into a\n"
" binary file that can be run by crater\n" " binary file that can be run by crater\n"
" -d, --disassemble <in> [<out>] convert a binary file into z80 assembly\n" " -d, --disassemble <in> [<out>] convert a binary file into z80 assembly\n"
@@ -202,7 +201,7 @@ static int parse_args(Config *config, int argc, char *argv[])
} }
config->scale = scale; config->scale = scale;
} else if (!strcmp(arg, "g") || !strcmp(arg, "debug")) { } else if (!strcmp(arg, "g") || !strcmp(arg, "debug")) {
config->debug = true;
config->debug++;
} else if (!strcmp(arg, "a") || !strcmp(arg, "assemble")) { } else if (!strcmp(arg, "a") || !strcmp(arg, "assemble")) {
if (paths_read >= 1) { if (paths_read >= 1) {
config->src_path = config->rom_path; config->src_path = config->rom_path;
@@ -277,7 +276,7 @@ static bool sanity_check(Config* config)
} else if (config->assemble && config->disassemble) { } else if (config->assemble && config->disassemble) {
ERROR("cannot assemble and disassemble at the same time") ERROR("cannot assemble and disassemble at the same time")
return false; return false;
} else if (assembler && (config->debug || config->fullscreen || config->scale > 1)) {
} else if (assembler && (config->fullscreen || config->scale > 1)) {
ERROR("cannot specify emulator options in assembler mode") ERROR("cannot specify emulator options in assembler mode")
return false; return false;
} else if (assembler && !config->src_path) { } else if (assembler && !config->src_path) {
@@ -309,7 +308,7 @@ int config_create(Config** config_ptr, int argc, char* argv[])
Config *config = cr_malloc(sizeof(Config)); Config *config = cr_malloc(sizeof(Config));
int retval; int retval;


config->debug = false;
config->debug = 0;
config->assemble = false; config->assemble = false;
config->disassemble = false; config->disassemble = false;
config->fullscreen = false; config->fullscreen = false;
@@ -342,21 +341,20 @@ void config_destroy(Config *config)
free(config); free(config);
} }


#ifdef DEBUG_MODE
/* /*
DEBUG FUNCTION: Print out all config arguments to stdout.
@DEBUG_LEVEL
Print out all config arguments to stdout.
*/ */
void config_dump_args(const Config* config) void config_dump_args(const Config* config)
{ {
DEBUG("Dumping arguments:") DEBUG("Dumping arguments:")
DEBUG("- fullscreen: %s", config->fullscreen ? "true" : "false")
DEBUG("- scale: %d", config->scale)
DEBUG("- debug: %s", config->debug ? "true" : "false")
DEBUG("- debug: %d", config->debug)
DEBUG("- assemble: %s", config->assemble ? "true" : "false") DEBUG("- assemble: %s", config->assemble ? "true" : "false")
DEBUG("- disassemble: %s", config->disassemble ? "true" : "false") DEBUG("- disassemble: %s", config->disassemble ? "true" : "false")
DEBUG("- fullscreen: %s", config->fullscreen ? "true" : "false")
DEBUG("- scale: %d", config->scale)
DEBUG("- rom_path: %s", config->rom_path ? config->rom_path : "(null)") DEBUG("- rom_path: %s", config->rom_path ? config->rom_path : "(null)")
DEBUG("- src_path: %s", config->src_path ? config->src_path : "(null)") DEBUG("- src_path: %s", config->src_path ? config->src_path : "(null)")
DEBUG("- dst_path: %s", config->dst_path ? config->dst_path : "(null)") DEBUG("- dst_path: %s", config->dst_path ? config->dst_path : "(null)")
DEBUG("- overwrite: %s", config->overwrite ? "true" : "false") DEBUG("- overwrite: %s", config->overwrite ? "true" : "false")
} }
#endif

+ 2
- 5
src/config.h View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#pragma once #pragma once
@@ -21,7 +21,7 @@
/* Structs */ /* Structs */


typedef struct { typedef struct {
bool debug;
int debug;
bool assemble; bool assemble;
bool disassemble; bool disassemble;
bool fullscreen; bool fullscreen;
@@ -36,7 +36,4 @@ typedef struct {


int config_create(Config**, int, char*[]); int config_create(Config**, int, char*[]);
void config_destroy(Config*); void config_destroy(Config*);

#ifdef DEBUG_MODE
void config_dump_args(const Config*); void config_dump_args(const Config*);
#endif

+ 5
- 7
src/iomanager.c View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <signal.h> #include <signal.h>
@@ -36,9 +36,8 @@ void iomanager_emulate(GameGear *gg)
while (!caught_signal) { while (!caught_signal) {
if (gamegear_simulate(gg)) { if (gamegear_simulate(gg)) {
ERROR("caught exception: %s", gamegear_get_exception(gg)) ERROR("caught exception: %s", gamegear_get_exception(gg))
#ifdef DEBUG_MODE
z80_dump_registers(&gg->cpu);
#endif
if (DEBUG_LEVEL)
z80_dump_registers(&gg->cpu);
break; break;
} }
usleep(1000 * 1000 / 60); usleep(1000 * 1000 / 60);
@@ -46,9 +45,8 @@ void iomanager_emulate(GameGear *gg)


if (caught_signal) { if (caught_signal) {
WARN("caught signal, stopping...") WARN("caught signal, stopping...")
#ifdef DEBUG_MODE
z80_dump_registers(&gg->cpu);
#endif
if (DEBUG_LEVEL)
z80_dump_registers(&gg->cpu);
} }


DEBUG("IOManager unpowering GameGear") DEBUG("IOManager unpowering GameGear")


+ 28
- 20
src/logging.h View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#pragma once #pragma once
@@ -10,30 +10,38 @@


/* Internal usage only */ /* Internal usage only */


#define LOG_MSG_(dest, level, extra, after, ...) \
do { \
fprintf(dest, level ": " __VA_ARGS__); \
extra; \
fprintf(dest, "\n"); \
after; \
#define LOG_MSG_(dest, level, type, extra, after, ...) \
do { \
if (logging_level_ >= level) { \
fprintf(dest, type " " __VA_ARGS__); \
extra; \
fprintf(dest, "\n"); \
after; \
} \
} while (0); } while (0);


#define LOG_ERR_(...) LOG_MSG_(stderr, __VA_ARGS__) #define LOG_ERR_(...) LOG_MSG_(stderr, __VA_ARGS__)
#define LOG_OUT_(...) LOG_MSG_(stdout, __VA_ARGS__) #define LOG_OUT_(...) LOG_MSG_(stdout, __VA_ARGS__)


#define PRINT_ERRNO_() fprintf(stderr, ": %s", strerror(errno))
#define PRINT_ERR_ fprintf(stderr, ": %s", strerror(errno))
#define EXIT_FAIL_ exit(EXIT_FAILURE)

#define DEBUG_TEXT_ "\x1b[0m\x1b[37m[DEBUG]\x1b[0m"
#define TRACE_TEXT_ "\x1b[1m\x1b[33m[TRACE]\x1b[0m"

unsigned logging_level_;


/* Public logging macros */ /* Public logging macros */


#define FATAL(...) LOG_ERR_("fatal", {}, exit(EXIT_FAILURE), __VA_ARGS__)
#define FATAL_ERRNO(...) LOG_ERR_("fatal", PRINT_ERRNO_(), exit(EXIT_FAILURE), __VA_ARGS__)
#define ERROR(...) LOG_ERR_("error", {}, {}, __VA_ARGS__)
#define ERROR_ERRNO(...) LOG_ERR_("error", PRINT_ERRNO_(), {}, __VA_ARGS__)
#define WARN(...) LOG_ERR_("warning", {}, {}, __VA_ARGS__)
#define WARN_ERRNO(...) LOG_ERR_("warning", PRINT_ERRNO_(), {}, __VA_ARGS__)
#ifdef DEBUG_MODE
#define DEBUG(...) LOG_OUT_("[DEBUG]", {}, {}, __VA_ARGS__)
#else
#define DEBUG(...) {}
#endif
#define FATAL(...) LOG_ERR_(0, "fatal:", {}, EXIT_FAIL_, __VA_ARGS__)
#define FATAL_ERRNO(...) LOG_ERR_(0, "fatal:", PRINT_ERR_, EXIT_FAIL_, __VA_ARGS__)
#define ERROR(...) LOG_ERR_(0, "error:", {}, {}, __VA_ARGS__)
#define ERROR_ERRNO(...) LOG_ERR_(0, "error:", PRINT_ERR_, {}, __VA_ARGS__)
#define WARN(...) LOG_ERR_(0, "warning:", {}, {}, __VA_ARGS__)
#define WARN_ERRNO(...) LOG_ERR_(0, "warning:", PRINT_ERR_, {}, __VA_ARGS__)
#define DEBUG(...) LOG_OUT_(1, DEBUG_TEXT_, {}, {}, __VA_ARGS__)
#define TRACE(...) LOG_OUT_(2, TRACE_TEXT_, {}, {}, __VA_ARGS__)
#define SET_LOG_LEVEL(level) logging_level_ = (level);
#define DEBUG_LEVEL (logging_level_ >= 1)
#define TRACE_LEVEL (logging_level_ >= 2)

+ 25
- 14
src/mmu.c View File

@@ -1,9 +1,10 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>


#include "mmu.h"
#include "logging.h" #include "logging.h"
#include "util.h" #include "util.h"
#include "z80.h" #include "z80.h"
@@ -31,6 +32,27 @@ void mmu_free(MMU *mmu)
} }


/* /*
@DEBUG_LEVEL
Print out the bank mapping.
*/
static void dump_bank_table(const MMU *mmu, const uint8_t *data)
{
char buffer[49];
size_t group, elem, bank;

DEBUG("Dumping MMU bank table:")
for (group = 0; group < MMU_NUM_ROM_BANKS / 8; group++) {
for (elem = 0; elem < 8; elem++) {
bank = 8 * group + elem;
snprintf(buffer + 6 * elem, 7, "%02zX=%02zX ", bank,
(mmu->rom_banks[bank] - data) >> 14);
}
buffer[47] = '\0';
DEBUG("- %s", buffer)
}
}

/*
Load a block of ROM into the MMU. Load a block of ROM into the MMU.


size must be a multiple of MMU_ROM_BANK_SIZE (16 KB), the load will fail size must be a multiple of MMU_ROM_BANK_SIZE (16 KB), the load will fail
@@ -55,19 +77,8 @@ void mmu_load_rom(MMU *mmu, const uint8_t *data, size_t size)
mmu->rom_banks[mirror] = data + (bank * MMU_ROM_BANK_SIZE); mmu->rom_banks[mirror] = data + (bank * MMU_ROM_BANK_SIZE);
} }


#ifdef DEBUG_MODE
char temp_str[64];
DEBUG("Dumping MMU bank table:")
for (size_t group = 0; group < MMU_NUM_ROM_BANKS / 8; group++) {
for (size_t elem = 0; elem < 8; elem++) {
bank = 8 * group + elem;
snprintf(temp_str + 6 * elem, 7, "%02zX=%02zX ", bank,
(mmu->rom_banks[bank] - data) >> 14);
}
temp_str[47] = '\0';
DEBUG("- %s", temp_str)
}
#endif
if (DEBUG_LEVEL)
dump_bank_table(mmu, data);
} }


/* /*


+ 41
- 34
src/rom.c View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include <ctype.h> #include <ctype.h>
@@ -18,11 +18,29 @@


static size_t header_locations[NUM_LOCATIONS] = {0x7FF0, 0x3FF0, 0x1FF0}; static size_t header_locations[NUM_LOCATIONS] = {0x7FF0, 0x3FF0, 0x1FF0};


#ifdef DEBUG_MODE
/* /*
DEBUG FUNCTION: Print out the header to stdout.
@DEBUG_LEVEL
Given a ROM size, return a pretty string.
*/ */
static void print_header(const uint8_t *header)
static const char* size_to_string(size_t size)
{
static char buffer[SIZE_CODE_BUF];

if (!size)
strncpy(buffer, "unknown", SIZE_CODE_BUF);
else if (size >= (1 << 20))
snprintf(buffer, SIZE_CODE_BUF, "%zu MB", size >> 20);
else
snprintf(buffer, SIZE_CODE_BUF, "%zu KB", size >> 10);

return buffer;
}

/*
@DEBUG_LEVEL
Print out the raw header to stdout.
*/
static void print_header_dump(const uint8_t *header)
{ {
char header_hex[3 * HEADER_SIZE], header_chr[3 * HEADER_SIZE]; char header_hex[3 * HEADER_SIZE], header_chr[3 * HEADER_SIZE];


@@ -40,26 +58,27 @@ static void print_header(const uint8_t *header)
DEBUG("- header dump (hex): %s", header_hex) DEBUG("- header dump (hex): %s", header_hex)
DEBUG("- header dump (chr): %s", header_chr) DEBUG("- header dump (chr): %s", header_chr)
} }
#endif


#ifdef DEBUG_MODE
/* /*
DEBUG FUNCTION: Given a ROM size, return a pretty string.
@DEBUG_LEVEL
Print out the analyzed header to stdout.
*/ */
static const char* size_to_string(size_t size)
static void print_header_contents(const ROM *rom, const uint8_t *header)
{ {
static char buffer[SIZE_CODE_BUF];

if (!size)
strncpy(buffer, "unknown", SIZE_CODE_BUF);
else if (size >= (1 << 20))
snprintf(buffer, SIZE_CODE_BUF, "%zu MB", size >> 20);
DEBUG("- header info:")
if (rom->reported_checksum == rom->expected_checksum)
DEBUG(" - checksum: 0x%04X (valid)", rom->reported_checksum)
else else
snprintf(buffer, SIZE_CODE_BUF, "%zu KB", size >> 10);

return buffer;
DEBUG(" - checksum: 0x%04X (invalid, expected 0x%04X)",
rom->reported_checksum, rom->expected_checksum)
DEBUG(" - product code: %u (%s)", rom->product_code,
rom_product(rom) ? rom_product(rom) : "unknown")
DEBUG(" - version: %u", rom->version)
DEBUG(" - region code: %u (%s)", rom->region_code,
rom_region(rom) ? rom_region(rom) : "unknown")
DEBUG(" - reported size: %s",
size_to_string(size_code_to_bytes(header[0xF] & 0xF)))
} }
#endif


/* /*
Parse a ROM image's header, and return whether or not it is valid. Parse a ROM image's header, and return whether or not it is valid.
@@ -88,9 +107,8 @@ static const char* size_to_string(size_t size)
*/ */
static bool parse_header(ROM *rom, const uint8_t *header) static bool parse_header(ROM *rom, const uint8_t *header)
{ {
#ifdef DEBUG_MODE
print_header(header);
#endif
if (DEBUG_LEVEL)
print_header_dump(header);


rom->reported_checksum = header[0xA] + (header[0xB] << 8); rom->reported_checksum = header[0xA] + (header[0xB] << 8);
rom->expected_checksum = compute_checksum(rom->data, rom->size, header[0xF]); rom->expected_checksum = compute_checksum(rom->data, rom->size, header[0xF]);
@@ -99,19 +117,8 @@ static bool parse_header(ROM *rom, const uint8_t *header)
rom->version = header[0xE] & 0x0F; rom->version = header[0xE] & 0x0F;
rom->region_code = header[0xF] >> 4; rom->region_code = header[0xF] >> 4;


DEBUG("- header info:")
if (rom->reported_checksum == rom->expected_checksum)
DEBUG(" - checksum: 0x%04X (valid)", rom->reported_checksum)
else
DEBUG(" - checksum: 0x%04X (invalid, expected 0x%04X)",
rom->reported_checksum, rom->expected_checksum)
DEBUG(" - product code: %u (%s)", rom->product_code,
rom_product(rom) ? rom_product(rom) : "unknown")
DEBUG(" - version: %u", rom->version)
DEBUG(" - region code: %u (%s)", rom->region_code,
rom_region(rom) ? rom_region(rom) : "unknown")
DEBUG(" - reported size: %s",
size_to_string(size_code_to_bytes(header[0xF] & 0xF)))
if (DEBUG_LEVEL)
print_header_contents(rom, header);
return true; return true;
} }




+ 18
- 7
src/z80.c View File

@@ -1,8 +1,9 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#include "logging.h"
#include "z80.h" #include "z80.h"
#include "disassembler.h"
#include "logging.h"


#define REG_AF 0 #define REG_AF 0
#define REG_BC 1 #define REG_BC 1
@@ -19,7 +20,6 @@
#define FLAG_ZERO 6 #define FLAG_ZERO 6
#define FLAG_SIGN 7 #define FLAG_SIGN 7


#ifdef DEBUG_MODE
#define BINARY_FMT "0b%u%u%u%u%u%u%u%u" // Used by z80_dump_registers() #define BINARY_FMT "0b%u%u%u%u%u%u%u%u" // Used by z80_dump_registers()
#define BINARY_VAL(data) \ #define BINARY_VAL(data) \
(data & (1 << 7) ? 1 : 0), \ (data & (1 << 7) ? 1 : 0), \
@@ -30,7 +30,6 @@
(data & (1 << 2) ? 1 : 0), \ (data & (1 << 2) ? 1 : 0), \
(data & (1 << 1) ? 1 : 0), \ (data & (1 << 1) ? 1 : 0), \
(data & (1 << 0) ? 1 : 0) (data & (1 << 0) ? 1 : 0)
#endif


/* /*
Initialize a Z80 object. Initialize a Z80 object.
@@ -92,6 +91,7 @@ static inline uint16_t get_pair(Z80 *z80, uint8_t pair)
case REG_HL: return (z80->regfile.h << 8) + z80->regfile.l; case REG_HL: return (z80->regfile.h << 8) + z80->regfile.l;
default: FATAL("invalid call: get_pair(z80, %u)", pair) default: FATAL("invalid call: get_pair(z80, %u)", pair)
} }
return 0;
} }


/* /*
@@ -164,6 +164,16 @@ static inline void increment_refresh_counter(Z80 *z80)
#include "z80_ops.inc.c" #include "z80_ops.inc.c"


/* /*
@TRACE_LEVEL
Trace the instruction about to be executed by the CPU.
*/
static inline void trace_instruction(const Z80 *z80)
{
TRACE("PC @ 0x%04X", z80->regfile.pc)
// TODO
}

/*
Emulate the given number of cycles of the Z80, or until an exception. Emulate the given number of cycles of the Z80, or until an exception.


The return value indicates whether the exception flag is set. If it is, The return value indicates whether the exception flag is set. If it is,
@@ -175,6 +185,8 @@ bool z80_do_cycles(Z80 *z80, double cycles)
cycles -= z80->pending_cycles; cycles -= z80->pending_cycles;
while (cycles > 0 && !z80->except) { while (cycles > 0 && !z80->except) {
uint8_t opcode = mmu_read_byte(z80->mmu, z80->regfile.pc); uint8_t opcode = mmu_read_byte(z80->mmu, z80->regfile.pc);
if (TRACE_LEVEL)
trace_instruction(z80);
increment_refresh_counter(z80); increment_refresh_counter(z80);
cycles -= (*instruction_lookup_table[opcode])(z80, opcode); cycles -= (*instruction_lookup_table[opcode])(z80, opcode);
} }
@@ -183,9 +195,9 @@ bool z80_do_cycles(Z80 *z80, double cycles)
return z80->except; return z80->except;
} }


#ifdef DEBUG_MODE
/* /*
DEBUG FUNCTION: Print out all register values to stdout.
@DEBUG_LEVEL
Print out all register values to stdout.
*/ */
void z80_dump_registers(const Z80 *z80) void z80_dump_registers(const Z80 *z80)
{ {
@@ -233,4 +245,3 @@ void z80_dump_registers(const Z80 *z80)
DEBUG("- IFF1: %u", rf->iff1) DEBUG("- IFF1: %u", rf->iff1)
DEBUG("- IFF2: %u", rf->iff2) DEBUG("- IFF2: %u", rf->iff2)
} }
#endif

+ 1
- 4
src/z80.h View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */ Released under the terms of the MIT License. See LICENSE for details. */


#pragma once #pragma once
@@ -35,7 +35,4 @@ typedef struct {
void z80_init(Z80*, MMU*); void z80_init(Z80*, MMU*);
void z80_power(Z80*); void z80_power(Z80*);
bool z80_do_cycles(Z80*, double); bool z80_do_cycles(Z80*, double);

#ifdef DEBUG_MODE
void z80_dump_registers(const Z80*); void z80_dump_registers(const Z80*);
#endif

Loading…
Cancel
Save