Core: Makes several fixes and general improvements to the code

This commit is contained in:
Gabriel Correia 2024-06-21 17:51:00 -03:00
parent 2ab9f469f1
commit 930a881139
47 changed files with 294 additions and 300 deletions

View File

@ -10,33 +10,20 @@
#include <common/alias.h>
namespace cosmic {
template <typename T>
class Ref {
class Optional : public std::optional<std::reference_wrapper<T>> {
public:
Ref() = default;
Ref(T& save) {
safe = save;
Optional() = default;
Optional(T& reference) : std::optional<std::reference_wrapper<T>>(reference) {
}
auto operator=(std::reference_wrapper<T>& wrapper) {
safe = wrapper;
return *this;
auto take() const {
return this->value().get();
}
auto operator=(std::reference_wrapper<T> wrapper) noexcept {
safe = wrapper;
return *this;
auto take() {
return std::addressof(this->value().get());
}
auto operator->() {
return &(safe.value().get());
return &this->value().get();
}
T& operator*() {
return safe->get();
}
explicit operator bool() const {
if (!safe.has_value())
return false;
return std::addressof(safe.value().get()) != nullptr;
}
private:
std::optional<std::reference_wrapper<T>> safe;
};
template<class To, class From>

View File

@ -5,11 +5,11 @@ namespace cosmic {
}
namespace cosmic::console {
BackDoor::BackDoor(vm::EmuVm& aliveVm) {
vm = std::make_unique<Ref<vm::EmuVm>>(std::ref(aliveVm));
vm = Optional(aliveVm);
echo.lock();
vmRefs = 1;
}
Ref<vm::EmuVm> BackDoor::openVm() {
Optional<vm::EmuVm> BackDoor::openVm() {
std::thread::id nub{};
if (owner == nub && owner != std::this_thread::get_id()) {
while (echo.try_lock()) {
@ -22,14 +22,14 @@ namespace cosmic::console {
}
if (owner != std::this_thread::get_id())
throw AppErr("This resource should have the lock held until the object is released");
Ref<vm::EmuVm> vmRef{};
Optional<vm::EmuVm> vmRef{};
if (vmRefs) {
vmRef = *vm;
vmRef = vm;
vmRefs++;
}
return vmRef;
}
void BackDoor::leaveVm(Ref<vm::EmuVm> lvm) {
void BackDoor::leaveVm(Optional<vm::EmuVm>& lvm) {
if (echo.try_lock()) {
if (owner != std::this_thread::get_id())
throw AppErr("The program flow is broken, review the usage of BackDoor in the code");
@ -37,7 +37,7 @@ namespace cosmic::console {
vmRefs--;
if (!vm || vmRefs <= 0) {
vm.reset();
vm = std::make_unique<Ref<vm::EmuVm>>(lvm);
vm = Optional(lvm);
vmRefs = 1;
}
owner = {};

View File

@ -10,12 +10,12 @@ namespace cosmic::console {
class BackDoor {
public:
BackDoor(vm::EmuVm& aliveVm);
Ref<vm::EmuVm> openVm();
void leaveVm(Ref<vm::EmuVm> lvm);
Optional<vm::EmuVm> openVm();
void leaveVm(Optional<vm::EmuVm>& lvm);
private:
std::thread::id owner;
std::mutex echo;
std::unique_ptr<Ref<vm::EmuVm>> vm;
Optional<vm::EmuVm> vm;
i32 vmRefs;
};
}

View File

@ -28,8 +28,7 @@ namespace cosmic::console {
return false;
std::array<u8, 16> romGroup;
if (!loadVersionInfo(getModule("ROMVER"), romGroup)) {
if (!loadVersionInfo(romGroup)) {
throw FsErr("Cannot load the ROM version information, group : {}", fmt::join(romGroup, ", "));
}
bios.dataCRC = cpu::check32(romGroup);
@ -47,14 +46,14 @@ namespace cosmic::console {
biosf.readFrom(here, 0);
romHeader.release();
}
Ref<RomEntry> BiosLoader::getModule(const std::string model) {
Optional<RomEntry> BiosLoader::getModule(const std::string model) {
std::span<u8> modelBin{BitCast<u8*>(model.c_str()), model.size()};
std::span<u8> hdrBin{romHeader->operator*(), hdrSize};
auto indexInt{ranges::search(hdrBin, modelBin)};
return *BitCast<RomEntry*>(indexInt.data());
}
bool BiosLoader::loadVersionInfo(Ref<RomEntry>, std::span<u8> info) {
bool BiosLoader::loadVersionInfo(std::span<u8> info) {
auto reset{getModule("RESET")};
auto directory{getModule("ROMDIR")};
@ -67,7 +66,7 @@ namespace cosmic::console {
u32 verOffset{};
// RESET -> ROMDIR->SIZE
u64 range{BitCast<u64>(std::addressof(*version) - std::addressof(*reset))};
std::span<RomEntry> entities{std::addressof(*reset), range};
std::span<RomEntry> entities{reset.take(), range};
if (!entities.size())
return false;

View File

@ -26,8 +26,8 @@ namespace cosmic::console {
private:
bool isABios();
Ref<RomEntry> getModule(const std::string model);
bool loadVersionInfo(Ref<RomEntry> entry, std::span<u8> info);
Optional<RomEntry> getModule(const std::string model);
bool loadVersionInfo(std::span<u8> info);
void fillVersion(hle::BiosInfo& bios, std::span<char> info);
DescriptorRaii biosf{};

View File

@ -30,8 +30,8 @@ namespace cosmic::console {
gif = std::make_shared<gs::GifBridge>(gs);
mio::HardWithDmaCap caps{};
caps.vif0 = std::ref(VUs->vifs[0]);
caps.vif1 = std::ref(VUs->vifs[1]);
caps.vif0 = Optional(VUs->vifs[0]);
caps.vif1 = Optional(VUs->vifs[1]);
caps.ee = eeR5900;
pipe->controller->connectDevices(caps);

View File

@ -32,7 +32,7 @@ namespace cosmic::creeper {
auto endIterator{std::end(run)};
for (; opIterator != run.end(); executedInst++) {
Ref<CachedMultiOp> opcInside{*opIterator};
Optional<CachedMultiOp> opcInside{*opIterator};
bool isLastABr{false};
// Todo: May not work as expected
if (opIterator != run.begin()) {
@ -57,7 +57,7 @@ namespace cosmic::creeper {
if ((opIterator + 1) != endIterator) {
// Simulating the pipeline execution with the aim of resolving one or more instructions
// within the same cycle
Ref<CachedMultiOp> opcSuper{*(opIterator + 1)};
Optional<CachedMultiOp> opcSuper{*(opIterator + 1)};
// Execute only two instructions if the operations use different pipelines
if (((opcInside->infoCallable.pipe ^ opcSuper->infoCallable.pipe) != invPipe) &&
opcSuper->infoCallable.pipe != dangerousPipe) {
@ -102,7 +102,7 @@ namespace cosmic::creeper {
block = localPc32;
}
}
MipsIvInterpreter::MipsIvInterpreter(Ref<ee::EeMipsCore> mips) :
MipsIvInterpreter::MipsIvInterpreter(Optional<ee::EeMipsCore> mips) :
ee::EeExecutor(mips) {
lastCleaned = actualPc = 0;
memset(metrics.data(), 0, sizeof(metrics));
@ -115,8 +115,8 @@ namespace cosmic::creeper {
auto vmRef{outside->openVm()};
vm = vmRef;
fpu = std::ref(cpu->cop1);
c0 = std::ref(cpu->cop0);
fpu = Optional(cpu->cop1);
c0 = Optional(cpu->cop0);
outside->leaveVm(vmRef);
}
@ -127,16 +127,16 @@ namespace cosmic::creeper {
PCs[0] = cpu->eePc;
actualPc = PCs[0];
PCs[1] = PCs[0] & cleanPcBlock;
Ref<BlockFrequency> chosen{};
Optional<BlockFrequency> chosen{};
ranges::for_each(metrics, [&](auto& met){
if (met.blockPc == PCs[1])
chosen = std::ref(met);
chosen = Optional(met);
});
bool isCached{true};
if (!chosen) {
// Choosing the metric with the lowest frequency number
std::sort(metrics.begin(), metrics.end());
chosen = std::ref(metrics[0]);
chosen = Optional(metrics[0]);
isCached = false;
}
[[unlikely]] if (!isCached) {

View File

@ -78,7 +78,7 @@ namespace cosmic::creeper {
class MipsIvInterpreter : public ee::EeExecutor {
public:
MipsIvInterpreter(Ref<ee::EeMipsCore> mips);
MipsIvInterpreter(Optional<ee::EeMipsCore> mips);
u32 executeCode() override;
void performInvalidation(u32 address) override;
@ -184,10 +184,10 @@ namespace cosmic::creeper {
u32 lastCleaned;
u32 actualPc;
static Ref<ee::EeMipsCore> cpu;
static Ref<vm::EmuVm> vm;
static Ref<ee::FpuCop> fpu;
static Ref<ee::CtrlCop> c0;
static Optional<ee::EeMipsCore> cpu;
static Optional<vm::EmuVm> vm;
static Optional<ee::FpuCop> fpu;
static Optional<ee::CtrlCop> c0;
static EeMapSpecial ivSpecial;
static EeRegImm ivRegImm;

View File

@ -208,10 +208,10 @@ namespace cosmic::creeper {
const u32 opcode{cpu->fetchByAddress(pc)};
return opcode;
}
Ref<EeMipsCore> MipsIvInterpreter::cpu;
Ref<vm::EmuVm> MipsIvInterpreter::vm;
Ref<FpuCop> MipsIvInterpreter::fpu;
Ref<CtrlCop> MipsIvInterpreter::c0;
Optional<EeMipsCore> MipsIvInterpreter::cpu;
Optional<vm::EmuVm> MipsIvInterpreter::vm;
Optional<FpuCop> MipsIvInterpreter::fpu;
Optional<CtrlCop> MipsIvInterpreter::c0;
u32& MipsIvInterpreter::doReg(const Reg regId) {
return cpu->GPRs[regId].words[0];

View File

@ -13,18 +13,22 @@ namespace cosmic::creeper {
void MipsIvInterpreter::c0mfc(Operands ops) {
if (!ops.rd)
return;
auto res = c0->mfc0(ops.rd);
auto res{c0->mfc0(ops.rd)};
cpu->GPRs[ops.rt].words[0] = res;
}
void MipsIvInterpreter::c0mtc(Operands ops) {
std::array<Ref<u32>, 2> c0mop{
std::array<u32, 2> c0mop{
cpu->GPRs[ops.rd].words[0],
cpu->GPRs[ops.rt].words[0]
};
if (*c0mop[0] != 14 && *c0mop[0] != 30) {
if (c0mop[0] && c0mop[0] != 14) {
}
c0->mtc0(static_cast<u8>(*c0mop[0]), *c0mop[1]);
if (c0mop[1] && c0mop[1] != 30) {
}
u32 posDest{c0mop[0]};
u32 setValue{c0mop[1]};
c0->mtc0(static_cast<u8>(posDest), setValue);
}
// bc0f, bc0t, bc0fl, bc0tl

View File

@ -219,9 +219,9 @@ namespace cosmic::creeper {
}
}
IopInterpreter::IopInterpreter(
Ref<iop::IoMipsCore> core) :
Optional<iop::IoMipsCore> core) :
IopExecVe(core) {
Ref<vm::EmuVm> vmInter{outside->openVm()};
Optional<vm::EmuVm> vmInter{outside->openVm()};
vm = vmInter;
outside->leaveVm(vm);

View File

@ -9,7 +9,7 @@ namespace cosmic::vm {
namespace cosmic::creeper {
class IopInterpreter : public iop::IopExecVe {
public:
IopInterpreter(Ref<iop::IoMipsCore> core);
IopInterpreter(Optional<iop::IoMipsCore> core);
u32 executeCode() override;
u32 execPsx(u32 opcode, std::array<u8, 3> opeRegs);
u32 execCop(u32 opcode, std::array<u8, 3> opeRegs);
@ -19,7 +19,7 @@ namespace cosmic::creeper {
CachedFastPc fastPc;
u32 fetchPcInst() override;
Ref<vm::EmuVm> vm;
Optional<vm::EmuVm> vm;
void issueInterruptSignal();
void sltiu(Operands ops);

View File

@ -1,7 +1,7 @@
#include <creeper/vector_codes.h>
#include <vu/vecu.h>
namespace cosmic::creeper {
Ref<vu::VectorUnit> VuMicroInterpreter::vu;
Optional<vu::VectorUnit> VuMicroInterpreter::vu;
u32 VuMicroInterpreter::executeCode() {
VuMicroOperands ops[2];

View File

@ -26,7 +26,7 @@ namespace cosmic::creeper {
class VuMicroInterpreter : public vu::VuMicroExecutor {
public:
VuMicroInterpreter(vu::VectorUnit& vuCake) :
VuMicroInterpreter(Optional<vu::VectorUnit> vuCake) :
vu::VuMicroExecutor(vuCake) {
vu = vuMicro;
}
@ -57,6 +57,6 @@ namespace cosmic::creeper {
private:
VuMicroOrder ordered;
static Ref<vu::VectorUnit> vu;
static Optional<vu::VectorUnit> vu;
};
}

View File

@ -103,7 +103,7 @@ namespace cosmic::ee {
void rectifyTimer(u32 pulseCycles);
bool isCacheHit(u32 address, u8 lane, CacheMode mode = Instruction);
os::vec readCache(u32 address, CacheMode mode = Instruction);
const os::vec& readCache(u32 address, CacheMode mode = Instruction);
void assignFlushedCache(CopCacheLine& eec, u32 tag, CacheMode mode = Instruction);
void loadCacheLine(u32 address, EeMipsCore& core, CacheMode mode = Instruction);
u32 getCachePfn(u32 address, CacheMode mode = Instruction);
@ -132,7 +132,7 @@ namespace cosmic::ee {
bool isIntEnabled();
private:
void incPerfByEvent(u32 mask, u32 cycles, u8 perfEv);
Ref<CopCacheLine> getCache(u32 mem, bool write, CacheMode mode = Instruction);
CopCacheLine& getCache(u32 mem, bool write, CacheMode mode = Instruction);
std::array<CopCacheLine, 128> inCache;
std::array<CopCacheLine, 64> dataCache;

View File

@ -4,49 +4,47 @@
namespace cosmic::ee {
// We don't check for a cache miss here
os::vec CtrlCop::readCache(u32 address, CacheMode mode) {
const os::vec& CtrlCop::readCache(u32 address, CacheMode mode) {
auto tagAddr{getCachePfn(address, mode)};
auto cache{getCache(address, false, mode)};
u8 fix{};
auto cachedData{getCache(address, false, mode)};
u8 lineLayer{};
tagAddr |= dirtyBit;
if (cache->tags[0] == tagAddr)
fix = 1;
else if (cache->tags[1] == tagAddr)
fix = 2;
if (cachedData.tags[0] == tagAddr)
lineLayer = 1;
else if (cachedData.tags[1] == tagAddr)
lineLayer = 2;
if (!fix) {
if (!lineLayer) {
throw Cop0Err("Address {} isn't cached or doesn't have a valid tag referencing it", address);
}
const auto& cont{cache->ec[fix - 1]};
const auto& cont{cachedData.ec[lineLayer - 1]};
return cont.vec[(address >> 4) & 3];
}
void CtrlCop::invIndexed(u32 address) {
auto cc{getCache(address, true)};
cc->tags[0] &= ~dirtyBit;
cc->tags[1] &= ~dirtyBit;
cc->lrf[0] = cc->lrf[1] = {
cc.tags[0] &= ~dirtyBit;
cc.tags[1] &= ~dirtyBit;
cc.lrf[0] = cc.lrf[1] = {
};
std::memset(cc->ec.data(), 0, sizeof(cc->ec));
std::memset(cc.ec.data(), 0, sizeof(cc.ec));
}
bool CtrlCop::isCacheHit(u32 address, u8 lane, CacheMode mode) {
// Each cache line is indexed by virtual address
auto addrTag{getCachePfn(address, mode)};
auto highway{getCache(address, false, mode)};
if (!highway)
return {};
addrTag |= dirtyBit;
switch (lane) {
case 0:
return highway->tags[0] == addrTag;
return highway.tags[0] == addrTag;
case 1:
return highway->tags[1] == addrTag;
return highway.tags[1] == addrTag;
case 2:
return
highway->tags[0] == addrTag ||
highway->tags[1] == addrTag;
highway.tags[0] == addrTag ||
highway.tags[1] == addrTag;
}
return {};
}
@ -56,19 +54,19 @@ namespace cosmic::ee {
auto pear{
getCache(address, true, mode)};
assignFlushedCache(*pear, masterIndex);
assignFlushedCache(pear, masterIndex);
masterIndex |= dirtyBit;
if ((pear->tags[0] != masterIndex && pear->tags[1] != masterIndex)) {
throw Cop0Err(
"No portion of the cache line {:#x} was properly selected! Tags: {:#x}",
masterIndex, fmt::join(pear->tags, ", "));
if ((pear.tags[0] != masterIndex &&
pear.tags[1] != masterIndex)) {
throw Cop0Err("No portion of the cache line {:#x} was properly selected! Tags: {:#x}",
masterIndex, fmt::join(pear.tags, ", "));
}
// Due to the LRF algorithm, we will write to the way that was written last (thus keeping
// the last data among the ways in the cache, waiting for one more miss)
u8 way{pear->lrf[0] && !pear->lrf[1]};
u8 way{pear.lrf[0] && !pear.lrf[1]};
if (!way) {
if (!pear->lrf[0] && pear->lrf[1])
if (!pear.lrf[0] && pear.lrf[1])
way = 2;
}
if (!way)
@ -78,17 +76,17 @@ namespace cosmic::ee {
switch (way) {
case 0xff:
pear->ec[1].vec[1] = core.mipsRead<os::vec>((address + 64));
pear->ec[1].vec[1] = core.mipsRead<os::vec>((address + 64) + 16);
pear->ec[1].vec[2] = core.mipsRead<os::vec>((address + 64) + 16 * 2);
pear->ec[1].vec[3] = core.mipsRead<os::vec>((address + 64) + 16 * 3);
pear.ec[1].vec[1] = core.mipsRead<os::vec>((address + 64));
pear.ec[1].vec[1] = core.mipsRead<os::vec>((address + 64) + 16);
pear.ec[1].vec[2] = core.mipsRead<os::vec>((address + 64) + 16 * 2);
pear.ec[1].vec[3] = core.mipsRead<os::vec>((address + 64) + 16 * 3);
missPenalty *= 4;
way = 1;
case 1 ... 2:
pear->ec[way - 1].vec[0] = core.mipsRead<os::vec>(address + 0);
pear->ec[way - 1].vec[1] = core.mipsRead<os::vec>(address + 16);
pear->ec[way - 1].vec[2] = core.mipsRead<os::vec>(address + 16 * 2);
pear->ec[way - 1].vec[3] = core.mipsRead<os::vec>(address + 16 * 3);
pear.ec[way - 1].vec[0] = core.mipsRead<os::vec>(address + 0);
pear.ec[way - 1].vec[1] = core.mipsRead<os::vec>(address + 16);
pear.ec[way - 1].vec[2] = core.mipsRead<os::vec>(address + 16 * 2);
pear.ec[way - 1].vec[3] = core.mipsRead<os::vec>(address + 16 * 3);
if (way != 0xff)
missPenalty *= 2;
@ -126,48 +124,49 @@ namespace cosmic::ee {
// Here is where we write the tag bits
eec.tags[assign] = tag | dirtyBit;
}
Ref<CopCacheLine> CtrlCop::getCache(u32 mem, bool write, CacheMode mode) {
std::array<Ref<u8*>, 2> wb;
u32 ci;
std::span<CopCacheLine> cc;
CopCacheLine& CtrlCop::getCache(u32 mem, bool write, CacheMode mode) {
u32 cacheIndex;
std::span<CopCacheLine> selectedCache;
if (mode == Instruction) {
ci = (mem >> 6) & 0x7f;
cc = inCache;
cacheIndex = (mem >> 6) & 0x7f;
selectedCache = inCache;
} else {
ci = (mem >> 6) & 0x3f;
cc = dataCache;
cacheIndex = (mem >> 6) & 0x3f;
selectedCache = dataCache;
}
wb[0] = Ref(virtMap[cc[ci].tags[0] >> 12]);
std::array<bool, 2> valid{
cc[ci].lrf[0],
cc[ci].lrf[1]
std::array<Optional<u8*>, 2> wb{
Optional(virtMap[selectedCache[cacheIndex].tags[0] >> 12]),
Optional(virtMap[selectedCache[cacheIndex].tags[1] >> 12])
};
std::array<bool, 2> valid{
selectedCache[cacheIndex].lrf[0],
selectedCache[cacheIndex].lrf[1]
};
wb[1] = Ref(virtMap[cc[ci].tags[1] >> 12]);
if (*wb[0] == virtMap[mem >> 12] && valid[0])
return cc[ci];
return selectedCache[cacheIndex];
if (*wb[1] == virtMap[mem >> 12] && valid[1])
return cc[ci];
return selectedCache[cacheIndex];
const u32 way{(
(cc[ci].tags[0] >> 6) & 1) ^ ((cc[ci].tags[1] >> 6) & 1)
(selectedCache[cacheIndex].tags[0] >> 6) & 1) ^ ((selectedCache[cacheIndex].tags[1] >> 6) & 1)
};
const auto isDirty{static_cast<bool>(cc[ci].tags[way] & dirtyBit)};
const auto isDirty{static_cast<bool>(selectedCache[cacheIndex].tags[way] & dirtyBit)};
if (write && mode == Data && isDirty) {
uintptr_t wrm{*(*wb[way]) + (mem & 0xfc0)};
BitCast<u64*>(wrm)[0] = cc[ci].ec[way].large[0];
BitCast<u64*>(wrm)[1] = cc[ci].ec[way].large[1];
BitCast<u64*>(wrm)[2] = cc[ci].ec[way].large[2];
BitCast<u64*>(wrm)[3] = cc[ci].ec[way].large[3];
BitCast<u64*>(wrm)[4] = cc[ci].ec[way].large[4];
BitCast<u64*>(wrm)[5] = cc[ci].ec[way].large[5];
BitCast<u64*>(wrm)[6] = cc[ci].ec[way].large[6];
BitCast<u64*>(wrm)[7] = cc[ci].ec[way].large[7];
BitCast<u64*>(wrm)[0] = selectedCache[cacheIndex].ec[way].large[0];
BitCast<u64*>(wrm)[1] = selectedCache[cacheIndex].ec[way].large[1];
BitCast<u64*>(wrm)[2] = selectedCache[cacheIndex].ec[way].large[2];
BitCast<u64*>(wrm)[3] = selectedCache[cacheIndex].ec[way].large[3];
BitCast<u64*>(wrm)[4] = selectedCache[cacheIndex].ec[way].large[4];
BitCast<u64*>(wrm)[5] = selectedCache[cacheIndex].ec[way].large[5];
BitCast<u64*>(wrm)[6] = selectedCache[cacheIndex].ec[way].large[6];
BitCast<u64*>(wrm)[7] = selectedCache[cacheIndex].ec[way].large[7];
}
if (write) {
// If we are writing to the cache, the dirty bit must be set
cc[ci].tags[way] |= dirtyBit;
selectedCache[cacheIndex].tags[way] |= dirtyBit;
}
return cc[ci];
return selectedCache[cacheIndex];
}
}

View File

@ -102,7 +102,7 @@ namespace cosmic::ee {
cached.isValid = currBase == cached.basePc;
if (!cached.isValid) {
auto fasterInstructions{cop0.readCache(address)};
const auto fasterInstructions{cop0.readCache(address)};
cached[0] = fasterInstructions.to32(0);
cached[4] = fasterInstructions.to32(1);
cached[8] = fasterInstructions.to32(2);
@ -124,9 +124,9 @@ namespace cosmic::ee {
if (executor)
executor.reset();
if (cpuMode == CachedInterpreter) {
executor = std::make_unique<creeper::MipsIvInterpreter>(*this);
executor = std::make_unique<creeper::MipsIvInterpreter>(Optional(*this));
} else if (cpuMode == JitRe) {
executor = std::make_unique<fishron::EeArm64Jitter>(*this);
executor = std::make_unique<fishron::EeArm64Jitter>(Optional(*this));
}
});
}
@ -140,7 +140,7 @@ namespace cosmic::ee {
if (!cond)
return;
isABranch = cond;
i64 pc{static_cast<i64>(eePc) + jumpRel + 4};
const auto pc{static_cast<i64>(eePc) + jumpRel + 4};
eePc = static_cast<u32>(pc);
delaySlot = 1;
}

View File

@ -5,14 +5,14 @@ namespace cosmic::ee {
class EeMipsCore;
class EeExecutor {
public:
EeExecutor(Ref<EeMipsCore> mips) :
EeExecutor(Optional<EeMipsCore>& mips) :
eeCpu(mips) {}
virtual u32 executeCode() = 0;
virtual u32 fetchPcInst(u32 pc) = 0;
virtual void performInvalidation(u32 address) = 0;
virtual ~EeExecutor() = default;
protected:
Ref<EeMipsCore> eeCpu;
Optional<EeMipsCore> eeCpu;
};
enum MipsRegsHw : u8 {

View File

@ -5,7 +5,7 @@
namespace cosmic::fishron {
class EeArm64Jitter : public ee::EeExecutor {
public:
EeArm64Jitter(ee::EeMipsCore& intCpu) :
EeArm64Jitter(Optional<ee::EeMipsCore> intCpu) :
EeExecutor(intCpu) {}
u32 executeCode() override;
u32 fetchPcInst(u32 address) override;

View File

@ -1,10 +1,10 @@
#include <common/global.h>
#include <gpu/graphics_layer.h>
namespace cosmic::gpu {
static void displayVersion(Ref<GraphicsLayer> gpu) {
static void displayVersion(GraphicsLayer& gpu) {
#if !defined(NDEBUG)
if (gpu->graphicsApi == HardwareVulkan) {
u32 version{gpu->app->enumerateInstanceVersion()};
if (gpu.graphicsApi == HardwareVulkan) {
u32 version{gpu.app->enumerateInstanceVersion()};
std::array<u32, 3> vkVA64{
version >> 22 & 0x3ff, version >> 12 & 0x3ff, version & 0xfff};
user->info("Vulkan version: {}", fmt::join(vkVA64, "."));
@ -46,25 +46,25 @@ namespace cosmic::gpu {
});
displayApiVersion = displayVersion;
}
static void startVulkanLayer(Ref<GraphicsLayer> gpu) {
gpu->app.reset();
gpu->instance.reset();
static void startVulkanLayer(GraphicsLayer& gpu) {
gpu.app.reset();
gpu.instance.reset();
auto getInstance{gpu->backend->vulkanInstanceAddr};
gpu->app = vk::raii::Context(getInstance);
gpu->instance = vulcano::createVulkanInstance(*gpu->app, gpu->haveValidation);
auto getInstance{gpu.backend->vulkanInstanceAddr};
gpu.app = vk::raii::Context(getInstance);
gpu.instance = vulcano::createVulkanInstance(*gpu.app, gpu.haveValidation);
struct vulcano::PhysicalDevice vulkanGpu{
vulcano::createPhysicalDevice(*gpu->instance)};
vulcano::createPhysicalDevice(*gpu.instance)};
gpu->vkDev = std::move(vulkanGpu.gpuUser);
gpu->deviceInfo = vulkanGpu.info;
gpu->queueFamilyId = vulkanGpu.desiredQueueId;
gpu.vkDev = std::move(vulkanGpu.gpuUser);
gpu.deviceInfo = vulkanGpu.info;
gpu.queueFamilyId = vulkanGpu.desiredQueueId;
#ifndef NDEBUG
if (gpu->haveValidation) {
if (gpu.haveValidation) {
auto debugInfoMsg{vulcano::createDebugInfo()};
vulcano::createDebugLayer(
getInstance, *gpu->instance, debugInfoMsg, {}, gpu->debugMessenger);
getInstance, *gpu.instance, debugInfoMsg, {}, gpu.debugMessenger);
}
#endif
}

View File

@ -1,7 +1,7 @@
#include <gpu/vulcano/vram_allocator.h>
namespace cosmic::gpu::vulcano {
VramManager::VramManager(Ref<GraphicsLayer> gpu) : graphics(gpu) {
VramManager::VramManager(Optional<GraphicsLayer>& gpu) : graphics(gpu) {
VmaAllocatorCreateInfo allocatorInfo{};
vmaCreateAllocator(&allocatorInfo, &vma);
}

View File

@ -6,10 +6,10 @@ namespace cosmic::gpu::vulcano {
class GraphicsLayer;
class VramManager {
public:
VramManager(Ref<GraphicsLayer> gpu);
VramManager(Optional<GraphicsLayer>& gpu);
~VramManager();
private:
VmaAllocator vma{VK_NULL_HANDLE};
Ref<GraphicsLayer> graphics;
Optional<GraphicsLayer> graphics;
};
}

View File

@ -99,26 +99,26 @@ namespace cosmic::gs {
for (u8 pack{}; pack < 2; pack++)
package[pack] = packet.to64(pack);
Ref<GifTag> activated{std::ref(paths[activatePath].tag)};
if (!activated->leftRegsData[1]) {
auto& activated{paths[activatePath].tag};
if (!activated.leftRegsData[1]) {
primitiveCounts++;
decodeGifTag(activated, package.data());
// NOTE: The GS Q register is initialized to 1.0f when reading a GIFtag
gsQ = 1.0;
if (activated->leftRegsData[1] != 0) {
if (activated.leftRegsData[1] != 0) {
}
} else {
switch (activated->dataFormat) {
switch (activated.dataFormat) {
case TagDataFormat::Packed:
// This is an element loop count, like N * M, where N is the count of regs and M is
// the number of times the regs data packet needs to be transferred
activated->leftRegsData[0]--;
activated.leftRegsData[0]--;
uploadPackedData(activated, package.data());
if (!activated->leftRegsData[0]) {
activated->leftRegsData[0] = activated->regsNum;
activated->leftRegsData[1]--;
if (!activated.leftRegsData[0]) {
activated.leftRegsData[0] = activated.regsNum;
activated.leftRegsData[1]--;
}
break;
case TagDataFormat::RegList:
@ -127,29 +127,29 @@ namespace cosmic::gs {
case TagDataFormat::Image3:
for (u8 pack{}; pack < 2; pack++)
gs->gsWrite(0x54, package[pack]);
activated->leftRegsData[1]--;
activated.leftRegsData[1]--;
break;
case TagDataFormat::Unrecognized:
break;
}
}
}
void GifBridge::decodeGifTag(Ref<GifTag>& unpacked, u64 packet[2]) {
unpacked->dataFormat = static_cast<TagDataFormat>(packet[0] >> 58 & 0x3);
if (unpacked->dataFormat > TagDataFormat::Image3) {
void GifBridge::decodeGifTag(GifTag& unpacked, u64 packet[2]) {
unpacked.dataFormat = static_cast<TagDataFormat>(packet[0] >> 58 & 0x3);
if (unpacked.dataFormat > TagDataFormat::Image3) {
}
// The first transfer from Vif to GS is its Gif-Tag let's decode it now
unpacked->perLoop = packet[0] & 0x7fff;
unpacked->isEndOfPacket = packet[0] & 1 << 0xf;
unpacked->regs = packet[1];
unpacked.perLoop = packet[0] & 0x7fff;
unpacked.isEndOfPacket = packet[0] & 1 << 0xf;
unpacked.regs = packet[1];
const u8 regs = packet[0] >> 60;
unpacked->regsNum = regs;
unpacked.regsNum = regs;
if (!regs) {
unpacked->regsNum = 0x10;
unpacked.regsNum = 0x10;
}
unpacked->leftRegsData[0] = unpacked->regsNum;
unpacked->leftRegsData[1] = unpacked->perLoop;
unpacked.leftRegsData[0] = unpacked.regsNum;
unpacked.leftRegsData[1] = unpacked.perLoop;
}
void GifBridge::deactivatePath(PathsTr path) {
}

View File

@ -66,8 +66,8 @@ namespace cosmic::gs {
void update(u32 cycles);
private:
void transfer2Gif(os::vec packet);
void decodeGifTag(Ref<GifTag>& unpacked, u64 packet[2]);
void uploadPackedData(Ref<GifTag>& dsTag, u64 packet[2]);
void decodeGifTag(GifTag& unpacked, u64 packet[2]);
void uploadPackedData(GifTag& dsTag, u64 packet[2]);
void queueReset();
u64 queueGetSize();
os::vec queueConsume();

View File

@ -2,16 +2,16 @@
#include <gs/gs_engine.h>
namespace cosmic::gs {
void GifBridge::uploadPackedData(Ref<GifTag>& dsTag, u64 packet[2]) {
void GifBridge::uploadPackedData(GifTag& dsTag, u64 packet[2]) {
RegDesc reg{};
u64 offset;
if (!dsTag->isEndOfPacket) {
offset = (dsTag->regsNum - dsTag->leftRegsData[0]) << 2;
if (!dsTag.isEndOfPacket) {
offset = (dsTag.regsNum - dsTag.leftRegsData[0]) << 2;
if (offset > 63) {
}
reg = static_cast<RegDesc>((dsTag->regs >> offset) & 0xf);
reg = static_cast<RegDesc>((dsTag.regs >> offset) & 0xf);
}
switch (reg) {

View File

@ -46,7 +46,7 @@ namespace cosmic::gs {
u64 rainbow;
struct {
u8 r, g, b, a;
float gsq;
f32 gsq;
};
};
union CoordinatesXyz {

View File

@ -24,6 +24,6 @@ namespace cosmic::hle {
void doSyscall(SyscallOrigin origin, i16 sys);
private:
void resetEe();
Ref<vm::EmuVm> vm;
Optional<vm::EmuVm> vm;
};
}

View File

@ -15,7 +15,7 @@ namespace cosmic::iop {
IoMipsCore::IoMipsCore(std::shared_ptr<mio::MemoryPipe>& pipe) :
iopMem(pipe) {
interpreter = std::make_unique<creeper::IopInterpreter>(*this);
interpreter = std::make_unique<creeper::IopInterpreter>(Optional(*this));
for (auto& cache : instCache) {
cache.data = {};
cache.tag = {};

View File

@ -23,30 +23,29 @@ namespace cosmic::iop {
void IopDma::pulseSpu2Chain() {
// When true, it means that we will write into the SPU2 device
bool write2Spu;
Ref<IopChan> channel;
auto spu2ch{Optional(channels[IopSpu2])};
std::array<u32, 2> packet{};
channel = std::ref(channels[IopSpu2]);
write2Spu = channel->status.isFrom2Device;
write2Spu = spu2ch->status.isFrom2Device;
if (channel->cyclesDelay) {
channel->cyclesDelay--;
if (spu2ch->cyclesDelay) {
spu2ch->cyclesDelay--;
return;
}
if (channel->cyclesDelay <= 0) {
if (spu2ch->cyclesDelay <= 0) {
if (write2Spu) {
packet[0] = ioDmaRead<u32>(channel->addr);
packet[0] = ioDmaRead<u32>(spu2ch->addr);
spu2->writeDmaData(packet[0]);
} else {
packet[1] = spu2->requestDmaData();
ioDmaWrite<u32>(channel->addr, packet[1]);
ioDmaWrite<u32>(spu2ch->addr, packet[1]);
}
channel->size--;
channel->addr += sizeof(u32);
channel->cyclesDelay = 3;
spu2ch->size--;
spu2ch->addr += sizeof(u32);
spu2ch->cyclesDelay = 3;
}
if (!channel->size) {
channel->wordCount = 0;
if (!spu2ch->size) {
spu2ch->wordCount = 0;
}
}
}

View File

@ -5,14 +5,14 @@ namespace cosmic::iop {
class IopExecVe {
public:
IopExecVe(Ref<IoMipsCore> mips) :
IopExecVe(Optional<IoMipsCore>& mips) :
cpu(mips) {}
virtual u32 executeCode() = 0;
virtual u32 fetchPcInst() = 0;
virtual ~IopExecVe() = default;
protected:
Ref<IoMipsCore> cpu;
Optional<IoMipsCore> cpu;
};
enum IopSpecial {

View File

@ -21,7 +21,7 @@ namespace cosmic::mio {
u8* iopUnaligned(u32 address);
u8* spu2Unaligned(u32 address);
void iopSoftClean() {
[[maybe_unused]] void iopSoftClean() {
memset(*iopBlock, 0, iopBlock.getBlockSize());
}
void printMemoryImage();

View File

@ -72,13 +72,12 @@ namespace cosmic::mio {
u32 countOfQw{};
for (; hasOwner && highCycles > 0; ) {
Ref<DmaChannel> owner{};
owner = std::ref(channels.at(hasOwner.getId()));
auto owner{Optional(channels.at(hasOwner.getId()))};
// "Owner" is the privileged channel that will use the available clock pulses at the moment
switch (owner->index) {
case Vif0:
countOfQw = feedVif0Pipe(owner).first; break;
countOfQw = feedVif0Pipe(*owner).first; break;
}
highCycles -= std::max(countOfQw, static_cast<u32>(1));
if (owner->isScratch)
@ -89,7 +88,7 @@ namespace cosmic::mio {
}
highCycles = 0;
}
Ref<u32> DmaController::dmaVirtSolver(u32 address) {
std::optional<u32> DmaController::dmaVirtSolver(u32 address) {
u64 invCid = channels.size();
u64 cid = invCid;
u8 which{};
@ -124,55 +123,55 @@ namespace cosmic::mio {
}
return {};
}
std::pair<u32, u8> DmaController::feedVif0Pipe(Ref<DmaChannel> vifc) {
std::pair<u32, u8> DmaController::feedVif0Pipe(DmaChannel& vifc) {
u32 transferred{};
auto [haveData, count] = pipeQuad2Transfer(vifc);
if (!haveData) {
u32 remainFifoSpace{hw.vif0->getFifoFreeSpace()};
u32 qwBlock{std::min(remainFifoSpace, vifc->qwc)};
u32 qwBlock{std::min(remainFifoSpace, vifc.qwc)};
for (u64 remain{};
qwBlock >= 4 && qwBlock - remain >= 0; remain += 4) {
hw.vif0->transferDmaData(dmacRead(vifc->adr));
advanceSrcDma(*vifc);
hw.vif0->transferDmaData(dmacRead(vifc->adr));
advanceSrcDma(*vifc);
hw.vif0->transferDmaData(dmacRead(vifc->adr));
advanceSrcDma(*vifc);
hw.vif0->transferDmaData(dmacRead(vifc->adr));
advanceSrcDma(*vifc);
hw.vif0->transferDmaData(dmacRead(vifc.adr));
advanceSrcDma(vifc);
hw.vif0->transferDmaData(dmacRead(vifc.adr));
advanceSrcDma(vifc);
hw.vif0->transferDmaData(dmacRead(vifc.adr));
advanceSrcDma(vifc);
hw.vif0->transferDmaData(dmacRead(vifc.adr));
advanceSrcDma(vifc);
transferred += 4;
}
while (qwBlock-- > 0 && transferred < count) {
hw.vif0->transferDmaData(
dmacRead(vifc->adr), true);
advanceSrcDma(*vifc);
dmacRead(vifc.adr), true);
advanceSrcDma(vifc);
transferred++;
}
}
if (!vifc->qwc) {
if (!vifc.qwc) {
} else {
switchChannel();
}
return {transferred, 0};
}
std::pair<bool, u32> DmaController::pipeQuad2Transfer(Ref<DmaChannel> ch) {
std::pair<bool, u32> DmaController::pipeQuad2Transfer(DmaChannel& channel) {
constexpr u8 qwcPerRequest{8};
if (!ch->qwc) {
if (!channel.qwc) {
return std::make_pair(false, 0);
}
u32 maxQwc{qwcPerRequest - (ch->adr >> 0x4) & 0x7};
u32 maxQwc{qwcPerRequest - (channel.adr >> 0x4) & 0x7};
if (maxQwc >= std::numeric_limits<u16>::max()) {
}
const auto toTransfer{std::min(ch->qwc, maxQwc)};
const auto toTransfer{std::min(channel.qwc, maxQwc)};
return {true, toTransfer};
}
void DmaController::disableChannel(DirectChannels channel, bool disableRequest) {
bool isDisable{!disableRequest};
auto index{static_cast<u32>(channel)};
const auto index{static_cast<u32>(channel)};
auto& dma{channels.at(index)};
if (disableRequest) {
@ -206,37 +205,37 @@ namespace cosmic::mio {
hw.core->cop0.enableIntNumber(1, enableSignal);
}
os::vec DmaController::dmacRead(u32& address) {
os::vec DmaController::dmacRead(u32 address) {
bool isScratchPad{address & (static_cast<u32>(1 << 31)) ||
(address & 0x70000000) == 0x70000000};
bool isVuArea{address >= 0x11000000 && address < 0x11010000};
auto vd{*dmaAddrSolver(
auto vd{dmaAddrSolver(
address, isScratchPad, isVuArea)};
return vd;
}
void DmaController::dmacWrite(u32 address, const os::vec& val) {
void DmaController::dmacWrite(u32 address, const os::vec& value) {
std::array<bool, 2> is;
is[0] = address & (static_cast<u32>(1 << 31)) ||
(address & 0x70000000) == 0x70000000;
is[1] = address >= 0x11000000 && address < 0x11010000;
*dmaAddrSolver(address, is[0], is[1]) = val.get();
dmaAddrSolver(address, is[0], is[1]) = value.get();
}
Ref<u128> DmaController::dmaAddrSolver(u32 address, bool isScr, bool isVu) {
u128& DmaController::dmaAddrSolver(u32 address, bool isScr, bool isVu) {
if (isScr) {
return *BitCast<u128*>(&hw.core->scratchPad[address & 0x3ff0]);
} else if (!isVu) {
return *PipeCraftPtr<u128*>(pipe, address & 0x01fffff0);
}
Ref<vu::VuWorkMemory> vu01Mem{};
Optional<vu::VuWorkMemory> vu01Mem{};
u32 mask;
if (address < 0x11008000) {
vu01Mem = std::ref(hw.vif0->vifVu->vecRegion);
vu01Mem = Optional(hw.vif0->vifVu->vecRegion);
mask = hw.vif0->vifVu->getMemMask();
} else {
vu01Mem = std::ref(hw.vif1->vifVu->vecRegion);
vu01Mem = Optional(hw.vif1->vifVu->vecRegion);
mask = hw.vif1->vifVu->getMemMask();
}
bool is0Inst{address < 0x11004000};

View File

@ -20,7 +20,7 @@ namespace cosmic::mio {
struct HardWithDmaCap {
public:
HardWithDmaCap() {}
Ref<vu::VifMalice>
Optional<vu::VifMalice>
vif0,
vif1;
std::shared_ptr<ee::EeMipsCore> ee;
@ -132,11 +132,11 @@ namespace cosmic::mio {
void resetMa();
void pulse(u32 cycles);
os::vec performRead(u32 address);
Ref<u32> dmaVirtSolver(u32 address);
std::optional<u32> dmaVirtSolver(u32 address);
Ref<u128> dmaAddrSolver(u32 address, bool isScr, bool isVu);
os::vec dmacRead(u32& address);
void dmacWrite(u32 address, const os::vec& val);
u128& dmaAddrSolver(u32 address, bool isScr, bool isVu);
os::vec dmacRead(u32 address);
void dmacWrite(u32 address, const os::vec& value);
void issueADmacRequest(DirectChannels channel);
void connectDevices(HardWithDmaCap& devices);
@ -175,8 +175,8 @@ namespace cosmic::mio {
OwnerChannel hasOwner;
i64 highCycles;
std::pair<u32, u8> feedVif0Pipe(Ref<DmaChannel> vifc);
std::pair<bool, u32> pipeQuad2Transfer(Ref<DmaChannel> ch);
std::pair<u32, u8> feedVif0Pipe(DmaChannel& vifc);
std::pair<bool, u32> pipeQuad2Transfer(DmaChannel& ch);
void checkStallOrActivateLater(DirectChannels channel);
void switchChannel();
@ -194,7 +194,7 @@ namespace cosmic::mio {
std::shared_ptr<MemoryPipe> pipe;
struct {
Ref<vu::VifMalice> vif1, vif0;
Optional<vu::VifMalice> vif1, vif0;
std::shared_ptr<ee::EeMipsCore> core;
} hw;
};

View File

@ -63,16 +63,18 @@ namespace cosmic::mio {
// Checks if the destination channel can be paused or should be, for a moment
if (checkForStall && chan.hasStallDrain && chan.adr == stallAddress) {
if (!chan.hasDmaStalled) {
// At this point, we are waiting for the data in memory at the specified address
// We cannot continue the transfer without first triggering an interrupt
user->info("The channel {} is waiting ({} | {})",
channelsName[chan.index], chan.adr, stallAddress);
raiseInt1();
intStat.channelStat[DmaStall] = true;
chan.hasDmaStalled = true;
if (chan.hasDmaStalled) {
queued.push_back(chan.index);
return;
}
// At this point, we are waiting for the data in memory at the specified address
// We cannot continue the transfer without first triggering an interrupt
user->info("The channel {} is waiting ({} | {})", channelsName[chan.index], chan.adr, stallAddress);
raiseInt1();
intStat.channelStat[DmaStall] = true;
chan.hasDmaStalled = true;
queued.push_back(chan.index);
return;
}
@ -93,7 +95,10 @@ namespace cosmic::mio {
}
os::vec DmaController::performRead(u32 address) {
os::vec fetched{};
fetched = *dmaVirtSolver(address);
auto dmaHas{dmaVirtSolver(address)};
if (!dmaHas) {
return fetched;
}
return fetched;
}
}

View File

@ -42,10 +42,10 @@ namespace cosmic::mio {
private:
u8* pointer{};
};
template<typename Type = os::vec>
Type bitBashing(os::vec vec) {
template<typename T = os::vec>
T bitBashing(const os::vec& vec) {
os::vec clb{0xff};
switch (sizeof(Type) * 8) {
switch (sizeof(T) * 8) {
case 16: clb = 0xffff; break;
case 32: clb = 0xffffffff; break;
case 64: clb = 0xffffffffffffffff; break;
@ -53,10 +53,10 @@ namespace cosmic::mio {
// This will clean all bits to 0
clb = {0xffffffffffffffff, 0xffffffffffffffff};
}
os::vec cleaned{vec & clb};
if constexpr (std::is_same<Type, u32>::value)
const os::vec cleaned{vec & clb};
if constexpr (std::is_same<T, u32>::value)
return cleaned.to32(0);
if constexpr (std::is_same<Type, os::vec>::value)
if constexpr (std::is_same<T, os::vec>::value)
return cleaned;
return {};
}
@ -77,7 +77,7 @@ namespace cosmic::mio {
return virt.read<u32*>();
return static_cast<u32>(0);
}
void writeBack(VirtualPointer& virt, os::vec value, u64 size) {
void writeBack(VirtualPointer& virt, const os::vec& value, u64 size) {
if (size == sizeof(u32)) {
virt.write<u32*>(0, bitBashing<u32>(value));
}

View File

@ -22,7 +22,7 @@ namespace cosmic::os {
auto get() const {
return native;
}
inline u32 to32(u8 lane) {
inline u32 to32(u8 lane) const {
switch (lane) {
case 0: return vgetq_lane_u32(native, 0);
case 1: return vgetq_lane_u32(native, 1);
@ -31,11 +31,11 @@ namespace cosmic::os {
}
return {};
}
inline u64 to64(u8 lane) {
inline u64 to64(u8 lane) const {
return lane == 0 ? vgetq_lane_u64(native, 0) : vgetq_lane_u64(native, 1);
}
template <typename T, u64 lane = 0>
T as() {
T as() const {
if constexpr (sizeof(T) == 4) {
return static_cast<T>(to32(lane));
} else if constexpr (sizeof(T) == 8) {
@ -49,7 +49,7 @@ namespace cosmic::os {
u64 operator[](u32 vec) const {
return reinterpret_cast<const u64*>(&native)[vec];
}
os::vec operator&(os::vec& vv) {
os::vec operator&(const os::vec& vv) const {
return {
vv.to64(0) & to64(0),
vv.to64(1) & to64(1)};

View File

@ -12,7 +12,7 @@ namespace cosmic::vm {
};
struct SharedVm {
SharedVm(EmuVm& svm) {
vm = std::ref(svm);
vm = Optional(svm);
running.store(false);
monitor.store(SvrNone);
}
@ -32,7 +32,7 @@ namespace cosmic::vm {
auto isRunning() const {
return running.load();
}
Ref<EmuVm> vm;
Optional<EmuVm> vm;
std::atomic<bool> running;
std::atomic<MonitorMode> monitor;
@ -47,10 +47,10 @@ namespace cosmic::vm {
void updateValues(std::shared_ptr<SharedVm>& svm, bool running, u8 isSuper);
static void vmMain(std::shared_ptr<SharedVm>& svm);
static void vmSupervisor(std::shared_ptr<SharedVm> svm);
static void runFrameLoop(Ref<EmuVm>& vm);
static void stepMips(Ref<EmuVm>& vm, u32 mips, u32 iop, u32 bus);
static void stepVus(Ref<EmuVm>& vm, u32 mips, u32 bus);
static void stepGs(Ref<EmuVm>& vm, u32 bus);
static void runFrameLoop(Optional<EmuVm>& vm);
static void stepMips(Optional<EmuVm>& vm, u32 mips, u32 iop, u32 bus);
static void stepVus(Optional<EmuVm>& vm, u32 mips, u32 bus);
static void stepGs(Optional<EmuVm>& vm, u32 bus);
std::thread vmThread;
std::shared_ptr<SharedVm> vmSharedPtr;

View File

@ -40,7 +40,7 @@ namespace cosmic::vm {
status.setDesiredFrames(30);
Ref<vu::VectorUnit> vus[]{
Optional<vu::VectorUnit> vus[]{
vu01->vpu0Cop2,
vu01->vpu1Dlo
};
@ -103,7 +103,7 @@ namespace cosmic::vm {
ioDma->resetIoDma();
sound->resetSound();
iop->iopMem->controller->mapped->iopSoftClean();
// iop->iopMem->controller->mapped->iopSoftClean();
}
void EmuVm::dealWithSyscalls() {
hle::SyscallOrigin origin{};
@ -119,11 +119,11 @@ namespace cosmic::vm {
if (origin == hle::SysEmotionEngine) {
dealer->doSyscall(origin, call[0]);
mips->eePc = mips->GPRs[31].words[0];
mips->cop0.cause.exCode = 0x00;
mips->cop0.cause.exCode = {};
return;
}
iop->handleException(mipsCall);
iop->cop.cause.code = 0x00;
iop->cop.cause.code = {};
}
}

View File

@ -2,25 +2,25 @@
#include <vm/emu_vm.h>
namespace cosmic::vm {
void EmuThread::stepMips(Ref<EmuVm>& vm, u32 mips, u32 iop, u32 bus) {
void EmuThread::stepMips(Optional<EmuVm>& vm, u32 mips, u32 iop, u32 bus) {
vm->mips->pulse(mips);
vm->iop->pulse(iop);
// DMAC runs in parallel, which could be optimized (and will be early next year)
vm->sharedPipe->controller->pulse(bus);
vm->mpegDecoder->update();
}
void EmuThread::stepVus(Ref<EmuVm>& vm, u32 mips, u32 bus) {
void EmuThread::stepVus(Optional<EmuVm>& vm, u32 mips, u32 bus) {
// VUs can run in parallel with EE...
for (u8 runVifs{}; runVifs < 2; runVifs++)
vm->vu01->vifs[runVifs].update(bus);
vm->vu01->vpu0Cop2.pulse(mips);
vm->vu01->vpu1Dlo.pulse(mips);
}
void EmuThread::stepGs(Ref<EmuVm>& vm, u32 bus) {
void EmuThread::stepGs(Optional<EmuVm>& vm, u32 bus) {
vm->gsGif->update(bus);
}
void EmuThread::runFrameLoop(Ref<EmuVm>& vm) {
void EmuThread::runFrameLoop(Optional<EmuVm>& vm) {
auto sched{vm->scheduler};
while (!vm->status.get(HasFrame)) {
u32 mipsCycles{sched->getNextCycles(Scheduler::Mips)};

View File

@ -1,16 +1,18 @@
#include <vu/v01_cop2vu.h>
namespace cosmic::vu {
MacroModeCop2::MacroModeCop2(Ref<VectorUnit> vus[2])
MacroModeCop2::MacroModeCop2(Optional<VectorUnit> vus[2])
: v0(vus[0]),
v1(vus[1]) {
cop2il = vuIl = false;
v1(vus[1]) {
cop2il = false;
vuIl = false;
}
// CFC2 is a requirement, it is a way for EE to access the V0 special registers
u32 MacroModeCop2::cfc2(u32 special) {
if (special < 0x10)
if (special < 0x10) {
if (special != 0)
return v0->intsRegs[special].uns;
}
return 0;
}
void MacroModeCop2::ctc2(u32 special, u32 value) {

View File

@ -6,7 +6,7 @@ namespace cosmic::vu {
// Just a communication interface between these two VUs
class MacroModeCop2 {
public:
MacroModeCop2(Ref<vu::VectorUnit> vus[2]);
MacroModeCop2(Optional<vu::VectorUnit> vus[2]);
void clearInterlock();
bool checkInterlock();
bool interlockCheck(bool isCop2);
@ -14,8 +14,8 @@ namespace cosmic::vu {
u32 cfc2(u32 special);
void ctc2(u32 special, u32 value);
Ref<vu::VectorUnit> v0;
Ref<vu::VectorUnit> v1;
Optional<vu::VectorUnit> v0;
Optional<vu::VectorUnit> v1;
bool cop2il,
vuIl;
};

View File

@ -28,7 +28,7 @@ namespace cosmic::vu {
}
}
VectorUnit::VectorUnit(Ref<VectorUnit> vu2, VuWorkMemory vuWm) :
VectorUnit::VectorUnit(Optional<VectorUnit> vu2, VuWorkMemory vuWm) :
paraVu(vu2),
vecRegion(vuWm) {
@ -198,9 +198,9 @@ namespace cosmic::vu {
}
return {};
}
void VectorUnit::establishVif(u16 conTops[2], Ref<gs::GifBridge> gif) {
void VectorUnit::establishVif(u16 conTops[2], Optional<gs::GifBridge> gif) {
for (u8 top{}; top < 2; top++)
vifTops[top] = Ref(conTops[top]);
vifTops[top] = Optional(conTops[top]);
if (gif)
vu1Gif = gif;

View File

@ -28,7 +28,7 @@ namespace cosmic::vu {
};
union alignas(16) VuReg {
union {
float x, y, z, w;
f32 x, y, z, w;
f32 floats[4];
};
u32 uns[4];
@ -81,7 +81,7 @@ namespace cosmic::vu {
class VectorUnit {
public:
VectorUnit() = delete;
VectorUnit(Ref<VectorUnit> vu2, VuWorkMemory vuWm);
VectorUnit(Optional<VectorUnit> vu2, VuWorkMemory vuWm);
void resetVu();
void softwareReset();
@ -103,7 +103,7 @@ namespace cosmic::vu {
VuReg acc;
alignas(32) std::array<VuIntReg, 16> intsRegs;
void establishVif(u16 conTops[2], Ref<gs::GifBridge> gif);
void establishVif(u16 conTops[2], Optional<gs::GifBridge> gif);
// P register: Used by EFU to store the result - waitp could be used to stall the execution
// while EFU doesn't finish the previous calculation
u32 vuPc{};
@ -113,7 +113,7 @@ namespace cosmic::vu {
VuStatus status;
VuIntPipeline intPipeline;
Ref<VectorUnit> paraVu;
Optional<VectorUnit> paraVu;
void pushIntPipe(u8 ir, u8 fir);
void finishStallPipeTask(bool isDiv);
@ -199,7 +199,7 @@ namespace cosmic::vu {
i64 trigger;
bool isDirty;
} clock;
Ref<u16> vifTops[2];
std::optional<Ref<gs::GifBridge>> vu1Gif;
Optional<u16> vifTops[2];
Optional<gs::GifBridge> vu1Gif;
};
}

View File

@ -2,7 +2,7 @@
#include <vu/vecu.h>
namespace cosmic::vu {
VifMalice::VifMalice(Ref<VectorUnit> vector, VifGifInterconnector card) :
VifMalice::VifMalice(Optional<VectorUnit> vector, VifGifInterconnector card) :
vif2gif(card), vifVu(vector) {
tops[0] = {};

View File

@ -57,7 +57,7 @@ namespace cosmic::vu {
public:
VifMalice() = default;
VifMalice(VifMalice&) = delete;
VifMalice(Ref<VectorUnit> vector, VifGifInterconnector card);
VifMalice(Optional<VectorUnit> vector, VifGifInterconnector card);
void update(u32 cycles);
void resetVif();
@ -74,7 +74,7 @@ namespace cosmic::vu {
std::shared_ptr<console::IntCInfra> interrupts;
std::shared_ptr<mio::DmaController> dmac;
Ref<VectorUnit> vifVu;
Optional<VectorUnit> vifVu;
mio::DirectChannels vifId;
private:
u16 memMask{};

View File

@ -15,15 +15,15 @@ namespace cosmic::vu {
u16 addr{gifAddr};
gifAddr += 16;
quad = *BitCast<os::vec*>(&vecRegion.rw[addr]);
if (vu1Gif.value()->feedPathWithData(gs::Vu1, quad)) {
std::memcpy(&quad, &vecRegion.rw[addr], sizeof(quad));
if (vu1Gif->feedPathWithData(gs::Vu1, quad)) {
if (!path1.stallXgKick) {
// Reactivating the previous interrupted transfer
path1.stallXgKick = {};
gifAddr = gifStallAddr;
vu1Gif.value()->requestDmac(gs::Vu1, true);
vu1Gif->requestDmac(gs::Vu1, true);
} else {
vu1Gif.value()->deactivatePath(gs::Vu1);
vu1Gif->deactivatePath(gs::Vu1);
path1.transferringGif = {};
return;
}
@ -33,9 +33,9 @@ namespace cosmic::vu {
void VectorUnit::startXgKick2Gif() {
if (!vu1Gif.has_value())
return;
vu1Gif.value()->requestDmac(gs::Vu1, true);
vu1Gif->requestDmac(gs::Vu1, true);
while (path1.cycles >= 0x2) {
if (!vu1Gif.value()->isPathActivated(gs::Vu1, true)) {
if (!vu1Gif->isPathActivated(gs::Vu1, true)) {
path1.cycles = 0;
break;
}

View File

@ -5,7 +5,7 @@ namespace cosmic::vu {
class VectorUnit;
class VuMicroExecutor {
public:
VuMicroExecutor(Ref<VectorUnit> vu) : vuMicro(vu) {
VuMicroExecutor(Optional<VectorUnit>& vu) : vuMicro(vu) {
}
virtual u32 executeCode() = 0;
@ -14,6 +14,6 @@ namespace cosmic::vu {
virtual std::pair<u32, u32> fetchPcInst() = 0;
virtual ~VuMicroExecutor() = default;
protected:
Ref<VectorUnit> vuMicro;
Optional<VectorUnit> vuMicro;
};
}