PPU nametable/pattern background rendering!!!
This commit is contained in:
parent
5fd5106ad4
commit
d9f0c67668
|
@ -10,7 +10,7 @@
|
||||||
#define WINDOW_ID_MAIN 1
|
#define WINDOW_ID_MAIN 1
|
||||||
#define WINDOW_MAIN_WIDTH 256
|
#define WINDOW_MAIN_WIDTH 256
|
||||||
#define WINDOW_MAIN_HEIGHT 240
|
#define WINDOW_MAIN_HEIGHT 240
|
||||||
#define WINDOW_MAIN_SCALING 3
|
#define WINDOW_MAIN_SCALING 2
|
||||||
|
|
||||||
#define WINDOW_ID_PATTERN 2
|
#define WINDOW_ID_PATTERN 2
|
||||||
#define WINDOW_PATTERN_WIDTH 128
|
#define WINDOW_PATTERN_WIDTH 128
|
||||||
|
|
|
@ -57,7 +57,6 @@
|
||||||
#define PALETTE_TABLE_SIZE 0x0020
|
#define PALETTE_TABLE_SIZE 0x0020
|
||||||
|
|
||||||
typedef struct ppu_memory {
|
typedef struct ppu_memory {
|
||||||
byte vram[PPU_VRAM_SIZE];
|
|
||||||
byte nametable_0[NAMETABLE_SIZE];
|
byte nametable_0[NAMETABLE_SIZE];
|
||||||
byte nametable_1[NAMETABLE_SIZE];
|
byte nametable_1[NAMETABLE_SIZE];
|
||||||
byte palette[PALETTE_TABLE_SIZE];
|
byte palette[PALETTE_TABLE_SIZE];
|
||||||
|
|
2
main.c
2
main.c
|
@ -26,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_japan.nes";
|
char *rom_path = "../test_roms/nestest.nes";
|
||||||
|
|
||||||
if (!rom_load(rom_path)) {
|
if (!rom_load(rom_path)) {
|
||||||
system_uninit();
|
system_uninit();
|
||||||
|
|
64
ppu/ppu.c
64
ppu/ppu.c
|
@ -60,13 +60,16 @@ void ppu_draw_tile() {
|
||||||
PPUTileFetch tile_fetch = ppu_state.tile_fetch;
|
PPUTileFetch tile_fetch = ppu_state.tile_fetch;
|
||||||
Canvas *canvas = gui_get_canvas(WINDOW_ID_MAIN);
|
Canvas *canvas = gui_get_canvas(WINDOW_ID_MAIN);
|
||||||
|
|
||||||
byte tile_fine_x = ppu_state.cycle % 8;
|
byte tile_fine_x = (ppu_state.cycle - 1) % 8;
|
||||||
|
|
||||||
byte bitmask = 1 << (PATTERN_TILE_SIZE - tile_fine_x - 1);
|
byte bitmask = 1 << (PATTERN_TILE_SIZE - tile_fine_x - 1);
|
||||||
byte p1_byte = tile_fetch.pattern_table_tile_low & bitmask;
|
byte p1_byte = tile_fetch.pattern_table_tile_low & bitmask;
|
||||||
byte p2_byte = tile_fetch.pattern_table_tile_high & bitmask;
|
byte p2_byte = tile_fetch.pattern_table_tile_high & bitmask;
|
||||||
|
|
||||||
Pixel pixel;
|
Pixel pixel;
|
||||||
|
// pixel.r = ~tile_fetch.nametable;
|
||||||
|
// pixel.g = ~tile_fetch.nametable;
|
||||||
|
// pixel.b = tile_fetch.nametable;
|
||||||
if (p1_byte && p2_byte) {
|
if (p1_byte && p2_byte) {
|
||||||
pixel.r = 255;
|
pixel.r = 255;
|
||||||
pixel.g = 255;
|
pixel.g = 255;
|
||||||
|
@ -91,39 +94,42 @@ void ppu_draw_tile() {
|
||||||
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) {
|
||||||
if (!ppu_read_flag(PPU_REGISTER_MASK, PPU_MASK_SHOW_BG) && ppu_state.scanline < 240) {
|
if (ppu_read_flag(PPU_REGISTER_MASK, PPU_MASK_SHOW_BG)) {
|
||||||
if (cycle <= 248) {
|
|
||||||
ppu_draw_tile();
|
ppu_draw_tile();
|
||||||
}
|
|
||||||
|
|
||||||
|
if (cycle <= 248) {
|
||||||
|
address read_addr;
|
||||||
byte tile_fetch_cycle = (cycle - 1) % 8;
|
byte tile_fetch_cycle = (cycle - 1) % 8;
|
||||||
switch (tile_fetch_cycle) {
|
switch (tile_fetch_cycle) {
|
||||||
case 1:
|
case 1:
|
||||||
address nt_addr = 0x2000 + (ppu_state.scanline * 16) + (ppu_state.cycle / 8);
|
read_addr = 0x2000 + ((ppu_state.scanline / 8) * 0x20) + (ppu_state.cycle / 8);
|
||||||
ppu_state.next_tile_fetch.nametable = ppu_read(nt_addr);
|
ppu_state.next_tile_fetch.nametable = ppu_read(read_addr);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
address at_addr = 0x23c0 + (ppu_state.cycle % 8);
|
read_addr = 0x23c0 + (ppu_state.cycle % 8);
|
||||||
ppu_state.next_tile_fetch.attribute_table = ppu_read(at_addr);
|
ppu_state.next_tile_fetch.attribute_table = ppu_read(read_addr);
|
||||||
ppu_state.ppu_address++;
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
ppu_state.next_tile_fetch.pattern_table_tile_low = ppu_read(0x0000);
|
read_addr = 0x1000 * ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_BG_PATTERN_TABLE_ADDR);
|
||||||
|
read_addr += ppu_state.next_tile_fetch.nametable * 16 + ppu_state.scanline % 8;
|
||||||
|
ppu_state.next_tile_fetch.pattern_table_tile_low = ppu_read(read_addr);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
ppu_state.next_tile_fetch.pattern_table_tile_high = ppu_read(0x0008);
|
read_addr = 0x1000 * ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_BG_PATTERN_TABLE_ADDR);
|
||||||
|
read_addr += ppu_state.next_tile_fetch.nametable * 16 + ppu_state.scanline % 8 + 8;
|
||||||
|
ppu_state.next_tile_fetch.pattern_table_tile_high = ppu_read(read_addr);
|
||||||
ppu_state.tile_fetch = ppu_state.next_tile_fetch;
|
ppu_state.tile_fetch = ppu_state.next_tile_fetch;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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);
|
||||||
} else {
|
} else if (cycle <= 336) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +204,7 @@ byte ppu_read_reg(byte reg) {
|
||||||
// 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.memory.vram[ppu_state.ppu_address];
|
ppu_state.registers[reg] = ppu_read(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];
|
||||||
|
@ -211,9 +217,7 @@ byte ppu_read_reg(byte reg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ppu_state.ppu_address += increment;
|
ppu_state.ppu_address += increment;
|
||||||
if (ppu_state.ppu_address >= PPU_VRAM_SIZE) {
|
ppu_state.ppu_address %= PPU_VRAM_SIZE;
|
||||||
ppu_state.ppu_address -= PPU_VRAM_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -230,37 +234,33 @@ void ppu_write_reg(byte reg, byte data) {
|
||||||
// The VBlank flag is still set, and the GEN_VBLANK_NMI was set from 0 to 1
|
// The VBlank flag is still set, and the GEN_VBLANK_NMI was set from 0 to 1
|
||||||
cpu_trigger_nmi();
|
cpu_trigger_nmi();
|
||||||
} else if (reg == PPU_REGISTER_SCROLL) {
|
} else if (reg == PPU_REGISTER_SCROLL) {
|
||||||
ppu_state.w = !ppu_state.w;
|
|
||||||
if (!ppu_state.w) {
|
if (!ppu_state.w) {
|
||||||
ppu_state.x = data;
|
ppu_state.x = data;
|
||||||
} else {
|
} else {
|
||||||
ppu_state.t = data;
|
ppu_state.t = data;
|
||||||
}
|
}
|
||||||
} else if (reg == PPU_REGISTER_ADDR) {
|
|
||||||
ppu_state.w = !ppu_state.w;
|
ppu_state.w = !ppu_state.w;
|
||||||
|
} else if (reg == PPU_REGISTER_ADDR) {
|
||||||
address addr = ppu_state.ppu_address;
|
address addr = ppu_state.ppu_address;
|
||||||
if (ppu_state.w) {
|
if (!ppu_state.w) {
|
||||||
addr &= 0xff & data;
|
addr = data;
|
||||||
} else {
|
} else {
|
||||||
addr &= (data << 8) | 0x0f;
|
addr = data | (addr << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr >= PPU_VRAM_SIZE) {
|
ppu_state.ppu_address = addr % PPU_VRAM_SIZE;
|
||||||
addr -= PPU_VRAM_SIZE;
|
ppu_state.w = !ppu_state.w;
|
||||||
}
|
|
||||||
ppu_state.ppu_address = addr;
|
|
||||||
} else if (reg == PPU_REGISTER_DATA) {
|
} else if (reg == PPU_REGISTER_DATA) {
|
||||||
ppu_write(ppu_state.ppu_address, data);
|
address addr = ppu_state.ppu_address;
|
||||||
|
ppu_write(addr, 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)) {
|
||||||
increment = 32;
|
increment = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
ppu_state.ppu_address += increment;
|
addr += increment;
|
||||||
if (ppu_state.ppu_address >= PPU_VRAM_SIZE) {
|
ppu_state.ppu_address = addr % PPU_VRAM_SIZE;
|
||||||
ppu_state.ppu_address -= PPU_VRAM_SIZE;
|
|
||||||
}
|
|
||||||
} else if (reg == PPU_REGISTER_OAM_DATA) {
|
} else if (reg == PPU_REGISTER_OAM_DATA) {
|
||||||
byte oam_addr = ppu_state.registers[PPU_REGISTER_OAM_ADDR];
|
byte oam_addr = ppu_state.registers[PPU_REGISTER_OAM_ADDR];
|
||||||
ppu_write_reg(PPU_REGISTER_OAM_ADDR, oam_addr + 1);
|
ppu_write_reg(PPU_REGISTER_OAM_ADDR, oam_addr + 1);
|
||||||
|
|
Loading…
Reference in New Issue