Add tile debugger to main view
This commit is contained in:
parent
77b37fc3b6
commit
1add13dd20
|
@ -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
|
||||
|
|
|
@ -89,7 +89,12 @@ int gui_input() {
|
|||
system_toggle_pause();
|
||||
} else {
|
||||
#if DEBUG
|
||||
pattern_window_key_up(&gui.pattern_window, event.key.keysym.sym);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
23
ppu/ppu.c
23
ppu/ppu.c
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue