Fixes #11 - Create better tracing facility

This commit is contained in:
Stefan Arentz 2016-11-18 16:50:31 -05:00
parent 0bee4f7b93
commit 8b2a89dda6
8 changed files with 238 additions and 138 deletions

View File

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

162
cpu.c
View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
@ -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;
}

13
cpu.h
View File

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

8
ewm.c
View File

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

156
fmt.c Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#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;
}
}
}

32
fmt.h Normal file
View File

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

1
mem.c
View File

@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "cpu.h"
#include "mem.h"
// The following two are our memory primitives that properly set go

2
mem.h
View File

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