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 <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>
@ -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;
}

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};
}
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,20 +869,21 @@ 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();
@ -887,3 +891,10 @@ int step_cpu() // returns cycle count
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 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);

View File

@ -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