mirror of https://github.com/mlaux/gb6.git
first output: nintendo logo
This commit is contained in:
parent
9601b9f7da
commit
261bb40563
|
@ -11,7 +11,7 @@ execute_process(COMMAND sdl2-config --libs
|
||||||
OUTPUT_VARIABLE SDL_LIBS
|
OUTPUT_VARIABLE SDL_LIBS
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "-std=c++14 ${SDL_CFLAGS}")
|
set(CMAKE_CXX_FLAGS "-std=c++14 -g -DGB6_DEBUG ${SDL_CFLAGS}")
|
||||||
|
|
||||||
add_executable(gb6
|
add_executable(gb6
|
||||||
../src/bootstrap.c
|
../src/bootstrap.c
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "imgui/imgui_memory_editor.h"
|
#include "imgui/imgui_memory_editor.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <SDL_timer.h>
|
||||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||||
#include <SDL_opengles2.h>
|
#include <SDL_opengles2.h>
|
||||||
#else
|
#else
|
||||||
|
@ -57,9 +58,9 @@ void convert_output(struct lcd *lcd) {
|
||||||
for (x = 0; x < 256; x++) {
|
for (x = 0; x < 256; x++) {
|
||||||
int val = lcd->buf[y * 256 + x];
|
int val = lcd->buf[y * 256 + x];
|
||||||
int fill = val ? 255 : 0;
|
int fill = val ? 255 : 0;
|
||||||
output_image[out_index++] = val;
|
output_image[out_index++] = fill;
|
||||||
output_image[out_index++] = val;
|
output_image[out_index++] = fill;
|
||||||
output_image[out_index++] = val;
|
output_image[out_index++] = fill;
|
||||||
output_image[out_index++] = 255;
|
output_image[out_index++] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +103,7 @@ int main(int argc, char *argv[])
|
||||||
dmg_new(&dmg, &cpu, &rom, &lcd);
|
dmg_new(&dmg, &cpu, &rom, &lcd);
|
||||||
cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
|
cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
|
||||||
|
|
||||||
cpu.pc = 0x100;
|
cpu.pc = 0;//0x100;
|
||||||
|
|
||||||
// Setup SDL
|
// Setup SDL
|
||||||
// (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
|
// (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
|
||||||
|
@ -173,6 +174,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
unsigned int lastDrawTime = 0, currentTime;
|
||||||
while (!done)
|
while (!done)
|
||||||
{
|
{
|
||||||
// Poll and handle events (inputs, window resize, etc.)
|
// Poll and handle events (inputs, window resize, etc.)
|
||||||
|
@ -190,71 +192,75 @@ int main(int argc, char *argv[])
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
|
||||||
ImGui_ImplSDL2_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
|
|
||||||
dmg_step(&dmg);
|
dmg_step(&dmg);
|
||||||
|
|
||||||
z_flag = flag_isset(dmg.cpu, FLAG_ZERO);
|
currentTime = SDL_GetTicks();
|
||||||
n_flag = flag_isset(dmg.cpu, FLAG_SIGN);
|
if (currentTime >= lastDrawTime + 16) {
|
||||||
h_flag = flag_isset(dmg.cpu, FLAG_HALF_CARRY);
|
// Start the Dear ImGui frame
|
||||||
c_flag = flag_isset(dmg.cpu, FLAG_CARRY);
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
ImGui_ImplSDL2_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
|
z_flag = flag_isset(dmg.cpu, FLAG_ZERO);
|
||||||
{
|
n_flag = flag_isset(dmg.cpu, FLAG_SIGN);
|
||||||
ImGui::Begin("State"); // Create a window called "Hello, world!" and append into it.
|
h_flag = flag_isset(dmg.cpu, FLAG_HALF_CARRY);
|
||||||
|
c_flag = flag_isset(dmg.cpu, FLAG_CARRY);
|
||||||
|
|
||||||
ImGui::Text(A_FORMAT, dmg.cpu->a);
|
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
|
||||||
ImGui::Text(B_FORMAT, dmg.cpu->b);
|
{
|
||||||
ImGui::SameLine();
|
ImGui::Begin("State"); // Create a window called "Hello, world!" and append into it.
|
||||||
ImGui::Text(C_FORMAT, dmg.cpu->c);
|
|
||||||
ImGui::Text(D_FORMAT, dmg.cpu->d);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text(E_FORMAT, dmg.cpu->e);
|
|
||||||
ImGui::Text(H_FORMAT, dmg.cpu->h);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text(L_FORMAT, dmg.cpu->l);
|
|
||||||
ImGui::Text(SP_FORMAT, dmg.cpu->sp);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text(PC_FORMAT, dmg.cpu->pc);
|
|
||||||
|
|
||||||
ImGui::Checkbox("Z", &z_flag);
|
ImGui::Text(A_FORMAT, dmg.cpu->a);
|
||||||
ImGui::SameLine();
|
ImGui::Text(B_FORMAT, dmg.cpu->b);
|
||||||
ImGui::Checkbox("N", &n_flag);
|
ImGui::SameLine();
|
||||||
ImGui::SameLine();
|
ImGui::Text(C_FORMAT, dmg.cpu->c);
|
||||||
ImGui::Checkbox("H", &h_flag);
|
ImGui::Text(D_FORMAT, dmg.cpu->d);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Checkbox("C", &c_flag);
|
ImGui::Text(E_FORMAT, dmg.cpu->e);
|
||||||
|
ImGui::Text(H_FORMAT, dmg.cpu->h);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(L_FORMAT, dmg.cpu->l);
|
||||||
|
ImGui::Text(SP_FORMAT, dmg.cpu->sp);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(PC_FORMAT, dmg.cpu->pc);
|
||||||
|
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
ImGui::Checkbox("Z", &z_flag);
|
||||||
ImGui::End();
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("N", &n_flag);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("H", &h_flag);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("C", &c_flag);
|
||||||
|
|
||||||
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ImGui::Begin("Output");
|
||||||
|
|
||||||
|
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::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
fill_memory_editor(&dmg);
|
||||||
|
|
||||||
|
editor.DrawWindow("Memory", full_address_space, 0x10000, 0x0000);
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
ImGui::Render();
|
||||||
|
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||||
|
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
SDL_GL_SwapWindow(window);
|
||||||
|
|
||||||
|
lastDrawTime = currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
ImGui::Begin("Output");
|
|
||||||
|
|
||||||
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::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
fill_memory_editor(&dmg);
|
|
||||||
|
|
||||||
editor.DrawWindow("Memory", full_address_space, 0x10000, 0x0000);
|
|
||||||
editor.DrawWindow("LCD", dmg.lcd->buf, 0x2000, 0);
|
|
||||||
|
|
||||||
// Rendering
|
|
||||||
ImGui::Render();
|
|
||||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
|
||||||
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
||||||
SDL_GL_SwapWindow(window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rom_free(&rom);
|
rom_free(&rom);
|
||||||
|
|
62
src/cpu.c
62
src/cpu.c
|
@ -110,19 +110,34 @@ static void dec_with_carry(struct cpu *regs, u8 *reg)
|
||||||
|
|
||||||
static u8 rotate_left(struct cpu *regs, u8 reg)
|
static u8 rotate_left(struct cpu *regs, u8 reg)
|
||||||
{
|
{
|
||||||
// copy old leftmost bit to carry flag
|
int old_carry = flag_isset(regs, FLAG_CARRY);
|
||||||
regs->f = (reg & 0x80) >> 3 | (regs->f & ~FLAG_CARRY);
|
// copy old leftmost bit to carry flag, clear Z, N, H
|
||||||
|
regs->f = (reg & 0x80) >> 3;
|
||||||
// rotate
|
// rotate
|
||||||
int result = reg << 1;
|
int result = reg << 1 | old_carry;
|
||||||
// restore leftmost (now rightmost) bit
|
if (!result) set_flag(regs, FLAG_ZERO);
|
||||||
result |= (regs->f & FLAG_CARRY) >> 4;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 rlc(struct cpu *cpu, u8 val)
|
||||||
|
{
|
||||||
|
int old_msb = (val & 0x80) >> 7;
|
||||||
|
int result = (val & 0x7f) << 1 | old_msb;
|
||||||
|
if (!result)
|
||||||
|
set_flag(cpu, FLAG_ZERO);
|
||||||
|
else clear_flag(cpu, FLAG_ZERO);
|
||||||
|
clear_flag(cpu, FLAG_SIGN);
|
||||||
|
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||||
|
if (old_msb)
|
||||||
|
set_flag(cpu, FLAG_CARRY);
|
||||||
|
else clear_flag(cpu, FLAG_CARRY);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 rotate_right(struct cpu *regs, u8 reg)
|
static u8 rotate_right(struct cpu *regs, u8 reg)
|
||||||
{
|
{
|
||||||
// copy old rightmost bit to carry flag
|
// copy old rightmost bit to carry flag
|
||||||
regs->f = (reg & 0x01) << 4 | (regs->f & ~FLAG_CARRY);
|
regs->f = (reg & 0x01) << 4;
|
||||||
// rotate
|
// rotate
|
||||||
int result = reg >> 1;
|
int result = reg >> 1;
|
||||||
// restore rightmost bit to left
|
// restore rightmost bit to left
|
||||||
|
@ -130,6 +145,21 @@ static u8 rotate_right(struct cpu *regs, u8 reg)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 rrc(struct cpu *cpu, u8 val)
|
||||||
|
{
|
||||||
|
int old_lsb = (val & 1) << 7;
|
||||||
|
int result = old_lsb | (val & 0xfe) >> 1;
|
||||||
|
if (!result)
|
||||||
|
set_flag(cpu, FLAG_ZERO);
|
||||||
|
else clear_flag(cpu, FLAG_ZERO);
|
||||||
|
clear_flag(cpu, FLAG_SIGN);
|
||||||
|
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||||
|
if (old_lsb)
|
||||||
|
set_flag(cpu, FLAG_CARRY);
|
||||||
|
else clear_flag(cpu, FLAG_CARRY);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static u8 shift_left(struct cpu *cpu, u8 value)
|
static u8 shift_left(struct cpu *cpu, u8 value)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -202,10 +232,18 @@ static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare
|
||||||
if (with_carry && flag_isset(cpu, FLAG_CARRY)) {
|
if (with_carry && flag_isset(cpu, FLAG_CARRY)) {
|
||||||
sum_full--;
|
sum_full--;
|
||||||
}
|
}
|
||||||
sum_trunc = (u8) sum_full;
|
sum_trunc = (u8) (sum_full & 0xff);
|
||||||
set_flag(cpu, sum_trunc == 0 ? FLAG_ZERO : 0);
|
if (!sum_trunc) {
|
||||||
|
set_flag(cpu, FLAG_ZERO);
|
||||||
|
} else {
|
||||||
|
clear_flag(cpu, FLAG_ZERO);
|
||||||
|
}
|
||||||
set_flag(cpu, FLAG_SIGN);
|
set_flag(cpu, FLAG_SIGN);
|
||||||
set_flag(cpu, sum_full < sum_trunc ? FLAG_CARRY : 0);
|
if (sum_full < sum_trunc) {
|
||||||
|
set_flag(cpu, FLAG_CARRY);
|
||||||
|
} else {
|
||||||
|
clear_flag(cpu, FLAG_CARRY);
|
||||||
|
}
|
||||||
// TODO H
|
// TODO H
|
||||||
|
|
||||||
if (!just_compare) {
|
if (!just_compare) {
|
||||||
|
@ -296,10 +334,10 @@ static void extended_insn(struct cpu *cpu, u8 insn)
|
||||||
int reg = insn & 0x7;
|
int reg = insn & 0x7;
|
||||||
|
|
||||||
u8 (*funcs[8])(struct cpu *, u8) = {
|
u8 (*funcs[8])(struct cpu *, u8) = {
|
||||||
|
rlc,
|
||||||
|
rrc,
|
||||||
rotate_left,
|
rotate_left,
|
||||||
rotate_right,
|
rotate_right,
|
||||||
rotate_left, // TODO non-carry version
|
|
||||||
rotate_right,
|
|
||||||
shift_left,
|
shift_left,
|
||||||
shift_right,
|
shift_right,
|
||||||
swap,
|
swap,
|
||||||
|
@ -356,7 +394,7 @@ void cpu_step(struct cpu *cpu)
|
||||||
cpu->pc += 2;
|
cpu->pc += 2;
|
||||||
break;
|
break;
|
||||||
case 0x07: // RLCA
|
case 0x07: // RLCA
|
||||||
cpu->a = rotate_left(cpu, cpu->a);
|
cpu->a = rlc(cpu, cpu->a);
|
||||||
break;
|
break;
|
||||||
case 0x08: // LD (a16),SP
|
case 0x08: // LD (a16),SP
|
||||||
write16(cpu, read16(cpu, cpu->pc), cpu->sp);
|
write16(cpu, read16(cpu, cpu->pc), cpu->sp);
|
||||||
|
|
44
src/dmg.c
44
src/dmg.c
|
@ -68,6 +68,7 @@ void dmg_write(void *_dmg, u16 address, u8 data)
|
||||||
// not sure about any of this yet
|
// not sure about any of this yet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void exit(int);
|
||||||
|
|
||||||
void dmg_step(void *_dmg)
|
void dmg_step(void *_dmg)
|
||||||
{
|
{
|
||||||
|
@ -89,26 +90,31 @@ void dmg_step(void *_dmg)
|
||||||
int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
|
int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
|
||||||
int tilebase = use_unsigned ? 0x8000 : 0x9000;
|
int tilebase = use_unsigned ? 0x8000 : 0x9000;
|
||||||
|
|
||||||
printf("base is %04x\n", bg_base);
|
printf("bg_base %04x, tilebase %04x\n", bg_base, tilebase);
|
||||||
|
|
||||||
int k, off = 0;
|
int k = 0, off = 0;
|
||||||
for (k = 0; k < 1024; k++) {
|
int tile_y = 0, tile_x = 0;
|
||||||
int tile = dmg_read(dmg, bg_base + k);
|
for (tile_y = 0; tile_y < 32; tile_y++) {
|
||||||
int eff_addr;
|
for (tile_x = 0; tile_x < 32; tile_x++) {
|
||||||
if (use_unsigned) {
|
off = 256 * 8 * tile_y + 8 * tile_x;
|
||||||
eff_addr = tilebase + 16 * tile;
|
int tile = dmg_read(dmg, bg_base + (tile_y * 32 + tile_x));
|
||||||
} else {
|
int eff_addr;
|
||||||
eff_addr = tilebase + 16 * (signed char) tile;
|
if (use_unsigned) {
|
||||||
}
|
eff_addr = tilebase + 16 * tile;
|
||||||
int b, i;
|
} else {
|
||||||
for (b = 0; b < 16; b += 2) {
|
eff_addr = tilebase + 16 * (signed char) tile;
|
||||||
int data1 = dmg_read(dmg, eff_addr + b);
|
}
|
||||||
int data2 = dmg_read(dmg, eff_addr + b + 1);
|
int b, i;
|
||||||
for (i = 0; i < 8; i++) {
|
for (b = 0; b < 16; b += 2) {
|
||||||
// monochrome for now
|
int data1 = dmg_read(dmg, eff_addr + b);
|
||||||
dmg->lcd->buf[off] |= (data1 & (1 << i)) ? 1 : 0;
|
int data2 = dmg_read(dmg, eff_addr + b + 1);
|
||||||
dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
|
for (i = 7; i >= 0; i--) {
|
||||||
off++;
|
// monochrome for now
|
||||||
|
dmg->lcd->buf[off] = (data1 & (1 << i)) ? 1 : 0;
|
||||||
|
//dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
|
||||||
|
off++;
|
||||||
|
}
|
||||||
|
off += 248;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue