summaryrefslogtreecommitdiff
path: root/mknes_ppu_registers.c
diff options
context:
space:
mode:
Diffstat (limited to 'mknes_ppu_registers.c')
-rw-r--r--mknes_ppu_registers.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/mknes_ppu_registers.c b/mknes_ppu_registers.c
new file mode 100644
index 0000000..a7aa351
--- /dev/null
+++ b/mknes_ppu_registers.c
@@ -0,0 +1,160 @@
+__attribute__((hot))
+static inline void ppu_write(struct nes_state *state, uint32_t offset, uint8_t value) {
+ struct ppu_state *ppu = &state->ppu;
+
+ switch(offset & 0x7) {
+ case 0: {
+ ppu->reg_ctrl = value;
+ ppu->temp_addr = (ppu->temp_addr & 0xf3ff) | ((value & 0x03) << 10);
+ } break;
+
+ case 1: {
+ ppu->reg_mask = value;
+ } break;
+
+ // case 2: // ONLY READ
+
+ case 3: {
+ ppu->oam_addr = value;
+ } break;
+
+ case 4: {
+ ppu->oam[ppu->oam_addr++] = value;
+ } break;
+
+ case 5: {
+ if(ppu->write_latch == 0) {
+ ppu->fine_x = value & 0x07;
+ ppu->temp_addr = (ppu->temp_addr & ~0x001f) | (value >> 3);
+ ppu->write_latch = 1;
+ } else {
+ ppu->temp_addr = (ppu->temp_addr & ~0x73e0) | ((value & 0x07) << 12) | ((value & 0xf8) << 2);
+ ppu->write_latch = 0;
+ }
+ } break;
+
+ case 6: {
+ if(ppu->write_latch == 0) {
+ ppu->temp_addr = (ppu->temp_addr & 0x00ff) | ((value & 0x3f) << 8);
+ ppu->write_latch = 1;
+ } else {
+ ppu->temp_addr = (ppu->temp_addr & 0xff00) | value;
+ ppu->vram_addr = ppu->temp_addr;
+ ppu->write_latch = 0;
+ }
+ } break;
+
+ case 7: {
+ uint32_t addr = ppu->vram_addr;
+
+ switch(addr) {
+ case 0x0000 ... 0x1fff: {
+ state->mapper_function.chr_write(state, addr, value);
+ } break;
+
+ case 0x2000 ... 0x3eff: {
+ state->mapper_function.ciram_write(state, addr, value);
+ } break;
+
+ case 0x3f00 ... 0x3fff: {
+ uint32_t pal_addr = addr & 0x1f;
+ if((pal_addr & 3) == 0) {
+ pal_addr &= ~0x10;
+ }
+ ppu->palette[pal_addr] = value;
+ } break;
+ }
+
+ ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1;
+ } break;
+
+ }
+
+ ppu->open_bus = value;
+ return;
+}
+
+
+__attribute__((hot))
+static inline uint8_t ppu_read(struct nes_state *state, uint32_t offset) {
+ struct ppu_state *ppu = &state->ppu;
+ uint8_t result = ppu->open_bus;
+
+ switch(offset & 0x7) {
+ case 2: {
+ result &= 0x1f;
+ result |= ppu->reg_status & 0xe0;
+ ppu->reg_status &= ~0x80;
+ ppu->write_latch = 0;
+ } break;
+
+ case 4: {
+ result = ppu->oam[ppu->oam_addr];
+ } break;
+
+ case 7: {
+ uint32_t addr = ppu->vram_addr;
+
+ switch(addr) {
+ case 0x0000 ... 0x1fff: {
+ result = ppu->vram_read_buffer;
+ ppu->vram_read_buffer = state->mapper_function.chr_read(state, addr);
+ } break;
+
+ case 0x2000 ... 0x3eff: {
+ result = ppu->vram_read_buffer;
+ ppu->vram_read_buffer = state->mapper_function.ciram_read(state, addr);
+ } break;
+
+ case 0x3f00 ... 0x3fff: {
+ uint32_t pal_addr = addr & 0x1f;
+ if((pal_addr & 0x13) == 0x10) {
+ pal_addr &= ~0x10;
+ }
+ result = ppu->palette[pal_addr] & 0x3f;
+ result |= ppu->open_bus & 0xc0;
+ ppu->vram_read_buffer = state->mapper_function.ciram_read(state, addr - 0x1000);
+ } break;
+
+ }
+
+ ppu->vram_addr += (ppu->reg_ctrl & 0x04) ? 32 : 1;
+ } break;
+
+ }
+ // ppu->open_bus = result;
+ return result;
+}
+
+
+static uint8_t memory_read_dma(struct nes_state *state, uint32_t offset);
+
+__attribute__((hot))
+static inline void ppu_dma_4014(struct nes_state *state, uint8_t page) {
+ uint32_t base = page << 8;
+
+ // Add 1 or 2 idle cycles depending on current CPU cycle
+ uint8_t idle_cycles = (state->cpu.cycles & 1) ? 1 : 2;
+ for(uint8_t i = 0; i < idle_cycles; i++) {
+ state->cpu.cycles++;
+ ppu_tick(state);
+ apu_tick(state);
+ }
+
+ for(uint32_t i = 0; i < 256; i++) {
+ uint32_t addr = base + i;
+
+ state->cpu.cycles++;
+ ppu_tick(state);
+ apu_tick(state);
+ uint8_t value = memory_read_dma(state, addr);
+
+ state->cpu.cycles++;
+ ppu_tick(state);
+ apu_tick(state);
+
+ ppu_write(state, 4, value);
+ }
+}
+
+