diff --git a/gui/canvas.c b/gui/canvas.c index f2e97fa..1753a16 100644 --- a/gui/canvas.c +++ b/gui/canvas.c @@ -28,14 +28,21 @@ void canvas_uninit(Canvas *canvas) { free(canvas->pixels); } -void canvas_draw(Canvas *canvas, Pixel pixel, int x, int y) { +void canvas_draw(Canvas *canvas, Pixel pixel, int index) { + assert(index >= 0); + assert(index < canvas->width * canvas->height); + + canvas->pixels[index] = pixel; +} + +void canvas_draw_pos(Canvas *canvas, Pixel pixel, int x, int y) { assert(x >= 0); assert(x < canvas->width); assert(y >= 0); assert(y < canvas->height); - int pixel_index = x + y * canvas->width; - canvas->pixels[pixel_index] = pixel; + int index = x + y * canvas->width; + canvas_draw(canvas, pixel, index); } void canvas_reset(Canvas *canvas) { diff --git a/gui/canvas.h b/gui/canvas.h index 8904124..58bb796 100644 --- a/gui/canvas.h +++ b/gui/canvas.h @@ -7,9 +7,6 @@ #include "../include/types.h" -//#define CANVAS_WIDTH 256 -//#define CANVAS_HEIGHT 240 - typedef struct pixel { byte r; byte g; @@ -25,7 +22,8 @@ typedef struct canvas { Canvas canvas_init(int width, int height); void canvas_uninit(Canvas *canvas); -void canvas_draw(Canvas *canvas, Pixel pixel, int x, int y); +void canvas_draw(Canvas *canvas, Pixel pixel, int index); +void canvas_draw_pos(Canvas *canvas, Pixel pixel, int x, int y); void canvas_reset(Canvas *canvas); #endif //NES_EMULATOR_CANVAS_H diff --git a/gui/gui.c b/gui/gui.c index 6f75932..e873aa8 100644 --- a/gui/gui.c +++ b/gui/gui.c @@ -3,14 +3,20 @@ // #include -#include "gui.h" #include "log.h" +#include "gui.h" +#include "window.h" +typedef struct nes_gui { + NesWindow main_window; + NesWindow debug_pattern_window; +} NesGui; NesGui gui; void gui_init() { - gui.main_window = window_init(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, "NES Emulator"); - gui.debug_pattern_window = window_init(DEBUG_PATTERN_WIDTH, DEBUG_PATTERN_HEIGHT, "Pattern Table"); + gui.main_window = window_init(WINDOW_MAIN_WIDTH, WINDOW_MAIN_HEIGHT, WINDOW_MAIN_SCALING, "NES Emulator"); + gui.debug_pattern_window = window_init(WINDOW_PATTERN_WIDTH, WINDOW_PATTERN_HEIGHT, WINDOW_PATTERN_SCALING, + "Pattern Table"); } void gui_uninit() { @@ -40,14 +46,18 @@ void gui_present() { window_present(&gui.debug_pattern_window); } +void gui_delay() { + SDL_Delay(16); +} + Canvas *gui_get_canvas(char win_id) { NesWindow *window; switch (win_id) { - case GUI_WINDOW_MAIN: + case WINDOW_ID_MAIN: window = &gui.main_window; break; - case GUI_WINDOW_PATTERN: + case WINDOW_ID_PATTERN: window = &gui.debug_pattern_window; break; default: diff --git a/gui/gui.h b/gui/gui.h index 52afb65..24d737e 100644 --- a/gui/gui.h +++ b/gui/gui.h @@ -5,22 +5,17 @@ #ifndef NES_EMULATOR_GUI_H #define NES_EMULATOR_GUI_H -#include #include "canvas.h" -#include "window.h" -#define MAIN_WINDOW_WIDTH 256 -#define MAIN_WINDOW_HEIGHT 240 -#define DEBUG_PATTERN_WIDTH 100 -#define DEBUG_PATTERN_HEIGHT 100 +#define WINDOW_ID_MAIN 1 +#define WINDOW_MAIN_WIDTH 256 +#define WINDOW_MAIN_HEIGHT 240 +#define WINDOW_MAIN_SCALING 3 -#define GUI_WINDOW_MAIN 1 -#define GUI_WINDOW_PATTERN 2 - -typedef struct nes_gui { - NesWindow main_window; - NesWindow debug_pattern_window; -} NesGui; +#define WINDOW_ID_PATTERN 2 +#define WINDOW_PATTERN_WIDTH 128 +#define WINDOW_PATTERN_HEIGHT 256 +#define WINDOW_PATTERN_SCALING 2 void gui_init(); void gui_uninit(); @@ -28,6 +23,7 @@ void gui_uninit(); int gui_input(); void gui_render(); void gui_present(); +void gui_delay(); Canvas *gui_get_canvas(char win_id); diff --git a/gui/window.c b/gui/window.c index 47d787f..4597972 100644 --- a/gui/window.c +++ b/gui/window.c @@ -2,13 +2,15 @@ // Created by william on 17/05/24. // +#include #include "window.h" #include "log.h" -NesWindow window_init(int width, int height, char *title) { +NesWindow window_init(int width, int height, int scaling, char *title) { NesWindow win; - win.width = width * WINDOW_SCALING; - win.height = height * WINDOW_SCALING; + win.scaling = scaling; + win.width = width * scaling; + win.height = height * scaling; win.canvas = canvas_init(width, height); int renderer_flags = SDL_RENDERER_ACCELERATED; @@ -44,17 +46,17 @@ void window_uninit(NesWindow *window) { void window_render(NesWindow *window) { SDL_RenderClear(window->renderer); - for (int x = 0; x < window->canvas.width; x++) { - for (int y = 0; y < window->canvas.height; y++) { + for (int y = 0; y < window->canvas.height; y++) { + for (int x = 0; x < window->canvas.width; x++) { int pixel_index = x + y * window->canvas.width; Pixel pixel = window->canvas.pixels[pixel_index]; SDL_SetRenderDrawColor(window->renderer, pixel.r, pixel.g, pixel.b, 255); - for (int i = 0; i < WINDOW_SCALING; i++) { - for (int j = 0; j < WINDOW_SCALING; j++) { - int scaled_x = x * WINDOW_SCALING + i; - int scaled_y = y * WINDOW_SCALING + j; + for (int i = 0; i < window->scaling; i++) { + for (int j = 0; j < window->scaling; j++) { + int scaled_x = x * window->scaling + i; + int scaled_y = y * window->scaling + j; SDL_RenderDrawPoint(window->renderer, scaled_x, scaled_y); } } @@ -64,4 +66,7 @@ void window_render(NesWindow *window) { void window_present(NesWindow *window) { SDL_RenderPresent(window->renderer); + + // TODO: Check if this is a good location + canvas_reset(&window->canvas); } \ No newline at end of file diff --git a/gui/window.h b/gui/window.h index a3e32be..848753a 100644 --- a/gui/window.h +++ b/gui/window.h @@ -8,18 +8,17 @@ #include #include "canvas.h" -#define WINDOW_SCALING 3 - -typedef struct new_window { +typedef struct nes_window { SDL_Renderer *renderer; SDL_Window *window; int width; int height; + int scaling; Canvas canvas; } NesWindow; -NesWindow window_init(int width, int height, char *title); +NesWindow window_init(int width, int height, int scaling, char *title); void window_uninit(NesWindow *window); void window_render(NesWindow *window); diff --git a/include/ppu.h b/include/ppu.h index 19a90e4..27619d7 100644 --- a/include/ppu.h +++ b/include/ppu.h @@ -63,9 +63,11 @@ typedef struct ppu { byte x; bool w; + bool fetching; + unsigned long frame; - unsigned int line; - unsigned int line_x; + unsigned int scanline; + unsigned int cycle; } PPU; PPU *ppu_get_state(); diff --git a/main.c b/main.c index a3b90e6..af07fe7 100644 --- a/main.c +++ b/main.c @@ -27,7 +27,7 @@ int main() { log_set_level(LOG_INFO); system_init(); - char *rom_path = "../test_roms/dk_jp.nes"; + char *rom_path = "../test_roms/smb.nes"; if (!rom_load(rom_path)) { system_uninit(); @@ -47,8 +47,7 @@ int main() { gui_render(); gui_present(); - - SDL_Delay(16); + gui_delay(); } system_uninit(); diff --git a/ppu/CMakeLists.txt b/ppu/CMakeLists.txt index 856c169..fbf880c 100644 --- a/ppu/CMakeLists.txt +++ b/ppu/CMakeLists.txt @@ -1,5 +1,7 @@ -set(SOURCE ppu.c) +set(HEADERS pattern_table.h + ppu.h) +set(SOURCE pattern_table.c ppu.c) -add_library(nes_ppu ${SOURCE}) +add_library(nes_ppu ${SOURCE} ${HEADERS}) target_link_libraries(nes_ppu log.c) \ No newline at end of file diff --git a/ppu/pattern_table.c b/ppu/pattern_table.c new file mode 100644 index 0000000..01bb034 --- /dev/null +++ b/ppu/pattern_table.c @@ -0,0 +1,57 @@ +// +// Created by william on 17/05/24. +// + +#include "pattern_table.h" +#include "ppu.h" +#include "../gui/canvas.h" +#include "../gui/gui.h" + +void pt_debug() { + Canvas *canvas = gui_get_canvas(WINDOW_ID_PATTERN); + + for (int palette = 0; palette < 2; palette++) { + address palette_addr = palette * 0x1000; + int palette_canvas_offset = palette * (PATTERN_TABLE_WIDTH * PATTERN_TILE_SIZE); + + for (int y = 0; y < PATTERN_TABLE_WIDTH; y++) { + for (int x = 0; x < PATTERN_TABLE_WIDTH; x++) { + address tile_addr = palette_addr + (x + y * PATTERN_TABLE_WIDTH) * PATTERN_TILE_MEM_SIZE; + + for (int tile_y = 0; tile_y < PATTERN_TILE_SIZE; tile_y++) { + byte p1_data = ppu_read(tile_addr + tile_y); + byte p2_data = ppu_read(tile_addr + tile_y + PATTERN_TILE_SIZE); + + for (int tile_x = 0; tile_x < PATTERN_TILE_SIZE; tile_x++) { + byte bitmask = 1 << (PATTERN_TILE_SIZE - tile_x - 1); + byte p1_byte = p1_data & bitmask; + byte p2_byte = p2_data & bitmask; + + Pixel pixel; + if (p1_byte && p2_byte) { + pixel.r = 255; + pixel.g = 255; + pixel.b = 255; + } else if (p2_byte) { + pixel.r = 255; + pixel.g = 0; + pixel.b = 0; + } else if (p1_byte) { + pixel.r = 0; + pixel.g = 255; + pixel.b = 255; + } else { + pixel.r = 0; + pixel.g = 0; + pixel.b = 0; + } + + int canvas_x = x * PATTERN_TILE_SIZE + tile_x; + int canvas_y = y * PATTERN_TILE_SIZE + tile_y + palette_canvas_offset; + canvas_draw_pos(canvas, pixel, canvas_x, canvas_y); + } + } + } + } + } +} \ No newline at end of file diff --git a/ppu/pattern_table.h b/ppu/pattern_table.h new file mode 100644 index 0000000..d8bb6ef --- /dev/null +++ b/ppu/pattern_table.h @@ -0,0 +1,14 @@ +// +// Created by william on 17/05/24. +// + +#ifndef NES_EMULATOR_PATTERN_TABLE_H +#define NES_EMULATOR_PATTERN_TABLE_H + +#define PATTERN_TABLE_WIDTH 16 +#define PATTERN_TILE_MEM_SIZE 16 +#define PATTERN_TILE_SIZE (PATTERN_TILE_MEM_SIZE / 2) + +void pt_debug(); + +#endif //NES_EMULATOR_PATTERN_TABLE_H diff --git a/ppu/ppu.c b/ppu/ppu.c index 4d7a822..2f35534 100644 --- a/ppu/ppu.c +++ b/ppu/ppu.c @@ -15,6 +15,7 @@ // #include +#include "ppu.h" #include "../include/ppu.h" #include "../cpu/cpu.h" @@ -39,10 +40,11 @@ void ppu_init(byte *registers_ram, byte *oam_dma_register) { ppu_state.registers[PPU_REGISTER_DATA] = 0x00; ppu_state.oam_dma_register = oam_dma_register; ppu_state.odd_frame = false; + ppu_state.fetching = false; ppu_state.frame = 0; - ppu_state.line = 0; - ppu_state.line_x = 0; + ppu_state.scanline = 0; + ppu_state.cycle = 0; } PPU *ppu_get_state() { @@ -66,10 +68,34 @@ void ppu_trigger_vbl_nmi() { cpu_trigger_nmi(); } -void ppu_visible_frame(unsigned int x) { - if (x >= 257 && x <= 320) { +typedef struct { + byte nametable; + byte attribute_table; + byte pattern_table_tile_low; + byte pattern_table_tile_high; + + byte fetch_tick; +} Tile; +Tile tile; + +void ppu_visible_frame(unsigned int cycle) { + if (cycle == 0) { + // Idle... + } else if (cycle <= 256) { + switch (tile.fetch_tick) { + + } + + if (tile.nametable == 0) { + + } + + tile.fetch_tick++; + } else if (cycle <= 320) { // OAMADDR is cleared on sprite loading for pre-render and visible lines ppu_write_reg(PPU_REGISTER_OAM_ADDR, 0); + } else { + } } @@ -94,12 +120,12 @@ void ppu_post_render(unsigned int x, unsigned int y) { } void ppu_cycle() { - if (ppu_state.line < PPU_VISIBLE_FRAME_END) { - ppu_visible_frame(ppu_state.line_x); - } else if (ppu_state.line >= PPU_POST_RENDER_LINE_START && ppu_state.line <= PPU_POST_RENDER_LINE_END) { - ppu_post_render(ppu_state.line_x, ppu_state.line); - } else if (ppu_state.line == PPU_PRE_RENDER_LINE) { - ppu_pre_render(ppu_state.line_x); + if (ppu_state.scanline < PPU_VISIBLE_FRAME_END) { + ppu_visible_frame(ppu_state.cycle); + } else if (ppu_state.scanline >= PPU_POST_RENDER_LINE_START && ppu_state.scanline <= PPU_POST_RENDER_LINE_END) { + ppu_post_render(ppu_state.cycle, ppu_state.scanline); + } else if (ppu_state.scanline == PPU_PRE_RENDER_LINE) { + ppu_pre_render(ppu_state.cycle); } int frame_width = PPU_LINE_WIDTH; @@ -112,14 +138,14 @@ void ppu_cycle() { frame_height = PPU_LINE_END - 1; } - ppu_state.line_x++; - if (ppu_state.line_x >= frame_width) { - ppu_state.line_x = 0; - ppu_state.line++; + ppu_state.cycle++; + if (ppu_state.cycle >= frame_width) { + ppu_state.cycle = 0; + ppu_state.scanline++; } - if (ppu_state.line >= frame_height) { - ppu_state.line = 0; + if (ppu_state.scanline >= frame_height) { + ppu_state.scanline = 0; ppu_state.frame++; ppu_state.odd_frame = !ppu_state.odd_frame; } @@ -220,4 +246,10 @@ void ppu_write_reg(byte reg, byte data) { } ppu_write_reg_ram(reg, data); +} + +byte ppu_read(address addr) { + assert(addr < PPU_VRAM_SIZE); + + return ppu_state.vram[addr]; } \ No newline at end of file diff --git a/ppu/ppu.h b/ppu/ppu.h new file mode 100644 index 0000000..367084b --- /dev/null +++ b/ppu/ppu.h @@ -0,0 +1,12 @@ +// +// Created by william on 17/05/24. +// + +#ifndef NES_EMULATOR_PPU_H +#define NES_EMULATOR_PPU_H + +#include "../include/types.h" + +byte ppu_read(address addr); + +#endif //NES_EMULATOR_PPU_H diff --git a/system.c b/system.c index 6485fd0..9620dea 100644 --- a/system.c +++ b/system.c @@ -8,6 +8,7 @@ #include #include #include "cpu.h" +#include "pattern_table.h" System current_sys; @@ -35,6 +36,8 @@ void system_next_frame() { ppu_cycle(); } } + + pt_debug(); } void system_uninit() {