From c5e9cf084e91a2bb1af5505a645c57b58c100040 Mon Sep 17 00:00:00 2001 From: Rob McMullen Date: Mon, 18 Dec 2017 09:15:02 -0800 Subject: [PATCH] Added command line args to set initial machine state * changed debug print to match a validation run found on nesdev.com --- 6502-emu.c | 84 +++++++++++++++++++++++++++++++++++++++++++++--------- 6502.c | 49 +++++++++++++++++++------------ 6502.h | 6 ++-- Makefile | 4 +-- 4 files changed, 107 insertions(+), 36 deletions(-) diff --git a/6502-emu.c b/6502-emu.c index 911eecf..5ace9c6 100644 --- a/6502-emu.c +++ b/6502-emu.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -18,14 +19,15 @@ void step_delay() nanosleep(&req, &rem); } -void run_cpu() +void run_cpu(int verbose, int mem_dump) { int cycles = 0; int cycles_per_step = (CPU_FREQ / (ONE_SECOND / STEP_DURATION)); for (;;) { for (cycles %= cycles_per_step; cycles < cycles_per_step;) { - cycles += step_cpu(); + if (mem_dump) save_memory(NULL); + cycles += step_cpu(verbose); step_uart(); } step_delay(); // remove this for more speed @@ -48,26 +50,82 @@ void raw_stdin() atexit(restore_stdin); } +int hextoint(char *str) { + int val; + + if (*str == '$') str++; + val = strtol(str, NULL, 16); + return val; +} + int main(int argc, char *argv[]) { - if (argc != 2) { - printf("Usage: %s file.rom\n", argv[0]); - printf("The first 16k of \"file.rom\" is loaded into the last 16k of memory.\n"); + int a, x, y, sp, sr, pc; + int verbose, interactive, mem_dump; + int opt; + + verbose = 0; + interactive = 0; + mem_dump = 0; + a = 0; + x = 0; + y = 0; + sp = 0; + sr = 0; + pc = -RST_VEC; // negative implies indirect + while ((opt = getopt(argc, argv, "vima:x:y:r:p:s:g:")) != -1) { + switch (opt) { + case 'v': + verbose = 1; + break; + case 'i': + interactive = 1; + break; + case 'm': + mem_dump = 1; + break; + case 'a': + a = hextoint(optarg); + break; + case 'x': + x = hextoint(optarg); + break; + case 'y': + y = hextoint(optarg); + break; + case 's': + sp = hextoint(optarg); + break; + case 'p': + sr = hextoint(optarg); + break; + case 'r': + case 'g': + pc = hextoint(optarg); + break; + default: /* '?' */ + fprintf(stderr, "Usage: %s [-v] [-i] [-a HEX] [-x HEX] [-y HEX] [-s HEX] [-p HEX] [-g|-r ADDR] file.rom\nThe first 16k of \"file.rom\" is loaded into the last 16k of memory.\n", + argv[0]); + exit(EXIT_FAILURE); + } + } + + if (optind >= argc) { + fprintf(stderr, "Expected argument after options\n"); + exit(EXIT_FAILURE); + } + if (load_rom(argv[optind]) != 0) { + printf("Error loading \"%s\".\n", argv[optind]); return EXIT_FAILURE; } - if (load_rom(argv[1]) != 0) { - printf("Error loading \"%s\".\n", argv[1]); - return EXIT_FAILURE; - } - - raw_stdin(); // allow individual keystrokes to be detected + if (interactive) raw_stdin(); // allow individual keystrokes to be detected init_tables(); init_uart(); - reset_cpu(); - run_cpu(); + reset_cpu(a, x, y, sp, sr, pc); + run_cpu(verbose, mem_dump); return EXIT_SUCCESS; } diff --git a/6502.c b/6502.c index 7b584f6..4e2fce0 100644 --- a/6502.c +++ b/6502.c @@ -833,18 +833,21 @@ void init_tables() // this is only done at runtime to improve code readability. instructions[0xFF] = (Instruction) {"???", inst_NOP, IMPL, 1}; } -void reset_cpu() +void reset_cpu(int _a, int _x, int _y, int _sp, int _sr, int _pc) { - A = 0; - X = 0; - Y = 0; - SP = 0xFF; + A = _a; + X = _x; + Y = _y; + SP = _sp; - SR.byte = 0; + SR.byte = _sr; SR.bits.interrupt = 1; SR.bits.unused = 1; - memcpy(&PC, &memory[RST_VEC], sizeof(PC)); + if (_pc < 0) + memcpy(&PC, &memory[-_pc], sizeof(PC)); + else + PC = _pc; } int load_rom(char * filename) @@ -866,24 +869,32 @@ int load_rom(char * filename) return 0; } -int step_cpu() // returns cycle count +int step_cpu(int verbose) // returns cycle count { inst = instructions[memory[PC]]; - #ifdef DEBUG - printf("PC=%04X OPCODE=%02X: %s\r\n", PC, memory[PC], inst.mnemonic); - printf("A=%02X X=%02X Y=%02X SR=%02X SP=%02X\r\n", A, X, Y, SR.byte, SP); - - /* dump memory for analysis (slows down emulation significantly) */ - - FILE * fp = fopen("memdump", "w"); - fwrite(&memory, sizeof(memory), 1, fp); - fclose(fp); - #endif - + if (verbose) { + // almost match for NES dump for easier comparison + printf("%04X ", PC); + if (lengths[inst.mode] == 3) + printf("%02X %02X %02X", memory[PC], memory[PC+1], memory[PC+2]); + else if (lengths[inst.mode] == 2) + printf("%02X %02X ", memory[PC], memory[PC+1]); + else + printf("%02X ", memory[PC]); + printf(" %-10s A:%02X X:%02X Y:%02X P:%02X SP:%02X CYC:%03d\n", inst.mnemonic, A, X, Y, SR.byte, SP, 0); + } + jumping = 0; inst.function(); if (jumping == 0) PC += lengths[inst.mode]; return inst.cycles; } + +void save_memory(char * filename) { // dump memory for analysis (slows down emulation significantly) + if (filename == NULL) filename = "memdump"; + FILE * fp = fopen(filename, "w"); + fwrite(&memory, sizeof(memory), 1, fp); + fclose(fp); +} diff --git a/6502.h b/6502.h index ec3d074..093ad78 100644 --- a/6502.h +++ b/6502.h @@ -65,8 +65,10 @@ Instruction instructions[0x100]; void init_tables(); -void reset_cpu(); +void reset_cpu(int _a, int _x, int _y, int _sp, int _sr, int _pc); int load_rom(char * filename); -int step_cpu(); +int step_cpu(int verbose); + +void save_memory(char * filename); diff --git a/Makefile b/Makefile index 29ff36d..4eb80cd 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -CFLAGS = -Wall -Wpedantic -Ofast -std=gnu99 -LDFLAGS = -Ofast +CFLAGS = -Wall -Wpedantic -std=gnu99 -g +#LDFLAGS = -Ofast OBJ := 6502-emu.o 6502.o 6850.o