Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions ps2xIOP/src/modules/cri_dtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1181,13 +1181,10 @@ namespace ps2x::iop::detail
continue;
}

appendToSjrmtData(sjrmt->second,
chunkDataAddress,
chunkLength);
appendToSjrmtData(sjrmt->second, chunkDataAddress, chunkLength);
(void)writeGuestPod(m_host, commandAddress + 4u, sjx->second.eeObjectAddress);
constexpr uint8_t roomLine = 0u;
(void)m_host.writeGuest(commandAddress + 1u,
&roomLine,
sizeof(roomLine));
(void)m_host.writeGuest(commandAddress + 1u, &roomLine, sizeof(roomLine));
}
consumeActivePs2RnaStreamsLocked();
}
Expand Down
14 changes: 7 additions & 7 deletions ps2xRecomp/src/lib/mmi_translation_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ namespace ps2recomp
{
// Swaps halfwords 1<->3 and 5<->7 within the 128-bit register
return fmt::format("SET_GPR_VEC(ctx, {}, _mm_shufflelo_epi16(_mm_shufflehi_epi16(GPR_VEC(ctx, {}), _MM_SHUFFLE(2,3,0,1)), _MM_SHUFFLE(2,3,0,1)));",
inst.rd, inst.rs);
inst.rd, inst.rt);
}


Expand All @@ -465,7 +465,7 @@ namespace ps2recomp
// Reverses the order of the 8 halfwords
return fmt::format("{{ __m128i mask = _mm_setr_epi8(14,15, 12,13, 10,11, 8,9, 6,7, 4,5, 2,3, 0,1); "
"SET_GPR_VEC(ctx, {}, PS2_SHUFFLE_EPI8(GPR_VEC(ctx, {}), mask)); }}",
inst.rd, inst.rs);
inst.rd, inst.rt);
}


Expand Down Expand Up @@ -514,15 +514,15 @@ namespace ps2recomp
std::string CodeGenerator::translatePEXEW(const Instruction &inst)
{
return fmt::format("SET_GPR_VEC(ctx, {}, PS2_PEXEW(GPR_VEC(ctx, {})));",
inst.rd, inst.rs);
inst.rd, inst.rt);
}


std::string CodeGenerator::translatePROT3W(const Instruction &inst)
{
// Rotates words left by 3: [d,c,b,a] -> [a,d,c,b]
return fmt::format("SET_GPR_VEC(ctx, {}, _mm_shuffle_epi32(GPR_VEC(ctx, {}), _MM_SHUFFLE(0,3,2,1)));",
inst.rd, inst.rs);
inst.rd, inst.rt);
}


Expand Down Expand Up @@ -562,7 +562,7 @@ namespace ps2recomp
{
// Parallel Exchange Center Halfword (same as MMI2 PEXEH)
return fmt::format("SET_GPR_VEC(ctx, {}, _mm_shufflelo_epi16(_mm_shufflehi_epi16(GPR_VEC(ctx, {}), _MM_SHUFFLE(2,3,0,1)), _MM_SHUFFLE(2,3,0,1)));",
inst.rd, inst.rs);
inst.rd, inst.rt);
}


Expand All @@ -571,15 +571,15 @@ namespace ps2recomp
// Parallel Copy Halfword (Broadcast lower 16 bits of each 64-bit half)
return fmt::format("{{ __m128i src = GPR_VEC(ctx, {}); uint16_t l = _mm_extract_epi16(src, 0); uint16_t h = _mm_extract_epi16(src, 4); \n"
" SET_GPR_VEC(ctx, {}, _mm_set_epi16(h,h,h,h, l,l,l,l)); }}",
inst.rs, inst.rd);
inst.rt, inst.rd);
}


std::string CodeGenerator::translatePEXCW(const Instruction &inst)
{
// Parallel Exchange Center Word (Swaps words 0<>2, 1<>3)
return fmt::format("SET_GPR_VEC(ctx, {}, _mm_shuffle_epi32(GPR_VEC(ctx, {}), _MM_SHUFFLE(1,0,3,2)));",
inst.rd, inst.rs);
inst.rd, inst.rt);
}


Expand Down
2 changes: 2 additions & 0 deletions ps2xRuntime/include/runtime/ee_scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ class EeScheduler

// Kernel object API. All calls except postEvent/requestStop execute on the
// EE executor and therefore need no host synchronization.
void setupCurrentThread(uint32_t stack, uint32_t stackSize, uint32_t gp);
int createThread(const EeThreadCreateParams &params);
int deleteThread(int id, uint32_t &ownedStack);
int startThread(int id, uint32_t arg, const R5900Context &caller, bool interruptSafe);
Expand Down Expand Up @@ -416,6 +417,7 @@ class EeScheduler
bool m_rescheduleRequested = false;
bool m_timeSliceExpired = false;
bool m_insideInterrupt = false;
uint32_t m_pendingEeTimerInterrupts = 0;
uint64_t m_eeCycle = 0;
uint64_t m_sliceEndCycle = kDefaultTimeSliceCycles;
std::thread::id m_executorThread{};
Expand Down
20 changes: 17 additions & 3 deletions ps2xRuntime/include/runtime/ps2_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <cstddef>
#include <cstdint>
#include <array>
#include <functional>
#include <vector>
#include <unordered_map>
Expand Down Expand Up @@ -306,6 +307,12 @@ class PS2Memory
bool writeIORegister(uint32_t address, uint32_t value);
uint32_t readIORegister(uint32_t address);

// EE timers advance from the scheduler's emulated EE-cycle clock. The
// returned mask uses bits 0..3 for newly raised TIM0..TIM3 interrupts.
uint32_t advanceEeTimers(uint64_t eeCycles) noexcept;
[[nodiscard]] uint64_t cyclesUntilNextEeTimerInterrupt() const noexcept;
void resetEeTimers() noexcept;

using GifPacketCallback = std::function<void(const uint8_t *, uint32_t)>;
void setGifPacketCallback(GifPacketCallback cb) { m_gifPacketCallback = std::move(cb); }
void setGifArbiter(GifArbiter *arbiter) { m_gifArbiter = arbiter; }
Expand Down Expand Up @@ -432,10 +439,17 @@ class PS2Memory
bool isScratchpad(uint32_t address) const;
uint8_t *mapVuMemory(uint32_t physAddr, uint32_t size, uint32_t &offset, uint32_t &limit);
const uint8_t *mapVuMemory(uint32_t physAddr, uint32_t size, uint32_t &offset, uint32_t &limit) const;
void updateEeTimer0Counter();
struct EeTimer
{
uint32_t count = 0;
uint32_t mode = 0;
uint32_t compare = 0;
uint32_t hold = 0;
uint64_t clockRemainder = 0;
};

std::array<EeTimer, 4> m_eeTimers{};
void queueCompletedDmacCause(uint32_t cause);
uint64_t m_timer0LastHostNs = 0;
uint64_t m_timer0FractionNs = 0;
};

#endif // PS2_MEMORY_H
96 changes: 82 additions & 14 deletions ps2xRuntime/src/lib/Kernel/EeScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ namespace
return (microseconds * EeScheduler::kEeClockHz + 999999ull) / 1000000ull;
}

std::chrono::nanoseconds eeCyclesToHostDuration(uint64_t cycles)
{
constexpr uint64_t kNanosecondsPerSecond = 1000000000ull;
const uint64_t wholeSeconds = cycles / EeScheduler::kEeClockHz;
const uint64_t remainingCycles = cycles % EeScheduler::kEeClockHz;
const uint64_t remainingNanoseconds = (remainingCycles * kNanosecondsPerSecond + EeScheduler::kEeClockHz - 1u) / EeScheduler::kEeClockHz;
return std::chrono::seconds(wholeSeconds) + std::chrono::nanoseconds(remainingNanoseconds);
}

constexpr uint64_t kVBlankPeriodCycles = microsecondsToEeCycles(16667u);
constexpr uint64_t kVBlankDurationCycles = microsecondsToEeCycles(500u);
constexpr uint64_t kAlarmTickCycles = microsecondsToEeCycles(kAlarmTickMicroseconds);
Expand Down Expand Up @@ -101,6 +110,7 @@ void EeScheduler::reset(uint8_t *rdram, const R5900Context &mainContext)
m_rescheduleRequested = false;
m_timeSliceExpired = false;
m_insideInterrupt = false;
m_pendingEeTimerInterrupts = 0u;
m_eeCycle = 0u;
m_sliceEndCycle = kDefaultTimeSliceCycles;
m_stopRequested.store(false, std::memory_order_release);
Expand All @@ -121,12 +131,15 @@ void EeScheduler::reset(uint8_t *rdram, const R5900Context &mainContext)
m_gsVSyncCallbackGp = 0;
m_gsVSyncCallbackSp = 0;
m_runtime.memory().gs().vsyncTick.store(0u, std::memory_order_release);
m_runtime.memory().resetEeTimers();

GuestThread main{};
main.id = kMainThreadId;
main.context = mainContext;
main.entry = mainContext.pc;
main.stack = getRegU32(&mainContext, 29);
// $sp is live execution state, not the stable initial stack descriptor
// returned by ReferThreadStatus. SetupThread records that metadata.
main.stack = 0u;
main.gp = getRegU32(&mainContext, 28);
main.initialPriority = 0;
main.currentPriority = 0;
Expand Down Expand Up @@ -375,14 +388,35 @@ bool EeScheduler::checkpointDue(uint32_t cycles) noexcept

void EeScheduler::accountCycles(uint32_t cycles) noexcept
{
m_eeCycle += std::max<uint64_t>(1u, cycles);
const uint64_t elapsed = std::max<uint64_t>(1u, cycles);
m_eeCycle += elapsed;
m_pendingEeTimerInterrupts |= m_runtime.memory().advanceEeTimers(elapsed);
if (m_pendingEeTimerInterrupts != 0u)
{
m_checkpointPending.store(true, std::memory_order_release);
}
}

bool EeScheduler::isExecutingGuest() const noexcept
{
return m_guestExecuting.load(std::memory_order_acquire);
}

void EeScheduler::setupCurrentThread(uint32_t stack, uint32_t stackSize, uint32_t gp)
{
assertExecutor();
GuestThread *target = currentThread();
if (!target)
{
return;
}

target->stack = stack;
target->stackSize = stackSize;
target->gp = gp;
publishSnapshot();
}

int EeScheduler::createThread(const EeThreadCreateParams &params)
{
assertExecutor();
Expand Down Expand Up @@ -1702,6 +1736,15 @@ void EeScheduler::processPendingEvents()
{
assertExecutor();
processDueDeadlines();
const uint32_t timerInterrupts = m_pendingEeTimerInterrupts;
m_pendingEeTimerInterrupts = 0u;
for (uint32_t timer = 0u; timer < 4u; ++timer)
{
if ((timerInterrupts & (1u << timer)) != 0u)
{
dispatchIrq(false, 9u + timer);
}
}
std::deque<EeEvent> pending;
{
std::lock_guard lock(m_eventMutex);
Expand Down Expand Up @@ -1950,30 +1993,55 @@ void EeScheduler::waitForEvent()
{
return;
}
if (m_deadlines.empty())
const uint64_t timerCycles = m_runtime.memory().cyclesUntilNextEeTimerInterrupt();
const bool hasTimerDeadline = timerCycles != std::numeric_limits<uint64_t>::max();
if (m_deadlines.empty() && !hasTimerDeadline)
{
m_eventCv.wait(lock, [this]()
{ return !m_events.empty() || m_stopRequested.load(std::memory_order_acquire); });
return;
}

const auto next = std::min_element(m_deadlines.begin(), m_deadlines.end(),
[](const ScheduledEvent &left, const ScheduledEvent &right)
{
if (left.deadlineCycle != right.deadlineCycle)
uint64_t deadlineCycle = 0u;
auto hostDeadline = std::chrono::steady_clock::time_point::max();
if (!m_deadlines.empty())
{
const auto next = std::min_element(m_deadlines.begin(), m_deadlines.end(),
[](const ScheduledEvent &left, const ScheduledEvent &right)
{
return left.deadlineCycle < right.deadlineCycle;
}
return left.sequence < right.sequence;
});
const uint64_t deadlineCycle = next->deadlineCycle;
const auto hostDeadline = next->hostDeadline;
if (left.deadlineCycle != right.deadlineCycle)
{
return left.deadlineCycle < right.deadlineCycle;
}
return left.sequence < right.sequence;
});
deadlineCycle = next->deadlineCycle;
hostDeadline = next->hostDeadline;
}
if (hasTimerDeadline)
{
const auto timerHostDeadline = std::chrono::steady_clock::now() + eeCyclesToHostDuration(timerCycles);
if (timerHostDeadline < hostDeadline)
{
deadlineCycle = m_eeCycle + timerCycles;
hostDeadline = timerHostDeadline;
}
}

const bool signaled = m_eventCv.wait_until(lock, hostDeadline, [this]()
{ return !m_events.empty() ||
m_stopRequested.load(std::memory_order_acquire); });
if (!signaled)
{
m_eeCycle = std::max(m_eeCycle, deadlineCycle);
const uint64_t elapsed = deadlineCycle > m_eeCycle ? deadlineCycle - m_eeCycle : 0u;
lock.unlock();
uint64_t remaining = elapsed;
while (remaining > 0u)
{
const uint32_t step = static_cast<uint32_t>(std::min<uint64_t>(remaining, std::numeric_limits<uint32_t>::max()));
accountCycles(step);
remaining -= step;
}
m_checkpointPending.store(true, std::memory_order_release);
}
}
Expand Down
4 changes: 2 additions & 2 deletions ps2xRuntime/src/lib/Kernel/Stubs/Helpers/Support.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ namespace
uint32_t g_cdStreamingEndLbn = 0xFFFFFFFFu;
bool g_cdInitialized = false;

constexpr uint32_t kIopHeapBase = 0x01A00000;
constexpr uint32_t kIopHeapLimit = 0x01F00000;
constexpr uint32_t kIopHeapBase = 0x04000000;
constexpr uint32_t kIopHeapLimit = 0x04500000;
constexpr uint32_t kIopHeapAlign = 64;
uint32_t g_iopHeapNext = kIopHeapBase;

Expand Down
Loading