Added command line args to set initial machine state

* changed debug print to match a validation run found on nesdev.com
This commit is contained in:
Rob McMullen 2017-12-18 09:15:02 -08:00
parent b9d74c2a85
commit c5e9cf084e
4 changed files with 107 additions and 36 deletions

View File

@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <termios.h> #include <termios.h>
#include <time.h> #include <time.h>
@ -18,14 +19,15 @@ void step_delay()
nanosleep(&req, &rem); nanosleep(&req, &rem);
} }
void run_cpu() void run_cpu(int verbose, int mem_dump)
{ {
int cycles = 0; int cycles = 0;
int cycles_per_step = (CPU_FREQ / (ONE_SECOND / STEP_DURATION)); int cycles_per_step = (CPU_FREQ / (ONE_SECOND / STEP_DURATION));
for (;;) { for (;;) {
for (cycles %= cycles_per_step; cycles < cycles_per_step;) { 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_uart();
} }
step_delay(); // remove this for more speed step_delay(); // remove this for more speed
@ -48,26 +50,82 @@ void raw_stdin()
atexit(restore_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[]) int main(int argc, char *argv[])
{ {
if (argc != 2) { int a, x, y, sp, sr, pc;
printf("Usage: %s file.rom\n", argv[0]); int verbose, interactive, mem_dump;
printf("The first 16k of \"file.rom\" is loaded into the last 16k of memory.\n"); 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; return EXIT_FAILURE;
} }
if (load_rom(argv[1]) != 0) { if (interactive) raw_stdin(); // allow individual keystrokes to be detected
printf("Error loading \"%s\".\n", argv[1]);
return EXIT_FAILURE;
}
raw_stdin(); // allow individual keystrokes to be detected
init_tables(); init_tables();
init_uart(); init_uart();
reset_cpu(); reset_cpu(a, x, y, sp, sr, pc);
run_cpu(); run_cpu(verbose, mem_dump);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

47
6502.c
View File

@ -833,18 +833,21 @@ void init_tables() // this is only done at runtime to improve code readability.
instructions[0xFF] = (Instruction) {"???", inst_NOP, IMPL, 1}; 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; A = _a;
X = 0; X = _x;
Y = 0; Y = _y;
SP = 0xFF; SP = _sp;
SR.byte = 0; SR.byte = _sr;
SR.bits.interrupt = 1; SR.bits.interrupt = 1;
SR.bits.unused = 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) int load_rom(char * filename)
@ -866,20 +869,21 @@ int load_rom(char * filename)
return 0; return 0;
} }
int step_cpu() // returns cycle count int step_cpu(int verbose) // returns cycle count
{ {
inst = instructions[memory[PC]]; inst = instructions[memory[PC]];
#ifdef DEBUG if (verbose) {
printf("PC=%04X OPCODE=%02X: %s\r\n", PC, memory[PC], inst.mnemonic); // almost match for NES dump for easier comparison
printf("A=%02X X=%02X Y=%02X SR=%02X SP=%02X\r\n", A, X, Y, SR.byte, SP); printf("%04X ", PC);
if (lengths[inst.mode] == 3)
/* dump memory for analysis (slows down emulation significantly) */ printf("%02X %02X %02X", memory[PC], memory[PC+1], memory[PC+2]);
else if (lengths[inst.mode] == 2)
FILE * fp = fopen("memdump", "w"); printf("%02X %02X ", memory[PC], memory[PC+1]);
fwrite(&memory, sizeof(memory), 1, fp); else
fclose(fp); printf("%02X ", memory[PC]);
#endif 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; jumping = 0;
inst.function(); inst.function();
@ -887,3 +891,10 @@ int step_cpu() // returns cycle count
return inst.cycles; 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);
}

6
6502.h
View File

@ -65,8 +65,10 @@ Instruction instructions[0x100];
void init_tables(); 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 load_rom(char * filename);
int step_cpu(); int step_cpu(int verbose);
void save_memory(char * filename);

View File

@ -1,5 +1,5 @@
CFLAGS = -Wall -Wpedantic -Ofast -std=gnu99 CFLAGS = -Wall -Wpedantic -std=gnu99 -g
LDFLAGS = -Ofast #LDFLAGS = -Ofast
OBJ := 6502-emu.o 6502.o 6850.o OBJ := 6502-emu.o 6502.o 6850.o