Core: Fixes various inconsistencies and improves code efficiency

This commit is contained in:
Gabriel Correia 2024-06-28 00:37:21 -03:00
parent 1dc6a03a69
commit 61b6374a80
11 changed files with 129 additions and 109 deletions

View File

@ -1,14 +1,13 @@
# Cosmic Project
### Project Progress:
- Progression: ```17%```
- Progression: ```19%```
- Current version: 0.0.20 (Pre-Boot stage)
- Target for the first demo release: 2025
- Top priority: Adding the IO coprocessor timers (IOP TIMERS)
- Top priority: Test everything already done
### Special thanks
- [DobieStation](https://github.com/PSI-Rockin/DobieStation.git) Used as the main reference for the project
- [Strato](https://github.com/strato-emu/strato.git) The main structure of the project was based on another emulation project
- [libadrenotools](https://github.com/bylaws/libadrenotools.git) The custom driver management system was implemented following the steps of this project
### Reference to third-party resources and assets used

View File

@ -3,8 +3,8 @@
namespace cosmic::ee {
bool CtrlCop::getCondition() {
u32 stat{mio::bitBashing<u32>(dmac->performRead(0x1000e10)) & 0x3ff};
u32 pcr{mio::bitBashing<u32>(dmac->performRead(0x1000e020)) & 0x3ff};
u32 stat{mio::BitBashing<u32>(dmac->performRead(0x1000e10)) & 0x3ff};
u32 pcr{mio::BitBashing<u32>(dmac->performRead(0x1000e020)) & 0x3ff};
return ((~pcr | stat) & 0x3ff) == 0x3ff;
}
}

View File

@ -49,7 +49,7 @@ namespace cosmic::iop {
"Usb",
"EXTR",
"FireWire",
"FDma" // FIreWire DMA? (unknown)
"FDma" // FireWire DMA? (unknown)
};
if (stat < iopIrqStats.size()) {
user->info("Stat flag being read, output value: {}", iopIrqStats[stat]);

View File

@ -7,13 +7,37 @@ namespace cosmic::iop {
ioSched->modifyTimerSet(intEvents[index],
vm::TimerSet::Pause, std::vector<u64>{0});
}
struct IopTimersCct {
u32 counter, control, target;
};
std::array<IopTimersCct, 1> iopTimersArea {
{{0x1f801120, 0x1f801124, 0x1f801128}}
};
os::vec IopTimers::performTimerAccess(u32 address, u32 value, bool write) {
u64 iopTimerIndex{};
os::vec result{};
ranges::for_each(iopTimersArea, [&](const auto& iotMap) {
if (iotMap.counter >= address && iotMap.target <= address) {
if (iotMap.counter == address && write)
writeCounter(iopTimerIndex, value);
else if (iotMap.control == address && write)
writeCtrl(iopTimerIndex, static_cast<u16>(value));
else if (iotMap.target == address && write)
writeTarget(iopTimerIndex, value);
}
iopTimerIndex++;
});
return result;
}
IopTimers::IopTimers(std::shared_ptr<vm::Scheduler> &source,
std::shared_ptr<console::IntCInfra> &infra) :
ioSched(source), infra(infra) {
}
void IopTimers::resetIoTimers() {
ranges::for_each(ioTimers, [](auto& timer){
ranges::for_each(ioTimers,
[](auto& timer){
timer = {};
});
timerIntEnbId = ioSched->createSchedTick(
@ -130,7 +154,7 @@ namespace cosmic::iop {
clockRate = 0;
}
enum PreScalesFactor {
Normal, // IOP clock,
Normal, // IOP clock
Scale8,
Scale16,
Scale256

View File

@ -4,6 +4,7 @@
#include <console/intc.h>
#include <vm/sched_logical.h>
#include <os/neon_simd.h>
namespace cosmic::iop {
struct TimerControl {
bool useGate;
@ -12,7 +13,7 @@ namespace cosmic::iop {
bool cmpIntEnb;
bool overIntEnb;
bool repeatInt;
// toggle bit 10 (intEnable) on IRQs if bit 6 (repeatInt) is set.
// toggle bit 10 (intEnable) on IRQs if bit 6 (repeatInt) is set
bool toggleInt;
bool intEnable;
bool externSignal;
@ -38,6 +39,8 @@ namespace cosmic::iop {
void writeCounter(u64 index, u32 value);
void writeCtrl(u64 index, u16 value);
void writeTarget(u64 index, u32 value);
os::vec performTimerAccess(u32 address, u32 value, bool write);
private:
void timerIrqTest(u64 index, bool overflow);
[[clang::always_inline]] void clearTimerCounter(u64 index);

View File

@ -24,6 +24,12 @@ namespace cosmic::mio {
[[maybe_unused]] void iopSoftClean() {
memset(*iopBlock, 0, iopBlock.getBlockSize());
}
[[maybe_unused]] void sndSoftClean() {
memset(*sndBlock, 0, sndBlock.getBlockSize());
}
[[maybe_unused]] void ramSoftClean() {
memset(*ramBlock, 0, ramBlock.getBlockSize());
}
void printMemoryImage();
private:
void dumpMemoryToDisk(boost::filesystem::path& devOutFile,

View File

@ -69,7 +69,7 @@ namespace cosmic::mio {
}
// 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);
user->info("The channel {} is waiting ({} - {})", channelsName[chan.index], chan.adr, stallAddress);
raiseInt1();
intStat.channelStat[DmaStall] = true;
@ -95,7 +95,7 @@ namespace cosmic::mio {
}
os::vec DmaController::performRead(u32 address) {
os::vec fetched{};
auto dmaHas{dmaVirtSolver(address)};
const auto dmaHas{dmaVirtSolver(address)};
if (!dmaHas) {
return fetched;
}

View File

@ -6,27 +6,31 @@
namespace cosmic::mio {
VirtualPointer MemoryPipe::solveGlobal(u32 address, PipeAccess dev) {
auto isMips{dev == IopDev || dev == CoreDevices};
VirtualPointer virtAddress{};
if (address >= 0x1fc00000 && address < 0x20000000 && isMips) {
return directPointer(address, dev);
virtAddress = directPointer(address, dev);
}
if (dev == IopDev) {
if (address < 0x00200000)
return directPointer(address, dev);
return iopHalLookup(address);
virtAddress = directPointer(address, dev);
else
virtAddress = iopHalLookup(address);
} else if (dev == CoreDevices) {
return directPointer(address, dev);
virtAddress = directPointer(address, dev);
}
return {};
return virtAddress;
}
MemoryPipe::MemoryPipe(std::shared_ptr<console::VirtDevices>& devices) : devs(devices) {
MemoryPipe::MemoryPipe(std::shared_ptr<console::VirtDevices>& devices) :
devs(devices) {
}
struct GlobalRangeSpecs {
u32 starts;
u32 ends;
MemoryPipe::MemoryOrderFuncId funcId;
MemoryPipe::MemoryOrderFuncId function;
};
os::vec MemoryPipe::imageDecoderGlb(u32 address, os::vec value, u64 size, bool ro) {
os::vec MemoryPipe::imageDecoderGlb(u32 address, const os::vec& value, u64 size, bool ro) {
os::vec ipu{};
switch (address) {
@ -34,77 +38,87 @@ namespace cosmic::mio {
if (size != sizeof(u32))
break;
if (ro)
devs->decoderMpeg12->issueACmd(bitBashing<u32>(value));
devs->decoderMpeg12->issueACmd(BitBashing<u32>(value));
}
return ipu;
}
os::vec MemoryPipe::dmaAddrCollector(u32 address, os::vec value, u64 size, bool ro) {
os::vec MemoryPipe::dmaAddrCollector(u32 address, const os::vec& value, u64 size, bool ro) {
os::vec from{};
if (ro)
from = controller->performRead(address);
return from;
}
std::array<GlobalRangeSpecs, 2> globalRanges{{
os::vec MemoryPipe::iopSpecialRegs(u32 address, const os::vec& value, u64 size, bool ro) {
u64 iopTimerIndex{};
os::vec result{};
switch (address) {
}
result = devs->mipsIop->timer->performTimerAccess(address, BitBashing<u32>(value), !ro);
return {};
}
std::array<GlobalRangeSpecs, 3> globalRanges{{
{0x10002000, 0x10002030, MemoryPipe::IpuRelatedAddr},
{0x10008000, 0x1000f000, MemoryPipe::DmaRelatedAddr}
{0x10008000, 0x1000f000, MemoryPipe::DmaRelatedAddr},
{0x1f801070, 0x1f801574, MemoryPipe::IopRelatedAddr},
}};
void MemoryPipe::writeGlobal(u32 address, os::vec value, u64 size, PipeAccess dev) {
pointer[0] = solveGlobal(address, dev);
void MemoryPipe::writeGlobal(u32 address, const os::vec& value, u64 size, PipeAccess dev) {
pointer = solveGlobal(address, dev);
bool threat{};
ranges::for_each(globalRanges, [&](auto& region) {
if (region.starts >= address && region.ends < address) {
switch (region.funcId) {
switch (region.function) {
case IpuRelatedAddr:
imageDecoderGlb(address, value, size, false); break;
case DmaRelatedAddr:
dmaAddrCollector(address, value, size, false); break;
case IopRelatedAddr:
iopSpecialRegs(address, value, size, false); break;
}
threat = true;
}
});
if (!threat && pointer[0]) {
writeBack(pointer[0], value, size);
}
if (!threat && pointer && size == sizeof(u32))
pointer.virtWrite<u32>(0, BitBashing<u32>(value));
}
os::vec MemoryPipe::readGlobal(u32 address, u64 size, PipeAccess dev) {
pointer[0] = solveGlobal(address, dev);
pointer = solveGlobal(address, dev);
bool threat{};
os::vec result{};
ranges::for_each(globalRanges, [&](auto& region) {
if (region.starts >= address && region.ends < address) {
switch (region.funcId) {
switch (region.function) {
case IpuRelatedAddr:
result = imageDecoderGlb(address, 0, size, true);
result = imageDecoderGlb(address, {}, size, true);
case DmaRelatedAddr:
result = dmaAddrCollector(address, 0, size, true);
result = dmaAddrCollector(address, {}, size, true);
case IopRelatedAddr:
result = iopSpecialRegs(address, {}, size, false); break;
}
threat = true;
}
});
if (!threat && pointer[0]) {
result = readBack(pointer[0], size);
}
if (!threat && pointer && size == sizeof(u32))
result = pointer.virtRead<u32>();
return result;
}
// https://www.psx-place.com/threads/ps2s-builtin-ps1-functions-documentation.26901/
enum PsxMode { Psx2Only = 0, Psx1Compatibility = 0x8 };
u32 hwIoCfg{Psx2Only};
u32 sSbus{};
u32 hole{};
u32 hwIoCfg,
sSbus,
hole;
struct IopTimersCct {
u32 counter, control, target;
};
std::array<IopTimersCct, 1> iopTimersArea {
{{0x1f801120, 0x1f801124, 0x1f801128}}
};
void MemoryPipe::resetIoVariables() {
hwIoCfg = Psx2Only;
sSbus = {};
hole = {};
}
VirtualPointer MemoryPipe::iopHalLookup(u32 address) {
switch (address) {
@ -116,15 +130,7 @@ namespace cosmic::mio {
// checking if the processor supports PS1 mode
return &hwIoCfg;
}
ranges::for_each(iopTimersArea, [&](const auto& tXMap) {
if (tXMap.counter == address) {
}
if (tXMap.control == address) {
}
if (tXMap.target == address) {
}
});
return &hole;
return {};
}
VirtualPointer MemoryPipe::directPointer(u32 address, PipeAccess dev) {
switch (dev) {

View File

@ -23,12 +23,12 @@ namespace cosmic::mio {
return BitCast<T>(pointer + address);
}
template<typename T>
auto read(u32 address = 0) {
return *as<T>(address);
auto virtRead(u32 address = 0) {
return *as<T*>(address);
}
template<typename T>
void write(u32 address = 0, auto value = {}) {
*as<T>(address) = value;
void virtWrite(u32 address = 0, auto value = {}) {
*as<T*>(address) = value;
}
VirtualPointer() = default;
VirtualPointer(u8* addr) : pointer(addr) {
@ -43,27 +43,17 @@ namespace cosmic::mio {
u8* pointer{};
};
template<typename T = os::vec>
T bitBashing(const os::vec& vec) {
os::vec clb{0xff};
switch (sizeof(T) * 8) {
case 16: clb = 0xffff; break;
case 32: clb = 0xffffffff; break;
case 64: clb = 0xffffffffffffffff; break;
case 128:
// This will clean all bits to 0
clb = {0xffffffffffffffff, 0xffffffffffffffff};
}
const os::vec cleaned{vec & clb};
T BitBashing(const os::vec& vec) {
if constexpr (std::is_same<T, u32>::value)
return cleaned.to32(0);
return vec.to32(0);
if constexpr (std::is_same<T, os::vec>::value)
return cleaned;
return vec;
return {};
}
class MemoryPipe {
public:
MemoryPipe(std::shared_ptr<console::VirtDevices>& devices);
void writeGlobal(u32 address, os::vec value, u64 size, PipeAccess dev);
void writeGlobal(u32 address, const os::vec& value, u64 size, PipeAccess dev);
os::vec readGlobal(u32 address, u64 size, PipeAccess dev);
VirtualPointer solveGlobal(u32 address = 0, PipeAccess dev = CoreDevices);
@ -71,50 +61,35 @@ namespace cosmic::mio {
VirtualPointer directPointer(u32 address, PipeAccess dev);
std::shared_ptr<DmaController> controller;
os::vec readBack(VirtualPointer& virt, u64 size) {
if (size == sizeof(u32))
return virt.read<u32*>();
return static_cast<u32>(0);
}
void writeBack(VirtualPointer& virt, const os::vec& value, u64 size) {
if (size == sizeof(u32)) {
virt.write<u32*>(0, bitBashing<u32>(value));
}
}
void resetIoVariables();
enum MemoryOrderFuncId {
IpuRelatedAddr,
DmaRelatedAddr
DmaRelatedAddr,
IopRelatedAddr,
};
private:
std::shared_ptr<console::VirtDevices> devs;
VirtualPointer pointer[1];
VirtualPointer pointer;
os::vec imageDecoderGlb(u32 address, os::vec value, u64 size, bool ro);
os::vec dmaAddrCollector(u32 address, os::vec value, u64 size, bool ro);
os::vec imageDecoderGlb(u32 address, const os::vec& value, u64 size, bool ro);
os::vec dmaAddrCollector(u32 address, const os::vec& value, u64 size, bool ro);
os::vec iopSpecialRegs(u32 address, const os::vec& value, u64 size, bool ro);
};
template <typename T>
[[gnu::always_inline]] auto PipeCraftPtr(
std::shared_ptr<MemoryPipe>& mem,
u32 address,
PipeAccess dev = CoreDevices) {
return mem->directPointer(address, dev).as<T>();
auto PipeCraftPtr(std::shared_ptr<MemoryPipe>& pipe,
u32 address, PipeAccess dev = CoreDevices) {
return pipe->directPointer(address, dev).as<T>();
}
template <typename T>
[[gnu::always_inline]] auto PipeRead(
std::shared_ptr<MemoryPipe>& mem,
u32 address,
PipeAccess dev = CoreDevices) {
return mem->readGlobal(address, sizeof(T), dev).as<T>();
auto PipeRead(std::shared_ptr<MemoryPipe>& pipe,
u32 address, PipeAccess dev = CoreDevices) {
return pipe->readGlobal(address, sizeof(T), dev).as<T>();
}
template <typename T>
[[gnu::always_inline]] void PipeWrite(
std::shared_ptr<MemoryPipe>& mem,
u32 address,
os::vec value,
PipeAccess dev = CoreDevices) {
mem->writeGlobal(address, value, sizeof(T), dev);
void PipeWrite(std::shared_ptr<MemoryPipe>& pipe,
u32 address, const os::vec& value, PipeAccess dev = CoreDevices) {
pipe->writeGlobal(address, value, sizeof(T), dev);
}
}

View File

@ -89,13 +89,13 @@ namespace cosmic::vm {
status.clearStatus();
scheduler->resetCycles();
// Resetting all co-processors
mips->resetCore();
gsGif->resetGif();
gsCore->resetGraphics();
sharedPipe->controller->resetMa();
sharedPipe->resetIoVariables();
mpegDecoder->resetDecoder();
mips->timer->resetTimers();
@ -108,7 +108,13 @@ namespace cosmic::vm {
ioDma->resetIoDma();
sound->resetSound();
// iop->iopMem->controller->mapped->iopSoftClean();
#if !defined(NDEBUG)
// Memory is assumed to be random content by a early moment before tbe 1ft boot stage,
// but for debugging purposes, we will cleanup everything from now (at least the EE memory)
iop->iopMem->controller->mapped->iopSoftClean();
iop->iopMem->controller->mapped->sndSoftClean();
iop->iopMem->controller->mapped->ramSoftClean();
#endif
}
void EmuVm::dealWithSyscalls() {
hle::SyscallOrigin origin{};

View File

@ -1,6 +1,8 @@
#include <vm/sched_logical.h>
#include <common/global.h>
namespace cosmic::vm {
constexpr u64 maxCycle{std::numeric_limits<u64>::max()};
void Scheduler::runTasks() {
if (eeCycles.cycles < nearestEventCycle)
return;
@ -47,7 +49,7 @@ namespace cosmic::vm {
iopCycles.cycles = 0;
// iopCycles = {};
nearestEventCycle = std::numeric_limits<u64>::max();
nearestEventCycle = maxCycle;
std::list<EventSched> ee{};
std::vector<TimerSched> te{};
@ -104,7 +106,7 @@ namespace cosmic::vm {
if (pause) {
auto event{searchIdEvent(sid)};
event->insideCycleCount = std::numeric_limits<u64>::max();
event->insideCycleCount = maxCycle;
} else {
pickedTimer.lastUpdate = eeCycles.cycles;
}
@ -188,7 +190,6 @@ namespace cosmic::vm {
}
auto result{sid};
result = {};
constexpr u64 maxCycle{std::numeric_limits<u64>::max()};
if (!isEvent) {
TimerSched timer{