diff --git a/src/emucore/CartELF.cxx b/src/emucore/CartELF.cxx index e36ffc551..652befaae 100644 --- a/src/emucore/CartELF.cxx +++ b/src/emucore/CartELF.cxx @@ -330,7 +330,9 @@ inline uInt8 CartridgeELF::driveBus(uInt16 address, uInt8 value) if (myIsBusDriven) value |= myDriveBusValue; - runArm(); + myVcsLib.updateBus(address, value); + + if (!myVcsLib.isSuspended()) runArm(); return value; } @@ -493,7 +495,7 @@ void CartridgeELF::runArm() const CortexM0::err_t err = myCortexEmu.run(cyclesGoal, cycles); - if (err && (CortexM0::getErrCustom(err) != ERR_QUEUE_FULL)) + if (err && (CortexM0::getErrCustom(err) != ERR_STOP_EXECUTION)) FatalEmulationError::raise("error executing ARM code: " + CortexM0::describeError(err)); } diff --git a/src/emucore/elf/ElfEnvironment.hxx b/src/emucore/elf/ElfEnvironment.hxx index e69927644..b45730fb3 100644 --- a/src/emucore/elf/ElfEnvironment.hxx +++ b/src/emucore/elf/ElfEnvironment.hxx @@ -112,7 +112,8 @@ namespace elfEnvironment { constexpr uInt32 RETURN_ADDR_MAIN = 0xffffdead; - constexpr uInt32 ERR_QUEUE_FULL = 1; + constexpr uInt32 ERR_STOP_EXECUTION = 1; + constexpr uInt32 QUEUE_SIZE_LIMIT = 10; enum class Palette: uInt8 {pal, ntsc}; diff --git a/src/emucore/elf/VcsLib.cxx b/src/emucore/elf/VcsLib.cxx index 03b07f075..444d3f11c 100644 --- a/src/emucore/elf/VcsLib.cxx +++ b/src/emucore/elf/VcsLib.cxx @@ -60,6 +60,10 @@ VcsLib::VcsLib(BusTransactionQueue& transactionQueue) : myTransactionQueue(trans void VcsLib::reset() { myStuffMaskA = myStuffMaskX = myStuffMaskY = 0x00; + myIsWaitingForRead = false; + myWaitingForReadAddress = 0; + myCurrentAddress = 0; + myCurrentValue = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -124,7 +128,7 @@ CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, Cortex CortexM0::err_t err; if (myTransactionQueue.size() >= elfEnvironment::QUEUE_SIZE_LIMIT) - return CortexM0::errCustom(ERR_QUEUE_FULL); + return CortexM0::errCustom(ERR_STOP_EXECUTION); myTransactionQueue.setTimestamp(cortex.getCycles()); @@ -170,7 +174,8 @@ CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, Cortex return returnFromStub(value, op); case ADDR_VCS_NOP2: - FatalEmulationError::raise("unimplemented: vcsNop2"); + myTransactionQueue.injectROM(0xea); + return returnFromStub(value, op); case ADDR_VCS_NOP2N: vcsNop2n(cortex.getRegister(0)); @@ -234,7 +239,28 @@ CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, Cortex return returnFromStub(value, op); case ADDR_VCS_READ4: - FatalEmulationError::raise("unimplemented: vcsRead4"); + if (myIsWaitingForRead) { + if (myTransactionQueue.size() > 0 || myCurrentAddress != myWaitingForReadAddress) + return CortexM0::errCustom(ERR_STOP_EXECUTION); + + myIsWaitingForRead = false; + cortex.setRegister(0, myCurrentValue); + + return returnFromStub(value, op); + } else { + arg = cortex.getRegister(0); + + myIsWaitingForRead = true; + myWaitingForReadAddress = arg; + + myTransactionQueue + .injectROM(0xad) + .injectROM(arg & 0xff) + .injectROM(arg >> 8) + .yield(arg); + + return CortexM0::errCustom(ERR_STOP_EXECUTION); + } case ADDR_RANDINT: FatalEmulationError::raise("unimplemented: randint "); @@ -277,6 +303,12 @@ CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, Cortex } } +void VcsLib::updateBus(uInt16 address, uInt8 value) +{ + myCurrentAddress = address; + myCurrentValue = value; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CortexM0::err_t VcsLib::returnFromStub(uInt16& value, uInt8& op) { diff --git a/src/emucore/elf/VcsLib.hxx b/src/emucore/elf/VcsLib.hxx index e40c3f27f..bcf77e2ac 100644 --- a/src/emucore/elf/VcsLib.hxx +++ b/src/emucore/elf/VcsLib.hxx @@ -20,8 +20,7 @@ #include "bspf.hxx" #include "CortexM0.hxx" - -class BusTransactionQueue; +#include "BusTransactionQueue.hxx" class VcsLib: public CortexM0::BusTransactionDelegate { public: @@ -31,6 +30,13 @@ class VcsLib: public CortexM0::BusTransactionDelegate { CortexM0::err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) override; + void updateBus(uInt16 address, uInt8 value); + + inline bool isSuspended() const { + return + myIsWaitingForRead && (myTransactionQueue.size() > 0 || (myWaitingForReadAddress != myCurrentAddress)); + } + void vcsWrite5(uInt8 zpAddress, uInt8 value); void vcsCopyOverblankToRiotRam(); void vcsStartOverblank(); @@ -48,6 +54,12 @@ class VcsLib: public CortexM0::BusTransactionDelegate { uInt8 myStuffMaskX{0x00}; uInt8 myStuffMaskY{0x00}; + bool myIsWaitingForRead{false}; + uInt16 myWaitingForReadAddress{0}; + + uInt16 myCurrentAddress{0}; + uInt8 myCurrentValue{0}; + private: VcsLib(const VcsLib&) = delete; VcsLib(VcsLib&&) = delete;