diff --git a/Makefile b/Makefile index b59ba65..2ecbed7 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC=cc CFLAGS=-O3 -std=c99 -Werror -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -SOURCES=cpu.c ins.c pia.c mem.c ewm.c +SOURCES=cpu.c ins.c pia.c mem.c ewm.c fmt.c OBJECTS=$(SOURCES:.c=.o) LIBS=-lcurses EXECUTABLE=ewm diff --git a/cpu.c b/cpu.c index b86db17..8313f74 100644 --- a/cpu.c +++ b/cpu.c @@ -21,6 +21,7 @@ // SOFTWARE. #include +#include #include #include #include @@ -34,6 +35,7 @@ #include "cpu.h" #include "ins.h" #include "mem.h" +#include "fmt.h" /* Private API */ @@ -97,125 +99,6 @@ void _cpu_set_status(struct cpu_t *cpu, uint8_t status) { cpu->state.c = (status & (1 << 0)); } -static void cpu_format_instruction(struct cpu_t *cpu, char *buffer) { - *buffer = 0x00; - - cpu_instruction_t *i = &instructions[mem_get_byte(cpu, cpu->state.pc)]; - uint8_t opcode = mem_get_byte(cpu, cpu->state.pc); - - /* Single byte instructions */ - if (i->bytes == 1) { - sprintf(buffer, "%s", i->name); - } - - /* JSR is the only exception */ - else if (opcode == 0x20) { - sprintf(buffer, "%s $%.4X", i->name, mem_get_word(cpu, cpu->state.pc+1)); - } - - /* Branches */ - else if ((opcode & 0b00011111) == 0b00010000) { - int8_t offset = (int8_t) mem_get_byte(cpu, cpu->state.pc+1); - uint16_t addr = cpu->state.pc + 2 + offset; - sprintf(buffer, "%s $%.4X", i->name, addr); - } - - else if ((opcode & 0b00000011) == 0b00000001) { - switch ((opcode & 0b00011100) >> 2) { - case 0b000: - sprintf(buffer, "%s ($%.2X,X)", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b001: - sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b010: - sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b011: - sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b100: - sprintf(buffer, "%s ($%.2X),Y", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b101: - sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b110: - sprintf(buffer, "%s $%.2X%.2X,Y", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b111: - sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); - break; - } - } - - else if ((opcode & 0b00000011) == 0b00000010) { - switch ((opcode & 0b00011100) >> 2) { - case 0b000: - sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b001: - sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b010: - sprintf(buffer, "%s", i->name); - break; - case 0b011: - sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b101: - sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b111: - sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); - break; - } - } - - else if ((opcode & 0b00000011) == 0b00000000) { - switch ((opcode & 0b00011100) >> 2) { - case 0b000: - sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b001: - sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b011: - sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b101: - sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); - break; - case 0b111: - sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); - break; - } - } -} - -static void cpu_format_state(struct cpu_t *cpu, char *buffer) { - sprintf(buffer, "A=%.2X X=%.2X Y=%.2X S=%.2X SP=%.4X %c%c%c%c%c%c%c%c", - cpu->state.a, cpu->state.x, cpu->state.y, cpu->state.s, 0x0100 + cpu->state.sp, - - cpu->state.n ? 'N' : '-', - cpu->state.v ? 'V' : '-', - '-', - cpu->state.b ? 'B' : '-', - cpu->state.d ? 'D' : '-', - cpu->state.i ? 'I' : '-', - cpu->state.z ? 'Z' : '-', - cpu->state.c ? 'C' : '-'); -} - -static void cpu_format_stack(struct cpu_t *cpu, char *buffer) { - *buffer = 0x00; - for (uint16_t sp = cpu->state.sp; sp != 0xff; sp++) { - char tmp[8]; - sprintf(tmp, " %.2X", _mem_get_byte_direct(cpu, 0x0100 + sp)); - buffer = strcat(buffer, tmp); - } -} - static int cpu_execute_instruction(struct cpu_t *cpu) { /* Trace code - Refactor into its own function or module */ char trace_instruction[256]; @@ -268,22 +151,23 @@ static int cpu_execute_instruction(struct cpu_t *cpu) { if (cpu->trace) { cpu_format_state(cpu, trace_state); - cpu_format_stack(cpu, trace_stack); // TODO: This crashes on the hello world test + cpu_format_stack(cpu, trace_stack); + char bytes[10]; switch (i->bytes) { case 1: - fprintf(stderr, "CPU: %.4X %-20s | %.2X %-20s STACK: %s\n", - pc, trace_instruction, mem_get_byte(cpu, pc), trace_state, trace_stack); + snprintf(bytes, sizeof bytes, "%.2X", mem_get_byte(cpu, pc)); break; case 2: - fprintf(stderr, "CPU: %.4X %-20s | %.2X %.2X %-20s STACK: %s\n", - pc, trace_instruction, mem_get_byte(cpu, pc), mem_get_byte(cpu, pc+1), trace_state, trace_stack); + snprintf(bytes, sizeof bytes, "%.2X %.2X", mem_get_byte(cpu, pc), mem_get_byte(cpu, pc+1)); break; case 3: - fprintf(stderr, "CPU: %.4X %-20s | %.2X %.2X %.2X %-20s STACK: %s\n", - pc, trace_instruction, mem_get_byte(cpu, pc), mem_get_byte(cpu, pc+1), mem_get_byte(cpu, pc+2), trace_state, trace_stack); + snprintf(bytes, sizeof bytes, "%.2X %.2X %.2X", mem_get_byte(cpu, pc), mem_get_byte(cpu, pc+1), mem_get_byte(cpu, pc+2)); break; } + + fprintf(cpu->trace, "%.4X: %-8s %-11s %-20s %s\n", + pc, bytes, trace_instruction, trace_state, trace_stack); } return 0; @@ -295,6 +179,13 @@ void cpu_init(struct cpu_t *cpu) { memset(cpu, 0x00, sizeof(struct cpu_t)); } +void cpu_shutdown(struct cpu_t *cpu) { + if (cpu->trace != NULL) { + (void) fclose(cpu->trace); + cpu->trace = NULL; + } +} + void cpu_add_mem(struct cpu_t *cpu, struct mem_t *mem) { if (cpu->mem == NULL) { cpu->mem = mem; @@ -405,13 +296,25 @@ void cpu_strict(struct cpu_t *cpu, bool strict) { cpu->strict = true; } -void cpu_trace(struct cpu_t *cpu, uint8_t trace) { - cpu->trace = trace; +int cpu_trace(struct cpu_t *cpu, char *path) { + if (cpu->trace != NULL) { + (void) fclose(cpu->trace); + cpu->trace = NULL; + } + + if (path != NULL) { + printf("MOO Tracing to %s\n", path); + cpu->trace = fopen(path, "w"); + if (cpu->trace == NULL) { + return errno; + } + } + + return 0; } void cpu_reset(struct cpu_t *cpu) { cpu->state.pc = mem_get_word(cpu, EWM_VECTOR_RES); - fprintf(stderr, "CPU: cpu->state.pc = %.4x\n", cpu->state.pc); cpu->state.a = 0x00; cpu->state.x = 0x00; cpu->state.y = 0x00; @@ -458,7 +361,6 @@ int cpu_run(struct cpu_t *cpu) { /* TODO: Tick? */ instruction_count++; } - fprintf(stderr, "Executed %" PRId64 " instructions\n", instruction_count); return err; } diff --git a/cpu.h b/cpu.h index f52cf4d..488cd59 100644 --- a/cpu.h +++ b/cpu.h @@ -41,11 +41,11 @@ struct cpu_state_t { }; struct cpu_t { - struct cpu_state_t state; - uint8_t trace; - bool strict; - struct mem_t *mem; - uint8_t *memory; // This is pointing to the first 2 pages of memory, zero page and stack. + struct cpu_state_t state; + FILE *trace; + bool strict; + struct mem_t *mem; + uint8_t *memory; // This is pointing to the first 2 pages of memory, zero page and stack. }; #define MEM_TYPE_RAM 0 @@ -79,6 +79,7 @@ uint8_t _cpu_get_status(struct cpu_t *cpu); void _cpu_set_status(struct cpu_t *cpu, uint8_t status); void cpu_init(struct cpu_t *cpu); +void cpu_shutdown(struct cpu_t *cpu); void cpu_add_mem(struct cpu_t *cpu, struct mem_t *mem); void cpu_add_ram(struct cpu_t *cpu, uint16_t start, uint16_t length); @@ -87,7 +88,7 @@ void cpu_add_rom_data(struct cpu_t *cpu, uint16_t start, uint16_t length, uint8_ void cpu_add_iom(struct cpu_t *cpu, uint16_t start, uint16_t length, void *obj, mem_read_handler_t read_handler, mem_write_handler_t write_handler); void cpu_strict(struct cpu_t *cpu, bool strict); -void cpu_trace(struct cpu_t *cpu, uint8_t trace); +int cpu_trace(struct cpu_t *cpu, char *path); void cpu_reset(struct cpu_t *cpu); int cpu_irq(struct cpu_t *cpu); diff --git a/ewm.c b/ewm.c index 5622820..b06e984 100644 --- a/ewm.c +++ b/ewm.c @@ -83,6 +83,7 @@ static struct ewm_machine_t machines[] = { static struct option options[] = { { "machine", required_argument, NULL, 'm' }, { "strict", no_argument, NULL, 's' }, + { "trace", optional_argument, NULL, 't' }, { NULL, 0, NULL, 0 } }; @@ -98,6 +99,7 @@ static struct ewm_machine_t *machine_with_name(char *name) { int main(int argc, char **argv) { struct ewm_machine_t *machine = NULL; bool strict = false; + char *trace_path = NULL; char ch; while ((ch = getopt_long(argc, argv, "m:", options, NULL)) != -1) { @@ -108,6 +110,9 @@ int main(int argc, char **argv) { case 's': strict = true; break; + case 't': + trace_path = optarg ? optarg : "/dev/stderr"; + break; } } @@ -122,6 +127,7 @@ int main(int argc, char **argv) { struct cpu_t cpu; cpu_init(&cpu); cpu_strict(&cpu, strict); + cpu_trace(&cpu, trace_path); (void) setup_replica1(&cpu); @@ -138,5 +144,7 @@ int main(int argc, char **argv) { break; } + cpu_shutdown(&cpu); + return 0; } diff --git a/fmt.c b/fmt.c new file mode 100644 index 0000000..516102c --- /dev/null +++ b/fmt.c @@ -0,0 +1,156 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Stefan Arentz - http://github.com/st3fan/ewm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +#include "cpu.h" +#include "ins.h" +#include "mem.h" +#include "fmt.h" + +void cpu_format_state(struct cpu_t *cpu, char *buffer) { + sprintf(buffer, "A=%.2X X=%.2X Y=%.2X S=%.2X SP=%.2X %c%c%c%c%c%c%c%c", + cpu->state.a, cpu->state.x, cpu->state.y, _cpu_get_status(cpu), cpu->state.sp, + + cpu->state.n ? 'N' : '-', + cpu->state.v ? 'V' : '-', + '-', + cpu->state.b ? 'B' : '-', + cpu->state.d ? 'D' : '-', + cpu->state.i ? 'I' : '-', + cpu->state.z ? 'Z' : '-', + cpu->state.c ? 'C' : '-'); +} + +void cpu_format_stack(struct cpu_t *cpu, char buffer[764]) { + if (cpu->state.sp != 0xff) { + char *p = buffer; + *p = 0x00; + p = strcat(p, "["); + for (uint16_t sp = cpu->state.sp; sp != 0xff; sp++) { + if (sp != cpu->state.sp) { + p = strcat(p, " "); + } + char tmp[8]; + sprintf(tmp, "%.2X", _mem_get_byte_direct(cpu, 0x0100 + sp)); + p = strcat(p, tmp); + } + strcat(p, "]"); + } +} + +void cpu_format_instruction(struct cpu_t *cpu, char *buffer) { + *buffer = 0x00; + + cpu_instruction_t *i = &instructions[mem_get_byte(cpu, cpu->state.pc)]; + uint8_t opcode = mem_get_byte(cpu, cpu->state.pc); + + /* Single byte instructions */ + if (i->bytes == 1) { + sprintf(buffer, "%s", i->name); + } + + /* JSR is the only exception */ + else if (opcode == 0x20) { + sprintf(buffer, "%s $%.4X", i->name, mem_get_word(cpu, cpu->state.pc+1)); + } + + /* Branches */ + else if ((opcode & 0b00011111) == 0b00010000) { + int8_t offset = (int8_t) mem_get_byte(cpu, cpu->state.pc+1); + uint16_t addr = cpu->state.pc + 2 + offset; + sprintf(buffer, "%s $%.4X", i->name, addr); + } + + else if ((opcode & 0b00000011) == 0b00000001) { + switch ((opcode & 0b00011100) >> 2) { + case 0b000: + sprintf(buffer, "%s ($%.2X,X)", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b001: + sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b010: + sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b011: + sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b100: + sprintf(buffer, "%s ($%.2X),Y", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b101: + sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b110: + sprintf(buffer, "%s $%.2X%.2X,Y", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b111: + sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + break; + } + } + + else if ((opcode & 0b00000011) == 0b00000010) { + switch ((opcode & 0b00011100) >> 2) { + case 0b000: + sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b001: + sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b010: + sprintf(buffer, "%s", i->name); + break; + case 0b011: + sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b101: + sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b111: + sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + break; + } + } + + else if ((opcode & 0b00000011) == 0b00000000) { + switch ((opcode & 0b00011100) >> 2) { + case 0b000: + sprintf(buffer, "%s #$%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b001: + sprintf(buffer, "%s $%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b011: + sprintf(buffer, "%s $%.2X%.2X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b101: + sprintf(buffer, "%s $%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+1)); + break; + case 0b111: + sprintf(buffer, "%s $%.2X%.2X,X", i->name, mem_get_byte(cpu, cpu->state.pc+2), mem_get_byte(cpu, cpu->state.pc+1)); + break; + } + } +} diff --git a/fmt.h b/fmt.h new file mode 100644 index 0000000..435c187 --- /dev/null +++ b/fmt.h @@ -0,0 +1,32 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Stefan Arentz - http://github.com/st3fan/ewm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef EWM_FMT_H +#define EWM_FMT_H + +struct cpu_t; + +void cpu_format_state(struct cpu_t *cpu, char *buffer); +void cpu_format_stack(struct cpu_t *cpu, char buffer[764]); +void cpu_format_instruction(struct cpu_t *cpu, char *buffer); + +#endif /* EWM_FMT_H */ diff --git a/mem.c b/mem.c index 23b78ec..4f5f47c 100644 --- a/mem.c +++ b/mem.c @@ -24,6 +24,7 @@ #include #include +#include "cpu.h" #include "mem.h" // The following two are our memory primitives that properly set go diff --git a/mem.h b/mem.h index cc763e4..b193d8c 100644 --- a/mem.h +++ b/mem.h @@ -23,7 +23,7 @@ #ifndef MEM_H #define MEM_H -#include "cpu.h" +struct cpu_t; typedef uint8_t (*mem_mod_t)(struct cpu_t *cpu, uint8_t b);