Initial cpu and instruction parsing
This commit is contained in:
parent
945b82a3ca
commit
cd588671c4
@ -21,4 +21,7 @@ typedef struct {
|
|||||||
|
|
||||||
bool cart_load(char *cart);
|
bool cart_load(char *cart);
|
||||||
|
|
||||||
rom_header *get_rom_header();
|
rom_header *get_rom_header();
|
||||||
|
|
||||||
|
u8 cart_read(u16 address);
|
||||||
|
void cart_write(u16 address, u8 value);
|
@ -14,4 +14,6 @@ typedef uint64_t u64;
|
|||||||
#define BIT_SET(a, n, on) (on ? (a) |= (1 << n) : (a) &= !(1 << n))
|
#define BIT_SET(a, n, on) (on ? (a) |= (1 << n) : (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);
|
||||||
|
|
||||||
|
#define NO_IMPL { fprintf(stderr, "NOT YET IMPLEMENTED\n"); exit(-5); }
|
@ -1,6 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <instructions.h>
|
||||||
|
|
||||||
|
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();
|
void cpu_init();
|
||||||
bool cpu_step();
|
bool cpu_step();
|
@ -9,4 +9,6 @@ typedef struct {
|
|||||||
} emu_context;
|
} emu_context;
|
||||||
|
|
||||||
int emu_run(int, char**);
|
int emu_run(int, char**);
|
||||||
emu_context *emu_get_context();
|
emu_context *emu_get_context();
|
||||||
|
|
||||||
|
void emu_cycles(int cpu_cycles);
|
111
include/instructions.h
Normal file
111
include/instructions.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
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);
|
32
lib/bus.c
32
lib/bus.c
@ -0,0 +1,32 @@
|
|||||||
|
#include <bus.h>
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
11
lib/cart.c
11
lib/cart.c
@ -173,4 +173,15 @@ bool cart_load(char *cart) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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
|
||||||
}
|
}
|
58
lib/cpu.c
58
lib/cpu.c
@ -1,10 +1,64 @@
|
|||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
|
#include <bus.h>
|
||||||
|
|
||||||
|
cpu_context ctx = {0};
|
||||||
|
|
||||||
void cpu_init() {
|
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() {
|
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;
|
||||||
}
|
}
|
29
lib/cpu_util.c
Normal file
29
lib/cpu_util.c
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <cpu.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -54,4 +54,8 @@ int emu_run(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emu_cycles(int cpu_cycles) {
|
||||||
|
//TODO
|
||||||
}
|
}
|
22
lib/instructions.c
Normal file
22
lib/instructions.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <instructions.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
@ -7,11 +7,6 @@
|
|||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <cart.h>
|
#include <cart.h>
|
||||||
|
|
||||||
START_TEST(test_nothing) {
|
|
||||||
bool b = cpu_step();
|
|
||||||
ck_assert_uint_eq(b, false);
|
|
||||||
} END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_cart) {
|
START_TEST(test_cart) {
|
||||||
bool b = cart_load("../../roms/cpu_instrs.gb");
|
bool b = cart_load("../../roms/cpu_instrs.gb");
|
||||||
ck_assert_uint_eq(b, true);
|
ck_assert_uint_eq(b, true);
|
||||||
@ -29,7 +24,6 @@ Suite *stack_suite() {
|
|||||||
Suite *s = suite_create("emu");
|
Suite *s = suite_create("emu");
|
||||||
TCase *tc = tcase_create("core");
|
TCase *tc = tcase_create("core");
|
||||||
|
|
||||||
tcase_add_test(tc, test_nothing);
|
|
||||||
tcase_add_test(tc, test_cart);
|
tcase_add_test(tc, test_cart);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user