diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index b81bf5f..4b1be7a 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -1,5 +1,5 @@ -set(HEADERS canvas.h gui.h window.h main_window.h char_map.h pattern_display.h pattern_window.h nametable_window.h) -set(SOURCE canvas.c gui.c window.c main_window.c char_map.c pattern_display.c pattern_window.c nametable_window.c) +set(HEADERS canvas.h gui.h window.h main_window.h char_map.h pattern_display.h pattern_window.h nametable_window.h dbg_pattern_table.h) +set(SOURCE canvas.c gui.c window.c main_window.c char_map.c pattern_display.c pattern_window.c nametable_window.c dbg_pattern_table.c) add_library(nes_gui ${SOURCE} ${HEADERS}) diff --git a/gui/dbg_pattern_table.c b/gui/dbg_pattern_table.c new file mode 100644 index 0000000..217a83a --- /dev/null +++ b/gui/dbg_pattern_table.c @@ -0,0 +1,96 @@ +// +// Created by william on 7/12/24. +// + +#include +#include +#include "dbg_pattern_table.h" +#include "../include/ppu.h" +#include "../include/system.h" + +DebugPatternTable pattern_table; + +void dbg_pattern_table_build_bank(DebugPattern *bank, byte *pattern_memory) { + for (int tile_index = 0; tile_index < PATTERN_TABLE_SIZE; tile_index++) { + DebugPattern *pattern = &bank[tile_index]; + + address tile_addr = tile_index * PATTERN_BYTES; + memcpy(pattern->data_low, &pattern_memory[tile_addr], PATTERN_SIZE); + memcpy(pattern->data_high, &pattern_memory[tile_addr + PATTERN_SIZE], PATTERN_SIZE); + } +} + +void dbg_pattern_table_init() { + byte *pattern_memory = system_get_mapper()->ppu_read(0); + + dbg_pattern_table_build_bank(pattern_table.bank_0, pattern_memory); + dbg_pattern_table_build_bank(pattern_table.bank_1, &pattern_memory[PATTERN_BANK_SIZE]); +} + +DebugPattern dbg_pattern_get(int x, int y, int bank) { + address pattern_addr = x + y * PATTERN_TABLE_WIDTH; + + switch (bank) { + case PATTERN_BANK_0: + return pattern_table.bank_0[pattern_addr]; + case PATTERN_BANK_1: + return pattern_table.bank_1[pattern_addr]; + default: + assert(false); + } +} + +void dbg_pattern_draw_borders(pixel *buffer, int buffer_width) { + for (int by = 0; by < PATTERN_DRAW_SIZE; by++) { + address pixel_addr = (by * buffer_width) + PATTERN_DRAW_SIZE - 1; + buffer[pixel_addr] = PATTERN_BORDER_COLOR; + } + + for (int bx = 0; bx < PATTERN_DRAW_SIZE; bx++) { + address pixel_addr = ((PATTERN_DRAW_SIZE - 1) * buffer_width) + bx; + buffer[pixel_addr] = PATTERN_BORDER_COLOR; + } +} + +void dbg_pattern_draw(int x, int y, int bank, pixel *buffer, int buffer_width) { + DebugPattern pattern = dbg_pattern_get(x, y, bank); + for (int fine_y = 0; fine_y < PATTERN_SIZE; fine_y++) { + byte data_high = pattern.data_high[fine_y]; + byte data_low = pattern.data_low[fine_y]; + + for (int fine_x = 0; fine_x < PATTERN_SIZE; fine_x++) { + byte bitmask = 1 << (PATTERN_SIZE - fine_x - 1); + byte bit_high = data_high & bitmask; + byte bit_low = data_low & bitmask; + + address pixel_addr = fine_x + fine_y * buffer_width; + pixel *pixel = &buffer[pixel_addr]; + + // TODO: Use palette colors + if (bit_high && bit_low) { + *pixel = 0xffffffff; + } else if (bit_low) { + *pixel = 0xffff0000; + } else if (bit_high) { + *pixel = 0xff00ffff; + } else { + *pixel = 0xff000000; + } + } + } + + dbg_pattern_draw_borders(buffer, buffer_width); +} + +void dbg_pattern_draw_bank(int bank, pixel *buffer) { + int buffer_width = PATTERN_TABLE_WIDTH * PATTERN_DRAW_SIZE; + + for (int x = 0; x < PATTERN_TABLE_WIDTH; x++) { + for (int y = 0; y < PATTERN_TABLE_WIDTH; y++) { + address row_addr = (y * PATTERN_DRAW_SIZE) * buffer_width; + address tile_addr = row_addr + (x * PATTERN_DRAW_SIZE); + + dbg_pattern_draw(x, y, bank, &buffer[tile_addr], buffer_width); + } + } +} \ No newline at end of file diff --git a/gui/dbg_pattern_table.h b/gui/dbg_pattern_table.h new file mode 100644 index 0000000..cfe60d2 --- /dev/null +++ b/gui/dbg_pattern_table.h @@ -0,0 +1,43 @@ +// +// Created by william on 7/12/24. +// + +#ifndef NES_EMULATOR_DBG_PATTERN_TABLE_H +#define NES_EMULATOR_DBG_PATTERN_TABLE_H + +#include +#include "../include/types.h" + +#define PATTERN_BANK_SIZE 0x1000 +#define PATTERN_TABLE_WIDTH 0x10 +#define PATTERN_TABLE_SIZE (PATTERN_TABLE_WIDTH * PATTERN_TABLE_WIDTH) +#define PATTERN_SIZE 8 +#define PATTERN_BYTES (PATTERN_SIZE * 2) +#define PATTERN_BORDER_WIDTH 1 +#define PATTERN_BORDER_COLOR 0xff2223b2 +#define PATTERN_DRAW_SIZE (PATTERN_SIZE + PATTERN_BORDER_WIDTH) + +#define PATTERN_BANK_0 0 +#define PATTERN_BANK_1 1 + +typedef unsigned int pixel; + +typedef struct dbg_pattern { + byte data_low[PATTERN_SIZE]; + byte data_high[PATTERN_SIZE]; +} DebugPattern; + +typedef struct dbg_pattern_table { + DebugPattern bank_0[PATTERN_TABLE_SIZE]; + DebugPattern bank_1[PATTERN_TABLE_SIZE]; +} DebugPatternTable; + +void dbg_pattern_table_init(); + +DebugPattern dbg_pattern_get(int x, int y, int bank); + +void dbg_pattern_draw(int x, int y, int bank, pixel *buffer, int buffer_width); + +void dbg_pattern_draw_bank(int bank, pixel *buffer); + +#endif //NES_EMULATOR_DBG_PATTERN_TABLE_H diff --git a/gui/gui.c b/gui/gui.c index daba98b..d3936e1 100644 --- a/gui/gui.c +++ b/gui/gui.c @@ -9,6 +9,7 @@ #include "pattern_window.h" #include "../include/system.h" #include "nametable_window.h" +#include "dbg_pattern_table.h" typedef struct nes_gui { NesMainWindow main_window; @@ -21,6 +22,7 @@ typedef struct nes_gui { bool debug_enabled; Uint32 last_frame_tick; Uint32 frame_delay; + unsigned long tick; } NesGui; NesGui gui; @@ -32,16 +34,14 @@ bool gui_init() { return false; } - gui.debug_enabled = false; + gui.debug_enabled = true; + gui.tick = 0; main_window_init(&gui.main_window, gui.font); if (gui.debug_enabled) { - byte *pattern_memory = system_get_mapper()->ppu_read(0); - pattern_window_init(&gui.pattern_window, pattern_memory); - - PPUMemory *ppu_memory = &ppu_get_state()->memory; - nametable_window_init(&gui.nametable_window, ppu_memory->nametable_0, ppu_memory->nametable_1); + pattern_window_init(&gui.pattern_window); +// nametable_window_init(&gui.nametable_window); } return true; @@ -52,7 +52,7 @@ void gui_uninit() { if (gui.debug_enabled) { pattern_window_uninit(&gui.pattern_window); - nametable_window_uninit(&gui.nametable_window); +// nametable_window_uninit(&gui.nametable_window); } TTF_CloseFont(gui.font); @@ -60,8 +60,9 @@ void gui_uninit() { void gui_post_sysinit() { if (gui.debug_enabled) { + dbg_pattern_table_init(); + pattern_window_build_table(&gui.pattern_window); - nametable_window_update(&gui.nametable_window); } } @@ -82,8 +83,15 @@ void gui_render() { if (gui.debug_enabled) { pattern_window_render(&gui.pattern_window); - nametable_window_render(&gui.nametable_window); + +// if (gui.tick % 60 == 0) { +// PPUMemory *ppu_memory = &ppu_get_state()->memory; +// nametable_window_update(&gui.nametable_window, ppu_memory->nametable_0, ppu_memory->nametable_1); +// } +// nametable_window_render(&gui.nametable_window); } + + gui.tick++; } void gui_present() { @@ -91,7 +99,7 @@ void gui_present() { if (gui.debug_enabled) { pattern_window_present(&gui.pattern_window); - nametable_window_present(&gui.nametable_window); +// nametable_window_present(&gui.nametable_window); } } diff --git a/gui/nametable_window.c b/gui/nametable_window.c index 1453c1d..906f473 100644 --- a/gui/nametable_window.c +++ b/gui/nametable_window.c @@ -7,14 +7,11 @@ #define NAMETABLE_BANK_SIZE 0x0400 -void nametable_window_init(NesNametableWindow *window, byte *nametable_0, byte *nametable_1) { +void nametable_window_init(NesNametableWindow *window) { int win_size = pattern_display_get_size(NW_ROW_TILE_COUNT); window->sdl_context = window_init("Nametable", win_size, win_size, NW_SCALE); - window->nametable_0 = nametable_0; - window->nametable_1 = nametable_1; - - pattern_display_init(&window->pattern_display, window->sdl_context.renderer, NW_ROW_TILE_COUNT, NW_ROW_TILE_COUNT, + pattern_display_init(&window->pattern_display, window->sdl_context.renderer, NW_ROW_TILE_COUNT, NW_ROW_TILE_COUNT - 2, PATTERN_DISPLAY_DYNAMIC); } @@ -27,7 +24,7 @@ static byte *nametable_window_read_byte(address addr, void *data) { assert(addr < NAMETABLE_BANK_SIZE * 4); assert(data != NULL); - NesNametableWindow *window = (NesNametableWindow *) data; + byte **nametables = (byte **) data; int bank = addr / NAMETABLE_BANK_SIZE; int bank_addr = addr % NAMETABLE_BANK_SIZE; @@ -35,14 +32,18 @@ static byte *nametable_window_read_byte(address addr, void *data) { switch (bank) { case 0: case 1: - return &window->nametable_0[bank_addr]; + return &nametables[0][bank_addr]; default: - return &window->nametable_1[bank_addr]; + return &nametables[1][bank_addr]; } } -void nametable_window_update(NesNametableWindow *window) { - pattern_display_build(&window->pattern_display, &nametable_window_read_byte, window); +void nametable_window_update(NesNametableWindow *window, byte *nametable_0, byte *nametable_1) { + byte **nametables[2]; + nametables[0] = &nametable_0; + nametables[1] = &nametable_1; + + pattern_display_build(&window->pattern_display, &nametable_window_read_byte, nametables); } void nametable_window_render(NesNametableWindow *window) { diff --git a/gui/nametable_window.h b/gui/nametable_window.h index edb8fa5..1383046 100644 --- a/gui/nametable_window.h +++ b/gui/nametable_window.h @@ -15,15 +15,12 @@ typedef struct nes_nametable_window { NesSdlContext sdl_context; PatternDisplay pattern_display; - - byte *nametable_0; - byte *nametable_1; } NesNametableWindow; -void nametable_window_init(NesNametableWindow *window, byte* nametable_0, byte* nametable_1); +void nametable_window_init(NesNametableWindow *window); void nametable_window_uninit(NesNametableWindow *window); -void nametable_window_update(NesNametableWindow *window); +void nametable_window_update(NesNametableWindow *window, byte* nametable_0, byte* nametable_1); void nametable_window_render(NesNametableWindow *window); void nametable_window_present(NesNametableWindow *window); diff --git a/gui/pattern_window.c b/gui/pattern_window.c index ebd6b3f..bd47da1 100644 --- a/gui/pattern_window.c +++ b/gui/pattern_window.c @@ -2,41 +2,43 @@ // Created by william on 6/14/24. // -#include #include "pattern_window.h" +#include "dbg_pattern_table.h" #define PW_SCALE 2 +#define PW_WIDTH (PW_ROW_TILE_COUNT * PATTERN_DRAW_SIZE) +#define PW_HEIGHT (PW_WIDTH * 2) +#define PW_BUFFER_SIZE (PW_WIDTH * PW_HEIGHT) -void pattern_window_init(NesPatternWindow *window, byte *pattern_memory) { +void pattern_window_init(NesPatternWindow *window) { int win_width = pattern_display_get_size(PW_ROW_TILE_COUNT); window->sdl_context = window_init("Pattern Table", win_width, win_width * 2, PW_SCALE); - window->pattern_memory = pattern_memory; - pattern_display_init(&window->pattern_display, window->sdl_context.renderer, PW_ROW_TILE_COUNT, - PW_ROW_TILE_COUNT * 2, PATTERN_DISPLAY_STATIC); + window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STATIC, PW_WIDTH, PW_HEIGHT); + +// pattern_display_init(&window->pattern_display, window->sdl_context.renderer, PW_ROW_TILE_COUNT, +// PW_ROW_TILE_COUNT * 2, PATTERN_DISPLAY_STATIC); } void pattern_window_uninit(NesPatternWindow *window) { - pattern_display_uninit(&window->pattern_display); + SDL_DestroyTexture(window->texture); +// pattern_display_uninit(&window->pattern_display); window_uninit(window->sdl_context); } -static byte *pattern_window_read_byte(address addr, void *data) { - assert(data != NULL); - assert(addr < 0x2000); - - NesPatternWindow *window = (NesPatternWindow *) data; - - return &window->pattern_memory[addr]; -} - void pattern_window_build_table(NesPatternWindow *window) { - pattern_display_build(&window->pattern_display, &pattern_window_read_byte, window); + pixel buffer[PW_BUFFER_SIZE] = {0}; + dbg_pattern_draw_bank(PATTERN_BANK_0, buffer); + dbg_pattern_draw_bank(PATTERN_BANK_1, &buffer[PW_WIDTH * (PW_HEIGHT / 2)]); + + SDL_UpdateTexture(window->texture, NULL, buffer, PW_WIDTH * sizeof(pixel)); } void pattern_window_render(NesPatternWindow *window) { SDL_RenderClear(window->sdl_context.renderer); - pattern_display_render(&window->pattern_display, window->sdl_context.renderer); + SDL_RenderCopy(window->sdl_context.renderer, window->texture, NULL, NULL); +// pattern_display_render(&window->pattern_display, window->sdl_context.renderer); } void pattern_window_present(NesPatternWindow *window) { diff --git a/gui/pattern_window.h b/gui/pattern_window.h index 9d004ca..c78386f 100644 --- a/gui/pattern_window.h +++ b/gui/pattern_window.h @@ -14,10 +14,10 @@ typedef struct nes_pattern_window { NesSdlContext sdl_context; PatternDisplay pattern_display; - byte* pattern_memory; + SDL_Texture *texture; } NesPatternWindow; -void pattern_window_init(NesPatternWindow *window, byte *pattern_memory); +void pattern_window_init(NesPatternWindow *window); void pattern_window_uninit(NesPatternWindow *window); void pattern_window_build_table(NesPatternWindow *window); diff --git a/include/ppu.h b/include/ppu.h index 3592ebf..eba088f 100644 --- a/include/ppu.h +++ b/include/ppu.h @@ -52,14 +52,14 @@ #define PPU_MASK_NONE 0xff -#define PATTERN_TABLE_SIZE 0x1000 -#define NAMETABLE_SIZE 0x0400 -#define PALETTE_TABLE_SIZE 0x0020 +#define PATTERN_TABLE_BYTES_SIZE 0x1000 +#define NAMETABLE_BYTES_SIZE 0x0400 +#define PALETTE_TABLE_BYTES_SIZE 0x0020 typedef struct ppu_memory { - byte nametable_0[NAMETABLE_SIZE]; - byte nametable_1[NAMETABLE_SIZE]; - byte palette[PALETTE_TABLE_SIZE]; + byte nametable_0[NAMETABLE_BYTES_SIZE]; + byte nametable_1[NAMETABLE_BYTES_SIZE]; + byte palette[PALETTE_TABLE_BYTES_SIZE]; } PPUMemory; typedef struct ppu_tile_fetch { diff --git a/ppu/ppu.c b/ppu/ppu.c index 66fd4ec..cd2b6e3 100644 --- a/ppu/ppu.c +++ b/ppu/ppu.c @@ -252,7 +252,7 @@ void ppu_cycle() { ppu_post_render(ppu_state.cycle, ppu_state.scanline); } else if (ppu_state.scanline == PPU_PRE_RENDER_LINE) { ppu_pre_render(ppu_state.cycle); - ppu_visible_frame(ppu_state.cycle); +// ppu_visible_frame(ppu_state.cycle); ppu_state.ppu_address = ppu_state.temp_ppu_addr; } @@ -315,7 +315,7 @@ void ppu_write(address addr, byte data) { relative_addr = addr - 0x2c00; ppu_state.memory.nametable_1[relative_addr] = data; } else if (addr >= 0x3f00) { - relative_addr = (addr - 0x3f00) % PALETTE_TABLE_SIZE; + relative_addr = (addr - 0x3f00) % PALETTE_TABLE_BYTES_SIZE; ppu_state.memory.palette[relative_addr] = data; } } @@ -356,7 +356,7 @@ byte ppu_read(address addr) { relative_addr = addr - 0x2c00; return ppu_state.memory.nametable_1[relative_addr]; } else if (addr >= 0x3f00) { - relative_addr = (addr - 0x3f00) % PALETTE_TABLE_SIZE; + relative_addr = (addr - 0x3f00) % PALETTE_TABLE_BYTES_SIZE; return ppu_state.memory.palette[relative_addr]; }