Pattern table view

This commit is contained in:
FyloZ 2024-05-17 13:16:21 -04:00
parent 036835d3d0
commit 87179ec891
Signed by: william
GPG Key ID: 835378AE9AF4AE97
14 changed files with 197 additions and 61 deletions

View File

@ -28,14 +28,21 @@ void canvas_uninit(Canvas *canvas) {
free(canvas->pixels); 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 >= 0);
assert(x < canvas->width); assert(x < canvas->width);
assert(y >= 0); assert(y >= 0);
assert(y < canvas->height); assert(y < canvas->height);
int pixel_index = x + y * canvas->width; int index = x + y * canvas->width;
canvas->pixels[pixel_index] = pixel; canvas_draw(canvas, pixel, index);
} }
void canvas_reset(Canvas *canvas) { void canvas_reset(Canvas *canvas) {

View File

@ -7,9 +7,6 @@
#include "../include/types.h" #include "../include/types.h"
//#define CANVAS_WIDTH 256
//#define CANVAS_HEIGHT 240
typedef struct pixel { typedef struct pixel {
byte r; byte r;
byte g; byte g;
@ -25,7 +22,8 @@ typedef struct canvas {
Canvas canvas_init(int width, int height); Canvas canvas_init(int width, int height);
void canvas_uninit(Canvas *canvas); 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); void canvas_reset(Canvas *canvas);
#endif //NES_EMULATOR_CANVAS_H #endif //NES_EMULATOR_CANVAS_H

View File

@ -3,14 +3,20 @@
// //
#include <assert.h> #include <assert.h>
#include "gui.h"
#include "log.h" #include "log.h"
#include "gui.h"
#include "window.h"
typedef struct nes_gui {
NesWindow main_window;
NesWindow debug_pattern_window;
} NesGui;
NesGui gui; NesGui gui;
void gui_init() { void gui_init() {
gui.main_window = window_init(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT, "NES Emulator"); gui.main_window = window_init(WINDOW_MAIN_WIDTH, WINDOW_MAIN_HEIGHT, WINDOW_MAIN_SCALING, "NES Emulator");
gui.debug_pattern_window = window_init(DEBUG_PATTERN_WIDTH, DEBUG_PATTERN_HEIGHT, "Pattern Table"); gui.debug_pattern_window = window_init(WINDOW_PATTERN_WIDTH, WINDOW_PATTERN_HEIGHT, WINDOW_PATTERN_SCALING,
"Pattern Table");
} }
void gui_uninit() { void gui_uninit() {
@ -40,14 +46,18 @@ void gui_present() {
window_present(&gui.debug_pattern_window); window_present(&gui.debug_pattern_window);
} }
void gui_delay() {
SDL_Delay(16);
}
Canvas *gui_get_canvas(char win_id) { Canvas *gui_get_canvas(char win_id) {
NesWindow *window; NesWindow *window;
switch (win_id) { switch (win_id) {
case GUI_WINDOW_MAIN: case WINDOW_ID_MAIN:
window = &gui.main_window; window = &gui.main_window;
break; break;
case GUI_WINDOW_PATTERN: case WINDOW_ID_PATTERN:
window = &gui.debug_pattern_window; window = &gui.debug_pattern_window;
break; break;
default: default:

View File

@ -5,22 +5,17 @@
#ifndef NES_EMULATOR_GUI_H #ifndef NES_EMULATOR_GUI_H
#define NES_EMULATOR_GUI_H #define NES_EMULATOR_GUI_H
#include <SDL.h>
#include "canvas.h" #include "canvas.h"
#include "window.h"
#define MAIN_WINDOW_WIDTH 256 #define WINDOW_ID_MAIN 1
#define MAIN_WINDOW_HEIGHT 240 #define WINDOW_MAIN_WIDTH 256
#define DEBUG_PATTERN_WIDTH 100 #define WINDOW_MAIN_HEIGHT 240
#define DEBUG_PATTERN_HEIGHT 100 #define WINDOW_MAIN_SCALING 3
#define GUI_WINDOW_MAIN 1 #define WINDOW_ID_PATTERN 2
#define GUI_WINDOW_PATTERN 2 #define WINDOW_PATTERN_WIDTH 128
#define WINDOW_PATTERN_HEIGHT 256
typedef struct nes_gui { #define WINDOW_PATTERN_SCALING 2
NesWindow main_window;
NesWindow debug_pattern_window;
} NesGui;
void gui_init(); void gui_init();
void gui_uninit(); void gui_uninit();
@ -28,6 +23,7 @@ void gui_uninit();
int gui_input(); int gui_input();
void gui_render(); void gui_render();
void gui_present(); void gui_present();
void gui_delay();
Canvas *gui_get_canvas(char win_id); Canvas *gui_get_canvas(char win_id);

View File

@ -2,13 +2,15 @@
// Created by william on 17/05/24. // Created by william on 17/05/24.
// //
#include <SDL.h>
#include "window.h" #include "window.h"
#include "log.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; NesWindow win;
win.width = width * WINDOW_SCALING; win.scaling = scaling;
win.height = height * WINDOW_SCALING; win.width = width * scaling;
win.height = height * scaling;
win.canvas = canvas_init(width, height); win.canvas = canvas_init(width, height);
int renderer_flags = SDL_RENDERER_ACCELERATED; int renderer_flags = SDL_RENDERER_ACCELERATED;
@ -44,17 +46,17 @@ void window_uninit(NesWindow *window) {
void window_render(NesWindow *window) { void window_render(NesWindow *window) {
SDL_RenderClear(window->renderer); 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; int pixel_index = x + y * window->canvas.width;
Pixel pixel = window->canvas.pixels[pixel_index]; Pixel pixel = window->canvas.pixels[pixel_index];
SDL_SetRenderDrawColor(window->renderer, pixel.r, pixel.g, pixel.b, 255); SDL_SetRenderDrawColor(window->renderer, pixel.r, pixel.g, pixel.b, 255);
for (int i = 0; i < WINDOW_SCALING; i++) { for (int i = 0; i < window->scaling; i++) {
for (int j = 0; j < WINDOW_SCALING; j++) { for (int j = 0; j < window->scaling; j++) {
int scaled_x = x * WINDOW_SCALING + i; int scaled_x = x * window->scaling + i;
int scaled_y = y * WINDOW_SCALING + j; int scaled_y = y * window->scaling + j;
SDL_RenderDrawPoint(window->renderer, scaled_x, scaled_y); SDL_RenderDrawPoint(window->renderer, scaled_x, scaled_y);
} }
} }
@ -64,4 +66,7 @@ void window_render(NesWindow *window) {
void window_present(NesWindow *window) { void window_present(NesWindow *window) {
SDL_RenderPresent(window->renderer); SDL_RenderPresent(window->renderer);
// TODO: Check if this is a good location
canvas_reset(&window->canvas);
} }

View File

@ -8,18 +8,17 @@
#include <SDL.h> #include <SDL.h>
#include "canvas.h" #include "canvas.h"
#define WINDOW_SCALING 3 typedef struct nes_window {
typedef struct new_window {
SDL_Renderer *renderer; SDL_Renderer *renderer;
SDL_Window *window; SDL_Window *window;
int width; int width;
int height; int height;
int scaling;
Canvas canvas; Canvas canvas;
} NesWindow; } 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_uninit(NesWindow *window);
void window_render(NesWindow *window); void window_render(NesWindow *window);

View File

@ -63,9 +63,11 @@ typedef struct ppu {
byte x; byte x;
bool w; bool w;
bool fetching;
unsigned long frame; unsigned long frame;
unsigned int line; unsigned int scanline;
unsigned int line_x; unsigned int cycle;
} PPU; } PPU;
PPU *ppu_get_state(); PPU *ppu_get_state();

5
main.c
View File

@ -27,7 +27,7 @@ int main() {
log_set_level(LOG_INFO); log_set_level(LOG_INFO);
system_init(); system_init();
char *rom_path = "../test_roms/dk_jp.nes"; char *rom_path = "../test_roms/smb.nes";
if (!rom_load(rom_path)) { if (!rom_load(rom_path)) {
system_uninit(); system_uninit();
@ -47,8 +47,7 @@ int main() {
gui_render(); gui_render();
gui_present(); gui_present();
gui_delay();
SDL_Delay(16);
} }
system_uninit(); system_uninit();

View File

@ -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) target_link_libraries(nes_ppu log.c)

57
ppu/pattern_table.c Normal file
View File

@ -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);
}
}
}
}
}
}

14
ppu/pattern_table.h Normal file
View File

@ -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

View File

@ -15,6 +15,7 @@
// //
#include <assert.h> #include <assert.h>
#include "ppu.h"
#include "../include/ppu.h" #include "../include/ppu.h"
#include "../cpu/cpu.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.registers[PPU_REGISTER_DATA] = 0x00;
ppu_state.oam_dma_register = oam_dma_register; ppu_state.oam_dma_register = oam_dma_register;
ppu_state.odd_frame = false; ppu_state.odd_frame = false;
ppu_state.fetching = false;
ppu_state.frame = 0; ppu_state.frame = 0;
ppu_state.line = 0; ppu_state.scanline = 0;
ppu_state.line_x = 0; ppu_state.cycle = 0;
} }
PPU *ppu_get_state() { PPU *ppu_get_state() {
@ -66,10 +68,34 @@ void ppu_trigger_vbl_nmi() {
cpu_trigger_nmi(); cpu_trigger_nmi();
} }
void ppu_visible_frame(unsigned int x) { typedef struct {
if (x >= 257 && x <= 320) { 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 // OAMADDR is cleared on sprite loading for pre-render and visible lines
ppu_write_reg(PPU_REGISTER_OAM_ADDR, 0); 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() { void ppu_cycle() {
if (ppu_state.line < PPU_VISIBLE_FRAME_END) { if (ppu_state.scanline < PPU_VISIBLE_FRAME_END) {
ppu_visible_frame(ppu_state.line_x); ppu_visible_frame(ppu_state.cycle);
} else if (ppu_state.line >= PPU_POST_RENDER_LINE_START && ppu_state.line <= PPU_POST_RENDER_LINE_END) { } else if (ppu_state.scanline >= PPU_POST_RENDER_LINE_START && ppu_state.scanline <= PPU_POST_RENDER_LINE_END) {
ppu_post_render(ppu_state.line_x, ppu_state.line); ppu_post_render(ppu_state.cycle, ppu_state.scanline);
} else if (ppu_state.line == PPU_PRE_RENDER_LINE) { } else if (ppu_state.scanline == PPU_PRE_RENDER_LINE) {
ppu_pre_render(ppu_state.line_x); ppu_pre_render(ppu_state.cycle);
} }
int frame_width = PPU_LINE_WIDTH; int frame_width = PPU_LINE_WIDTH;
@ -112,14 +138,14 @@ void ppu_cycle() {
frame_height = PPU_LINE_END - 1; frame_height = PPU_LINE_END - 1;
} }
ppu_state.line_x++; ppu_state.cycle++;
if (ppu_state.line_x >= frame_width) { if (ppu_state.cycle >= frame_width) {
ppu_state.line_x = 0; ppu_state.cycle = 0;
ppu_state.line++; ppu_state.scanline++;
} }
if (ppu_state.line >= frame_height) { if (ppu_state.scanline >= frame_height) {
ppu_state.line = 0; ppu_state.scanline = 0;
ppu_state.frame++; ppu_state.frame++;
ppu_state.odd_frame = !ppu_state.odd_frame; ppu_state.odd_frame = !ppu_state.odd_frame;
} }
@ -221,3 +247,9 @@ void ppu_write_reg(byte reg, byte data) {
ppu_write_reg_ram(reg, data); ppu_write_reg_ram(reg, data);
} }
byte ppu_read(address addr) {
assert(addr < PPU_VRAM_SIZE);
return ppu_state.vram[addr];
}

12
ppu/ppu.h Normal file
View File

@ -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

View File

@ -8,6 +8,7 @@
#include <unistd.h> #include <unistd.h>
#include <assert.h> #include <assert.h>
#include "cpu.h" #include "cpu.h"
#include "pattern_table.h"
System current_sys; System current_sys;
@ -35,6 +36,8 @@ void system_next_frame() {
ppu_cycle(); ppu_cycle();
} }
} }
pt_debug();
} }
void system_uninit() { void system_uninit() {