mirror of https://github.com/mlaux/gb6.git
Compare commits
3 Commits
9601b9f7da
...
bc3f717285
Author | SHA1 | Date |
---|---|---|
Matthew Laux | bc3f717285 | |
Matthew Laux | b1dca59463 | |
Matthew Laux | 261bb40563 |
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -49,6 +50,7 @@ GLuint make_output_texture() {
|
|||
}
|
||||
|
||||
unsigned char output_image[256 * 256 * 4];
|
||||
unsigned char vram_tiles[256 * 96 * 4];
|
||||
|
||||
void convert_output(struct lcd *lcd) {
|
||||
int x, y;
|
||||
|
@ -57,14 +59,41 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convert_vram(struct dmg *dmg) {
|
||||
int tile_y, tile_x;
|
||||
int off, in;
|
||||
for (tile_y = 0; tile_y < 12; tile_y++) {
|
||||
for (tile_x = 0; tile_x < 32; tile_x++) {
|
||||
off = 256 * 8 * tile_y + 8 * tile_x;
|
||||
in = 16 * (tile_y * 32 + tile_x);
|
||||
int b, i;
|
||||
for (b = 0; b < 16; b += 2) {
|
||||
int data1 = dmg->video_ram[in + b];
|
||||
int data2 = dmg->video_ram[in + b + 1];
|
||||
for (i = 7; i >= 0; i--) {
|
||||
// monochrome for now
|
||||
int fill = (data1 & (1 << i)) ? 255 : 0;
|
||||
vram_tiles[4 * off + 0] = fill;
|
||||
vram_tiles[4 * off + 1] = fill;
|
||||
vram_tiles[4 * off + 2] = fill;
|
||||
vram_tiles[4 * off + 3] = 255;
|
||||
//dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
|
||||
off++;
|
||||
}
|
||||
off += 248;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char full_address_space[0x10000];
|
||||
void fill_memory_editor(struct dmg *dmg)
|
||||
{
|
||||
|
@ -164,6 +193,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
// setup output
|
||||
GLuint texture = make_output_texture();
|
||||
GLuint vram_texture = make_output_texture();
|
||||
|
||||
// Our state
|
||||
bool z_flag = false;
|
||||
|
@ -173,88 +203,104 @@ 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.)
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
if (event.type == SDL_QUIT)
|
||||
done = true;
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
|
||||
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) {
|
||||
// Poll and handle events (inputs, window resize, etc.)
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
if (event.type == SDL_QUIT)
|
||||
done = true;
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
|
||||
done = true;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
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);
|
||||
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::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);
|
||||
// 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::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||
ImGui::End();
|
||||
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::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();
|
||||
}
|
||||
|
||||
{
|
||||
ImGui::Begin("VRAM");
|
||||
|
||||
convert_vram(&dmg);
|
||||
glBindTexture(GL_TEXTURE_2D, vram_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 96, 0, GL_RGBA, GL_UNSIGNED_BYTE, vram_tiles);
|
||||
ImGui::Image((void*)(intptr_t) vram_texture, ImVec2(256, 96));
|
||||
|
||||
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);
|
||||
|
|
109
src/cpu.c
109
src/cpu.c
|
@ -110,23 +110,53 @@ 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);
|
||||
int old_carry = flag_isset(regs, FLAG_CARRY) << 7;
|
||||
// copy old rightmost bit to carry flag, clear ZNH
|
||||
regs->f = (reg & 0x01) << 4;
|
||||
// rotate
|
||||
int result = reg >> 1;
|
||||
// restore rightmost bit to left
|
||||
result |= (regs->f & FLAG_CARRY) << 3;
|
||||
int result = old_carry | reg >> 1;
|
||||
if (!result) set_flag(regs, FLAG_ZERO);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -544,6 +582,7 @@ void cpu_step(struct cpu *cpu)
|
|||
case 0xc0: // RET NZ
|
||||
if (!flag_isset(cpu, FLAG_ZERO)) {
|
||||
cpu->pc = pop(cpu);
|
||||
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
|
||||
}
|
||||
break;
|
||||
case 0xc9: // RET
|
||||
|
@ -561,6 +600,7 @@ void cpu_step(struct cpu *cpu)
|
|||
case 0xd2: // JP NC,a16
|
||||
if (flag_isset(cpu, FLAG_CARRY)) {
|
||||
cpu->pc = read16(cpu, cpu->pc);
|
||||
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -657,6 +697,18 @@ void cpu_step(struct cpu *cpu)
|
|||
case 0xc5: // PUSH BC
|
||||
push(cpu, read_bc(cpu));
|
||||
break;
|
||||
case 0xc8: // RET Z
|
||||
if (flag_isset(cpu, FLAG_ZERO)) {
|
||||
cpu->pc = pop(cpu);
|
||||
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
|
||||
}
|
||||
break;
|
||||
case 0xca: // JP Z, u16
|
||||
if (flag_isset(cpu, FLAG_ZERO)) {
|
||||
cpu->pc = read16(cpu, cpu->pc);
|
||||
cpu->cycle_count += instructions[opc].cycles_branch - instructions[opc].cycles;
|
||||
}
|
||||
break;
|
||||
case 0xcb:
|
||||
extended_insn(cpu, read8(cpu, cpu->pc));
|
||||
cpu->pc++;
|
||||
|
@ -665,13 +717,28 @@ void cpu_step(struct cpu *cpu)
|
|||
add(cpu, read8(cpu, cpu->pc), 1);
|
||||
cpu->pc++;
|
||||
break;
|
||||
case 0xd1: // POP DE
|
||||
write_de(cpu, pop(cpu));
|
||||
break;
|
||||
case 0xd5: // PUSH DE
|
||||
push(cpu, read_de(cpu));
|
||||
break;
|
||||
case 0xe0: // LD (a8),A
|
||||
write8(cpu, 0xff00 + read8(cpu, cpu->pc), cpu->a);
|
||||
cpu->pc++;
|
||||
break;
|
||||
case 0xe1: // POP HL
|
||||
write_hl(cpu, pop(cpu));
|
||||
break;
|
||||
case 0xe2: // LD (C),A
|
||||
write8(cpu, 0xff00 + cpu->c, cpu->a);
|
||||
break;
|
||||
case 0xe5: // PUSH HL
|
||||
push(cpu, read_hl(cpu));
|
||||
break;
|
||||
case 0xe9: // JP HL
|
||||
cpu->pc = read_hl(cpu);
|
||||
break;
|
||||
case 0xea: // LD (a16),A
|
||||
write8(cpu, read16(cpu, cpu->pc), cpu->a);
|
||||
cpu->pc += 2;
|
||||
|
@ -680,11 +747,21 @@ void cpu_step(struct cpu *cpu)
|
|||
cpu->a = read8(cpu, 0xff00 + read8(cpu, cpu->pc));
|
||||
cpu->pc++;
|
||||
break;
|
||||
case 0xf1: // POP AF
|
||||
write_af(cpu, pop(cpu));
|
||||
break;
|
||||
case 0xf2: // LD A,(C)
|
||||
cpu->a = read8(cpu, 0xff00 + cpu->c);
|
||||
break;
|
||||
case 0xf3: // DI
|
||||
break;
|
||||
case 0xf5: // PUSH AF
|
||||
push(cpu, read_af(cpu));
|
||||
break;
|
||||
case 0xfa: // LD A,(u16)
|
||||
cpu->a = read8(cpu, read16(cpu, cpu->pc));
|
||||
cpu->pc += 2;
|
||||
break;
|
||||
case 0xfb: // EI
|
||||
break;
|
||||
default:
|
||||
|
|
54
src/dmg.c
54
src/dmg.c
|
@ -18,9 +18,10 @@ void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom, struct lcd *lcd)
|
|||
u8 dmg_read(void *_dmg, u16 address)
|
||||
{
|
||||
struct dmg *dmg = (struct dmg *) _dmg;
|
||||
if (address < 0x100) {
|
||||
return dmg_boot_rom[address];
|
||||
} else if (address < 0x4000) {
|
||||
// if (address < 0x100) {
|
||||
// return dmg_boot_rom[address];
|
||||
// } else if (address < 0x4000) {
|
||||
if (address < 0x4000) {
|
||||
return dmg->rom->data[address];
|
||||
} else if (address < 0x8000) {
|
||||
// TODO switchable rom bank
|
||||
|
@ -68,6 +69,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)
|
||||
{
|
||||
|
@ -78,7 +80,8 @@ void dmg_step(void *_dmg)
|
|||
cpu_step(dmg->cpu);
|
||||
|
||||
// each line takes 456 cycles
|
||||
if (dmg->cpu->cycle_count % 456 == 0) {
|
||||
if (dmg->cpu->cycle_count - dmg->last_lcd_update >= 456) {
|
||||
dmg->last_lcd_update = dmg->cpu->cycle_count;
|
||||
int next_scanline = lcd_step(dmg->lcd);
|
||||
if (next_scanline == 144) {
|
||||
// vblank has started, draw all the stuff from ram into the lcd
|
||||
|
@ -89,26 +92,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("tile map: %04x, tile data: %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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue