auto CPU::apuPortRead(uint24 addr, uint8 data) -> uint8 { synchronizeSMP(); return smp.portRead(addr.bits(0,1)); } auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 { addr &= 0xffff; //WMDATA if(addr == 0x2180) { return bus.read(0x7e0000 | status.wram_addr++, r.mdr); } //JOYSER0 //7-2 = MDR //1-0 = Joypad serial data if(addr == 0x4016) { uint8 v = r.mdr & 0xfc; v |= SuperFamicom::peripherals.controllerPort1->data(); return v; } //JOYSER1 if(addr == 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 if(addr == 0x4210) { //7 = NMI acknowledge //6-4 = MDR //3-0 = CPU (5a22) version uint8 v = (r.mdr & 0x70); v |= (uint8)(rdnmi()) << 7; v |= (cpu_version & 0x0f); return v; } //TIMEUP if(addr == 0x4211) { //7 = IRQ acknowledge //6-0 = MDR uint8 v = (r.mdr & 0x7f); v |= (uint8)(timeup()) << 7; return v; } //HVBJOY if(addr == 0x4212) { //7 = VBLANK acknowledge //6 = HBLANK acknowledge //5-1 = MDR //0 = JOYPAD acknowledge uint8 v = (r.mdr & 0x3e); if(status.auto_joypad_active) v |= 0x01; if(hcounter() <= 2 || hcounter() >= 1096) v |= 0x40; //hblank if(vcounter() >= ppu.vdisp()) v |= 0x80; //vblank return v; } //RDIO if(addr == 0x4213) { return status.pio; } //RDDIVL if(addr == 0x4214) { return status.rddiv.byte(0); } //RDDIVH if(addr == 0x4215) { return status.rddiv.byte(1); } //RDMPYL if(addr == 0x4216) { return status.rdmpy.byte(0); } //RDMPYH if(addr == 0x4217) { return status.rdmpy.byte(1); } if(addr == 0x4218) return status.joy1.byte(0); //JOY1L if(addr == 0x4219) return status.joy1.byte(1); //JOY1H if(addr == 0x421a) return status.joy2.byte(0); //JOY2L if(addr == 0x421b) return status.joy2.byte(1); //JOY2H if(addr == 0x421c) return status.joy3.byte(0); //JOY3L if(addr == 0x421d) return status.joy3.byte(1); //JOY3H if(addr == 0x421e) return status.joy4.byte(0); //JOY4L if(addr == 0x421f) return status.joy4.byte(1); //JOY4H return data; } auto CPU::dmaPortRead(uint24 addr, uint8 data) -> uint8 { auto& channel = this->channel[addr.bits(4,6)]; addr &= 0xff0f; //DMAPx if(addr == 0x4300) return ( channel.direction << 7 | channel.indirect << 6 | channel.unused << 5 | channel.reverse_transfer << 4 | channel.fixed_transfer << 3 | channel.transfer_mode << 0 ); //BBADx if(addr == 0x4301) return channel.dest_addr; //A1TxL if(addr == 0x4302) return channel.source_addr >> 0; //A1TxH if(addr == 0x4303) return channel.source_addr >> 8; //A1Bx if(addr == 0x4304) return channel.source_bank; //DASxL -- union { uint16 transfer_size; uint16 indirect_addr; }; if(addr == 0x4305) return channel.transfer_size >> 0; //DASxH -- union { uint16 transfer_size; uint16 indirect_addr; }; if(addr == 0x4306) return channel.transfer_size >> 8; //DASBx if(addr == 0x4307) return channel.indirect_bank; //A2AxL if(addr == 0x4308) return channel.hdma_addr >> 0; //A2AxH if(addr == 0x4309) return channel.hdma_addr >> 8; //NTRLx if(addr == 0x430a) return channel.line_counter; //??? if(addr == 0x430b || addr == 0x430f) return channel.unknown; return data; } auto CPU::apuPortWrite(uint24 addr, uint8 data) -> void { synchronizeSMP(); return portWrite(addr.bits(0,1), data); } auto CPU::cpuPortWrite(uint24 addr, uint8 data) -> void { addr &= 0xffff; //WMDATA if(addr == 0x2180) { bus.write(0x7e0000 | status.wram_addr++, data); } //WMADDL if(addr == 0x2181) { status.wram_addr.bits(0,7) = data; } //WMADDM if(addr == 0x2182) { status.wram_addr.bits(8,15) = data; } //WMADDH if(addr == 0x2183) { status.wram_addr.bit(16) = data.bit(0); } //JOYSER0 if(addr == 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)); } //NMITIMEN if(addr == 0x4200) { status.auto_joypad_poll = data.bit(0); nmitimenUpdate(data); } //WRIO if(addr == 0x4201) { if(status.pio.bit(7) && !data.bit(7)) ppu.latchCounters(); status.pio = data; } //WRMPYA if(addr == 0x4202) { status.wrmpya = data; } //WRMPYB if(addr == 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; } //WRDIVL if(addr == 0x4204) { status.wrdiva.byte(0) = data; } //WRDIVH if(addr == 0x4205) { status.wrdiva.byte(1) = data; } //WRDIVB if(addr == 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; } //HTIMEL if(addr == 0x4207) { status.hirq_pos.bits(0,7) = data; } //HTIMEH if(addr == 0x4208) { status.hirq_pos.bit(8) = data.bit(0); } //VTIMEL if(addr == 0x4209) { status.virq_pos.bits(0,7) = data; } //VTIMEH if(addr == 0x420a) { status.virq_pos.bit(8) = data; } //DMAEN if(addr == 0x420b) { for(auto n : range(8)) channel[n].dma_enabled = data.bit(n); if(data) status.dma_pending = true; } //HDMAEN if(addr == 0x420c) { for(auto n : range(8)) channel[n].hdma_enabled = data.bit(n); } //MEMSEL if(addr == 0x420d) { status.rom_speed = data.bit(0) ? 6 : 8; } } auto CPU::dmaPortWrite(uint24 addr, uint8 data) -> void { auto& channel = this->channel[addr.bits(4,6)]; addr &= 0xff0f; //DMAPx if(addr == 0x4300) { channel.direction = data & 0x80; channel.indirect = data & 0x40; channel.unused = data & 0x20; channel.reverse_transfer = data & 0x10; channel.fixed_transfer = data & 0x08; channel.transfer_mode = data & 0x07; } //DDBADx if(addr == 0x4301) { channel.dest_addr = data; } //A1TxL if(addr == 0x4302) { channel.source_addr = (channel.source_addr & 0xff00) | (data << 0); } //A1TxH if(addr == 0x4303) { channel.source_addr = (channel.source_addr & 0x00ff) | (data << 8); } //A1Bx if(addr == 0x4304) { channel.source_bank = data; } //DASxL -- union { uint16 transfer_size; uint16 indirect_addr; }; if(addr == 0x4305) { channel.transfer_size = (channel.transfer_size & 0xff00) | (data << 0); } //DASxH -- union { uint16 transfer_size; uint16 indirect_addr; }; if(addr == 0x4306) { channel.transfer_size = (channel.transfer_size & 0x00ff) | (data << 8); } //DASBx if(addr == 0x4307) { channel.indirect_bank = data; } //A2AxL if(addr == 0x4308) { channel.hdma_addr = (channel.hdma_addr & 0xff00) | (data << 0); } //A2AxH if(addr == 0x4309) { channel.hdma_addr = (channel.hdma_addr & 0x00ff) | (data << 8); } //NTRLx if(addr == 0x430a) { channel.line_counter = data; } //??? if(addr == 0x430b || addr == 0x430f) { channel.unknown = data; } }