From 61b6374a808b229bb2581ed21a9460b06a82f088 Mon Sep 17 00:00:00 2001 From: Gabriel Correia Date: Fri, 28 Jun 2024 00:37:21 -0300 Subject: [PATCH] `Core`: Fixes various inconsistencies and improves code efficiency --- README.md | 5 +- app/src/main/cpp/cosmic/ee/cop_dma.cpp | 4 +- app/src/main/cpp/cosmic/iop/iop_intc.cpp | 2 +- app/src/main/cpp/cosmic/iop/iop_timers.cpp | 28 +++++- app/src/main/cpp/cosmic/iop/iop_timers.h | 5 +- app/src/main/cpp/cosmic/mio/blocks.h | 6 ++ app/src/main/cpp/cosmic/mio/dma_move.cpp | 4 +- app/src/main/cpp/cosmic/mio/mem_pipe.cpp | 94 +++++++++++--------- app/src/main/cpp/cosmic/mio/mem_pipe.h | 73 +++++---------- app/src/main/cpp/cosmic/vm/emu_vm.cpp | 10 ++- app/src/main/cpp/cosmic/vm/sched_logical.cpp | 7 +- 11 files changed, 129 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index dabfad0..c75b7f0 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/app/src/main/cpp/cosmic/ee/cop_dma.cpp b/app/src/main/cpp/cosmic/ee/cop_dma.cpp index e11c405..42fe402 100644 --- a/app/src/main/cpp/cosmic/ee/cop_dma.cpp +++ b/app/src/main/cpp/cosmic/ee/cop_dma.cpp @@ -3,8 +3,8 @@ namespace cosmic::ee { bool CtrlCop::getCondition() { - u32 stat{mio::bitBashing(dmac->performRead(0x1000e10)) & 0x3ff}; - u32 pcr{mio::bitBashing(dmac->performRead(0x1000e020)) & 0x3ff}; + u32 stat{mio::BitBashing(dmac->performRead(0x1000e10)) & 0x3ff}; + u32 pcr{mio::BitBashing(dmac->performRead(0x1000e020)) & 0x3ff}; return ((~pcr | stat) & 0x3ff) == 0x3ff; } } diff --git a/app/src/main/cpp/cosmic/iop/iop_intc.cpp b/app/src/main/cpp/cosmic/iop/iop_intc.cpp index 8456ceb..57bf4a5 100644 --- a/app/src/main/cpp/cosmic/iop/iop_intc.cpp +++ b/app/src/main/cpp/cosmic/iop/iop_intc.cpp @@ -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]); diff --git a/app/src/main/cpp/cosmic/iop/iop_timers.cpp b/app/src/main/cpp/cosmic/iop/iop_timers.cpp index b6410d4..da39d92 100644 --- a/app/src/main/cpp/cosmic/iop/iop_timers.cpp +++ b/app/src/main/cpp/cosmic/iop/iop_timers.cpp @@ -7,13 +7,37 @@ namespace cosmic::iop { ioSched->modifyTimerSet(intEvents[index], vm::TimerSet::Pause, std::vector{0}); } + struct IopTimersCct { + u32 counter, control, target; + }; + std::array 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(value)); + else if (iotMap.target == address && write) + writeTarget(iopTimerIndex, value); + } + iopTimerIndex++; + }); + + return result; + } IopTimers::IopTimers(std::shared_ptr &source, std::shared_ptr &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 diff --git a/app/src/main/cpp/cosmic/iop/iop_timers.h b/app/src/main/cpp/cosmic/iop/iop_timers.h index 23ad567..3d95d3e 100644 --- a/app/src/main/cpp/cosmic/iop/iop_timers.h +++ b/app/src/main/cpp/cosmic/iop/iop_timers.h @@ -4,6 +4,7 @@ #include #include +#include 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); diff --git a/app/src/main/cpp/cosmic/mio/blocks.h b/app/src/main/cpp/cosmic/mio/blocks.h index 5294e67..6ec7c12 100644 --- a/app/src/main/cpp/cosmic/mio/blocks.h +++ b/app/src/main/cpp/cosmic/mio/blocks.h @@ -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, diff --git a/app/src/main/cpp/cosmic/mio/dma_move.cpp b/app/src/main/cpp/cosmic/mio/dma_move.cpp index 478399a..5f100b5 100644 --- a/app/src/main/cpp/cosmic/mio/dma_move.cpp +++ b/app/src/main/cpp/cosmic/mio/dma_move.cpp @@ -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; } diff --git a/app/src/main/cpp/cosmic/mio/mem_pipe.cpp b/app/src/main/cpp/cosmic/mio/mem_pipe.cpp index 898e0f7..bf04f30 100644 --- a/app/src/main/cpp/cosmic/mio/mem_pipe.cpp +++ b/app/src/main/cpp/cosmic/mio/mem_pipe.cpp @@ -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& devices) : devs(devices) { + MemoryPipe::MemoryPipe(std::shared_ptr& 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(value)); + devs->decoderMpeg12->issueACmd(BitBashing(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 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(value), !ro); + + return {}; + } + std::array 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(0, BitBashing(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(); 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 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) { diff --git a/app/src/main/cpp/cosmic/mio/mem_pipe.h b/app/src/main/cpp/cosmic/mio/mem_pipe.h index 0d6ed69..59fa93d 100644 --- a/app/src/main/cpp/cosmic/mio/mem_pipe.h +++ b/app/src/main/cpp/cosmic/mio/mem_pipe.h @@ -23,12 +23,12 @@ namespace cosmic::mio { return BitCast(pointer + address); } template - auto read(u32 address = 0) { - return *as(address); + auto virtRead(u32 address = 0) { + return *as(address); } template - void write(u32 address = 0, auto value = {}) { - *as(address) = value; + void virtWrite(u32 address = 0, auto value = {}) { + *as(address) = value; } VirtualPointer() = default; VirtualPointer(u8* addr) : pointer(addr) { @@ -43,27 +43,17 @@ namespace cosmic::mio { u8* pointer{}; }; template - 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::value) - return cleaned.to32(0); + return vec.to32(0); if constexpr (std::is_same::value) - return cleaned; + return vec; return {}; } class MemoryPipe { public: MemoryPipe(std::shared_ptr& 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 controller; - - os::vec readBack(VirtualPointer& virt, u64 size) { - if (size == sizeof(u32)) - return virt.read(); - return static_cast(0); - } - void writeBack(VirtualPointer& virt, const os::vec& value, u64 size) { - if (size == sizeof(u32)) { - virt.write(0, bitBashing(value)); - } - } + void resetIoVariables(); enum MemoryOrderFuncId { IpuRelatedAddr, - DmaRelatedAddr + DmaRelatedAddr, + IopRelatedAddr, }; private: std::shared_ptr 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 - [[gnu::always_inline]] auto PipeCraftPtr( - std::shared_ptr& mem, - u32 address, - PipeAccess dev = CoreDevices) { - return mem->directPointer(address, dev).as(); + auto PipeCraftPtr(std::shared_ptr& pipe, + u32 address, PipeAccess dev = CoreDevices) { + return pipe->directPointer(address, dev).as(); } template - [[gnu::always_inline]] auto PipeRead( - std::shared_ptr& mem, - u32 address, - PipeAccess dev = CoreDevices) { - return mem->readGlobal(address, sizeof(T), dev).as(); + auto PipeRead(std::shared_ptr& pipe, + u32 address, PipeAccess dev = CoreDevices) { + return pipe->readGlobal(address, sizeof(T), dev).as(); } template - [[gnu::always_inline]] void PipeWrite( - std::shared_ptr& mem, - u32 address, - os::vec value, - PipeAccess dev = CoreDevices) { - mem->writeGlobal(address, value, sizeof(T), dev); + void PipeWrite(std::shared_ptr& pipe, + u32 address, const os::vec& value, PipeAccess dev = CoreDevices) { + pipe->writeGlobal(address, value, sizeof(T), dev); } } \ No newline at end of file diff --git a/app/src/main/cpp/cosmic/vm/emu_vm.cpp b/app/src/main/cpp/cosmic/vm/emu_vm.cpp index f365a0e..d7d6756 100644 --- a/app/src/main/cpp/cosmic/vm/emu_vm.cpp +++ b/app/src/main/cpp/cosmic/vm/emu_vm.cpp @@ -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{}; diff --git a/app/src/main/cpp/cosmic/vm/sched_logical.cpp b/app/src/main/cpp/cosmic/vm/sched_logical.cpp index d706a1c..952c4df 100644 --- a/app/src/main/cpp/cosmic/vm/sched_logical.cpp +++ b/app/src/main/cpp/cosmic/vm/sched_logical.cpp @@ -1,6 +1,8 @@ #include #include namespace cosmic::vm { + constexpr u64 maxCycle{std::numeric_limits::max()}; + void Scheduler::runTasks() { if (eeCycles.cycles < nearestEventCycle) return; @@ -47,7 +49,7 @@ namespace cosmic::vm { iopCycles.cycles = 0; // iopCycles = {}; - nearestEventCycle = std::numeric_limits::max(); + nearestEventCycle = maxCycle; std::list ee{}; std::vector te{}; @@ -104,7 +106,7 @@ namespace cosmic::vm { if (pause) { auto event{searchIdEvent(sid)}; - event->insideCycleCount = std::numeric_limits::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::max()}; if (!isEvent) { TimerSched timer{