mirror of
https://github.com/shadergz/cosmic-station.git
synced 2024-11-27 00:00:21 +00:00
Core
: Makes several fixes and general improvements to the code
This commit is contained in:
parent
2ab9f469f1
commit
930a881139
@ -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>
|
||||
|
@ -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 = {};
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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{};
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -46,7 +46,7 @@ namespace cosmic::gs {
|
||||
u64 rainbow;
|
||||
struct {
|
||||
u8 r, g, b, a;
|
||||
float gsq;
|
||||
f32 gsq;
|
||||
};
|
||||
};
|
||||
union CoordinatesXyz {
|
||||
|
@ -24,6 +24,6 @@ namespace cosmic::hle {
|
||||
void doSyscall(SyscallOrigin origin, i16 sys);
|
||||
private:
|
||||
void resetEe();
|
||||
Ref<vm::EmuVm> vm;
|
||||
Optional<vm::EmuVm> vm;
|
||||
};
|
||||
}
|
||||
|
@ -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 = {};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
@ -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)};
|
||||
|
@ -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;
|
||||
|
@ -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 = {};
|
||||
}
|
||||
}
|
||||
|
@ -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)};
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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] = {};
|
||||
|
@ -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{};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user