diff --git a/include/cart.h b/include/cart.h index 464625e..f991e20 100644 --- a/include/cart.h +++ b/include/cart.h @@ -21,4 +21,7 @@ typedef struct { bool cart_load(char *cart); -rom_header *get_rom_header(); \ No newline at end of file +rom_header *get_rom_header(); + +u8 cart_read(u16 address); +void cart_write(u16 address, u8 value); \ No newline at end of file diff --git a/include/common.h b/include/common.h index 2ed67ba..9f1f784 100644 --- a/include/common.h +++ b/include/common.h @@ -14,4 +14,6 @@ typedef uint64_t u64; #define BIT_SET(a, n, on) (on ? (a) |= (1 << n) : (a) &= !(1 << n)) #define BETWEEN(a, b, c) ((a >= b) && (a <= c)) -void delay(u32 ms); \ No newline at end of file +void delay(u32 ms); + +#define NO_IMPL { fprintf(stderr, "NOT YET IMPLEMENTED\n"); exit(-5); } \ No newline at end of file diff --git a/include/cpu.h b/include/cpu.h index 1aa4e62..fb8eb3b 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -1,6 +1,34 @@ #pragma once #include +#include + +typedef struct { + u8 a; + u8 f; + u8 b; + u8 c; + u8 d; + u8 e; + u8 h; + u8 l; + u16 pc; + u16 sp; +} cpu_registers; + +typedef struct { + cpu_registers regs; + + //current fetch... + u16 fetched_data; + u16 mem_dest; + bool dest_is_mem; + u8 cur_opcode; + instruction *cur_inst; + + bool halted; + bool stepping; +} cpu_context; void cpu_init(); bool cpu_step(); \ No newline at end of file diff --git a/include/emu.h b/include/emu.h index 2b6da59..af0d9b9 100644 --- a/include/emu.h +++ b/include/emu.h @@ -9,4 +9,6 @@ typedef struct { } emu_context; int emu_run(int, char**); -emu_context *emu_get_context(); \ No newline at end of file +emu_context *emu_get_context(); + +void emu_cycles(int cpu_cycles); \ No newline at end of file diff --git a/include/instructions.h b/include/instructions.h new file mode 100644 index 0000000..82b43c0 --- /dev/null +++ b/include/instructions.h @@ -0,0 +1,111 @@ +#pragma once +#include + +typedef enum { + AM_R_D16, + AM_R_R, + AM_MR_R, + AM_R, + AM_R_D8, + AM_R_MR, + AM_R_HLI, + AM_R_HLD, + AM_HLI_R, + AM_HLD_R, + AM_R_A8, + AM_A8_R, + AM_HL_SPR, + AM_D16, + AM_D8, + AM_IMP, + AM_D16_R, + AM_MR_D8, + AM_MR, + AM_A16_R, + AM_R_A16 +} addr_mode; + +typedef enum { + RT_NONE, + RT_A, + RT_F, + RT_B, + RT_C, + RT_D, + RT_E, + RT_H, + RT_L, + RT_AF, + RT_BC, + RT_DE, + RT_HL, + RT_SP, + RT_PC +} reg_type; + +typedef enum { + IN_NONE, + IN_NOP, + IN_LD, + IN_INC, + IN_DEC, + IN_RLCA, + IN_ADD, + IN_RRCA, + IN_STOP, + IN_RLA, + IN_JR, + IN_RRA, + IN_DAA, + IN_CPL, + IN_SCF, + IN_CCF, + IN_HALT, + IN_ADC, + IN_SUB, + IN_SBC, + IN_AND, + IN_XOR, + IN_OR, + IN_CP, + IN_POP, + IN_JP, + IN_PUSH, + IN_RET, + IN_CB, + IN_CALL, + IN_RETI, + IN_LDH, + IN_JPHL, + IN_DI, + IN_EI, + IN_RST, + IN_ERR, + //CB instructions... + IN_RCL, + IN_RRC, + IN_RL, + IN_RR, + IN_SLA, + IN_SRA, + IN_SWAP, + IN_SRL, + IN_BIT, + IN_RES, + IN_SET +} in_type; + +typedef enum { + CT_NONE, CT_NZ, CT_Z, CT_NC, CT_C +} cond_type; + +typedef struct { + in_type type; + addr_mode mode; + reg_type reg_1; + reg_type reg_2; + cond_type cond; + u8 param; +} instruction; + +instruction *instruction_by_opcode(u8 opcode); \ No newline at end of file diff --git a/lib/bus.c b/lib/bus.c index e69de29..a116bed 100644 --- a/lib/bus.c +++ b/lib/bus.c @@ -0,0 +1,32 @@ +#include + +// 0x0000 - 0x3FFF : ROM Bank 0 +// 0x4000 - 0x7FFF : ROM Bank 1 - Switchable +// 0x8000 - 0x97FF : CHR RAM +// 0x9800 - 0x9BFF : BG Map 1 +// 0x9C00 - 0x9FFF : BG Map 2 +// 0xA000 - 0xBFFF : Cartridge RAM +// 0xC000 - 0xCFFF : RAM Bank 0 +// 0xD000 - 0xDFFF : RAM Bank 1-7 - switchable - Color only +// 0xE000 - 0xFDFF : Reserved - Echo RAM +// 0xFE00 - 0xFE9F : Object Attribute Memory +// 0xFEA0 - 0xFEFF : Reserved - Unusable +// 0xFF00 - 0xFF7F : I/O Registers +// 0xFF80 - 0xFFFE : Zero Page + +u8 bus_read(u16 address) { + if(address < 0x8000) { + return cart_read(address); + } + + NO_IMPL +} + +void bus_write(u16 address, u8 value) { + if(address < 0x8000) { + cart_write(address); + return; + } + + NO_IMPL +} \ No newline at end of file diff --git a/lib/cart.c b/lib/cart.c index 39753b8..5cc5fdc 100644 --- a/lib/cart.c +++ b/lib/cart.c @@ -173,4 +173,15 @@ bool cart_load(char *cart) { } return true; +} + +u8 cart_read(u16 address){ + //for now ROM ONLY type supported... + + return ctx.rom_data[address]; +} + +void cart_write(u16 address, u8 value){ + + NO_IMPL } \ No newline at end of file diff --git a/lib/cpu.c b/lib/cpu.c index dbb84fb..ccbb900 100644 --- a/lib/cpu.c +++ b/lib/cpu.c @@ -1,10 +1,64 @@ #include +#include + +cpu_context ctx = {0}; void cpu_init() { + ctx.regs.pc = 0x100; +} +static void fetch_instruction() { + ctx.cur_opcode = bus_read(ctx.regs.pc++); + ctx.cur_inst = instruction_by_opcode(ctx.cur_opcode); + if(ctx.cur_inst == NULL){ + printf("Unknown Instruction! %d\n", ctx.cur_opcode); + exit(-7); + } +} + +static void fetch_data() { + ctx.mem_dest = 0; + ctx.dest_is_mem = false; + + switch(ctx.cur_inst->mode) { + case AM_IMP: return; + case AM_R: + ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_1); + return; + case AM_R_D8: + ctx.fetched_data = bus_read(ctx.regs.pc); + emu_cycles(1); + ctx.regs.pc++; + return; + case AM_D16: { + u16 lo = bus_read(ctx.regs.pc); + emu_cycles(1); + u16 hi = bus_read(ctx.regs.pc+1); + emu_cycles(1); + ctx.fetched_data = lo | (hi << 8); + ctx.regs.pc += 2; + return; + } + default: + printf("Unknown Addressing Mode! %d\n", ctx.cur_inst->mode); + exit(-7); + return; + } +} + +static void execute() { + printf("\tNot executing yet...\n"); } bool cpu_step() { - printf("Cpu not yet implemented.\n"); - return false; + + if(!ctx.halted) { + u16 pc = ctx.regs.pc; + fetch_instruction(); + fetch_data(); + printf("Executing Instruction: %02X PC: %04X\n", ctx.cur_opcode, pc); + execute(); + } + + return true; } \ No newline at end of file diff --git a/lib/cpu_util.c b/lib/cpu_util.c new file mode 100644 index 0000000..8cce035 --- /dev/null +++ b/lib/cpu_util.c @@ -0,0 +1,29 @@ +#include + +extern cpu_context ctx; + +u16 reverse(u16 n) { + return ((n & 0XFF00) >> 8) | ((n & 0x00FF) << 8); +} + +u16 cpu_read_reg(reg_type rt) { + switch(rt) { + case RT_A: return ctx.regs.a; + case RT_F: return ctx.regs.f; + case RT_B: return ctx.regs.b; + case RT_C: return ctx.regs.c; + case RT_D: return ctx.regs.d; + case RT_E: return ctx.regs.e; + case RT_H: return ctx.regs.h; + case RT_L: return ctx.regs.l; + + case RT_AF: return reverse(*((u16 *)&ctx.regs.a)); + case RT_BC: return reverse(*((u16 *)&ctx.regs.b)); + case RT_DE: return reverse(*((u16 *)&ctx.regs.d)); + case RT_HL: return reverse(*((u16 *)&ctx.regs.h)); + + case RT_PC: return ctx.regs.pc; + case RT_SP: return ctx.regs.sp; + default: return 0; + } +} \ No newline at end of file diff --git a/lib/emu.c b/lib/emu.c index 5eeb652..a9cb5e8 100644 --- a/lib/emu.c +++ b/lib/emu.c @@ -54,4 +54,8 @@ int emu_run(int argc, char **argv) { } return 0; +} + +void emu_cycles(int cpu_cycles) { + //TODO } \ No newline at end of file diff --git a/lib/instructions.c b/lib/instructions.c new file mode 100644 index 0000000..27db91e --- /dev/null +++ b/lib/instructions.c @@ -0,0 +1,22 @@ +#include +#include + +instruction instructions[0x100] = { + [0x00] = {IN_NOP, AM_IMP}, + + [0x05] = {IN_DEC, AM_R, RT_B}, + + [0x0E] = {IN_LD, AM_R_D8, RT_C}, + + [0xAF] = {IN_XOR, AM_R, RT_A}, + + [0xC3] = {IN_JP, AM_D16}, +}; + +instruction *instruction_by_opcode(u8 opcode) { + if (instructions[opcode].type == IN_NONE) { + return NULL; + } + + return &instructions[opcode]; +} \ No newline at end of file diff --git a/tests/test.c b/tests/test.c index f7bb279..f98e864 100644 --- a/tests/test.c +++ b/tests/test.c @@ -7,11 +7,6 @@ #include #include -START_TEST(test_nothing) { - bool b = cpu_step(); - ck_assert_uint_eq(b, false); -} END_TEST - START_TEST(test_cart) { bool b = cart_load("../../roms/cpu_instrs.gb"); ck_assert_uint_eq(b, true); @@ -29,7 +24,6 @@ Suite *stack_suite() { Suite *s = suite_create("emu"); TCase *tc = tcase_create("core"); - tcase_add_test(tc, test_nothing); tcase_add_test(tc, test_cart); suite_add_tcase(s, tc);