LD, LDH, WRAM, and HRAM
This commit is contained in:
parent
1bf98447a3
commit
022c24dd35
@ -4,3 +4,6 @@
|
|||||||
|
|
||||||
u8 bus_read(u16 address);
|
u8 bus_read(u16 address);
|
||||||
void bus_write(u16 address, u8 value);
|
void bus_write(u16 address, u8 value);
|
||||||
|
|
||||||
|
u16 bus_read16(u16 address);
|
||||||
|
void bus_write16(u16 address, u16 value);
|
@ -30,6 +30,7 @@ typedef struct {
|
|||||||
bool stepping;
|
bool stepping;
|
||||||
|
|
||||||
bool int_master_enabled;
|
bool int_master_enabled;
|
||||||
|
u8 ie_register;
|
||||||
} cpu_context;
|
} cpu_context;
|
||||||
|
|
||||||
void cpu_init();
|
void cpu_init();
|
||||||
@ -43,3 +44,10 @@ IN_PROC inst_get_processor(in_type type);
|
|||||||
#define CPU_FLAG_C BIT(ctx->regs.f, 4)
|
#define CPU_FLAG_C BIT(ctx->regs.f, 4)
|
||||||
|
|
||||||
u16 cpu_read_reg(reg_type rt);
|
u16 cpu_read_reg(reg_type rt);
|
||||||
|
|
||||||
|
void cpu_set_reg(reg_type rt, u16 val);
|
||||||
|
|
||||||
|
void fetch_data();
|
||||||
|
|
||||||
|
u8 cpu_get_ie_register();
|
||||||
|
void cpu_set_ie_register(u8 ie);
|
9
include/ram.h
Normal file
9
include/ram.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
u8 wram_read(u16 address);
|
||||||
|
void wram_write(u16 address, u8 value);
|
||||||
|
|
||||||
|
u8 hram_read(u16 address);
|
||||||
|
void hram_write(u16 address, u8 value);
|
86
lib/bus.c
86
lib/bus.c
@ -1,4 +1,8 @@
|
|||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <cart.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
#include <ram.h>
|
||||||
|
|
||||||
// 0x0000 - 0x3FFF : ROM Bank 0
|
// 0x0000 - 0x3FFF : ROM Bank 0
|
||||||
// 0x4000 - 0x7FFF : ROM Bank 1 - Switchable
|
// 0x4000 - 0x7FFF : ROM Bank 1 - Switchable
|
||||||
@ -17,16 +21,92 @@
|
|||||||
u8 bus_read(u16 address) {
|
u8 bus_read(u16 address) {
|
||||||
if(address < 0x8000) {
|
if(address < 0x8000) {
|
||||||
return cart_read(address);
|
return cart_read(address);
|
||||||
|
} else if (address < 0xA000) {
|
||||||
|
//Char/Map Data
|
||||||
|
//TODO
|
||||||
|
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
||||||
|
NO_IMPL
|
||||||
|
} else if (address < 0xC000) {
|
||||||
|
//Cartridge RAM
|
||||||
|
return cart_read(address);
|
||||||
|
} else if (address < 0xE000) {
|
||||||
|
//WRAM (Working RAM)
|
||||||
|
return wram_read(address);
|
||||||
|
} else if (address < 0xFE00) {
|
||||||
|
//reserved echo ram...
|
||||||
|
return 0;
|
||||||
|
} else if (address < 0xFEA0) {
|
||||||
|
//OAM
|
||||||
|
//TODO
|
||||||
|
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
||||||
|
NO_IMPL
|
||||||
|
} else if (address < 0xFF00) {
|
||||||
|
//reserved unusable
|
||||||
|
return 0;
|
||||||
|
} else if (address < 0xFF80) {
|
||||||
|
//IO registers
|
||||||
|
//TODO
|
||||||
|
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
||||||
|
//NO_IMPL
|
||||||
|
} else if (address == 0xFFFF) {
|
||||||
|
//CPU ENABLE REGISTER
|
||||||
|
//TODO
|
||||||
|
return cpu_get_ie_register();
|
||||||
}
|
}
|
||||||
|
|
||||||
NO_IMPL
|
return hram_read(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bus_write(u16 address, u8 value) {
|
void bus_write(u16 address, u8 value) {
|
||||||
if(address < 0x8000) {
|
if(address < 0x8000) {
|
||||||
cart_write(address);
|
cart_write(address, value);
|
||||||
|
return;
|
||||||
|
} else if (address < 0xA000) {
|
||||||
|
//Char/Map Data
|
||||||
|
//TODO
|
||||||
|
printf("UNSUPPORTED bus_write(%04X)\n", address);
|
||||||
|
NO_IMPL
|
||||||
|
} else if (address < 0xC000) {
|
||||||
|
//Cartridge RAM
|
||||||
|
cart_write(address, value);
|
||||||
|
return;
|
||||||
|
} else if (address < 0xE000) {
|
||||||
|
//WRAM (Working RAM)
|
||||||
|
wram_write(address, value);
|
||||||
|
return;
|
||||||
|
} else if (address < 0xFE00) {
|
||||||
|
//reserved echo ram...
|
||||||
|
return;
|
||||||
|
} else if (address < 0xFEA0) {
|
||||||
|
//OAM
|
||||||
|
//TODO
|
||||||
|
printf("UNSUPPORTED bus_write(%04X)\n", address);
|
||||||
|
NO_IMPL
|
||||||
|
} else if (address < 0xFF00) {
|
||||||
|
//reserved unusable
|
||||||
|
return;
|
||||||
|
} else if (address < 0xFF80) {
|
||||||
|
//IO registers
|
||||||
|
//TODO
|
||||||
|
printf("UNSUPPORTED bus_write(%04X)\n", address);
|
||||||
|
//NO_IMPL
|
||||||
|
return;
|
||||||
|
} else if (address == 0xFFFF) {
|
||||||
|
//CPU ENABLE REGISTER
|
||||||
|
cpu_set_ie_register(value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NO_IMPL
|
hram_write(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 bus_read16(u16 address) {
|
||||||
|
u16 lo = bus_read(address);
|
||||||
|
u16 hi = bus_read(address+1);
|
||||||
|
return lo | (hi << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bus_write16(u16 address, u16 value) {
|
||||||
|
bus_write(address+1, (value >> 8) & 0xFF);
|
||||||
|
bus_write(address, value * 0xFF);
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
#include <cart.h>
|
#include <cart.h>
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char filename[1024];
|
char filename[1024];
|
||||||
@ -182,6 +183,6 @@ u8 cart_read(u16 address){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cart_write(u16 address, u8 value){
|
void cart_write(u16 address, u8 value){
|
||||||
|
printf("UNSUPPORTED cart_write(%04X)\n");
|
||||||
NO_IMPL
|
//NO_IMPL
|
||||||
}
|
}
|
47
lib/cpu.c
47
lib/cpu.c
@ -1,11 +1,11 @@
|
|||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
cpu_context ctx = {0};
|
cpu_context ctx = {0};
|
||||||
|
|
||||||
void cpu_init() {
|
void cpu_init() {
|
||||||
ctx.regs.pc = 0x100;
|
ctx.regs.pc = 0x100;
|
||||||
ctx.regs.a = 0x01;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fetch_instruction() {
|
static void fetch_instruction() {
|
||||||
@ -13,42 +13,11 @@ static void fetch_instruction() {
|
|||||||
ctx.cur_inst = instruction_by_opcode(ctx.cur_opcode);
|
ctx.cur_inst = instruction_by_opcode(ctx.cur_opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fetch_data() {
|
|
||||||
ctx.mem_dest = 0;
|
|
||||||
ctx.dest_is_mem = false;
|
|
||||||
|
|
||||||
if(ctx.cur_inst == NULL) return;
|
|
||||||
|
|
||||||
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 (%02X)\n", ctx.cur_inst->mode, ctx.cur_opcode);
|
|
||||||
exit(-7);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void execute() {
|
static void execute() {
|
||||||
IN_PROC proc = inst_get_processor(ctx.cur_inst->type);
|
IN_PROC proc = inst_get_processor(ctx.cur_inst->type);
|
||||||
|
|
||||||
if (!proc) {
|
if (!proc) {
|
||||||
|
printf("no implementation(%02X)\n", ctx.cur_opcode);
|
||||||
NO_IMPL
|
NO_IMPL
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,14 +29,22 @@ bool cpu_step() {
|
|||||||
if(!ctx.halted) {
|
if(!ctx.halted) {
|
||||||
u16 pc = ctx.regs.pc;
|
u16 pc = ctx.regs.pc;
|
||||||
fetch_instruction();
|
fetch_instruction();
|
||||||
fetch_data();
|
printf("%04X: %-7s (%02X %02X %02X) AF: %02X%02X BC: %02X%02X DE: %02X%02X HL: %02X%02X SP: %04X PC: %04X\n", pc, inst_name(ctx.cur_inst->type), ctx.cur_opcode, bus_read(pc+1), bus_read(pc+2), ctx.regs.a, ctx.regs.f, ctx.regs.b, ctx.regs.c, ctx.regs.d, ctx.regs.e, ctx.regs.h, ctx.regs.l, ctx.regs.sp, ctx.regs.pc);
|
||||||
printf("%04X: %-7s (%02X %02X %02X) A: %02X B: %02X C: %02X\n", pc, inst_name(ctx.cur_inst->type), ctx.cur_opcode, bus_read(pc+1), bus_read(pc+2), ctx.regs.a, ctx.regs.b, ctx.regs.c);
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
fetch_data();
|
||||||
execute();
|
execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 cpu_get_ie_register(){
|
||||||
|
return ctx.ie_register;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_set_ie_register(u8 ie){
|
||||||
|
ctx.ie_register = ie;
|
||||||
|
}
|
137
lib/cpu_fetch.c
Normal file
137
lib/cpu_fetch.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include <cpu.h>
|
||||||
|
#include <bus.h>
|
||||||
|
#include <emu.h>
|
||||||
|
|
||||||
|
extern cpu_context ctx;
|
||||||
|
|
||||||
|
void fetch_data() {
|
||||||
|
ctx.mem_dest = 0;
|
||||||
|
ctx.dest_is_mem = false;
|
||||||
|
|
||||||
|
if(ctx.cur_inst == NULL) return;
|
||||||
|
|
||||||
|
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_R:
|
||||||
|
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
||||||
|
case AM_R_D8:
|
||||||
|
ctx.fetched_data = bus_read(ctx.regs.pc);
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.regs.pc++;
|
||||||
|
return;
|
||||||
|
case AM_R_D16:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
case AM_MR_R:
|
||||||
|
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
||||||
|
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
||||||
|
ctx.dest_is_mem = true;
|
||||||
|
|
||||||
|
if (ctx.cur_inst->reg_1 == RT_C) {
|
||||||
|
ctx.mem_dest |= 0xFF00;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case AM_R_MR: {
|
||||||
|
u16 addr = cpu_read_reg(ctx.cur_inst->reg_2);
|
||||||
|
if(ctx.cur_inst->reg_1 == RT_C) {
|
||||||
|
addr |= 0xFF00;
|
||||||
|
}
|
||||||
|
ctx.fetched_data = bus_read(addr);
|
||||||
|
emu_cycles(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AM_R_HLI:
|
||||||
|
ctx.fetched_data = bus_read(cpu_read_reg(ctx.cur_inst->reg_2));
|
||||||
|
emu_cycles(1);
|
||||||
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)+1);
|
||||||
|
return;
|
||||||
|
case AM_R_HLD:
|
||||||
|
ctx.fetched_data = bus_read(cpu_read_reg(ctx.cur_inst->reg_2));
|
||||||
|
emu_cycles(1);
|
||||||
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)-1);
|
||||||
|
return;
|
||||||
|
case AM_HLI_R:
|
||||||
|
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.dest_is_mem = true;
|
||||||
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)+1);
|
||||||
|
return;
|
||||||
|
case AM_HLD_R:
|
||||||
|
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
||||||
|
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
||||||
|
ctx.dest_is_mem = true;
|
||||||
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)-1);
|
||||||
|
return;
|
||||||
|
case AM_R_A8:
|
||||||
|
ctx.fetched_data = bus_read(bus_read(ctx.regs.pc));
|
||||||
|
emu_cycles(2);
|
||||||
|
ctx.regs.pc++;
|
||||||
|
return;
|
||||||
|
case AM_A8_R:
|
||||||
|
ctx.mem_dest = bus_read(ctx.regs.pc) | 0xFF00;
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.dest_is_mem = true;
|
||||||
|
ctx.regs.pc++;
|
||||||
|
return;
|
||||||
|
case AM_HL_SPR:
|
||||||
|
ctx.fetched_data = bus_read(ctx.regs.pc);
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.regs.pc++;
|
||||||
|
return;
|
||||||
|
case AM_D8:
|
||||||
|
ctx.fetched_data = bus_read(ctx.regs.pc);
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.regs.pc++;
|
||||||
|
return;
|
||||||
|
case AM_A16_R:
|
||||||
|
case AM_D16_R: {
|
||||||
|
u16 lo = bus_read(ctx.regs.pc);
|
||||||
|
emu_cycles(1);
|
||||||
|
u16 hi = bus_read(ctx.regs.pc+1);
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.mem_dest = lo | (hi << 8);
|
||||||
|
ctx.dest_is_mem = true;
|
||||||
|
ctx.regs.pc += 2;
|
||||||
|
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
||||||
|
} return;
|
||||||
|
|
||||||
|
case AM_MR_D8:
|
||||||
|
ctx.fetched_data = bus_read(ctx.regs.pc);
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.regs.pc++;
|
||||||
|
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
||||||
|
ctx.dest_is_mem = true;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case AM_MR:
|
||||||
|
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
||||||
|
ctx.dest_is_mem = true;
|
||||||
|
ctx.fetched_data = bus_read(cpu_read_reg(ctx.cur_inst->reg_1));
|
||||||
|
emu_cycles(1);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case AM_R_A16: {
|
||||||
|
u16 lo = bus_read(ctx.regs.pc);
|
||||||
|
emu_cycles(1);
|
||||||
|
u16 hi = bus_read(ctx.regs.pc+1);
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.fetched_data = bus_read(lo | (hi << 8));
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.regs.pc += 2;
|
||||||
|
} return;
|
||||||
|
default:
|
||||||
|
printf("Unknown Addressing Mode! %d (%02X)\n", ctx.cur_inst->mode, ctx.cur_opcode);
|
||||||
|
exit(-7);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,9 @@
|
|||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <emu.h>
|
#include <emu.h>
|
||||||
|
#include <bus.h>
|
||||||
|
|
||||||
//process CPU instructions...
|
//process CPU instructions...
|
||||||
|
|
||||||
static void proc_none(cpu_context *ctx) {
|
|
||||||
printf("INVALID INSTRUCTION!\n");
|
|
||||||
exit(-7);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void proc_nop(cpu_context *ctx) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_set_flags(cpu_context *ctx, u8 z, u8 n, u8 h, u8 c){
|
void cpu_set_flags(cpu_context *ctx, u8 z, u8 n, u8 h, u8 c){
|
||||||
if (z != -1){
|
if (z != -1){
|
||||||
BIT_SET(ctx->regs.f, 7, z)
|
BIT_SET(ctx->regs.f, 7, z)
|
||||||
@ -27,6 +19,24 @@ void cpu_set_flags(cpu_context *ctx, u8 z, u8 n, u8 h, u8 c){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void proc_none(cpu_context *ctx) {
|
||||||
|
printf("INVALID INSTRUCTION!\n");
|
||||||
|
exit(-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void proc_nop(cpu_context *ctx) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
} else {
|
||||||
|
bus_write(0xFF00 | ctx->mem_dest, ctx->cur_inst->reg_2);
|
||||||
|
}
|
||||||
|
emu_cycles(1);
|
||||||
|
}
|
||||||
|
|
||||||
static void proc_xor(cpu_context *ctx) {
|
static void proc_xor(cpu_context *ctx) {
|
||||||
ctx->regs.a ^= ctx->fetched_data & 0XFF;
|
ctx->regs.a ^= ctx->fetched_data & 0XFF;
|
||||||
cpu_set_flags(ctx, ctx->regs.a == 0, 0, 0, 0);
|
cpu_set_flags(ctx, ctx->regs.a == 0, 0, 0, 0);
|
||||||
@ -37,7 +47,25 @@ static void proc_di(cpu_context *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void proc_ld(cpu_context *ctx) {
|
static void proc_ld(cpu_context *ctx) {
|
||||||
//TODO
|
if(ctx->dest_is_mem) {
|
||||||
|
if(ctx->cur_inst->reg_2 >= RT_AF) {
|
||||||
|
bus_write16(ctx->mem_dest, ctx->fetched_data);
|
||||||
|
emu_cycles(1);
|
||||||
|
} else {
|
||||||
|
bus_write(ctx->mem_dest, ctx->fetched_data);
|
||||||
|
emu_cycles(1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->cur_inst->mode == AM_HL_SPR) {
|
||||||
|
u8 hflag = (cpu_read_reg(ctx->cur_inst->reg_2) & 0xF) + (ctx->fetched_data & 0xF) >= 0x10;
|
||||||
|
u8 cflag = (cpu_read_reg(ctx->cur_inst->reg_2) & 0xFF) + (ctx->fetched_data & 0xFF) >= 0x100;
|
||||||
|
cpu_set_flags(ctx, 0, 0, hflag, cflag);
|
||||||
|
cpu_set_reg(ctx->cur_inst->reg_1, cpu_read_reg(ctx->cur_inst->reg_2) + (char)ctx->fetched_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_set_reg(ctx->cur_inst->reg_1, ctx->fetched_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_condition(cpu_context *ctx) {
|
static bool check_condition(cpu_context *ctx) {
|
||||||
@ -68,7 +96,8 @@ IN_PROC processors[] = {
|
|||||||
[IN_LD] = proc_ld,
|
[IN_LD] = proc_ld,
|
||||||
[IN_JP] = proc_jp,
|
[IN_JP] = proc_jp,
|
||||||
[IN_DI] = proc_di,
|
[IN_DI] = proc_di,
|
||||||
[IN_XOR] = proc_xor
|
[IN_XOR] = proc_xor,
|
||||||
|
[IN_LDH] = proc_ldh
|
||||||
};
|
};
|
||||||
|
|
||||||
IN_PROC inst_get_processor(in_type type) {
|
IN_PROC inst_get_processor(in_type type) {
|
||||||
|
@ -27,3 +27,25 @@ u16 cpu_read_reg(reg_type rt) {
|
|||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_set_reg(reg_type rt, u16 val) {
|
||||||
|
switch(rt) {
|
||||||
|
case RT_A: ctx.regs.a = val & 0XFF; break;
|
||||||
|
case RT_F: ctx.regs.f = val & 0XFF; break;
|
||||||
|
case RT_B: ctx.regs.b = val & 0XFF; break;
|
||||||
|
case RT_C: ctx.regs.c = val & 0XFF; break;
|
||||||
|
case RT_D: ctx.regs.d = val & 0XFF; break;
|
||||||
|
case RT_E: ctx.regs.e = val & 0XFF; break;
|
||||||
|
case RT_H: ctx.regs.h = val & 0XFF; break;
|
||||||
|
case RT_L: ctx.regs.l = val & 0XFF; break;
|
||||||
|
|
||||||
|
case RT_AF: *((u16 *)&ctx.regs.a) = reverse(val); break;
|
||||||
|
case RT_BC: *((u16 *)&ctx.regs.b) = reverse(val); break;
|
||||||
|
case RT_DE: *((u16 *)&ctx.regs.d) = reverse(val); break;
|
||||||
|
case RT_HL: *((u16 *)&ctx.regs.h) = reverse(val); break;
|
||||||
|
|
||||||
|
case RT_PC: ctx.regs.pc = val; break;
|
||||||
|
case RT_SP: ctx.regs.sp = val; break;
|
||||||
|
case RT_NONE: break;
|
||||||
|
}
|
||||||
|
}
|
@ -2,17 +2,121 @@
|
|||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
|
|
||||||
instruction instructions[0x100] = {
|
instruction instructions[0x100] = {
|
||||||
|
//0x0X
|
||||||
[0x00] = {IN_NOP, AM_IMP},
|
[0x00] = {IN_NOP, AM_IMP},
|
||||||
|
[0x01] = {IN_LD, AM_R_D16, RT_BC},
|
||||||
|
[0x02] = {IN_LD, AM_MR_R, RT_BC, RT_A},
|
||||||
[0x05] = {IN_DEC, AM_R, RT_B},
|
[0x05] = {IN_DEC, AM_R, RT_B},
|
||||||
|
[0x06] = {IN_LD, AM_R_D8, RT_B},
|
||||||
|
[0x08] = {IN_LD, AM_A16_R, RT_NONE, RT_SP},
|
||||||
|
[0x0A] = {IN_LD, AM_R_MR, RT_A, RT_BC},
|
||||||
[0x0E] = {IN_LD, AM_R_D8, RT_C},
|
[0x0E] = {IN_LD, AM_R_D8, RT_C},
|
||||||
|
//0x1X
|
||||||
|
[0x11] = {IN_LD, AM_R_D16, RT_DE},
|
||||||
|
[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},
|
||||||
|
[0x1A] = {IN_LD, AM_R_MR, RT_A, RT_DE},
|
||||||
|
[0x1E] = {IN_LD, AM_R_D8, RT_E},
|
||||||
|
//0x2X
|
||||||
|
[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},
|
||||||
|
[0x2A] = {IN_LD, AM_R_HLI, RT_A, RT_HL},
|
||||||
|
[0x2E] = {IN_LD, AM_R_D8, RT_L},
|
||||||
|
//0x3X
|
||||||
|
[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},
|
||||||
|
[0x3A] = {IN_LD, AM_R_HLD, RT_A, RT_HL},
|
||||||
|
[0x3E] = {IN_LD, AM_R_D8, RT_A},
|
||||||
|
//0x4X
|
||||||
|
[0x40] = {IN_LD, AM_R_R, RT_B, RT_B},
|
||||||
|
[0x41] = {IN_LD, AM_R_R, RT_B, RT_C},
|
||||||
|
[0x42] = {IN_LD, AM_R_R, RT_B, RT_D},
|
||||||
|
[0x43] = {IN_LD, AM_R_R, RT_B, RT_E},
|
||||||
|
[0x44] = {IN_LD, AM_R_R, RT_B, RT_H},
|
||||||
|
[0x45] = {IN_LD, AM_R_R, RT_B, RT_L},
|
||||||
|
[0x46] = {IN_LD, AM_R_MR, RT_B, RT_HL},
|
||||||
|
[0x47] = {IN_LD, AM_R_R, RT_B, RT_A},
|
||||||
|
[0x48] = {IN_LD, AM_R_R, RT_C, RT_B},
|
||||||
|
[0x49] = {IN_LD, AM_R_R, RT_C, RT_C},
|
||||||
|
[0x4A] = {IN_LD, AM_R_R, RT_C, RT_D},
|
||||||
|
[0x4B] = {IN_LD, AM_R_R, RT_C, RT_E},
|
||||||
|
[0x4C] = {IN_LD, AM_R_R, RT_C, RT_H},
|
||||||
|
[0x4D] = {IN_LD, AM_R_R, RT_C, RT_L},
|
||||||
|
[0x4E] = {IN_LD, AM_R_MR, RT_C, RT_HL},
|
||||||
|
[0x4F] = {IN_LD, AM_R_R, RT_C, RT_A},
|
||||||
|
//0x5X
|
||||||
|
[0x50] = {IN_LD, AM_R_R, RT_D, RT_B},
|
||||||
|
[0x51] = {IN_LD, AM_R_R, RT_D, RT_C},
|
||||||
|
[0x52] = {IN_LD, AM_R_R, RT_D, RT_D},
|
||||||
|
[0x53] = {IN_LD, AM_R_R, RT_D, RT_E},
|
||||||
|
[0x54] = {IN_LD, AM_R_R, RT_D, RT_H},
|
||||||
|
[0x55] = {IN_LD, AM_R_R, RT_D, RT_L},
|
||||||
|
[0x56] = {IN_LD, AM_R_MR, RT_D, RT_HL},
|
||||||
|
[0x57] = {IN_LD, AM_R_R, RT_D, RT_A},
|
||||||
|
[0x58] = {IN_LD, AM_R_R, RT_E, RT_B},
|
||||||
|
[0x59] = {IN_LD, AM_R_R, RT_E, RT_C},
|
||||||
|
[0x5A] = {IN_LD, AM_R_R, RT_E, RT_D},
|
||||||
|
[0x5B] = {IN_LD, AM_R_R, RT_E, RT_E},
|
||||||
|
[0x5C] = {IN_LD, AM_R_R, RT_E, RT_H},
|
||||||
|
[0x5D] = {IN_LD, AM_R_R, RT_E, RT_L},
|
||||||
|
[0x5E] = {IN_LD, AM_R_MR, RT_E, RT_HL},
|
||||||
|
[0x5F] = {IN_LD, AM_R_R, RT_E, RT_A},
|
||||||
|
//0x6X
|
||||||
|
[0x60] = {IN_LD, AM_R_R, RT_H, RT_B},
|
||||||
|
[0x61] = {IN_LD, AM_R_R, RT_H, RT_C},
|
||||||
|
[0x62] = {IN_LD, AM_R_R, RT_H, RT_D},
|
||||||
|
[0x63] = {IN_LD, AM_R_R, RT_H, RT_E},
|
||||||
|
[0x64] = {IN_LD, AM_R_R, RT_H, RT_H},
|
||||||
|
[0x65] = {IN_LD, AM_R_R, RT_H, RT_L},
|
||||||
|
[0x66] = {IN_LD, AM_R_MR, RT_H, RT_HL},
|
||||||
|
[0x67] = {IN_LD, AM_R_R, RT_H, RT_A},
|
||||||
|
[0x68] = {IN_LD, AM_R_R, RT_L, RT_B},
|
||||||
|
[0x69] = {IN_LD, AM_R_R, RT_L, RT_C},
|
||||||
|
[0x6A] = {IN_LD, AM_R_R, RT_L, RT_D},
|
||||||
|
[0x6B] = {IN_LD, AM_R_R, RT_L, RT_E},
|
||||||
|
[0x6C] = {IN_LD, AM_R_R, RT_L, RT_H},
|
||||||
|
[0x6D] = {IN_LD, AM_R_R, RT_L, RT_L},
|
||||||
|
[0x6E] = {IN_LD, AM_R_MR, RT_L, RT_HL},
|
||||||
|
[0x6F] = {IN_LD, AM_R_R, RT_L, RT_A},
|
||||||
|
//0x7X
|
||||||
|
[0x70] = {IN_LD, AM_MR_R, RT_HL, RT_B},
|
||||||
|
[0x71] = {IN_LD, AM_MR_R, RT_HL, RT_C},
|
||||||
|
[0x72] = {IN_LD, AM_MR_R, RT_HL, RT_D},
|
||||||
|
[0x73] = {IN_LD, AM_MR_R, RT_HL, RT_E},
|
||||||
|
[0x74] = {IN_LD, AM_MR_R, RT_HL, RT_H},
|
||||||
|
[0x75] = {IN_LD, AM_MR_R, RT_HL, RT_L},
|
||||||
|
[0x76] = {IN_HALT},
|
||||||
|
[0x77] = {IN_LD, AM_MR_R, RT_HL, RT_A},
|
||||||
|
[0x78] = {IN_LD, AM_R_R, RT_A, RT_B},
|
||||||
|
[0x79] = {IN_LD, AM_R_R, RT_A, RT_C},
|
||||||
|
[0x7A] = {IN_LD, AM_R_R, RT_A, RT_D},
|
||||||
|
[0x7B] = {IN_LD, AM_R_R, RT_A, RT_E},
|
||||||
|
[0x7C] = {IN_LD, AM_R_R, RT_A, RT_H},
|
||||||
|
[0x7D] = {IN_LD, AM_R_R, RT_A, RT_L},
|
||||||
|
[0x7E] = {IN_LD, AM_R_MR, RT_A, RT_HL},
|
||||||
|
[0x7F] = {IN_LD, AM_R_R, RT_A, RT_A},
|
||||||
|
//0x8X
|
||||||
|
//0x9X
|
||||||
|
//0xAX
|
||||||
[0xAF] = {IN_XOR, AM_R, RT_A},
|
[0xAF] = {IN_XOR, AM_R, RT_A},
|
||||||
|
//0xBX
|
||||||
|
//0xCX
|
||||||
[0xC3] = {IN_JP, AM_D16},
|
[0xC3] = {IN_JP, AM_D16},
|
||||||
|
//0xDX
|
||||||
|
//0xEX
|
||||||
|
[0xE0] = {IN_LDH, AM_A8_R, RT_NONE, RT_A},
|
||||||
|
[0xE2] = {IN_LD, AM_MR_R, RT_C, RT_A},
|
||||||
|
[0xEA] = {IN_LD, AM_A16_R, RT_NONE, RT_A},
|
||||||
|
//0xFX
|
||||||
|
[0xF0] = {IN_LDH, AM_R_A8, RT_A},
|
||||||
|
[0xF2] = {IN_LD, AM_R_MR, RT_A, RT_C},
|
||||||
[0xF3] = {IN_DI},
|
[0xF3] = {IN_DI},
|
||||||
|
[0xFA] = {IN_LD, AM_R_A16, RT_A},
|
||||||
};
|
};
|
||||||
|
|
||||||
instruction *instruction_by_opcode(u8 opcode) {
|
instruction *instruction_by_opcode(u8 opcode) {
|
||||||
|
30
lib/ram.c
Normal file
30
lib/ram.c
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <ram.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 wram[0x2000];
|
||||||
|
u8 hram[0x80];
|
||||||
|
} ram_context;
|
||||||
|
|
||||||
|
static ram_context ctx;
|
||||||
|
|
||||||
|
u8 wram_read(u16 address) {
|
||||||
|
address -= 0xC000;
|
||||||
|
|
||||||
|
return ctx.wram[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
void wram_write(u16 address, u8 value){
|
||||||
|
address -= 0xC000;
|
||||||
|
ctx.wram[address] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 hram_read(u16 address){
|
||||||
|
address -= 0xFF80;
|
||||||
|
|
||||||
|
return ctx.hram[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
void hram_write(u16 address, u8 value){
|
||||||
|
address -= 0xFF80;
|
||||||
|
ctx.hram[address] = value;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user