Implement most of vcslib.

This commit is contained in:
Christian Speckner 2024-08-08 22:45:46 +02:00
parent 948ad8d67e
commit e7de075b20
4 changed files with 67 additions and 17 deletions

View File

@ -21,10 +21,10 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BusTransactionQueue::Transaction BusTransactionQueue::Transaction::transactionYield( BusTransactionQueue::Transaction BusTransactionQueue::Transaction::transactionYield(
uInt16 address, uInt64 timestamp uInt16 address, uInt64 timestamp, uInt16 mask
) { ) {
address &= 0x1fff; address &= 0x1fff;
return {.address = address, .value = 0, .timestamp = timestamp, .yield = true}; return {.address = address, .mask = mask, .value = 0, .timestamp = timestamp, .yield = true};
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -32,7 +32,7 @@ BusTransactionQueue::Transaction BusTransactionQueue::Transaction::transactionDr
uInt16 address, uInt8 value, uInt64 timestamp uInt16 address, uInt8 value, uInt64 timestamp
) { ) {
address &= 0x1fff; address &= 0x1fff;
return {.address = address, .value = value, .timestamp = timestamp, .yield = false}; return {.address = address, .mask = 0xffff, .value = value, .timestamp = timestamp, .yield = false};
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -112,9 +112,9 @@ BusTransactionQueue& BusTransactionQueue::stuffByte(uInt8 value, uInt16 address)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BusTransactionQueue& BusTransactionQueue::yield(uInt16 address) BusTransactionQueue& BusTransactionQueue::yield(uInt16 address, uInt16 mask)
{ {
push(Transaction::transactionYield(address, myTimestamp)); push(Transaction::transactionYield(address, myTimestamp, mask));
return *this; return *this;
} }
@ -131,7 +131,10 @@ BusTransactionQueue::Transaction* BusTransactionQueue::getNextTransaction(uInt16
if (myQueueSize == 0) return nullptr; if (myQueueSize == 0) return nullptr;
Transaction* nextTransaction = &myQueue[myQueueNext]; Transaction* nextTransaction = &myQueue[myQueueNext];
if (nextTransaction->address != (address & 0x1fff) || nextTransaction->timestamp > timestamp) return nullptr; if (
nextTransaction->address != (address & 0x1fff & nextTransaction->mask) ||
nextTransaction->timestamp > timestamp
) return nullptr;
myQueueNext = (myQueueNext + 1) % myQueueCapacity; myQueueNext = (myQueueNext + 1) % myQueueCapacity;
myQueueSize--; myQueueSize--;

View File

@ -23,12 +23,13 @@
class BusTransactionQueue { class BusTransactionQueue {
public: public:
struct Transaction { struct Transaction {
static Transaction transactionYield(uInt16 address, uInt64 timestamp); static Transaction transactionYield(uInt16 address, uInt64 timestamp, uInt16 mask);
static Transaction transactionDrive(uInt16 address, uInt8 value, uInt64 timestamp); static Transaction transactionDrive(uInt16 address, uInt8 value, uInt64 timestamp);
void setBusState(bool& drive, uInt8& value) const; void setBusState(bool& drive, uInt8& value) const;
uInt16 address{0}; uInt16 address{0};
uInt16 mask{0xffff};
uInt8 value{0}; uInt8 value{0};
uInt64 timestamp{0}; uInt64 timestamp{0};
bool yield{false}; bool yield{false};
@ -48,7 +49,7 @@ class BusTransactionQueue {
BusTransactionQueue& injectROMAt(uInt8 value, uInt16 address); BusTransactionQueue& injectROMAt(uInt8 value, uInt16 address);
BusTransactionQueue& stuffByte(uInt8 value, uInt16 address); BusTransactionQueue& stuffByte(uInt8 value, uInt16 address);
BusTransactionQueue& yield(uInt16 address); BusTransactionQueue& yield(uInt16 address, uInt16 mask = 0xffff);
bool hasPendingTransaction() const; bool hasPendingTransaction() const;
Transaction* getNextTransaction(uInt16 address, uInt64 timestamp); Transaction* getNextTransaction(uInt16 address, uInt64 timestamp);

View File

@ -176,6 +176,15 @@ void VcsLib::vcsLda2(uInt8 value)
.injectROM(value); .injectROM(value);
} }
CortexM0::err_t VcsLib::stackOperation(uInt16& value, uInt8& op, uInt8 opcode)
{
myTransactionQueue
.injectROM(opcode)
.yield(0, 0x1000);
return returnFromStub(value, op);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex)
{ {
@ -244,7 +253,17 @@ CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, Cortex
return returnFromStub(value, op); return returnFromStub(value, op);
case ADDR_VCS_WRITE6: case ADDR_VCS_WRITE6:
FatalEmulationError::raise("unimplemented: vcsWrite6"); arg = cortex.getRegister(0);
myTransactionQueue
.injectROM(0xa9)
.injectROM(cortex.getRegister(1))
.injectROM(0x8d)
.injectROM(arg)
.injectROM(arg >> 8)
.yield(arg);
return returnFromStub(value, op);
case ADDR_VCS_LDA2: case ADDR_VCS_LDA2:
vcsLda2(cortex.getRegister(0)); vcsLda2(cortex.getRegister(0));
@ -265,7 +284,14 @@ CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, Cortex
return returnFromStub(value, op); return returnFromStub(value, op);
case ADDR_VCS_SAX3: case ADDR_VCS_SAX3:
FatalEmulationError::raise("unimplemented: vcsSax3"); arg = cortex.getRegister(0);
myTransactionQueue
.injectROM(0x87)
.injectROM(arg)
.yield(arg);
return returnFromStub(value, op);
case ADDR_VCS_STA3: case ADDR_VCS_STA3:
arg = cortex.getRegister(0); arg = cortex.getRegister(0);
@ -371,22 +397,32 @@ CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, Cortex
return returnFromStub(value, op); return returnFromStub(value, op);
case ADDR_VCS_TXS2: case ADDR_VCS_TXS2:
FatalEmulationError::raise("unimplemented: vcsTx2"); myTransactionQueue.injectROM(0x9a);
return returnFromStub(value, op);
case ADDR_VCS_JSR6: case ADDR_VCS_JSR6:
FatalEmulationError::raise("unimplemented: vcsJsr6"); arg = cortex.getRegister(0);
myTransactionQueue
.injectROM(0x20)
.injectROM(arg)
.yield(0, 0x1000)
.injectROM(arg >> 8)
.setNextInjectAddress(arg & 0x1fff);
return returnFromStub(value, op);
case ADDR_VCS_PHA3: case ADDR_VCS_PHA3:
FatalEmulationError::raise("unimplemented: vcsPha3"); return stackOperation(value, op, 0x48);
case ADDR_VCS_PHP3: case ADDR_VCS_PHP3:
FatalEmulationError::raise("unimplemented: vcsPph3"); return stackOperation(value, op, 0x08);
case ADDR_VCS_PLA4: case ADDR_VCS_PLA4:
FatalEmulationError::raise("unimplemented: vcsPla4"); return stackOperation(value, op, 0x68);
case ADDR_VCS_PLP4: case ADDR_VCS_PLP4:
FatalEmulationError::raise("unimplemented: vcsPlp4"); return stackOperation(value, op, 0x28);
case ADDR_VCS_PLA4_EX: case ADDR_VCS_PLA4_EX:
FatalEmulationError::raise("unimplemented: vcsPla4Ex"); FatalEmulationError::raise("unimplemented: vcsPla4Ex");
@ -395,7 +431,15 @@ CortexM0::err_t VcsLib::fetch16(uInt32 address, uInt16& value, uInt8& op, Cortex
FatalEmulationError::raise("unimplemented: vcsPlp4Ex"); FatalEmulationError::raise("unimplemented: vcsPlp4Ex");
case ADDR_VCS_JMP_TO_RAM3: case ADDR_VCS_JMP_TO_RAM3:
FatalEmulationError::raise("unimplemented: vcsJmpToRam3"); arg = cortex.getRegister(0);
myTransactionQueue
.injectROM(0x4c)
.injectROM(arg)
.injectROM(arg >> 8)
.yield(arg);
return returnFromStub(value, op);
case ADDR_VCS_WAIT_FOR_ADDRESS: case ADDR_VCS_WAIT_FOR_ADDRESS:
FatalEmulationError::raise("unimplemented: vcsWaitForAddress"); FatalEmulationError::raise("unimplemented: vcsWaitForAddress");

View File

@ -59,6 +59,8 @@ class VcsLib: public CortexM0::BusTransactionDelegate {
return CortexM0::ERR_NONE; return CortexM0::ERR_NONE;
} }
CortexM0::err_t stackOperation(uInt16& value, uInt8& op, uInt8 opcode);
private: private:
BusTransactionQueue& myTransactionQueue; BusTransactionQueue& myTransactionQueue;