shadPS4/src/core/platform.h

89 lines
2.6 KiB
C
Raw Normal View History

2024-05-10 19:48:01 +00:00
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/singleton.h"
#include "common/types.h"
#include "magic_enum.hpp"
#include <functional>
#include <mutex>
#include <optional>
#include <queue>
namespace Platform {
enum class InterruptId : u32 {
Compute0RelMem = 0u,
Compute1RelMem = 1u,
Compute2RelMem = 2u,
Compute3RelMem = 3u,
Compute4RelMem = 4u,
Compute5RelMem = 5u,
Compute6RelMem = 6u,
GfxEop = 7u,
GfxFlip = 8u
2024-05-10 19:48:01 +00:00
};
using IrqHandler = std::function<void(InterruptId)>;
struct IrqController {
void RegisterOnce(InterruptId irq, IrqHandler handler) {
ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
auto& ctx = irq_contexts[static_cast<u32>(irq)];
std::unique_lock lock{ctx.m_lock};
ctx.one_time_subscribers.emplace(handler);
2024-05-10 19:48:01 +00:00
}
void Register(InterruptId irq, IrqHandler handler) {
ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
auto& ctx = irq_contexts[static_cast<u32>(irq)];
ASSERT_MSG(!ctx.persistent_handler.has_value(),
2024-05-10 19:48:01 +00:00
"Too many persistent handlers"); // Add a slot map if so
2024-05-10 21:51:24 +00:00
std::unique_lock lock{ctx.m_lock};
ctx.persistent_handler.emplace(handler);
2024-05-10 19:48:01 +00:00
}
void Unregister(InterruptId irq) {
ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Invalid IRQ number");
auto& ctx = irq_contexts[static_cast<u32>(irq)];
std::unique_lock lock{ctx.m_lock};
ctx.persistent_handler.reset();
2024-05-10 19:48:01 +00:00
}
void Signal(InterruptId irq) {
ASSERT_MSG(static_cast<u32>(irq) < irq_contexts.size(), "Unexpected IRQ signaled");
auto& ctx = irq_contexts[static_cast<u32>(irq)];
std::unique_lock lock{ctx.m_lock};
2024-05-10 21:51:24 +00:00
2024-05-10 19:48:01 +00:00
LOG_TRACE(Core, "IRQ signaled: {}", magic_enum::enum_name(irq));
if (ctx.persistent_handler) {
ctx.persistent_handler.value()(irq);
2024-05-10 21:51:24 +00:00
}
2024-05-10 19:48:01 +00:00
while (!ctx.one_time_subscribers.empty()) {
const auto& h = ctx.one_time_subscribers.front();
2024-05-10 21:51:24 +00:00
h(irq);
2024-05-10 19:48:01 +00:00
ctx.one_time_subscribers.pop();
2024-05-10 19:48:01 +00:00
}
}
private:
struct IrqContext {
std::optional<IrqHandler> persistent_handler{};
std::queue<IrqHandler> one_time_subscribers{};
std::mutex m_lock{};
};
std::array<IrqContext, magic_enum::enum_count<InterruptId>()> irq_contexts{};
2024-05-10 19:48:01 +00:00
};
using IrqC = Common::Singleton<IrqController>;
} // namespace Platform