auto CPU::keypadRead() -> uint4 { uint4 data = 0; if(r.ypadEnable) { data |= system.keypad.y1 << 0; data |= system.keypad.y2 << 1; data |= system.keypad.y3 << 2; data |= system.keypad.y4 << 3; } if(r.xpadEnable) { data |= system.keypad.x1 << 0; data |= system.keypad.x2 << 1; data |= system.keypad.x3 << 2; data |= system.keypad.x4 << 3; } if(r.buttonEnable) { data |= system.keypad.start << 1; data |= system.keypad.a << 2; data |= system.keypad.b << 3; } return data; } auto CPU::portRead(uint16 addr) -> uint8 { //DMA_SRC if(addr == 0x0040) return r.dmaSource.byte(0); if(addr == 0x0041) return r.dmaSource.byte(1); if(addr == 0x0042) return r.dmaSource.byte(2); //DMA_DST if(addr == 0x0044) return r.dmaTarget.byte(0); if(addr == 0x0045) return r.dmaTarget.byte(1); //DMA_LEN if(addr == 0x0046) return r.dmaLength.byte(0); if(addr == 0x0047) return r.dmaLength.byte(1); //DMA_CTRL if(addr == 0x0048) return r.dmaMode << 0 | r.dmaEnable << 7; //WSC_SYSTEM if(addr == 0x0062) return ( (system.model() == Model::SwanCrystal) << 7 ); //HW_FLAGS if(addr == 0x00a0) { bool model = system.model() != Model::WonderSwan; return ( 1 << 0 //0 = BIOS mapped; 1 = cartridge mapped | model << 1 //0 = WonderSwan; 1 = WonderSwan Color or SwanCrystal | 1 << 2 //0 = 8-bit bus width; 1 = 16-bit bus width | 1 << 7 //1 = built-in self-test passed ); } //INT_BASE if(addr == 0x00b0) return ( r.interruptBase | (system.model() == Model::WonderSwan ? 3 : 0) ); //SER_DATA if(addr == 0x00b1) return r.serialData; //INT_ENABLE if(addr == 0x00b2) return r.interruptEnable; //SER_STATUS if(addr == 0x00b3) return ( 1 << 2 //hack: always report send buffer as empty | r.serialBaudRate << 6 | r.serialEnable << 7 ); //INT_STATUS if(addr == 0x00b4) return r.interruptStatus; //KEYPAD if(addr == 0x00b5) return ( keypadRead() << 0 | r.ypadEnable << 4 | r.xpadEnable << 5 | r.buttonEnable << 6 ); return 0x00; } auto CPU::portWrite(uint16 addr, uint8 data) -> void { //DMA_SRC if(addr == 0x0040) r.dmaSource.byte(0) = data & ~1; if(addr == 0x0041) r.dmaSource.byte(1) = data; if(addr == 0x0042) r.dmaSource.byte(2) = data; //DMA_DST if(addr == 0x0044) r.dmaTarget.byte(0) = data & ~1; if(addr == 0x0045) r.dmaTarget.byte(1) = data; //DMA_LEN if(addr == 0x0046) r.dmaLength.byte(0) = data & ~1; if(addr == 0x0047) r.dmaLength.byte(1) = data; //DMA_CTRL if(addr == 0x0048) { r.dmaMode = data.bit(0); r.dmaEnable = data.bit(7); if(r.dmaEnable) dmaTransfer(); } //WSC_SYSTEM if(addr == 0x0062) { //todo: d0 = 1 powers off system } //HW_FLAGS if(addr == 0x00a0) { //todo: d2 (bus width) bit is writable; but ... it will do very bad things } //INT_BASE if(addr == 0x00b0) { r.interruptBase = (system.model() == Model::WonderSwan) ? data & ~7 : data & ~1; } //SER_DATA if(addr == 0x00b1) r.serialData = data; //INT_ENABLE if(addr == 0x00b2) { r.interruptEnable = data; r.interruptStatus &= ~r.interruptEnable; } //SER_STATUS if(addr == 0x00b3) { r.serialBaudRate = data.bit(6); r.serialEnable = data.bit(7); } //KEYPAD if(addr == 0x00b5) { r.ypadEnable = data.bit(4); r.xpadEnable = data.bit(5); r.buttonEnable = data.bit(6); } //INT_ACK if(addr == 0x00b6) { //acknowledge only edge-sensitive interrupts r.interruptStatus &= ~(data & 0b11110010); } }