PPU debugging
This commit is contained in:
parent
66785039a9
commit
5fd5106ad4
|
@ -42,7 +42,7 @@ void cpu_init() {
|
||||||
|
|
||||||
void print_registers(byte op, unsigned long cycle_count) {
|
void print_registers(byte op, unsigned long cycle_count) {
|
||||||
log_debug("%#02x %#02x %s \t A:%#02x X:%#02x Y:%#02x F:%#02x SP:%#02x \t [%d]",
|
log_debug("%#02x %#02x %s \t A:%#02x X:%#02x Y:%#02x F:%#02x SP:%#02x \t [%d]",
|
||||||
cpu_state.program_counter,
|
cpu_state.program_counter - 1, // The PC as been incremented when printing
|
||||||
op,
|
op,
|
||||||
get_op_code_name(op),
|
get_op_code_name(op),
|
||||||
cpu_state.accumulator,
|
cpu_state.accumulator,
|
||||||
|
|
|
@ -98,6 +98,8 @@ void mem_set_byte(address addr, byte data) {
|
||||||
byte ppu_reg = relative_addr % 8;
|
byte ppu_reg = relative_addr % 8;
|
||||||
ppu_write_reg(ppu_reg, data);
|
ppu_write_reg(ppu_reg, data);
|
||||||
} else if (addr == PPU_REGISTER_OAM_DMA_ADDR) {
|
} else if (addr == PPU_REGISTER_OAM_DMA_ADDR) {
|
||||||
|
ppu_write_reg_oam_addr(data);
|
||||||
|
|
||||||
// Writing to this address triggers an upload to the PPU memory
|
// Writing to this address triggers an upload to the PPU memory
|
||||||
cpu_trigger_oam_dma();
|
cpu_trigger_oam_dma();
|
||||||
} else if (addr < APU_MAX_ADDR) {
|
} else if (addr < APU_MAX_ADDR) {
|
||||||
|
|
|
@ -53,11 +53,14 @@
|
||||||
#define PPU_MASK_NONE 0xff
|
#define PPU_MASK_NONE 0xff
|
||||||
|
|
||||||
#define PATTERN_TABLE_SIZE 0x1000
|
#define PATTERN_TABLE_SIZE 0x1000
|
||||||
|
#define NAMETABLE_SIZE 0x0400
|
||||||
|
#define PALETTE_TABLE_SIZE 0x0020
|
||||||
|
|
||||||
typedef struct ppu_memory {
|
typedef struct ppu_memory {
|
||||||
byte *nametable_0;
|
byte vram[PPU_VRAM_SIZE];
|
||||||
byte *nametable_1;
|
byte nametable_0[NAMETABLE_SIZE];
|
||||||
byte *palette;
|
byte nametable_1[NAMETABLE_SIZE];
|
||||||
|
byte palette[PALETTE_TABLE_SIZE];
|
||||||
} PPUMemory;
|
} PPUMemory;
|
||||||
|
|
||||||
typedef struct ppu_tile_fetch {
|
typedef struct ppu_tile_fetch {
|
||||||
|
@ -72,7 +75,6 @@ typedef struct ppu {
|
||||||
|
|
||||||
byte registers[8];
|
byte registers[8];
|
||||||
byte oam_dma_register;
|
byte oam_dma_register;
|
||||||
byte vram[PPU_VRAM_SIZE];
|
|
||||||
byte oam[PPU_OAM_SIZE];
|
byte oam[PPU_OAM_SIZE];
|
||||||
bool odd_frame;
|
bool odd_frame;
|
||||||
address v;
|
address v;
|
||||||
|
@ -83,6 +85,7 @@ typedef struct ppu {
|
||||||
address ppu_address;
|
address ppu_address;
|
||||||
|
|
||||||
PPUTileFetch tile_fetch;
|
PPUTileFetch tile_fetch;
|
||||||
|
PPUTileFetch next_tile_fetch;
|
||||||
unsigned long frame;
|
unsigned long frame;
|
||||||
unsigned int scanline;
|
unsigned int scanline;
|
||||||
unsigned int cycle;
|
unsigned int cycle;
|
||||||
|
@ -129,4 +132,8 @@ byte ppu_read_reg(byte reg);
|
||||||
|
|
||||||
void ppu_write_reg(byte reg, byte data);
|
void ppu_write_reg(byte reg, byte data);
|
||||||
|
|
||||||
|
void ppu_write_reg_oam_addr(byte data);
|
||||||
|
|
||||||
|
void ppu_write(address addr, byte data);
|
||||||
|
|
||||||
#endif //NESEMULATOR_PPU_H
|
#endif //NESEMULATOR_PPU_H
|
||||||
|
|
3
main.c
3
main.c
|
@ -17,7 +17,6 @@
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "debugger/debugger.h"
|
|
||||||
|
|
||||||
#include "include/rom.h"
|
#include "include/rom.h"
|
||||||
#include "include/system.h"
|
#include "include/system.h"
|
||||||
|
@ -27,7 +26,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/dk_japan.nes";
|
||||||
|
|
||||||
if (!rom_load(rom_path)) {
|
if (!rom_load(rom_path)) {
|
||||||
system_uninit();
|
system_uninit();
|
||||||
|
|
135
ppu/ppu.c
135
ppu/ppu.c
|
@ -19,6 +19,8 @@
|
||||||
#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 "../gui/gui.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
|
||||||
|
@ -54,28 +56,69 @@ void ppu_trigger_vbl_nmi() {
|
||||||
cpu_trigger_nmi();
|
cpu_trigger_nmi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ppu_draw_tile() {
|
||||||
|
PPUTileFetch tile_fetch = ppu_state.tile_fetch;
|
||||||
|
Canvas *canvas = gui_get_canvas(WINDOW_ID_MAIN);
|
||||||
|
|
||||||
|
byte tile_fine_x = ppu_state.cycle % 8;
|
||||||
|
|
||||||
|
byte bitmask = 1 << (PATTERN_TILE_SIZE - tile_fine_x - 1);
|
||||||
|
byte p1_byte = tile_fetch.pattern_table_tile_low & bitmask;
|
||||||
|
byte p2_byte = tile_fetch.pattern_table_tile_high & 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_draw_pos(canvas, pixel, ppu_state.cycle, ppu_state.scanline);
|
||||||
|
}
|
||||||
|
|
||||||
void ppu_visible_frame(unsigned int cycle) {
|
void ppu_visible_frame(unsigned int cycle) {
|
||||||
if (cycle == 0) {
|
if (cycle == 0) {
|
||||||
// Idle...
|
// Idle...
|
||||||
} else if (cycle <= 256) {
|
} else if (cycle <= 256) {
|
||||||
// byte tile_fetch_cycle = (cycle - 1) % 8;
|
if (!ppu_read_flag(PPU_REGISTER_MASK, PPU_MASK_SHOW_BG) && ppu_state.scanline < 240) {
|
||||||
// switch (tile_fetch_cycle) {
|
if (cycle <= 248) {
|
||||||
// case 1:
|
ppu_draw_tile();
|
||||||
// ppu_state.tile_fetch.nametable = ppu_read(ppu_state.ppu_address);
|
}
|
||||||
// break;
|
|
||||||
// case 3:
|
byte tile_fetch_cycle = (cycle - 1) % 8;
|
||||||
// ppu_state.tile_fetch.attribute_table = ppu_read(ppu_state.ppu_address);
|
switch (tile_fetch_cycle) {
|
||||||
// break;
|
case 1:
|
||||||
// case 5:
|
address nt_addr = 0x2000 + (ppu_state.scanline * 16) + (ppu_state.cycle / 8);
|
||||||
// ppu_state.tile_fetch.pattern_table_tile_low = ppu_read(ppu_state.ppu_address);
|
ppu_state.next_tile_fetch.nametable = ppu_read(nt_addr);
|
||||||
// break;
|
break;
|
||||||
// case 7:
|
case 3:
|
||||||
// ppu_state.tile_fetch.pattern_table_tile_high = ppu_read(ppu_state.ppu_address);
|
address at_addr = 0x23c0 + (ppu_state.cycle % 8);
|
||||||
// ppu_state.ppu_address++;
|
ppu_state.next_tile_fetch.attribute_table = ppu_read(at_addr);
|
||||||
// break;
|
ppu_state.ppu_address++;
|
||||||
// default:
|
break;
|
||||||
// break;
|
case 5:
|
||||||
// }
|
ppu_state.next_tile_fetch.pattern_table_tile_low = ppu_read(0x0000);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
ppu_state.next_tile_fetch.pattern_table_tile_high = ppu_read(0x0008);
|
||||||
|
ppu_state.tile_fetch = ppu_state.next_tile_fetch;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (cycle <= 320) {
|
} 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);
|
||||||
|
@ -146,14 +189,16 @@ byte ppu_read_reg(byte reg) {
|
||||||
|
|
||||||
if (reg == PPU_REGISTER_STATUS) {
|
if (reg == PPU_REGISTER_STATUS) {
|
||||||
ppu_state.w = false;
|
ppu_state.w = false;
|
||||||
|
byte status = ppu_state.registers[PPU_REGISTER_STATUS];
|
||||||
ppu_state.registers[PPU_REGISTER_STATUS] &= ~PPU_STATUS_VBLANK;
|
ppu_state.registers[PPU_REGISTER_STATUS] &= ~PPU_STATUS_VBLANK;
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg == PPU_REGISTER_DATA) {
|
if (reg == PPU_REGISTER_DATA) {
|
||||||
// Access to VRAM memory is slow, so reading it a first time generally return the memory at the previous address.
|
// Access to VRAM memory is slow, so reading it a first time generally return the memory at the previous address.
|
||||||
// So we get the data first, then update the register.
|
// So we get the data first, then update the register.
|
||||||
byte data = ppu_state.registers[reg];
|
byte data = ppu_state.registers[reg];
|
||||||
ppu_state.registers[reg] = ppu_state.vram[ppu_state.ppu_address];
|
ppu_state.registers[reg] = ppu_state.memory.vram[ppu_state.ppu_address];
|
||||||
if (ppu_state.ppu_address > 0x3eff) {
|
if (ppu_state.ppu_address > 0x3eff) {
|
||||||
// But the palette data is returned immediately
|
// But the palette data is returned immediately
|
||||||
data = ppu_state.registers[reg];
|
data = ppu_state.registers[reg];
|
||||||
|
@ -205,7 +250,7 @@ void ppu_write_reg(byte reg, byte data) {
|
||||||
}
|
}
|
||||||
ppu_state.ppu_address = addr;
|
ppu_state.ppu_address = addr;
|
||||||
} else if (reg == PPU_REGISTER_DATA) {
|
} else if (reg == PPU_REGISTER_DATA) {
|
||||||
ppu_state.vram[ppu_state.ppu_address] = data;
|
ppu_write(ppu_state.ppu_address, data);
|
||||||
|
|
||||||
byte increment = 1;
|
byte increment = 1;
|
||||||
if (ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_VRAM_ADDR_INCREMENT)) {
|
if (ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_VRAM_ADDR_INCREMENT)) {
|
||||||
|
@ -224,6 +269,51 @@ void ppu_write_reg(byte reg, byte data) {
|
||||||
ppu_state.registers[reg] = data;
|
ppu_state.registers[reg] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ppu_write_reg_oam_addr(byte data) {
|
||||||
|
ppu_state.oam_dma_register = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ppu_write(address addr, byte data) {
|
||||||
|
assert(addr < PPU_VRAM_SIZE);
|
||||||
|
|
||||||
|
address relative_addr;
|
||||||
|
|
||||||
|
if (addr < 0x2000) {
|
||||||
|
// TODO Unsupported ?
|
||||||
|
} else if (addr < 0x2400) {
|
||||||
|
relative_addr = addr - 0x2000;
|
||||||
|
ppu_state.memory.nametable_0[relative_addr] = data;
|
||||||
|
} else if (addr < 0x2800) {
|
||||||
|
relative_addr = addr - 0x2400;
|
||||||
|
byte *nametable;
|
||||||
|
|
||||||
|
if (rom_get()->nametable_mirrored) {
|
||||||
|
nametable = ppu_state.memory.nametable_1;
|
||||||
|
} else {
|
||||||
|
nametable = ppu_state.memory.nametable_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nametable[relative_addr] = data;
|
||||||
|
} else if (addr < 0x2c00) {
|
||||||
|
relative_addr = addr - 0x2800;
|
||||||
|
byte *nametable;
|
||||||
|
|
||||||
|
if (rom_get()->nametable_mirrored) {
|
||||||
|
nametable = ppu_state.memory.nametable_0;
|
||||||
|
} else {
|
||||||
|
nametable = ppu_state.memory.nametable_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nametable[relative_addr] = data;
|
||||||
|
} else if (addr < 0x3000) {
|
||||||
|
relative_addr = addr - 0x2c00;
|
||||||
|
ppu_state.memory.nametable_1[relative_addr] = data;
|
||||||
|
} else if (addr >= 0x3f00) {
|
||||||
|
relative_addr = (addr - 0x3f00) % PALETTE_TABLE_SIZE;
|
||||||
|
ppu_state.memory.palette[relative_addr] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
byte ppu_read(address addr) {
|
byte ppu_read(address addr) {
|
||||||
assert(addr < PPU_VRAM_SIZE);
|
assert(addr < PPU_VRAM_SIZE);
|
||||||
|
|
||||||
|
@ -260,9 +350,10 @@ byte ppu_read(address addr) {
|
||||||
relative_addr = addr - 0x2c00;
|
relative_addr = addr - 0x2c00;
|
||||||
return ppu_state.memory.nametable_1[relative_addr];
|
return ppu_state.memory.nametable_1[relative_addr];
|
||||||
} else if (addr >= 0x3f00) {
|
} else if (addr >= 0x3f00) {
|
||||||
relative_addr = (addr - 0x3f00) % 0x20;
|
relative_addr = (addr - 0x3f00) % PALETTE_TABLE_SIZE;
|
||||||
return ppu_state.memory.palette[relative_addr];
|
return ppu_state.memory.palette[relative_addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
// assert(false);
|
||||||
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in New Issue