mirror of https://github.com/stella-emu/stella.git
State saves.
This commit is contained in:
parent
d6e7ed151b
commit
fcc05a84fc
|
@ -237,53 +237,8 @@ CartridgeELF::~CartridgeELF() = default;
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeELF::reset()
|
void CartridgeELF::reset()
|
||||||
{
|
{
|
||||||
const bool devMode = mySettings.getBool("dev.settings");
|
setupConfig();
|
||||||
const bool strictMode = devMode && mySettings.getBool("dev.thumb.trapfatal");
|
resetWithConfig();
|
||||||
const uInt32 mips = devMode ? mySettings.getInt("dev.arm.mips") : MIPS_MAX;
|
|
||||||
|
|
||||||
std::fill_n(myLastPeekResult.get(), 0x1000, 0);
|
|
||||||
myIsBusDriven = false;
|
|
||||||
myDriveBusValue = 0;
|
|
||||||
myArmCyclesOffset = 0;
|
|
||||||
myArmCyclesPer6502Cycle = (mips * 1000000) / get6502SpeedHz(myConsoleTiming);
|
|
||||||
|
|
||||||
mySystemType = determineSystemType(myProperties);
|
|
||||||
myLinker->relink(externalSymbols(mySystemType));
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
setupMemoryMap(strictMode);
|
|
||||||
myCortexEmu.reset();
|
|
||||||
|
|
||||||
myTransactionQueue
|
|
||||||
.reset()
|
|
||||||
.injectROMAt(0x00, 0x1ffc)
|
|
||||||
.injectROM(0x10)
|
|
||||||
.setNextInjectAddress(0x1000);
|
|
||||||
|
|
||||||
myVcsLib.reset();
|
|
||||||
|
|
||||||
myVcsLib.vcsCopyOverblankToRiotRam();
|
|
||||||
myVcsLib.vcsStartOverblank();
|
|
||||||
myVcsLib.vcsEndOverblank();
|
|
||||||
myVcsLib.vcsNop2n(1024);
|
|
||||||
|
|
||||||
myExecutionStage = ExecutionStage::boot;
|
|
||||||
myInitFunctionIndex = 0;
|
|
||||||
|
|
||||||
switchExecutionStage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -303,7 +258,28 @@ void CartridgeELF::install(System& system)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool CartridgeELF::save(Serializer& out) const
|
bool CartridgeELF::save(Serializer& out) const
|
||||||
{
|
{
|
||||||
return false;
|
try {
|
||||||
|
out.putBool(myConfigStrictMode);
|
||||||
|
out.putInt(myConfigMips);
|
||||||
|
out.putByte(static_cast<uInt8>(myConfigSystemType));
|
||||||
|
|
||||||
|
out.putBool(myIsBusDriven);
|
||||||
|
out.putByte(myDriveBusValue);
|
||||||
|
out.putLong(myArmCyclesOffset);
|
||||||
|
out.putByte(static_cast<uInt8>(myExecutionStage));
|
||||||
|
out.putInt(myInitFunctionIndex);
|
||||||
|
out.putByte(static_cast<uInt8>(myConsoleTiming));
|
||||||
|
|
||||||
|
myTransactionQueue.save(out);
|
||||||
|
myCortexEmu.save(out);
|
||||||
|
myVcsLib.save(out);
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
cerr << "ERROR: failed to save ELF\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -533,7 +509,7 @@ void CartridgeELF::callMain()
|
||||||
err |= myCortexEmu.write32(sp, myArmCyclesPer6502Cycle * get6502SpeedHz(myConsoleTiming));
|
err |= myCortexEmu.write32(sp, myArmCyclesPer6502Cycle * get6502SpeedHz(myConsoleTiming));
|
||||||
|
|
||||||
sp -= 4;
|
sp -= 4;
|
||||||
err |= myCortexEmu.write32(sp, getSystemTypeParam(mySystemType));
|
err |= myCortexEmu.write32(sp, getSystemTypeParam(myConfigSystemType));
|
||||||
|
|
||||||
if (err) throw runtime_error("unable to setup main args");
|
if (err) throw runtime_error("unable to setup main args");
|
||||||
|
|
||||||
|
@ -651,3 +627,59 @@ CortexM0::err_t CartridgeELF::BusFallbackDelegate::handleError(
|
||||||
|
|
||||||
return CortexM0::ERR_NONE;
|
return CortexM0::ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void CartridgeELF::setupConfig()
|
||||||
|
{
|
||||||
|
const bool devMode = mySettings.getBool("dev.settings");
|
||||||
|
|
||||||
|
myConfigStrictMode = devMode && mySettings.getBool("dev.thumb.trapfatal");
|
||||||
|
myConfigMips = devMode ? mySettings.getInt("dev.arm.mips") : MIPS_MAX;
|
||||||
|
myConfigSystemType = determineSystemType(myProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CartridgeELF::resetWithConfig()
|
||||||
|
{
|
||||||
|
std::fill_n(myLastPeekResult.get(), 0x1000, 0);
|
||||||
|
myIsBusDriven = false;
|
||||||
|
myDriveBusValue = 0;
|
||||||
|
myArmCyclesOffset = 0;
|
||||||
|
myArmCyclesPer6502Cycle = (myConfigMips * 1000000) / get6502SpeedHz(myConsoleTiming);
|
||||||
|
|
||||||
|
myLinker->relink(externalSymbols(myConfigSystemType));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
setupMemoryMap(myConfigStrictMode);
|
||||||
|
myCortexEmu.reset();
|
||||||
|
|
||||||
|
myTransactionQueue
|
||||||
|
.reset()
|
||||||
|
.injectROMAt(0x00, 0x1ffc)
|
||||||
|
.injectROM(0x10)
|
||||||
|
.setNextInjectAddress(0x1000);
|
||||||
|
|
||||||
|
myVcsLib.reset();
|
||||||
|
|
||||||
|
myVcsLib.vcsCopyOverblankToRiotRam();
|
||||||
|
myVcsLib.vcsStartOverblank();
|
||||||
|
myVcsLib.vcsEndOverblank();
|
||||||
|
myVcsLib.vcsNop2n(1024);
|
||||||
|
|
||||||
|
myExecutionStage = ExecutionStage::boot;
|
||||||
|
myInitFunctionIndex = 0;
|
||||||
|
|
||||||
|
switchExecutionStage();
|
||||||
|
}
|
||||||
|
|
|
@ -99,6 +99,9 @@ class CartridgeELF: public Cartridge {
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setupConfig();
|
||||||
|
void resetWithConfig();
|
||||||
|
|
||||||
uInt64 getArmCycles() const;
|
uInt64 getArmCycles() const;
|
||||||
|
|
||||||
uInt8 driveBus(uInt16 address, uInt8 value);
|
uInt8 driveBus(uInt16 address, uInt8 value);
|
||||||
|
@ -120,6 +123,10 @@ class CartridgeELF: public Cartridge {
|
||||||
|
|
||||||
System* mySystem{nullptr};
|
System* mySystem{nullptr};
|
||||||
|
|
||||||
|
bool myConfigStrictMode{false};
|
||||||
|
uInt32 myConfigMips{100};
|
||||||
|
elfEnvironment::SystemType myConfigSystemType{elfEnvironment::SystemType::ntsc};
|
||||||
|
|
||||||
unique_ptr<uint8_t[]> myLastPeekResult;
|
unique_ptr<uint8_t[]> myLastPeekResult;
|
||||||
BusTransactionQueue myTransactionQueue;
|
BusTransactionQueue myTransactionQueue;
|
||||||
|
|
||||||
|
@ -149,8 +156,6 @@ class CartridgeELF: public Cartridge {
|
||||||
ExecutionStage myExecutionStage{ExecutionStage::boot};
|
ExecutionStage myExecutionStage{ExecutionStage::boot};
|
||||||
uInt32 myInitFunctionIndex{0};
|
uInt32 myInitFunctionIndex{0};
|
||||||
|
|
||||||
elfEnvironment::SystemType mySystemType{elfEnvironment::SystemType::ntsc};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
CartridgeELF(const CartridgeELF&) = delete;
|
CartridgeELF(const CartridgeELF&) = delete;
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
|
|
||||||
#include "CortexM0.hxx"
|
#include "CortexM0.hxx"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "Serializable.hxx"
|
||||||
#include "Base.hxx"
|
#include "Base.hxx"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -555,13 +558,66 @@ CortexM0::CortexM0()
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void CortexM0::MemoryRegion::save(Serializer& serializer) const
|
||||||
|
{
|
||||||
|
if (type != MemoryRegionType::directCode && type != MemoryRegionType::directData) return;
|
||||||
|
|
||||||
|
serializer.putBool(dirty);
|
||||||
|
if (!dirty) return;
|
||||||
|
|
||||||
|
serializer.putInt(accessWatermarkLow);
|
||||||
|
serializer.putInt(accessWatermarkHigh);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MemoryRegionType::directCode:
|
||||||
|
serializer.putByteArray(
|
||||||
|
std::get<1>(access).backingStore + (accessWatermarkLow - base),
|
||||||
|
accessWatermarkHigh - accessWatermarkLow + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MemoryRegionType::directData:
|
||||||
|
serializer.putByteArray(
|
||||||
|
std::get<0>(access).backingStore + (accessWatermarkLow - base),
|
||||||
|
accessWatermarkHigh - accessWatermarkLow + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void CortexM0::save(Serializer& serializer) const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 16; i++)
|
||||||
|
serializer.putInt(reg_norm[i]);
|
||||||
|
|
||||||
|
serializer.putInt(znFlags);
|
||||||
|
serializer.putInt(cFlag);
|
||||||
|
serializer.putInt(vFlag);
|
||||||
|
serializer.putLong(myCycleCounter);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < myNextRegionIndex; i++)
|
||||||
|
myRegions[i].save(serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void CortexM0::MemoryRegion::reset()
|
||||||
|
{
|
||||||
|
type = MemoryRegionType::unmapped;
|
||||||
|
access.emplace<std::monostate>();
|
||||||
|
|
||||||
|
accessWatermarkHigh = 0;
|
||||||
|
accessWatermarkLow = ~0;
|
||||||
|
dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
CortexM0& CortexM0::resetMappings()
|
CortexM0& CortexM0::resetMappings()
|
||||||
{
|
{
|
||||||
for (auto& region: myRegions) {
|
for (auto& region: myRegions) region.reset();
|
||||||
region.type = MemoryRegionType::unmapped;
|
|
||||||
region.access.emplace<std::monostate>();
|
|
||||||
}
|
|
||||||
|
|
||||||
myNextRegionIndex = 0;
|
myNextRegionIndex = 0;
|
||||||
std::fill_n(myPageMap.get(), PAGEMAP_SIZE, 0xff);
|
std::fill_n(myPageMap.get(), PAGEMAP_SIZE, 0xff);
|
||||||
|
@ -802,11 +858,25 @@ CortexM0::err_t CortexM0::write32(uInt32 address, uInt32 value)
|
||||||
case MemoryRegionType::delegate:
|
case MemoryRegionType::delegate:
|
||||||
return std::get<2>(region.access)->write32(address, value, *this);
|
return std::get<2>(region.access)->write32(address, value, *this);
|
||||||
|
|
||||||
case MemoryRegionType::directCode:
|
case MemoryRegionType::directCode: {
|
||||||
WRITE32(std::get<1>(region.access).backingStore, address - region.base, value);
|
const uInt32 offset = address - region.base;
|
||||||
|
|
||||||
|
region.dirty = true;
|
||||||
|
region.accessWatermarkLow = std::min(address, region.accessWatermarkLow);
|
||||||
|
region.accessWatermarkHigh = std::max(address + 3, region.accessWatermarkHigh);
|
||||||
|
|
||||||
|
WRITE32(std::get<1>(region.access).backingStore, offset, value);
|
||||||
|
std::get<1>(region.access).ops[offset >> 1] = decodeInstructionWord(value);
|
||||||
|
std::get<1>(region.access).ops[(offset + 2) >> 1] = decodeInstructionWord(value >> 16);
|
||||||
|
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
case MemoryRegionType::directData:
|
case MemoryRegionType::directData:
|
||||||
|
region.dirty = true;
|
||||||
|
region.accessWatermarkLow = std::min(address, region.accessWatermarkLow);
|
||||||
|
region.accessWatermarkHigh = std::max(address + 3, region.accessWatermarkHigh);
|
||||||
|
|
||||||
WRITE32(std::get<0>(region.access).backingStore, address - region.base, value);
|
WRITE32(std::get<0>(region.access).backingStore, address - region.base, value);
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
|
|
||||||
|
@ -832,6 +902,10 @@ CortexM0::err_t CortexM0::write16(uInt32 address, uInt16 value)
|
||||||
case MemoryRegionType::directCode: {
|
case MemoryRegionType::directCode: {
|
||||||
const uInt32 offset = address - region.base;
|
const uInt32 offset = address - region.base;
|
||||||
|
|
||||||
|
region.dirty = true;
|
||||||
|
region.accessWatermarkLow = std::min(address, region.accessWatermarkLow);
|
||||||
|
region.accessWatermarkHigh = std::max(address + 1, region.accessWatermarkHigh);
|
||||||
|
|
||||||
WRITE16(std::get<1>(region.access).backingStore, offset, value);
|
WRITE16(std::get<1>(region.access).backingStore, offset, value);
|
||||||
std::get<1>(region.access).ops[offset >> 1] = decodeInstructionWord(value);
|
std::get<1>(region.access).ops[offset >> 1] = decodeInstructionWord(value);
|
||||||
|
|
||||||
|
@ -839,6 +913,10 @@ CortexM0::err_t CortexM0::write16(uInt32 address, uInt16 value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case MemoryRegionType::directData:
|
case MemoryRegionType::directData:
|
||||||
|
region.dirty = true;
|
||||||
|
region.accessWatermarkLow = std::min(address, region.accessWatermarkLow);
|
||||||
|
region.accessWatermarkHigh = std::max(address + 1, region.accessWatermarkHigh);
|
||||||
|
|
||||||
WRITE16(std::get<0>(region.access).backingStore, address - region.base, value);
|
WRITE16(std::get<0>(region.access).backingStore, address - region.base, value);
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
|
|
||||||
|
@ -862,6 +940,10 @@ CortexM0::err_t CortexM0::write8(uInt32 address, uInt8 value)
|
||||||
case MemoryRegionType::directCode: {
|
case MemoryRegionType::directCode: {
|
||||||
const uInt32 offset = address - region.base;
|
const uInt32 offset = address - region.base;
|
||||||
|
|
||||||
|
region.dirty = true;
|
||||||
|
region.accessWatermarkLow = std::min(address, region.accessWatermarkLow);
|
||||||
|
region.accessWatermarkHigh = std::max(address, region.accessWatermarkHigh);
|
||||||
|
|
||||||
std::get<1>(region.access).backingStore[offset] = value;
|
std::get<1>(region.access).backingStore[offset] = value;
|
||||||
std::get<1>(region.access).ops[offset >> 1] = decodeInstructionWord(value);
|
std::get<1>(region.access).ops[offset >> 1] = decodeInstructionWord(value);
|
||||||
|
|
||||||
|
@ -869,6 +951,10 @@ CortexM0::err_t CortexM0::write8(uInt32 address, uInt8 value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case MemoryRegionType::directData:
|
case MemoryRegionType::directData:
|
||||||
|
region.dirty = true;
|
||||||
|
region.accessWatermarkLow = std::min(address, region.accessWatermarkLow);
|
||||||
|
region.accessWatermarkHigh = std::max(address, region.accessWatermarkHigh);
|
||||||
|
|
||||||
std::get<0>(region.access).backingStore[address - region.base] = value;
|
std::get<0>(region.access).backingStore[address - region.base] = value;
|
||||||
return ERR_NONE;
|
return ERR_NONE;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
class Serializer;
|
||||||
|
|
||||||
class CortexM0
|
class CortexM0
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -116,6 +118,8 @@ class CortexM0
|
||||||
|
|
||||||
CortexM0& mapDefault(BusTransactionDelegate* delegate);
|
CortexM0& mapDefault(BusTransactionDelegate* delegate);
|
||||||
|
|
||||||
|
void save(Serializer& serializer) const;
|
||||||
|
|
||||||
CortexM0& reset();
|
CortexM0& reset();
|
||||||
CortexM0& setPc(uInt32 pc);
|
CortexM0& setPc(uInt32 pc);
|
||||||
CortexM0& setRegister(uInt8 regno, uInt32 value);
|
CortexM0& setRegister(uInt8 regno, uInt32 value);
|
||||||
|
@ -165,6 +169,10 @@ class CortexM0
|
||||||
uInt32 size{0};
|
uInt32 size{0};
|
||||||
bool readOnly{false};
|
bool readOnly{false};
|
||||||
|
|
||||||
|
bool dirty{false};
|
||||||
|
uInt32 accessWatermarkLow{static_cast<uInt32>(~0)};
|
||||||
|
uInt32 accessWatermarkHigh{0};
|
||||||
|
|
||||||
std::variant<
|
std::variant<
|
||||||
MemoryRegionAccessData, // ::get<0>, directData
|
MemoryRegionAccessData, // ::get<0>, directData
|
||||||
MemoryRegionAccessCode, // ::get<1>, directCode
|
MemoryRegionAccessCode, // ::get<1>, directCode
|
||||||
|
@ -172,6 +180,9 @@ class CortexM0
|
||||||
std::monostate
|
std::monostate
|
||||||
> access;
|
> access;
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void save(Serializer& serializer) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryRegion(const MemoryRegion&) = delete;
|
MemoryRegion(const MemoryRegion&) = delete;
|
||||||
MemoryRegion(MemoryRegion&&) = delete;
|
MemoryRegion(MemoryRegion&&) = delete;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "BusTransactionQueue.hxx"
|
#include "BusTransactionQueue.hxx"
|
||||||
|
|
||||||
|
#include "Serializable.hxx"
|
||||||
#include "exception/FatalEmulationError.hxx"
|
#include "exception/FatalEmulationError.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -64,6 +65,27 @@ BusTransactionQueue& BusTransactionQueue::reset()
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void BusTransactionQueue::save(Serializer& serializer) const
|
||||||
|
{
|
||||||
|
serializer.putInt(myQueueSize);
|
||||||
|
serializer.putShort(myNextInjectAddress);
|
||||||
|
serializer.putLong(myTimestamp);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < myQueueSize; i++)
|
||||||
|
myQueue[(myQueueNext + i) % myQueueCapacity].save(serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void BusTransactionQueue::Transaction::save(Serializer& serializer) const
|
||||||
|
{
|
||||||
|
serializer.putShort(address);
|
||||||
|
serializer.putShort(mask);
|
||||||
|
serializer.putByte(value);
|
||||||
|
serializer.putLong(timestamp);
|
||||||
|
serializer.putBool(yield);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
BusTransactionQueue& BusTransactionQueue::setNextInjectAddress(uInt16 address)
|
BusTransactionQueue& BusTransactionQueue::setNextInjectAddress(uInt16 address)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
class Serializer;
|
||||||
|
|
||||||
class BusTransactionQueue {
|
class BusTransactionQueue {
|
||||||
public:
|
public:
|
||||||
struct Transaction {
|
struct Transaction {
|
||||||
|
@ -33,6 +35,8 @@ class BusTransactionQueue {
|
||||||
uInt8 value{0};
|
uInt8 value{0};
|
||||||
uInt64 timestamp{0};
|
uInt64 timestamp{0};
|
||||||
bool yield{false};
|
bool yield{false};
|
||||||
|
|
||||||
|
void save(Serializer& serializer) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -41,6 +45,8 @@ class BusTransactionQueue {
|
||||||
|
|
||||||
BusTransactionQueue& reset();
|
BusTransactionQueue& reset();
|
||||||
|
|
||||||
|
void save(Serializer& serializer) const;
|
||||||
|
|
||||||
BusTransactionQueue& setNextInjectAddress(uInt16 address);
|
BusTransactionQueue& setNextInjectAddress(uInt16 address);
|
||||||
uInt16 getNextInjectAddress() const;
|
uInt16 getNextInjectAddress() const;
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,21 @@ VcsLib::VcsLib(BusTransactionQueue& transactionQueue)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void VcsLib::save(Serializer& serializer) const
|
||||||
|
{
|
||||||
|
serializer.putByte(myStuffMaskA);
|
||||||
|
serializer.putByte(myStuffMaskX);
|
||||||
|
serializer.putByte(myStuffMaskY);
|
||||||
|
serializer.putBool(myIsWaitingForRead);
|
||||||
|
serializer.putShort(myWaitingForReadAddress);
|
||||||
|
serializer.putShort(myCurrentAddress);
|
||||||
|
serializer.putBool(myCurrentValue);
|
||||||
|
|
||||||
|
if (!myRand.save(serializer))
|
||||||
|
throw runtime_error("failed to save RNG");
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void VcsLib::reset()
|
void VcsLib::reset()
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,11 +23,15 @@
|
||||||
#include "CortexM0.hxx"
|
#include "CortexM0.hxx"
|
||||||
#include "BusTransactionQueue.hxx"
|
#include "BusTransactionQueue.hxx"
|
||||||
|
|
||||||
|
class Serializer;
|
||||||
|
|
||||||
class VcsLib: public CortexM0::BusTransactionDelegate {
|
class VcsLib: public CortexM0::BusTransactionDelegate {
|
||||||
public:
|
public:
|
||||||
explicit VcsLib(BusTransactionQueue& transactionQueue);
|
explicit VcsLib(BusTransactionQueue& transactionQueue);
|
||||||
~VcsLib() override = default;
|
~VcsLib() override = default;
|
||||||
|
|
||||||
|
void save(Serializer& serializer) const;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
CortexM0::err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) override;
|
CortexM0::err_t fetch16(uInt32 address, uInt16& value, uInt8& op, CortexM0& cortex) override;
|
||||||
|
|
Loading…
Reference in New Issue