mirror of https://github.com/stella-emu/stella.git
Implement "strict mode".
This commit is contained in:
parent
0567eb18b0
commit
22af25e77c
|
@ -26,6 +26,7 @@
|
||||||
#include "ElfEnvironment.hxx"
|
#include "ElfEnvironment.hxx"
|
||||||
#include "Logger.hxx"
|
#include "Logger.hxx"
|
||||||
#include "Props.hxx"
|
#include "Props.hxx"
|
||||||
|
#include "Settings.hxx"
|
||||||
#include "exception/FatalEmulationError.hxx"
|
#include "exception/FatalEmulationError.hxx"
|
||||||
|
|
||||||
#include "CartELF.hxx"
|
#include "CartELF.hxx"
|
||||||
|
@ -220,7 +221,7 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5
|
||||||
createRomAccessArrays(0x1000);
|
createRomAccessArrays(0x1000);
|
||||||
|
|
||||||
parseAndLinkElf();
|
parseAndLinkElf();
|
||||||
setupMemoryMap();
|
allocationSections();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -229,6 +230,9 @@ CartridgeELF::~CartridgeELF() = default;
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeELF::reset()
|
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);
|
std::fill_n(myLastPeekResult.get(), 0x1000, 0);
|
||||||
myIsBusDriven = false;
|
myIsBusDriven = false;
|
||||||
myDriveBusValue = 0;
|
myDriveBusValue = 0;
|
||||||
|
@ -251,6 +255,7 @@ void CartridgeELF::reset()
|
||||||
myLinker->getSegmentSize(ElfLinker::SegmentType::rodata));
|
myLinker->getSegmentSize(ElfLinker::SegmentType::rodata));
|
||||||
std::memcpy(mySectionTables.get(), LOOKUP_TABLES, sizeof(LOOKUP_TABLES));
|
std::memcpy(mySectionTables.get(), LOOKUP_TABLES, sizeof(LOOKUP_TABLES));
|
||||||
|
|
||||||
|
setupMemoryMap(strictMode);
|
||||||
myCortexEmu.reset();
|
myCortexEmu.reset();
|
||||||
|
|
||||||
myTransactionQueue
|
myTransactionQueue
|
||||||
|
@ -349,20 +354,76 @@ uInt8 CartridgeELF::overdrivePoke(uInt16 address, uInt8 value)
|
||||||
return driveBus(address, value);
|
return driveBus(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
CortexM0::err_t CartridgeELF::BusFallbackDelegate::fetch16(
|
CortexM0::err_t CartridgeELF::BusFallbackDelegate::fetch16(
|
||||||
uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex
|
uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex
|
||||||
) {
|
) {
|
||||||
return address == (RETURN_ADDR & ~1)
|
if (address == (RETURN_ADDR & ~1)) return CortexM0::errCustom(ERR_RETURN);
|
||||||
? CortexM0::errCustom(ERR_RETURN)
|
|
||||||
: CortexM0::errIntrinsic(CortexM0::ERR_UNMAPPED_FETCH16, address);
|
return handleError("fetch16", address, CortexM0::ERR_UNMAPPED_FETCH16, cortex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
CortexM0::err_t CartridgeELF::BusFallbackDelegate::read8(uInt32 address, uInt8& value, CortexM0& cortex)
|
CortexM0::err_t CartridgeELF::BusFallbackDelegate::read8(uInt32 address, uInt8& value, CortexM0& cortex)
|
||||||
{
|
{
|
||||||
// TODO: remove this hack and replace it with a setting.
|
return handleError("read8", address, CortexM0::ERR_UNMAPPED_READ8, cortex);
|
||||||
value = 0;
|
}
|
||||||
return 0;
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
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);
|
mySectionStack = make_unique<uInt8[]>(STACK_SIZE);
|
||||||
mySectionText = make_unique<uInt8[]>(TEXT_SIZE);
|
mySectionText = make_unique<uInt8[]>(TEXT_SIZE);
|
||||||
mySectionData = make_unique<uInt8[]>(DATA_SIZE);
|
mySectionData = make_unique<uInt8[]>(DATA_SIZE);
|
||||||
mySectionRodata = make_unique<uInt8[]>(RODATA_SIZE);
|
mySectionRodata = make_unique<uInt8[]>(RODATA_SIZE);
|
||||||
mySectionTables = make_unique<uInt8[]>(TABLES_SIZE);
|
mySectionTables = make_unique<uInt8[]>(TABLES_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void CartridgeELF::setupMemoryMap(bool strictMode)
|
||||||
|
{
|
||||||
myCortexEmu
|
myCortexEmu
|
||||||
|
.resetMappings()
|
||||||
.mapRegionData(ADDR_STACK_BASE / CortexM0::PAGE_SIZE,
|
.mapRegionData(ADDR_STACK_BASE / CortexM0::PAGE_SIZE,
|
||||||
STACK_SIZE / CortexM0::PAGE_SIZE, false, mySectionStack.get())
|
STACK_SIZE / CortexM0::PAGE_SIZE, false, mySectionStack.get())
|
||||||
.mapRegionCode(ADDR_TEXT_BASE / CortexM0::PAGE_SIZE,
|
.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,
|
.mapRegionData(ADDR_DATA_BASE / CortexM0::PAGE_SIZE,
|
||||||
DATA_SIZE / CortexM0::PAGE_SIZE, false, mySectionData.get())
|
DATA_SIZE / CortexM0::PAGE_SIZE, false, mySectionData.get())
|
||||||
.mapRegionData(ADDR_RODATA_BASE / CortexM0::PAGE_SIZE,
|
.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,
|
.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,
|
.mapRegionDelegate(ADDR_STUB_BASE / CortexM0::PAGE_SIZE,
|
||||||
STUB_SIZE / CortexM0::PAGE_SIZE, true, &myVcsLib)
|
STUB_SIZE / CortexM0::PAGE_SIZE, true, &myVcsLib)
|
||||||
.mapDefault(&myFallbackDelegate);
|
.mapDefault(&myFallbackDelegate);
|
||||||
|
|
||||||
|
myFallbackDelegate.setErrorsAreFatal(strictMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -572,7 +640,15 @@ void CartridgeELF::runArm()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CortexM0::getErrCustom(err) != ERR_STOP_EXECUTION)
|
if (CortexM0::getErrCustom(err) != ERR_STOP_EXECUTION) {
|
||||||
FatalEmulationError::raise("error executing ARM code: " + CortexM0::describeError(err));
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,24 @@ class CartridgeELF: public Cartridge {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class BusFallbackDelegate: public CortexM0::BusTransactionDelegate {
|
class BusFallbackDelegate: public CortexM0::BusTransactionDelegate {
|
||||||
CortexM0::err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) override;
|
public:
|
||||||
CortexM0::err_t read8(uInt32 address, uInt8& value, CortexM0& cortex) override;
|
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 {
|
enum class ExecutionStage: uInt8 {
|
||||||
|
@ -83,7 +99,8 @@ class CartridgeELF: public Cartridge {
|
||||||
uInt8 driveBus(uInt16 address, uInt8 value);
|
uInt8 driveBus(uInt16 address, uInt8 value);
|
||||||
|
|
||||||
void parseAndLinkElf();
|
void parseAndLinkElf();
|
||||||
void setupMemoryMap();
|
void allocationSections();
|
||||||
|
void setupMemoryMap(bool strictMode);
|
||||||
|
|
||||||
uInt32 getCoreClock() const;
|
uInt32 getCoreClock() const;
|
||||||
|
|
||||||
|
|
|
@ -546,9 +546,23 @@ string CortexM0::describeError(err_t err) {
|
||||||
CortexM0::CortexM0()
|
CortexM0::CortexM0()
|
||||||
{
|
{
|
||||||
myPageMap = make_unique<uInt8[]>(PAGEMAP_SIZE);
|
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);
|
std::fill_n(myPageMap.get(), PAGEMAP_SIZE, 0xff);
|
||||||
|
|
||||||
reset();
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -103,6 +103,8 @@ class CortexM0
|
||||||
CortexM0();
|
CortexM0();
|
||||||
~CortexM0() = default;
|
~CortexM0() = default;
|
||||||
|
|
||||||
|
CortexM0& resetMappings();
|
||||||
|
|
||||||
CortexM0& mapRegionData(uInt32 pageBase, uInt32 pageCount,
|
CortexM0& mapRegionData(uInt32 pageBase, uInt32 pageCount,
|
||||||
bool readOnly, uInt8* backingStore);
|
bool readOnly, uInt8* backingStore);
|
||||||
|
|
||||||
|
@ -166,7 +168,8 @@ class CortexM0
|
||||||
std::variant<
|
std::variant<
|
||||||
MemoryRegionAccessData, // ::get<0>, directData
|
MemoryRegionAccessData, // ::get<0>, directData
|
||||||
MemoryRegionAccessCode, // ::get<1>, directCode
|
MemoryRegionAccessCode, // ::get<1>, directCode
|
||||||
BusTransactionDelegate* // ::get<2>, delegate
|
BusTransactionDelegate*, // ::get<2>, delegate
|
||||||
|
std::monostate
|
||||||
> access;
|
> access;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue