Cop0: Fixes the data types used in the cache

This commit is contained in:
Gabriel Correia 2024-06-11 21:29:04 -03:00
parent e93610d5c3
commit 05e2d5b5ed
3 changed files with 34 additions and 33 deletions

View File

@ -5,9 +5,8 @@
namespace cosmic::ee { namespace cosmic::ee {
// We don't check for a cache miss here // We don't check for a cache miss here
os::vec CtrlCop::readCache(u32 address, CacheMode mode) { os::vec CtrlCop::readCache(u32 address, CacheMode mode) {
u32 tag{getCachePfn(address, mode)}; auto tag{getCachePfn(address, mode)};
Ref<CopCacheLine> cache; auto cache{getCache(address, false, mode)};
cache = getCache(address, false, mode);
u8 fix{}; u8 fix{};
if (cache->tags[0] == tag) if (cache->tags[0] == tag)
fix = 1; fix = 1;
@ -17,7 +16,7 @@ namespace cosmic::ee {
if (!fix) { if (!fix) {
throw Cop0Err("Address {} isn't cached or doesn't have a valid tag referencing it", address); throw Cop0Err("Address {} isn't cached or doesn't have a valid tag referencing it", address);
} }
const CopCacheLine::CacheWay cont{cache->ec[fix - 1]}; const auto cont{cache->ec[fix - 1]};
return cont.vec[address & 3]; return cont.vec[address & 3];
} }
void CtrlCop::invIndexed(u32 address) { void CtrlCop::invIndexed(u32 address) {
@ -30,7 +29,7 @@ namespace cosmic::ee {
} }
bool CtrlCop::isCacheHit(u32 address, u8 lane, CacheMode mode) { bool CtrlCop::isCacheHit(u32 address, u8 lane, CacheMode mode) {
// Each cache line is indexed by virtual address // Each cache line is indexed by virtual address
u16 tag{getCachePfn(address, mode)}; auto tag{getCachePfn(address, mode)};
auto highway{getCache(address, false, mode)}; auto highway{getCache(address, false, mode)};
if (!highway) if (!highway)
@ -43,20 +42,18 @@ namespace cosmic::ee {
return {}; return {};
} }
void CtrlCop::loadCacheLine(u32 address, EeMipsCore& core, CacheMode mode) { void CtrlCop::loadCacheLine(u32 address, EeMipsCore& core, CacheMode mode) {
Ref<CopCacheLine> pear{}; auto logical{getCachePfn(address, mode)};
u16 logical{getCachePfn(address, mode)};
pear = getCache(address, true, mode); auto pear{getCache(address, true, mode)};
assignFlushedCache(*pear, logical); assignFlushedCache(*pear, logical);
if (pear->tags[0] != logical && pear->tags[1] != logical) { if (pear->tags[0] != logical && pear->tags[1] != logical) {
throw Cop0Err("No portion of the cache line {} was properly selected! Tags: {}", logical, throw Cop0Err("No portion of the cache line {} was properly selected! Tags: {}",
fmt::join(pear->tags, ",")); logical, fmt::join(pear->tags, ","));
} }
auto cacheData{core.mipsRead<os::vec>(address)}; auto cacheData{core.mipsRead<os::vec>(address)};
// Due to the LRF algorithm, we will write to the way that was written last (thus keeping // 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) // the last data among the ways in the cache, waiting for one more miss)
u8 way; u8 way{pear->lrf[0] && !pear->lrf[1]};
way = pear->lrf[0] && !pear->lrf[1];
if (!way) { if (!way) {
if (!pear->lrf[0] && pear->lrf[1]) if (!pear->lrf[0] && pear->lrf[1])
way = 2; way = 2;
@ -90,9 +87,10 @@ namespace cosmic::ee {
void CtrlCop::assignFlushedCache(CopCacheLine& eec, u32 tag, CacheMode mode) { void CtrlCop::assignFlushedCache(CopCacheLine& eec, u32 tag, CacheMode mode) {
// The EE uses a Least Recently Filled (LRF) algorithm to determine which way to load data into // The EE uses a Least Recently Filled (LRF) algorithm to determine which way to load data into
u32 assign{}; u32 assign{};
std::array<u8, 2> mix{}; const std::array<u8, 2> mix{
mix[0] = static_cast<u8>(eec.tags[0] & ~validBit); static_cast<u8>(eec.tags[0] & ~validBit),
mix[1] = static_cast<u8>(eec.tags[1] & ~validBit); static_cast<u8>(eec.tags[1] & ~validBit)
};
if (mix[0] && !mix[1]) if (mix[0] && !mix[1])
assign = 0; assign = 0;
@ -121,8 +119,7 @@ namespace cosmic::ee {
} }
} }
Ref<CopCacheLine> CtrlCop::getCache(u32 mem, bool write, CacheMode mode) { Ref<CopCacheLine> CtrlCop::getCache(u32 mem, bool write, CacheMode mode) {
std::array<u8*, 2> wb; std::array<Ref<u8>, 2> wb;
std::array<bool, 2> valid;
u32 ci; u32 ci;
std::span<CopCacheLine> cc; std::span<CopCacheLine> cc;
if (mode == Instruction) { if (mode == Instruction) {
@ -132,20 +129,25 @@ namespace cosmic::ee {
ci = (mem >> 6) & 0x3f; ci = (mem >> 6) & 0x3f;
cc = dataCache; cc = dataCache;
} }
wb[0] = virtMap[cc[ci].tags[0] >> 12]; wb[0] = Ref(*virtMap[cc[ci].tags[0] >> 12]);
valid[0] = cc[ci].lrf[0]; std::array<bool, 2> valid{
valid[1] = cc[ci].lrf[1]; cc[ci].lrf[0],
wb[1] = virtMap[cc[ci].tags[1] >> 12]; cc[ci].lrf[1]
};
wb[1] = Ref(*virtMap[cc[ci].tags[1] >> 12]);
if (wb[0] == virtMap[mem >> 12] && valid[0]) if (*wb[0] == *virtMap[mem >> 12] && valid[0])
return cc[ci]; return cc[ci];
if (wb[1] == virtMap[mem >> 12] && valid[1]) if (*wb[1] == *virtMap[mem >> 12] && valid[1])
return cc[ci]; return cc[ci];
u32 way{((cc[ci].tags[0] >> 6) & 1) ^ ((cc[ci].tags[1] >> 6) & 1)}; const u32 way{(
(cc[ci].tags[0] >> 6) & 1) ^
((cc[ci].tags[1] >> 6) & 1)
};
const auto isDirty{static_cast<bool>(cc[ci].tags[way] & dirtyBit)}; const auto isDirty{static_cast<bool>(cc[ci].tags[way] & dirtyBit)};
if (write && mode == Data && isDirty) { if (write && mode == Data && isDirty) {
auto wrm{wb[way] + (mem & 0xfc0)}; u64 wrm{*wb[way] + (mem & 0xfc0)};
BitCast<u64*>(wrm)[0] = cc[ci].ec[way].large[0]; BitCast<u64*>(wrm)[0] = cc[ci].ec[way].large[0];
BitCast<u64*>(wrm)[1] = cc[ci].ec[way].large[1]; BitCast<u64*>(wrm)[1] = cc[ci].ec[way].large[1];
BitCast<u64*>(wrm)[2] = cc[ci].ec[way].large[2]; BitCast<u64*>(wrm)[2] = cc[ci].ec[way].large[2];
@ -155,9 +157,10 @@ namespace cosmic::ee {
BitCast<u64*>(wrm)[6] = cc[ci].ec[way].large[6]; BitCast<u64*>(wrm)[6] = cc[ci].ec[way].large[6];
BitCast<u64*>(wrm)[7] = cc[ci].ec[way].large[7]; BitCast<u64*>(wrm)[7] = cc[ci].ec[way].large[7];
} }
if (write) if (write) {
// If we are writing to the cache, the dirty bit must be set // If we are writing to the cache, the dirty bit must be set
cc[ci].tags[way] |= ~dirtyBit; cc[ci].tags[way] |= ~dirtyBit;
}
return cc[ci]; return cc[ci];
} }
} }

View File

@ -167,7 +167,7 @@ namespace cosmic::ee {
void EeMipsCore::handleException(u8 el, u32 exceptVec, u8 code) { void EeMipsCore::handleException(u8 el, u32 exceptVec, u8 code) {
cop0.cause.exCode = code & 0xd; cop0.cause.exCode = code & 0xd;
const u8 savePcId{static_cast<u8>(el == 1 ? 14 : 30)}; const auto savePcId{static_cast<u8>(el == 1 ? 14 : 30)};
if (isABranch) { if (isABranch) {
cop0.mtc0(savePcId, eePc - 4); cop0.mtc0(savePcId, eePc - 4);
} else { } else {

View File

@ -28,11 +28,6 @@ namespace cosmic::ee {
} }
u32 pcValue{}; u32 pcValue{};
}; };
struct EeFlowCtrl {
i64 cycles[1],
runCycles;
};
enum ExecutionMode : u8 { enum ExecutionMode : u8 {
// JIT compiler, the fastest option but with various interpretation issues // JIT compiler, the fastest option but with various interpretation issues
JitRe, JitRe,
@ -41,7 +36,7 @@ namespace cosmic::ee {
CachedInterpreter CachedInterpreter
}; };
class EeMipsCore : public EeFlowCtrl { class EeMipsCore {
static constexpr u8 countOfGPRs{32}; static constexpr u8 countOfGPRs{32};
public: public:
EeMipsCore(std::shared_ptr<mio::MemoryPipe>& pipe); EeMipsCore(std::shared_ptr<mio::MemoryPipe>& pipe);
@ -95,6 +90,9 @@ namespace cosmic::ee {
} }
bool isABranch{}; bool isABranch{};
u32 delaySlot{}; u32 delaySlot{};
i64 cycles[1],
runCycles;
ExecutionMode cpuMode{ExecutionMode::CachedInterpreter}; ExecutionMode cpuMode{ExecutionMode::CachedInterpreter};
CtrlCop cop0; CtrlCop cop0;
FpuCop cop1; FpuCop cop1;