diff --git a/ares/gba/apu/io.cpp b/ares/gba/apu/io.cpp index 49a8518aca..b6c347e477 100644 --- a/ares/gba/apu/io.cpp +++ b/ares/gba/apu/io.cpp @@ -142,7 +142,7 @@ auto APU::readIO(n32 address) -> n8 { } - return cpu.pipeline.fetch.instruction.byte(address & 1); + return cpu.openBus.get(Byte, address); } auto APU::writeIO(n32 address, n8 data) -> void { diff --git a/ares/gba/cpu/bus.cpp b/ares/gba/cpu/bus.cpp index 7d62a62c21..237c459dd5 100644 --- a/ares/gba/cpu/bus.cpp +++ b/ares/gba/cpu/bus.cpp @@ -6,10 +6,11 @@ auto CPU::sleep() -> void { template inline auto CPU::getBus(u32 mode, n32 address) -> n32 { u32 clocks = _wait(mode, address); - u32 word = pipeline.fetch.instruction; + u32 word; if(address >= 0x1000'0000) { if constexpr(!UseDebugger) prefetchStep(clocks); + return openBus.get(mode, address); } else if(address & 0x0800'0000) { if(mode & Prefetch && wait.prefetch) { prefetchSync(address); @@ -33,8 +34,11 @@ inline auto CPU::getBus(u32 mode, n32 address) -> n32 { else if(address >= 0x0500'0000) word = ppu.readPRAM(mode, address); else if((address & 0xffff'fc00) == 0x0400'0000) word = bus.io[address & 0x3ff]->readIO(mode, address); else if((address & 0xff00'ffff) == 0x0400'0800) word = ((IO*)this)->readIO(mode, 0x0400'0800 | (address & 3)); + else return openBus.get(mode, address); } + openBus.set(mode, address, word); + return word; } @@ -69,6 +73,8 @@ auto CPU::set(u32 mode, n32 address, n32 word) -> void { else if((address & 0xffff'fc00) == 0x0400'0000) bus.io[address & 0x3ff]->writeIO(mode, address, word); else if((address & 0xff00'ffff) == 0x0400'0800) ((IO*)this)->writeIO(mode, 0x0400'0800 | (address & 3), word); } + + openBus.set(mode, address, word); } auto CPU::_wait(u32 mode, n32 address) -> u32 { @@ -97,3 +103,31 @@ auto CPU::_wait(u32 mode, n32 address) -> u32 { if(mode & Word) clocks += s; //16-bit bus requires two transfers for words return clocks; } + +auto CPU::OpenBus::get(u32 mode, n32 address) -> n32 { + if(mode & Word) address &= ~3; + if(mode & Half) address &= ~1; + return data >> (8 * (address & 3)); +} + +auto CPU::OpenBus::set(u32 mode, n32 address, n32 word) -> void { + if(address >> 24 == 0x3) { + //open bus from IWRAM only overwrites part of the last IWRAM value accessed + if(mode & Word) { + iwramData = word; + } else if(mode & Half) { + if(address & 2) { + iwramData.bit(16,31) = (n16)word; + } else { + iwramData.bit( 0,15) = (n16)word; + } + } else if(mode & Byte) { + iwramData.byte(address & 3) = (n8)word; + } + data = iwramData; + } else { + if(mode & Byte) word = (word & 0xff) * 0x01010101; + if(mode & Half) word = (word & 0xffff) * 0x00010001; + data = word; + } +} diff --git a/ares/gba/cpu/cpu.hpp b/ares/gba/cpu/cpu.hpp index 7afda8cf9f..8de209ace5 100644 --- a/ares/gba/cpu/cpu.hpp +++ b/ares/gba/cpu/cpu.hpp @@ -227,6 +227,13 @@ struct CPU : ARM7TDMI, Thread, IO { n4 unknown2; } memory; + struct OpenBus { + auto get(u32 mode, n32 address) -> n32; + auto set(u32 mode, n32 address, n32 word) -> void; + n32 data; + n32 iwramData; + } openBus; + struct { auto empty() const { return addr == load; } auto full() const { return load - addr == 16; } diff --git a/ares/gba/cpu/io.cpp b/ares/gba/cpu/io.cpp index af32a00028..7d476760d9 100644 --- a/ares/gba/cpu/io.cpp +++ b/ares/gba/cpu/io.cpp @@ -244,7 +244,7 @@ auto CPU::readIO(n32 address) -> n8 { } - return cpu.pipeline.fetch.instruction.byte(address & 1); + return cpu.openBus.get(Byte, address); } auto CPU::writeIO(n32 address, n8 data) -> void { diff --git a/ares/gba/cpu/serialization.cpp b/ares/gba/cpu/serialization.cpp index 465ca4a713..8e39635b61 100644 --- a/ares/gba/cpu/serialization.cpp +++ b/ares/gba/cpu/serialization.cpp @@ -100,6 +100,9 @@ auto CPU::serialize(serializer& s) -> void { s(memory.ewramWait); s(memory.unknown2); + s(openBus.data); + s(openBus.iwramData); + s(prefetch.slot); s(prefetch.addr); s(prefetch.load); diff --git a/ares/gba/memory/memory.cpp b/ares/gba/memory/memory.cpp index c6f84cf43f..2ff001d5b9 100644 --- a/ares/gba/memory/memory.cpp +++ b/ares/gba/memory/memory.cpp @@ -42,7 +42,7 @@ auto IO::writeIO(u32 mode, n32 address, n32 word) -> void { struct UnmappedIO : IO { auto readIO(n32 address) -> n8 override { - return cpu.pipeline.fetch.instruction.byte(address & 1); + return cpu.openBus.get(Byte, address); } auto writeIO(n32 address, n8 byte) -> void override { diff --git a/ares/gba/ppu/io.cpp b/ares/gba/ppu/io.cpp index 9b43a84b2d..5ae022698e 100644 --- a/ares/gba/ppu/io.cpp +++ b/ares/gba/ppu/io.cpp @@ -99,7 +99,7 @@ auto PPU::readIO(n32 address) -> n8 { } - return cpu.pipeline.fetch.instruction.byte(address & 1); + return cpu.openBus.get(Byte, address); } auto PPU::writeIO(n32 address, n8 data) -> void { diff --git a/ares/gba/system/bios.cpp b/ares/gba/system/bios.cpp index a7be18ddc4..4aeebab6b5 100644 --- a/ares/gba/system/bios.cpp +++ b/ares/gba/system/bios.cpp @@ -17,7 +17,7 @@ auto BIOS::readROM(n25 address) -> n32 { auto BIOS::read(u32 mode, n25 address) -> n32 { //unmapped memory if(address >= 0x0000'4000) { - return cpu.pipeline.fetch.instruction; //0000'4000-01ff'ffff + return cpu.openBus.get(mode, address); //0000'4000-01ff'ffff } //GBA BIOS is read-protected; only the BIOS itself can read its own memory diff --git a/ares/gba/system/serialization.cpp b/ares/gba/system/serialization.cpp index c1694006a4..0e173f5d17 100644 --- a/ares/gba/system/serialization.cpp +++ b/ares/gba/system/serialization.cpp @@ -1,4 +1,4 @@ -static const string SerializerVersion = "v141.1"; +static const string SerializerVersion = "v141.2"; auto System::serialize(bool synchronize) -> serializer { if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);