Start hooking up ARM: memory map.

This commit is contained in:
Christian Speckner 2024-07-24 23:17:17 +02:00
parent cbe3fb3308
commit 87f5c91c8f
4 changed files with 213 additions and 125 deletions

View File

@ -178,14 +178,6 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5
const Settings& settings)
: Cartridge(settings, md5), myImageSize(size)
{
ElfParser elfParser;
try {
elfParser.parse(image.get(), size);
} catch (ElfParser::ElfParseError& e) {
throw runtime_error("failed to initialize ELF: " + string(e.what()));
}
myImage = make_unique<uInt8[]>(size);
std::memcpy(myImage.get(), image.get(), size);
@ -194,37 +186,10 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5
createRomAccessArrays(0x1000);
#ifdef DUMP_ELF
dumpElf(elfParser);
#endif
parseAndLinkElf();
setupMemoryMap();
ElfLinker elfLinker(ADDR_TEXT_BASE, ADDR_DATA_BASE, ADDR_RODATA_BASE, elfParser);
try {
elfLinker.link(externalSymbols(Palette::ntsc));
} catch (const ElfLinker::ElfLinkError& e) {
throw runtime_error("failed to link ELF: " + string(e.what()));
}
try {
myArmEntrypoint = elfLinker.findRelocatedSymbol("elf_main").value;
} catch (const ElfLinker::ElfSymbolResolutionError& e) {
throw runtime_error("failed to resolve ARM entrypoint" + string(e.what()));
}
for (auto segment: {ElfLinker::SegmentType::text, ElfLinker::SegmentType::data, ElfLinker::SegmentType::rodata})
if (elfLinker.getSegmentSize(segment) > 0x00100000)
throw runtime_error("segment size exceeds limit");
#ifdef DUMP_ELF
dumpLinkage(elfParser, elfLinker);
cout
<< "\nARM entrypoint: 0x"
<< std::hex << std::setw(8) << std::setfill('0') << myArmEntrypoint << std::dec
<< '\n';
writeDebugBinary(elfLinker);
#endif
reset();
}
@ -245,6 +210,22 @@ void CartridgeELF::reset()
vcsCopyOverblankToRiotRam();
vcsStartOverblank();
std::memset(mySectionStack.get(), 0, STACK_SIZE);
std::memset(mySectionText.get(), 0, TEXT_SIZE);
std::memset(mySectionData.get(), 0, DATA_SIZE);
std::memset(mySectionRodata.get(), 0, RODATA_SIZE);
std::memset(mySectionTables.get(), 0, TABLES_SIZE);
std::memcpy(mySectionText.get(), myLinker->getSegmentData(ElfLinker::SegmentType::text),
myLinker->getSegmentSize(ElfLinker::SegmentType::text));
std::memcpy(mySectionData.get(), myLinker->getSegmentData(ElfLinker::SegmentType::data),
myLinker->getSegmentSize(ElfLinker::SegmentType::data));
std::memcpy(mySectionRodata.get(), myLinker->getSegmentData(ElfLinker::SegmentType::rodata),
myLinker->getSegmentSize(ElfLinker::SegmentType::rodata));
std::memcpy(mySectionTables.get(), LOOKUP_TABLES, sizeof(LOOKUP_TABLES));
myCortexEmu.reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -455,4 +436,71 @@ void CartridgeELF::BusTransactionQueue::push(const BusTransaction& transaction)
myQueue[(myQueueNext + myQueueSize++) % TRANSACTION_QUEUE_CAPACITY] = transaction;
}
void CartridgeELF::parseAndLinkElf()
{
ElfParser elfParser;
try {
elfParser.parse(myImage.get(), myImageSize);
} catch (ElfParser::ElfParseError& e) {
throw runtime_error("failed to initialize ELF: " + string(e.what()));
}
#ifdef DUMP_ELF
dumpElf(elfParser);
#endif
myLinker = make_unique<ElfLinker>(ADDR_TEXT_BASE, ADDR_DATA_BASE, ADDR_RODATA_BASE, elfParser);
try {
myLinker->link(externalSymbols(Palette::ntsc));
} catch (const ElfLinker::ElfLinkError& e) {
throw runtime_error("failed to link ELF: " + string(e.what()));
}
try {
myArmEntrypoint = myLinker->findRelocatedSymbol("elf_main").value;
} catch (const ElfLinker::ElfSymbolResolutionError& e) {
throw runtime_error("failed to resolve ARM entrypoint" + string(e.what()));
}
if (myLinker->getSegmentSize(ElfLinker::SegmentType::text) > TEXT_SIZE)
throw runtime_error("text segment too large");
if (myLinker->getSegmentSize(ElfLinker::SegmentType::data) > DATA_SIZE)
throw runtime_error("data segment too large");
if (myLinker->getSegmentSize(ElfLinker::SegmentType::rodata) > RODATA_SIZE)
throw runtime_error("rodata segment too large");
#ifdef DUMP_ELF
dumpLinkage(elfParser, *myLinker);
cout
<< "\nARM entrypoint: 0x"
<< std::hex << std::setw(8) << std::setfill('0') << myArmEntrypoint << std::dec
<< '\n';
writeDebugBinary(*myLinker);
#endif
}
void CartridgeELF::setupMemoryMap()
{
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);
myCortexEmu
.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())
.mapRegionData(ADDR_RODATA_BASE / CortexM0::PAGE_SIZE,
RODATA_SIZE / CortexM0::PAGE_SIZE, true, mySectionData.get())
.mapRegionData(ADDR_TABLES_BASE / CortexM0::PAGE_SIZE,
TABLES_SIZE / CortexM0::PAGE_SIZE, false, mySectionRodata.get());
}

View File

@ -20,6 +20,9 @@
#include "bspf.hxx"
#include "Cart.hxx"
#include "CortexM0.hxx"
class ElfLinker;
class CartridgeELF: public Cartridge {
public:
@ -103,6 +106,10 @@ class CartridgeELF: public Cartridge {
uInt16 myNextInjectAddress{0};
};
private:
void parseAndLinkElf();
void setupMemoryMap();
private:
ByteBuffer myImage;
size_t myImageSize{0};
@ -116,6 +123,15 @@ class CartridgeELF: public Cartridge {
uInt8 myDriveBusValue{0};
uInt32 myArmEntrypoint{0};
CortexM0 myCortexEmu;
unique_ptr<ElfLinker> myLinker;
unique_ptr<uInt8[]> mySectionStack;
unique_ptr<uInt8[]> mySectionText;
unique_ptr<uInt8[]> mySectionData;
unique_ptr<uInt8[]> mySectionRodata;
unique_ptr<uInt8[]> mySectionTables;
};
#endif // CARTRIDGE_ELF

View File

@ -95,47 +95,47 @@ const uInt8 elfEnvironment::LOOKUP_TABLES[3 * 256] = {
vector<ElfLinker::ExternalSymbol> elfEnvironment::externalSymbols(elfEnvironment::Palette palette)
{
static const vector<ElfLinker::ExternalSymbol> EXTERNAL_SYMBOLS_STATIC = {
{"ADDR_IDR", ADDR_ADDR_IDR},
{"DATA_IDR", ADDR_DATA_IDR},
{"DATA_ODR", ADDR_DATA_ODR},
{"DATA_MODER", ADDR_DATA_MODER},
{"memset", ADDR_MEMSET},
{"memcpy", ADDR_MEMCPY},
{"vcsLdaForBusStuff2", ADDR_VCS_LDA_FOR_BUS_STUFF2},
{"vcsLdxForBusStuff2", ADDR_VCS_LDX_FOR_BUS_STUFF2},
{"vcsLdyForBusStuff2", ADDR_VCS_LDY_FOR_BUS_STUFF2},
{"vcsWrite3", ADDR_VCS_WRITE3},
{"vcsJmp3", ADDR_VCS_JMP3},
{"vcsNop2", ADDR_VCS_NOP2},
{"vcsNop2n", ADDR_VCS_NOP2N},
{"vcsWrite5", ADDR_VCS_WRITE5},
{"vcsWrite6", ADDR_VCS_WRITE6},
{"vcsLda2", ADDR_VCS_LDA2},
{"vcsLdx2", ADDR_VCS_LDX2},
{"vcsLdy2", ADDR_VCS_LDY2},
{"vcsSax3", ADDR_VCS_SAX3},
{"vcsSta3", ADDR_VCS_STA3},
{"vcsStx3", ADDR_VCS_STX3},
{"vcsSty3", ADDR_VCS_STY3},
{"vcsSta4", ADDR_VCS_STA4},
{"vcsStx4", ADDR_VCS_STX4},
{"vcsSty4", ADDR_VCS_STY4},
{"vcsCopyOverblankToRiotRam", ADDR_VCS_COPY_OVERBLANK_TO_RIOT_RAM},
{"vcsStartOverblank", ADDR_VCS_START_OVERBLANK},
{"vcsEndOverblank", ADDR_VCS_END_OVERBLANK},
{"vcsRead4", ADDR_VCS_READ4},
{"randint", ADDR_RANDINT},
{"vcsTxs2", ADDR_VCS_TXS2},
{"vcsJsr6", ADDR_VCS_JSR6},
{"vcsPha3", ADDR_VCS_PHA3},
{"vcsPhp3", ADDR_VCS_PHP3},
{"vcsPla4", ADDR_VCS_PLA4},
{"vcsPlp4", ADDR_VCS_PLP4},
{"vcsPla4Ex", ADDR_VCS_PLA4_EX},
{"vcsPlp4Ex", ADDR_VCS_PLP4_EX},
{"vcsJmpToRam3", ADDR_VCS_JMP_TO_RAM3},
{"vcsWaitForAddress", ADDR_VCS_WAIT_FOR_ADDRESS},
{"injectDmaData", ADDR_INJECT_DMA_DATA},
{"ADDR_IDR", ADDR_ADDR_IDR + 1},
{"DATA_IDR", ADDR_DATA_IDR + 1},
{"DATA_ODR", ADDR_DATA_ODR + 1},
{"DATA_MODER", ADDR_DATA_MODER + 1},
{"memset", ADDR_MEMSET + 1},
{"memcpy", ADDR_MEMCPY + 1},
{"vcsLdaForBusStuff2", ADDR_VCS_LDA_FOR_BUS_STUFF2 + 1},
{"vcsLdxForBusStuff2", ADDR_VCS_LDX_FOR_BUS_STUFF2 + 1},
{"vcsLdyForBusStuff2", ADDR_VCS_LDY_FOR_BUS_STUFF2 + 1},
{"vcsWrite3", ADDR_VCS_WRITE3 + 1},
{"vcsJmp3", ADDR_VCS_JMP3 + 1},
{"vcsNop2", ADDR_VCS_NOP2 + 1},
{"vcsNop2n", ADDR_VCS_NOP2N + 1},
{"vcsWrite5", ADDR_VCS_WRITE5 + 1},
{"vcsWrite6", ADDR_VCS_WRITE6 + 1},
{"vcsLda2", ADDR_VCS_LDA2 + 1},
{"vcsLdx2", ADDR_VCS_LDX2 + 1},
{"vcsLdy2", ADDR_VCS_LDY2 + 1},
{"vcsSax3", ADDR_VCS_SAX3 + 1},
{"vcsSta3", ADDR_VCS_STA3 + 1},
{"vcsStx3", ADDR_VCS_STX3 + 1},
{"vcsSty3", ADDR_VCS_STY3 + 1},
{"vcsSta4", ADDR_VCS_STA4 + 1},
{"vcsStx4", ADDR_VCS_STX4 + 1},
{"vcsSty4", ADDR_VCS_STY4 + 1},
{"vcsCopyOverblankToRiotRam", ADDR_VCS_COPY_OVERBLANK_TO_RIOT_RAM + 1},
{"vcsStartOverblank", ADDR_VCS_START_OVERBLANK + 1},
{"vcsEndOverblank", ADDR_VCS_END_OVERBLANK + 1},
{"vcsRead4", ADDR_VCS_READ4 + 1},
{"randint", ADDR_RANDINT + 1},
{"vcsTxs2", ADDR_VCS_TXS2 + 1},
{"vcsJsr6", ADDR_VCS_JSR6 + 1},
{"vcsPha3", ADDR_VCS_PHA3 + 1},
{"vcsPhp3", ADDR_VCS_PHP3 + 1},
{"vcsPla4", ADDR_VCS_PLA4 + 1},
{"vcsPlp4", ADDR_VCS_PLP4 + 1},
{"vcsPla4Ex", ADDR_VCS_PLA4_EX + 1},
{"vcsPlp4Ex", ADDR_VCS_PLP4_EX + 1},
{"vcsJmpToRam3", ADDR_VCS_JMP_TO_RAM3 + 1},
{"vcsWaitForAddress", ADDR_VCS_WAIT_FOR_ADDRESS + 1},
{"injectDmaData", ADDR_INJECT_DMA_DATA + 1},
{"ReverseByte", ADDR_TABLE_COLOR_LOOKUP_REVERSE_BYTE}
};

View File

@ -22,56 +22,80 @@
#include "ElfLinker.hxx"
namespace elfEnvironment {
constexpr uInt32 ADDR_TEXT_BASE = 0x00100000;
constexpr uInt32 ADDR_DATA_BASE = 0x00200000;
constexpr uInt32 ADDR_RODATA_BASE = 0x00300000;
constexpr uInt32 ADDR_TABLES_BASE = 0x00400000;
// Memory map. Our cortex emulator maps memory in multiples of 4kB, so use that
// here, too.
constexpr uInt32 ADDR_ADDR_IDR = 0xf0000000;
constexpr uInt32 ADDR_DATA_IDR = 0xf0000004;
constexpr uInt32 ADDR_DATA_ODR = 0xf0000008;
constexpr uInt32 ADDR_DATA_MODER = 0xf0000010;
// runtime method stubs: 4kB - 8kB
constexpr uInt32 ADDR_STUB_BASE = 0x1000; // 4kB
constexpr uInt32 STUB_SIZE = 0x1000; // 4kB
constexpr uInt32 STUB_BASE = 0x1001;
// stack (32kB): 16kB - 48kB
constexpr uInt32 ADDR_STACK_BASE = 0x4000; // 16kB
constexpr uInt32 STACK_SIZE = 0x8000; // 32kB
constexpr uInt32 ADDR_MEMSET = STUB_BASE;
constexpr uInt32 ADDR_MEMCPY = STUB_BASE + 4;
// text (1MB): 1MB - 2MB
constexpr uInt32 ADDR_TEXT_BASE = 0x00100000; // 1MB
constexpr uInt32 TEXT_SIZE = 0x00100000; // 1MB
constexpr uInt32 ADDR_VCS_LDA_FOR_BUS_STUFF2 = STUB_BASE + 8;
constexpr uInt32 ADDR_VCS_LDX_FOR_BUS_STUFF2 = STUB_BASE + 12;
constexpr uInt32 ADDR_VCS_LDY_FOR_BUS_STUFF2 = STUB_BASE + 16;
constexpr uInt32 ADDR_VCS_WRITE3 = STUB_BASE + 20;
constexpr uInt32 ADDR_VCS_JMP3 = STUB_BASE + 24;
constexpr uInt32 ADDR_VCS_NOP2 = STUB_BASE + 28;
constexpr uInt32 ADDR_VCS_NOP2N = STUB_BASE + 32;
constexpr uInt32 ADDR_VCS_WRITE5 = STUB_BASE + 36;
constexpr uInt32 ADDR_VCS_WRITE6 = STUB_BASE + 40;
constexpr uInt32 ADDR_VCS_LDA2 = STUB_BASE + 44;
constexpr uInt32 ADDR_VCS_LDX2 = STUB_BASE + 48;
constexpr uInt32 ADDR_VCS_LDY2 = STUB_BASE + 52;
constexpr uInt32 ADDR_VCS_SAX3 = STUB_BASE + 56;
constexpr uInt32 ADDR_VCS_STA3 = STUB_BASE + 60;
constexpr uInt32 ADDR_VCS_STX3 = STUB_BASE + 64;
constexpr uInt32 ADDR_VCS_STY3 = STUB_BASE + 68;
constexpr uInt32 ADDR_VCS_STA4 = STUB_BASE + 72;
constexpr uInt32 ADDR_VCS_STX4 = STUB_BASE + 76;
constexpr uInt32 ADDR_VCS_STY4 = STUB_BASE + 80;
constexpr uInt32 ADDR_VCS_COPY_OVERBLANK_TO_RIOT_RAM = STUB_BASE + 84;
constexpr uInt32 ADDR_VCS_START_OVERBLANK = STUB_BASE + 88;
constexpr uInt32 ADDR_VCS_END_OVERBLANK = STUB_BASE + 92;
constexpr uInt32 ADDR_VCS_READ4 = STUB_BASE + 96;
constexpr uInt32 ADDR_RANDINT = STUB_BASE + 100;
constexpr uInt32 ADDR_VCS_TXS2 = STUB_BASE + 104;
constexpr uInt32 ADDR_VCS_JSR6 = STUB_BASE + 108;
constexpr uInt32 ADDR_VCS_PHA3 = STUB_BASE + 112;
constexpr uInt32 ADDR_VCS_PHP3 = STUB_BASE + 116;
constexpr uInt32 ADDR_VCS_PLA4 = STUB_BASE + 120;
constexpr uInt32 ADDR_VCS_PLP4 = STUB_BASE + 124;
constexpr uInt32 ADDR_VCS_PLA4_EX = STUB_BASE + 128;
constexpr uInt32 ADDR_VCS_PLP4_EX = STUB_BASE + 132;
constexpr uInt32 ADDR_VCS_JMP_TO_RAM3 = STUB_BASE + 136;
constexpr uInt32 ADDR_VCS_WAIT_FOR_ADDRESS = STUB_BASE + 140;
constexpr uInt32 ADDR_INJECT_DMA_DATA = STUB_BASE + 144;
// data (512kB): 2MB - 2.5MB
constexpr uInt32 ADDR_DATA_BASE = 0x00200000; // 2MB
constexpr uInt32 DATA_SIZE = 0x00080000; // 512kB
// rodata (512kB): 3MB - 3.5MB
constexpr uInt32 ADDR_RODATA_BASE = 0x00300000; // 3MB
constexpr uInt32 RODATA_SIZE = 0x00080000; // 512kB
// lookup tables (4kB): 4MB -- 4.004MB
constexpr uInt32 ADDR_TABLES_BASE = 0x00400000; // 4MB
constexpr uInt32 TABLES_SIZE = 0x1000; // 4kB
// peripherials: 4kB @ 0xf0000000
constexpr uInt32 ADDR_PERIPHERIALS_BASE = 0xf0000000;
constexpr uInt32 PERIPHERIALS_SIZE = 0x1000;
constexpr uInt32 ADDR_ADDR_IDR = ADDR_PERIPHERIALS_BASE;
constexpr uInt32 ADDR_DATA_IDR =ADDR_PERIPHERIALS_BASE + 4;
constexpr uInt32 ADDR_DATA_ODR = ADDR_PERIPHERIALS_BASE + 8;
constexpr uInt32 ADDR_DATA_MODER = ADDR_PERIPHERIALS_BASE + 12;
constexpr uInt32 ADDR_MEMSET = ADDR_STUB_BASE;
constexpr uInt32 ADDR_MEMCPY = ADDR_STUB_BASE + 4;
constexpr uInt32 ADDR_VCS_LDA_FOR_BUS_STUFF2 = ADDR_STUB_BASE + 8;
constexpr uInt32 ADDR_VCS_LDX_FOR_BUS_STUFF2 = ADDR_STUB_BASE + 12;
constexpr uInt32 ADDR_VCS_LDY_FOR_BUS_STUFF2 = ADDR_STUB_BASE + 16;
constexpr uInt32 ADDR_VCS_WRITE3 = ADDR_STUB_BASE + 20;
constexpr uInt32 ADDR_VCS_JMP3 = ADDR_STUB_BASE + 24;
constexpr uInt32 ADDR_VCS_NOP2 = ADDR_STUB_BASE + 28;
constexpr uInt32 ADDR_VCS_NOP2N = ADDR_STUB_BASE + 32;
constexpr uInt32 ADDR_VCS_WRITE5 = ADDR_STUB_BASE + 36;
constexpr uInt32 ADDR_VCS_WRITE6 = ADDR_STUB_BASE + 40;
constexpr uInt32 ADDR_VCS_LDA2 = ADDR_STUB_BASE + 44;
constexpr uInt32 ADDR_VCS_LDX2 = ADDR_STUB_BASE + 48;
constexpr uInt32 ADDR_VCS_LDY2 = ADDR_STUB_BASE + 52;
constexpr uInt32 ADDR_VCS_SAX3 = ADDR_STUB_BASE + 56;
constexpr uInt32 ADDR_VCS_STA3 = ADDR_STUB_BASE + 60;
constexpr uInt32 ADDR_VCS_STX3 = ADDR_STUB_BASE + 64;
constexpr uInt32 ADDR_VCS_STY3 = ADDR_STUB_BASE + 68;
constexpr uInt32 ADDR_VCS_STA4 = ADDR_STUB_BASE + 72;
constexpr uInt32 ADDR_VCS_STX4 = ADDR_STUB_BASE + 76;
constexpr uInt32 ADDR_VCS_STY4 = ADDR_STUB_BASE + 80;
constexpr uInt32 ADDR_VCS_COPY_OVERBLANK_TO_RIOT_RAM = ADDR_STUB_BASE + 84;
constexpr uInt32 ADDR_VCS_START_OVERBLANK = ADDR_STUB_BASE + 88;
constexpr uInt32 ADDR_VCS_END_OVERBLANK = ADDR_STUB_BASE + 92;
constexpr uInt32 ADDR_VCS_READ4 = ADDR_STUB_BASE + 96;
constexpr uInt32 ADDR_RANDINT = ADDR_STUB_BASE + 100;
constexpr uInt32 ADDR_VCS_TXS2 = ADDR_STUB_BASE + 104;
constexpr uInt32 ADDR_VCS_JSR6 = ADDR_STUB_BASE + 108;
constexpr uInt32 ADDR_VCS_PHA3 = ADDR_STUB_BASE + 112;
constexpr uInt32 ADDR_VCS_PHP3 = ADDR_STUB_BASE + 116;
constexpr uInt32 ADDR_VCS_PLA4 = ADDR_STUB_BASE + 120;
constexpr uInt32 ADDR_VCS_PLP4 = ADDR_STUB_BASE + 124;
constexpr uInt32 ADDR_VCS_PLA4_EX = ADDR_STUB_BASE + 128;
constexpr uInt32 ADDR_VCS_PLP4_EX = ADDR_STUB_BASE + 132;
constexpr uInt32 ADDR_VCS_JMP_TO_RAM3 = ADDR_STUB_BASE + 136;
constexpr uInt32 ADDR_VCS_WAIT_FOR_ADDRESS = ADDR_STUB_BASE + 140;
constexpr uInt32 ADDR_INJECT_DMA_DATA = ADDR_STUB_BASE + 144;
constexpr uInt32 ADDR_TABLE_COLOR_LOOKUP_NTSC = ADDR_TABLES_BASE;
constexpr uInt32 ADDR_TABLE_COLOR_LOOKUP_PAL = ADDR_TABLES_BASE + 256;