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 &= (uint8)~0xc0; //up+down cannot be pressed simultaneously if((result & 0x30) == 0x30) result &= (uint8)~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; } }