mirror of https://github.com/bsnes-emu/bsnes.git
346 lines
7.3 KiB
C++
346 lines
7.3 KiB
C++
|
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++, regs.mdr);
|
||
|
}
|
||
|
|
||
|
//JOYSER0
|
||
|
//7-2 = MDR
|
||
|
//1-0 = Joypad serial data
|
||
|
if(addr == 0x4016) {
|
||
|
uint8 r = regs.mdr & 0xfc;
|
||
|
r |= device.controllerPort1->data();
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
//JOYSER1
|
||
|
if(addr == 0x4017) {
|
||
|
//7-5 = MDR
|
||
|
//4-2 = Always 1 (pins are connected to GND)
|
||
|
//1-0 = Joypad serial data
|
||
|
uint8 r = (regs.mdr & 0xe0) | 0x1c;
|
||
|
r |= device.controllerPort2->data();
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
//RDNMI
|
||
|
if(addr == 0x4210) {
|
||
|
//7 = NMI acknowledge
|
||
|
//6-4 = MDR
|
||
|
//3-0 = CPU (5a22) version
|
||
|
uint8 r = (regs.mdr & 0x70);
|
||
|
r |= (uint8)(rdnmi()) << 7;
|
||
|
r |= (cpu_version & 0x0f);
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
//TIMEUP
|
||
|
if(addr == 0x4211) {
|
||
|
//7 = IRQ acknowledge
|
||
|
//6-0 = MDR
|
||
|
uint8 r = (regs.mdr & 0x7f);
|
||
|
r |= (uint8)(timeup()) << 7;
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
//HVBJOY
|
||
|
if(addr == 0x4212) {
|
||
|
//7 = VBLANK acknowledge
|
||
|
//6 = HBLANK acknowledge
|
||
|
//5-1 = MDR
|
||
|
//0 = JOYPAD acknowledge
|
||
|
uint8 r = (regs.mdr & 0x3e);
|
||
|
if(status.auto_joypad_active) r |= 0x01;
|
||
|
if(hcounter() <= 2 || hcounter() >= 1096) r |= 0x40; //hblank
|
||
|
if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) r |= 0x80; //vblank
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
//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.
|
||
|
device.controllerPort1->latch(data.bit(0));
|
||
|
device.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.latch_counters();
|
||
|
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;
|
||
|
}
|
||
|
}
|