mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-08-31 09:45:24 +02:00
Extends the SysconSerialMMIO stub added for VSH boot into a real command/ response protocol matching uofw's Syscon_cmd() reference exactly (packet framing, checksum, GPIO4 "response ready" handshake via a new GpioMMIO cross-module hook), with handling for NOP/read-write clock/read-write alarm commands. Still hitting a SIGSEGV though. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9 (cherry picked from commit 11887bf9e1fecd1eac56ec705c01b6fcfac09b2e)
192 lines
5.0 KiB
C++
192 lines
5.0 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#include <cstring>
|
|
|
|
#include "Core/HW/GpioMMIO.h"
|
|
|
|
namespace GpioMMIO {
|
|
|
|
namespace {
|
|
|
|
u32 g_regs[SIZE / 4];
|
|
|
|
constexpr u32 REG_INTR_ACK = 0x024;
|
|
|
|
} // namespace
|
|
|
|
u32 Read32(u32 address) {
|
|
u32 offset = address - BASE_ADDRESS;
|
|
return g_regs[offset / 4];
|
|
}
|
|
|
|
void Write32(u32 address, u32 value) {
|
|
u32 offset = address - BASE_ADDRESS;
|
|
if (offset == REG_INTR_ACK) {
|
|
// Acknowledging an interrupt clears the corresponding bit(s) in the triggered-status
|
|
// register, rather than storing the acknowledge value itself - matches uofw's usage
|
|
// (GpioAcquireIntr writes the same bit it's acknowledging) and JPCSP's
|
|
// acknowledgeInterrupt().
|
|
g_regs[REG_INTR_STATUS / 4] &= ~value;
|
|
return;
|
|
}
|
|
g_regs[offset / 4] = value;
|
|
}
|
|
|
|
void SetInterruptStatusBits(u32 bits) {
|
|
g_regs[REG_INTR_STATUS / 4] |= bits;
|
|
}
|
|
|
|
} // namespace GpioMMIO
|
|
|
|
namespace SysconSerialMMIO {
|
|
|
|
namespace {
|
|
|
|
// Real PSP Syscon command bytes (from JPCSP's sceSyscon.java, which lists the full real set -
|
|
// only the ones vsh_module's boot path is known to need are actually handled specially here).
|
|
enum SysconCmd : u8 {
|
|
CMD_NOP = 0x00,
|
|
CMD_READ_CLOCK = 0x09,
|
|
CMD_READ_ALARM = 0x0A,
|
|
CMD_WRITE_CLOCK = 0x20,
|
|
CMD_WRITE_ALARM = 0x22,
|
|
};
|
|
|
|
// Packet layout (shared between TX and RX, matching uofw's Syscon_cmd() and JPCSP's
|
|
// MMIOHandlerSyscon): byte 0 = command (TX) / status (RX), byte 1 = length in bytes
|
|
// (including these first two), bytes 2.. = payload, byte [length] = checksum
|
|
// (~sum(bytes[0..length-1]) & 0xFF).
|
|
constexpr int DATA_SIZE = 16;
|
|
u8 g_data[DATA_SIZE];
|
|
int g_dataIndex = 0;
|
|
int g_responseLen = 0;
|
|
bool g_dataExhausted = true;
|
|
|
|
// AC_SUPPLY | WLAN_POWER | POWER_SWITCH - matches JPCSP's MMIOHandlerSyscon.getBaryonStatus(),
|
|
// used as the RX status byte for every response (real hardware would report genuine baryon
|
|
// status bits here; this is just a plausible constant since PPSSPP doesn't model those).
|
|
constexpr u8 kBaryonStatus = 0x13;
|
|
|
|
// Persistent alarm value across sceSysconReadAlarm/WriteAlarm calls - mirrors JPCSP's
|
|
// sceSyscon.java readAlarm()/writeAlarm(), which are just as simple (a stored int, no real
|
|
// hardware backing).
|
|
u32 g_alarm = 0;
|
|
|
|
void ProcessCommand() {
|
|
u8 cmd = g_data[0];
|
|
|
|
// Sub-status byte: must not be 0x80 or 0x81 (uofw's Syscon_cmd() treats those as
|
|
// SYSCON_RES_80/81 and retries the whole command) - 0x82 is what JPCSP's own fallback
|
|
// path uses for exactly this reason.
|
|
u8 payload[DATA_SIZE] = { 0x82 };
|
|
int payloadLen = 1;
|
|
|
|
switch (cmd) {
|
|
case CMD_READ_CLOCK:
|
|
// No real hardware clock modeled - always reports zero, matching JPCSP's fallback.
|
|
memset(&payload[payloadLen], 0, 4);
|
|
payloadLen += 4;
|
|
break;
|
|
case CMD_READ_ALARM:
|
|
memcpy(&payload[payloadLen], &g_alarm, 4);
|
|
payloadLen += 4;
|
|
break;
|
|
case CMD_WRITE_CLOCK:
|
|
// Not modeled - accept and ignore, same as JPCSP's writeClock().
|
|
break;
|
|
case CMD_WRITE_ALARM:
|
|
memcpy(&g_alarm, &g_data[2], 4);
|
|
break;
|
|
case CMD_NOP:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
g_data[0] = kBaryonStatus;
|
|
g_data[1] = (u8)(payloadLen + 2);
|
|
memcpy(&g_data[2], payload, payloadLen);
|
|
u8 sum = 0;
|
|
for (int i = 0; i < g_data[1]; i++)
|
|
sum += g_data[i];
|
|
g_data[g_data[1]] = (u8)~sum;
|
|
|
|
g_dataIndex = 0;
|
|
g_responseLen = g_data[1];
|
|
g_dataExhausted = false;
|
|
|
|
// Signals "response ready" the way real hardware raising GPIO4 would - see
|
|
// uofw's Syscon_cmd(), which polls exactly this bit after triggering a command.
|
|
GpioMMIO::SetInterruptStatusBits(0x10);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
u32 Read32(u32 address) {
|
|
u32 offset = address - BASE_ADDRESS;
|
|
switch (offset) {
|
|
case 0x004:
|
|
return 0;
|
|
case 0x008:
|
|
{
|
|
u32 value = (g_data[g_dataIndex] << 8) | g_data[g_dataIndex + 1];
|
|
g_dataIndex += 2;
|
|
if (g_dataIndex > g_responseLen) {
|
|
g_dataIndex = 0;
|
|
g_dataExhausted = true;
|
|
}
|
|
return value;
|
|
}
|
|
case 0x00C:
|
|
{
|
|
u32 flags = 1; // bit 0: no error.
|
|
if (!g_dataExhausted)
|
|
flags |= 4; // bit 2: more response data available.
|
|
return flags;
|
|
}
|
|
case 0x018:
|
|
return 0;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void Write32(u32 address, u32 value) {
|
|
u32 offset = address - BASE_ADDRESS;
|
|
switch (offset) {
|
|
case 0x004:
|
|
if (value & 4) {
|
|
g_dataIndex = 0;
|
|
}
|
|
if (value & 2) {
|
|
ProcessCommand();
|
|
}
|
|
break;
|
|
case 0x008:
|
|
if (g_dataIndex + 1 < DATA_SIZE) {
|
|
g_data[g_dataIndex] = (value >> 8) & 0xFF;
|
|
g_data[g_dataIndex + 1] = value & 0xFF;
|
|
}
|
|
g_dataIndex += 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // namespace SysconSerialMMIO
|