Finished CPU instructions and created ui window.

This commit is contained in:
Samuel Walker 2025-01-31 14:39:38 -07:00
parent 83c5a7cbe6
commit 9a6dc67c3e
Signed by: piwalker
GPG Key ID: BE1F84BF85111255
12 changed files with 265 additions and 33 deletions

View File

@ -30,7 +30,9 @@ typedef struct {
bool stepping;
bool int_master_enabled;
bool enabling_ime;
u8 ie_register;
u8 int_flags;
} cpu_context;
void cpu_init();
@ -41,6 +43,8 @@ typedef void (*IN_PROC)(cpu_context *);
IN_PROC inst_get_processor(in_type type);
#define CPU_FLAG_Z BIT(ctx->regs.f, 7)
#define CPU_FLAG_N BIT(ctx->regs.f, 6)
#define CPU_FLAG_H BIT(ctx->regs.f, 5)
#define CPU_FLAG_C BIT(ctx->regs.f, 4)
u16 cpu_read_reg(reg_type rt);
@ -56,4 +60,7 @@ void fetch_data();
u8 cpu_get_ie_register();
void cpu_set_ie_register(u8 ie);
cpu_registers *cpu_get_regs();
cpu_registers *cpu_get_regs();
u8 cpu_get_int_flags();
void cpu_set_int_flags(u8 value);

View File

@ -5,6 +5,7 @@
typedef struct {
bool paused;
bool running;
bool die;
u64 ticks;
} emu_context;

16
include/interrupts.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <common.h>
#include <cpu.h>
typedef enum {
IT_VBLANK = 1,
IT_LCD_STAT = 2,
IT_TIMER = 4,
IT_SERIAL = 8,
IT_JOYPAD = 16
} interrupt_type;
void cpu_request_interrupt(interrupt_type t);
void cpu_handle_interrupts(cpu_context *ctx);

9
include/ui.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <common.h>
static const int SCREEN_WIDTH = 1024;
static const int SCREEN_HEIGHT = 768;
void ui_init();
void ui_handle_events();

View File

@ -25,7 +25,8 @@ u8 bus_read(u16 address) {
//Char/Map Data
//TODO
printf("UNSUPPORTED bus_read(%04X)\n", address);
NO_IMPL
//NO_IMPL
return 0;
} else if (address < 0xC000) {
//Cartridge RAM
return cart_read(address);
@ -39,7 +40,8 @@ u8 bus_read(u16 address) {
//OAM
//TODO
printf("UNSUPPORTED bus_read(%04X)\n", address);
NO_IMPL
//NO_IMPL
return 0;
} else if (address < 0xFF00) {
//reserved unusable
return 0;
@ -48,6 +50,7 @@ u8 bus_read(u16 address) {
//TODO
printf("UNSUPPORTED bus_read(%04X)\n", address);
//NO_IMPL
return 0;
} else if (address == 0xFFFF) {
//CPU ENABLE REGISTER
//TODO
@ -65,7 +68,7 @@ void bus_write(u16 address, u8 value) {
//Char/Map Data
//TODO
printf("UNSUPPORTED bus_write(%04X)\n", address);
NO_IMPL
//NO_IMPL
} else if (address < 0xC000) {
//Cartridge RAM
cart_write(address, value);
@ -81,7 +84,7 @@ void bus_write(u16 address, u8 value) {
//OAM
//TODO
printf("UNSUPPORTED bus_write(%04X)\n", address);
NO_IMPL
//NO_IMPL
} else if (address < 0xFF00) {
//reserved unusable
return;

View File

@ -2,6 +2,7 @@
#include <bus.h>
#include <common.h>
#include <emu.h>
#include <interrupts.h>
cpu_context ctx = {0};
@ -44,6 +45,22 @@ bool cpu_step() {
exit(-7);
}
execute();
} else {
//is halted
emu_cycles(1);
if(ctx.int_flags) {
ctx.halted = false;
}
}
if(ctx.int_master_enabled) {
cpu_handle_interrupts(&ctx);
ctx.enabling_ime = false;
}
if(ctx.enabling_ime) {
ctx.int_master_enabled = true;
}
return true;

View File

@ -33,6 +33,46 @@ static void proc_nop(cpu_context *ctx) {
}
static void proc_daa(cpu_context *ctx) {
u8 u = 0;
int fc = 0;
if(CPU_FLAG_H || (!CPU_FLAG_N && (ctx->regs.a & 0xF) >9)) {
u = 6;
}
if(CPU_FLAG_C || (!CPU_FLAG_N && ctx->regs.a > 0x99)) {
u |= 0x60;
fc = 1;
}
ctx->regs.a += CPU_FLAG_N ? -u : u;
cpu_set_flags(ctx, ctx->regs.a == 0, -1, 0, fc);
}
static void proc_cpl(cpu_context *ctx) {
ctx->regs.a = -ctx->regs.a;
cpu_set_flags(ctx, -1, 1, 1, -1);
}
static void proc_scf(cpu_context *ctx) {
cpu_set_flags(ctx, -1, 0, 0, 1);
}
static void proc_ccf(cpu_context *ctx) {
cpu_set_flags(ctx, -1, 0, 0, CPU_FLAG_C ^ 1);
}
static void proc_halt(cpu_context *ctx) {
ctx->halted = true;
}
static void proc_stop(cpu_context *ctx) {
printf("CPU STOP!\n");
NO_IMPL
}
static void proc_rlca(cpu_context *ctx) {
u8 u = ctx->regs.a;
bool c = (u >> 7) & 1;
@ -51,11 +91,22 @@ static void proc_rrca(cpu_context *ctx) {
}
static void proc_rla(cpu_context *ctx) {
u8 u = ctx->regs.a;
u8 cf = CPU_FLAG_C;
u8 c = (u >> 7) & 1;
ctx->regs.a = (u << 1) | cf;
cpu_set_flags(ctx, 0, 0, 0, c);
}
static void proc_rra(cpu_context *ctx) {
u8 carry = CPU_FLAG_C;
u8 new_c = ctx->regs.a & 1;
ctx->regs.a >>= 1;
ctx->regs.a |= (carry << 7);
cpu_set_flags(ctx, 0, 0, 0, new_c);
}
static void proc_cb(cpu_context *ctx) {
@ -360,6 +411,10 @@ static void proc_di(cpu_context *ctx) {
ctx->int_master_enabled = false;
}
static void proc_ei(cpu_context *ctx) {
ctx->enabling_ime = true;
}
static void proc_ld(cpu_context *ctx) {
if(ctx->dest_is_mem) {
if(is_16_bit(ctx->cur_inst->reg_2)) {
@ -471,7 +526,18 @@ IN_PROC processors[] = {
[IN_XOR] = proc_xor,
[IN_OR] = proc_or,
[IN_CP] = proc_cp,
[IN_CB] = proc_cb
[IN_RLCA] = proc_rlca,
[IN_RRCA] = proc_rrca,
[IN_RRA] = proc_rra,
[IN_RLA] = proc_rla,
[IN_STOP] = proc_stop,
[IN_HALT] = proc_halt,
[IN_DAA] = proc_daa,
[IN_CPL] = proc_cpl,
[IN_SCF] = proc_scf,
[IN_CCF] = proc_ccf,
[IN_CB] = proc_cb,
[IN_EI] = proc_ei
};
IN_PROC inst_get_processor(in_type type) {

View File

@ -92,4 +92,12 @@ void cpu_set_reg8(reg_type rt, u8 val) {
cpu_registers *cpu_get_regs() {
return &ctx.regs;
}
u8 cpu_get_int_flags(){
return ctx.int_flags;
}
void cpu_set_int_flags(u8 value){
ctx.int_flags = value;
}

View File

@ -2,8 +2,15 @@
#include <stdio.h>
#include <cart.h>
#include <cpu.h>
#include <SDL.h>
#include <SDL_ttf.h>
#include <ui.h>
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef _UNIX
#include <pthread.h>
#include <unistd.h>
#endif
static emu_context ctx;
@ -11,28 +18,7 @@ emu_context *emu_get_context() {
return &ctx;
}
void delay(u32 ms) {
SDL_Delay(ms);
}
int emu_run(int argc, char **argv) {
if (argc < 2) {
printf("Usage: gbemu <rom_file>\n");
return -1;
}
if(!cart_load(argv[1])) {
printf("Failed to load ROM file: %s\n", argv[1]);
return -2;
}
printf("Cart loaded..\n");
SDL_Init(SDL_INIT_VIDEO);
printf("SDL INIT\n");
TTF_Init();
printf("TTF INIT\n");
DWORD WINAPI cpu_run(void *p) {
cpu_init();
ctx.running = true;
@ -56,6 +42,53 @@ int emu_run(int argc, char **argv) {
return 0;
}
void sleep_ms(int milis) {
#ifdef _WIN32
Sleep(milis);
#endif
#ifdef _UNIX
usleep(milis * 1000);
#endif
}
int emu_run(int argc, char **argv) {
if (argc < 2) {
printf("Usage: gbemu <rom_file>\n");
return -1;
}
if(!cart_load(argv[1])) {
printf("Failed to load ROM file: %s\n", argv[1]);
return -2;
}
printf("Cart loaded..\n");
ui_init();
#ifdef _WIN32
HANDLE thread = CreateThread(NULL, 0, cpu_run, NULL, 0, NULL);
if(!thread) {
fprintf(stderr, "Unable to create main CPU thread!\n");
return -1;
}
#endif
#ifdef _UNIX
pthread_t t1;
if(pthread_create(&t1, NULL, cpu_run, NULL)) {
fprintf(stderr, "Unable to create main CPU thread!\n");
return -1;
}
#endif
while(!ctx.die) {
sleep_ms(1);
ui_handle_events();
}
return 0;
}
void emu_cycles(int cpu_cycles) {
//TODO
}

34
lib/interrupts.c Normal file
View File

@ -0,0 +1,34 @@
#include <interrupts.h>
#include <stack.h>
void int_handle(cpu_context *ctx, u16 address) {
stack_push16(ctx->regs.pc);
ctx->regs.pc = address;
}
bool int_check(cpu_context *ctx, u16 address, interrupt_type t){
if(ctx->int_flags & t && ctx->ie_register & t) {
int_handle(ctx, address);
ctx->int_flags &= -t;
ctx->halted = false;
ctx->int_master_enabled = false;
return true;
}
return false;
}
void cpu_request_interrupt(interrupt_type t);
void cpu_handle_interrupts(cpu_context *ctx) {
if (int_check(ctx, 0x40, IT_VBLANK)) {
} else if(int_check(ctx, 0x48, IT_LCD_STAT)){
} else if(int_check(ctx, 0x50, IT_TIMER)){
} else if(int_check(ctx, 0x58, IT_SERIAL)){
} else if(int_check(ctx, 0x60, IT_JOYPAD)){
}
}

32
lib/ui.c Normal file
View File

@ -0,0 +1,32 @@
#include <ui.h>
#include <emu.h>
#include <SDL.h>
#include <SDL_ttf.h>
SDL_Window *sdlWindow;
SDL_Renderer *sdlRenderer;
SDL_Texture *sdlTexture;
SDL_Surface *screen;
void ui_init(){
SDL_Init(SDL_INIT_VIDEO);
printf("SDL INIT\n");
TTF_Init();
printf("TTF INIT\n");
SDL_CreateWindowAndRenderer(SCREEN_WIDTH, SCREEN_HEIGHT, 0, &sdlWindow, &sdlRenderer);
}
void ui_handle_events(){
SDL_Event e;
while(SDL_PollEvent(&e) > 0) {
if(e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_CLOSE) {
emu_get_context()->die = true;
}
}
}
void delay(u32 ms) {
SDL_Delay(ms);
}

View File

@ -4,4 +4,10 @@ FILE(GLOB SRCS *.c)
add_executable(tests ${SRCS})
target_include_directories(tests PUBLIC ../include ../build/deps/check/src ../build/deps/check)
target_link_libraries(tests PUBLIC Lib check)
add_test(NAME mytests COMMAND tests)
add_test(NAME mytests COMMAND tests)
if(WIN32)
add_definitions(-D_WIN32)
elseif(UNIX)
add_definitions(-d_UNIX)
endif()