Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
2413208
Added sub bitmask to read32 call, allowing for SWR/SWL calls to limit…
EngineersBox Jun 15, 2026
97c8e49
Fixed template linking issues with non-inline specialisation, moved t…
EngineersBox Jun 15, 2026
01dc987
Cleaned up whitespace changes
EngineersBox Jun 15, 2026
ac2eeca
Emitted x64/aarch64 assembly for read32Masked call in SWR/SWL callsa
EngineersBox Jun 16, 2026
3b754b7
Moved mask into arg2 for constant address cases in SWR
EngineersBox Jun 16, 2026
acf346b
Moved mask into arg2 for constant address cases in SWR
EngineersBox Jun 16, 2026
a488eac
Moved mask into arg2 for constant address cases in SWR
EngineersBox Jun 16, 2026
4c220d3
Fixed loading of mask on aarch64
EngineersBox Jun 16, 2026
52d0b57
Testing masking derived from LUT
EngineersBox Jun 16, 2026
129b4d2
Implemented masking for LWL/LWR calls
EngineersBox Jun 17, 2026
1613ac3
Implemented masking for LWL/LWR calls
EngineersBox Jun 17, 2026
1c9c384
Removed testing logs
EngineersBox Jun 17, 2026
53742a9
Removed testing logs
EngineersBox Jun 17, 2026
0ecaf37
Added write32Masked call and refactored swl/swr calls to use it, allo…
EngineersBox Jun 17, 2026
48bdfd0
Registered write32Masked in symbols
EngineersBox Jun 17, 2026
0722b5c
Fixed register cloberring when applying shift + mask in SWR/SWL
EngineersBox Jun 17, 2026
9d880e6
Restored x64 instructions and fixed aarch64 msan mask to depend in im…
EngineersBox Jun 17, 2026
0c2b11f
Fixed MSAN mask choosing registered bytes instead of memory-read bytes
EngineersBox Jun 17, 2026
61e6842
Implemented x64 equivalent of SWL/SWR and LWL/LWR msan fixes
EngineersBox Jun 17, 2026
0738a12
Removed debug logs
EngineersBox Jun 17, 2026
5835611
Merge branch 'main' into fix-msan-false-positive-swl-swr-uninit-read
EngineersBox Jun 17, 2026
b306771
Revered useless change
EngineersBox Jun 17, 2026
03d6ce1
Whitespace fixes
EngineersBox Jun 17, 2026
f1aef19
Fixed LWR read mask
EngineersBox Jun 19, 2026
9e4c902
Removed unused ctsdint header includes
EngineersBox Jun 20, 2026
cdc40e3
Merged masked read32/write32 into base call to avoid redundant symbol…
EngineersBox Jun 20, 2026
45487a3
Merged masked read32/write32 into base call to avoid redundant symbol…
EngineersBox Jun 20, 2026
3cee0a0
Refactored interpreted CPU LWL/LWR/SWL/SWR to use new masked variants…
EngineersBox Jun 20, 2026
09e817a
Fixed read32/write32 calls in interpreted CPU and fixed warnings for …
EngineersBox Jun 20, 2026
8dc8b85
Disambiguated partial and fully initialised reads with MSAN
EngineersBox Jun 20, 2026
3d9f7c8
Disambiguated partial and fully initialised reads with MSAN
EngineersBox Jun 20, 2026
aacc535
Changed static_cast to reinterpret_cast for variable/function registr…
EngineersBox Jun 20, 2026
1298529
Fixed comment on partial initialisation for MSAN status
EngineersBox Jun 20, 2026
2449d4f
WIP MSAN test suites
EngineersBox Jun 22, 2026
a61f8dd
WIP MSAN test suites
EngineersBox Jun 22, 2026
7ff4674
Added missing bitmap check to MSAN tests
EngineersBox Jun 22, 2026
7386cab
Fixed compilation issue with pcsxhw.h header and log line
EngineersBox Jun 23, 2026
89b9119
Fixed test format
EngineersBox Jun 23, 2026
0ea228e
Fixed pointer case and ASM clobber decl (=r -> +r)
EngineersBox Jun 23, 2026
0272064
Stringified lw_suffix in INVALID_SWX_LWX macro
EngineersBox Jun 23, 2026
372957a
Fixed LWX asm instruction missing comma
EngineersBox Jun 23, 2026
b1af116
Fixed assert macros and test setup/teardown
EngineersBox Jun 23, 2026
cbca77f
Fixed CESTER_X_EACH macro usage and moved mem_32_bit into CESTER_BODY
EngineersBox Jun 23, 2026
ed522a5
Fixed missing semi-colons and reset values for result before assembly…
EngineersBox Jun 23, 2026
25a34b7
Fixed syntax issues with valid tests and simplified with macro
EngineersBox Jun 23, 2026
73e0152
Fixed syntax issues with valid tests and simplified with macro
EngineersBox Jun 23, 2026
1f825a5
Fixed test invocation
EngineersBox Jun 23, 2026
ab41d9b
Fixed test invocation
EngineersBox Jun 23, 2026
4366397
Handled elapsed time exceeded to terminate test early
EngineersBox Jun 23, 2026
265fb86
Fixed makefile builds for msan-invalid and msan-valid
EngineersBox Jun 23, 2026
deb7f2d
Fixed MSAN positive tests
EngineersBox Jun 23, 2026
c118bb1
Fixed MSAN positive tests
EngineersBox Jun 23, 2026
bd230e2
Fixed return value exit conditon from loop
EngineersBox Jun 23, 2026
e7f7505
Simplified valid test invocation
EngineersBox Jun 23, 2026
d6c8647
Simplified valid test invocation
EngineersBox Jun 23, 2026
26be900
Simplified valid test invocation
EngineersBox Jun 23, 2026
fef195f
Simplified valid test invocation
EngineersBox Jun 23, 2026
40b91fa
Added MainInvoker::isInStartup check and refactored MSAN tests to ens…
EngineersBox Jun 23, 2026
1011074
Added MainInvoker::isInStartup check and refactored MSAN tests to ens…
EngineersBox Jun 23, 2026
b501af8
Merge branch 'main' into fix-msan-false-positive-swl-swr-uninit-read
EngineersBox Jun 23, 2026
c72c696
Test fixes
EngineersBox Jun 23, 2026
8358fda
Reduced test code duplication and fixed missing result handling
EngineersBox Jun 24, 2026
6c6011a
Added missing test assertion failure propagation from subroutine
EngineersBox Jun 24, 2026
4dc1726
Temp stop GH actions indefinite running
EngineersBox Jun 24, 2026
e2ef4a4
Temp stop GH actions indefinite running
EngineersBox Jun 24, 2026
ca11101
Improved tests and WIP migration from direct _Imm_ usage to address &…
EngineersBox Jun 28, 2026
db7c89c
Fixed test guard in msan_valid.c
EngineersBox Jun 28, 2026
16fdb97
Fixed test guard in msan_valid.c
EngineersBox Jun 28, 2026
e62bf66
Ported masking fixes to x86 and interpreted CPU
EngineersBox Jun 29, 2026
21957d4
Fixed BAD_COMBINATION with shl/shr instructions not using CL register…
EngineersBox Jun 30, 2026
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
118 changes: 87 additions & 31 deletions src/core/DynaRec_aa64/instructions.cc

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/core/DynaRec_aa64/recompiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
static uint8_t read8Wrapper(uint32_t address) { return PCSX::g_emulator->m_mem->read8(address); }
static uint16_t read16Wrapper(uint32_t address) { return PCSX::g_emulator->m_mem->read16(address); }
static uint32_t read32Wrapper(uint32_t address) { return PCSX::g_emulator->m_mem->read32(address); }
static uint32_t read32MaskedWrapper(uint32_t address, const uint32_t msanSubBitmask) {
return PCSX::g_emulator->m_mem->read32(address, PCSX::Memory::ReadType::Data, msanSubBitmask);
}

static void SPU_writeRegisterWrapper(uint32_t addr, uint16_t value) {
PCSX::g_emulator->m_spu->writeRegister(addr, value);
Expand All @@ -91,6 +94,9 @@ static void SPU_writeRegisterWrapper(uint32_t addr, uint16_t value) {
static void write8Wrapper(uint32_t address, uint32_t value) { PCSX::g_emulator->m_mem->write8(address, value); }
static void write16Wrapper(uint32_t address, uint32_t value) { PCSX::g_emulator->m_mem->write16(address, value); }
static void write32Wrapper(uint32_t address, uint32_t value) { PCSX::g_emulator->m_mem->write32(address, value); }
static void write32MaskedWrapper(uint32_t address, uint32_t value, const uint32_t msanSubBitmask) {
PCSX::g_emulator->m_mem->write32(address, value, msanSubBitmask);
}

using DynarecCallback = void (*)(); // A function pointer to JIT-emitted code

Expand Down
177 changes: 127 additions & 50 deletions src/core/DynaRec_x64/instructions.cc

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/core/DynaRec_x64/recompiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,13 @@
#define _ImmLU_ _fImmLU_(code)

static uint32_t read32Wrapper(uint32_t address) { return PCSX::g_emulator->m_mem->read32(address); }
static uint32_t read32MaskedWrapper(uint32_t address, const uint32_t msanSubBitmask) {
return PCSX::g_emulator->m_mem->read32(address, PCSX::Memory::ReadType::Data, msanSubBitmask);
}
static void write32Wrapper(uint32_t address, uint32_t value) { PCSX::g_emulator->m_mem->write32(address, value); }
static void write32MaskedWrapper(uint32_t address, uint32_t value, const uint32_t msanSubBitmask) {
PCSX::g_emulator->m_mem->write32(address, value, msanSubBitmask);
}
static void SPU_writeRegisterWrapper(uint32_t addr, uint16_t value) {
PCSX::g_emulator->m_spu->writeRegister(addr, value);
}
Expand Down
7 changes: 5 additions & 2 deletions src/core/DynaRec_x64/symbols.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
#include "fmt/format.h"

#define REGISTER_VARIABLE(variable, name, size) \
m_symbols += fmt::format("{} {} {}\n", (void*)&(variable), (name), (size))
m_symbols += fmt::format("{} {} {}\n", reinterpret_cast<const void*>(&(variable)), (name), (size))

#define REGISTER_FUNCTION(function, name) m_symbols += fmt::format("{} {}\n", (void*)&(function), (name));
#define REGISTER_FUNCTION(function, name) \
m_symbols += fmt::format("{} {}\n", reinterpret_cast<const void*>(&(function)), (name));

#define REGISTER_CLASS_FUNCTION(function, name) \
{ \
Expand Down Expand Up @@ -93,7 +94,9 @@ void DynaRecCPU::makeSymbols() {
}

REGISTER_FUNCTION(read32Wrapper, "read32_wrapper");
REGISTER_FUNCTION(read32MaskedWrapper, "read32_masked_wrapper");
REGISTER_FUNCTION(write32Wrapper, "write32_wrapper");
REGISTER_FUNCTION(write32MaskedWrapper, "write32_masked_wrapper");

REGISTER_CLASS_FUNCTION(PCSX::Memory::read8, "read8");
REGISTER_CLASS_FUNCTION(PCSX::Memory::read16, "read16");
Expand Down
10 changes: 10 additions & 0 deletions src/core/gpu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@
if (usingMsan && PCSX::Memory::inMsanRange(addr)) {
addr &= 0xfffffffc;
switch (g_emulator->m_mem->msanGetStatus<4>(addr)) {
case PCSX::MsanStatus::PARTIALLY_INITIALIZED:
g_system->log(LogClass::GPU,
_("GPU DMA went into uninitialized bytes in usable, partially initialized msan memory: %8.8lx\n"),
addr);
break;

Check warning on line 334 in src/core/gpu.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Complex Method

PCSX::GPU::gpuDmaChainSize increases in cyclomatic complexity from 12 to 13, threshold = 9 This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
case PCSX::MsanStatus::UNINITIALIZED:
g_system->log(LogClass::GPU, _("GPU DMA went into usable but uninitialized msan memory: %8.8lx\n"),
addr);
Expand Down Expand Up @@ -596,6 +601,11 @@
addr &= 0xfffffffc;
const uint32_t *headerPtr = (uint32_t *)(g_emulator->m_mem->m_msanRAM + (addr - PCSX::Memory::c_msanStart));
switch (g_emulator->m_mem->msanGetStatus<4>(addr)) {
case PCSX::MsanStatus::PARTIALLY_INITIALIZED:
g_system->log(LogClass::GPU,
_("GPU DMA went into uninitialized bytes in usable, partially initialized msan memory: %8.8lx\n"),
addr);
break;

Check warning on line 608 in src/core/gpu.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Complex Method

PCSX::GPU::chainedDMAWrite increases in cyclomatic complexity from 13 to 14, threshold = 9 This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
case PCSX::MsanStatus::UNINITIALIZED:
g_system->log(LogClass::GPU, _("GPU DMA went into usable but uninitialized msan memory: %8.8lx\n"),
addr);
Expand Down
5 changes: 5 additions & 0 deletions src/core/psxhw.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ class HW {
if (usingMsan && PCSX::Memory::inMsanRange(madr)) {
madr &= 0xfffffffc;
switch (g_emulator->m_mem->msanGetStatus<4>(madr)) {
case MsanStatus::PARTIALLY_INITIALIZED:
g_system->log(LogClass::GPU,
_("GPU DMA went into uninitialized bytes in usable, partially initialized msan memory: %8.8lx\n"),
madr);
break;
case PCSX::MsanStatus::UNINITIALIZED:
g_system->log(LogClass::GPU,
_("GPU DMA went into usable but uninitialized msan memory: %8.8lx\n"),
Expand Down
57 changes: 37 additions & 20 deletions src/core/psxinterpreter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "core/pgxp_debug.h"
#include "core/pgxp_gte.h"
#include "core/psxemulator.h"
#include "core/psxmem.h"
#include "core/r3000a.h"
#include "tracy/Tracy.hpp"

Expand Down Expand Up @@ -935,25 +936,35 @@
void InterpretedCPU::psxLWL(uint32_t code) {
uint32_t addr = _oB_;
uint32_t shift = addr & 3;
uint32_t mem = PCSX::g_emulator->m_mem->read32(addr & ~3);
const uint32_t msanReadMask = 0b1111 >> (3 - shift);
uint32_t mem = PCSX::g_emulator->m_mem->read32(
addr & ~3,
PCSX::Memory::ReadType::Data,
msanReadMask
);

// load delay = 1 latency
if (!_Rt_) return;
_u32(delayedLoadRef(_Rt_, LWL_MASK[shift])) = mem << LWL_SHIFT[shift];

/*
Mem = 1234. Reg = abcd
0 4bcd (mem << 24) | (reg & 0x00ffffff)
1 34cd (mem << 16) | (reg & 0x0000ffff)
2 234d (mem << 8) | (reg & 0x000000ff)
3 1234 (mem ) | (reg & 0x00000000)
*/
}

void InterpretedCPU::psxLWR(uint32_t code) {
uint32_t addr = _oB_;
uint32_t shift = addr & 3;
uint32_t mem = PCSX::g_emulator->m_mem->read32(addr & ~3);
const uint32_t msanReadMask = (0b1111 << shift) & 0b1111;
uint32_t mem = PCSX::g_emulator->m_mem->read32(
addr & ~3,
PCSX::Memory::ReadType::Data,
msanReadMask
);

Check warning on line 967 in src/core/psxinterpreter.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Code Duplication

introduced similar code in: InterpretedCPU::psxLWL,InterpretedCPU::psxLWR Avoid duplicated, aka copy-pasted, code inside the module. More duplication lowers the code health.

// load delay = 1 latency
if (!_Rt_) return;
Expand Down Expand Up @@ -998,15 +1009,18 @@
uint32_t addr = _oB_;
uint32_t shift = addr & 3;
addr ^= shift;
uint32_t mem;
// special handling to avoid msan interpreting this as a read
if (PCSX::g_emulator->m_mem->msanInitialized() && PCSX::g_emulator->m_mem->inMsanRange(addr)) {
mem = *(uint32_t *)&PCSX::g_emulator->m_mem->m_msanRAM[addr - PCSX::Memory::c_msanStart];
} else {
mem = PCSX::g_emulator->m_mem->read32(addr);
}

PCSX::g_emulator->m_mem->write32(addr, (_u32(_rRt_) >> SWL_SHIFT[shift]) | (mem & SWL_MASK[shift]));
// 0x0 mask avoids msan interpreting this as a read
uint32_t mem = PCSX::g_emulator->m_mem->read32(
addr,
PCSX::Memory::ReadType::Data,
0x0
);
const uint32_t msanWriteMask = 0b1111 >> (3 - shift);
PCSX::g_emulator->m_mem->write32(
addr,
(_u32(_rRt_) >> SWL_SHIFT[shift]) | (mem & SWL_MASK[shift]),
msanWriteMask
);
/*
Mem = 1234. Reg = abcd
0 123a (reg >> 24) | (mem & 0xffffff00)
Expand All @@ -1020,15 +1034,18 @@
uint32_t addr = _oB_;
uint32_t shift = addr & 3;
addr ^= shift;
uint32_t mem;
// special handling to avoid msan interpreting this as a read
if (PCSX::g_emulator->m_mem->msanInitialized() && PCSX::g_emulator->m_mem->inMsanRange(addr)) {
mem = *(uint32_t *)&PCSX::g_emulator->m_mem->m_msanRAM[addr - PCSX::Memory::c_msanStart];
} else {
mem = PCSX::g_emulator->m_mem->read32(addr);
}

PCSX::g_emulator->m_mem->write32(addr, (_u32(_rRt_) << SWR_SHIFT[shift]) | (mem & SWR_MASK[shift]));
// 0x0 mask avoids msan interpreting this as a read
uint32_t mem = PCSX::g_emulator->m_mem->read32(
addr,
PCSX::Memory::ReadType::Data,
0x0
);
const uint32_t msanWriteMask = (0b1111 << shift) & 0b1111;
PCSX::g_emulator->m_mem->write32(
addr,
(_u32(_rRt_) << SWR_SHIFT[shift]) | (mem & SWR_MASK[shift]),
msanWriteMask
);

/*
Mem = 1234. Reg = abcd
Expand Down
25 changes: 21 additions & 4 deletions src/core/psxmem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "core/pio-cart.h"
#include "core/psxhw.h"
#include "core/r3000a.h"
#include "core/system.h"
#include "mips/common/util/encoder.hh"
#include "support/file.h"
#include "supportpsx/binloader.h"
Expand Down Expand Up @@ -297,6 +298,11 @@ uint8_t PCSX::Memory::read8(uint32_t address) {
if (pointer != nullptr) {
if (msanInitialized() && inMsanRange(address)) [[unlikely]] {
switch (msanGetStatus<1>(address)) {
case MsanStatus::PARTIALLY_INITIALIZED:
g_system->log(LogClass::CPU,
_("8-bit read from uninitialized bytes in usable, partially initialized msan memory: %8.8lx\n"),
address);
break;
case MsanStatus::UNINITIALIZED:
g_system->log(LogClass::CPU, _("8-bit read from usable but uninitialized msan memory: %8.8lx\n"),
address);
Expand Down Expand Up @@ -348,6 +354,11 @@ uint16_t PCSX::Memory::read16(uint32_t address) {
if (pointer != nullptr) {
if (msanInitialized() && inMsanRange(address)) {
switch (msanGetStatus<2>(address)) {
case MsanStatus::PARTIALLY_INITIALIZED:
g_system->log(LogClass::CPU,
_("16-bit read from uninitialized bytes in usable, partially initialized msan memory: %8.8lx\n"),
address);
break;
case MsanStatus::UNINITIALIZED:
g_system->log(LogClass::CPU, _("16-bit read from usable but uninitialized msan memory: %8.8lx\n"),
address);
Expand Down Expand Up @@ -387,15 +398,20 @@ uint16_t PCSX::Memory::read16(uint32_t address) {
return 0xffff;
}

uint32_t PCSX::Memory::read32(uint32_t address, ReadType readType) {
uint32_t PCSX::Memory::read32(uint32_t address, ReadType readType, const uint32_t msanSubBitmask) {
if (readType == ReadType::Data) g_emulator->m_cpu->m_regs.cycle += 1;
const uint32_t page = address >> 16;
const auto pointer = (uint8_t *)m_readLUT[page];
const bool pioConnected = g_emulator->settings.get<Emulator::SettingPIOConnected>().value;

if (pointer != nullptr) {
if (msanInitialized() && inMsanRange(address)) {
switch (msanGetStatus<4>(address)) {
switch (msanGetStatus<4>(address, msanSubBitmask)) {
case MsanStatus::PARTIALLY_INITIALIZED:
g_system->log(LogClass::CPU,
_("32-bit read from uninitialized bytes in usable, partially initialized msan memory: %8.8lx\n"),
address);
break;
case MsanStatus::UNINITIALIZED:
g_system->log(LogClass::CPU, _("32-bit read from usable but uninitialized msan memory: %8.8lx\n"),
address);
Expand Down Expand Up @@ -586,15 +602,15 @@ void PCSX::Memory::write16(uint32_t address, uint32_t value) {
}
}

void PCSX::Memory::write32(uint32_t address, uint32_t value) {
void PCSX::Memory::write32(uint32_t address, uint32_t value, const uint32_t msanSubBitmask) {
g_emulator->m_cpu->m_regs.cycle += 1;
const uint32_t page = address >> 16;
const auto pointer = (uint8_t *)m_writeLUT[page];
const bool pioConnected = g_emulator->settings.get<Emulator::SettingPIOConnected>().value;

if (pointer != nullptr) {
if (msanInitialized() && inMsanRange(address)) {
if (msanValidateWrite<4>(address)) {
if (msanValidateWrite<4>(address, msanSubBitmask)) {
*(uint32_t *)&m_msanRAM[address - c_msanStart] = SWAP_LEu32(value);
} else {
g_system->log(LogClass::CPU, _("32-bit write to unusable msan memory: %8.8lx\n"), address);
Expand Down Expand Up @@ -884,6 +900,7 @@ uint32_t PCSX::Memory::msanAlloc(uint32_t size) {

// Check if we still have enough memory.
if (m_msanPtr + actualSize > c_msanSize) {
g_system->printf(_("m_msanPtr: 0x%x actualSize: %zu, c_msanSize: %zu\n"), m_msanPtr, actualSize, c_msanSize);
g_system->printf(_("Out of memory in MsanAlloc\n"));
g_system->pause();
return 0;
Expand Down
30 changes: 17 additions & 13 deletions src/core/psxmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@
namespace PCSX {

enum class MsanStatus {
UNUSABLE, // memory that hasn't been allocated or has been freed
UNINITIALIZED, // allocated memory that has never been written to, has undefined contents
OK // free to use
UNUSABLE, // memory that hasn't been allocated or has been freed
UNINITIALIZED, // allocated memory that has never been written to, has undefined contents
PARTIALLY_INITIALIZED, // allocated memory that has had some subset of bytes being read initialised
// but not all of them
OK // free to use
};

class Memory {
Expand All @@ -66,10 +68,10 @@ class Memory {

uint8_t read8(uint32_t address);
uint16_t read16(uint32_t address);
uint32_t read32(uint32_t address, ReadType = ReadType::Data);
uint32_t read32(uint32_t address, ReadType = ReadType::Data, const uint32_t msanSubBitmask = UINT32_MAX);
void write8(uint32_t address, uint32_t value);
void write16(uint32_t address, uint32_t value);
void write32(uint32_t address, uint32_t value);
void write32(uint32_t address, uint32_t value, const uint32_t msanSubBitmask = UINT32_MAX);
const void *pointerRead(uint32_t address);
const void *pointerWrite(uint32_t address, int size);

Expand All @@ -92,33 +94,35 @@ class Memory {
uint32_t msanGetChainPtr(uint32_t addr) const;

template <uint32_t length>
MsanStatus msanGetStatus(uint32_t addr) const {
MsanStatus msanGetStatus(uint32_t addr, const uint32_t subBitmask = UINT32_MAX) const {
uint32_t bitmapIndex = (addr - c_msanStart) / 8;
uint32_t bitmask = ((1 << length) - 1) << addr % 8;
uint32_t bitmask = (((1 << length) - 1) << addr % 8) & subBitmask;
MsanStatus bestCase = MsanStatus::OK;
if (uint32_t nextBitmask = bitmask >> 8) [[unlikely]] {
if ((m_msanInitializedBitmap[bitmapIndex + 1] & nextBitmask) != nextBitmask) {
const uint8_t nextInitEntry = m_msanInitializedBitmap[bitmapIndex + 1] & nextBitmask;
if (nextInitEntry != nextBitmask) {
if ((m_msanUsableBitmap[bitmapIndex + 1] & nextBitmask) != nextBitmask) {
return MsanStatus::UNUSABLE;
}
bestCase = MsanStatus::UNINITIALIZED;
bestCase = nextInitEntry ? MsanStatus::PARTIALLY_INITIALIZED : MsanStatus::UNINITIALIZED;
}
bitmask &= 0xff;
}
if ((m_msanInitializedBitmap[bitmapIndex] & bitmask) != bitmask) [[unlikely]] {
const uint8_t initEntry = m_msanInitializedBitmap[bitmapIndex] & bitmask;
if (initEntry != bitmask) [[unlikely]] {
if ((m_msanUsableBitmap[bitmapIndex] & bitmask) != bitmask) {
return MsanStatus::UNUSABLE;
}
return MsanStatus::UNINITIALIZED;
return initEntry ? MsanStatus::PARTIALLY_INITIALIZED : MsanStatus::UNINITIALIZED;
}
return bestCase;
}

// if the write is valid, marks the address as initialized, otherwise returns false
template <uint32_t length>
bool msanValidateWrite(uint32_t addr) {
bool msanValidateWrite(uint32_t addr, const uint32_t subBitmask = UINT32_MAX) {
uint32_t bitmapIndex = (addr - c_msanStart) / 8;
uint32_t bitmask = ((1 << length) - 1) << addr % 8;
uint32_t bitmask = (((1 << length) - 1) << addr % 8) & subBitmask;
if (uint32_t nextBitmask = bitmask >> 8) [[unlikely]] {
if ((m_msanUsableBitmap[bitmapIndex + 1] & nextBitmask) != nextBitmask) {
return false;
Expand Down
14 changes: 13 additions & 1 deletion src/main/main.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/***************************************************************************

Check notice on line 1 in src/main/main.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

✅ Getting better: Overall Code Complexity

The mean cyclomatic complexity decreases from 7.56 to 7.10, threshold = 4 This file has many conditional statements (e.g. if, for, while) across its implementation, leading to lower code health. Avoid adding more conditionals.
* Copyright (C) 2019 PCSX-Redux authors *
* *
* This program is free software; you can redistribute it and/or modify *
Expand All @@ -17,10 +17,13 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/

#include "main/main.h"
#include <atomic>
#include <csignal>
#include <filesystem>
#include <iostream>
#include <map>
#include <memory>
#include <string>

#include "core/arguments.h"
Expand All @@ -30,6 +33,7 @@
#include "core/psxemulator.h"
#include "core/r3000a.h"
#include "core/sstate.h"
#include "core/system.h"
#include "core/ui.h"
#include "flags.h"
#include "fmt/chrono.h"
Expand Down Expand Up @@ -155,7 +159,7 @@
void useLogfile(const PCSX::u8string &filename) {
m_logfile.setFile(new PCSX::UvFile(filename, PCSX::FileOps::TRUNCATE));
}
bool m_inStartup = true;
std::atomic_bool m_inStartup = true;
};

struct Cleaner {
Expand Down Expand Up @@ -484,3 +488,11 @@

return exitCode;
}

bool MainInvoker::isInStartup() {
if (PCSX::g_system == nullptr || PCSX::g_emulator == nullptr) {
return true;
}
SystemImpl* system = reinterpret_cast<SystemImpl*>(PCSX::g_system);
return system->m_inStartup;
}
1 change: 1 addition & 0 deletions src/main/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class MainInvoker {
fprintf(stderr, "PCSX-Redux test finished with exit code %d\n", r);
return r;
}
bool isInStartup();

private:
int m_count;
Expand Down
Loading
Loading