@@ -3,3 +3,5 @@ roms/* | |||
!roms/README | |||
crater | |||
crater-dev | |||
tests/runner | |||
tests/asm/*.gg |
@@ -1,4 +1,4 @@ | |||
Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
@@ -24,12 +24,19 @@ Installing | |||
---------- | |||
Only OS X and Linux are tested. You'll need a modern compiler that supports C11 | |||
(clang preferred) and SDL 2. Using Homebrew, you can `brew install sdl2`; using | |||
apt, you can `apt-get install libsdl2-dev`. | |||
([clang][clang] preferred) and [SDL 2][sdl2]. Using Homebrew, you can | |||
`brew install sdl2`; using apt, you can `apt-get install libsdl2-dev`. | |||
Run `make` to create `./crater`. To build the development version with debug | |||
symbols (they can exist simultaneously), run `make DEBUG=1`, which creates | |||
`./crater-dev`. This also enables the printing of debugging info to stdout. | |||
symbols and extra diagnostic info (they can exist simultaneously), run | |||
`make DEBUG=1`, which creates `./crater-dev`. | |||
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 | |||
`{component}` is one of `cpu`, `vdp`, `psg`, `asm`, `dis`, or `integrate`. | |||
[clang]: http://clang.llvm.org/ | |||
[sdl2]: https://www.libsdl.org/ | |||
Usage | |||
----- | |||
@@ -1,50 +1,59 @@ | |||
# Copyright (C) 2014 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. | |||
PROGRAM = crater | |||
SOURCES = src | |||
BUILD = build | |||
DEVEXT = -dev | |||
TESTS = cpu vdp psg asm dis integrate | |||
CC = clang | |||
FLAGS = -O2 -Wall -Wextra -pedantic -std=c11 | |||
CFLAGS = $(shell sdl2-config --cflags) | |||
LIBS = $(shell sdl2-config --libs) | |||
DFLAGS = -g -DDEBUG_MODE | |||
MKDIR = mkdir -p | |||
RM = rm -rf | |||
ASM_UP = scripts/update_asm_instructions.py | |||
MODE = release | |||
BNRY = $(PROGRAM) | |||
FLGS = $(FLAGS) | |||
SDRS = $(shell find $(SOURCES) -type d | xargs echo) | |||
SRCS = $(filter-out %.inc.c,$(foreach d,. $(SDRS),$(wildcard $(addprefix $(d)/*,.c)))) | |||
OBJS = $(patsubst %.c,%.o,$(addprefix $(BUILD)/$(MODE)/,$(SRCS))) | |||
DEPS = $(OBJS:%.o=%.d) | |||
DIRS = $(sort $(dir $(OBJS))) | |||
TCPS = $(addprefix test-,$(TESTS)) | |||
ifdef DEBUG | |||
BNRY := $(BNRY)$(DEVEXT) | |||
FLAGS += -g -DDEBUG_MODE | |||
MODE = debug | |||
BNRY := $(BNRY)$(DEVEXT) | |||
FLGS += $(DFLAGS) | |||
MODE = debug | |||
endif | |||
.PHONY: all clean test test-all test-z80 test-asm test-dasm | |||
export CC | |||
export FLAGS | |||
export RM | |||
.PHONY: all clean test tests test-prereqs test-make-prereqs $(TCPS) | |||
all: $(BNRY) | |||
clean: | |||
$(RM) $(BUILD) $(PROGRAM) $(PROGRAM)$(DEVEXT) | |||
@$(MAKE) -C tests clean | |||
$(DIRS): | |||
$(MKDIR) $@ | |||
$(BNRY): $(OBJS) | |||
$(CC) $(FLAGS) $(LIBS) $(OBJS) -o $@ | |||
$(CC) $(FLGS) $(LIBS) $(OBJS) -o $@ | |||
$(OBJS): | $(DIRS) | |||
$(BUILD)/$(MODE)/%.o: %.c | |||
$(CC) $(FLAGS) $(CFLAGS) -MMD -MP -c $< -o $@ | |||
$(CC) $(FLGS) $(CFLAGS) -MMD -MP -c $< -o $@ | |||
-include $(DEPS) | |||
@@ -52,16 +61,16 @@ ASM_INST = $(SOURCES)/assembler/instructions | |||
$(ASM_INST).inc.c: $(ASM_INST).yml $(ASM_UP) | |||
python $(ASM_UP) | |||
test: test-all test-z80 test-asm test-dasm | |||
test-prereqs: $(PROGRAM) | |||
@: # No-op; prevents make from cluttering output with "X is up to date" | |||
test-all: | |||
@echo "running all tests" | |||
test-make-prereqs: | |||
@$(MAKE) test-prereqs DEBUG= | |||
test-z80: | |||
@echo "running Z80 CPU tests" | |||
test: test-make-prereqs | |||
@$(MAKE) -C tests -s all | |||
test-asm: | |||
@echo "running assembler tests" | |||
tests: test | |||
test-dasm: | |||
@echo "running disassembler tests" | |||
$(TCPS): test-make-prereqs | |||
@$(MAKE) -C tests -s $(subst test-,,$@) |
@@ -98,8 +98,6 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||
#define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg) | |||
/* ----------------------------- END WORK BLOCK ---------------------------- */ | |||
/* | |||
Fill an instruction's byte array with the given data. | |||
@@ -276,6 +276,21 @@ static bool parse_space( | |||
} | |||
/* | |||
Parse a string like parse_string(), but null-terminate it. | |||
*/ | |||
static bool parse_cstring( | |||
char **result, size_t *length, const char *arg, ssize_t size) | |||
{ | |||
if (!parse_string(result, length, arg, size)) | |||
return false; | |||
(*length)++; | |||
*result = cr_realloc(*result, sizeof(char) * (*length)); | |||
(*result)[*length - 1] = '\0'; | |||
return true; | |||
} | |||
/* | |||
Parse data encoded in a line into an ASMData object. | |||
On success, return NULL and store the instruction in *data_ptr. On failure, | |||
@@ -285,7 +300,7 @@ static ErrorInfo* parse_data( | |||
const ASMLine *line, ASMData **data_ptr, size_t offset) | |||
{ | |||
const char *directive; | |||
parser_func parser = (parser_func) parse_string; | |||
parser_func parser; | |||
if (IS_DIRECTIVE(line, DIR_BYTE)) { | |||
directive = DIR_BYTE; | |||
@@ -295,10 +310,13 @@ static ErrorInfo* parse_data( | |||
parser = parse_space; | |||
} else if (IS_DIRECTIVE(line, DIR_ASCII)) { | |||
directive = DIR_ASCII; | |||
parser = (parser_func) parse_string; | |||
} else if (IS_DIRECTIVE(line, DIR_ASCIZ)) { | |||
directive = DIR_ASCIZ; | |||
parser = (parser_func) parse_cstring; | |||
} else if (IS_DIRECTIVE(line, DIR_ASCIIZ)) { | |||
directive = DIR_ASCIIZ; | |||
parser = (parser_func) parse_cstring; | |||
} else { | |||
return error_info_create(line, ET_PREPROC, ED_PP_UNKNOWN); | |||
} | |||
@@ -90,7 +90,7 @@ static int get_rom_paths(char ***path_ptr) | |||
} | |||
closedir(dirp); | |||
} else { | |||
WARN_ERRNO("couldn't open 'roms/'") | |||
WARN_ERRNO("couldn't open '" ROMS_DIR "/'") | |||
} | |||
*path_ptr = paths; | |||
return npaths; | |||
@@ -10,12 +10,13 @@ | |||
/* Internal usage only */ | |||
#define LOG_MSG_(dest, level, extra, after, ...) { \ | |||
#define LOG_MSG_(dest, level, extra, after, ...) \ | |||
do { \ | |||
fprintf(dest, level ": " __VA_ARGS__); \ | |||
extra; \ | |||
fprintf(dest, "\n"); \ | |||
after; \ | |||
} | |||
} while (0); | |||
#define LOG_ERR_(...) LOG_MSG_(stderr, __VA_ARGS__) | |||
#define LOG_OUT_(...) LOG_MSG_(stdout, __VA_ARGS__) | |||
@@ -32,7 +32,7 @@ static void print_header(const uint8_t *header) | |||
snprintf(&header_chr[3 * i], 3, "%2c", header[i]); | |||
else { | |||
header_chr[3 * i] = ' '; | |||
header_chr[3 * i + 1] = '?'; | |||
header_chr[3 * i + 1] = '.'; | |||
} | |||
header_hex[3 * i + 2] = header_chr[3 * i + 2] = ' '; | |||
} | |||
@@ -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. */ | |||
/* | |||
@@ -0,0 +1,16 @@ | |||
;; Copyright (C) 2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
;; Released under the terms of the MIT License. See LICENSE for details. | |||
; ----- CRATER UNIT TESTING SUITE --------------------------------------------- | |||
; 02-headers1.asm | |||
; Basic test for headers and other directives, mostly using default values | |||
.rom_size auto | |||
.rom_header auto | |||
.rom_product 0 | |||
.rom_version 0 | |||
.rom_region "GG Export" | |||
.rom_checksum off | |||
.rom_declsize auto | |||
.cross_blocks auto |
@@ -0,0 +1,16 @@ | |||
;; Copyright (C) 2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
;; Released under the terms of the MIT License. See LICENSE for details. | |||
; ----- CRATER UNIT TESTING SUITE --------------------------------------------- | |||
; 03-headers2.asm | |||
; Header/directive test using non-default values | |||
.rom_size "64 KB" | |||
.rom_header $7FF0 | |||
.rom_product 101893 | |||
.rom_version 3 | |||
.rom_region "GG International" | |||
.rom_checksum on | |||
.rom_declsize "32 KB" | |||
.cross_blocks off |
@@ -0,0 +1,21 @@ | |||
;; Copyright (C) 2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
;; Released under the terms of the MIT License. See LICENSE for details. | |||
; ----- CRATER UNIT TESTING SUITE --------------------------------------------- | |||
; 04-basic.asm | |||
; Basic instruction test | |||
.org $0000 | |||
main: | |||
di | |||
ld a, $23 | |||
inc a | |||
call foo | |||
foo: | |||
push bc | |||
xor c | |||
ret z | |||
rrca | |||
ret |
@@ -0,0 +1,17 @@ | |||
;; Copyright (C) 2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
;; Released under the terms of the MIT License. See LICENSE for details. | |||
; ----- CRATER UNIT TESTING SUITE --------------------------------------------- | |||
; 05-includes.asm | |||
; Source file inclusion test, involving cross-file label references and complex | |||
; origins | |||
.include "05.inc1.asm" | |||
.org $0000 | |||
main: | |||
di | |||
ld c, $FA | |||
inc c | |||
call bar |
@@ -0,0 +1,13 @@ | |||
.org $0100 | |||
.include "05.inc2.asm" | |||
.include "05.inc3.asm" | |||
bar: | |||
push de | |||
call blah | |||
xor d | |||
ret pe | |||
call testfunc | |||
exx | |||
ret |
@@ -0,0 +1,3 @@ | |||
testfunc: | |||
sub b | |||
ret |
@@ -0,0 +1,2 @@ | |||
.include "05.inc4.asm" | |||
.rom_product 57005 |
@@ -0,0 +1,3 @@ | |||
blah: | |||
ei | |||
ret |
@@ -0,0 +1,16 @@ | |||
;; Copyright (C) 2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
;; Released under the terms of the MIT License. See LICENSE for details. | |||
; ----- CRATER UNIT TESTING SUITE --------------------------------------------- | |||
; 06-formatting.asm | |||
; Complex formatting test, involving strange indentation and newline usage | |||
foo: .inCLUde "06.inc.asm" | |||
.ORG $0100 | |||
ayy: lmao: | |||
di | |||
InC a | |||
ret |
@@ -0,0 +1,13 @@ | |||
test1:test2: test3: test4: | |||
inc a | |||
inc b | |||
inc c | |||
ret | |||
@@ -0,0 +1,31 @@ | |||
;; Copyright (C) 2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
;; Released under the terms of the MIT License. See LICENSE for details. | |||
; ----- CRATER UNIT TESTING SUITE --------------------------------------------- | |||
; 07-data.asm | |||
; Test of data directives to fill ROM with non-code bytes | |||
.org $1000 | |||
str1: .ascii "Hello, world!" | |||
str2: .asciz "World, hello!" | |||
str3: .asciiz "foobar" | |||
arr1: .byte 1 2 3 4 5 6 | |||
arr2: .byte 14 $14 $FF 255 $F0 | |||
arr3: .byte 8, $10, 4 5 6, 8, 10 | |||
void1: .space 3 | |||
void2: .space 6 $D0 | |||
void3: .space 128 $DE | |||
.org $0000 | |||
main: | |||
di | |||
loop: | |||
jp loop | |||
.org $0066 | |||
nmi: | |||
retn |
@@ -0,0 +1,103 @@ | |||
;; Copyright (C) 2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
;; Released under the terms of the MIT License. See LICENSE for details. | |||
; ----- CRATER UNIT TESTING SUITE --------------------------------------------- | |||
; 08-instructions.asm | |||
; Exhaustive test of instruction syntax | |||
.define COUNTER $C010 | |||
.define OFFSET 6 | |||
.define OFFSET2 157 | |||
.org $1000 | |||
str1: .ascii "Hello, world!" | |||
.org $0000 | |||
main: | |||
di | |||
call inst | |||
halt | |||
.org $0066 | |||
nmi: | |||
retn | |||
.org $2000 | |||
inst: | |||
inc a | |||
inc c | |||
inc hl | |||
inc sp | |||
inc (hl) | |||
inc ( hl ) | |||
inc ix | |||
inc iyl | |||
inc (ix) | |||
inc ( ix ) | |||
inc (iy+0) | |||
inc (ix+3) | |||
inc (ix+OFFSET) | |||
inc (ix-OFFSET) | |||
inc ( ix + 7 ) | |||
inc (ix-8) | |||
inc (ix - +9) | |||
inc (iy+127) | |||
inc (iy-128) | |||
add a, e | |||
add a, 5 | |||
add a, $12 | |||
add a, (hl) | |||
add a, (ix+4) | |||
add hl, bc | |||
add ix, de | |||
adc a, e | |||
adc a, 5 | |||
adc a, $12 | |||
adc a, (hl) | |||
adc a, (ix+4) | |||
adc hl, bc | |||
rlca | |||
rrca | |||
rla | |||
rra | |||
daa | |||
cpl | |||
scf | |||
ccf | |||
halt | |||
exx | |||
ei | |||
di | |||
cpd | |||
cpdr | |||
cpi | |||
cpir | |||
ind | |||
indr | |||
ini | |||
inir | |||
ldd | |||
lddr | |||
ldi | |||
ldir | |||
otdr | |||
otir | |||
outd | |||
outi | |||
rrd | |||
rld | |||
ld hl, COUNTER ; H contains $C0, L contains $10 | |||
ld d, (hl) ; D contains $FF (garbage) | |||
ld c, $3B ; C contains $3B | |||
ld (hl), c ; memory address $C010 contains $3B | |||
ld hl, str1 | |||
ld b, (hl) ; B contains 'H' | |||
ld hl, (str1) ; H contains 'e', L contains 'H' | |||
ld (hl), b ; error, writing to cartridge ROM |
@@ -0,0 +1,8 @@ | |||
01-empty.asm 01-empty.gg | |||
02-headers1.asm 02-headers1.gg | |||
03-headers2.asm 03-headers2.gg | |||
04-basic.asm 04-basic.gg | |||
05-includes.asm 05-includes.gg | |||
06-formatting.asm 06-formatting.gg | |||
07-data.asm 07-data.gg | |||
08-instructions.asm 08-instructions.gg |
@@ -0,0 +1,27 @@ | |||
# Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com> | |||
# Released under the terms of the MIT License. See LICENSE for details. | |||
RUNNER = runner | |||
COMPONENTS = cpu vdp psg asm dis integrate | |||
.PHONY: all clean $(COMPONENTS) | |||
all: $(COMPONENTS) | |||
clean: | |||
$(RM) $(RUNNER) | |||
$(RM) asm/*.gg | |||
$(RUNNER): $(RUNNER).c | |||
$(CC) $(FLAGS) $< -o $@ | |||
$(COMPONENTS): $(RUNNER) | |||
./$(RUNNER) $@ | |||
asm: asm-unarchive | |||
asm-archive: | |||
tar -czf asm/roms.tar.gz asm/*.gg | |||
asm-unarchive: | |||
tar -xf asm/roms.tar.gz |
@@ -1,4 +1,274 @@ | |||
/* 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. */ | |||
// ... | |||
#include <stdbool.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include "../src/logging.h" | |||
#include "../src/util.h" | |||
#define ASM_PREFIX "asm/" | |||
#define ASM_OUTFILE ASM_PREFIX ".output.gg" | |||
/* Helper macros for reporting test passings/failures */ | |||
#define PASS_TEST() \ | |||
do { \ | |||
printf("."); \ | |||
fflush(stdout); \ | |||
passed_tests++; \ | |||
pending_nl = true; \ | |||
} while(0); | |||
#define FAIL_MSG "***** FAILURE *****" | |||
#define FAIL_TEST(format, ...) \ | |||
do { \ | |||
printf("F\n"); \ | |||
fprintf(stderr, FAIL_MSG "\n" format "\n", __VA_ARGS__); \ | |||
failed_tests++; \ | |||
pending_nl = false; \ | |||
} while(0); | |||
#define READY_STDOUT() \ | |||
do { \ | |||
if (pending_nl) { \ | |||
printf("\n"); \ | |||
pending_nl = false; \ | |||
} \ | |||
} while(0); | |||
static int passed_tests = 0, failed_tests = 0; | |||
static bool pending_nl = false; | |||
/* | |||
Prints out the test report. Called before exiting using atexit(). | |||
*/ | |||
static void finalize() { | |||
READY_STDOUT() | |||
if (failed_tests) | |||
printf("fail (%d/%d)\n", passed_tests, passed_tests + failed_tests); | |||
else | |||
printf("pass (%d/%d)\n", passed_tests, passed_tests); | |||
} | |||
/* | |||
Compare two files. If they are identical, then return true. Otherwise, | |||
return false and print an error message showing the difference. | |||
*/ | |||
static bool diff_files(const char *expected_path, const char *actual_path) | |||
{ | |||
bool same = false; | |||
FILE *expected = NULL, *actual = NULL; | |||
if (!(actual = fopen(actual_path, "rb"))) { | |||
FAIL_TEST("missing output file: %s", actual_path) | |||
goto cleanup; | |||
} | |||
if (!(expected = fopen(expected_path, "rb"))) { | |||
FAIL_TEST("missing reference file: %s", expected_path) | |||
goto cleanup; | |||
} | |||
size_t len = 0; | |||
int e, a; | |||
while ((e = fgetc(expected)) != EOF) { | |||
a = fgetc(actual); | |||
if (a == EOF) { | |||
FAIL_TEST("files differ: output file too short (index %zu)", len) | |||
goto cleanup; | |||
} | |||
if (e != a) { | |||
FAIL_TEST("files differ: 0x%02X != 0x%02X (expected vs. actual at " | |||
"index %zu)", e, a, len) | |||
goto cleanup; | |||
} | |||
len++; | |||
} | |||
if (fgetc(actual) != EOF) { | |||
FAIL_TEST("files differ: junk at end of output file (index %zu)", len) | |||
goto cleanup; | |||
} | |||
same = true; | |||
cleanup: | |||
if (expected) | |||
fclose(expected); | |||
if (actual) | |||
fclose(actual); | |||
return same; | |||
} | |||
/* | |||
Return whether the given character is valid within a filename. | |||
*/ | |||
static bool is_valid_filename_char(char c) { | |||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || | |||
(c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-'; | |||
} | |||
/* | |||
Run a single ASM->ROM test, converting the given source file to a temporary | |||
output file, compared against the reference file. | |||
*/ | |||
static bool run_asm_test(const char *src_file, const char *ref_file) | |||
{ | |||
char *cmd_prefix = "../crater --assemble " ASM_PREFIX; | |||
char *cmd = cr_malloc(sizeof(char) * | |||
(strlen(cmd_prefix) + strlen(ASM_OUTFILE) + strlen(src_file)) + 2); | |||
// Construct the command by concatenating: | |||
// ../crater --assemble asm/<src_file> asm/.output.gg | |||
stpcpy(stpcpy(stpcpy(cmd, cmd_prefix), src_file), " " ASM_OUTFILE); | |||
unlink(ASM_OUTFILE); | |||
system(cmd); | |||
free(cmd); | |||
// Construct the full reference file path in a temporary variable and diff | |||
// it with the output file: | |||
char *ref_path = malloc(sizeof(char) * | |||
(strlen(ASM_PREFIX) + strlen(ref_file) + 1)); | |||
stpcpy(stpcpy(ref_path, ASM_PREFIX), ref_file); | |||
bool diff = diff_files(ref_path, ASM_OUTFILE); | |||
free(ref_path); | |||
return diff; | |||
} | |||
/* --------------------------- Main test runners --------------------------- */ | |||
/* | |||
Run tests for the Z80 CPU. | |||
*/ | |||
static bool test_cpu() | |||
{ | |||
// TODO | |||
return true; | |||
} | |||
/* | |||
Run tests for the VDP. | |||
*/ | |||
static bool test_vdp() | |||
{ | |||
// TODO | |||
return true; | |||
} | |||
/* | |||
Run tests for the SN76489 PSG. | |||
*/ | |||
static bool test_psg() | |||
{ | |||
// TODO | |||
return true; | |||
} | |||
/* | |||
Run tests for the assembler. | |||
*/ | |||
static bool test_asm() | |||
{ | |||
FILE *fp = fopen(ASM_PREFIX "manifest", "r"); | |||
if (!fp) { | |||
ERROR_ERRNO("couldn't open manifest file") | |||
return false; | |||
} | |||
char *line = NULL, *split, c; | |||
size_t cap = 0, lineno = 0, i; | |||
ssize_t len; | |||
while ((len = getline(&line, &cap, fp)) > 0) { | |||
lineno++; | |||
line[--len] = '\0'; | |||
if (!len) | |||
continue; | |||
i = 0; | |||
while ((c = line[i++])) { | |||
if (!is_valid_filename_char(c) && c != ' ') { | |||
READY_STDOUT() | |||
ERROR("bad character in manifest file on line %zu", lineno) | |||
return false; | |||
} | |||
} | |||
split = strchr(line, ' '); | |||
if (!split || strchr(split + 1, ' ')) { | |||
READY_STDOUT() | |||
ERROR("bad format in manifest file on line %zu", lineno) | |||
return false; | |||
} | |||
*(split++) = '\0'; | |||
if (!run_asm_test(line, split)) { | |||
fprintf(stderr, "in test: %s -> %s\n", line, split); | |||
return false; | |||
} | |||
PASS_TEST() | |||
} | |||
unlink(ASM_OUTFILE); | |||
free(line); | |||
return true; | |||
} | |||
/* | |||
Run tests for the disassembler. | |||
*/ | |||
static bool test_dis() | |||
{ | |||
// TODO | |||
return true; | |||
} | |||
/* | |||
Run integration tests (i.e., multiple components working together). | |||
*/ | |||
static bool test_integrate() | |||
{ | |||
// TODO | |||
return true; | |||
} | |||
/* | |||
Main function. | |||
*/ | |||
int main(int argc, char *argv[]) | |||
{ | |||
if (argc != 2) | |||
FATAL("a single component name is required") | |||
const char *component = argv[1], *name; | |||
bool (*func)(); | |||
if (!strcmp(component, "cpu")) { | |||
name = "Z80 CPU"; | |||
func = test_cpu; | |||
} else if (!strcmp(component, "vdp")) { | |||
name = "VDP"; | |||
func = test_vdp; | |||
} else if (!strcmp(component, "psg")) { | |||
name = "SN76489 PSG"; | |||
func = test_psg; | |||
} else if (!strcmp(component, "asm")) { | |||
name = "assembler"; | |||
func = test_asm; | |||
} else if (!strcmp(component, "dis")) { | |||
name = "disassembler"; | |||
func = test_dis; | |||
} else if (!strcmp(component, "integrate")) { | |||
name = "integration"; | |||
func = test_integrate; | |||
} else { | |||
FATAL("unknown component: %s", component) | |||
} | |||
printf("crater: running %s tests\n", name); | |||
atexit(finalize); | |||
return func() ? EXIT_SUCCESS : EXIT_FAILURE; | |||
} |