first output: nintendo logo

This commit is contained in:
Matthew Laux 2022-07-14 00:48:18 -05:00
parent 9601b9f7da
commit 261bb40563
4 changed files with 144 additions and 94 deletions

View File

@ -11,7 +11,7 @@ execute_process(COMMAND sdl2-config --libs
OUTPUT_VARIABLE SDL_LIBS
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
../src/bootstrap.c

View File

@ -9,6 +9,7 @@
#include "imgui/imgui_memory_editor.h"
#include <stdio.h>
#include <SDL.h>
#include <SDL_timer.h>
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL_opengles2.h>
#else
@ -57,9 +58,9 @@ void convert_output(struct lcd *lcd) {
for (x = 0; x < 256; x++) {
int val = lcd->buf[y * 256 + x];
int fill = val ? 255 : 0;
output_image[out_index++] = val;
output_image[out_index++] = val;
output_image[out_index++] = val;
output_image[out_index++] = fill;
output_image[out_index++] = fill;
output_image[out_index++] = fill;
output_image[out_index++] = 255;
}
}
@ -102,7 +103,7 @@ int main(int argc, char *argv[])
dmg_new(&dmg, &cpu, &rom, &lcd);
cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
cpu.pc = 0x100;
cpu.pc = 0;//0x100;
// Setup SDL
// (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
bool done = false;
unsigned int lastDrawTime = 0, currentTime;
while (!done)
{
// Poll and handle events (inputs, window resize, etc.)
@ -190,71 +192,75 @@ int main(int argc, char *argv[])
done = true;
}
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
dmg_step(&dmg);
z_flag = flag_isset(dmg.cpu, FLAG_ZERO);
n_flag = flag_isset(dmg.cpu, FLAG_SIGN);
h_flag = flag_isset(dmg.cpu, FLAG_HALF_CARRY);
c_flag = flag_isset(dmg.cpu, FLAG_CARRY);
currentTime = SDL_GetTicks();
if (currentTime >= lastDrawTime + 16) {
// Start the Dear ImGui frame
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.
{
ImGui::Begin("State"); // Create a window called "Hello, world!" and append into it.
z_flag = flag_isset(dmg.cpu, FLAG_ZERO);
n_flag = flag_isset(dmg.cpu, FLAG_SIGN);
h_flag = flag_isset(dmg.cpu, FLAG_HALF_CARRY);
c_flag = flag_isset(dmg.cpu, FLAG_CARRY);
ImGui::Text(A_FORMAT, dmg.cpu->a);
ImGui::Text(B_FORMAT, dmg.cpu->b);
ImGui::SameLine();
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);
// 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::Checkbox("Z", &z_flag);
ImGui::SameLine();
ImGui::Checkbox("N", &n_flag);
ImGui::SameLine();
ImGui::Checkbox("H", &h_flag);
ImGui::SameLine();
ImGui::Checkbox("C", &c_flag);
ImGui::Text(A_FORMAT, dmg.cpu->a);
ImGui::Text(B_FORMAT, dmg.cpu->b);
ImGui::SameLine();
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::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End();
ImGui::Checkbox("Z", &z_flag);
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);

View File

@ -110,19 +110,34 @@ static void dec_with_carry(struct cpu *regs, u8 *reg)
static u8 rotate_left(struct cpu *regs, u8 reg)
{
// copy old leftmost bit to carry flag
regs->f = (reg & 0x80) >> 3 | (regs->f & ~FLAG_CARRY);
int old_carry = flag_isset(regs, FLAG_CARRY);
// copy old leftmost bit to carry flag, clear Z, N, H
regs->f = (reg & 0x80) >> 3;
// rotate
int result = reg << 1;
// restore leftmost (now rightmost) bit
result |= (regs->f & FLAG_CARRY) >> 4;
int result = reg << 1 | old_carry;
if (!result) set_flag(regs, FLAG_ZERO);
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;
}
static u8 rotate_right(struct cpu *regs, u8 reg)
{
// copy old rightmost bit to carry flag
regs->f = (reg & 0x01) << 4 | (regs->f & ~FLAG_CARRY);
regs->f = (reg & 0x01) << 4;
// rotate
int result = reg >> 1;
// restore rightmost bit to left
@ -130,6 +145,21 @@ static u8 rotate_right(struct cpu *regs, u8 reg)
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)
{
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)) {
sum_full--;
}
sum_trunc = (u8) sum_full;
set_flag(cpu, sum_trunc == 0 ? FLAG_ZERO : 0);
sum_trunc = (u8) (sum_full & 0xff);
if (!sum_trunc) {
set_flag(cpu, FLAG_ZERO);
} else {
clear_flag(cpu, FLAG_ZERO);
}
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
if (!just_compare) {
@ -296,10 +334,10 @@ static void extended_insn(struct cpu *cpu, u8 insn)
int reg = insn & 0x7;
u8 (*funcs[8])(struct cpu *, u8) = {
rlc,
rrc,
rotate_left,
rotate_right,
rotate_left, // TODO non-carry version
rotate_right,
shift_left,
shift_right,
swap,
@ -356,7 +394,7 @@ void cpu_step(struct cpu *cpu)
cpu->pc += 2;
break;
case 0x07: // RLCA
cpu->a = rotate_left(cpu, cpu->a);
cpu->a = rlc(cpu, cpu->a);
break;
case 0x08: // LD (a16),SP
write16(cpu, read16(cpu, cpu->pc), cpu->sp);

View File

@ -68,6 +68,7 @@ void dmg_write(void *_dmg, u16 address, u8 data)
// not sure about any of this yet
}
}
void exit(int);
void dmg_step(void *_dmg)
{
@ -89,26 +90,31 @@ void dmg_step(void *_dmg)
int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
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;
for (k = 0; k < 1024; k++) {
int tile = dmg_read(dmg, bg_base + k);
int eff_addr;
if (use_unsigned) {
eff_addr = tilebase + 16 * tile;
} else {
eff_addr = tilebase + 16 * (signed char) tile;
}
int b, i;
for (b = 0; b < 16; b += 2) {
int data1 = dmg_read(dmg, eff_addr + b);
int data2 = dmg_read(dmg, eff_addr + b + 1);
for (i = 0; i < 8; i++) {
// monochrome for now
dmg->lcd->buf[off] |= (data1 & (1 << i)) ? 1 : 0;
dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
off++;
int k = 0, off = 0;
int tile_y = 0, tile_x = 0;
for (tile_y = 0; tile_y < 32; tile_y++) {
for (tile_x = 0; tile_x < 32; tile_x++) {
off = 256 * 8 * tile_y + 8 * tile_x;
int tile = dmg_read(dmg, bg_base + (tile_y * 32 + tile_x));
int eff_addr;
if (use_unsigned) {
eff_addr = tilebase + 16 * tile;
} else {
eff_addr = tilebase + 16 * (signed char) tile;
}
int b, i;
for (b = 0; b < 16; b += 2) {
int data1 = dmg_read(dmg, eff_addr + b);
int data2 = dmg_read(dmg, eff_addr + b + 1);
for (i = 7; i >= 0; i--) {
// monochrome for now
dmg->lcd->buf[off] = (data1 & (1 << i)) ? 1 : 0;
//dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
off++;
}
off += 248;
}
}
}