Finished CPU instructions and created ui window.
This commit is contained in:
parent
83c5a7cbe6
commit
9a6dc67c3e
@ -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);
|
||||
@ -57,3 +61,6 @@ u8 cpu_get_ie_register();
|
||||
void cpu_set_ie_register(u8 ie);
|
||||
|
||||
cpu_registers *cpu_get_regs();
|
||||
|
||||
u8 cpu_get_int_flags();
|
||||
void cpu_set_int_flags(u8 value);
|
@ -5,6 +5,7 @@
|
||||
typedef struct {
|
||||
bool paused;
|
||||
bool running;
|
||||
bool die;
|
||||
u64 ticks;
|
||||
} emu_context;
|
||||
|
||||
|
16
include/interrupts.h
Normal file
16
include/interrupts.h
Normal 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
9
include/ui.h
Normal 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();
|
11
lib/bus.c
11
lib/bus.c
@ -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;
|
||||
|
17
lib/cpu.c
17
lib/cpu.c
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -93,3 +93,11 @@ 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;
|
||||
}
|
81
lib/emu.c
81
lib/emu.c
@ -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
34
lib/interrupts.c
Normal 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
32
lib/ui.c
Normal 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);
|
||||
}
|
@ -5,3 +5,9 @@ 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)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-D_WIN32)
|
||||
elseif(UNIX)
|
||||
add_definitions(-d_UNIX)
|
||||
endif()
|
Loading…
Reference in New Issue
Block a user