From 54e65a9c0302590ce1290cd7f75fa037b3f95698 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Sat, 27 Jul 2024 00:05:33 +0200 Subject: [PATCH] Refactoring. --- src/emucore/CartELF.cxx | 280 +----------------------- src/emucore/CartELF.hxx | 61 +----- src/emucore/elf/BusTransactionQueue.cxx | 134 ++++++++++++ src/emucore/elf/BusTransactionQueue.hxx | 69 ++++++ src/emucore/elf/VcsLib.cxx | 189 ++++++++++++++++ src/emucore/elf/VcsLib.hxx | 49 +++++ src/emucore/elf/module.mk | 4 +- src/os/windows/Stella.vcxproj | 4 + src/os/windows/Stella.vcxproj.filters | 12 + 9 files changed, 474 insertions(+), 328 deletions(-) create mode 100644 src/emucore/elf/BusTransactionQueue.cxx create mode 100644 src/emucore/elf/BusTransactionQueue.hxx create mode 100644 src/emucore/elf/VcsLib.cxx create mode 100644 src/emucore/elf/VcsLib.hxx diff --git a/src/emucore/CartELF.cxx b/src/emucore/CartELF.cxx index 52a005586..493c03360 100644 --- a/src/emucore/CartELF.cxx +++ b/src/emucore/CartELF.cxx @@ -176,7 +176,8 @@ namespace { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5, const Settings& settings) - : Cartridge(settings, md5), myImageSize(size), myVcslibDelegate(*this) + : Cartridge(settings, md5), myImageSize(size), myTransactionQueue(TRANSACTION_QUEUE_CAPACITY), + myVcsLib(myTransactionQueue) { myImage = make_unique(size); std::memcpy(myImage.get(), image.get(), size); @@ -203,13 +204,14 @@ void CartridgeELF::reset() myIsBusDriven = false; myDriveBusValue = 0; - myTransactionQueue.reset(); - myTransactionQueue.injectROM(0x00, 0x1ffc); - myTransactionQueue.injectROM(0x10); - myTransactionQueue.setNextInjectAddress(0x1000); + myTransactionQueue + .reset() + .injectROM(0x00, 0x1ffc) + .injectROM(0x10) + .setNextInjectAddress(0x1000); - vcsCopyOverblankToRiotRam(); - vcsStartOverblank(); + myVcsLib.vcsCopyOverblankToRiotRam(); + myVcsLib.vcsStartOverblank(); std::memset(mySectionStack.get(), 0, STACK_SIZE); std::memset(mySectionText.get(), 0, TEXT_SIZE); @@ -299,7 +301,7 @@ uInt8 CartridgeELF::overdrivePoke(uInt16 address, uInt8 value) inline uInt8 CartridgeELF::driveBus(uInt16 address, uInt8 value) { - BusTransaction* nextTransaction = myTransactionQueue.getNextTransaction(address); + auto* nextTransaction = myTransactionQueue.getNextTransaction(address); if (nextTransaction) nextTransaction->setBusState(myIsBusDriven, myDriveBusValue); if (myIsBusDriven) value |= myDriveBusValue; @@ -307,266 +309,6 @@ inline uInt8 CartridgeELF::driveBus(uInt16 address, uInt8 value) return value; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::vcsWrite5(uInt8 zpAddress, uInt8 value) -{ - myTransactionQueue.injectROM(0xa9); - myTransactionQueue.injectROM(value); - myTransactionQueue.injectROM(0x85); - myTransactionQueue.injectROM(zpAddress); - myTransactionQueue.yield(zpAddress); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::vcsCopyOverblankToRiotRam() -{ - for (uInt8 i = 0; i < OVERBLANK_PROGRAM_SIZE; i++) - vcsWrite5(0x80 + i, OVERBLANK_PROGRAM[i]); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::vcsStartOverblank() -{ - myTransactionQueue.injectROM(0x4c); - myTransactionQueue.injectROM(0x80); - myTransactionQueue.injectROM(0x00); - myTransactionQueue.yield(0x0080); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeELF::BusTransaction CartridgeELF::BusTransaction::transactionYield(uInt16 address) -{ - address &= 0x1fff; - return {.address = address, .value = 0, .yield = true}; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeELF::BusTransaction CartridgeELF::BusTransaction::transactionDrive(uInt16 address, uInt8 value) -{ - address &= 0x1fff; - return {.address = address, .value = value, .yield = false}; -} - - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::BusTransaction::setBusState(bool& bs_drive, uInt8& bs_value) const -{ - if (yield) { - bs_drive = false; - } else { - bs_drive = true; - bs_value = this->value; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeELF::BusTransactionQueue::BusTransactionQueue() -{ - myQueue = make_unique(TRANSACTION_QUEUE_CAPACITY); - reset(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::BusTransactionQueue::reset() -{ - myQueueNext = myQueueSize = 0; - myNextInjectAddress = 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::BusTransactionQueue::setNextInjectAddress(uInt16 address) -{ - myNextInjectAddress = address; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::BusTransactionQueue::injectROM(uInt8 value) -{ - injectROM(value, myNextInjectAddress); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::BusTransactionQueue::injectROM(uInt8 value, uInt16 address) -{ - push(BusTransaction::transactionDrive(address, value)); - myNextInjectAddress = address + 1; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::BusTransactionQueue::yield(uInt16 address) -{ - push(BusTransaction::transactionYield(address)); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool CartridgeELF::BusTransactionQueue::hasPendingTransaction() const -{ - return myQueueSize > 0; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -CartridgeELF::BusTransaction* CartridgeELF::BusTransactionQueue::getNextTransaction(uInt16 address) -{ - if (myQueueSize == 0) return nullptr; - - BusTransaction* nextTransaction = &myQueue[myQueueNext]; - if (nextTransaction->address != (address & 0x1fff)) return nullptr; - - myQueueNext = (myQueueNext + 1) % TRANSACTION_QUEUE_CAPACITY; - myQueueSize--; - - return nextTransaction; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void CartridgeELF::BusTransactionQueue::push(const BusTransaction& transaction) -{ - if (myQueueSize > 0) { - BusTransaction& lastTransaction = myQueue[(myQueueNext + myQueueSize - 1) % TRANSACTION_QUEUE_CAPACITY]; - - if (lastTransaction.address == transaction.address) { - lastTransaction = transaction; - return; - } - } - - if (myQueueSize == TRANSACTION_QUEUE_CAPACITY) - throw FatalEmulationError("read stream overflow"); - - 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() { ElfParser elfParser; @@ -635,7 +377,7 @@ void CartridgeELF::setupMemoryMap() .mapRegionData(ADDR_TABLES_BASE / CortexM0::PAGE_SIZE, TABLES_SIZE / CortexM0::PAGE_SIZE, true, mySectionTables.get()) .mapRegionDelegate(ADDR_STUB_BASE / CortexM0::PAGE_SIZE, - STUB_SIZE / CortexM0::PAGE_SIZE, true, &myVcslibDelegate); + STUB_SIZE / CortexM0::PAGE_SIZE, true, &myVcsLib); } diff --git a/src/emucore/CartELF.hxx b/src/emucore/CartELF.hxx index 168aa28e2..ca3be468e 100644 --- a/src/emucore/CartELF.hxx +++ b/src/emucore/CartELF.hxx @@ -21,6 +21,8 @@ #include "bspf.hxx" #include "Cart.hxx" #include "CortexM0.hxx" +#include "BusTransactionQueue.hxx" +#include "VcsLib.hxx" class ElfLinker; @@ -64,63 +66,6 @@ class CartridgeELF: public Cartridge { private: uInt8 driveBus(uInt16 address, uInt8 value); - void vcsWrite5(uInt8 zpAddress, uInt8 value); - void vcsCopyOverblankToRiotRam(); - void vcsStartOverblank(); - - private: - struct BusTransaction { - static BusTransaction transactionYield(uInt16 address); - static BusTransaction transactionDrive(uInt16 address, uInt8 value); - - void setBusState(bool& drive, uInt8& value) const; - - uInt16 address; - uInt8 value; - bool yield; - }; - - class BusTransactionQueue { - public: - BusTransactionQueue(); - - void reset(); - - void setNextInjectAddress(uInt16 address); - void injectROM(uInt8 value); - void injectROM(uInt8 value, uInt16 address); - - void yield(uInt16 address); - - bool hasPendingTransaction() const; - BusTransaction* getNextTransaction(uInt16 address); - - private: - void push(const BusTransaction& transaction); - - private: - unique_ptr myQueue; - size_t myQueueNext{0}; - size_t myQueueSize{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: void parseAndLinkElf(); void setupMemoryMap(); @@ -148,7 +93,7 @@ class CartridgeELF: public Cartridge { unique_ptr mySectionRodata; unique_ptr mySectionTables; - VcslibDelegate myVcslibDelegate; + VcsLib myVcsLib; }; #endif // CARTRIDGE_ELF diff --git a/src/emucore/elf/BusTransactionQueue.cxx b/src/emucore/elf/BusTransactionQueue.cxx new file mode 100644 index 000000000..b7c4082d1 --- /dev/null +++ b/src/emucore/elf/BusTransactionQueue.cxx @@ -0,0 +1,134 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "BusTransactionQueue.hxx" + +#include "exception/FatalEmulationError.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue::Transaction BusTransactionQueue::Transaction::transactionYield(uInt16 address) +{ + address &= 0x1fff; + return {.address = address, .value = 0, .yield = true}; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue::Transaction BusTransactionQueue::Transaction::transactionDrive(uInt16 address, uInt8 value) +{ + address &= 0x1fff; + return {.address = address, .value = value, .yield = false}; +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void BusTransactionQueue::Transaction::setBusState(bool& bs_drive, uInt8& bs_value) const +{ + if (yield) { + bs_drive = false; + } else { + bs_drive = true; + bs_value = this->value; + } +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue::BusTransactionQueue(size_t capacity) : myQueueCapacity(capacity) +{ + myQueue = make_unique(myQueueCapacity); + reset(); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue& BusTransactionQueue::reset() +{ + myQueueNext = myQueueSize = 0; + myNextInjectAddress = 0; + + return *this; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue& BusTransactionQueue::setNextInjectAddress(uInt16 address) +{ + myNextInjectAddress = address; + + return *this; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue& BusTransactionQueue::injectROM(uInt8 value) +{ + injectROM(value, myNextInjectAddress); + + return *this; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue& BusTransactionQueue::injectROM(uInt8 value, uInt16 address) +{ + push(Transaction::transactionDrive(address, value)); + myNextInjectAddress = address + 1; + + return *this; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue& BusTransactionQueue::yield(uInt16 address) +{ + push(Transaction::transactionYield(address)); + + return *this; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool BusTransactionQueue::hasPendingTransaction() const +{ + return myQueueSize > 0; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +BusTransactionQueue::Transaction* BusTransactionQueue::getNextTransaction(uInt16 address) +{ + if (myQueueSize == 0) return nullptr; + + Transaction* nextTransaction = &myQueue[myQueueNext]; + if (nextTransaction->address != (address & 0x1fff)) return nullptr; + + myQueueNext = (myQueueNext + 1) % myQueueCapacity; + myQueueSize--; + + return nextTransaction; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void BusTransactionQueue::push(const Transaction& transaction) +{ + if (myQueueSize > 0) { + Transaction& lastTransaction = myQueue[(myQueueNext + myQueueSize - 1) % myQueueCapacity]; + + if (lastTransaction.address == transaction.address) { + lastTransaction = transaction; + return; + } + } + + if (myQueueSize == myQueueCapacity) + throw FatalEmulationError("read stream overflow"); + + myQueue[(myQueueNext + myQueueSize++) % myQueueCapacity] = transaction; +} diff --git a/src/emucore/elf/BusTransactionQueue.hxx b/src/emucore/elf/BusTransactionQueue.hxx new file mode 100644 index 000000000..567766e1e --- /dev/null +++ b/src/emucore/elf/BusTransactionQueue.hxx @@ -0,0 +1,69 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef BUS_TRANSACTION_QUEUE +#define BUS_TRANSACTION_QUEUE + +#include "bspf.hxx" + +class BusTransactionQueue { + public: + struct Transaction { + static Transaction transactionYield(uInt16 address); + static Transaction transactionDrive(uInt16 address, uInt8 value); + + void setBusState(bool& drive, uInt8& value) const; + + uInt16 address; + uInt8 value; + bool yield; + }; + + public: + explicit BusTransactionQueue(size_t capacity); + + BusTransactionQueue& reset(); + + BusTransactionQueue& setNextInjectAddress(uInt16 address); + BusTransactionQueue& injectROM(uInt8 value); + BusTransactionQueue& injectROM(uInt8 value, uInt16 address); + + BusTransactionQueue& yield(uInt16 address); + + bool hasPendingTransaction() const; + Transaction* getNextTransaction(uInt16 address); + + private: + void push(const Transaction& transaction); + + private: + const size_t myQueueCapacity; + + unique_ptr myQueue; + size_t myQueueNext{0}; + size_t myQueueSize{0}; + + uInt16 myNextInjectAddress{0}; + + private: + BusTransactionQueue(const BusTransactionQueue&) = delete; + BusTransactionQueue(BusTransactionQueue&&) = delete; + BusTransactionQueue& operator=(const BusTransactionQueue&) = delete; + BusTransactionQueue& operator=(BusTransactionQueue&&) = delete; +}; + +#endif // BUS_TRANSACTION_QUEUE diff --git a/src/emucore/elf/VcsLib.cxx b/src/emucore/elf/VcsLib.cxx new file mode 100644 index 000000000..da4ae09df --- /dev/null +++ b/src/emucore/elf/VcsLib.cxx @@ -0,0 +1,189 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "VcsLib.hxx" + +#include "BusTransactionQueue.hxx" +#include "ElfEnvironment.hxx" +#include "exception/FatalEmulationError.hxx" + +using namespace elfEnvironment; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +VcsLib::VcsLib(BusTransactionQueue& transactionQueue) : myTransactionQueue(transactionQueue) +{} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VcsLib::vcsWrite5(uInt8 zpAddress, uInt8 value) +{ + myTransactionQueue + .injectROM(0xa9) + .injectROM(value) + .injectROM(0x85) + .injectROM(zpAddress) + .yield(zpAddress); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VcsLib::vcsCopyOverblankToRiotRam() +{ + for (uInt8 i = 0; i < OVERBLANK_PROGRAM_SIZE; i++) + vcsWrite5(0x80 + i, OVERBLANK_PROGRAM[i]); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void VcsLib::vcsStartOverblank() +{ + myTransactionQueue + .injectROM(0x4c) + .injectROM(0x80) + .injectROM(0x00) + .yield(0x0080); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +CortexM0::err_t VcsLib::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: + vcsCopyOverblankToRiotRam(); + return returnFromStub(value, op); + + case ADDR_VCS_START_OVERBLANK: + 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 VcsLib::returnFromStub(uInt16& value, uInt8& op) +{ + constexpr uInt16 BX_LR = 0x7047; + + value = BX_LR; + op = CortexM0::decodeInstructionWord(BX_LR); + + return CortexM0::ERR_NONE; +} diff --git a/src/emucore/elf/VcsLib.hxx b/src/emucore/elf/VcsLib.hxx new file mode 100644 index 000000000..dbbf2836d --- /dev/null +++ b/src/emucore/elf/VcsLib.hxx @@ -0,0 +1,49 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef VCSLIB_H +#define VCSLIB_H + +#include "bspf.hxx" +#include "CortexM0.hxx" + +class BusTransactionQueue; + +class VcsLib: public CortexM0::BusTransactionDelegate { + public: + explicit VcsLib(BusTransactionQueue& transactionQueue); + + CortexM0::err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) override; + + void vcsWrite5(uInt8 zpAddress, uInt8 value); + void vcsCopyOverblankToRiotRam(); + void vcsStartOverblank(); + + private: + CortexM0::err_t returnFromStub(uInt16& value, uInt8& op); + + private: + BusTransactionQueue& myTransactionQueue; + + private: + VcsLib(const VcsLib&) = delete; + VcsLib(VcsLib&&) = delete; + const VcsLib& operator=(const VcsLib&) = delete; + const VcsLib& operator=(VcsLib&&) = delete; +}; + +#endif // VCSLIB_H diff --git a/src/emucore/elf/module.mk b/src/emucore/elf/module.mk index 21dfc746b..e71ab01c5 100644 --- a/src/emucore/elf/module.mk +++ b/src/emucore/elf/module.mk @@ -4,7 +4,9 @@ MODULE_OBJS = \ src/emucore/elf/ElfParser.o \ src/emucore/elf/ElfLinker.o \ src/emucore/elf/ElfUtil.o \ - src/emucore/elf/ElfEnvironment.o + src/emucore/elf/ElfEnvironment.o \ + src/emucore/elf/BusTransactionQueue.o \ + src/emucore/elf/VcsLib.o MODULE_TEST_OBJS = \ src/emucore/elf/ElfUtil.o \ diff --git a/src/os/windows/Stella.vcxproj b/src/os/windows/Stella.vcxproj index bccef1544..146b54753 100755 --- a/src/os/windows/Stella.vcxproj +++ b/src/os/windows/Stella.vcxproj @@ -695,6 +695,8 @@ + + @@ -1671,6 +1673,8 @@ + + diff --git a/src/os/windows/Stella.vcxproj.filters b/src/os/windows/Stella.vcxproj.filters index 33f81f4e5..8faf2c6ae 100644 --- a/src/os/windows/Stella.vcxproj.filters +++ b/src/os/windows/Stella.vcxproj.filters @@ -1260,6 +1260,12 @@ Source Files\emucore\elf + + Source Files\emucore\elf + + + Source Files\emucore\elf + @@ -2552,6 +2558,12 @@ Header Files\emucore\elf + + Source Files\emucore\elf + + + Source Files\emucore\elf +