mirror of https://github.com/mlaux/gb6.git
Compare commits
2 Commits
1b5f02ef7a
...
8d87ee1f26
Author | SHA1 | Date |
---|---|---|
Matthew Laux | 8d87ee1f26 | |
Matthew Laux | 5735d65470 |
|
@ -1,8 +1,3 @@
|
|||
// Dear ImGui: standalone example application for SDL2 + OpenGL
|
||||
// (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.)
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/imgui_impl_sdl.h"
|
||||
#include "imgui/imgui_impl_opengl3.h"
|
||||
|
@ -10,11 +5,7 @@
|
|||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
#include <SDL_timer.h>
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <SDL_opengles2.h>
|
||||
#else
|
||||
#include <SDL_opengl.h>
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
extern "C" {
|
||||
|
@ -34,6 +25,28 @@ static const char *L_FORMAT = "L: 0x%02x";
|
|||
static const char *SP_FORMAT = "SP: 0x%02x";
|
||||
static const char *PC_FORMAT = "PC: 0x%02x";
|
||||
|
||||
unsigned char output_image[256 * 256 * 4];
|
||||
unsigned char vram_tiles[256 * 96 * 4];
|
||||
unsigned char full_address_space[0x10000];
|
||||
|
||||
struct key_input {
|
||||
int scancode;
|
||||
int button;
|
||||
int field;
|
||||
};
|
||||
|
||||
struct key_input key_inputs[] = {
|
||||
{ SDL_SCANCODE_D, BUTTON_RIGHT, FIELD_JOY },
|
||||
{ SDL_SCANCODE_A, BUTTON_LEFT, FIELD_JOY },
|
||||
{ SDL_SCANCODE_W, BUTTON_UP, FIELD_JOY },
|
||||
{ SDL_SCANCODE_S, BUTTON_DOWN, FIELD_JOY },
|
||||
{ SDL_SCANCODE_L, BUTTON_A, FIELD_ACTION },
|
||||
{ SDL_SCANCODE_K, BUTTON_B, FIELD_ACTION },
|
||||
{ SDL_SCANCODE_N, BUTTON_SELECT, FIELD_ACTION },
|
||||
{ SDL_SCANCODE_M, BUTTON_START, FIELD_ACTION },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static MemoryEditor editor;
|
||||
|
||||
GLuint make_output_texture() {
|
||||
|
@ -43,15 +56,10 @@ GLuint make_output_texture() {
|
|||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is required on WebGL for non power-of-two textures
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Same
|
||||
|
||||
return image_texture;
|
||||
}
|
||||
|
||||
unsigned char output_image[256 * 256 * 4];
|
||||
unsigned char vram_tiles[256 * 96 * 4];
|
||||
|
||||
void convert_output(struct lcd *lcd) {
|
||||
int x, y;
|
||||
int out_index = 0;
|
||||
|
@ -94,7 +102,6 @@ void convert_vram(struct dmg *dmg) {
|
|||
}
|
||||
}
|
||||
|
||||
char full_address_space[0x10000];
|
||||
void fill_memory_editor(struct dmg *dmg)
|
||||
{
|
||||
int k;
|
||||
|
@ -112,6 +119,8 @@ int main(int argc, char *argv[])
|
|||
struct lcd lcd = { 0 };
|
||||
|
||||
int executed;
|
||||
int paused = 0;
|
||||
int pause_next = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("no rom specified\n");
|
||||
|
@ -133,24 +142,13 @@ int main(int argc, char *argv[])
|
|||
|
||||
cpu.pc = 0x100;
|
||||
|
||||
// Setup SDL
|
||||
// (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
|
||||
// depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!)
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
printf("Error: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Decide GL+GLSL versions
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
// GL ES 2.0 + GLSL 100
|
||||
const char* glsl_version = "#version 100";
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
#elif defined(__APPLE__)
|
||||
#if defined(__APPLE__)
|
||||
// GL 3.2 Core + GLSL 150
|
||||
const char* glsl_version = "#version 150";
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
|
||||
|
@ -171,7 +169,7 @@ int main(int argc, char *argv[])
|
|||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
|
||||
SDL_Window* window = SDL_CreateWindow("gb6 debug", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
|
||||
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
|
||||
SDL_GL_MakeCurrent(window, gl_context);
|
||||
SDL_GL_SetSwapInterval(0); // disable vsync
|
||||
|
@ -179,9 +177,8 @@ int main(int argc, char *argv[])
|
|||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
|
@ -195,7 +192,7 @@ int main(int argc, char *argv[])
|
|||
GLuint texture = make_output_texture();
|
||||
GLuint vram_texture = make_output_texture();
|
||||
|
||||
// Our state
|
||||
// for flag checkboxes
|
||||
bool z_flag = false;
|
||||
bool n_flag = false;
|
||||
bool h_flag = false;
|
||||
|
@ -204,9 +201,14 @@ int main(int argc, char *argv[])
|
|||
// Main loop
|
||||
bool done = false;
|
||||
unsigned int lastDrawTime = 0, currentTime;
|
||||
while (!done)
|
||||
{
|
||||
dmg_step(&dmg);
|
||||
|
||||
while (!done) {
|
||||
if (!paused) {
|
||||
dmg_step(&dmg);
|
||||
}
|
||||
if (pause_next) {
|
||||
paused = 1;
|
||||
}
|
||||
|
||||
currentTime = SDL_GetTicks();
|
||||
if (currentTime >= lastDrawTime + 16) {
|
||||
|
@ -219,10 +221,25 @@ int main(int argc, char *argv[])
|
|||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
if (event.type == SDL_QUIT)
|
||||
if (event.type == SDL_QUIT) {
|
||||
done = true;
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
|
||||
}
|
||||
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE
|
||||
&& event.window.windowID == SDL_GetWindowID(window)) {
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) {
|
||||
struct key_input *key = key_inputs;
|
||||
while (key->scancode) {
|
||||
if (key->scancode == event.key.keysym.scancode) {
|
||||
dmg_set_button(&dmg, key->field, key->button, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
}
|
||||
key++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start the Dear ImGui frame
|
||||
|
@ -235,9 +252,8 @@ int main(int argc, char *argv[])
|
|||
h_flag = flag_isset(dmg.cpu, FLAG_HALF_CARRY);
|
||||
c_flag = flag_isset(dmg.cpu, FLAG_CARRY);
|
||||
|
||||
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
|
||||
{
|
||||
ImGui::Begin("State"); // Create a window called "Hello, world!" and append into it.
|
||||
ImGui::Begin("State");
|
||||
|
||||
ImGui::Text(A_FORMAT, dmg.cpu->a);
|
||||
ImGui::Text(B_FORMAT, dmg.cpu->b);
|
||||
|
@ -261,6 +277,20 @@ int main(int argc, char *argv[])
|
|||
ImGui::SameLine();
|
||||
ImGui::Checkbox("C", &c_flag);
|
||||
|
||||
if (ImGui::Button("Run")) {
|
||||
paused = 0;
|
||||
pause_next = 0;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Stop")) {
|
||||
paused = 1;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Step")) {
|
||||
paused = 0;
|
||||
pause_next = 1;
|
||||
}
|
||||
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGui::End();
|
||||
}
|
||||
|
@ -271,7 +301,7 @@ int main(int argc, char *argv[])
|
|||
convert_output(dmg.lcd);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, output_image);
|
||||
ImGui::Image((void*)(intptr_t) texture, ImVec2(256, 256));
|
||||
ImGui::Image((void*)(intptr_t) texture, ImVec2(512, 512));
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
@ -290,6 +320,7 @@ int main(int argc, char *argv[])
|
|||
fill_memory_editor(&dmg);
|
||||
|
||||
editor.DrawWindow("Memory", full_address_space, 0x10000, 0x0000);
|
||||
editor.DrawWindow("ROM", dmg.rom->data, 0x8000, 0);
|
||||
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
|
@ -303,8 +334,6 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
rom_free(&rom);
|
||||
|
||||
// Cleanup
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
|
@ -314,5 +343,7 @@ int main(int argc, char *argv[])
|
|||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
|
||||
rom_free(&rom);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
91
src/cpu.c
91
src/cpu.c
|
@ -91,6 +91,7 @@ static void inc_with_carry(struct cpu *regs, u8 *reg)
|
|||
clear_flag(regs, FLAG_SIGN);
|
||||
if(*reg == 0xff || *reg == 0x0f)
|
||||
set_flag(regs, FLAG_HALF_CARRY);
|
||||
else clear_flag(regs, FLAG_HALF_CARRY);
|
||||
(*reg)++;
|
||||
if(*reg == 0)
|
||||
set_flag(regs, FLAG_ZERO);
|
||||
|
@ -102,6 +103,7 @@ static void dec_with_carry(struct cpu *regs, u8 *reg)
|
|||
set_flag(regs, FLAG_SIGN);
|
||||
if(*reg == 0x00 || *reg == 0x10)
|
||||
set_flag(regs, FLAG_HALF_CARRY);
|
||||
else clear_flag(regs, FLAG_HALF_CARRY);
|
||||
(*reg)--;
|
||||
if(*reg == 0)
|
||||
set_flag(regs, FLAG_ZERO);
|
||||
|
@ -218,10 +220,22 @@ static void add(struct cpu *cpu, u8 value, int with_carry)
|
|||
sum_full++;
|
||||
}
|
||||
sum_trunc = (u8) sum_full;
|
||||
set_flag(cpu, sum_trunc == 0 ? FLAG_ZERO : 0);
|
||||
if (sum_trunc == 0) {
|
||||
set_flag(cpu, FLAG_ZERO);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_ZERO);
|
||||
}
|
||||
clear_flag(cpu, FLAG_SIGN);
|
||||
set_flag(cpu, sum_full > sum_trunc ? FLAG_CARRY : 0);
|
||||
// TODO H
|
||||
if (sum_full > sum_trunc) {
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_CARRY);
|
||||
}
|
||||
if (((cpu->a & 0xf) + (value & 0xf)) & 0x10) {
|
||||
set_flag(cpu, FLAG_HALF_CARRY);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
}
|
||||
cpu->a = sum_trunc;
|
||||
}
|
||||
|
||||
|
@ -239,12 +253,16 @@ static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare
|
|||
clear_flag(cpu, FLAG_ZERO);
|
||||
}
|
||||
set_flag(cpu, FLAG_SIGN);
|
||||
if (sum_full < sum_trunc) {
|
||||
if (value > cpu->a) {
|
||||
set_flag(cpu, FLAG_CARRY);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_CARRY);
|
||||
}
|
||||
// TODO H
|
||||
if (((cpu->a & 0xf) - (value & 0xf)) & 0x10) {
|
||||
set_flag(cpu, FLAG_HALF_CARRY);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
}
|
||||
|
||||
if (!just_compare) {
|
||||
cpu->a = sum_trunc;
|
||||
|
@ -382,14 +400,50 @@ static void conditional_jump(struct cpu *cpu, u8 opc, u8 neg_op, int flag) {
|
|||
}
|
||||
}
|
||||
|
||||
static u16 handlers[] = { 0x40, 0x48, 0x50, 0x58, 0x60 };
|
||||
|
||||
static u16 check_interrupts(struct cpu *cpu)
|
||||
{
|
||||
int k;
|
||||
|
||||
if (!cpu->interrupt_enable) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 enabled = cpu->mem_read(cpu->mem_model, 0xffff);
|
||||
u16 requested = cpu->mem_read(cpu->mem_model, 0xff0f);
|
||||
|
||||
for (k = 0; k < NUM_INTERRUPTS; k++) {
|
||||
int check = 1 << k;
|
||||
if ((enabled & check) && (requested & check)) {
|
||||
// clear request flag for this interrupt and disable all further
|
||||
// interrupts until service routine executes EI or RETI
|
||||
cpu->mem_write(cpu->mem_model, 0xff0f, requested & ~check);
|
||||
cpu->interrupt_enable = 0;
|
||||
return handlers[k];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpu_step(struct cpu *cpu)
|
||||
{
|
||||
u8 temp;
|
||||
u16 temp16;
|
||||
u16 temp16, intr_dest;
|
||||
|
||||
intr_dest = check_interrupts(cpu);
|
||||
if (intr_dest) {
|
||||
push(cpu, cpu->pc);
|
||||
cpu->pc = intr_dest;
|
||||
return;
|
||||
}
|
||||
|
||||
u8 opc = cpu->mem_read(cpu->mem_model, cpu->pc);
|
||||
#ifdef GB6_DEBUG
|
||||
printf("0x%04x %s\n", cpu->pc, instructions[opc].format);
|
||||
#endif
|
||||
|
||||
cpu->pc++;
|
||||
cpu->cycle_count += instructions[opc].cycles;
|
||||
switch (opc) {
|
||||
|
@ -399,6 +453,9 @@ void cpu_step(struct cpu *cpu)
|
|||
write_bc(cpu, read16(cpu, cpu->pc));
|
||||
cpu->pc += 2;
|
||||
break;
|
||||
case 0x0f: // RRCA
|
||||
cpu->a = rrc(cpu, cpu->a);
|
||||
break;
|
||||
case 0x11: // LD DE,d16
|
||||
write_de(cpu, read16(cpu, cpu->pc));
|
||||
cpu->pc += 2;
|
||||
|
@ -596,6 +653,14 @@ void cpu_step(struct cpu *cpu)
|
|||
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
|
||||
}
|
||||
break;
|
||||
case 0xc2: // JP NZ, u16
|
||||
temp16 = read16(cpu, cpu->pc);
|
||||
cpu->pc += 2;
|
||||
if (!flag_isset(cpu, FLAG_ZERO)) {
|
||||
cpu->pc = temp16;
|
||||
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
|
||||
}
|
||||
break;
|
||||
case 0xc9: // RET
|
||||
cpu->pc = pop(cpu);
|
||||
break;
|
||||
|
@ -609,8 +674,10 @@ void cpu_step(struct cpu *cpu)
|
|||
cpu->pc = read16(cpu, cpu->pc);
|
||||
break;
|
||||
case 0xd2: // JP NC,a16
|
||||
temp16 = read16(cpu, cpu->pc);
|
||||
cpu->pc += 2;
|
||||
if (flag_isset(cpu, FLAG_CARRY)) {
|
||||
cpu->pc = read16(cpu, cpu->pc);
|
||||
cpu->pc = temp16;
|
||||
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
|
||||
}
|
||||
break;
|
||||
|
@ -727,8 +794,10 @@ void cpu_step(struct cpu *cpu)
|
|||
}
|
||||
break;
|
||||
case 0xca: // JP Z, u16
|
||||
temp16 = read16(cpu, cpu->pc);
|
||||
cpu->pc += 2;
|
||||
if (flag_isset(cpu, FLAG_ZERO)) {
|
||||
cpu->pc = read16(cpu, cpu->pc);
|
||||
cpu->pc = temp16;
|
||||
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
|
||||
}
|
||||
break;
|
||||
|
@ -742,6 +811,10 @@ void cpu_step(struct cpu *cpu)
|
|||
case 0xd5: // PUSH DE
|
||||
push(cpu, read_de(cpu));
|
||||
break;
|
||||
case 0xd9: // RETI
|
||||
cpu->pc = pop(cpu);
|
||||
cpu->interrupt_enable = 1;
|
||||
break;
|
||||
case 0xe0: // LD (a8),A
|
||||
write8(cpu, 0xff00 + read8(cpu, cpu->pc), cpu->a);
|
||||
cpu->pc++;
|
||||
|
@ -773,6 +846,7 @@ void cpu_step(struct cpu *cpu)
|
|||
cpu->a = read8(cpu, 0xff00 + cpu->c);
|
||||
break;
|
||||
case 0xf3: // DI
|
||||
cpu->interrupt_enable = 0;
|
||||
break;
|
||||
case 0xf5: // PUSH AF
|
||||
push(cpu, read_af(cpu));
|
||||
|
@ -782,6 +856,7 @@ void cpu_step(struct cpu *cpu)
|
|||
cpu->pc += 2;
|
||||
break;
|
||||
case 0xfb: // EI
|
||||
cpu->interrupt_enable = 1;
|
||||
break;
|
||||
default:
|
||||
printf("unknown opcode 0x%02x %s\n", opc, instructions[opc].format);
|
||||
|
|
|
@ -16,6 +16,7 @@ struct cpu
|
|||
u16 sp;
|
||||
u16 pc;
|
||||
u32 cycle_count;
|
||||
u8 interrupt_enable;
|
||||
|
||||
u8 (*mem_read)(void *, u16);
|
||||
void (*mem_write)(void *, u16, u8);
|
||||
|
@ -37,4 +38,11 @@ int flag_isset(struct cpu *cpu, int flag);
|
|||
#define FLAG_HALF_CARRY 0x20
|
||||
#define FLAG_CARRY 0x10
|
||||
|
||||
#define INT_VBLANK (1 << 0)
|
||||
#define INT_LCDSTAT (1 << 1)
|
||||
#define INT_TIMER (1 << 2)
|
||||
#define INT_SERIAL (1 << 3)
|
||||
#define INT_JOYPAD (1 << 4)
|
||||
#define NUM_INTERRUPTS 5
|
||||
|
||||
#endif
|
||||
|
|
48
src/dmg.c
48
src/dmg.c
|
@ -13,6 +13,33 @@ void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom, struct lcd *lcd)
|
|||
dmg->cpu = cpu;
|
||||
dmg->rom = rom;
|
||||
dmg->lcd = lcd;
|
||||
|
||||
dmg->joypad = 0xf; // nothing pressed
|
||||
dmg->action_buttons = 0xf;
|
||||
}
|
||||
|
||||
void dmg_set_button(struct dmg *dmg, int field, int button, int pressed)
|
||||
{
|
||||
u8 *mod;
|
||||
if (field == FIELD_JOY) {
|
||||
mod = &dmg->joypad;
|
||||
} else if (field == FIELD_ACTION) {
|
||||
mod = &dmg->action_buttons;
|
||||
} else {
|
||||
printf("setting invalid button state\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pressed) {
|
||||
*mod &= ~button;
|
||||
} else {
|
||||
*mod |= button;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 get_button_state(struct dmg *dmg)
|
||||
{
|
||||
return dmg->action_selected ? dmg->action_buttons : dmg->joypad;
|
||||
}
|
||||
|
||||
u8 dmg_read(void *_dmg, u16 address)
|
||||
|
@ -37,6 +64,12 @@ u8 dmg_read(void *_dmg, u16 address)
|
|||
return lcd_read(dmg->lcd, address);
|
||||
} else if (address >= 0xff80 && address <= 0xfffe) {
|
||||
return dmg->zero_page[address - 0xff80];
|
||||
} else if (address == 0xff00) {
|
||||
return get_button_state(dmg);
|
||||
} else if (address == 0xff0f) {
|
||||
return dmg->interrupt_requested;
|
||||
} else if (address == 0xffff) {
|
||||
return dmg->interrupt_enabled;
|
||||
} else {
|
||||
// not sure about any of this yet
|
||||
// commented out bc of memory view window
|
||||
|
@ -65,11 +98,21 @@ void dmg_write(void *_dmg, u16 address, u8 data)
|
|||
lcd_write(dmg->lcd, address, data);
|
||||
} else if (address >= 0xff80 && address <= 0xfffe) {
|
||||
dmg->zero_page[address - 0xff80] = data;
|
||||
} else if (address == 0xff00) {
|
||||
dmg->action_selected = data & (1 << 5);
|
||||
} else if (address == 0xff0f) {
|
||||
dmg->interrupt_requested = data;
|
||||
} else if (address == 0xffff) {
|
||||
dmg->interrupt_enabled = data;
|
||||
} else {
|
||||
// not sure about any of this yet
|
||||
}
|
||||
}
|
||||
void exit(int);
|
||||
|
||||
void dmg_request_interrupt(struct dmg *dmg, int nr)
|
||||
{
|
||||
dmg->interrupt_requested |= nr;
|
||||
}
|
||||
|
||||
void dmg_step(void *_dmg)
|
||||
{
|
||||
|
@ -85,6 +128,7 @@ void dmg_step(void *_dmg)
|
|||
int next_scanline = lcd_step(dmg->lcd);
|
||||
if (next_scanline == 144) {
|
||||
// vblank has started, draw all the stuff from ram into the lcd
|
||||
dmg_request_interrupt(dmg, INT_VBLANK);
|
||||
|
||||
int lcdc = lcd_read(dmg->lcd, REG_LCDC);
|
||||
int bg_base = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800;
|
||||
|
@ -92,7 +136,7 @@ void dmg_step(void *_dmg)
|
|||
int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
|
||||
int tilebase = use_unsigned ? 0x8000 : 0x9000;
|
||||
|
||||
printf("tile map: %04x, tile data: %04x\n", bg_base, tilebase);
|
||||
printf("%04x %04x %04x\n", bg_base, window_base, tilebase);
|
||||
|
||||
int k = 0, off = 0;
|
||||
int tile_y = 0, tile_x = 0;
|
||||
|
|
19
src/dmg.h
19
src/dmg.h
|
@ -5,6 +5,18 @@
|
|||
#include "rom.h"
|
||||
#include "lcd.h"
|
||||
|
||||
#define FIELD_JOY 1
|
||||
#define FIELD_ACTION 2
|
||||
|
||||
#define BUTTON_RIGHT (1 << 0)
|
||||
#define BUTTON_LEFT (1 << 1)
|
||||
#define BUTTON_UP (1 << 2)
|
||||
#define BUTTON_DOWN (1 << 3)
|
||||
#define BUTTON_A (1 << 0)
|
||||
#define BUTTON_B (1 << 1)
|
||||
#define BUTTON_SELECT (1 << 2)
|
||||
#define BUTTON_START (1 << 3)
|
||||
|
||||
struct dmg {
|
||||
struct cpu *cpu;
|
||||
struct rom *rom;
|
||||
|
@ -13,9 +25,16 @@ struct dmg {
|
|||
u8 video_ram[0x2000];
|
||||
u8 zero_page[0x80];
|
||||
u32 last_lcd_update;
|
||||
int action_selected; // non-0 if A/B/start/select selected, 0 for directions
|
||||
u8 interrupt_enabled;
|
||||
u8 interrupt_requested;
|
||||
|
||||
u8 joypad;
|
||||
u8 action_buttons;
|
||||
};
|
||||
|
||||
void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom, struct lcd *lcd);
|
||||
void dmg_set_button(struct dmg *dmg, int field, int button, int pressed);
|
||||
|
||||
// why did i make these void *
|
||||
u8 dmg_read(void *dmg, u16 address);
|
||||
|
|
Loading…
Reference in New Issue