Compare commits

..

2 Commits

Author SHA1 Message Date
FyloZ 96af510b19
Less buggy PPU 2024-07-25 22:08:08 -04:00
FyloZ 54825ecb5a
Move debugging to compiler flag 2024-07-25 21:22:00 -04:00
21 changed files with 85 additions and 426 deletions

View File

@ -3,6 +3,10 @@ set(CMAKE_C_COMPILER gcc)
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(nes_emulator LANGUAGES C VERSION 0.1 ) project(nes_emulator LANGUAGES C VERSION 0.1 )
if (NES_DEBUG)
add_definitions(-DDEBUG=1)
endif(NES_DEBUG)
add_subdirectory(libs/log.c) add_subdirectory(libs/log.c)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
include_directories(${PROJECT_SOURCE_DIR}/libs/log.c/src ${COMMON_INCLUDES}) include_directories(${PROJECT_SOURCE_DIR}/libs/log.c/src ${COMMON_INCLUDES})
@ -11,7 +15,6 @@ add_subdirectory(cpu)
add_subdirectory(ppu) add_subdirectory(ppu)
add_subdirectory(mappers) add_subdirectory(mappers)
add_subdirectory(rom) add_subdirectory(rom)
#add_subdirectory(debugger)
add_subdirectory(utils) add_subdirectory(utils)
add_subdirectory(gui) add_subdirectory(gui)

View File

@ -37,6 +37,7 @@ only tested on Linux. Here is how to run the project:
- Debug - Debug
- Frame Delay: Done - Frame Delay: Done
- Pattern Table Viewer: Done - Pattern Table Viewer: Done
- Nametable Viewer: Done
- CPU Debugger: To Do - CPU Debugger: To Do
- Memory Inspector: To Do - Memory Inspector: To Do
- PPU Debugger: To Do - PPU Debugger: To Do

View File

@ -1,5 +1,10 @@
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 dbg_nametable.h) set(HEADERS gui.h window.h main_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 dbg_pattern_table.c dbg_nametable.c) set(SOURCE gui.c window.c main_window.c)
if (NES_DEBUG)
list(APPEND HEADERS char_map.h pattern_window.h nametable_window.h dbg_pattern_table.h dbg_nametable.h)
list(APPEND SOURCE char_map.c pattern_window.c nametable_window.c dbg_pattern_table.c dbg_nametable.c)
endif (NES_DEBUG)
add_library(nes_gui ${SOURCE} ${HEADERS}) add_library(nes_gui ${SOURCE} ${HEADERS})

View File

@ -1,50 +0,0 @@
//
// Created by william on 16/05/24.
//
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "canvas.h"
Canvas canvas_init(int width, int height) {
assert(width > 0);
assert(height > 0);
Canvas canvas;
canvas.width = width;
canvas.height = height;
int size = width * height;
canvas.pixels = malloc(sizeof(Pixel) * size);
return canvas;
}
void canvas_uninit(Canvas *canvas) {
assert(canvas != NULL);
assert(canvas->pixels != NULL);
free(canvas->pixels);
}
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 index = x + y * canvas->width;
canvas_draw(canvas, pixel, index);
}
void canvas_reset(Canvas *canvas) {
memset(canvas->pixels, 0, sizeof(Pixel) * (canvas->width * canvas->height));
}

View File

@ -1,29 +0,0 @@
//
// Created by william on 16/05/24.
//
#ifndef NES_EMULATOR_CANVAS_H
#define NES_EMULATOR_CANVAS_H
#include "../include/types.h"
typedef struct pixel {
byte r;
byte g;
byte b;
} Pixel;
typedef struct canvas {
int width;
int height;
Pixel *pixels;
} Canvas;
Canvas canvas_init(int width, int height);
void canvas_uninit(Canvas *canvas);
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

View File

@ -11,6 +11,7 @@
#include "nametable_window.h" #include "nametable_window.h"
#include "dbg_pattern_table.h" #include "dbg_pattern_table.h"
#include "dbg_nametable.h" #include "dbg_nametable.h"
#include "char_map.h"
typedef struct nes_gui { typedef struct nes_gui {
NesMainWindow main_window; NesMainWindow main_window;
@ -19,11 +20,12 @@ typedef struct nes_gui {
TTF_Font *font; TTF_Font *font;
// Debug info
bool debug_enabled;
Uint32 last_frame_tick; Uint32 last_frame_tick;
Uint32 frame_delay; Uint32 frame_delay;
#if DEBUG
unsigned long tick; unsigned long tick;
#endif
} NesGui; } NesGui;
NesGui gui; NesGui gui;
@ -35,15 +37,15 @@ bool gui_init() {
return false; return false;
} }
gui.debug_enabled = true; #if DEBUG
gui.tick = 0; gui.tick = 0;
pattern_window_init(&gui.pattern_window);
nametable_window_init(&gui.nametable_window);
main_window_init(&gui.main_window, gui.font); char_map_init(gui.main_window.sdl_context.renderer, gui.font);
#endif
if (gui.debug_enabled) { main_window_init(&gui.main_window);
pattern_window_init(&gui.pattern_window);
nametable_window_init(&gui.nametable_window);
}
return true; return true;
} }
@ -51,22 +53,24 @@ bool gui_init() {
void gui_uninit() { void gui_uninit() {
main_window_uninit(&gui.main_window); main_window_uninit(&gui.main_window);
if (gui.debug_enabled) { #if DEBUG
pattern_window_uninit(&gui.pattern_window); char_map_uninit();
nametable_window_uninit(&gui.nametable_window);
} pattern_window_uninit(&gui.pattern_window);
nametable_window_uninit(&gui.nametable_window);
#endif
TTF_CloseFont(gui.font); TTF_CloseFont(gui.font);
} }
void gui_post_sysinit() { void gui_post_sysinit() {
if (gui.debug_enabled) { #if DEBUG
dbg_pattern_table_init(); dbg_pattern_table_init();
dbg_nametable_init(); dbg_nametable_init();
pattern_window_build_table(&gui.pattern_window); pattern_window_build_table(&gui.pattern_window);
nametable_window_update(&gui.nametable_window); nametable_window_update(&gui.nametable_window);
} #endif
} }
int gui_input() { int gui_input() {
@ -82,27 +86,25 @@ int gui_input() {
} }
void gui_render() { void gui_render() {
main_window_render(&gui.main_window, ppu_get_state()->pixels); #if DEBUG
pattern_window_render(&gui.pattern_window);
if (gui.debug_enabled) { nametable_window_update(&gui.nametable_window);
pattern_window_render(&gui.pattern_window); nametable_window_render(&gui.nametable_window);
// if (gui.tick % 60 == 0) {
nametable_window_update(&gui.nametable_window);
// }
nametable_window_render(&gui.nametable_window);
}
gui.tick++; gui.tick++;
#endif
main_window_render(&gui.main_window, ppu_get_state()->pixels);
} }
void gui_present() { void gui_present() {
main_window_present(&gui.main_window); #if DEBUG
pattern_window_present(&gui.pattern_window);
nametable_window_present(&gui.nametable_window);
#endif
if (gui.debug_enabled) { main_window_present(&gui.main_window);
pattern_window_present(&gui.pattern_window);
nametable_window_present(&gui.nametable_window);
}
} }
void gui_delay() { void gui_delay() {
@ -118,10 +120,6 @@ void gui_delay() {
gui.last_frame_tick = SDL_GetTicks(); gui.last_frame_tick = SDL_GetTicks();
} }
bool gui_debug_enabled() {
return gui.debug_enabled;
}
unsigned int gui_get_frame_delay() { unsigned int gui_get_frame_delay() {
return gui.frame_delay; return gui.frame_delay;
} }

View File

@ -6,7 +6,6 @@
#define NES_EMULATOR_GUI_H #define NES_EMULATOR_GUI_H
#include <stdbool.h> #include <stdbool.h>
#include "canvas.h"
bool gui_init(); bool gui_init();
void gui_uninit(); void gui_uninit();
@ -18,7 +17,6 @@ void gui_render();
void gui_present(); void gui_present();
void gui_delay(); void gui_delay();
bool gui_debug_enabled();
unsigned int gui_get_frame_delay(); unsigned int gui_get_frame_delay();
#endif //NES_EMULATOR_GUI_H #endif //NES_EMULATOR_GUI_H

View File

@ -8,20 +8,18 @@
#include "char_map.h" #include "char_map.h"
#include "gui.h" #include "gui.h"
void main_window_init(NesMainWindow *window, TTF_Font *font) { void main_window_init(NesMainWindow *window) {
window->sdl_context = window_init("NES Emulator", MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, MAIN_WINDOW_SCALE); window->sdl_context = window_init("NES Emulator", MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, MAIN_WINDOW_SCALE);
window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888, window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT); SDL_TEXTUREACCESS_STREAMING, MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT);
char_map_init(window->sdl_context.renderer, font);
} }
void main_window_uninit(NesMainWindow *window) { void main_window_uninit(NesMainWindow *window) {
char_map_uninit();
SDL_DestroyTexture(window->texture); SDL_DestroyTexture(window->texture);
window_uninit(window->sdl_context); window_uninit(window->sdl_context);
} }
#if DEBUG
void main_window_render_delay(SDL_Renderer *renderer) { void main_window_render_delay(SDL_Renderer *renderer) {
Uint32 delay = gui_get_frame_delay(); Uint32 delay = gui_get_frame_delay();
@ -34,12 +32,12 @@ void main_window_render_delay(SDL_Renderer *renderer) {
char_map_render(renderer, buffer); char_map_render(renderer, buffer);
} }
#endif
void main_window_render(NesMainWindow *window, PPUPixel *pixels) { void main_window_render(NesMainWindow *window, PPUPixel *pixels) {
SDL_RenderClear(window->sdl_context.renderer); SDL_RenderClear(window->sdl_context.renderer);
unsigned int frame_buffer[240 * 256]; unsigned int frame_buffer[240 * 256];
for (int i = 0; i < 240 * 256; i++) { for (int i = 0; i < 240 * 256; i++) {
PPUPixel pixel = pixels[i]; PPUPixel pixel = pixels[i];
@ -53,9 +51,9 @@ void main_window_render(NesMainWindow *window, PPUPixel *pixels) {
SDL_UpdateTexture(window->texture, NULL, &frame_buffer, 240 * sizeof(unsigned int)); SDL_UpdateTexture(window->texture, NULL, &frame_buffer, 240 * sizeof(unsigned int));
SDL_RenderCopy(window->sdl_context.renderer, window->texture, NULL, NULL); SDL_RenderCopy(window->sdl_context.renderer, window->texture, NULL, NULL);
if (gui_debug_enabled()) { #if DEBUG
main_window_render_delay(window->sdl_context.renderer); main_window_render_delay(window->sdl_context.renderer);
} #endif
} }
void main_window_present(NesMainWindow *window) { void main_window_present(NesMainWindow *window) {

View File

@ -19,7 +19,7 @@ typedef struct nes_main_window {
SDL_Texture *texture; SDL_Texture *texture;
} NesMainWindow; } NesMainWindow;
void main_window_init(NesMainWindow *window, TTF_Font *font); void main_window_init(NesMainWindow *window);
void main_window_uninit(NesMainWindow *window); void main_window_uninit(NesMainWindow *window);
void main_window_render(NesMainWindow *window, PPUPixel* pixels); void main_window_render(NesMainWindow *window, PPUPixel* pixels);

View File

@ -10,8 +10,7 @@
#define NW_BUFFER_SIZE (NAMETABLE_ROW_WIDTH * NAMETABLE_COL_HEIGHT * PATTERN_DRAW_SIZE * PATTERN_DRAW_SIZE) #define NW_BUFFER_SIZE (NAMETABLE_ROW_WIDTH * NAMETABLE_COL_HEIGHT * PATTERN_DRAW_SIZE * PATTERN_DRAW_SIZE)
void nametable_window_init(NesNametableWindow *window) { void nametable_window_init(NesNametableWindow *window) {
int win_size = pattern_display_get_size(NW_ROW_TILE_COUNT); window->sdl_context = window_init("Nametable", NW_WIDTH, NW_HEIGHT, NW_SCALE);
window->sdl_context = window_init("Nametable", win_size, win_size, NW_SCALE);
window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888, window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, NW_WIDTH, NW_HEIGHT); SDL_TEXTUREACCESS_STREAMING, NW_WIDTH, NW_HEIGHT);
@ -22,7 +21,7 @@ void nametable_window_uninit(NesNametableWindow *window) {
window_uninit(window->sdl_context); window_uninit(window->sdl_context);
} }
void nametable_window_update_bank(NesNametableWindow *window, int bank, pixel* buffer) { void nametable_window_update_bank(NesNametableWindow *window, int bank, pixel *buffer) {
dbg_nametable_render_bank(bank, buffer); dbg_nametable_render_bank(bank, buffer);
SDL_Rect rect; SDL_Rect rect;

View File

@ -7,7 +7,6 @@
#include "window.h" #include "window.h"
#include "../include/types.h" #include "../include/types.h"
#include "pattern_display.h"
#define NW_SCALE 1 #define NW_SCALE 1
#define NW_ROW_COUNT 60 #define NW_ROW_COUNT 60

View File

@ -1,123 +0,0 @@
//
// Created by william on 12/07/24.
//
#include <assert.h>
#include "pattern_display.h"
#define PATTERN_BYTES (PATTERN_SIZE * 2)
void pattern_display_init(PatternDisplay *display, SDL_Renderer *renderer, int tiles_x, int tiles_y, int display_type) {
assert(tiles_x > 0);
assert(tiles_y > 0);
display->width = tiles_x;
display->height = tiles_y;
display->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, display_type,
pattern_display_get_size(tiles_x),
pattern_display_get_size(tiles_y));
}
void pattern_display_uninit(PatternDisplay *display) {
SDL_DestroyTexture(display->texture);
}
void pattern_display_draw_borders(unsigned int *buffer, int win_width, int win_height) {
assert(buffer != NULL);
for (int x = 0; x < win_width; x++) {
buffer[x] = PATTERN_BORDER_COLOR;
}
for (int y = 1; y < win_height; y++) {
buffer[y * win_width] = PATTERN_BORDER_COLOR;
}
}
void pattern_display_build_table(PatternTile *tile_table, int tile_count, read_func read_func,
void *read_func_data) {
for (int tile_index = 0; tile_index < tile_count; tile_index++) {
PatternTile *tile = &tile_table[tile_index];
address tile_addr = tile_index * PATTERN_BYTES;
memcpy(tile->data_low, read_func(tile_addr, read_func_data), 8);
memcpy(tile->data_high, read_func(tile_addr + 8, read_func_data), 8);
}
}
void pattern_display_draw_tile_borders(int tile_addr, pixel *buffer, int win_width) {
assert(buffer != NULL);
for (int by = 0; by < PATTERN_DRAW_SIZE; by++) {
address pixel_addr = tile_addr + (by * win_width) + PATTERN_DRAW_SIZE - 1;
buffer[pixel_addr] = PATTERN_BORDER_COLOR;
}
for (int bx = 0; bx < PATTERN_DRAW_SIZE; bx++) {
address pixel_addr = tile_addr + ((PATTERN_DRAW_SIZE - 1) * win_width) + bx;
buffer[pixel_addr] = PATTERN_BORDER_COLOR;
}
}
void pattern_display_draw_tile(PatternTile *tile, pixel *buffer, int tile_addr, int win_width) {
assert(buffer != NULL);
for (int fine_y = 0; fine_y < PATTERN_SIZE; fine_y++) {
byte data_high = tile->data_high[fine_y];
byte data_low = tile->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;
int pixel_addr = tile_addr + fine_x + fine_y * win_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;
}
}
}
pattern_display_draw_tile_borders(tile_addr, buffer, win_width);
}
void pattern_display_build(PatternDisplay *display, read_func read_func, void *read_func_data) {
int tile_count = display->width * display->height;
PatternTile *tile_table = malloc(tile_count * sizeof(PatternTile));
pattern_display_build_table(tile_table, tile_count, read_func, read_func_data);
int win_width = pattern_display_get_size(display->width);
int win_height = pattern_display_get_size(display->height);
pixel *buffer = malloc(win_width * win_height * sizeof(pixel));
pattern_display_draw_borders(buffer, win_width, win_height);
for (int x = 0; x < display->width; x++) {
for (int y = 0; y < display->height; y++) {
PatternTile *tile = &tile_table[x + y * display->width];
address row_addr = (y * PATTERN_DRAW_SIZE + PATTERN_BORDER_WIDTH) * win_width;
address tile_addr = row_addr + (x * PATTERN_DRAW_SIZE + PATTERN_BORDER_WIDTH);
pattern_display_draw_tile(tile, buffer, tile_addr, win_width);
}
}
SDL_UpdateTexture(display->texture, NULL, buffer, win_width * sizeof(pixel));
free(tile_table);
free(buffer);
}
void pattern_display_render(PatternDisplay *display, SDL_Renderer *renderer) {
SDL_RenderCopy(renderer, display->texture, NULL, NULL);
}

View File

@ -1,47 +0,0 @@
//
// Created by william on 12/07/24.
//
#ifndef NES_EMULATOR_PATTERN_DISPLAY_H
#define NES_EMULATOR_PATTERN_DISPLAY_H
#include <SDL.h>
#include "../include/types.h"
#define PATTERN_DISPLAY_STATIC SDL_TEXTUREACCESS_STATIC
#define PATTERN_DISPLAY_DYNAMIC SDL_TEXTUREACCESS_STREAMING
#define PATTERN_SIZE 8
#define PATTERN_BORDER_WIDTH 1
#define PATTERN_BORDER_COLOR 0xff2223b2
#define PATTERN_DRAW_SIZE (PATTERN_SIZE + PATTERN_BORDER_WIDTH)
typedef unsigned int pixel;
typedef byte *(*read_func)(address, void *);
typedef struct pattern_tile {
byte data_low[8];
byte data_high[8];
} PatternTile;
typedef struct pattern_display {
SDL_Texture *texture;
PatternTile *tiles;
int width;
int height;
} PatternDisplay;
static inline int pattern_display_get_size(int tile_count) {
return tile_count * PATTERN_DRAW_SIZE + PATTERN_BORDER_WIDTH;
}
void pattern_display_init(PatternDisplay *display, SDL_Renderer *renderer, int tiles_x, int tiles_y, int display_type);
void pattern_display_uninit(PatternDisplay *display);
void pattern_display_build(PatternDisplay *display, read_func read_func, void *read_func_data);
void pattern_display_render(PatternDisplay *display, SDL_Renderer *renderer);
#endif //NES_EMULATOR_PATTERN_DISPLAY_H

View File

@ -10,8 +10,7 @@
#define PW_BUFFER_SIZE (PW_WIDTH * PW_HEIGHT) #define PW_BUFFER_SIZE (PW_WIDTH * PW_HEIGHT)
void pattern_window_init(NesPatternWindow *window) { void pattern_window_init(NesPatternWindow *window) {
int win_width = pattern_display_get_size(PW_ROW_TILE_COUNT); window->sdl_context = window_init("Pattern Table", PW_WIDTH, PW_HEIGHT, PW_SCALE);
window->sdl_context = window_init("Pattern Table", win_width, win_width * 2, PW_SCALE);
window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888, window->texture = SDL_CreateTexture(window->sdl_context.renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC, PW_WIDTH, PW_HEIGHT); SDL_TEXTUREACCESS_STATIC, PW_WIDTH, PW_HEIGHT);

View File

@ -7,14 +7,12 @@
#include "../include/types.h" #include "../include/types.h"
#include "window.h" #include "window.h"
#include "pattern_display.h"
#define PW_SCALE 2 #define PW_SCALE 2
#define PW_ROW_TILE_COUNT 16 #define PW_ROW_TILE_COUNT 16
typedef struct nes_pattern_window { typedef struct nes_pattern_window {
NesSdlContext sdl_context; NesSdlContext sdl_context;
PatternDisplay pattern_display;
SDL_Texture *texture; SDL_Texture *texture;
} NesPatternWindow; } NesPatternWindow;

1
main.c
View File

@ -24,6 +24,7 @@
int main() { int main() {
char *rom_path = "./test_roms/dk_jp.nes"; char *rom_path = "./test_roms/dk_jp.nes";
// char *rom_path = "./test_roms/nes-test-roms/other/BLOCKS.NES";
log_set_level(LOG_INFO); log_set_level(LOG_INFO);
if (!gui_init()) { if (!gui_init()) {

View File

@ -1,5 +1,5 @@
set(HEADERS pattern_table.h ppu.h palette.h) set(HEADERS ppu.h palette.h)
set(SOURCE pattern_table.c ppu.c palette.c) set(SOURCE ppu.c palette.c)
add_library(nes_ppu ${SOURCE} ${HEADERS}) add_library(nes_ppu ${SOURCE} ${HEADERS})

View File

@ -1,61 +0,0 @@
//
// Created by william on 17/05/24.
//
#include "pattern_table.h"
#include "ppu.h"
#include "../gui/canvas.h"
#include "../gui/gui.h"
inline void test() {
}
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);
// }
// }
// }
// }
// }
}

View File

@ -1,14 +0,0 @@
//
// 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

View File

@ -19,7 +19,6 @@
#include "../include/ppu.h" #include "../include/ppu.h"
#include "../cpu/cpu.h" #include "../cpu/cpu.h"
#include "../include/rom.h" #include "../include/rom.h"
#include "pattern_table.h"
#define PPU_VISIBLE_FRAME_END 240 #define PPU_VISIBLE_FRAME_END 240
#define PPU_POST_RENDER_LINE_START PPU_VISIBLE_FRAME_END #define PPU_POST_RENDER_LINE_START PPU_VISIBLE_FRAME_END
@ -76,7 +75,7 @@ static inline unsigned int ppu_pixel_get_index(unsigned int scanline, unsigned i
} }
static inline byte ppu_pixel_get_mask(unsigned int tile_fine_x) { static inline byte ppu_pixel_get_mask(unsigned int tile_fine_x) {
return 1 << (PATTERN_TILE_SIZE - tile_fine_x - 1); return 1 << (8 - tile_fine_x - 1);
} }
static inline void ppu_pixel_set_color(PPUPixel *pixel, byte pt_low, byte pt_high) { static inline void ppu_pixel_set_color(PPUPixel *pixel, byte pt_low, byte pt_high) {
@ -110,7 +109,19 @@ static inline void ppu_pixel_set_color(PPUPixel *pixel, byte pt_low, byte pt_hig
void ppu_draw_tile() { void ppu_draw_tile() {
PPUTileFetch fetch = ppu_state.tile_queue.displayed_fetch; PPUTileFetch fetch = ppu_state.tile_queue.displayed_fetch;
unsigned int pixel_index = ppu_state.scanline * PPU_VISIBLE_FRAME_END + ppu_state.cycle; unsigned int y = ppu_state.scanline;
unsigned int x = ppu_state.cycle + 0;
// if (x > PPU_LINE_WIDTH) {
// x -= PPU_LINE_WIDTH;
// y++;
// }
//
// if (y > PPU_PRE_RENDER_LINE) {
// y -= PPU_PRE_RENDER_LINE;
// }
unsigned int pixel_index = y * PPU_VISIBLE_FRAME_END + x;
PPUPixel *pixel = &ppu_state.pixels[pixel_index]; PPUPixel *pixel = &ppu_state.pixels[pixel_index];
ppu_pixel_set_color(pixel, fetch.pattern_table_tile_low, fetch.pattern_table_tile_high); ppu_pixel_set_color(pixel, fetch.pattern_table_tile_low, fetch.pattern_table_tile_high);
} }
@ -121,7 +132,7 @@ byte ppu_get_pattern(byte tile_index, byte high) {
return ppu_read(pattern_addr); return ppu_read(pattern_addr);
} }
void ppu_fetch_tile() { void ppu_fetch_tile(bool render) {
byte fetch_cycle = (ppu_state.cycle - 1) % 8; byte fetch_cycle = (ppu_state.cycle - 1) % 8;
if (fetch_cycle == 1) { if (fetch_cycle == 1) {
@ -151,7 +162,10 @@ void ppu_fetch_tile() {
} else if (fetch_cycle == 7) { } else if (fetch_cycle == 7) {
ppu_state.fetch.pattern_table_tile_high = ppu_get_pattern(ppu_state.fetch.nametable, 1); ppu_state.fetch.pattern_table_tile_high = ppu_get_pattern(ppu_state.fetch.nametable, 1);
ppu_state.tile_queue.displayed_fetch = ppu_state.fetch; ppu_state.tile_queue.displayed_fetch = ppu_state.fetch;
ppu_draw_tile();
if (render) {
ppu_draw_tile();
}
if ((ppu_state.ppu_address & 0x1f) == 0x1f) { if ((ppu_state.ppu_address & 0x1f) == 0x1f) {
ppu_state.ppu_address &= ~0x1f; ppu_state.ppu_address &= ~0x1f;
@ -160,31 +174,6 @@ void ppu_fetch_tile() {
ppu_state.ppu_address++; ppu_state.ppu_address++;
} }
} }
// address read_addr;
// switch (fetch_cycle) {
// case 1:
// read_addr = 0x2000 + ((ppu_state.scanline / 8) * 0x20) + (ppu_state.cycle / 8);
// ppu_state.fetch.nametable = ppu_read(read_addr);
// break;
// case 3:
// read_addr = 0x23c0 + (ppu_state.cycle % 8);
// ppu_state.fetch.attribute_table = ppu_read(read_addr);
// break;
// case 5:
// read_addr = 0x1000 * ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_BG_PATTERN_TABLE_ADDR);
// read_addr += ppu_state.fetch.nametable * 16 + ppu_state.scanline % 8;
// ppu_state.fetch.pattern_table_tile_low = ppu_read(read_addr);
// break;
// case 7:
// read_addr = 0x1000 * ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_BG_PATTERN_TABLE_ADDR);
// read_addr += ppu_state.fetch.nametable * 16 + ppu_state.scanline % 8 + 8;
// ppu_state.fetch.pattern_table_tile_high = ppu_read(read_addr);
// ppu_tile_push();
// break;
// default:
// break;
// }
} }
void ppu_visible_frame(unsigned int cycle) { void ppu_visible_frame(unsigned int cycle) {
@ -195,8 +184,8 @@ void ppu_visible_frame(unsigned int cycle) {
if (cycle == 0) { if (cycle == 0) {
// Idle... // Idle...
} else if (cycle <= 256) { } else if (cycle >= 8 && cycle <= 256) {
ppu_fetch_tile(); ppu_fetch_tile(true);
if (cycle == 256) { if (cycle == 256) {
if ((ppu_state.ppu_address & 0x7000) != 0x7000) { if ((ppu_state.ppu_address & 0x7000) != 0x7000) {
@ -208,7 +197,7 @@ void ppu_visible_frame(unsigned int cycle) {
ppu_state.ppu_address += 0x20; ppu_state.ppu_address += 0x20;
} else { } else {
ppu_state.ppu_address &= ~0x3e0; ppu_state.ppu_address &= ~0x3e0;
// ppu_state.ppu_address ^= 0x0800; ppu_state.ppu_address ^= 0x0800;
} }
} }
} }
@ -220,8 +209,8 @@ void ppu_visible_frame(unsigned int cycle) {
ppu_state.ppu_address = (ppu_state.ppu_address & 0xfbe0) | (ppu_state.temp_ppu_addr & ~0xfbe0); ppu_state.ppu_address = (ppu_state.ppu_address & 0xfbe0) | (ppu_state.temp_ppu_addr & ~0xfbe0);
ppu_state.x_scroll = 0; ppu_state.x_scroll = 0;
} }
} else if (cycle <= 336) { } else if (cycle <= 328) {
ppu_fetch_tile(); ppu_fetch_tile(false);
} }
} }
@ -262,8 +251,8 @@ void ppu_cycle() {
if (rendering_enabled && ppu_state.odd_frame) { if (rendering_enabled && ppu_state.odd_frame) {
// With rendering enabled, the odd frames are shorter // With rendering enabled, the odd frames are shorter
// TODO: and doing the last cycle of the last dummy nametable fetch there instead // TODO: and doing the last cycle of the last dummy nametable fetch there instead
frame_width = PPU_LINE_WIDTH - 2; // frame_width = PPU_LINE_WIDTH - 2;
frame_height = PPU_LINE_END - 1; // frame_height = PPU_LINE_END - 1;
} }
ppu_state.cycle++; ppu_state.cycle++;

View File

@ -5,10 +5,7 @@
#include "include/cpu.h" #include "include/cpu.h"
#include "include/system.h" #include "include/system.h"
#include "memory.h" #include "memory.h"
#include <unistd.h>
#include <assert.h>
#include "cpu.h" #include "cpu.h"
#include "pattern_table.h"
System current_sys; System current_sys;
@ -33,8 +30,6 @@ void system_next_frame() {
ppu_cycle(); ppu_cycle();
} }
} }
pt_debug();
} }
void system_uninit() { void system_uninit() {