Implement "strict mode".

This commit is contained in:
Christian Speckner 2024-08-11 14:53:53 +02:00
parent 0567eb18b0
commit 22af25e77c
4 changed files with 128 additions and 18 deletions

View File

@ -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<uInt8[]>(STACK_SIZE);
mySectionText = make_unique<uInt8[]>(TEXT_SIZE);
mySectionData = make_unique<uInt8[]>(DATA_SIZE);
mySectionRodata = make_unique<uInt8[]>(RODATA_SIZE);
mySectionTables = make_unique<uInt8[]>(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());
}
}
}

View File

@ -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;

View File

@ -546,9 +546,23 @@ string CortexM0::describeError(err_t err) {
CortexM0::CortexM0()
{
myPageMap = make_unique<uInt8[]>(PAGEMAP_SIZE);
resetMappings();
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CortexM0& CortexM0::resetMappings()
{
for (auto& region: myRegions) {
region.type = MemoryRegionType::unmapped;
region.access.emplace<std::monostate>();
}
myNextRegionIndex = 0;
std::fill_n(myPageMap.get(), PAGEMAP_SIZE, 0xff);
reset();
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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: