PPU_CTRL, PPU_STATUS
This commit is contained in:
parent
d5fba04314
commit
1bc9d4950f
11
cpu/memory.c
11
cpu/memory.c
|
@ -22,7 +22,7 @@ byte mem_get_byte(address addr) {
|
||||||
|
|
||||||
if (addr >= RAM_MAX_ADDR && addr < PPU_MAX_ADDR) {
|
if (addr >= RAM_MAX_ADDR && addr < PPU_MAX_ADDR) {
|
||||||
byte reg = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE;
|
byte reg = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE;
|
||||||
ppu_sig_read_register(reg);
|
return ppu_read_reg(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ram[addr];
|
return ram[addr];
|
||||||
|
@ -57,14 +57,7 @@ void mem_set_byte(address addr, byte byte) {
|
||||||
}
|
}
|
||||||
} else if (addr < PPU_MAX_ADDR) {
|
} else if (addr < PPU_MAX_ADDR) {
|
||||||
address reg_addr = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE;
|
address reg_addr = (addr - RAM_MAX_ADDR) % PPU_BANK_SIZE;
|
||||||
|
ppu_write_reg(reg_addr, byte);
|
||||||
int bank_count = (PPU_MAX_ADDR - RAM_MAX_ADDR) / PPU_BANK_SIZE;
|
|
||||||
for (int i = 0; i < bank_count; i++) {
|
|
||||||
address ram_addr = reg_addr + PPU_BANK_SIZE * i + RAM_MAX_ADDR;
|
|
||||||
ram[ram_addr] = byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
ppu_sig_write_register(reg_addr);
|
|
||||||
} else {
|
} else {
|
||||||
ram[addr] = byte;
|
ram[addr] = byte;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
#define PPU_REGISTER_SIZE 0x8
|
#define PPU_REGISTER_SIZE 0x8
|
||||||
#define PPU_VRAM_SIZE 0x4000
|
#define PPU_VRAM_SIZE 0x4000
|
||||||
#define PPU_OAM_SIZE 0xff
|
#define PPU_OAM_SIZE 0xff
|
||||||
|
#define PPU_RAM_BASE_ADDR 0x2000
|
||||||
|
#define PPU_RAM_MAX_ADDR 0x4000
|
||||||
|
#define PPU_RAM_BANK_SIZE 0x8
|
||||||
|
#define PPU_RAM_BANK_COUNT ((PPU_RAM_MAX_ADDR - PPU_RAM_BASE_ADDR) / PPU_RAM_BANK_SIZE)
|
||||||
|
|
||||||
#define PPU_REGISTER_CTRL 0x00
|
#define PPU_REGISTER_CTRL 0x00
|
||||||
#define PPU_REGISTER_MASK 0x01
|
#define PPU_REGISTER_MASK 0x01
|
||||||
|
@ -22,6 +26,8 @@
|
||||||
#define PPU_REGISTER_ADDR 0x06
|
#define PPU_REGISTER_ADDR 0x06
|
||||||
#define PPU_REGISTER_DATA 0x07
|
#define PPU_REGISTER_DATA 0x07
|
||||||
|
|
||||||
|
#define PPU_CTRL_SCROLL_X 0x1
|
||||||
|
#define PPU_CTRL_SCROLL_Y 0x2
|
||||||
#define PPU_CTRL_BASE_NAMETABLE_ADDR 0x3
|
#define PPU_CTRL_BASE_NAMETABLE_ADDR 0x3
|
||||||
#define PPU_CTRL_VRAM_ADDR_INCREMENT 0x4
|
#define PPU_CTRL_VRAM_ADDR_INCREMENT 0x4
|
||||||
#define PPU_CTRL_SP_PATTERN_TABLE_ADDR 0x8
|
#define PPU_CTRL_SP_PATTERN_TABLE_ADDR 0x8
|
||||||
|
@ -56,8 +62,6 @@ typedef struct ppu {
|
||||||
address t;
|
address t;
|
||||||
byte x;
|
byte x;
|
||||||
bool w;
|
bool w;
|
||||||
|
|
||||||
|
|
||||||
} PPU;
|
} PPU;
|
||||||
|
|
||||||
PPU *ppu_get_state();
|
PPU *ppu_get_state();
|
||||||
|
@ -93,8 +97,11 @@ bool ppu_read_flag(size_t reg, byte mask);
|
||||||
* @param reg The register index
|
* @param reg The register index
|
||||||
* @param mask The value mask
|
* @param mask The value mask
|
||||||
*/
|
*/
|
||||||
void ppu_sig_read_register(byte reg);
|
//void ppu_sig_read_register(byte reg);
|
||||||
|
//
|
||||||
|
//void ppu_sig_write_register(byte reg);
|
||||||
|
|
||||||
void ppu_sig_write_register(byte reg);
|
byte ppu_read_reg(byte reg);
|
||||||
|
void ppu_write_reg(byte reg, byte data);
|
||||||
|
|
||||||
#endif //NESEMULATOR_PPU_H
|
#endif //NESEMULATOR_PPU_H
|
||||||
|
|
98
ppu/ppu.c
98
ppu/ppu.c
|
@ -14,6 +14,7 @@
|
||||||
// 10. This is where I'm stuck. I think I need to read the "sprites" section of https://wiki.nesdev.com/w/index.php/PPU_rendering very carefully.
|
// 10. This is where I'm stuck. I think I need to read the "sprites" section of https://wiki.nesdev.com/w/index.php/PPU_rendering very carefully.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include "../include/ppu.h"
|
#include "../include/ppu.h"
|
||||||
#include "../cpu/cpu.h"
|
#include "../cpu/cpu.h"
|
||||||
|
|
||||||
|
@ -98,31 +99,94 @@ bool ppu_read_flag(size_t reg, byte mask) {
|
||||||
return ppu_state.registers[reg] & mask;
|
return ppu_state.registers[reg] & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
//byte ppu_sig_read_register(size_t reg, byte mask) {
|
byte ppu_read_reg(byte reg) {
|
||||||
// return ppu_state.registers[reg] & mask;
|
assert(reg >= 0);
|
||||||
//}
|
assert(reg <= PPU_REGISTER_SIZE);
|
||||||
|
|
||||||
void ppu_sig_read_register(byte reg) {
|
|
||||||
if (reg == PPU_REGISTER_STATUS) {
|
if (reg == PPU_REGISTER_STATUS) {
|
||||||
ppu_state.w = false;
|
ppu_state.w = false;
|
||||||
|
ppu_state.registers[PPU_REGISTER_STATUS] &= ~PPU_STATUS_VBLANK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
// So we get the data first, then update the register.
|
||||||
|
byte data = ppu_state.registers[reg];
|
||||||
|
ppu_state.registers[reg] = ppu_state.vram[ppu_state.v];
|
||||||
|
if (ppu_state.v > 0x3eff) {
|
||||||
|
// But the palette data is returned immediately
|
||||||
|
data = ppu_state.registers[reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
// We then need to increment the VRAM address
|
||||||
|
byte increment = 1;
|
||||||
|
if (ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_VRAM_ADDR_INCREMENT)) {
|
||||||
|
increment = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppu_state.v += increment;
|
||||||
|
if (ppu_state.v >= PPU_VRAM_SIZE) {
|
||||||
|
ppu_state.v -= PPU_VRAM_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ppu_state.registers[reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ppu_write_reg_ram(byte reg, byte data) {
|
||||||
|
byte *ppu_ram = mem_get_ptr(PPU_RAM_BASE_ADDR);
|
||||||
|
|
||||||
|
for (int i = 0; i < PPU_RAM_BANK_COUNT; i++) {
|
||||||
|
byte ram_offset = (i * PPU_RAM_BANK_SIZE) + reg;
|
||||||
|
*(ppu_ram + ram_offset) = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppu_sig_write_register(byte reg) {
|
void ppu_write_reg(byte reg, byte data) {
|
||||||
if (reg == PPU_REGISTER_ADDR) {
|
ppu_state.registers[reg] = data;
|
||||||
byte addr_write = ppu_state.registers[PPU_REGISTER_ADDR];
|
|
||||||
if (!ppu_state.w) {
|
if (reg == PPU_REGISTER_CTRL && ppu_read_flag(PPU_REGISTER_STATUS, PPU_STATUS_VBLANK) &&
|
||||||
ppu_state.v &= (addr_write << 8) | 0x0f;
|
!ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_GEN_VBLANK_NMI) &&
|
||||||
|
data & PPU_CTRL_GEN_VBLANK_NMI) {
|
||||||
|
// The VBlank flag is still set, and the GEN_VBLANK_NMI was set from 0 to 1
|
||||||
|
cpu_trigger_nmi();
|
||||||
|
} else if (reg == PPU_REGISTER_SCROLL || reg == PPU_REGISTER_ADDR) {
|
||||||
|
ppu_state.
|
||||||
|
w = !ppu_state.w;
|
||||||
|
} else if (reg == PPU_REGISTER_ADDR) {
|
||||||
|
address addr = ppu_state.v;
|
||||||
|
if (ppu_state.w) {
|
||||||
|
addr &= 0xff &
|
||||||
|
data;
|
||||||
} else {
|
} else {
|
||||||
ppu_state.v &= 0xff & addr_write;
|
addr &= (data << 8) | 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addr >= PPU_VRAM_SIZE) {
|
||||||
|
addr -= PPU_VRAM_SIZE;
|
||||||
|
}
|
||||||
|
ppu_state.
|
||||||
|
v = addr;
|
||||||
|
} else if (reg == PPU_REGISTER_DATA) {
|
||||||
|
ppu_state.vram[ppu_state.v] =
|
||||||
|
data;
|
||||||
|
|
||||||
|
byte increment = 1;
|
||||||
|
if (ppu_read_flag(PPU_REGISTER_CTRL, PPU_CTRL_VRAM_ADDR_INCREMENT)) {
|
||||||
|
increment = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppu_state.v +=
|
||||||
|
increment;
|
||||||
|
if (ppu_state.v >= PPU_VRAM_SIZE) {
|
||||||
|
ppu_state.v -= PPU_VRAM_SIZE;
|
||||||
|
}
|
||||||
|
} else if (reg == PPU_REGISTER_OAM_DATA) {
|
||||||
|
byte oam_addr = ppu_state.registers[PPU_REGISTER_OAM_ADDR];
|
||||||
|
ppu_write_reg(PPU_REGISTER_OAM_ADDR, oam_addr + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg == PPU_REGISTER_SCROLL || reg == PPU_REGISTER_ADDR) {
|
ppu_write_reg_ram(reg, data);
|
||||||
ppu_state.w = !ppu_state.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reg == PPU_REGISTER_OAM_DATA) {
|
|
||||||
ppu_state.registers[PPU_REGISTER_OAM_ADDR]++;
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue