Add tile debugger to main view

This commit is contained in:
william 2024-08-17 17:38:15 -04:00
parent 77b37fc3b6
commit 1add13dd20
9 changed files with 79 additions and 64 deletions

View File

@ -11,6 +11,7 @@ only tested on Linux. Here is how to run the project:
## Controls
- `p`: Pauses the emulation
- `o`: Go to the next palette in the pattern viewer
- `t`: Show tile IDs
## Dependencies
- GCC compiler

View File

@ -89,7 +89,12 @@ int gui_input() {
system_toggle_pause();
} else {
#if DEBUG
if (event.key.keysym.sym == SDLK_t) {
PPUDebugFlags *ppu_debug = &ppu_get_state()->debug;
ppu_debug->flags.tile_debugger = !ppu_debug->flags.tile_debugger;
} else {
pattern_window_key_up(&gui.pattern_window, event.key.keysym.sym);
}
#endif
}
}

View File

@ -34,20 +34,8 @@ void main_window_render_delay(SDL_Renderer *renderer) {
}
#endif
void main_window_render(NesMainWindow *window, PPUPixel *pixels) {
void main_window_render(NesMainWindow *window, pixel *pixels) {
SDL_RenderClear(window->sdl_context.renderer);
// unsigned int frame_buffer[240 * 256];
// for (int i = 0; i < 240 * 256; i++) {
// PPUPixel pixel = pixels[i];
//
// unsigned int *data = &frame_buffer[i];
// *data = 0xff000000;
// *data |= pixel.r << 16;
// *data |= pixel.g << 8;
// *data |= pixel.b;
// }
SDL_UpdateTexture(window->texture, NULL, pixels, 240 * sizeof(unsigned int));
SDL_RenderCopy(window->sdl_context.renderer, window->texture, NULL, NULL);

View File

@ -11,7 +11,7 @@
#define MAIN_WINDOW_WIDTH 256
#define MAIN_WINDOW_HEIGHT 240
#define MAIN_WINDOW_SCALE 2
#define MAIN_WINDOW_SCALE 3
typedef struct nes_main_window {
NesSdlContext sdl_context;
@ -22,7 +22,7 @@ typedef struct nes_main_window {
void main_window_init(NesMainWindow *window);
void main_window_uninit(NesMainWindow *window);
void main_window_render(NesMainWindow *window, PPUPixel* pixels);
void main_window_render(NesMainWindow *window, pixel* pixels);
void main_window_present(NesMainWindow *window);
#endif //NES_EMULATOR_MAIN_WINDOW_H

View File

@ -69,46 +69,42 @@ typedef struct ppu_tile_fetch {
byte pattern_table_tile_high;
} PPUTileFetch;
//typedef struct ppu_pixel {
// byte r;
// byte g;
// byte b;
//} PPUPixel;
typedef unsigned int PPUPixel;
typedef struct ppu_tile_queue {
PPUTileFetch first_fetch;
PPUTileFetch second_fetch;
PPUTileFetch displayed_fetch;
} PPUTileQueue;
#if DEBUG
typedef union {
struct {
byte tile_debugger: 1;
} flags;
byte flags_byte;
} PPUDebugFlags;
#endif
typedef struct ppu {
PPUMemory memory;
PPUPixel pixels[256 * 240];
pixel pixels[256 * 240];
byte registers[8];
byte oam_dma_register;
byte oam[PPU_OAM_SIZE];
bool odd_frame;
address v;
address t;
byte x;
bool w;
byte x_scroll;
byte fine_x_scroll;
byte y_scroll;
byte ppu_addr_increment;
byte x;
bool w;
byte ppu_addr_increment;
address ppu_address;
address temp_ppu_addr;
address bg_pattern_table_addr;
PPUTileFetch fetch;
PPUTileQueue tile_queue;
unsigned long frame;
unsigned int scanline;
unsigned int cycle;
#if DEBUG
PPUDebugFlags debug;
#endif
} PPU;
PPU *ppu_get_state();
@ -137,17 +133,6 @@ void ppu_cycle();
*/
bool ppu_read_flag(size_t reg, byte mask);
/**
* Read a value from the PPU registers. Does not apply any offset to the value, a mask of 0x20 will either result in 0x20 (true) or 0x0 (false).
* Read a value from the PPU registers. Does not apply any offset to the value, a mask of 0x20 will either result in 0x20 (true) or 0x0 (false).
*
* @param reg The register index
* @param mask The value mask
*/
//void ppu_sig_read_register(byte reg);
//
//void ppu_sig_write_register(byte reg);
byte ppu_read_reg(byte reg);
void ppu_write_reg(byte reg, byte data);

View File

@ -5,14 +5,9 @@
#ifndef NESEMULATOR_TYPES_H
#define NESEMULATOR_TYPES_H
//#define RAM_SIZE 0xffff
//#define VRAM_SIZE 0x4000
typedef unsigned char byte;
typedef unsigned short address;
typedef unsigned short word;
//typedef byte ram[RAM_SIZE];
//typedef byte vram[VRAM_SIZE];
typedef unsigned int pixel;
#endif //NESEMULATOR_TYPES_H

View File

@ -20,6 +20,7 @@
#include "../cpu/cpu.h"
#include "../include/rom.h"
#include "colors.h"
#include "tile_debugger.h"
#define PPU_VISIBLE_FRAME_END 240
#define PPU_POST_RENDER_LINE_START PPU_VISIBLE_FRAME_END
@ -31,7 +32,7 @@
#define NAMETABLE_TILE_SIZE 8
PPU ppu_state;
PPUPixel color_list[0x40] = COLOR_LIST;
pixel color_list[0x40] = COLOR_LIST;
void ppu_init() {
memset(&ppu_state, 0, sizeof(PPU));
@ -95,7 +96,7 @@ static inline byte ppu_pixel_get_palette(byte attribute) {
return palette & 0b11;
}
static inline void ppu_pixel_set_color(PPUPixel *pixel, byte pt_low, byte pt_high, byte attribute) {
static inline void ppu_pixel_set_color(pixel *pixel, byte pt_low, byte pt_high, byte attribute) {
for (int i = 0; i < 8; i++) {
byte pixel_offset = 8 - i - 1;
@ -114,7 +115,7 @@ static inline void ppu_pixel_set_color(PPUPixel *pixel, byte pt_low, byte pt_hig
}
void ppu_draw_tile() {
PPUTileFetch fetch = ppu_state.tile_queue.displayed_fetch;
PPUTileFetch fetch = ppu_state.fetch;
unsigned int y = ppu_state.scanline;
unsigned int x = ppu_state.cycle;
@ -129,15 +130,20 @@ void ppu_draw_tile() {
// }
unsigned int pixel_index = y * PPU_VISIBLE_FRAME_END + x;
PPUPixel *pixel = &ppu_state.pixels[pixel_index];
pixel *pixel = &ppu_state.pixels[pixel_index];
ppu_pixel_set_color(pixel, fetch.pattern_table_tile_low, fetch.pattern_table_tile_high, fetch.attribute_table);
}
byte ppu_get_pattern(byte tile_index, byte high) {
return tile_index;
// byte tile_row_index = (ppu_state.scanline + ppu_state.y_scroll) % 8;
// address pattern_addr = ppu_state.bg_pattern_table_addr | tile_index << 4 | high << 3 | tile_row_index;
// return ppu_read(pattern_addr);
#if DEBUG
if (ppu_state.debug.flags.tile_debugger) {
return tile_debugger_encode_number_as_pattern(tile_index, ppu_state.scanline % 8);
}
#endif
byte tile_row_index = (ppu_state.scanline + ppu_state.y_scroll) % 8;
address pattern_addr = ppu_state.bg_pattern_table_addr | tile_index << 4 | high << 3 | tile_row_index;
return ppu_read(pattern_addr);
}
void ppu_fetch_tile(bool render) {
@ -169,7 +175,6 @@ void ppu_fetch_tile(bool render) {
ppu_state.fetch.pattern_table_tile_low = ppu_get_pattern(ppu_state.fetch.nametable, 0);
} else if (fetch_cycle == 7) {
ppu_state.fetch.pattern_table_tile_high = ppu_get_pattern(ppu_state.fetch.nametable, 1);
ppu_state.tile_queue.displayed_fetch = ppu_state.fetch;
if (render) {
ppu_draw_tile();

View File

@ -4,7 +4,34 @@
#include "tile_debugger.h"
byte tile_encode_number(byte num) {
// 8 segment display
// Contains the patterns of every hexadecimal digit encoded as pattern data.
// The first dimension of the table represents a row in a tile.
byte hex_pattern_table[5][0x10] = {
{0b111, 0b001, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 0b111, 0b010, 0b111, 0b111, 0b110, 0b111, 0b111},
{0b101, 0b001, 0b001, 0b001, 0b101, 0b100, 0b100, 0b001, 0b101, 0b101, 0b101, 0b101, 0b100, 0b101, 0b100, 0b100},
{0b101, 0b001, 0b111, 0b111, 0b111, 0b111, 0b111, 0b010, 0b111, 0b111, 0b111, 0b110, 0b100, 0b101, 0b111, 0b110},
{0b101, 0b001, 0b100, 0b001, 0b001, 0b001, 0b101, 0b010, 0b101, 0b001, 0b101, 0b101, 0b100, 0b101, 0b100, 0b100},
{0b111, 0b001, 0b111, 0b111, 0b001, 0b111, 0b111, 0b010, 0b111, 0b001, 0b101, 0b111, 0b111, 0b110, 0b111, 0b100},
};
byte tile_debugger_encode_number_as_pattern(byte num, byte tile_fine_y) {
if (tile_fine_y == 6) {
return 0x7f; // On row 6, a full line is drawn to make it easier to separate tiles
} else if (tile_fine_y == 5 || tile_fine_y == 7) {
return 0;
}
// The first digit of the hex is encoded
byte remaining = num % 0x10;
byte encoded = hex_pattern_table[tile_fine_y][remaining];
if (num > 0xf) {
// If the number is greater than 0xF, we need a second digit
// We encode it, then add it 4 pixels to the left of the already encoded digit
byte tenths = num / 0x10;
byte tenths_encoded = hex_pattern_table[tile_fine_y][tenths];
encoded = (tenths_encoded << 4) | encoded;
}
return encoded;
}

View File

@ -7,4 +7,13 @@
#include "../include/types.h"
/**
* Encodes a number as pattern data.
*
* @param num The number to encode
* @param tile_fine_y The row of the tile
* @return Pattern data representing the row of the encoded number
*/
byte tile_debugger_encode_number_as_pattern(byte num, byte tile_fine_y);
#endif //NES_EMULATOR_TILE_DEBUGGER_H