diff --git a/src/emucore/CartELF.cxx b/src/emucore/CartELF.cxx index ba5f60dff..d1cec5790 100644 --- a/src/emucore/CartELF.cxx +++ b/src/emucore/CartELF.cxx @@ -26,6 +26,7 @@ #include "ElfEnvironment.hxx" #include "Logger.hxx" #include "Props.hxx" +#include "Settings.hxx" #include "exception/FatalEmulationError.hxx" #include "CartELF.hxx" @@ -220,7 +221,7 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5 createRomAccessArrays(0x1000); parseAndLinkElf(); - setupMemoryMap(); + allocationSections(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -229,6 +230,9 @@ CartridgeELF::~CartridgeELF() = default; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeELF::reset() { + const bool devMode = mySettings.getBool("dev.settings"); + const bool strictMode = devMode && mySettings.getBool("dev.thumb.trapfatal"); + std::fill_n(myLastPeekResult.get(), 0x1000, 0); myIsBusDriven = false; myDriveBusValue = 0; @@ -251,6 +255,7 @@ void CartridgeELF::reset() myLinker->getSegmentSize(ElfLinker::SegmentType::rodata)); std::memcpy(mySectionTables.get(), LOOKUP_TABLES, sizeof(LOOKUP_TABLES)); + setupMemoryMap(strictMode); myCortexEmu.reset(); myTransactionQueue @@ -349,20 +354,76 @@ uInt8 CartridgeELF::overdrivePoke(uInt16 address, uInt8 value) return driveBus(address, value); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CortexM0::err_t CartridgeELF::BusFallbackDelegate::fetch16( uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex ) { - return address == (RETURN_ADDR & ~1) - ? CortexM0::errCustom(ERR_RETURN) - : CortexM0::errIntrinsic(CortexM0::ERR_UNMAPPED_FETCH16, address); + if (address == (RETURN_ADDR & ~1)) return CortexM0::errCustom(ERR_RETURN); + + return handleError("fetch16", address, CortexM0::ERR_UNMAPPED_FETCH16, cortex); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CortexM0::err_t CartridgeELF::BusFallbackDelegate::read8(uInt32 address, uInt8& value, CortexM0& cortex) { - // TODO: remove this hack and replace it with a setting. - value = 0; - return 0; + return handleError("read8", address, CortexM0::ERR_UNMAPPED_READ8, cortex); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CortexM0::err_t CartridgeELF::BusFallbackDelegate::read16(uInt32 address, uInt16& value, CortexM0& cortex) +{ + return handleError("read16", address, CortexM0::ERR_UNMAPPED_READ16, cortex); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CortexM0::err_t CartridgeELF::BusFallbackDelegate::read32(uInt32 address, uInt32& value, CortexM0& cortex) +{ + return handleError("read32", address, CortexM0::ERR_UNMAPPED_READ32, cortex); +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CortexM0::err_t CartridgeELF::BusFallbackDelegate::write8(uInt32 address, uInt8 value, CortexM0& cortex) +{ + return handleError("write8", address, CortexM0::ERR_UNMAPPED_WRITE8, cortex); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CortexM0::err_t CartridgeELF::BusFallbackDelegate::write16(uInt32 address, uInt16 value, CortexM0& cortex) +{ + return handleError("write16", address, CortexM0::ERR_UNMAPPED_WRITE16, cortex); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CortexM0::err_t CartridgeELF::BusFallbackDelegate::write32(uInt32 address, uInt32 value, CortexM0& cortex) +{ + return handleError("write32", address, CortexM0::ERR_UNMAPPED_WRITE32, cortex); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeELF::BusFallbackDelegate::setErrorsAreFatal(bool fatal) +{ + myErrorsAreFatal = fatal; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CortexM0::err_t CartridgeELF::BusFallbackDelegate::handleError( + string_view accessType, uInt32 address, CortexM0::err_t err, CortexM0& cortex +) const { + if (myErrorsAreFatal) return CortexM0::errIntrinsic(err, address); + + stringstream s; + + s + << "invalid " << accessType << " access to 0x" + << std::hex << std::setw(8) << std::setfill('0') << address + << " (PC = 0x" + << std::hex << std::setw(8) << std::setfill('0') << cortex.getRegister(15) + << ")"; + + Logger::error(s.str()); + + return CortexM0::ERR_NONE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -438,28 +499,35 @@ void CartridgeELF::parseAndLinkElf() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::setupMemoryMap() +void CartridgeELF::allocationSections() { mySectionStack = make_unique(STACK_SIZE); mySectionText = make_unique(TEXT_SIZE); mySectionData = make_unique(DATA_SIZE); mySectionRodata = make_unique(RODATA_SIZE); mySectionTables = make_unique(TABLES_SIZE); +} +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void CartridgeELF::setupMemoryMap(bool strictMode) +{ myCortexEmu + .resetMappings() .mapRegionData(ADDR_STACK_BASE / CortexM0::PAGE_SIZE, STACK_SIZE / CortexM0::PAGE_SIZE, false, mySectionStack.get()) .mapRegionCode(ADDR_TEXT_BASE / CortexM0::PAGE_SIZE, - TEXT_SIZE / CortexM0::PAGE_SIZE, true, mySectionText.get()) + TEXT_SIZE / CortexM0::PAGE_SIZE, strictMode, mySectionText.get()) .mapRegionData(ADDR_DATA_BASE / CortexM0::PAGE_SIZE, DATA_SIZE / CortexM0::PAGE_SIZE, false, mySectionData.get()) .mapRegionData(ADDR_RODATA_BASE / CortexM0::PAGE_SIZE, - RODATA_SIZE / CortexM0::PAGE_SIZE, true, mySectionRodata.get()) + RODATA_SIZE / CortexM0::PAGE_SIZE, strictMode, mySectionRodata.get()) .mapRegionData(ADDR_TABLES_BASE / CortexM0::PAGE_SIZE, - TABLES_SIZE / CortexM0::PAGE_SIZE, true, mySectionTables.get()) + TABLES_SIZE / CortexM0::PAGE_SIZE, strictMode, mySectionTables.get()) .mapRegionDelegate(ADDR_STUB_BASE / CortexM0::PAGE_SIZE, STUB_SIZE / CortexM0::PAGE_SIZE, true, &myVcsLib) .mapDefault(&myFallbackDelegate); + + myFallbackDelegate.setErrorsAreFatal(strictMode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -572,7 +640,15 @@ void CartridgeELF::runArm() } } - if (CortexM0::getErrCustom(err) != ERR_STOP_EXECUTION) - FatalEmulationError::raise("error executing ARM code: " + CortexM0::describeError(err)); + if (CortexM0::getErrCustom(err) != ERR_STOP_EXECUTION) { + ostringstream s; + + s + << "error executing ARM code (PC = 0x" + << std::hex << std::setw(8) << std::setfill('0') << myCortexEmu.getRegister(15) + << "): " << CortexM0::describeError(err); + + FatalEmulationError::raise(s.str()); + } } } diff --git a/src/emucore/CartELF.hxx b/src/emucore/CartELF.hxx index 7d763038b..0082a6817 100644 --- a/src/emucore/CartELF.hxx +++ b/src/emucore/CartELF.hxx @@ -69,8 +69,24 @@ class CartridgeELF: public Cartridge { private: class BusFallbackDelegate: public CortexM0::BusTransactionDelegate { - CortexM0::err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) override; - CortexM0::err_t read8(uInt32 address, uInt8& value, CortexM0& cortex) override; + public: + CortexM0::err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) override; + CortexM0::err_t read8(uInt32 address, uInt8& value, CortexM0& cortex) override; + CortexM0::err_t read16(uInt32 address, uInt16& value, CortexM0& cortex) override; + CortexM0::err_t read32(uInt32 address, uInt32& value, CortexM0& cortex) override; + CortexM0::err_t write8(uInt32 address, uInt8 value, CortexM0& cortex) override; + CortexM0::err_t write16(uInt32 address, uInt16 value, CortexM0& cortex) override; + CortexM0::err_t write32(uInt32 address, uInt32 value, CortexM0& cortex) override; + + void setErrorsAreFatal(bool fatal); + + private: + CortexM0::err_t handleError( + string_view accessType, uInt32 address, CortexM0::err_t err, CortexM0& cortex + ) const; + + private: + bool myErrorsAreFatal{false}; }; enum class ExecutionStage: uInt8 { @@ -83,7 +99,8 @@ class CartridgeELF: public Cartridge { uInt8 driveBus(uInt16 address, uInt8 value); void parseAndLinkElf(); - void setupMemoryMap(); + void allocationSections(); + void setupMemoryMap(bool strictMode); uInt32 getCoreClock() const; diff --git a/src/emucore/CortexM0.cxx b/src/emucore/CortexM0.cxx index 961ec562a..53534c973 100644 --- a/src/emucore/CortexM0.cxx +++ b/src/emucore/CortexM0.cxx @@ -546,9 +546,23 @@ string CortexM0::describeError(err_t err) { CortexM0::CortexM0() { myPageMap = make_unique(PAGEMAP_SIZE); + + resetMappings(); + reset(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CortexM0& CortexM0::resetMappings() +{ + for (auto& region: myRegions) { + region.type = MemoryRegionType::unmapped; + region.access.emplace(); + } + + myNextRegionIndex = 0; std::fill_n(myPageMap.get(), PAGEMAP_SIZE, 0xff); - reset(); + return *this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CortexM0.hxx b/src/emucore/CortexM0.hxx index 6d0eb97a4..c7d79141d 100644 --- a/src/emucore/CortexM0.hxx +++ b/src/emucore/CortexM0.hxx @@ -103,6 +103,8 @@ class CortexM0 CortexM0(); ~CortexM0() = default; + CortexM0& resetMappings(); + CortexM0& mapRegionData(uInt32 pageBase, uInt32 pageCount, bool readOnly, uInt8* backingStore); @@ -166,7 +168,8 @@ class CortexM0 std::variant< MemoryRegionAccessData, // ::get<0>, directData MemoryRegionAccessCode, // ::get<1>, directCode - BusTransactionDelegate* // ::get<2>, delegate + BusTransactionDelegate*, // ::get<2>, delegate + std::monostate > access; private: