diff --git a/ares/gba/cartridge/cartridge.cpp b/ares/gba/cartridge/cartridge.cpp index 051e65a869..ae775eb268 100644 --- a/ares/gba/cartridge/cartridge.cpp +++ b/ares/gba/cartridge/cartridge.cpp @@ -113,30 +113,36 @@ auto Cartridge::power() -> void { #define RAM_ANALYZE -auto Cartridge::read(u32 mode, n32 address) -> n32 { - if(address < 0x0e00'0000) { - if(has.eeprom && (address & eeprom.mask) == eeprom.test) return eeprom.read(); - return mrom.read(mode, address); - } else { - n32 word = 0xff; - if(has.sram) word = sram.read(address); - if(has.flash) word = flash.read(address); - word |= word << 8; - word |= word << 16; +auto Cartridge::readRom(u32 mode, n32 address) -> n32 { + if(mode & Word) { + n32 word = 0; + word |= readRom(mode & ~Word | Half, (address & ~3) + 0) << 0; + word |= readRom(mode & ~Word | Half, (address & ~3) + 2) << 16; return word; } + + if(has.eeprom && (address & eeprom.mask) == eeprom.test) return eeprom.read(); + return mrom.read(mode, address); } -auto Cartridge::write(u32 mode, n32 address, n32 word) -> void { - if(address < 0x0e00'0000) { - if(has.eeprom && (address & eeprom.mask) == eeprom.test) return eeprom.write(word & 1); - return mrom.write(mode, address, word); - } else { - if(mode & Word) word = word >> (8 * (address & 3)); - if(mode & Half) word = word >> (8 * (address & 1)); - if(has.sram) return sram.write(address, word); - if(has.flash) return flash.write(address, word); - } +auto Cartridge::readBackup(u32 mode, n32 address) -> n32 { + n32 word = 0xff; + if(has.sram) word = sram.read(address); + if(has.flash) word = flash.read(address); + word *= 0x01010101; + return word; +} + +auto Cartridge::writeRom(u32 mode, n32 address, n32 word) -> void { + if(has.eeprom && (address & eeprom.mask) == eeprom.test) return eeprom.write(word & 1); + return mrom.write(mode, address, word); +} + +auto Cartridge::writeBackup(u32 mode, n32 address, n32 word) -> void { + if(mode & Word) word = word >> (8 * (address & 3)); + if(mode & Half) word = word >> (8 * (address & 1)); + if(has.sram) return sram.write(address, word); + if(has.flash) return flash.write(address, word); } } diff --git a/ares/gba/cartridge/cartridge.hpp b/ares/gba/cartridge/cartridge.hpp index db63a63aa2..3ff1f75961 100644 --- a/ares/gba/cartridge/cartridge.hpp +++ b/ares/gba/cartridge/cartridge.hpp @@ -17,8 +17,10 @@ struct Cartridge { auto save() -> void; auto power() -> void; - auto read(u32 mode, n32 address) -> n32; - auto write(u32 mode, n32 address, n32 word) -> void; + auto readRom(u32 mode, n32 address) -> n32; + auto readBackup(u32 mode, n32 address) -> n32; + auto writeRom(u32 mode, n32 address, n32 word) -> void; + auto writeBackup(u32 mode, n32 address, n32 word) -> void; auto serialize(serializer&) -> void; diff --git a/ares/gba/cartridge/memory.hpp b/ares/gba/cartridge/memory.hpp index 0215655593..513b5255f2 100644 --- a/ares/gba/cartridge/memory.hpp +++ b/ares/gba/cartridge/memory.hpp @@ -1,7 +1,6 @@ struct MROM { //mrom.cpp - auto read(u32 mode, n32 address) -> n32; - auto readBus(u32 mode, n32 address) -> n16; + auto read(u32 mode, n32 address) -> n16; auto write(u32 mode, n32 address, n32 word) -> void; //serialization.cpp diff --git a/ares/gba/cartridge/mrom.cpp b/ares/gba/cartridge/mrom.cpp index e5e5bee1c2..2d0508a4c9 100644 --- a/ares/gba/cartridge/mrom.cpp +++ b/ares/gba/cartridge/mrom.cpp @@ -1,15 +1,4 @@ -auto Cartridge::MROM::read(u32 mode, n32 address) -> n32 { - if(mode & Word) { - n32 word = 0; - word |= readBus(mode & ~Word | Half, (address & ~3) + 0) << 0; - word |= readBus(mode & ~Word | Half, (address & ~3) + 2) << 16; - return word; - } - - return readBus(mode, address); -} - -auto Cartridge::MROM::readBus(u32 mode, n32 address) -> n16 { +auto Cartridge::MROM::read(u32 mode, n32 address) -> n16 { address &= 0x01ff'ffff; if(address >= size) { @@ -20,8 +9,7 @@ auto Cartridge::MROM::readBus(u32 mode, n32 address) -> n16 { if(mode & Half) address &= ~1; auto p = data + address; if(mode & Half) return p[0] << 0 | p[1] << 8; - if(mode & Byte) return p[0] << 0; - return 0; //should never occur + return p[0] << 0; } auto Cartridge::MROM::write(u32 mode, n32 address, n32 word) -> void { diff --git a/ares/gba/cpu/bus.cpp b/ares/gba/cpu/bus.cpp index cce9f7ddff..9af77919bb 100644 --- a/ares/gba/cpu/bus.cpp +++ b/ares/gba/cpu/bus.cpp @@ -43,19 +43,26 @@ inline auto CPU::getBus(u32 mode, n32 address) -> n32 { word = ppu.readOAM(mode, address); break; - case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: if(mode & Prefetch && wait.prefetch) { prefetchSync(address); prefetchStep(1); word = prefetchRead(); if(mode & Word) word |= prefetchRead() << 16; } else { + if(context.dmaActive) context.dmaRomAccess = true; if constexpr(!UseDebugger) prefetchReset(); if constexpr(!UseDebugger) step(waitCartridge(mode, address)); - word = cartridge.read(mode, address); + word = cartridge.readRom(mode, address); } break; + case 0x0e: case 0x0f: + if constexpr(!UseDebugger) prefetchReset(); + if constexpr(!UseDebugger) step(waitCartridge(mode, address)); + word = cartridge.readBackup(mode, address); + break; + default: if constexpr(!UseDebugger) prefetchStep(1); return openBus.get(mode, address); @@ -117,10 +124,17 @@ auto CPU::set(u32 mode, n32 address, n32 word) -> void { ppu.writeOAM(mode, address, word); break; - case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: + if(context.dmaActive) context.dmaRomAccess = true; + prefetchReset(); + step(waitCartridge(mode, address)); + cartridge.writeRom(mode, address, word); + break; + + case 0x0e: case 0x0f: prefetchReset(); step(waitCartridge(mode, address)); - cartridge.write(mode, address, word); + cartridge.writeBackup(mode, address, word); break; default: diff --git a/ares/gba/cpu/cpu.cpp b/ares/gba/cpu/cpu.cpp index 80eaead89b..c14ef195dd 100644 --- a/ares/gba/cpu/cpu.cpp +++ b/ares/gba/cpu/cpu.cpp @@ -58,11 +58,18 @@ auto CPU::main() -> void { auto CPU::dmaRun() -> void { if(!context.dmaActive && !context.busLocked) { context.dmaActive = true; - while(dma[0].run() | dma[1].run() | dma[2].run() | dma[3].run()); + while(true) { + if(dma[0].run()) continue; + if(dma[1].run()) continue; + if(dma[2].run()) continue; + if(dma[3].run()) continue; + break; + } if(context.dmaRan) { idle(); context.dmaRan = false; context.dmaRomAccess = false; + context.dmaActiveChannel = 0; //assign burst to a channel that cannot access ROM } context.dmaActive = false; } diff --git a/ares/gba/cpu/cpu.hpp b/ares/gba/cpu/cpu.hpp index 9aad197a54..7ede68567b 100644 --- a/ares/gba/cpu/cpu.hpp +++ b/ares/gba/cpu/cpu.hpp @@ -263,6 +263,7 @@ struct CPU : ARM7TDMI, Thread, IO { n1 dmaRan; n1 dmaRomAccess; n1 dmaActive; + n2 dmaActiveChannel; n1 timerLatched; n1 busLocked; } context; diff --git a/ares/gba/cpu/dma.cpp b/ares/gba/cpu/dma.cpp index 694f42963a..d2c6b493d2 100644 --- a/ares/gba/cpu/dma.cpp +++ b/ares/gba/cpu/dma.cpp @@ -10,40 +10,39 @@ inline auto CPU::DMA::run() -> bool { auto CPU::DMA::transfer() -> void { u32 seek = size ? 4 : 2; u32 mode = size ? Word : Half; - mode |= latch.length() == length() ? Nonsequential : Sequential; if(!cpu.context.dmaRan) { cpu.context.dmaRan = true; cpu.idle(); } + if(cpu.context.dmaActiveChannel != id) { + //channel has switched - new burst transfer must be started + cpu.context.dmaRomAccess = 0; + cpu.context.dmaActiveChannel = id; + } + if(latch.source() < 0x0200'0000) { cpu.idle(); //cannot access BIOS } else { n32 addr = latch.source(); if(mode & Word) addr &= ~3; if(mode & Half) addr &= ~1; - if(addr & 0x0800'0000) cpu.context.dmaRomAccess = true; - latch.data = cpu.get(mode, addr); + u32 sequential = Nonsequential; + if(cpu.context.dmaRomAccess) sequential = Sequential; + latch.data = cpu.get(mode | sequential, addr); if(mode & Half) latch.data |= latch.data << 16; } - if(mode & Nonsequential) { - if((source() & 0x0800'0000) && (target() & 0x0800'0000)) { - //ROM -> ROM transfer - mode |= Sequential; - mode ^= Nonsequential; - } - } - if(latch.target() < 0x0200'0000) { cpu.idle(); //cannot access BIOS } else { n32 addr = latch.target(); if(mode & Word) addr &= ~3; if(mode & Half) addr &= ~1; - if(addr & 0x0800'0000) cpu.context.dmaRomAccess = true; - cpu.set(mode, addr, latch.data >> (addr & 2) * 8); + u32 sequential = Nonsequential; + if(cpu.context.dmaRomAccess) sequential = Sequential; + cpu.set(mode | sequential, addr, latch.data >> (addr & 2) * 8); } switch(sourceMode) { diff --git a/ares/gba/cpu/prefetch.cpp b/ares/gba/cpu/prefetch.cpp index dd96fc338a..98b48b277c 100644 --- a/ares/gba/cpu/prefetch.cpp +++ b/ares/gba/cpu/prefetch.cpp @@ -11,11 +11,11 @@ auto CPU::prefetchSync(n32 address) -> void { auto CPU::prefetchStep(u32 clocks) -> void { step(clocks); - if(!wait.prefetch || context.dmaRomAccess || prefetch.stopped) return; + if(!wait.prefetch || prefetch.stopped) return; while(!prefetch.full() && clocks--) { if(--prefetch.wait) continue; - prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load); + prefetch.slot[prefetch.load >> 1 & 7] = cartridge.readRom(Half, prefetch.load); prefetch.load += 2; prefetch.wait = waitCartridge(Half | Sequential, prefetch.load); } diff --git a/ares/gba/cpu/serialization.cpp b/ares/gba/cpu/serialization.cpp index 6f2716a0d6..800da13659 100644 --- a/ares/gba/cpu/serialization.cpp +++ b/ares/gba/cpu/serialization.cpp @@ -116,6 +116,7 @@ auto CPU::serialize(serializer& s) -> void { s(context.dmaRan); s(context.dmaRomAccess); s(context.dmaActive); + s(context.dmaActiveChannel); s(context.timerLatched); s(context.busLocked); } diff --git a/ares/gba/system/serialization.cpp b/ares/gba/system/serialization.cpp index be00b4501b..cd4374a3f0 100644 --- a/ares/gba/system/serialization.cpp +++ b/ares/gba/system/serialization.cpp @@ -1,4 +1,4 @@ -static const string SerializerVersion = "v141.6"; +static const string SerializerVersion = "v142"; auto System::serialize(bool synchronize) -> serializer { if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);