Skip to content

Commit

Permalink
gba: open bus improvements (#1706)
Browse files Browse the repository at this point in the history
Fixes a few issues relating to open bus emulation:

- Accounts for cases where the last memory access was not an instruction
fetch
- For most memory regions, 8-bit and 16-bit accesses should be mirrored
along bus (except in IWRAM, where only part of the open bus value gets
overwritten, and the rest is carried over from the last IWRAM access)
- Open bus read alignment was not being respected in all regions
  • Loading branch information
png183 authored Nov 28, 2024
1 parent de2d7d8 commit 3bd385e
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 7 deletions.
2 changes: 1 addition & 1 deletion ares/gba/apu/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
36 changes: 35 additions & 1 deletion ares/gba/cpu/bus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ auto CPU::sleep() -> void {
template <bool UseDebugger>
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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
}
7 changes: 7 additions & 0 deletions ares/gba/cpu/cpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
2 changes: 1 addition & 1 deletion ares/gba/cpu/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions ares/gba/cpu/serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion ares/gba/memory/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion ares/gba/ppu/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion ares/gba/system/bios.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion ares/gba/system/serialization.cpp
Original file line number Diff line number Diff line change
@@ -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);
Expand Down

0 comments on commit 3bd385e

Please sign in to comment.