mirror of https://github.com/bsnes-emu/bsnes.git
322 lines
10 KiB
C++
322 lines
10 KiB
C++
auto CPU::read(uint32 addr) -> uint8 {
|
|
uint8 result = 0;
|
|
|
|
switch(addr) {
|
|
|
|
//DMA0CNT_H
|
|
//DMA1CNT_H
|
|
//DMA2CNT_H
|
|
//DMA3CNT_H
|
|
case 0x040000ba: case 0x040000bb:
|
|
case 0x040000c6: case 0x040000c7:
|
|
case 0x040000d2: case 0x040000d3:
|
|
case 0x040000de: case 0x040000df: {
|
|
auto& dma = regs.dma[(addr - 0x040000ba) / 12];
|
|
unsigned shift = (addr & 1) * 8;
|
|
return dma.control >> shift;
|
|
}
|
|
|
|
//TM0CNT_L
|
|
//TM1CNT_L
|
|
//TM2CNT_L
|
|
//TM3CNT_L
|
|
case 0x04000100: case 0x04000101:
|
|
case 0x04000104: case 0x04000105:
|
|
case 0x04000108: case 0x04000109:
|
|
case 0x0400010c: case 0x0400010d: {
|
|
auto& timer = regs.timer[(addr >> 2) & 3];
|
|
unsigned shift = (addr & 1) * 8;
|
|
return timer.period >> shift;
|
|
}
|
|
|
|
//TIM0CNT_H
|
|
case 0x04000102: case 0x04000103:
|
|
case 0x04000106: case 0x04000107:
|
|
case 0x0400010a: case 0x0400010b:
|
|
case 0x0400010e: case 0x0400010f: {
|
|
auto& timer = regs.timer[(addr >> 2) & 3];
|
|
unsigned shift = (addr & 1) * 8;
|
|
return timer.control >> shift;
|
|
}
|
|
|
|
//SIOMULTI0 (SIODATA32_L)
|
|
//SIOMULTI1 (SIODATA32_H)
|
|
//SIOMULTI2
|
|
//SIOMULTI3
|
|
case 0x04000120: case 0x04000121:
|
|
case 0x04000122: case 0x04000123:
|
|
case 0x04000124: case 0x04000125:
|
|
case 0x04000126: case 0x04000127: {
|
|
if(auto data = player.read()) return data() >> ((addr & 3) << 3);
|
|
unsigned shift = (addr & 1) * 8;
|
|
auto& data = regs.serial.data[(addr >> 1) & 3];
|
|
return data >> shift;
|
|
}
|
|
|
|
//SIOCNT
|
|
case 0x04000128: return regs.serial.control >> 0;
|
|
case 0x04000129: return regs.serial.control >> 8;
|
|
|
|
//SIOMLT_SEND (SIODATA8)
|
|
case 0x0400012a: return regs.serial.data8;
|
|
case 0x0400012b: return 0u;
|
|
|
|
//KEYINPUT
|
|
case 0x04000130:
|
|
if(auto result = player.keyinput()) return result() >> 0;
|
|
for(unsigned n = 0; n < 8; n++) result |= interface->inputPoll(0, 0, n) << n;
|
|
if((result & 0xc0) == 0xc0) result &= ~0xc0; //up+down cannot be pressed simultaneously
|
|
if((result & 0x30) == 0x30) result &= ~0x30; //left+right cannot be pressed simultaneously
|
|
return result ^ 0xff;
|
|
case 0x04000131:
|
|
if(auto result = player.keyinput()) return result() >> 8;
|
|
result |= interface->inputPoll(0, 0, 8) << 0;
|
|
result |= interface->inputPoll(0, 0, 9) << 1;
|
|
return result ^ 0x03;
|
|
|
|
//KEYCNT
|
|
case 0x04000132: return regs.keypad.control >> 0;
|
|
case 0x04000133: return regs.keypad.control >> 8;
|
|
|
|
//RCNT
|
|
case 0x04000134: return regs.joybus.settings >> 0;
|
|
case 0x04000135: return regs.joybus.settings >> 8;
|
|
|
|
//JOYCNT
|
|
case 0x04000140: return regs.joybus.control >> 0;
|
|
case 0x04000141: return regs.joybus.control >> 8;
|
|
|
|
//JOY_RECV_L
|
|
//JOY_RECV_H
|
|
case 0x04000150: return regs.joybus.receive >> 0;
|
|
case 0x04000151: return regs.joybus.receive >> 8;
|
|
case 0x04000152: return regs.joybus.receive >> 16;
|
|
case 0x04000153: return regs.joybus.receive >> 24;
|
|
|
|
//JOY_TRANS_L
|
|
//JOY_TRANS_H
|
|
case 0x04000154: return regs.joybus.transmit >> 0;
|
|
case 0x04000155: return regs.joybus.transmit >> 8;
|
|
case 0x04000156: return regs.joybus.transmit >> 16;
|
|
case 0x04000157: return regs.joybus.transmit >> 24;
|
|
|
|
//JOYSTAT
|
|
case 0x04000158: return regs.joybus.status >> 0;
|
|
case 0x04000159: return regs.joybus.status >> 8;
|
|
|
|
//IE
|
|
case 0x04000200: return regs.irq.enable >> 0;
|
|
case 0x04000201: return regs.irq.enable >> 8;
|
|
|
|
//IF
|
|
case 0x04000202: return regs.irq.flag >> 0;
|
|
case 0x04000203: return regs.irq.flag >> 8;
|
|
|
|
//WAITCNT
|
|
case 0x04000204: return regs.wait.control >> 0;
|
|
case 0x04000205: return regs.wait.control >> 8;
|
|
|
|
//IME
|
|
case 0x04000208: return regs.ime;
|
|
case 0x04000209: return 0u;
|
|
|
|
//POSTFLG + HALTCNT
|
|
case 0x04000300: return regs.postboot;
|
|
case 0x04000301: return 0u;
|
|
|
|
//MEMCNT_L
|
|
case 0x04000800: return regs.memory.control >> 0;
|
|
case 0x04000801: return regs.memory.control >> 8;
|
|
|
|
//MEMCNT_H
|
|
case 0x04000802: return regs.memory.control >> 16;
|
|
case 0x04000803: return regs.memory.control >> 24;
|
|
|
|
}
|
|
|
|
return 0u;
|
|
}
|
|
|
|
auto CPU::write(uint32 addr, uint8 byte) -> void {
|
|
switch(addr) {
|
|
|
|
//DMA0SAD
|
|
//DMA1SAD
|
|
//DMA2SAD
|
|
//DMA3SAD
|
|
case 0x040000b0: case 0x040000b1: case 0x040000b2: case 0x040000b3:
|
|
case 0x040000bc: case 0x040000bd: case 0x040000be: case 0x040000bf:
|
|
case 0x040000c8: case 0x040000c9: case 0x040000ca: case 0x040000cb:
|
|
case 0x040000d4: case 0x040000d5: case 0x040000d6: case 0x040000d7: {
|
|
auto& dma = regs.dma[(addr - 0x040000b0) / 12];
|
|
unsigned shift = (addr & 3) * 8;
|
|
dma.source = (dma.source & ~(255 << shift)) | (byte << shift);
|
|
return;
|
|
}
|
|
|
|
//DMA0DAD
|
|
//DMA1DAD
|
|
//DMA2DAD
|
|
//DMA3DAD
|
|
case 0x040000b4: case 0x040000b5: case 0x040000b6: case 0x040000b7:
|
|
case 0x040000c0: case 0x040000c1: case 0x040000c2: case 0x040000c3:
|
|
case 0x040000cc: case 0x040000cd: case 0x040000ce: case 0x040000cf:
|
|
case 0x040000d8: case 0x040000d9: case 0x040000da: case 0x040000db: {
|
|
auto& dma = regs.dma[(addr - 0x040000b4) / 12];
|
|
unsigned shift = (addr & 3) * 8;
|
|
dma.target = (dma.target & ~(255 << shift)) | (byte << shift);
|
|
return;
|
|
}
|
|
|
|
//DMA0CNT_L
|
|
//DMA1CNT_L
|
|
//DMA2CNT_L
|
|
//DMA3CNT_L
|
|
case 0x040000b8: case 0x040000b9:
|
|
case 0x040000c4: case 0x040000c5:
|
|
case 0x040000d0: case 0x040000d1:
|
|
case 0x040000dc: case 0x040000dd: {
|
|
auto& dma = regs.dma[(addr - 0x040000b8) / 12];
|
|
unsigned shift = (addr & 1) * 8;
|
|
dma.length = (dma.length & ~(255 << shift)) | (byte << shift);
|
|
return;
|
|
}
|
|
|
|
//DMA0CNT_H
|
|
//DMA1CNT_H
|
|
//DMA2CNT_H
|
|
//DMA3CNT_H
|
|
case 0x040000ba: case 0x040000bb:
|
|
case 0x040000c6: case 0x040000c7:
|
|
case 0x040000d2: case 0x040000d3:
|
|
case 0x040000de: case 0x040000df: {
|
|
if(addr == 0x040000bb || addr == 0x040000c7 || addr == 0x040000d3) byte &= 0xf7; //gamepak DRQ valid for DMA3 only
|
|
auto& dma = regs.dma[(addr - 0x040000ba) / 12];
|
|
unsigned shift = (addr & 1) * 8;
|
|
bool enable = dma.control.enable;
|
|
dma.control = (dma.control & ~(255 << shift)) | (byte << shift);
|
|
if(enable == 0 && dma.control.enable) {
|
|
if(dma.control.timingmode == 0) dma.pending = true; //immediate transfer mode
|
|
dma.run.target = dma.target;
|
|
dma.run.source = dma.source;
|
|
dma.run.length = dma.length;
|
|
} else if(dma.control.enable == 0) {
|
|
dma.pending = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//TM0CNT_L
|
|
//TM1CNT_L
|
|
//TM2CNT_L
|
|
//TM3CNT_L
|
|
case 0x04000100: case 0x04000101:
|
|
case 0x04000104: case 0x04000105:
|
|
case 0x04000108: case 0x04000109:
|
|
case 0x0400010c: case 0x0400010d: {
|
|
auto& timer = regs.timer[(addr >> 2) & 3];
|
|
unsigned shift = (addr & 1) * 8;
|
|
timer.reload = (timer.reload & ~(255 << shift)) | (byte << shift);
|
|
return;
|
|
}
|
|
|
|
//TM0CNT_H
|
|
//TM1CNT_H
|
|
//TM2CNT_H
|
|
//TM3CNT_H
|
|
case 0x04000102:
|
|
case 0x04000106:
|
|
case 0x0400010a:
|
|
case 0x0400010e: {
|
|
auto& timer = regs.timer[(addr >> 2) & 3];
|
|
bool enable = timer.control.enable;
|
|
timer.control = byte;
|
|
if(enable == 0 && timer.control.enable == 1) {
|
|
timer.pending = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//SIOMULTI0 (SIODATA32_L)
|
|
//SIOMULTI1 (SIODATA32_H)
|
|
//SIOMULTI2
|
|
//SIOMULTI3
|
|
case 0x04000120: case 0x04000121:
|
|
case 0x04000122: case 0x04000123:
|
|
case 0x04000124: case 0x04000125:
|
|
case 0x04000126: case 0x04000127: {
|
|
player.write(byte, addr & 3);
|
|
auto& data = regs.serial.data[(addr >> 1) & 3];
|
|
unsigned shift = (addr & 1) * 8;
|
|
data = (data & ~(255 << shift)) | (byte << shift);
|
|
return;
|
|
}
|
|
|
|
//SIOCNT
|
|
case 0x04000128: regs.serial.control = (regs.serial.control & 0xff00) | (byte << 0); return;
|
|
case 0x04000129: regs.serial.control = (regs.serial.control & 0x00ff) | (byte << 8); return;
|
|
|
|
//SIOMLT_SEND (SIODATA8)
|
|
case 0x0400012a: regs.serial.data8 = byte; return;
|
|
case 0x0400012b: return;
|
|
|
|
//KEYCNT
|
|
case 0x04000132: regs.keypad.control = (regs.keypad.control & 0xff00) | (byte << 0); return;
|
|
case 0x04000133: regs.keypad.control = (regs.keypad.control & 0x00ff) | (byte << 8); return;
|
|
|
|
//RCNT
|
|
case 0x04000134: regs.joybus.settings = (regs.joybus.settings & 0xff00) | (byte << 0); return;
|
|
case 0x04000135: regs.joybus.settings = (regs.joybus.settings & 0x00ff) | (byte << 8); return;
|
|
|
|
//JOYCNT
|
|
case 0x04000140: regs.joybus.control = (regs.joybus.control & 0xff00) | (byte << 0); return;
|
|
case 0x04000141: regs.joybus.control = (regs.joybus.control & 0x00ff) | (byte << 8); return;
|
|
|
|
//JOY_RECV_L
|
|
//JOY_RECV_H
|
|
case 0x04000150: regs.joybus.receive = (regs.joybus.receive & 0xffffff00) | (byte << 0); return;
|
|
case 0x04000151: regs.joybus.receive = (regs.joybus.receive & 0xffff00ff) | (byte << 8); return;
|
|
case 0x04000152: regs.joybus.receive = (regs.joybus.receive & 0xff00ffff) | (byte << 16); return;
|
|
case 0x04000153: regs.joybus.receive = (regs.joybus.receive & 0x00ffffff) | (byte << 24); return;
|
|
|
|
//JOY_TRANS_L
|
|
//JOY_TRANS_H
|
|
case 0x04000154: regs.joybus.transmit = (regs.joybus.transmit & 0xffffff00) | (byte << 0); return;
|
|
case 0x04000155: regs.joybus.transmit = (regs.joybus.transmit & 0xffff00ff) | (byte << 8); return;
|
|
case 0x04000156: regs.joybus.transmit = (regs.joybus.transmit & 0xff00ffff) | (byte << 16); return;
|
|
case 0x04000157: regs.joybus.transmit = (regs.joybus.transmit & 0x00ffffff) | (byte << 24); return;
|
|
|
|
//JOYSTAT
|
|
case 0x04000158: regs.joybus.status = (regs.joybus.status & 0xff00) | (byte << 0); return;
|
|
case 0x04000159: regs.joybus.status = (regs.joybus.status & 0x00ff) | (byte << 8); return;
|
|
|
|
//IE
|
|
case 0x04000200: regs.irq.enable = (regs.irq.enable & 0xff00) | (byte << 0); return;
|
|
case 0x04000201: regs.irq.enable = (regs.irq.enable & 0x00ff) | (byte << 8); return;
|
|
|
|
//IF
|
|
case 0x04000202: regs.irq.flag = regs.irq.flag & ~(byte << 0); return;
|
|
case 0x04000203: regs.irq.flag = regs.irq.flag & ~(byte << 8); return;
|
|
|
|
//WAITCNT
|
|
case 0x04000204: regs.wait.control = (regs.wait.control & 0xff00) | ((byte & 0xff) << 0); return;
|
|
case 0x04000205: regs.wait.control = (regs.wait.control & 0x00ff) | ((byte & 0x7f) << 8); return;
|
|
|
|
//IME
|
|
case 0x04000208: regs.ime = byte >> 0; return;
|
|
case 0x04000209: return;
|
|
|
|
//POSTFLG, HALTCNT
|
|
case 0x04000300: regs.postboot |= byte >> 0; return;
|
|
case 0x04000301: regs.mode = byte & 0x80 ? Registers::Mode::Stop : Registers::Mode::Halt; return;
|
|
|
|
//MEMCNT_L
|
|
//MEMCNT_H
|
|
case 0x04000800: regs.memory.control = (regs.memory.control & 0xffffff00) | (byte << 0); return;
|
|
case 0x04000801: regs.memory.control = (regs.memory.control & 0xffff00ff) | (byte << 8); return;
|
|
case 0x04000802: regs.memory.control = (regs.memory.control & 0xff00ffff) | (byte << 16); return;
|
|
case 0x04000803: regs.memory.control = (regs.memory.control & 0x00ffffff) | (byte << 24); return;
|
|
|
|
}
|
|
}
|