cpu: get blarg CPU instruction test 6 passing

Its been too long since a checkin, but here's some of the
improvements:

- Support for diffing with other emulators
- Better disassmbed output
- New CPU instructions implemented
- Lots of CPU fixes
This commit is contained in:
2018-08-26 22:49:45 -07:00
parent 6f9ed73ef2
commit c4ded6d077
8 changed files with 639 additions and 138 deletions

View File

@@ -29,6 +29,7 @@ typedef void (gbdb_cmd)(struct tokens **tokens);
static void breakpoint_addr_hit(uint16_t id);
static void breakpoint_cb(struct lr35902_state *lr);
static void reset_breakpoints(void);
static int64_t parse_val(const char *str);
static const char prompt[] = "gbdb >";
static const char usage[] =
@@ -38,7 +39,7 @@ static const char usage[] =
"break <addr>: Adds a breakpoint for the given addess\n"
"step <cycles>: executes \"cycle\" instructions (default 1)\n"
"regs: dumps the state of the registers\n"
"peek: view the next instruction to run\n"
"disas: view the next instruction to run\n"
"exit: quit the program\n";
static struct lr35902_ops cpu_ops;
@@ -53,6 +54,7 @@ static volatile sig_atomic_t paused = 0;
static struct {
bool quiet;
int log_fd;
int trace_fd;
} config;
void gb_log(const char *fmt, ...)
@@ -112,12 +114,34 @@ static void init(void)
gb_mem_init(memory, &video);
config.log_fd = -1;
config.trace_fd = -1;
}
static void print_trace(void)
{
if (config.trace_fd > -1) {
uint8_t instr = gb_mem_read(memory, cpu.pc);
dprintf(config.trace_fd,
"A:%02X F:%c%c%c%c BC:%04X DE:%04x HL:%04x SP:%04x PC:%04x 0x%02x",
cpu.a,
(cpu.zf) ? 'Z' : '-', (cpu.nf) ? 'N' : '-',
(cpu.hf) ? 'H' : '-', (cpu.cf) ? 'C' : '-',
cpu.bc, cpu.de, cpu.hl, cpu.sp, cpu.pc, instr);
if (instr == 0xcb) {
dprintf(config.trace_fd, " 0x%02x", gb_mem_read(memory, cpu.pc + 1));
}
dprintf(config.trace_fd, "\n");
}
}
static void cycle()
{
int cycles;
print_trace();
cycles = lr35902_cycle(&cpu);
gb_video_cycle(&video, cycles);
}
@@ -159,9 +183,6 @@ static void set_logfile(struct tokens **tokens)
char *token = token_next(tokens);
int fd;
if (token != NULL) {
strip_newline(token);
}
if (token == NULL || strcmp(token, "") == 0) {
if (config.log_fd != -1) {
@@ -186,6 +207,36 @@ static void set_logfile(struct tokens **tokens)
config.log_fd = fd;
}
static void set_tracefile(struct tokens **tokens)
{
char *token = token_next(tokens);
int fd;
if (token == NULL || strcmp(token, "") == 0) {
if (config.trace_fd >= -1) {
close(config.trace_fd);
}
config.trace_fd = -1;
return;
}
fd = open(token,
O_WRONLY | O_TRUNC | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd < 0) {
gb_error("Failed to open tracefile %s, %s\n", token, strerror(errno));
return;
}
if (config.trace_fd != -1) {
close(config.trace_fd);
}
config.trace_fd = fd;
gb_log("Trace fd=%d\n", config.trace_fd);
}
static void set_quiet_on(struct tokens **tokens)
{
config.quiet = true;
@@ -227,6 +278,7 @@ static void set(struct tokens **tokens)
tri_init(&commands);
tri_add_string(&commands, "quiet", set_quiet);
tri_add_string(&commands, "logfile", set_logfile);
tri_add_string(&commands, "trace", set_tracefile);
tri_add_string(&commands, "video_debug", set_video_debug);
init = true;
}
@@ -259,11 +311,11 @@ static void step(struct tokens **tokens)
{
uint64_t steps, end_steps;
char *token;
token = token_next(tokens);
if (token == NULL) {
steps = 1;
} else {
strip_newline(token);
steps = strtol(token, NULL, 0);
}
@@ -305,16 +357,42 @@ static void regs(struct tokens **tokens)
gb_log("SP: 0x%04x\n", cpu.sp);
}
static void peek(struct tokens **tokens)
static uint8_t decode_fetch_mem(void *opaque, uint16_t addr)
{
return gb_mem_read(memory, addr);
}
static void disas(struct tokens **tokens)
{
uint16_t pc = lr35902_get_reg_16(&cpu, LR35902_REG_PC);
uint8_t byte = gb_mem_read(memory, pc);
gb_log("0x%04x:%s\n", pc, gb_byte_to_opcode(byte));
uint16_t old_pc = pc;
const char *disas_cnt_str;
int64_t num_disas, i;
if (tokens) {
disas_cnt_str = token_next(tokens);
if (disas_cnt_str == NULL) {
num_disas = 1;
} else {
num_disas = parse_val(disas_cnt_str);
}
} else {
num_disas = 1;
}
for (i = 0; i < num_disas; i++) {
const char *opcode;
old_pc = pc;
opcode = gb_byte_to_opcode(&pc, decode_fetch_mem, &memory);
gb_log("0x%04x:%s\n", old_pc, opcode);
free((void *) opcode);
}
}
static void vstep(struct tokens **tokens)
{
peek(NULL);
disas(NULL);
step(tokens);
regs(NULL);
}
@@ -359,7 +437,7 @@ static int64_t parse_reg_str(const char *str)
{ "c", cpu.c },
{ "d", cpu.d },
{ "e", cpu.e },
{ "f", (cpu.zf << 3) | (cpu.nf << 2) | (cpu.hf << 1) | (cpu.cf << 0) },
{ "f", f },
};
@@ -387,7 +465,7 @@ static void assert(struct tokens **tokens)
const char *usage = "usage: assert <value> <operator> <value>\n";
int64_t val0, val1;
val0_str = token_next(tokens);
val0_str = strdup(token_next(tokens));
if (val0_str == NULL) {
gb_error("%s", usage);
return;
@@ -400,7 +478,7 @@ static void assert(struct tokens **tokens)
return;
}
val1_str = token_next(tokens);
val1_str = strdup(token_next(tokens));
if (val1_str == NULL) {
gb_error("%s", usage);
return;
@@ -438,7 +516,7 @@ static void assert(struct tokens **tokens)
return;
fail:
gb_error("ASSERT: %s %s %s\n", val0_str, operator_str, val1_str);
gb_error("%s=%" PRId64 ", %s=%" PRId64 "\n", val0_str, val0, val1_str, val1);
gb_error("%s=0x%" PRIx64 ", %s=0x%" PRIx64 "\n", val0_str, val0, val1_str, val1);
free(val0_str);
free(val1_str);
free(operator_str);
@@ -449,10 +527,9 @@ fail:
static void mem(struct tokens **tokens)
{
uint16_t addr, bytes, i;
uint16_t addr, bytes, addr_end;
char *token = token_next(tokens);
gb_log("mem_addr=%s\n", token);
int i;
if (token == NULL) {
gb_error("usage: mem <addr> (num bytes) (format)\n");
@@ -461,29 +538,16 @@ static void mem(struct tokens **tokens)
addr = parse_val(token);
token = token_next(tokens);
gb_log("mem_bytes=%s\n", token);
if (token == NULL) {
bytes = 1;
} else {
bytes = parse_val(token);
}
token = token_next(tokens);
gb_log("mem_format=%s\n", token);
for (i = 0; i < bytes; i++) {
//TODO: Make sure this has no side effects
uint8_t val = gb_mem_read(memory, addr + i);
if (token != NULL && token[0] == 'i') {
gb_log("0x%04x:%s\n", addr + i, gb_byte_to_opcode(val));
} else if (token != NULL && token[0] == 'b') {
gb_log("0x%04x:0x%02x %s\n", addr + i, val, gb_byte_to_opcode(val));
} else {
gb_log("0x%04x:0x%02x\n", addr + i, val);
}
gb_log("0x%04x: 0x%02x\n", addr + i, gb_mem_read(memory, addr + i));
}
}
static void load(struct tokens **tokens)
@@ -749,6 +813,9 @@ static void process_cmd(const char *cmd_str, struct tri *commands)
}
call_next_cmd(&tokens, commands, "");
/* Ensure there are no leftover tokens to leak */
do {} while (token_next(&tokens));
}
}
@@ -795,7 +862,7 @@ int main(int argc, char **argv)
tri_add_string(&commands, "mem", mem);
/* FIXME */
/* tri_add_string(&commands, "dump", mem_dump); */
tri_add_string(&commands, "peek", peek);
tri_add_string(&commands, "disassemble", disas);
tri_add_string(&commands, "help", help);
tri_add_string(&commands, "?", help);
tri_add_string(&commands, "breakpoint", breakpoint);
@@ -839,5 +906,9 @@ int main(int argc, char **argv)
close(config.log_fd);
}
if (config.trace_fd != -1) {
close(config.log_fd);
}
return 0;
}