Refactoring.

This commit is contained in:
Christian Speckner 2024-07-27 00:05:33 +02:00
parent 239c307f91
commit 54e65a9c03
9 changed files with 474 additions and 328 deletions

View File

@ -176,7 +176,8 @@ 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), myVcslibDelegate(*this) : Cartridge(settings, md5), myImageSize(size), myTransactionQueue(TRANSACTION_QUEUE_CAPACITY),
myVcsLib(myTransactionQueue)
{ {
myImage = make_unique<uInt8[]>(size); myImage = make_unique<uInt8[]>(size);
std::memcpy(myImage.get(), image.get(), size); std::memcpy(myImage.get(), image.get(), size);
@ -203,13 +204,14 @@ void CartridgeELF::reset()
myIsBusDriven = false; myIsBusDriven = false;
myDriveBusValue = 0; myDriveBusValue = 0;
myTransactionQueue.reset(); myTransactionQueue
myTransactionQueue.injectROM(0x00, 0x1ffc); .reset()
myTransactionQueue.injectROM(0x10); .injectROM(0x00, 0x1ffc)
myTransactionQueue.setNextInjectAddress(0x1000); .injectROM(0x10)
.setNextInjectAddress(0x1000);
vcsCopyOverblankToRiotRam(); myVcsLib.vcsCopyOverblankToRiotRam();
vcsStartOverblank(); myVcsLib.vcsStartOverblank();
std::memset(mySectionStack.get(), 0, STACK_SIZE); std::memset(mySectionStack.get(), 0, STACK_SIZE);
std::memset(mySectionText.get(), 0, TEXT_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) 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 (nextTransaction) nextTransaction->setBusState(myIsBusDriven, myDriveBusValue);
if (myIsBusDriven) value |= myDriveBusValue; if (myIsBusDriven) value |= myDriveBusValue;
@ -307,266 +309,6 @@ inline uInt8 CartridgeELF::driveBus(uInt16 address, uInt8 value)
return 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<BusTransaction[]>(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() void CartridgeELF::parseAndLinkElf()
{ {
ElfParser elfParser; ElfParser elfParser;
@ -635,7 +377,7 @@ void CartridgeELF::setupMemoryMap()
.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, .mapRegionDelegate(ADDR_STUB_BASE / CortexM0::PAGE_SIZE,
STUB_SIZE / CortexM0::PAGE_SIZE, true, &myVcslibDelegate); STUB_SIZE / CortexM0::PAGE_SIZE, true, &myVcsLib);
} }

View File

@ -21,6 +21,8 @@
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx" #include "Cart.hxx"
#include "CortexM0.hxx" #include "CortexM0.hxx"
#include "BusTransactionQueue.hxx"
#include "VcsLib.hxx"
class ElfLinker; class ElfLinker;
@ -64,63 +66,6 @@ class CartridgeELF: public Cartridge {
private: private:
uInt8 driveBus(uInt16 address, uInt8 value); 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<BusTransaction[]> 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: private:
void parseAndLinkElf(); void parseAndLinkElf();
void setupMemoryMap(); void setupMemoryMap();
@ -148,7 +93,7 @@ class CartridgeELF: public Cartridge {
unique_ptr<uInt8[]> mySectionRodata; unique_ptr<uInt8[]> mySectionRodata;
unique_ptr<uInt8[]> mySectionTables; unique_ptr<uInt8[]> mySectionTables;
VcslibDelegate myVcslibDelegate; VcsLib myVcsLib;
}; };
#endif // CARTRIDGE_ELF #endif // CARTRIDGE_ELF

View File

@ -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<Transaction[]>(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;
}

View File

@ -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<Transaction[]> 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

189
src/emucore/elf/VcsLib.cxx Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -4,7 +4,9 @@ MODULE_OBJS = \
src/emucore/elf/ElfParser.o \ src/emucore/elf/ElfParser.o \
src/emucore/elf/ElfLinker.o \ src/emucore/elf/ElfLinker.o \
src/emucore/elf/ElfUtil.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 = \ MODULE_TEST_OBJS = \
src/emucore/elf/ElfUtil.o \ src/emucore/elf/ElfUtil.o \

View File

@ -695,6 +695,8 @@
<ClCompile Include="..\..\emucore\elf\ElfLinker.cxx" /> <ClCompile Include="..\..\emucore\elf\ElfLinker.cxx" />
<ClCompile Include="..\..\emucore\elf\ElfUtil.cxx" /> <ClCompile Include="..\..\emucore\elf\ElfUtil.cxx" />
<ClCompile Include="..\..\emucore\elf\ElfEnvironment.cxx" /> <ClCompile Include="..\..\emucore\elf\ElfEnvironment.cxx" />
<ClCompile Include="..\..\emucore\elf\BusTransactionQueue.cxx" />
<ClCompile Include="..\..\emucore\elf\VcsLib.cxx" />
<ClCompile Include="..\..\emucore\CortexM0.cxx" /> <ClCompile Include="..\..\emucore\CortexM0.cxx" />
<ClCompile Include="..\..\emucore\EmulationTiming.cxx" /> <ClCompile Include="..\..\emucore\EmulationTiming.cxx" />
<ClCompile Include="..\..\emucore\EmulationWorker.cxx" /> <ClCompile Include="..\..\emucore\EmulationWorker.cxx" />
@ -1671,6 +1673,8 @@
<ClInclude Include="..\..\emucore\elf\ElfLinker.hxx" /> <ClInclude Include="..\..\emucore\elf\ElfLinker.hxx" />
<ClInclude Include="..\..\emucore\elf\ElfUtil.hxx" /> <ClInclude Include="..\..\emucore\elf\ElfUtil.hxx" />
<ClInclude Include="..\..\emucore\elf\ElfEnvironment.hxx" /> <ClInclude Include="..\..\emucore\elf\ElfEnvironment.hxx" />
<ClCompile Include="..\..\emucore\elf\BusTransactionQueue.hxx" />
<ClCompile Include="..\..\emucore\elf\VcsLib.hxx" />
<ClInclude Include="..\..\emucore\CortexM0.hxx" /> <ClInclude Include="..\..\emucore\CortexM0.hxx" />
<ClInclude Include="..\..\emucore\EmulationTiming.hxx" /> <ClInclude Include="..\..\emucore\EmulationTiming.hxx" />
<ClInclude Include="..\..\emucore\EmulationWorker.hxx" /> <ClInclude Include="..\..\emucore\EmulationWorker.hxx" />

View File

@ -1260,6 +1260,12 @@
<ClCompile Include="..\..\emucore\elf\ElfEnvironment.cxx"> <ClCompile Include="..\..\emucore\elf\ElfEnvironment.cxx">
<Filter>Source Files\emucore\elf</Filter> <Filter>Source Files\emucore\elf</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\emucore\elf\BusTransactionCode.cxx">
<Filter>Source Files\emucore\elf</Filter>
</ClCompile>
<ClCompile Include="..\..\emucore\elf\VcsLib.cxx">
<Filter>Source Files\emucore\elf</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\emucore\AtariVox.hxx"> <ClInclude Include="..\..\emucore\AtariVox.hxx">
@ -2552,6 +2558,12 @@
<ClInclude Include="..\..\emucore\elf\ElfEnvironment.hxx"> <ClInclude Include="..\..\emucore\elf\ElfEnvironment.hxx">
<Filter>Header Files\emucore\elf</Filter> <Filter>Header Files\emucore\elf</Filter>
</ClInclude> </ClInclude>
<ClCompile Include="..\..\emucore\elf\BusTransactionCode.hxx">
<Filter>Source Files\emucore\elf</Filter>
</ClCompile>
<ClCompile Include="..\..\emucore\elf\VcsLib.hxx">
<Filter>Source Files\emucore\elf</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="stella.ico"> <None Include="stella.ico">