From 5d9e150d2dcce5dacbfdc01c7afc86bcff62786a Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 30 Sep 2024 18:58:46 -0700 Subject: [PATCH] Changing strategy for async cdrom calls. --- src/mips/psyqo/cdrom-device.hh | 42 +++++++++-------- src/mips/psyqo/src/cdrom-device-cdda.cpp | 57 +++++++++++++++++++++--- src/mips/psyqo/src/cdrom-device.cpp | 51 +++------------------ 3 files changed, 80 insertions(+), 70 deletions(-) diff --git a/src/mips/psyqo/cdrom-device.hh b/src/mips/psyqo/cdrom-device.hh index ce7ff5d21..c95905d6a 100644 --- a/src/mips/psyqo/cdrom-device.hh +++ b/src/mips/psyqo/cdrom-device.hh @@ -245,7 +245,7 @@ class CDRomDevice final : public CDRom { * stop the CDRom drive motor, which means that another `playCDDA` * call start playing faster than if the motor was stopped. */ - static void pauseCDDA() { __asm__ volatile("break 14, 1\n"); } + void pauseCDDA(); /** * @brief Stops CDDA playback. @@ -255,7 +255,7 @@ class CDRomDevice final : public CDRom { * the CDRom drive motor, which means that another `playCDDA` call * will take longer to start playing than if the motor was not stopped. */ - static void stopCDDA() { __asm__ volatile("break 14, 2\n"); } + void stopCDDA(); /** * @brief Get the Playback location of the CDDA audio. @@ -278,22 +278,22 @@ class CDRomDevice final : public CDRom { * @brief Set the Volume of the CDDA audio. * * @details This method will set the volume of the CDDA audio. The - * volume is set using four values, which represent the volume of - * the left channel to the left speaker, the right channel to the - * left speaker, the left channel to the right speaker, and the - * right channel to the right speaker. The given output value - * should be in the range of 0 to 128, where 0 is silence and 128 - * is full volume. The values for a given output speaker will be - * added together, so clipping can occur if the sum of the values - * is greater than 128. The method can be used at any time, unlike - * the mute/unmute methods, which can only be used when the drive - * is idle. The normal volume setting is 0x80, 0x00, 0x00, 0x80. - * - * @param leftToLeft The volume of the left channel to the left speaker. - * @param rightToLeft The volume of the right channel to the left speaker. - * @param leftToRight The volume of the left channel to the right speaker. - * @param rightToRight The volume of the right channel to the right speaker. - */ + * volume is set using four values, which represent the volume of + * the left channel to the left speaker, the right channel to the + * left speaker, the left channel to the right speaker, and the + * right channel to the right speaker. The given output value + * should be in the range of 0 to 128, where 0 is silence and 128 + * is full volume. The values for a given output speaker will be + * added together, so clipping can occur if the sum of the values + * is greater than 128. The method can be used at any time, unlike + * the mute/unmute methods, which can only be used when the drive + * is idle. The normal volume setting is 0x80, 0x00, 0x00, 0x80. + * + * @param leftToLeft The volume of the left channel to the left speaker. + * @param rightToLeft The volume of the right channel to the left speaker. + * @param leftToRight The volume of the left channel to the right speaker. + * @param rightToRight The volume of the right channel to the right speaker. + */ void setVolume(uint8_t leftToLeft, uint8_t rightToLeft, uint8_t leftToRight, uint8_t rightToRight); /** @@ -336,7 +336,6 @@ class CDRomDevice final : public CDRom { bool m_success = false; bool m_blocking = false; bool m_pendingGetLocation = false; - uint8_t m_leftToLeft, m_rightToLeft, m_leftToRight, m_rightToRight; struct BlockingAction { BlockingAction(CDRomDevice *, GPU &); @@ -346,6 +345,11 @@ class CDRomDevice final : public CDRom { CDRomDevice *m_device; GPU &m_gpu; }; + + struct MaskedIRQ { + MaskedIRQ(); + ~MaskedIRQ(); + }; }; } // namespace psyqo diff --git a/src/mips/psyqo/src/cdrom-device-cdda.cpp b/src/mips/psyqo/src/cdrom-device-cdda.cpp index 7c6ae7975..39d192a85 100644 --- a/src/mips/psyqo/src/cdrom-device-cdda.cpp +++ b/src/mips/psyqo/src/cdrom-device-cdda.cpp @@ -193,19 +193,61 @@ void psyqo::CDRomDevice::resumeCDDA(eastl::function &&callback) { s_playCDDAAction.start(this, eastl::move(callback)); } +void psyqo::CDRomDevice::pauseCDDA() { + MaskedIRQ masked; + // If no action is in progress, it means we got + // raced to the end of the track and/or disc, and + // we should just ignore this. + if (m_action == nullptr) return; + // If we aren't actually playing audio, that's + // a fatal error. + Kernel::assert(m_state == 100, "CDRomDevice::pauseCDDA called while not playing"); + m_state = 101; + eastl::atomic_signal_fence(eastl::memory_order_release); + Hardware::CDRom::Command.send(Hardware::CDRom::CDL::PAUSE); +} + +void psyqo::CDRomDevice::stopCDDA() { + MaskedIRQ masked; + // If no action is in progress, it means we got + // raced to the end of the track and/or disc, and + // we should just ignore this. + if (m_action == nullptr) return; + // If we aren't actually playing audio, that's + // a fatal error. + Kernel::assert(m_state == 100, "CDRomDevice::stopCDDA called while not playing"); + m_state = 101; + eastl::atomic_signal_fence(eastl::memory_order_release); + Hardware::CDRom::Command.send(Hardware::CDRom::CDL::STOP); +} + void psyqo::CDRomDevice::getPlaybackLocation(eastl::function &&callback) { + MaskedIRQ masked; Kernel::assert(m_locationCallback == nullptr, "CDRomDevice::getPlaybackLocation while another one is pending"); + if (m_action == nullptr) { + Kernel::queueCallbackFromISR([callback = eastl::move(callback)]() { callback(nullptr); }); + return; + } m_locationCallback = eastl::move(callback); m_locationPtr = &m_locationStorage; - __asm__ volatile("break 14, 3"); + m_pendingGetLocation = true; + eastl::atomic_signal_fence(eastl::memory_order_release); + Hardware::CDRom::Command.send(Hardware::CDRom::CDL::GETLOCP); } void psyqo::CDRomDevice::getPlaybackLocation(PlaybackLocation *location, eastl::function &&callback) { + MaskedIRQ masked; Kernel::assert(m_locationCallback == nullptr, "CDRomDevice::getPlaybackLocation while another one is pending"); + if (m_action == nullptr) { + Kernel::queueCallbackFromISR([callback = eastl::move(callback)]() { callback(nullptr); }); + return; + } m_locationCallback = eastl::move(callback); m_locationPtr = location ? location : &m_locationStorage; - __asm__ volatile("break 14, 3"); + m_pendingGetLocation = true; + eastl::atomic_signal_fence(eastl::memory_order_release); + Hardware::CDRom::Command.send(Hardware::CDRom::CDL::GETLOCP); } psyqo::TaskQueue::Task psyqo::CDRomDevice::scheduleGetPlaybackLocation(PlaybackLocation *location) { @@ -229,9 +271,10 @@ void psyqo::CDRomDevice::ActionBase::queueGetLocationCallback(bool success) { } void psyqo::CDRomDevice::setVolume(uint8_t leftToLeft, uint8_t rightToLeft, uint8_t leftToRight, uint8_t rightToRight) { - m_leftToLeft = leftToLeft; - m_rightToLeft = rightToLeft; - m_leftToRight = leftToRight; - m_rightToRight = rightToRight; - __asm__ volatile("break 14, 4"); + MaskedIRQ masked; + Hardware::CDRom::LeftToLeftVolume = leftToLeft; + Hardware::CDRom::RightToLeftVolume = rightToLeft; + Hardware::CDRom::LeftToRightVolume = leftToRight; + Hardware::CDRom::RightToRightVolume = rightToRight; + Hardware::CDRom::VolumeSettings = 0x20; } diff --git a/src/mips/psyqo/src/cdrom-device.cpp b/src/mips/psyqo/src/cdrom-device.cpp index c80f84473..0a97090eb 100644 --- a/src/mips/psyqo/src/cdrom-device.cpp +++ b/src/mips/psyqo/src/cdrom-device.cpp @@ -48,50 +48,6 @@ void psyqo::CDRomDevice::prepare() { m_event = Kernel::openEvent(EVENT_CDROM, 0x1000, EVENT_MODE_CALLBACK, eastl::move(callback)); syscall_enableEvent(m_event); } - Kernel::queuePsyqoBreakHandler([this](uint32_t code) { - switch (code) { - // Pause CDDA playback - case 1: - // Stop CDDA playback - case 2: - // If no action is in progress, it means we got - // raced to the end of the track and/or disc, and - // we should just ignore this. - if (m_action == nullptr) return true; - // If we aren't actually playing audio, that's - // a fatal error. - if (m_state != 100) return false; - m_state = 101; - eastl::atomic_signal_fence(eastl::memory_order_release); - Hardware::CDRom::Command.send(code == 1 ? Hardware::CDRom::CDL::PAUSE : Hardware::CDRom::CDL::STOP); - return true; - // Get playback location - case 3: - // We got raced to the end of the track and/or disc, and we can't - // properly handle this request. Just ignore it and let the caller - // retry if they want to. - if (m_action == nullptr) { - Kernel::queueCallbackFromISR([callback = eastl::move(m_locationCallback)]() { callback(nullptr); }); - return true; - } - m_pendingGetLocation = true; - eastl::atomic_signal_fence(eastl::memory_order_release); - Hardware::CDRom::Command.send(Hardware::CDRom::CDL::GETLOCP); - return true; - // Set CDDA volume - case 4: - // This needs to be done in the interrupt handler, so we - // don't mess up the internal cdrom state machine if we - // happen to get an IRQ while changing these registers. - Hardware::CDRom::LeftToLeftVolume = m_leftToLeft; - Hardware::CDRom::RightToLeftVolume = m_rightToLeft; - Hardware::CDRom::LeftToRightVolume = m_leftToRight; - Hardware::CDRom::RightToRightVolume = m_rightToRight; - Hardware::CDRom::VolumeSettings = 0x20; - return true; - } - return false; - }); setVolume(0x80, 0x00, 0x00, 0x80); } @@ -208,6 +164,13 @@ psyqo::CDRomDevice::BlockingAction::~BlockingAction() { Hardware::CPU::IMask.set(Hardware::CPU::IRQ::CDRom); } +psyqo::CDRomDevice::MaskedIRQ::MaskedIRQ() { + Hardware::CPU::IMask.clear(Hardware::CPU::IRQ::CDRom); + Hardware::CPU::flushWriteQueue(); +} + +psyqo::CDRomDevice::MaskedIRQ::~MaskedIRQ() { Hardware::CPU::IMask.set(Hardware::CPU::IRQ::CDRom); } + void psyqo::CDRomDevice::actionComplete() { auto callback = eastl::move(m_callback); m_callback = nullptr;