diff --git a/src/emucore/CartELF.cxx b/src/emucore/CartELF.cxx index e8b779a80..f39209e8a 100644 --- a/src/emucore/CartELF.cxx +++ b/src/emucore/CartELF.cxx @@ -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(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(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(STACK_SIZE); + mySectionText = make_unique(TEXT_SIZE); + mySectionData = make_unique(DATA_SIZE); + mySectionRodata = make_unique(RODATA_SIZE); + mySectionTables = make_unique(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()); +} + diff --git a/src/emucore/CartELF.hxx b/src/emucore/CartELF.hxx index 7a2e3abd8..d79cdcec8 100644 --- a/src/emucore/CartELF.hxx +++ b/src/emucore/CartELF.hxx @@ -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 myLinker; + + unique_ptr mySectionStack; + unique_ptr mySectionText; + unique_ptr mySectionData; + unique_ptr mySectionRodata; + unique_ptr mySectionTables; }; #endif // CARTRIDGE_ELF diff --git a/src/emucore/elf/ElfEnvironment.cxx b/src/emucore/elf/ElfEnvironment.cxx index e33bdba9d..2f10a826a 100644 --- a/src/emucore/elf/ElfEnvironment.cxx +++ b/src/emucore/elf/ElfEnvironment.cxx @@ -95,47 +95,47 @@ const uInt8 elfEnvironment::LOOKUP_TABLES[3 * 256] = { vector elfEnvironment::externalSymbols(elfEnvironment::Palette palette) { static const vector 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} }; diff --git a/src/emucore/elf/ElfEnvironment.hxx b/src/emucore/elf/ElfEnvironment.hxx index 841d13e66..a190c0cd0 100644 --- a/src/emucore/elf/ElfEnvironment.hxx +++ b/src/emucore/elf/ElfEnvironment.hxx @@ -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;