auto CPU::readAPU(uint24 addr, uint8 data) -> uint8 { synchronizeSMP(); return smp.portRead(addr.bits(0,1)); } auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 { switch((uint16)addr) { //WMDATA case 0x2180: { return bus.read(0x7e0000 | status.wramAddress++, r.mdr); } //JOYSER0 //7-2 = MDR //1-0 = Joypad serial data case 0x4016: { uint8 v = r.mdr & 0xfc; v |= SuperFamicom::peripherals.controllerPort1->data(); return v; } //JOYSER1 case 0x4017: { //7-5 = MDR //4-2 = Always 1 (pins are connected to GND) //1-0 = Joypad serial data uint8 v = (r.mdr & 0xe0) | 0x1c; v |= SuperFamicom::peripherals.controllerPort2->data(); return v; } //RDNMI case 0x4210: { //7 = NMI acknowledge //6-4 = MDR //3-0 = CPU (5a22) version uint8 v = (r.mdr & 0x70); v |= (uint8)(rdnmi()) << 7; v |= (version & 0x0f); return v; } //TIMEUP case 0x4211: { //7 = IRQ acknowledge //6-0 = MDR uint8 v = (r.mdr & 0x7f); v |= (uint8)(timeup()) << 7; return v; } //HVBJOY case 0x4212: { //7 = VBLANK acknowledge //6 = HBLANK acknowledge //5-1 = MDR //0 = JOYPAD acknowledge uint8 v = (r.mdr & 0x3e); if(status.autoJoypadActive) v |= 0x01; if(hcounter() <= 2 || hcounter() >= 1096) v |= 0x40; //hblank if(vcounter() >= ppu.vdisp()) v |= 0x80; //vblank return v; } //RDIO case 0x4213: { return status.pio; } //RDDIVL case 0x4214: { return status.rddiv.byte(0); } //RDDIVH case 0x4215: { return status.rddiv.byte(1); } //RDMPYL case 0x4216: { return status.rdmpy.byte(0); } //RDMPYH case 0x4217: { return status.rdmpy.byte(1); } case 0x4218: return status.joy1.byte(0); //JOY1L case 0x4219: return status.joy1.byte(1); //JOY1H case 0x421a: return status.joy2.byte(0); //JOY2L case 0x421b: return status.joy2.byte(1); //JOY2H case 0x421c: return status.joy3.byte(0); //JOY3L case 0x421d: return status.joy3.byte(1); //JOY3H case 0x421e: return status.joy4.byte(0); //JOY4L case 0x421f: return status.joy4.byte(1); //JOY4H } return data; } auto CPU::readDMA(uint24 addr, uint8 data) -> uint8 { auto& channel = this->channel[addr.bits(4,6)]; switch(addr & 0xff0f) { //DMAPx case 0x4300: return ( channel.transferMode << 0 | channel.fixedTransfer << 3 | channel.reverseTransfer << 4 | channel.unused << 5 | channel.indirect << 6 | channel.direction << 7 ); //BBADx case 0x4301: return channel.targetAddress; //A1TxL case 0x4302: return channel.sourceAddress >> 0; //A1TxH case 0x4303: return channel.sourceAddress >> 8; //A1Bx case 0x4304: return channel.sourceBank; //DASxL -- union { uint16 transferSize; uint16 indirectAddress; }; case 0x4305: return channel.transferSize.byte(0); //DASxH -- union { uint16 transferSize; uint16 indirectAddress; }; case 0x4306: return channel.transferSize.byte(1); //DASBx case 0x4307: return channel.indirectBank; //A2AxL case 0x4308: return channel.hdmaAddress.byte(0); //A2AxH case 0x4309: return channel.hdmaAddress.byte(1); //NTRLx case 0x430a: return channel.lineCounter; //??? case 0x430b: case 0x430f: return channel.unknown; } return data; } auto CPU::writeAPU(uint24 addr, uint8 data) -> void { synchronizeSMP(); return portWrite(addr.bits(0,1), data); } auto CPU::writeCPU(uint24 addr, uint8 data) -> void { switch((uint16)addr) { //WMDATA case 0x2180: { return bus.write(0x7e0000 | status.wramAddress++, data); } case 0x2181: status.wramAddress.bits( 0, 7) = data; return; //WMADDL case 0x2182: status.wramAddress.bits( 8,15) = data; return; //WMADDM case 0x2183: status.wramAddress.bit (16 ) = data.bit(0); return; //WMADDH //JOYSER0 case 0x4016: { //bit 0 is shared between JOYSER0 and JOYSER1, therefore //strobing $4016.d0 affects both controller port latches. //$4017 bit 0 writes are ignored. SuperFamicom::peripherals.controllerPort1->latch(data.bit(0)); SuperFamicom::peripherals.controllerPort2->latch(data.bit(0)); return; } //NMITIMEN case 0x4200: { status.autoJoypadPoll = data.bit(0); nmitimenUpdate(data); return; } //WRIO case 0x4201: { if(status.pio.bit(7) && !data.bit(7)) ppu.latchCounters(); status.pio = data; return; } //WRMPYA case 0x4202: status.wrmpya = data; return; //WRMPYB case 0x4203: { status.rdmpy = 0; if(alu.mpyctr || alu.divctr) return; status.wrmpyb = data; status.rddiv = (status.wrmpyb << 8) | status.wrmpya; alu.mpyctr = 8; //perform multiplication over the next eight cycles alu.shift = status.wrmpyb; return; } case 0x4204: { status.wrdiva.byte(0) = data; return; } //WRDIVL case 0x4205: { status.wrdiva.byte(1) = data; return; } //WRDIVH //WRDIVB case 0x4206: { status.rdmpy = status.wrdiva; if(alu.mpyctr || alu.divctr) return; status.wrdivb = data; alu.divctr = 16; //perform division over the next sixteen cycles alu.shift = status.wrdivb << 16; return; } case 0x4207: status.hirqPos.bits(0,7) = data; return; //HTIMEL case 0x4208: status.hirqPos.bit (8 ) = data.bit(0); return; //HTIMEH case 0x4209: status.virqPos.bits(0,7) = data; return; //VTIMEL case 0x420a: status.virqPos.bit (8 ) = data.bit(0); return; //VTIMEH //DMAEN case 0x420b: { for(auto n : range(8)) channel[n].dmaEnabled = data.bit(n); if(data) status.dmaPending = true; return; } //HDMAEN case 0x420c: { for(auto n : range(8)) channel[n].hdmaEnabled = data.bit(n); return; } //MEMSEL case 0x420d: { status.romSpeed = data.bit(0) ? 6 : 8; return; } } } auto CPU::writeDMA(uint24 addr, uint8 data) -> void { auto& channel = this->channel[addr.bits(4,6)]; switch(addr & 0xff0f) { //DMAPx case 0x4300: { channel.transferMode = data.bits(0,2); channel.fixedTransfer = data.bit (3); channel.reverseTransfer = data.bit (4); channel.unused = data.bit (5); channel.indirect = data.bit (6); channel.direction = data.bit (7); return; } //DDBADx case 0x4301: channel.targetAddress = data; return; //A1TxL case 0x4302: channel.sourceAddress.byte(0) = data; return; //A1TxH case 0x4303: channel.sourceAddress.byte(1) = data; return; //A1Bx case 0x4304: channel.sourceBank = data; return; //DASxL -- union { uint16 transferSize; uint16 indirectAddress; }; case 0x4305: channel.transferSize.byte(0) = data; return; //DASxH -- union { uint16 transferSize; uint16 indirectAddress; }; case 0x4306: channel.transferSize.byte(1) = data; return; //DASBx case 0x4307: channel.indirectBank = data; return; //A2AxL case 0x4308: channel.hdmaAddress.byte(0) = data; return; //A2AxH case 0x4309: channel.hdmaAddress.byte(1) = data; return; //NTRLx case 0x430a: channel.lineCounter = data; return; //??? case 0x430b: case 0x430f: channel.unknown = data; return; } }