diff --git a/src/mips/psyqo/cdrom-commandbuffer.hh b/src/mips/psyqo/cdrom-commandbuffer.hh new file mode 100644 index 000000000..bbe471cd9 --- /dev/null +++ b/src/mips/psyqo/cdrom-commandbuffer.hh @@ -0,0 +1,58 @@ +/* + +MIT License + +Copyright (c) 2025 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#pragma once + +#include + +#include +#include + +namespace psyqo::Hardware::CDRom { + +template +concept CDRomArgumentType = std::is_integral::value; + +struct CDRomCommandBuffer { + template + void set(T... values) { + size = sizeof...(values); + recursiveSet(0, values...); + } + + uint8_t buffer[16]; + uint8_t size = 0; + + private: + void recursiveSet(uint8_t pos, uint8_t arg) { buffer[pos] = arg; } + + template + void recursiveSet(uint8_t pos, uint8_t arg, T... args) { + buffer[pos] = arg; + recursiveSet(pos + 1, args...); + } +}; +} // namespace psyqo::Hardware::CDRom \ No newline at end of file diff --git a/src/mips/psyqo/cdrom-device.hh b/src/mips/psyqo/cdrom-device.hh index c17e66e95..69e7be28b 100644 --- a/src/mips/psyqo/cdrom-device.hh +++ b/src/mips/psyqo/cdrom-device.hh @@ -35,6 +35,7 @@ SOFTWARE. #include #include +#include "psyqo/cdrom-commandbuffer.hh" #include "psyqo/cdrom.hh" #include "psyqo/msf.hh" #include "psyqo/task.hh" @@ -412,6 +413,15 @@ class CDRomDevice final : public CDRom { */ void setVolume(uint8_t leftToLeft, uint8_t rightToLeft, uint8_t leftToRight, uint8_t rightToRight); + /** + * @brief Sends a test command to the CDRom mech + * + * @param callback The callback to call when the command operation is complete. + */ + void test(const psyqo::Hardware::CDRom::CDRomCommandBuffer &commandBuffer, eastl::function &&callback); + TaskQueue::Task scheduleTest(const psyqo::Hardware::CDRom::CDRomCommandBuffer &commandBuffer); + void testBlocking(GPU &, const psyqo::Hardware::CDRom::CDRomCommandBuffer &commandBuffer); + /** * @brief The action base class for the internal state machine. * diff --git a/src/mips/psyqo/hardware/cdrom.hh b/src/mips/psyqo/hardware/cdrom.hh index 1f5b6967d..2c4d382ea 100644 --- a/src/mips/psyqo/hardware/cdrom.hh +++ b/src/mips/psyqo/hardware/cdrom.hh @@ -26,6 +26,12 @@ SOFTWARE. #pragma once +#include + +#include +#include + +#include "psyqo/cdrom-commandbuffer.hh" #include "psyqo/hardware/hwregs.hh" namespace psyqo::Hardware::CDRom { @@ -78,6 +84,13 @@ struct Access { }; struct CommandFifo { + void send(CDL cmd, const CDRomCommandBuffer& commandBuffer) { + Ctrl = 0; + for (unsigned i = 0; i < commandBuffer.size; i++) { + Fifo = commandBuffer.buffer[i]; + } + Response = static_cast(cmd); + } void send(CDL cmd) { Ctrl = 0; Response = static_cast(cmd); diff --git a/src/mips/psyqo/src/cdrom-device-test.cpp b/src/mips/psyqo/src/cdrom-device-test.cpp new file mode 100644 index 000000000..eced65d4a --- /dev/null +++ b/src/mips/psyqo/src/cdrom-device-test.cpp @@ -0,0 +1,95 @@ +/* + +MIT License + +Copyright (c) 2025 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "psyqo/cdrom-device.hh" + +#include + +#include "psyqo/cdrom-commandbuffer.hh" +#include "psyqo/hardware/cdrom.hh" +#include "psyqo/kernel.hh" + +namespace { + +enum class TestActionState : uint8_t { + IDLE, + TEST, +}; + +class TestAction : public psyqo::CDRomDevice::Action { + public: + TestAction() : Action("TestAction") {} + + void start(psyqo::CDRomDevice *device, const psyqo::Hardware::CDRom::CDRomCommandBuffer &commandBuffer, + eastl::function &&callback) { + psyqo::Kernel::assert(device->isIdle(), "CDRomDevice::test() called while another action is in progress"); + registerMe(device); + setCallback(eastl::move(callback)); + setState(TestActionState::TEST); + eastl::atomic_signal_fence(eastl::memory_order_release); + psyqo::Hardware::CDRom::Command.send(psyqo::Hardware::CDRom::CDL::TEST, commandBuffer); + } + void start(psyqo::CDRomDevice *device, eastl::function &&callback) { + start(device, m_commandBuffer, eastl::move(callback)); + } + bool complete(const psyqo::CDRomDevice::Response &) override { + setSuccess(true); + return true; + } + bool acknowledge(const psyqo::CDRomDevice::Response &response) override { + setSuccess(true); + return true; + } + + psyqo::Hardware::CDRom::CDRomCommandBuffer m_commandBuffer; +}; + +TestAction s_testAction; + +} // namespace + +void psyqo::CDRomDevice::test(const psyqo::Hardware::CDRom::CDRomCommandBuffer &commandBuffer, + eastl::function &&callback) { + Kernel::assert(m_callback == nullptr, "CDRomDevice::test called with pending action"); + s_testAction.start(this, commandBuffer, eastl::move(callback)); +} + +psyqo::TaskQueue::Task psyqo::CDRomDevice::scheduleTest( + const psyqo::Hardware::CDRom::CDRomCommandBuffer &commandBuffer) { + s_testAction.m_commandBuffer = commandBuffer; + + return TaskQueue::Task( + [this](auto task) { s_testAction.start(this, [task](bool success) { task->complete(success); }); }); +} + +void psyqo::CDRomDevice::testBlocking(GPU &gpu, const psyqo::Hardware::CDRom::CDRomCommandBuffer &commandBuffer) { + Kernel::assert(m_callback == nullptr, "CDRomDevice::testBlocking called with pending action"); + bool success = false; + { + BlockingAction blocking(this, gpu); + s_testAction.start(this, commandBuffer, [&success](bool success_) { success = success_; }); + } +}