static inline void ppu_tick(struct nes_state *state); static inline uint8_t memory_read(struct nes_state *state, uint32_t offset); // DMC frequency table (NTSC) static const uint16_t dmc_rate_table[16] = { 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 85, 72, 54 }; // $4015 write static void apu_write4015(struct nes_state *state, uint8_t val) { struct apu_state *apu = &state->apu; if(val & 0x10) { if(!apu->dmc_dma_enabled || apu->dmc_bytes_remaining == 0) { apu->dmc_current_addr = 0xC000 + ((uint16_t)apu->dmc_sample_addr << 6); apu->dmc_bytes_remaining = ((uint16_t)apu->dmc_sample_len << 4); } apu->dmc_dma_enabled = 1; } else { apu->dmc_dma_enabled = 0; } } // $4015 read static uint8_t apu_read4015(struct nes_state *state) { struct apu_state *apu = &state->apu; uint8_t result = 0; if(apu->dmc_bytes_remaining > 0) { result |= 0x10; } if(apu->irq_pending) { result |= 0x40; apu->irq_pending = 0; } return result; } // $4010–$4013, $4015 write static void apu_write(struct nes_state *state, uint16_t addr, uint8_t val) { struct apu_state *apu = &state->apu; switch(addr) { case 0x4010: { apu->dmc_irq_enable = (val >> 7) & 1; apu->dmc_loop_flag = (val >> 6) & 1; apu->dmc_freq_index = val & 0x0F; } break; case 0x4011: { // DAC write ignored } break; case 0x4012: { apu->dmc_sample_addr = val; } break; case 0x4013: { apu->dmc_sample_len = val; } break; case 0x4015: { apu_write4015(state, val); } break; } } // APU tick static inline void apu_tick(struct nes_state *state) { struct apu_state *apu = &state->apu; apu->frame_cycle++; if(apu->mode == 0) { if(apu->frame_cycle == 7457) { // Quarter frame } else if(apu->frame_cycle == 14913) { // Quarter frame // Half frame } else if(apu->frame_cycle == 22371) { // Quarter frame } else if(apu->frame_cycle == 29829) { // Half frame if(!apu->irq_inhibit) { apu->irq_pending = 1; } } else if(apu->frame_cycle >= 29830) { apu->frame_cycle = 0; } } else { if(apu->frame_cycle == 7457) { // Quarter frame } else if(apu->frame_cycle == 14913) { // Quarter frame // Half frame } else if(apu->frame_cycle == 22371) { // Quarter frame } else if(apu->frame_cycle == 29829) { // Half frame } else if(apu->frame_cycle == 37281) { // Quarter frame } else if(apu->frame_cycle >= 37282) { apu->frame_cycle = 0; } } // if(apu->mode == 0) { // if(apu->frame_cycle == 7457 || apu->frame_cycle == 14913 || apu->frame_cycle == 22371) { // // Quarter frame // } // if(apu->frame_cycle == 14913 || apu->frame_cycle == 29829) { // // Half frame // } // if(apu->frame_cycle == 29829 && !apu->irq_inhibit) { // apu->irq_pending = 1; // } // if(apu->frame_cycle >= 29830) { // apu->frame_cycle = 0; // } // } else { // if(apu->frame_cycle == 7457 || apu->frame_cycle == 14913 || apu->frame_cycle == 22371 || apu->frame_cycle == 37281) { // // Quarter frame // } // if(apu->frame_cycle == 14913 || apu->frame_cycle == 29829) { // // Half frame // } // if(apu->frame_cycle >= 37282) { // apu->frame_cycle = 0; // } // } if(apu->dmc_dma_enabled && apu->dmc_bytes_remaining > 0) { apu->dmc_sample_timer++; if(apu->dmc_sample_timer >= dmc_rate_table[apu->dmc_freq_index]) { apu->dmc_sample_timer = 0; uint8_t val = memory_read(state, apu->dmc_current_addr); (void)val; apu->dmc_current_addr++; if(apu->dmc_current_addr == 0x0000) { apu->dmc_current_addr = 0x8000; } apu->dmc_bytes_remaining--; if(apu->dmc_bytes_remaining == 0) { if(apu->dmc_loop_flag) { apu->dmc_current_addr = 0xC000 + ((uint16_t)apu->dmc_sample_addr << 6); apu->dmc_bytes_remaining = ((uint16_t)apu->dmc_sample_len << 4); } else { if(apu->dmc_irq_enable) { apu->irq_pending = 1; } apu->dmc_dma_enabled = 0; } } for(uint32_t i = 0; i < 4; i++) { state->cpu.cycles++; ppu_tick(state); } } } }