Skip to content

Commit 19598ec

Browse files
authored
Merge branch 'grumpycoders:main' into Breakpoints-improvements
2 parents 46109a2 + e6f816d commit 19598ec

File tree

12 files changed

+267
-51
lines changed

12 files changed

+267
-51
lines changed

LICENSES.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
R"(
22

3-
PCSX-Redux, Copyright (C) 2019-2024 [PCSX-Redux authors](AUTHORS)
3+
PCSX-Redux, Copyright (C) 2019-2025 [PCSX-Redux authors](AUTHORS)
44
PCSX-Redux comes with ABSOLUTELY NO WARRANTY.
55
This is free software, and you are welcome to redistribute it
66
under certain conditions. See [the license](https://github.com/grumpycoders/pcsx-redux/blob/main/LICENSE) for details.
77

8-
OpenBIOS, Copyright (C) 2019-2024 [PCSX-Redux authors](AUTHORS)
8+
OpenBIOS, Copyright (C) 2019-2025 [PCSX-Redux authors](AUTHORS)
99
OpenBIOS comes with ABSOLUTELY NO WARRANTY.
1010
This is free software, and you are welcome to redistribute it
1111
under certain conditions. See [the license](https://github.com/grumpycoders/pcsx-redux/blob/main/src/mips/LICENSE) for details.

src/core/debug.cc

Lines changed: 113 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "core/psxemulator.h"
2929
#include "core/psxmem.h"
3030
#include "core/r3000a.h"
31+
#include "supportpsx/memory.h"
3132

3233
enum {
3334
MAP_EXEC = 1,
@@ -40,80 +41,134 @@ enum {
4041
MAP_EXEC_JAL = 128,
4142
};
4243

44+
PCSX::Debug::Debug() : m_listener(g_system->m_eventBus) {
45+
m_listener.listen<PCSX::Events::ExecutionFlow::Reset>([this](auto&) {
46+
m_checkKernel = false;
47+
clearMaps();
48+
});
49+
}
50+
4351
uint32_t PCSX::Debug::normalizeAddress(uint32_t address) {
44-
uint32_t base = (address >> 20) & 0xffc;
45-
uint32_t real = address & 0x7fffff;
52+
PSXAddress addr(address);
4653
const bool ramExpansion = PCSX::g_emulator->settings.get<PCSX::Emulator::Setting8MB>();
47-
if (!ramExpansion && ((base == 0x000) || (base == 0x800) || (base == 0xa00))) {
48-
return address & ~0x00600000;
54+
if (!ramExpansion && (addr.type == PSXAddress::Type::RAM)) {
55+
addr.physical &= ~0x00600000;
4956
}
50-
return address;
57+
return addr.toVirtual().value_or(0xffffffff);
58+
}
59+
60+
bool PCSX::Debug::isInKernel(uint32_t address, bool biosIsKernel) {
61+
PSXAddress addr(address);
62+
const bool ramExpansion = PCSX::g_emulator->settings.get<PCSX::Emulator::Setting8MB>();
63+
if (addr.type == PSXAddress::Type::ROM) return biosIsKernel;
64+
if (addr.type != PSXAddress::Type::RAM) return false;
65+
if (!ramExpansion) addr.physical &= ~0x00600000;
66+
return addr.physical < 0x10000;
5167
}
5268

5369
void PCSX::Debug::markMap(uint32_t address, int mask) {
54-
address = normalizeAddress(address);
55-
uint32_t base = (address >> 20) & 0xffc;
56-
uint32_t real = address & 0x7fffff;
57-
uint32_t shortReal = address & 0x3fffff;
58-
if (((base == 0x000) || (base == 0x800) || (base == 0xa00)) && (real < sizeof(m_mainMemoryMap))) {
59-
m_mainMemoryMap[real] |= mask;
60-
} else if ((base == 0x1f8) && (real < sizeof(m_scratchPadMap))) {
61-
m_scratchPadMap[real] |= mask;
62-
} else if ((base == 0xbfc) && (shortReal < sizeof(m_biosMemoryMap))) {
63-
m_biosMemoryMap[shortReal] |= mask;
70+
PSXAddress addr(normalizeAddress(address));
71+
72+
switch (addr.type) {
73+
case PSXAddress::Type::RAM:
74+
if (addr.physical < sizeof(m_mainMemoryMap)) {
75+
m_mainMemoryMap[addr.physical] |= mask;
76+
}
77+
break;
78+
case PSXAddress::Type::ScratchPad:
79+
if (addr.physical < sizeof(m_scratchPadMap)) {
80+
m_scratchPadMap[addr.physical] |= mask;
81+
}
82+
break;
83+
case PSXAddress::Type::ROM:
84+
if (addr.physical < sizeof(m_biosMemoryMap)) {
85+
m_biosMemoryMap[addr.physical] |= mask;
86+
}
87+
break;
6488
}
6589
}
6690

6791
bool PCSX::Debug::isMapMarked(uint32_t address, int mask) {
68-
address = normalizeAddress(address);
69-
uint32_t base = (address >> 20) & 0xffc;
70-
uint32_t real = address & 0x7fffff;
71-
uint32_t shortReal = address & 0x3fffff;
72-
if (((base == 0x000) || (base == 0x800) || (base == 0xa00)) && (real < sizeof(m_mainMemoryMap))) {
73-
return m_mainMemoryMap[real] & mask;
74-
} else if ((base == 0x1f8) && (real < sizeof(m_scratchPadMap))) {
75-
return m_scratchPadMap[real] & mask;
76-
} else if ((base == 0xbfc) && (shortReal < sizeof(m_biosMemoryMap))) {
77-
return m_biosMemoryMap[shortReal] & mask;
92+
PSXAddress addr(normalizeAddress(address));
93+
94+
switch (addr.type) {
95+
case PSXAddress::Type::RAM:
96+
if (addr.physical < sizeof(m_mainMemoryMap)) {
97+
return m_mainMemoryMap[addr.physical] & mask;
98+
}
99+
break;
100+
case PSXAddress::Type::ScratchPad:
101+
if (addr.physical < sizeof(m_scratchPadMap)) {
102+
return m_scratchPadMap[addr.physical] & mask;
103+
}
104+
break;
105+
case PSXAddress::Type::ROM:
106+
if (addr.physical < sizeof(m_biosMemoryMap)) {
107+
return m_biosMemoryMap[addr.physical] & mask;
108+
}
109+
break;
78110
}
79111
return false;
80112
}
81113

82114
void PCSX::Debug::process(uint32_t oldPC, uint32_t newPC, uint32_t oldCode, uint32_t newCode, bool linked) {
115+
const auto& regs = g_emulator->m_cpu->m_regs;
83116
const uint32_t basic = newCode >> 26;
84117
const bool isAnyLoadOrStore = (basic >= 0x20) && (basic < 0x3b);
85-
const auto& regs = g_emulator->m_cpu->m_regs;
118+
const bool isJAL = basic == 3;
119+
const bool isJR = (basic == 0) && ((newCode & 0x3f) == 8);
120+
const bool isJALR = (basic == 0) && ((newCode & 0x3f) == 9);
121+
const bool isLB = basic == 0x20;
122+
const bool isLH = basic == 0x21;
123+
const bool isLWL = basic == 0x22;
124+
const bool isLW = basic == 0x23;
125+
const bool isLBU = basic == 0x24;
126+
const bool isLHU = basic == 0x25;
127+
const bool isLWR = basic == 0x26;
128+
const bool isSB = basic == 0x28;
129+
const bool isSH = basic == 0x29;
130+
const bool isSWL = basic == 0x2a;
131+
const bool isSW = basic == 0x2b;
132+
const bool isSWR = basic == 0x2e;
133+
const bool isLWC2 = basic == 0x32;
134+
const bool isSWC2 = basic == 0x3a;
135+
const bool isLoad = isLB || isLBU || isLH || isLHU || isLW || isLWL || isLWR || isLWC2;
136+
const bool isStore = isSB || isSH || isSW || isSWL || isSWR || isSWC2;
137+
const bool wasInKernel = isInKernel(oldPC);
138+
const bool isInKernelNow = isInKernel(newPC);
139+
const uint32_t target = (newCode & 0x03ffffff) * 4 + (newPC & 0xf0000000);
140+
const bool isTargetInKernel = isInKernel(target);
141+
const uint32_t rd = (newCode >> 11) & 0x1f;
142+
uint32_t offset = regs.GPR.r[(newCode >> 21) & 0x1f] + int16_t(newCode);
143+
const bool offsetIsInKernel = isInKernel(offset, false);
144+
const bool isJRToRA = isJR && (rd == 31);
145+
const uint32_t oldPCBase = normalizeAddress(oldPC) & ~0xe0000000;
146+
const uint32_t newPCBase = normalizeAddress(newPC) & ~0xe0000000;
147+
const uint32_t targetBase = normalizeAddress(target) & ~0xe0000000;
86148

87149
checkBP(newPC, BreakpointType::Exec, 4);
88150
if (m_breakmp_e && !isMapMarked(newPC, MAP_EXEC)) {
89151
triggerBP(nullptr, newPC, 4, _("Execution map"));
90152
}
91153
if (m_mapping_e) {
92-
const bool isJAL = basic == 3;
93-
const bool isJALR = (basic == 0) && ((newCode & 0x3F) == 9);
94-
const uint32_t target = (newCode & 0x03ffffff) * 4 + (newPC & 0xf0000000);
95-
const uint32_t rd = (newCode >> 11) & 0x1f;
96154
markMap(newPC, MAP_EXEC);
97155
if (isJAL) markMap(target, MAP_EXEC_JAL);
98156
if (isJALR) markMap(regs.GPR.r[rd], MAP_EXEC_JAL);
99157
}
100158

159+
// Are we jumping from a non-kernel address to a kernel address which:
160+
// - is not a jr to $ra (aka a return from a callback)
161+
// - is not a jump to 0xa0 / 0xb0 / 0xc0 (aka the syscall gates)
162+
// - is not going to the break or exception handler
163+
if ((isJR || isJALR) && !wasInKernel && isTargetInKernel && !isJRToRA && (targetBase != 0x40) &&
164+
(targetBase != 0x80) && (targetBase != 0xa0) && (targetBase != 0xb0) && (targetBase != 0xc0)) {
165+
if (m_checkKernel) {
166+
g_system->printf(_("Kernel checker: Jump from 0x%08x to 0x%08x\n"), oldPC, targetBase);
167+
g_system->pause();
168+
}
169+
}
170+
101171
if (isAnyLoadOrStore) {
102-
const bool isLB = basic == 0x20;
103-
const bool isLH = basic == 0x21;
104-
const bool isLWL = basic == 0x22;
105-
const bool isLW = (basic == 0x23) || (basic == 0x32);
106-
const bool isLBU = basic == 0x24;
107-
const bool isLHU = basic == 0x25;
108-
const bool isLWR = basic == 0x26;
109-
const bool isSB = basic == 0x28;
110-
const bool isSH = basic == 0x29;
111-
const bool isSWL = basic == 0x2a;
112-
const bool isSW = (basic == 0x2b) || (basic == 0x3a);
113-
const bool isSWR = basic == 0x2e;
114-
const bool isLWC2 = basic == 0x32;
115-
const bool isSWC2 = basic == 0x3a;
116-
uint32_t offset = regs.GPR.r[(newCode >> 21) & 0x1f] + int16_t(newCode);
117172
if (isLWL || isLWR || isSWR || isSWL) offset &= ~3;
118173
if (isLB || isLBU) {
119174
checkBP(offset, BreakpointType::Read, 1);
@@ -157,6 +212,19 @@ void PCSX::Debug::process(uint32_t oldPC, uint32_t newPC, uint32_t oldCode, uint
157212
}
158213
if (m_mapping_w32) markMap(offset, MAP_W32);
159214
}
215+
// Are we accessing a kernel address from a non-kernel address, while not in IRQ?
216+
if (!g_emulator->m_cpu->m_inISR && offsetIsInKernel && !wasInKernel) {
217+
if (m_checkKernel) {
218+
if (isLoad) {
219+
g_system->printf(_("Kernel checker: Reading %08x from %08x\n"), offset, oldPC);
220+
g_system->pause();
221+
} else {
222+
g_system->printf(_("Kernel checker: Writing to %08x from %08x\n"), offset, oldPC);
223+
g_system->pause();
224+
}
225+
g_system->pause();
226+
}
227+
}
160228
}
161229

162230
if (m_step == STEP_NONE) return;

src/core/debug.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ namespace PCSX {
3232

3333
class Debug {
3434
public:
35-
uint32_t normalizeAddress(uint32_t address);
35+
Debug();
36+
static uint32_t normalizeAddress(uint32_t address);
37+
static bool isInKernel(uint32_t address, bool biosIsKernel = true);
3638
static inline std::function<const char*()> s_breakpoint_type_names[] = {l_("Exec"), l_("Read"), l_("Write")};
3739
enum class BreakpointType { Exec, Read, Write };
3840
enum class BreakpointCondition { Always, Change, Greater, Less, Equal };
@@ -125,6 +127,7 @@ class Debug {
125127
bool m_breakmp_e = false;
126128
bool m_breakmp_r8 = false, m_breakmp_r16 = false, m_breakmp_r32 = false;
127129
bool m_breakmp_w8 = false, m_breakmp_w16 = false, m_breakmp_w32 = false;
130+
bool m_checkKernel = false;
128131

129132
void clearMaps() {
130133
memset(m_mainMemoryMap, 0, sizeof(m_mainMemoryMap));
@@ -187,6 +190,7 @@ class Debug {
187190
bool m_wasInISR = false;
188191
Breakpoint* m_lastBP = nullptr;
189192
std::optional<std::tuple<uint32_t, bool>> m_scheduledCop0;
193+
EventBus::Listener m_listener;
190194
};
191195

192196
} // namespace PCSX

src/core/psxhw.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <stdint.h>
2323

2424
#include "core/cdrom.h"
25+
#include "core/debug.h"
2526
#include "core/gpu.h"
2627
#include "core/logger.h"
2728
#include "core/mdec.h"
@@ -117,6 +118,9 @@ uint8_t PCSX::HW::read8(uint32_t add) {
117118
case 0x1f802083:
118119
hard = 0x58;
119120
break;
121+
case 0x1f802088:
122+
hard = g_emulator->m_debug->m_checkKernel;
123+
break;
120124
default:
121125
hard = g_emulator->m_mem->m_hard[hwadd & 0xffff];
122126
PSXHW_LOG("*Unknown 8bit read at address %x\n", add);
@@ -441,6 +445,9 @@ void PCSX::HW::write8(uint32_t add, uint32_t rawvalue) {
441445
while (top != L.gettop()) L.pop();
442446
}
443447
break;
448+
case 0x1f802088:
449+
g_emulator->m_debug->m_checkKernel = value;
450+
break;
444451

445452
default:
446453
if (addressInRegisterSpace(hwadd)) {

src/core/r3000a.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
int PCSX::R3000Acpu::psxInit() {
3939
g_system->printf(_("PCSX-Redux booting\n"));
40-
g_system->printf(_("Copyright (C) 2019-%i PCSX-Redux authors\n"), 2024);
40+
g_system->printf(_("Copyright (C) 2019-%i PCSX-Redux authors\n"), 2025);
4141
const auto& args = g_system->getArgs();
4242

4343
if (g_emulator->settings.get<Emulator::SettingDynarec>()) {

src/core/web-server.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,7 @@ struct PCSX::WebClient::WebClientImpl {
11561156

11571157
void send400(std::string_view code) {
11581158
std::string str =
1159-
fmt::format("HTTP/1.1 400 Bad Request\r\n\r\Request failed to parse properly. Error: {}\r\n", code);
1159+
fmt::format("HTTP/1.1 400 Bad Request\r\n\r\nRequest failed to parse properly. Error: {}\r\n", code);
11601160
write(std::move(str));
11611161
scheduleClose();
11621162
}

src/mips/common/hardware/pcsxhw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@ static __inline__ void pcsx_debugbreak() { *((volatile char* const)0x1f802081) =
3333
static __inline__ void pcsx_execSlot(uint8_t slot) { *((volatile uint8_t* const)0x1f802081) = slot; }
3434
static __inline__ void pcsx_exit(int code) { *((volatile int16_t* const)0x1f802082) = code; }
3535
static __inline__ void pcsx_message(const char* msg) { *((volatile const char** const)0x1f802084) = msg; }
36+
static __inline__ void pcsx_checkKernel(int enable) { *((volatile char*)0x1f802088) = enable; }
37+
static __inline__ int pcsx_isCheckingKernel() { return *((volatile char* const)0x1f802088) != 0; }
3638

3739
static __inline__ int pcsx_present() { return *((volatile uint32_t* const)0x1f802080) == 0x58534350; }

src/mips/openbios/main/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ static void boot(char *systemCnfPath, char *binaryPath) {
339339
}
340340
buildIDstring[count * 2] = 0;
341341
}
342-
psxprintf("PS-X Realtime Kernel OpenBios - build id %s.\nCopyright (C) 2019-2024 PCSX-Redux authors.\n",
342+
psxprintf("PS-X Realtime Kernel OpenBios - build id %s.\nCopyright (C) 2019-2025 PCSX-Redux authors.\n",
343343
buildIDstring);
344344
}
345345
POST = 6;

src/mips/psyqo/src/kernel.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ void psyqo::Kernel::Internal::prepare(Application& application) {
319319
KernelData* const events = reinterpret_cast<KernelData*>(0x120);
320320
__builtin_memset(handlers->data, 0, handlers->size);
321321
__builtin_memset(events->data, 0, events->size);
322+
pcsx_checkKernel(1);
322323
syscall_setDefaultExceptionJmpBuf();
323324
syscall_enqueueSyscallHandler(0);
324325
syscall_enqueueIrqHandler(3);

0 commit comments

Comments
 (0)