CPU testing

This commit is contained in:
Samuel Walker 2025-01-31 17:07:09 -07:00
parent 9a6dc67c3e
commit 5206c3871e
Signed by: piwalker
GPG Key ID: BE1F84BF85111255
11 changed files with 212 additions and 14 deletions

View File

@ -11,7 +11,7 @@ typedef uint32_t u32;
typedef uint64_t u64; typedef uint64_t u64;
#define BIT(a, n) ((a & (1 << n)) ? 1 : 0) #define BIT(a, n) ((a & (1 << n)) ? 1 : 0)
#define BIT_SET(a, n, on) {if(on) a |= (1 << n); else a &= !(1 << n);} #define BIT_SET(a, n, on) {if(on) a |= (1 << n); else a &= ~(1 << n);}
#define BETWEEN(a, b, c) ((a >= b) && (a <= c)) #define BETWEEN(a, b, c) ((a >= b) && (a <= c))
void delay(u32 ms); void delay(u32 ms);

View File

@ -64,3 +64,5 @@ cpu_registers *cpu_get_regs();
u8 cpu_get_int_flags(); u8 cpu_get_int_flags();
void cpu_set_int_flags(u8 value); void cpu_set_int_flags(u8 value);
void inst_to_str(cpu_context *ctx, char *str);

6
include/dbg.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <common.h>
void dbg_update();
void dbg_print();

6
include/io.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <common.h>
u8 io_read(u16 address);
void io_write(u16 address, u8 value);

View File

@ -3,6 +3,7 @@
#include <cart.h> #include <cart.h>
#include <cpu.h> #include <cpu.h>
#include <ram.h> #include <ram.h>
#include <io.h>
// 0x0000 - 0x3FFF : ROM Bank 0 // 0x0000 - 0x3FFF : ROM Bank 0
// 0x4000 - 0x7FFF : ROM Bank 1 - Switchable // 0x4000 - 0x7FFF : ROM Bank 1 - Switchable
@ -48,9 +49,8 @@ u8 bus_read(u16 address) {
} else if (address < 0xFF80) { } else if (address < 0xFF80) {
//IO registers //IO registers
//TODO //TODO
printf("UNSUPPORTED bus_read(%04X)\n", address);
//NO_IMPL //NO_IMPL
return 0; return io_read(address);
} else if (address == 0xFFFF) { } else if (address == 0xFFFF) {
//CPU ENABLE REGISTER //CPU ENABLE REGISTER
//TODO //TODO
@ -68,6 +68,7 @@ void bus_write(u16 address, u8 value) {
//Char/Map Data //Char/Map Data
//TODO //TODO
printf("UNSUPPORTED bus_write(%04X)\n", address); printf("UNSUPPORTED bus_write(%04X)\n", address);
return;
//NO_IMPL //NO_IMPL
} else if (address < 0xC000) { } else if (address < 0xC000) {
//Cartridge RAM //Cartridge RAM
@ -84,6 +85,7 @@ void bus_write(u16 address, u8 value) {
//OAM //OAM
//TODO //TODO
printf("UNSUPPORTED bus_write(%04X)\n", address); printf("UNSUPPORTED bus_write(%04X)\n", address);
return;
//NO_IMPL //NO_IMPL
} else if (address < 0xFF00) { } else if (address < 0xFF00) {
//reserved unusable //reserved unusable
@ -91,7 +93,7 @@ void bus_write(u16 address, u8 value) {
} else if (address < 0xFF80) { } else if (address < 0xFF80) {
//IO registers //IO registers
//TODO //TODO
printf("UNSUPPORTED bus_write(%04X)\n", address); io_write(address, value);
//NO_IMPL //NO_IMPL
return; return;
} else if (address == 0xFFFF) { } else if (address == 0xFFFF) {

View File

@ -3,6 +3,7 @@
#include <common.h> #include <common.h>
#include <emu.h> #include <emu.h>
#include <interrupts.h> #include <interrupts.h>
#include <dbg.h>
cpu_context ctx = {0}; cpu_context ctx = {0};
@ -39,11 +40,19 @@ bool cpu_step() {
ctx.regs.f & (1 << 5) ? 'H' : '-', ctx.regs.f & (1 << 5) ? 'H' : '-',
ctx.regs.f & (1 << 4) ? 'C' : '-' ctx.regs.f & (1 << 4) ? 'C' : '-'
); );
printf("%08lX - %04X: %-7s (%02X %02X %02X) A: %02X F: %s BC: %02X%02X DE: %02X%02X HL: %02X%02X SP: %04X PC: %04X\n", emu_get_context()->ticks, pc, inst_name(ctx.cur_inst->type), ctx.cur_opcode, bus_read(pc+1), bus_read(pc+2), ctx.regs.a, flags, ctx.regs.b, ctx.regs.c, ctx.regs.d, ctx.regs.e, ctx.regs.h, ctx.regs.l, ctx.regs.sp, ctx.regs.pc);
char inst[16];
inst_to_str(&ctx, inst);
printf("%08lX - %04X: %-12s (%02X %02X %02X) A: %02X F: %s BC: %02X%02X DE: %02X%02X HL: %02X%02X SP: %04X PC: %04X\n", emu_get_context()->ticks, pc, inst, ctx.cur_opcode, bus_read(pc+1), bus_read(pc+2), ctx.regs.a, flags, ctx.regs.b, ctx.regs.c, ctx.regs.d, ctx.regs.e, ctx.regs.h, ctx.regs.l, ctx.regs.sp, ctx.regs.pc);
if(ctx.cur_inst == NULL){ if(ctx.cur_inst == NULL){
printf("Unknown Instruction! %02X\n", ctx.cur_opcode); printf("Unknown Instruction! %02X\n", ctx.cur_opcode);
exit(-7); exit(-7);
} }
dbg_update();
dbg_print();
execute(); execute();
} else { } else {
//is halted //is halted

View File

@ -63,7 +63,7 @@ void fetch_data() {
return; return;
case AM_HLI_R: case AM_HLI_R:
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2); ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
ctx.mem_dest = bus_read(cpu_read_reg(ctx.cur_inst->reg_1)); ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
ctx.dest_is_mem = true; ctx.dest_is_mem = true;
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)+1); cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)+1);
return; return;

View File

@ -37,7 +37,7 @@ static void proc_daa(cpu_context *ctx) {
u8 u = 0; u8 u = 0;
int fc = 0; int fc = 0;
if(CPU_FLAG_H || (!CPU_FLAG_N && (ctx->regs.a & 0xF) >9)) { if(CPU_FLAG_H || (!CPU_FLAG_N && (ctx->regs.a & 0xF) > 9)) {
u = 6; u = 6;
} }
@ -402,7 +402,7 @@ static void proc_ldh(cpu_context *ctx) {
if (!ctx->dest_is_mem) { if (!ctx->dest_is_mem) {
cpu_set_reg(ctx->cur_inst->reg_1, bus_read(0XFF00 | ctx->fetched_data)); cpu_set_reg(ctx->cur_inst->reg_1, bus_read(0XFF00 | ctx->fetched_data));
} else { } else {
bus_write(0xFF00 | ctx->mem_dest, ctx->cur_inst->reg_2); bus_write(0xFF00 | ctx->mem_dest, cpu_read_reg(ctx->cur_inst->reg_2));
} }
emu_cycles(1); emu_cycles(1);
} }

21
lib/dbg.c Normal file
View File

@ -0,0 +1,21 @@
#include <dbg.h>
#include <bus.h>
static char dbg_msg[1024] = {0};
static int msg_size = 0;
void dbg_update(){
if (bus_read(0xFF02) == 0x81) {
char c = bus_read(0xFF01);
dbg_msg[msg_size++] = c;
bus_write(0xFF02, 0);
}
}
void dbg_print(){
if(dbg_msg[0]) {
printf("DBG: %s\n", dbg_msg);
}
}

View File

@ -242,12 +242,12 @@ instruction instructions[0x100] = {
[0xE1] = {IN_POP, AM_IMP, RT_HL}, [0xE1] = {IN_POP, AM_IMP, RT_HL},
[0xE2] = {IN_LD, AM_MR_R, RT_C, RT_A}, [0xE2] = {IN_LD, AM_MR_R, RT_C, RT_A},
[0xE5] = {IN_PUSH, AM_IMP, RT_HL}, [0xE5] = {IN_PUSH, AM_IMP, RT_HL},
[0xE6] = {IN_AND, AM_D8}, [0xE6] = {IN_AND, AM_R_D8, RT_A},
[0xE7] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x20}, [0xE7] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x20},
[0xE8] = {IN_ADD, AM_R_D8, RT_SP}, [0xE8] = {IN_ADD, AM_R_D8, RT_SP},
[0xE9] = {IN_JP, AM_MR, RT_HL}, [0xE9] = {IN_JP, AM_R, RT_HL},
[0xEA] = {IN_LD, AM_A16_R, RT_NONE, RT_A}, [0xEA] = {IN_LD, AM_A16_R, RT_NONE, RT_A},
[0xEE] = {IN_XOR, AM_D8}, [0xEE] = {IN_XOR, AM_R_D8, RT_A},
[0xEF] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x28}, [0xEF] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x28},
//0xFX //0xFX
[0xF0] = {IN_LDH, AM_R_A8, RT_A}, [0xF0] = {IN_LDH, AM_R_A8, RT_A},
@ -255,13 +255,13 @@ instruction instructions[0x100] = {
[0xF2] = {IN_LD, AM_R_MR, RT_A, RT_C}, [0xF2] = {IN_LD, AM_R_MR, RT_A, RT_C},
[0xF3] = {IN_DI}, [0xF3] = {IN_DI},
[0xF5] = {IN_PUSH, AM_IMP, RT_AF}, [0xF5] = {IN_PUSH, AM_IMP, RT_AF},
[0xF6] = {IN_OR, AM_D8}, [0xF6] = {IN_OR, AM_R_D8, RT_A},
[0xF7] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x30}, [0xF7] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x30},
[0xF8] = {IN_LD, AM_HL_SPR, RT_HL, RT_SP}, [0xF8] = {IN_LD, AM_HL_SPR, RT_HL, RT_SP},
[0xF9] = {IN_LD, AM_R_R, RT_HL, RT_SP}, [0xF9] = {IN_LD, AM_R_R, RT_HL, RT_SP},
[0xFA] = {IN_LD, AM_R_A16, RT_A}, [0xFA] = {IN_LD, AM_R_A16, RT_A},
[0xFB] = {IN_EI}, [0xFB] = {IN_EI},
[0xFE] = {IN_CP, AM_D8}, [0xFE] = {IN_CP, AM_R_D8, RT_A},
[0xFF] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x38} [0xFF] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x38}
}; };
@ -323,3 +323,123 @@ char *inst_lookup[] = {
char *inst_name(in_type t) { char *inst_name(in_type t) {
return inst_lookup[t]; return inst_lookup[t];
} }
static char *rt_lookup[] = {
"<NONE>",
"A",
"F",
"B",
"C",
"D",
"E",
"H",
"L",
"AF",
"BC",
"DE",
"HL",
"SP",
"PC"
};
void inst_to_str(cpu_context *ctx, char *str) {
instruction *inst = ctx->cur_inst;
sprintf(str, "%s ", inst_name(inst->type));
switch(inst->mode) {
case AM_IMP:
return;
case AM_R_D16:
case AM_R_A16:
sprintf(str, "%s %s,$%04X", inst_name(inst->type),
rt_lookup[inst->reg_1], ctx->fetched_data);
return;
case AM_R:
sprintf(str, "%s %s", inst_name(inst->type),
rt_lookup[inst->reg_1]);
return;
case AM_R_R:
sprintf(str, "%s %s,%s", inst_name(inst->type),
rt_lookup[inst->reg_1], rt_lookup[inst->reg_2]);
return;
case AM_MR_R:
sprintf(str, "%s (%s),%s", inst_name(inst->type),
rt_lookup[inst->reg_1], rt_lookup[inst->reg_2]);
return;
case AM_MR:
sprintf(str, "%s (%s)", inst_name(inst->type),
rt_lookup[inst->reg_1]);
return;
case AM_R_MR:
sprintf(str, "%s %s,(%s)", inst_name(inst->type),
rt_lookup[inst->reg_1], rt_lookup[inst->reg_2]);
return;
case AM_R_D8:
case AM_R_A8:
sprintf(str, "%s %s,$%02X", inst_name(inst->type),
rt_lookup[inst->reg_1], ctx->fetched_data & 0xFF);
return;
case AM_R_HLI:
sprintf(str, "%s %s,(%s+)", inst_name(inst->type),
rt_lookup[inst->reg_1], rt_lookup[inst->reg_2]);
return;
case AM_R_HLD:
sprintf(str, "%s %s,(%s-)", inst_name(inst->type),
rt_lookup[inst->reg_1], rt_lookup[inst->reg_2]);
return;
case AM_HLI_R:
sprintf(str, "%s (%s+),%s", inst_name(inst->type),
rt_lookup[inst->reg_1], rt_lookup[inst->reg_2]);
return;
case AM_HLD_R:
sprintf(str, "%s (%s-),%s", inst_name(inst->type),
rt_lookup[inst->reg_1], rt_lookup[inst->reg_2]);
return;
case AM_A8_R:
sprintf(str, "%s $%02X,%s", inst_name(inst->type),
bus_read(ctx->regs.pc - 1), rt_lookup[inst->reg_2]);
return;
case AM_HL_SPR:
sprintf(str, "%s (%s),SP+%d", inst_name(inst->type),
rt_lookup[inst->reg_1], ctx->fetched_data & 0xFF);
return;
case AM_D8:
sprintf(str, "%s $%02X", inst_name(inst->type),
ctx->fetched_data & 0xFF);
return;
case AM_D16:
sprintf(str, "%s $%04X", inst_name(inst->type),
ctx->fetched_data);
return;
case AM_MR_D8:
sprintf(str, "%s (%s),$%02X", inst_name(inst->type),
rt_lookup[inst->reg_1], ctx->fetched_data & 0xFF);
return;
case AM_A16_R:
sprintf(str, "%s ($%04X),%s", inst_name(inst->type),
ctx->fetched_data, rt_lookup[inst->reg_2]);
return;
default:
fprintf(stderr, "INVALID AM: %d\n", inst->mode);
NO_IMPL
}
}

32
lib/io.c Normal file
View File

@ -0,0 +1,32 @@
#include <io.h>
static char serial_data[2];
u8 io_read(u16 address){
if(address == 0xFF01) {
return serial_data[0];
}
if(address == 0xFF02) {
return serial_data[1];
}
printf("UNSUPPORTED io_read(%04X)\n", address);
return 0;
}
void io_write(u16 address, u8 value){
if(address == 0xFF01) {
serial_data[0] = value;
return;
}
if(address == 0xFF02) {
serial_data[1] = value;
return;
}
printf("UNSUPPORTED io_write(%04X)\n", address);
}