Stub vcslib.

This commit is contained in:
Christian Speckner 2024-07-25 23:10:05 +02:00
parent 9e1c416f5d
commit 5a3ec4a8bc
4 changed files with 219 additions and 33 deletions

View File

@ -176,7 +176,7 @@ namespace {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5, CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5,
const Settings& settings) const Settings& settings)
: Cartridge(settings, md5), myImageSize(size) : Cartridge(settings, md5), myImageSize(size), myVcslibDelegate(*this)
{ {
myImage = make_unique<uInt8[]>(size); myImage = make_unique<uInt8[]>(size);
std::memcpy(myImage.get(), image.get(), size); std::memcpy(myImage.get(), image.get(), size);
@ -436,6 +436,137 @@ void CartridgeELF::BusTransactionQueue::push(const BusTransaction& transaction)
myQueue[(myQueueNext + myQueueSize++) % TRANSACTION_QUEUE_CAPACITY] = transaction; myQueue[(myQueueNext + myQueueSize++) % TRANSACTION_QUEUE_CAPACITY] = transaction;
} }
CortexM0::err_t CartridgeELF::VcslibDelegate::fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex)
{
switch (address) {
case ADDR_MEMSET:
FatalEmulationError::raise("unimplemented: memset");
case ADDR_MEMCPY:
FatalEmulationError::raise("unimplemented: memcpy");
case ADDR_VCS_LDA_FOR_BUS_STUFF2:
FatalEmulationError::raise("unimplemented: vcsLdaForBusStuff2");
case ADDR_VCS_LDX_FOR_BUS_STUFF2:
FatalEmulationError::raise("unimplemented: vcsLdxForBusStuff2");
case ADDR_VCS_LDY_FOR_BUS_STUFF2:
FatalEmulationError::raise("unimplemented: vcsLdyForBusStuff2");
case ADDR_VCS_WRITE3:
FatalEmulationError::raise("unimplemented: vcsWrite3");
case ADDR_VCS_JMP3:
FatalEmulationError::raise("unimplemented: vcsJump3");
case ADDR_VCS_NOP2:
FatalEmulationError::raise("unimplemented: vcsNop2");
case ADDR_VCS_NOP2N:
FatalEmulationError::raise("unimplemented: vcsNop2n");
case ADDR_VCS_WRITE5:
FatalEmulationError::raise("unimplemented: vcsWrite5");
case ADDR_VCS_WRITE6:
FatalEmulationError::raise("unimplemented: vcsWrite6");
case ADDR_VCS_LDA2:
FatalEmulationError::raise("unimplemented: vcsLda2");
case ADDR_VCS_LDX2:
FatalEmulationError::raise("unimplemented: vcsLdx2");
case ADDR_VCS_LDY2:
FatalEmulationError::raise("unimplemented: vcsLdy2");
case ADDR_VCS_SAX3:
FatalEmulationError::raise("unimplemented: vcsSax3");
case ADDR_VCS_STA3:
FatalEmulationError::raise("unimplemented: vcsSta3");
case ADDR_VCS_STX3:
FatalEmulationError::raise("unimplemented: vcsStx3");
case ADDR_VCS_STY3:
FatalEmulationError::raise("unimplemented: vcsSty3");
case ADDR_VCS_STA4:
FatalEmulationError::raise("unimplemented: vcsSta4");
case ADDR_VCS_STX4:
FatalEmulationError::raise("unimplemented: vcsStx4");
case ADDR_VCS_STY4:
FatalEmulationError::raise("unimplemented: vcsSty4");
case ADDR_VCS_COPY_OVERBLANK_TO_RIOT_RAM:
myCart.vcsCopyOverblankToRiotRam();
return returnFromStub(value, op);
case ADDR_VCS_START_OVERBLANK:
myCart.vcsStartOverblank();
return returnFromStub(value, op);
case ADDR_VCS_END_OVERBLANK:
FatalEmulationError::raise("unimplemented: vcsEndOverblank");
case ADDR_VCS_READ4:
FatalEmulationError::raise("unimplemented: vcsRead4");
case ADDR_RANDINT:
FatalEmulationError::raise("unimplemented: randint ");
case ADDR_VCS_TXS2:
FatalEmulationError::raise("unimplemented: vcsTx2");
case ADDR_VCS_JSR6:
FatalEmulationError::raise("unimplemented: vcsJsr6");
case ADDR_VCS_PHA3:
FatalEmulationError::raise("unimplemented: vcsPha3");
case ADDR_VCS_PHP3:
FatalEmulationError::raise("unimplemented: vcsPph3");
case ADDR_VCS_PLA4:
FatalEmulationError::raise("unimplemented: vcsPla4");
case ADDR_VCS_PLP4:
FatalEmulationError::raise("unimplemented: vcsPlp4");
case ADDR_VCS_PLA4_EX:
FatalEmulationError::raise("unimplemented: vcsPla4Ex");
case ADDR_VCS_PLP4_EX:
FatalEmulationError::raise("unimplemented: vcsPlp4Ex");
case ADDR_VCS_JMP_TO_RAM3:
FatalEmulationError::raise("unimplemented: vcsJmpToRam3");
case ADDR_VCS_WAIT_FOR_ADDRESS:
FatalEmulationError::raise("unimplemented: vcsWaitForAddress");
case ADDR_INJECT_DMA_DATA:
FatalEmulationError::raise("unimplemented: vcsInjectDmaData");
default:
return CortexM0::errIntrinsic(CortexM0::ERR_UNMAPPED_FETCH16, address);
}
}
CortexM0::err_t CartridgeELF::VcslibDelegate::returnFromStub(uInt16& value, uInt8& op)
{
constexpr uInt16 BX_LR = 0x7047;
value = BX_LR;
op = CortexM0::decodeInstructionWord(BX_LR);
return CortexM0::ERR_NONE;
}
void CartridgeELF::parseAndLinkElf() void CartridgeELF::parseAndLinkElf()
{ {
ElfParser elfParser; ElfParser elfParser;
@ -502,7 +633,9 @@ void CartridgeELF::setupMemoryMap()
.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, true, 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, true, mySectionTables.get())
.mapRegionDelegate(ADDR_STUB_BASE / CortexM0::PAGE_SIZE,
STUB_SIZE / CortexM0::PAGE_SIZE, true, &myVcslibDelegate);
} }

View File

@ -106,6 +106,21 @@ class CartridgeELF: public Cartridge {
uInt16 myNextInjectAddress{0}; uInt16 myNextInjectAddress{0};
}; };
class VcslibDelegate: public CortexM0::BusTransactionDelegate {
public:
VcslibDelegate(CartridgeELF& cart) : myCart(cart) {}
CortexM0::err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) override;
private:
CortexM0::err_t returnFromStub(uInt16& value, uInt8& op);
private:
CartridgeELF& myCart;
};
friend VcslibDelegate;
private: private:
void parseAndLinkElf(); void parseAndLinkElf();
void setupMemoryMap(); void setupMemoryMap();
@ -132,6 +147,8 @@ class CartridgeELF: public Cartridge {
unique_ptr<uInt8[]> mySectionData; unique_ptr<uInt8[]> mySectionData;
unique_ptr<uInt8[]> mySectionRodata; unique_ptr<uInt8[]> mySectionRodata;
unique_ptr<uInt8[]> mySectionTables; unique_ptr<uInt8[]> mySectionTables;
VcslibDelegate myVcslibDelegate;
}; };
#endif // CARTRIDGE_ELF #endif // CARTRIDGE_ELF

View File

@ -397,10 +397,40 @@ namespace {
} }
} }
CortexM0::err_t CortexM0::BusTransactionDelegate::read32(uInt32 address, uInt32& value, CortexM0& cortex)
{
return errIntrinsic(ERR_UNMAPPED_READ32, address);
}
CortexM0::err_t CortexM0::BusTransactionDelegate::read16(uInt32 address, uInt16& value, CortexM0& cortex)
{
return errIntrinsic(ERR_UNMAPPED_READ16, address);
}
CortexM0::err_t CortexM0::BusTransactionDelegate::read8(uInt32 address, uInt8& value, CortexM0& cortex)
{
return errIntrinsic(ERR_UNMAPPED_READ8, address);
}
CortexM0::err_t CortexM0::BusTransactionDelegate::write32(uInt32 address, uInt32 value, CortexM0& cortex)
{
return errIntrinsic(ERR_UNMAPPED_WRITE32, address);
}
CortexM0::err_t CortexM0::BusTransactionDelegate::write16(uInt32 address, uInt16 value, CortexM0& cortex)
{
return errIntrinsic(ERR_UNMAPPED_WRITE16, address);
}
CortexM0::err_t CortexM0::BusTransactionDelegate::write8(uInt32 address, uInt8 value, CortexM0& cortex)
{
return errIntrinsic(ERR_UNMAPPED_WRITE8, address);
}
CortexM0::err_t CortexM0::BusTransactionDelegate::fetch16( CortexM0::err_t CortexM0::BusTransactionDelegate::fetch16(
uInt32 address, uInt16& value, uInt8& op uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex
) { ) {
const err_t err = read16(address, value); const err_t err = read16(address, value, cortex);
if (err) return err; if (err) return err;
op = decodeInstructionWord(value); op = decodeInstructionWord(value);
@ -537,7 +567,7 @@ CortexM0::err_t CortexM0::read32(uInt32 address, uInt32& value)
switch (region.type) { switch (region.type) {
case MemoryRegionType::delegate: case MemoryRegionType::delegate:
return region.access.delegate->read32(address, value); return region.access.delegate->read32(address, value, *this);
case MemoryRegionType::directCode: case MemoryRegionType::directCode:
value = READ32(region.access.accessCode.backingStore, address - region.base); value = READ32(region.access.accessCode.backingStore, address - region.base);
@ -549,7 +579,7 @@ CortexM0::err_t CortexM0::read32(uInt32 address, uInt32& value)
default: default:
return myDefaultDelegate ? return myDefaultDelegate ?
myDefaultDelegate->read32(address, value) : errIntrinsic(ERR_UNMAPPED_ACCESS, address); myDefaultDelegate->read32(address, value, *this) : errIntrinsic(ERR_UNMAPPED_READ32, address);
} }
} }
@ -561,7 +591,7 @@ CortexM0::err_t CortexM0::read16(uInt32 address, uInt16& value)
switch (region.type) { switch (region.type) {
case MemoryRegionType::delegate: case MemoryRegionType::delegate:
return region.access.delegate->read16(address, value); return region.access.delegate->read16(address, value, *this);
case MemoryRegionType::directCode: case MemoryRegionType::directCode:
value = READ16(region.access.accessCode.backingStore, address - region.base); value = READ16(region.access.accessCode.backingStore, address - region.base);
@ -573,7 +603,7 @@ CortexM0::err_t CortexM0::read16(uInt32 address, uInt16& value)
default: default:
return myDefaultDelegate ? return myDefaultDelegate ?
myDefaultDelegate->read16(address, value) : errIntrinsic(ERR_UNMAPPED_ACCESS, address); myDefaultDelegate->read16(address, value, *this) : errIntrinsic(ERR_UNMAPPED_READ16, address);
} }
} }
@ -583,7 +613,7 @@ CortexM0::err_t CortexM0::read8(uInt32 address, uInt8& value)
switch (region.type) { switch (region.type) {
case MemoryRegionType::delegate: case MemoryRegionType::delegate:
return region.access.delegate->read8(address, value); return region.access.delegate->read8(address, value, *this);
case MemoryRegionType::directCode: case MemoryRegionType::directCode:
value = region.access.accessCode.backingStore[address - region.base]; value = region.access.accessCode.backingStore[address - region.base];
@ -595,7 +625,7 @@ CortexM0::err_t CortexM0::read8(uInt32 address, uInt8& value)
default: default:
return myDefaultDelegate ? return myDefaultDelegate ?
myDefaultDelegate->read8(address, value) : errIntrinsic(ERR_UNMAPPED_ACCESS, address); myDefaultDelegate->read8(address, value, *this) : errIntrinsic(ERR_UNMAPPED_READ8, address);
} }
} }
@ -608,7 +638,7 @@ CortexM0::err_t CortexM0::write32(uInt32 address, uInt32 value)
switch (region.type) { switch (region.type) {
case MemoryRegionType::delegate: case MemoryRegionType::delegate:
return region.access.delegate->write32(address, value); return region.access.delegate->write32(address, value, *this);
case MemoryRegionType::directCode: case MemoryRegionType::directCode:
WRITE32(region.access.accessCode.backingStore, address - region.base, value); WRITE32(region.access.accessCode.backingStore, address - region.base, value);
@ -620,7 +650,7 @@ CortexM0::err_t CortexM0::write32(uInt32 address, uInt32 value)
default: default:
return myDefaultDelegate ? return myDefaultDelegate ?
myDefaultDelegate->write32(address, value) : errIntrinsic(ERR_UNMAPPED_ACCESS, address); myDefaultDelegate->write32(address, value, *this) : errIntrinsic(ERR_UNMAPPED_WRITE32, address);
} }
} }
@ -633,7 +663,7 @@ CortexM0::err_t CortexM0::write16(uInt32 address, uInt16 value)
switch (region.type) { switch (region.type) {
case MemoryRegionType::delegate: case MemoryRegionType::delegate:
return region.access.delegate->write16(address, value); return region.access.delegate->write16(address, value, *this);
case MemoryRegionType::directCode: { case MemoryRegionType::directCode: {
const uInt32 offset = address - region.base; const uInt32 offset = address - region.base;
@ -650,7 +680,7 @@ CortexM0::err_t CortexM0::write16(uInt32 address, uInt16 value)
default: default:
return myDefaultDelegate ? return myDefaultDelegate ?
myDefaultDelegate->write16(address, value) : errIntrinsic(ERR_UNMAPPED_ACCESS, address); myDefaultDelegate->write16(address, value, *this) : errIntrinsic(ERR_UNMAPPED_WRITE16, address);
} }
} }
@ -663,7 +693,7 @@ CortexM0::err_t CortexM0::write8(uInt32 address, uInt8 value)
switch (region.type) { switch (region.type) {
case MemoryRegionType::delegate: case MemoryRegionType::delegate:
return region.access.delegate->write8(address, value); return region.access.delegate->write8(address, value, *this);
case MemoryRegionType::directCode: { case MemoryRegionType::directCode: {
const uInt32 offset = address - region.base; const uInt32 offset = address - region.base;
@ -680,7 +710,7 @@ CortexM0::err_t CortexM0::write8(uInt32 address, uInt8 value)
default: default:
return myDefaultDelegate ? return myDefaultDelegate ?
myDefaultDelegate->write8(address, value) : errIntrinsic(ERR_UNMAPPED_ACCESS, address); myDefaultDelegate->write8(address, value, *this) : errIntrinsic(ERR_UNMAPPED_WRITE8, address);
} }
} }
@ -692,7 +722,7 @@ CortexM0::err_t CortexM0::fetch16(uInt32 address, uInt16& value, uInt8& op)
switch (region.type) { switch (region.type) {
case MemoryRegionType::delegate: case MemoryRegionType::delegate:
return region.access.delegate->fetch16(address, value, op); return region.access.delegate->fetch16(address, value, op, *this);
case MemoryRegionType::directCode: { case MemoryRegionType::directCode: {
const uInt32 offset = address - region.base; const uInt32 offset = address - region.base;
@ -711,7 +741,7 @@ CortexM0::err_t CortexM0::fetch16(uInt32 address, uInt16& value, uInt8& op)
default: default:
return myDefaultDelegate ? return myDefaultDelegate ?
myDefaultDelegate->fetch16(address, value, op) : errIntrinsic(ERR_UNMAPPED_ACCESS, address); myDefaultDelegate->fetch16(address, value, op, *this) : errIntrinsic(ERR_UNMAPPED_FETCH16, address);
} }
} }

View File

@ -34,28 +34,34 @@ class CortexM0
public: public:
virtual ~BusTransactionDelegate() = default; virtual ~BusTransactionDelegate() = default;
virtual err_t read32(uInt32 address, uInt32& value) = 0; virtual err_t read32(uInt32 address, uInt32& value, CortexM0& cortex);
virtual err_t read16(uInt32 address, uInt16& value) = 0; virtual err_t read16(uInt32 address, uInt16& value, CortexM0& cortex);
virtual err_t read8(uInt32 address, uInt8& value) = 0; virtual err_t read8(uInt32 address, uInt8& value, CortexM0& cortex);
virtual err_t write32(uInt32 address, uInt32 value) = 0; virtual err_t write32(uInt32 address, uInt32 value, CortexM0& cortex);
virtual err_t write16(uInt32 address, uInt16 value) = 0; virtual err_t write16(uInt32 address, uInt16 value, CortexM0& cortex);
virtual err_t write8(uInt32 address, uInt8 value) = 0; virtual err_t write8(uInt32 address, uInt8 value, CortexM0& cortex);
virtual err_t fetch16(uInt32 address, uInt16& value, uInt8& op); virtual err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex);
}; };
static constexpr uInt32 PAGE_SIZE = 4096; static constexpr uInt32 PAGE_SIZE = 4096;
static constexpr err_t ERR_NONE = 0; static constexpr err_t ERR_NONE = 0;
static constexpr err_t ERR_UNMAPPED_ACCESS = 1; static constexpr err_t ERR_UNMAPPED_READ32 = 1;
static constexpr err_t ERR_WRITE_ACCESS_DENIED = 2; static constexpr err_t ERR_UNMAPPED_READ16 = 2;
static constexpr err_t ERR_ACCESS_ALIGNMENT_FAULT = 3; static constexpr err_t ERR_UNMAPPED_READ8 = 3;
static constexpr err_t ERR_BKPT = 4; static constexpr err_t ERR_UNMAPPED_WRITE32 = 4;
static constexpr err_t ERR_INVALID_OPERATING_MODE = 5; static constexpr err_t ERR_UNMAPPED_WRITE16 = 5;
static constexpr err_t ERR_UNIMPLEMENTED_INST = 6; static constexpr err_t ERR_UNMAPPED_WRITE8 = 6;
static constexpr err_t ERR_SWI = 7; static constexpr err_t ERR_UNMAPPED_FETCH16 = 7;
static constexpr err_t ERR_UNDEFINED_INST = 8; static constexpr err_t ERR_WRITE_ACCESS_DENIED = 8;
static constexpr err_t ERR_ACCESS_ALIGNMENT_FAULT = 9;
static constexpr err_t ERR_BKPT = 10;
static constexpr err_t ERR_INVALID_OPERATING_MODE = 11;
static constexpr err_t ERR_UNIMPLEMENTED_INST = 12;
static constexpr err_t ERR_SWI = 13;
static constexpr err_t ERR_UNDEFINED_INST = 14;
static inline bool isErrCustom(err_t err) { static inline bool isErrCustom(err_t err) {
return (err & 0xff) == 0; return (err & 0xff) == 0;