ref: 2c5078c443482b8102b45eb4309b8f8068757a91
dir: /snes/apu.c/
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <stddef.h> #include "apu.h" #include "snes.h" #include "spc.h" #include "dsp.h" static const uint8_t bootRom[0x40] = { 0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0, 0xfc, 0x8f, 0xaa, 0xf4, 0x8f, 0xbb, 0xf5, 0x78, 0xcc, 0xf4, 0xd0, 0xfb, 0x2f, 0x19, 0xeb, 0xf4, 0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5, 0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab, 0x01, 0x10, 0xef, 0x7e, 0xf4, 0x10, 0xeb, 0xba, 0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4, 0xf4, 0xdd, 0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0x00, 0xc0, 0xff }; Apu* apu_init() { Apu* apu = (Apu * )malloc(sizeof(Apu)); apu->spc = spc_init(apu); apu->dsp = dsp_init(apu->ram); return apu; } void apu_free(Apu* apu) { spc_free(apu->spc); dsp_free(apu->dsp); free(apu); } void apu_saveload(Apu *apu, SaveLoadFunc *func, void *ctx) { func(ctx, apu->ram, offsetof(Apu, hist) - offsetof(Apu, ram)); dsp_saveload(apu->dsp, func, ctx); spc_saveload(apu->spc, func, ctx); } void apu_reset(Apu* apu) { apu->romReadable = true; // before resetting spc, because it reads reset vector from it spc_reset(apu->spc); dsp_reset(apu->dsp); memset(apu->ram, 0, sizeof(apu->ram)); apu->dspAdr = 0; apu->cycles = 0; memset(apu->inPorts, 0, sizeof(apu->inPorts)); memset(apu->outPorts, 0, sizeof(apu->outPorts)); for(int i = 0; i < 3; i++) { apu->timer[i].cycles = 0; apu->timer[i].divider = 0; apu->timer[i].target = 0; apu->timer[i].counter = 0; apu->timer[i].enabled = false; } apu->cpuCyclesLeft = 7; apu->hist.count = 0; } void apu_cycle(Apu* apu) { if(apu->cpuCyclesLeft == 0) { apu->cpuCyclesLeft = spc_runOpcode(apu->spc); } apu->cpuCyclesLeft--; if((apu->cycles & 0x1f) == 0) { // every 32 cycles dsp_cycle(apu->dsp); } // handle timers for(int i = 0; i < 3; i++) { if(apu->timer[i].cycles == 0) { apu->timer[i].cycles = i == 2 ? 16 : 128; if(apu->timer[i].enabled) { apu->timer[i].divider++; if(apu->timer[i].divider == apu->timer[i].target) { apu->timer[i].divider = 0; apu->timer[i].counter++; apu->timer[i].counter &= 0xf; } } } apu->timer[i].cycles--; } apu->cycles++; } uint8_t apu_cpuRead(Apu* apu, uint16_t adr) { switch(adr) { case 0xf0: case 0xf1: case 0xfa: case 0xfb: case 0xfc: { return 0; } case 0xf2: { return apu->dspAdr; } case 0xf3: { return dsp_read(apu->dsp, apu->dspAdr & 0x7f); } case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: { return apu->inPorts[adr - 0xf4]; } case 0xfd: case 0xfe: case 0xff: { uint8_t ret = apu->timer[adr - 0xfd].counter; apu->timer[adr - 0xfd].counter = 0; return ret; } } if(apu->romReadable && adr >= 0xffc0) { return bootRom[adr - 0xffc0]; } return apu->ram[adr]; } void apu_cpuWrite(Apu* apu, uint16_t adr, uint8_t val) { switch(adr) { case 0xf0: { break; // test register } case 0xf1: { for(int i = 0; i < 3; i++) { if(!apu->timer[i].enabled && (val & (1 << i))) { apu->timer[i].divider = 0; apu->timer[i].counter = 0; } apu->timer[i].enabled = val & (1 << i); } if(val & 0x10) { apu->inPorts[0] = 0; apu->inPorts[1] = 0; } if(val & 0x20) { apu->inPorts[2] = 0; apu->inPorts[3] = 0; } apu->romReadable = val & 0x80; break; } case 0xf2: { apu->dspAdr = val; break; } case 0xf3: { int i = apu->hist.count; if (i != 256) { apu->hist.count = i + 1; apu->hist.addr[i] = apu->dspAdr; apu->hist.val[i] = val; } if(apu->dspAdr < 0x80) dsp_write(apu->dsp, apu->dspAdr, val); break; } case 0xf4: case 0xf5: case 0xf6: case 0xf7: { apu->outPorts[adr - 0xf4] = val; break; } case 0xf8: case 0xf9: { apu->inPorts[adr - 0xf4] = val; break; } case 0xfa: case 0xfb: case 0xfc: { apu->timer[adr - 0xfa].target = val; break; } } apu->ram[adr] = val; }