From dd1c6d2e0e26df2e45d6555370da80074bb7d862 Mon Sep 17 00:00:00 2001 From: Samuel Walker Date: Thu, 30 Jan 2025 22:54:33 -0700 Subject: [PATCH] calls, jumps, and stack. --- include/cpu.h | 4 ++- include/stack.h | 9 ++++++ lib/cpu_fetch.c | 1 + lib/cpu_proc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++-- lib/cpu_util.c | 4 +++ lib/instructions.c | 37 ++++++++++++++++++++++++ lib/stack.c | 23 +++++++++++++++ 7 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 include/stack.h create mode 100644 lib/stack.c diff --git a/include/cpu.h b/include/cpu.h index 1c2d43b..678944e 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -50,4 +50,6 @@ void cpu_set_reg(reg_type rt, u16 val); void fetch_data(); u8 cpu_get_ie_register(); -void cpu_set_ie_register(u8 ie); \ No newline at end of file +void cpu_set_ie_register(u8 ie); + +cpu_registers *cpu_get_regs(); \ No newline at end of file diff --git a/include/stack.h b/include/stack.h new file mode 100644 index 0000000..d756656 --- /dev/null +++ b/include/stack.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +void stack_push(u8 data); +void stack_push16(u16 data); + +u8 stack_pop(); +u16 stack_pop16(); \ No newline at end of file diff --git a/lib/cpu_fetch.c b/lib/cpu_fetch.c index 291dcf1..e1eaa51 100644 --- a/lib/cpu_fetch.c +++ b/lib/cpu_fetch.c @@ -17,6 +17,7 @@ void fetch_data() { return; case AM_R_R: ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2); + return; case AM_R_D8: ctx.fetched_data = bus_read(ctx.regs.pc); emu_cycles(1); diff --git a/lib/cpu_proc.c b/lib/cpu_proc.c index c8bdc07..f866754 100644 --- a/lib/cpu_proc.c +++ b/lib/cpu_proc.c @@ -1,6 +1,7 @@ #include #include #include +#include //process CPU instructions... @@ -28,6 +29,21 @@ static void proc_nop(cpu_context *ctx) { } +static void proc_pop(cpu_context *ctx) { + u16 n = stack_pop16(); + cpu_set_reg(ctx->cur_inst->reg_1, n); + emu_cycles(2); + + if (ctx->cur_inst->reg_1 == RT_AF) { + cpu_set_reg(ctx->cur_inst->reg_1, n & 0xFFF0); + } +} + +static void proc_push(cpu_context *ctx) { + stack_push16(cpu_read_reg(ctx->cur_inst->reg_1)); + emu_cycles(2); +} + static void proc_ldh(cpu_context *ctx) { if (!ctx->dest_is_mem) { cpu_set_reg(ctx->cur_inst->reg_1, bus_read(0XFF00 | ctx->fetched_data)); @@ -83,13 +99,56 @@ static bool check_condition(cpu_context *ctx) { return false; } -static void proc_jp(cpu_context *ctx) { +static void goto_addr(cpu_context *ctx, u16 addr, bool pushpc){ if (check_condition(ctx)) { - ctx->regs.pc = ctx->fetched_data; + if(pushpc) { + stack_push16(ctx->regs.pc); + emu_cycles(2); + } + ctx->regs.pc = addr; emu_cycles(1); } } +static void proc_jp(cpu_context *ctx) { + goto_addr(ctx, ctx->fetched_data, false); +} + +static void proc_call(cpu_context *ctx) { + goto_addr(ctx, ctx->fetched_data, true); +} + +static void proc_rst(cpu_context *ctx) { + goto_addr(ctx, ctx->cur_inst->param, true); +} + +static void proc_ret(cpu_context *ctx) { + if (ctx->cur_inst->cond != CT_NONE) { + emu_cycles(1); + } + if(check_condition(ctx)){ + u16 lo = stack_pop(); + emu_cycles(1); + u16 hi = stack_pop(); + emu_cycles(1); + + u16 n = (hi << 8) | lo; + ctx->regs.pc = n; + emu_cycles(1); + } +} + +static void proc_reti(cpu_context *ctx) { + ctx->int_master_enabled = true; + proc_ret(ctx); +} + +static void proc_jr(cpu_context *ctx) { + char rel = (char)(ctx->fetched_data & 0XFF); + u16 addr = ctx->regs.pc + rel; + goto_addr(ctx, addr, false); +} + IN_PROC processors[] = { [IN_NONE] = proc_none, [IN_NOP] = proc_nop, @@ -97,7 +156,14 @@ IN_PROC processors[] = { [IN_JP] = proc_jp, [IN_DI] = proc_di, [IN_XOR] = proc_xor, - [IN_LDH] = proc_ldh + [IN_LDH] = proc_ldh, + [IN_POP] = proc_pop, + [IN_PUSH] = proc_push, + [IN_CALL] = proc_call, + [IN_JR] = proc_jr, + [IN_RET] = proc_ret, + [IN_RETI] = proc_reti, + [IN_RST] = proc_rst }; IN_PROC inst_get_processor(in_type type) { diff --git a/lib/cpu_util.c b/lib/cpu_util.c index 81ffeb6..4084d30 100644 --- a/lib/cpu_util.c +++ b/lib/cpu_util.c @@ -48,4 +48,8 @@ void cpu_set_reg(reg_type rt, u16 val) { case RT_SP: ctx.regs.sp = val; break; case RT_NONE: break; } +} + +cpu_registers *cpu_get_regs() { + return &ctx.regs; } \ No newline at end of file diff --git a/lib/instructions.c b/lib/instructions.c index ba13aca..41cd7ed 100644 --- a/lib/instructions.c +++ b/lib/instructions.c @@ -16,20 +16,25 @@ instruction instructions[0x100] = { [0x12] = {IN_LD, AM_MR_R, RT_DE, RT_A}, [0x15] = {IN_DEC, AM_R, RT_D}, [0x16] = {IN_LD, AM_R_D8, RT_D}, + [0x18] = {IN_JR, AM_D8}, [0x1A] = {IN_LD, AM_R_MR, RT_A, RT_DE}, [0x1E] = {IN_LD, AM_R_D8, RT_E}, //0x2X + [0x20] = {IN_JR, AM_D8, RT_NONE, RT_NONE, CT_NZ}, [0x21] = {IN_LD, AM_R_D16, RT_HL}, [0x22] = {IN_LD, AM_HLI_R, RT_HL, RT_A}, [0x25] = {IN_DEC, AM_R, RT_H}, [0x26] = {IN_LD, AM_R_D8, RT_H}, + [0x28] = {IN_JR, AM_D8, RT_NONE, RT_NONE, CT_Z}, [0x2A] = {IN_LD, AM_R_HLI, RT_A, RT_HL}, [0x2E] = {IN_LD, AM_R_D8, RT_L}, //0x3X + [0x30] = {IN_JR, AM_D8, RT_NONE, RT_NONE, CT_NC}, [0x31] = {IN_LD, AM_R_D16, RT_SP}, [0x32] = {IN_LD, AM_HLD_R, RT_HL, RT_A}, [0x35] = {IN_DEC, AM_MR, RT_HL}, [0x36] = {IN_LD, AM_MR_D8, RT_HL}, + [0x38] = {IN_JR, AM_D8, RT_NONE, RT_NONE, CT_C}, [0x3A] = {IN_LD, AM_R_HLD, RT_A, RT_HL}, [0x3E] = {IN_LD, AM_R_D8, RT_A}, //0x4X @@ -106,17 +111,49 @@ instruction instructions[0x100] = { [0xAF] = {IN_XOR, AM_R, RT_A}, //0xBX //0xCX + [0xC0] = {IN_RET, AM_IMP, RT_NONE, RT_NONE, CT_NZ}, + [0xC1] = {IN_POP, AM_IMP, RT_BC}, + [0xC2] = {IN_JP, AM_D16, RT_NONE, RT_NONE, CT_NZ}, [0xC3] = {IN_JP, AM_D16}, + [0xC4] = {IN_CALL, AM_D16, RT_NONE, RT_NONE, CT_NZ}, + [0xC5] = {IN_PUSH, AM_IMP, RT_BC}, + [0xC7] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x00}, + [0xC8] = {IN_RET, AM_IMP, RT_NONE, RT_NONE, CT_Z}, + [0xC9] = {IN_RET}, + [0xCA] = {IN_JP, AM_D16, RT_NONE, RT_NONE, CT_Z}, + [0xCC] = {IN_CALL, AM_D16, RT_NONE, RT_NONE, CT_Z}, + [0xCD] = {IN_CALL, AM_D16}, + [0xCF] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x08}, //0xDX + [0xD0] = {IN_RET, AM_IMP, RT_NONE, RT_NONE, CT_NC}, + [0xD1] = {IN_POP, AM_IMP, RT_DE}, + [0xD2] = {IN_JP, AM_D16, RT_NONE, RT_NONE, CT_NC}, + [0xD4] = {IN_CALL, AM_D16, RT_NONE, RT_NONE, CT_NC}, + [0xD5] = {IN_PUSH, AM_IMP, RT_DE}, + [0xD7] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x10}, + [0xD8] = {IN_RET, AM_IMP, RT_NONE, RT_NONE, CT_C}, + [0xD9] = {IN_RETI}, + [0xDA] = {IN_JP, AM_D16, RT_NONE, RT_NONE, CT_C}, + [0xDC] = {IN_CALL, AM_D16, RT_NONE, RT_NONE, CT_C}, + [0xDF] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x18}, //0xEX [0xE0] = {IN_LDH, AM_A8_R, RT_NONE, RT_A}, + [0xE1] = {IN_POP, AM_IMP, RT_HL}, [0xE2] = {IN_LD, AM_MR_R, RT_C, RT_A}, + [0xE5] = {IN_PUSH, AM_IMP, RT_HL}, + [0xE7] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x20}, + [0xE9] = {IN_JP, AM_MR, RT_HL}, [0xEA] = {IN_LD, AM_A16_R, RT_NONE, RT_A}, + [0xEF] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x28}, //0xFX [0xF0] = {IN_LDH, AM_R_A8, RT_A}, + [0xF1] = {IN_POP, AM_IMP, RT_AF}, [0xF2] = {IN_LD, AM_R_MR, RT_A, RT_C}, [0xF3] = {IN_DI}, + [0xF5] = {IN_PUSH, AM_IMP, RT_AF}, + [0xF7] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x30}, [0xFA] = {IN_LD, AM_R_A16, RT_A}, + [0xFF] = {IN_RST, AM_IMP, RT_NONE, RT_NONE, CT_NONE, 0x38} }; instruction *instruction_by_opcode(u8 opcode) { diff --git a/lib/stack.c b/lib/stack.c new file mode 100644 index 0000000..c602823 --- /dev/null +++ b/lib/stack.c @@ -0,0 +1,23 @@ +#include +#include +#include + +void stack_push(u8 data){ + cpu_get_regs()->sp--; + bus_write(cpu_get_regs()->sp, data); +} + +void stack_push16(u16 data){ + stack_push((data >> 8) & 0xFF); + stack_push(data & 0xFF); +} + +u8 stack_pop(){ + return bus_read(cpu_get_regs()->sp++); +} + +u16 stack_pop16(){ + u16 lo = stack_pop(); + u16 hi = stack_pop(); + return (hi << 8) || lo; +}