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 stepping;
|
||||||
|
|
||||||
bool int_master_enabled;
|
bool int_master_enabled;
|
||||||
|
bool enabling_ime;
|
||||||
u8 ie_register;
|
u8 ie_register;
|
||||||
|
u8 int_flags;
|
||||||
} cpu_context;
|
} cpu_context;
|
||||||
|
|
||||||
void cpu_init();
|
void cpu_init();
|
||||||
@ -41,6 +43,8 @@ typedef void (*IN_PROC)(cpu_context *);
|
|||||||
IN_PROC inst_get_processor(in_type type);
|
IN_PROC inst_get_processor(in_type type);
|
||||||
|
|
||||||
#define CPU_FLAG_Z BIT(ctx->regs.f, 7)
|
#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)
|
#define CPU_FLAG_C BIT(ctx->regs.f, 4)
|
||||||
|
|
||||||
u16 cpu_read_reg(reg_type rt);
|
u16 cpu_read_reg(reg_type rt);
|
||||||
@ -57,3 +61,6 @@ u8 cpu_get_ie_register();
|
|||||||
void cpu_set_ie_register(u8 ie);
|
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);
|
@ -5,6 +5,7 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
bool paused;
|
bool paused;
|
||||||
bool running;
|
bool running;
|
||||||
|
bool die;
|
||||||
u64 ticks;
|
u64 ticks;
|
||||||
} emu_context;
|
} 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
|
//Char/Map Data
|
||||||
//TODO
|
//TODO
|
||||||
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
||||||
NO_IMPL
|
//NO_IMPL
|
||||||
|
return 0;
|
||||||
} else if (address < 0xC000) {
|
} else if (address < 0xC000) {
|
||||||
//Cartridge RAM
|
//Cartridge RAM
|
||||||
return cart_read(address);
|
return cart_read(address);
|
||||||
@ -39,7 +40,8 @@ u8 bus_read(u16 address) {
|
|||||||
//OAM
|
//OAM
|
||||||
//TODO
|
//TODO
|
||||||
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
||||||
NO_IMPL
|
//NO_IMPL
|
||||||
|
return 0;
|
||||||
} else if (address < 0xFF00) {
|
} else if (address < 0xFF00) {
|
||||||
//reserved unusable
|
//reserved unusable
|
||||||
return 0;
|
return 0;
|
||||||
@ -48,6 +50,7 @@ u8 bus_read(u16 address) {
|
|||||||
//TODO
|
//TODO
|
||||||
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
printf("UNSUPPORTED bus_read(%04X)\n", address);
|
||||||
//NO_IMPL
|
//NO_IMPL
|
||||||
|
return 0;
|
||||||
} else if (address == 0xFFFF) {
|
} else if (address == 0xFFFF) {
|
||||||
//CPU ENABLE REGISTER
|
//CPU ENABLE REGISTER
|
||||||
//TODO
|
//TODO
|
||||||
@ -65,7 +68,7 @@ void bus_write(u16 address, u8 value) {
|
|||||||
//Char/Map Data
|
//Char/Map Data
|
||||||
//TODO
|
//TODO
|
||||||
printf("UNSUPPORTED bus_write(%04X)\n", address);
|
printf("UNSUPPORTED bus_write(%04X)\n", address);
|
||||||
NO_IMPL
|
//NO_IMPL
|
||||||
} else if (address < 0xC000) {
|
} else if (address < 0xC000) {
|
||||||
//Cartridge RAM
|
//Cartridge RAM
|
||||||
cart_write(address, value);
|
cart_write(address, value);
|
||||||
@ -81,7 +84,7 @@ void bus_write(u16 address, u8 value) {
|
|||||||
//OAM
|
//OAM
|
||||||
//TODO
|
//TODO
|
||||||
printf("UNSUPPORTED bus_write(%04X)\n", address);
|
printf("UNSUPPORTED bus_write(%04X)\n", address);
|
||||||
NO_IMPL
|
//NO_IMPL
|
||||||
} else if (address < 0xFF00) {
|
} else if (address < 0xFF00) {
|
||||||
//reserved unusable
|
//reserved unusable
|
||||||
return;
|
return;
|
||||||
|
17
lib/cpu.c
17
lib/cpu.c
@ -2,6 +2,7 @@
|
|||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <emu.h>
|
#include <emu.h>
|
||||||
|
#include <interrupts.h>
|
||||||
|
|
||||||
cpu_context ctx = {0};
|
cpu_context ctx = {0};
|
||||||
|
|
||||||
@ -44,6 +45,22 @@ bool cpu_step() {
|
|||||||
exit(-7);
|
exit(-7);
|
||||||
}
|
}
|
||||||
execute();
|
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;
|
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) {
|
static void proc_rlca(cpu_context *ctx) {
|
||||||
u8 u = ctx->regs.a;
|
u8 u = ctx->regs.a;
|
||||||
bool c = (u >> 7) & 1;
|
bool c = (u >> 7) & 1;
|
||||||
@ -51,11 +91,22 @@ static void proc_rrca(cpu_context *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void proc_rla(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) {
|
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) {
|
static void proc_cb(cpu_context *ctx) {
|
||||||
@ -360,6 +411,10 @@ static void proc_di(cpu_context *ctx) {
|
|||||||
ctx->int_master_enabled = false;
|
ctx->int_master_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void proc_ei(cpu_context *ctx) {
|
||||||
|
ctx->enabling_ime = true;
|
||||||
|
}
|
||||||
|
|
||||||
static void proc_ld(cpu_context *ctx) {
|
static void proc_ld(cpu_context *ctx) {
|
||||||
if(ctx->dest_is_mem) {
|
if(ctx->dest_is_mem) {
|
||||||
if(is_16_bit(ctx->cur_inst->reg_2)) {
|
if(is_16_bit(ctx->cur_inst->reg_2)) {
|
||||||
@ -471,7 +526,18 @@ IN_PROC processors[] = {
|
|||||||
[IN_XOR] = proc_xor,
|
[IN_XOR] = proc_xor,
|
||||||
[IN_OR] = proc_or,
|
[IN_OR] = proc_or,
|
||||||
[IN_CP] = proc_cp,
|
[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) {
|
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() {
|
cpu_registers *cpu_get_regs() {
|
||||||
return &ctx.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 <stdio.h>
|
||||||
#include <cart.h>
|
#include <cart.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <SDL.h>
|
#include <ui.h>
|
||||||
#include <SDL_ttf.h>
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
#ifdef _UNIX
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static emu_context ctx;
|
static emu_context ctx;
|
||||||
|
|
||||||
@ -11,28 +18,7 @@ emu_context *emu_get_context() {
|
|||||||
return &ctx;
|
return &ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delay(u32 ms) {
|
DWORD WINAPI cpu_run(void *p) {
|
||||||
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");
|
|
||||||
|
|
||||||
cpu_init();
|
cpu_init();
|
||||||
|
|
||||||
ctx.running = true;
|
ctx.running = true;
|
||||||
@ -56,6 +42,53 @@ int emu_run(int argc, char **argv) {
|
|||||||
return 0;
|
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) {
|
void emu_cycles(int cpu_cycles) {
|
||||||
//TODO
|
//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_include_directories(tests PUBLIC ../include ../build/deps/check/src ../build/deps/check)
|
||||||
target_link_libraries(tests PUBLIC Lib 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()
|
Loading…
Reference in New Issue
Block a user