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
1 change: 1 addition & 0 deletions src/core/debug.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ uint32_t PCSX::Debug::normalizeAddress(uint32_t address) {

bool PCSX::Debug::isInKernel(uint32_t address, bool biosIsKernel) {
PSXAddress addr(address);
if (addr.type == PSXAddress::Type::MSAN) return false;
const bool ramExpansion = PCSX::g_emulator->settings.get<PCSX::Emulator::Setting8MB>();
if (addr.type == PSXAddress::Type::ROM) return biosIsKernel;
if (addr.type != PSXAddress::Type::RAM) return false;
Expand Down
20 changes: 18 additions & 2 deletions src/core/psxhw.cc
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,17 @@
case 0x1f802080:
hard = 0x58534350;
break;

case 0x1f80208c: {
uint32_t size = g_emulator->m_cpu->m_regs.GPR.n.a0;
hard = g_emulator->m_mem->msanAlloc(size);
break;
}
case 0x1f802090: {
uint32_t ptr = g_emulator->m_cpu->m_regs.GPR.n.a0;
uint32_t size = g_emulator->m_cpu->m_regs.GPR.n.a1;
hard = g_emulator->m_mem->msanRealloc(ptr, size);
break;
}

Check warning on line 373 in src/core/psxhw.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::HW::read32 increases in cyclomatic complexity from 24 to 26, 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.
Comment on lines +363 to +373
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring to reduce complexity.

The read32 and write32 methods have high cyclomatic complexity (26 and 49 respectively) and are getting more complex with the new MSAN cases. Consider:

  1. Extracting MSAN-related operations into separate methods
  2. Using a command pattern or lookup table for different address handlers
  3. Breaking down the large switch statements into smaller, focused functions

This will improve maintainability and make future additions easier.

Would you like me to propose a refactored structure that reduces the complexity?

Also applies to: 804-807

🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 363-373: ❌ Getting worse: Complex Method
PCSX::HW::read32 increases in cyclomatic complexity from 24 to 26, 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.

default: {
uint32_t *ptr = (uint32_t *)&g_emulator->m_mem->m_hard[hwadd & 0xffff];
hard = SWAP_LEu32(*ptr);
Expand Down Expand Up @@ -445,7 +455,9 @@
case 0x1f802088:
g_emulator->m_debug->m_checkKernel = value;
break;

case 0x1f802089:
g_emulator->m_mem->initMsan(value);
break;

Check warning on line 460 in src/core/psxhw.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::HW::write8 increases in cyclomatic complexity from 23 to 24, 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.
default:
if (addressInRegisterSpace(hwadd)) {
uint32_t *ptr = (uint32_t *)&g_emulator->m_mem->m_hard[hwadd & 0xffff];
Expand Down Expand Up @@ -789,6 +801,10 @@
g_system->message("%s", memFile->gets<false>());
break;
}
case 0x1f80208c: {
g_emulator->m_mem->msanFree(value);
break;
}

Check warning on line 807 in src/core/psxhw.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::HW::write32 increases in cyclomatic complexity from 48 to 49, 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.
default: {
if ((hwadd >= 0x1f801c00) && (hwadd < 0x1f801e00)) {
write16(add, value & 0xffff);
Expand Down
223 changes: 221 additions & 2 deletions src/core/psxmem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@
#endif
};

PCSX::Memory::Memory() : m_listener(g_system->m_eventBus) {
m_listener.listen<Events::ExecutionFlow::Reset>([this](auto &) {
free(m_msanRAM);
free(m_msanBitmap);
free(m_msanWrittenBitmap);
m_msanRAM = nullptr;
m_msanBitmap = nullptr;
m_msanWrittenBitmap = nullptr;
m_msanAllocs.clear();
});
}

int PCSX::Memory::init() {
m_readLUT = (uint8_t **)calloc(0x10000, sizeof(void *));
m_writeLUT = (uint8_t **)calloc(0x10000, sizeof(void *));
Expand Down Expand Up @@ -140,7 +152,7 @@
memset(m_exp1, 0xff, exp1_size);
f->read(m_exp1, rom_size);
f->close();
PCSX::g_system->printf(_("Loaded %i bytes to EXP1 from file: %s\n"), rom_size, exp1Path.string());
g_system->printf(_("Loaded %i bytes to EXP1 from file: %s\n"), rom_size, exp1Path.string());
result = true;
}
} else {
Expand Down Expand Up @@ -222,7 +234,7 @@
f->read(m_bios, bios_size);
}
f->close();
PCSX::g_system->printf(_("Loaded BIOS: %s\n"), biosPath.string());
g_system->printf(_("Loaded BIOS: %s\n"), biosPath.string());
}
}

Expand Down Expand Up @@ -250,6 +262,14 @@

free(m_readLUT);
free(m_writeLUT);

free(m_msanRAM);
free(m_msanBitmap);
free(m_msanWrittenBitmap);
m_msanRAM = nullptr;
m_msanBitmap = nullptr;
m_msanWrittenBitmap = nullptr;
m_msanAllocs.clear();
}

uint8_t PCSX::Memory::read8(uint32_t address) {
Expand All @@ -261,6 +281,20 @@
if (pointer != nullptr) {
const uint32_t offset = address & 0xffff;
return *(pointer + offset);
} else if (msanInitialized() && (address >= 0x20000000) && (address < (0x20000000 + c_msanSize))) {
uint32_t msanAddress = address - 0x20000000;
if ((m_msanWrittenBitmap[msanAddress / 8] & (1 << (msanAddress % 8))) == 0) {
g_system->log(LogClass::CPU, _("8-bit read from usable but uninitialized msan memory: %8.8lx\n"), address);
g_system->pause();
return 0;
}
if (m_msanBitmap[msanAddress / 8] & (1 << (msanAddress % 8))) {
return m_msanRAM[msanAddress];
} else {
g_system->log(LogClass::CPU, _("8-bit read from unsable msan memory: %8.8lx\n"), address);
g_system->pause();
return 0;
}

Check warning on line 297 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::Memory::read8 increases in cyclomatic complexity from 14 to 19, 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.

Check warning on line 297 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Conditional

PCSX::Memory::read8 increases from 2 complex conditionals with 4 branches to 3 complex conditionals with 6 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
Comment on lines +284 to +297
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reduce code duplication in read methods.

The MSAN checks in read8, read16, and read32 are very similar. Consider:

  1. Extracting common MSAN validation logic into helper methods
  2. Using templates to handle different sizes
  3. Creating a unified error reporting function

This will reduce duplication and make the code more maintainable.

Would you like me to propose a refactored structure that reduces duplication?

Also applies to: 333-349, 382-398

🧰 Tools
🪛 GitHub Check: CodeScene Cloud Delta Analysis (main)

[warning] 284-297: ❌ Getting worse: Complex Method
PCSX::Memory::read8 increases in cyclomatic complexity from 14 to 19, 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.


[warning] 284-297: ❌ Getting worse: Complex Conditional
PCSX::Memory::read8 increases from 2 complex conditionals with 4 branches to 3 complex conditionals with 6 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.

} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80) {
if ((address & 0xffff) < 0x400) {
return m_hard[address & 0x3ff];
Expand Down Expand Up @@ -296,6 +330,23 @@
if (pointer != nullptr) {
const uint32_t offset = address & 0xffff;
return SWAP_LEu16(*(uint16_t *)(pointer + offset));
} else if (msanInitialized() && (address >= 0x20000000) && (address < (0x20000000 + c_msanSize))) {
uint32_t msanAddress = address - 0x20000000;
for (unsigned offset = 0; offset < 2; offset++) {
if ((m_msanWrittenBitmap[(msanAddress + offset) / 8] & (1 << ((msanAddress + offset) % 8))) == 0) {
g_system->log(LogClass::CPU, _("16-bit read from usable but uninitialized msan memory: %8.8lx\n"),
address);
g_system->pause();
return 0;
}
}
if (m_msanBitmap[msanAddress / 8] & (1 << (msanAddress % 8))) {
return *(uint16_t *)&m_msanRAM[msanAddress];
} else {
g_system->log(LogClass::CPU, _("16-bit read from unsable msan memory: %8.8lx\n"), address);
g_system->pause();
return 0;
}

Check warning on line 349 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::Memory::read16 increases in cyclomatic complexity from 12 to 18, 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.

Check warning on line 349 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Conditional

PCSX::Memory::read16 increases from 2 complex conditionals with 4 branches to 3 complex conditionals with 6 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80) {
if ((address & 0xffff) < 0x400) {
uint16_t *ptr = (uint16_t *)&m_hard[address & 0x3ff];
Expand Down Expand Up @@ -328,6 +379,23 @@
if (pointer != nullptr) {
const uint32_t offset = address & 0xffff;
return SWAP_LEu32(*(uint32_t *)(pointer + offset));
} else if (msanInitialized() && (address >= 0x20000000) && (address < (0x20000000 + c_msanSize))) {
uint32_t msanAddress = address - 0x20000000;
for (unsigned offset = 0; offset < 4; offset++) {
if ((m_msanWrittenBitmap[(msanAddress + offset) / 8] & (1 << ((msanAddress + offset) % 8))) == 0) {
g_system->log(LogClass::CPU, _("32-bit read from usable but uninitialized msan memory: %8.8lx\n"),
address);
g_system->pause();
return 0;
}
}
if (m_msanBitmap[msanAddress / 8] & (1 << (msanAddress % 8))) {
return *(uint32_t *)&m_msanRAM[msanAddress];
} else {
g_system->log(LogClass::CPU, _("32-bit read from unsable msan memory: %8.8lx\n"), address);
g_system->pause();
return 0;
}

Check warning on line 398 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::Memory::read32 increases in cyclomatic complexity from 14 to 20, 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.

Check warning on line 398 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Conditional

PCSX::Memory::read32 increases from 2 complex conditionals with 4 branches to 3 complex conditionals with 6 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80) {
if ((address & 0xffff) < 0x400) {
uint32_t *ptr = (uint32_t *)&m_hard[address & 0x3ff];
Expand Down Expand Up @@ -437,6 +505,15 @@
const uint32_t offset = address & 0xffff;
*(pointer + offset) = static_cast<uint8_t>(value);
g_emulator->m_cpu->Clear((address & (~3)), 1);
} else if (msanInitialized() && (address >= 0x20000000) && (address < (0x20000000 + c_msanSize))) {
uint32_t msanAddress = address - 0x20000000;
if (m_msanBitmap[msanAddress / 8] & (1 << (msanAddress % 8))) {
m_msanWrittenBitmap[msanAddress / 8] |= (1 << (msanAddress % 8));
m_msanRAM[msanAddress] = value;
} else {
g_system->log(LogClass::CPU, _("8-bit write to unsable msan memory: %8.8lx\n"), address);
g_system->pause();
}

Check warning on line 516 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::Memory::write8 increases in cyclomatic complexity from 12 to 16, 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.

Check warning on line 516 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Conditional

PCSX::Memory::write8 increases from 2 complex conditionals with 4 branches to 3 complex conditionals with 6 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80) {
if ((address & 0xffff) < 0x400) {
m_hard[address & 0x3ff] = value;
Expand Down Expand Up @@ -465,6 +542,17 @@
const uint32_t offset = address & 0xffff;
*(uint16_t *)(pointer + offset) = SWAP_LEu16(static_cast<uint16_t>(value));
g_emulator->m_cpu->Clear((address & (~3)), 1);
} else if (msanInitialized() && (address >= 0x20000000) && (address < (0x20000000 + c_msanSize))) {
uint32_t msanAddress = address - 0x20000000;
if (m_msanBitmap[msanAddress / 8] & (1 << (msanAddress % 8))) {
for (unsigned offset = 0; offset < 2; offset++) {
m_msanWrittenBitmap[(msanAddress + offset) / 8] |= (1 << ((msanAddress + offset) % 8));
}
*(uint16_t *)&m_msanRAM[msanAddress] = value;
} else {
g_system->log(LogClass::CPU, _("16-bit write to unsable msan memory: %8.8lx\n"), address);
g_system->pause();
}

Check warning on line 555 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::Memory::write16 increases in cyclomatic complexity from 12 to 17, 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.

Check warning on line 555 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Conditional

PCSX::Memory::write16 increases from 2 complex conditionals with 4 branches to 3 complex conditionals with 6 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80) {
if ((address & 0xffff) < 0x400) {
uint16_t *ptr = (uint16_t *)&m_hard[address & 0x3ff];
Expand Down Expand Up @@ -494,6 +582,17 @@
const uint32_t offset = address & 0xffff;
*(uint32_t *)(pointer + offset) = SWAP_LEu32(value);
g_emulator->m_cpu->Clear((address & (~3)), 1);
} else if (msanInitialized() && (address >= 0x20000000) && (address < (0x20000000 + c_msanSize))) {
uint32_t msanAddress = address - 0x20000000;
if (m_msanBitmap[msanAddress / 8] & (1 << (msanAddress % 8))) {
for (unsigned offset = 0; offset < 4; offset++) {
m_msanWrittenBitmap[(msanAddress + offset) / 8] |= (1 << ((msanAddress + offset) % 8));
}
*(uint32_t *)&m_msanRAM[msanAddress] = value;
} else {
g_system->log(LogClass::CPU, _("32-bit write to unsable msan memory: %8.8lx\n"), address);
g_system->pause();
}

Check warning on line 595 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::Memory::write32 increases in cyclomatic complexity from 19 to 24, 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.

Check warning on line 595 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Conditional

PCSX::Memory::write32 increases from 2 complex conditionals with 4 branches to 3 complex conditionals with 6 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80) {
if ((address & 0xffff) < 0x400) {
uint32_t *ptr = (uint32_t *)&m_hard[address & 0x3ff];
Expand Down Expand Up @@ -717,3 +816,123 @@
auto toCopy = std::min(size, c_blockSize - offset);
memcpy(block + offset, src, toCopy);
}

void PCSX::Memory::initMsan(bool reset) {
if (reset) {
free(m_msanRAM);
free(m_msanBitmap);
free(m_msanWrittenBitmap);
m_msanRAM = nullptr;
m_msanBitmap = nullptr;
m_msanWrittenBitmap = nullptr;
m_msanAllocs.clear();
}
if (msanInitialized()) {
g_system->printf(_("MSAN system was already initialized.\n"));
g_system->pause();
return;
}

// 1.5GB of RAM, with 384MB worth of bitmap, between 0x20000000 and 0x80000000
m_msanRAM = (uint8_t *)calloc(c_msanSize, 1);
m_msanBitmap = (uint8_t *)calloc(c_msanSize / 8, 1);
m_msanWrittenBitmap = (uint8_t *)calloc(c_msanSize / 8, 1);
m_msanPtr = 1024;
}
Comment on lines +820 to +841
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for memory allocation failures.

The initialization looks good but should handle allocation failures. Consider:

  1. Checking allocation results
  2. Cleaning up on partial allocation failures
  3. Returning a status code to indicate success/failure
 void PCSX::Memory::initMsan(bool reset) {
     // ... reset code ...
     m_msanRAM = (uint8_t *)calloc(c_msanSize, 1);
+    if (!m_msanRAM) {
+        g_system->printf(_("Failed to allocate MSAN RAM\n"));
+        g_system->pause();
+        return;
+    }
     m_msanBitmap = (uint8_t *)calloc(c_msanSize / 8, 1);
+    if (!m_msanBitmap) {
+        free(m_msanRAM);
+        m_msanRAM = nullptr;
+        g_system->printf(_("Failed to allocate MSAN bitmap\n"));
+        g_system->pause();
+        return;
+    }
     m_msanWrittenBitmap = (uint8_t *)calloc(c_msanSize / 8, 1);
+    if (!m_msanWrittenBitmap) {
+        free(m_msanRAM);
+        free(m_msanBitmap);
+        m_msanRAM = nullptr;
+        m_msanBitmap = nullptr;
+        g_system->printf(_("Failed to allocate MSAN written bitmap\n"));
+        g_system->pause();
+        return;
+    }
     m_msanPtr = 1024;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void PCSX::Memory::initMsan(bool reset) {
if (reset) {
free(m_msanRAM);
free(m_msanBitmap);
free(m_msanWrittenBitmap);
m_msanRAM = nullptr;
m_msanBitmap = nullptr;
m_msanWrittenBitmap = nullptr;
m_msanAllocs.clear();
}
if (msanInitialized()) {
g_system->printf(_("MSAN system was already initialized.\n"));
g_system->pause();
return;
}
// 1.5GB of RAM, with 384MB worth of bitmap, between 0x20000000 and 0x80000000
m_msanRAM = (uint8_t *)calloc(c_msanSize, 1);
m_msanBitmap = (uint8_t *)calloc(c_msanSize / 8, 1);
m_msanWrittenBitmap = (uint8_t *)calloc(c_msanSize / 8, 1);
m_msanPtr = 1024;
}
void PCSX::Memory::initMsan(bool reset) {
if (reset) {
free(m_msanRAM);
free(m_msanBitmap);
free(m_msanWrittenBitmap);
m_msanRAM = nullptr;
m_msanBitmap = nullptr;
m_msanWrittenBitmap = nullptr;
m_msanAllocs.clear();
}
if (msanInitialized()) {
g_system->printf(_("MSAN system was already initialized.\n"));
g_system->pause();
return;
}
// 1.5GB of RAM, with 384MB worth of bitmap, between 0x20000000 and 0x80000000
m_msanRAM = (uint8_t *)calloc(c_msanSize, 1);
if (!m_msanRAM) {
g_system->printf(_("Failed to allocate MSAN RAM\n"));
g_system->pause();
return;
}
m_msanBitmap = (uint8_t *)calloc(c_msanSize / 8, 1);
if (!m_msanBitmap) {
free(m_msanRAM);
m_msanRAM = nullptr;
g_system->printf(_("Failed to allocate MSAN bitmap\n"));
g_system->pause();
return;
}
m_msanWrittenBitmap = (uint8_t *)calloc(c_msanSize / 8, 1);
if (!m_msanWrittenBitmap) {
free(m_msanRAM);
free(m_msanBitmap);
m_msanRAM = nullptr;
m_msanBitmap = nullptr;
g_system->printf(_("Failed to allocate MSAN written bitmap\n"));
g_system->pause();
return;
}
m_msanPtr = 1024;
}


uint32_t PCSX::Memory::msanAlloc(uint32_t size) {
// Allocate 1kB more than requested, to redzone the allocation.
// This is to detect out-of-bounds accesses.
uint32_t actualSize = size + 1 * 1024;
// Then round up to the next 16-byte boundary.
actualSize = actualSize + 15 & ~15;

// Check if we still have enough memory.
if (m_msanPtr + actualSize > c_msanSize) {
g_system->printf(_("Out of memory in MsanAlloc\n"));
g_system->pause();
return 0;
}

// Allocate the memory.
uint32_t ptr = m_msanPtr;
m_msanPtr += actualSize;
// Mark the allocation as usable.
for (uint32_t i = 0; i < size; i++) {
m_msanBitmap[(ptr + i) / 8] |= 1 << ((ptr + i) % 8);
}

// Insert the allocation into the list of allocations.
m_msanAllocs.insert({ptr, size});
return ptr + 0x20000000;
}

void PCSX::Memory::msanFree(uint32_t ptr) {
if (ptr == 0) {
return;
}
// Check if the pointer is valid.
if (ptr < 0x20000000 || ptr >= 0x20000000 + c_msanSize) {
g_system->printf(_("Invalid pointer passed to MsanFree: %08x\n"), ptr);
g_system->pause();
return;
}
ptr -= 0x20000000;
auto it = m_msanAllocs.find(ptr);
if (it == m_msanAllocs.end()) {
g_system->printf(_("Invalid pointer passed to MsanFree: %08x\n"), ptr);
g_system->pause();
return;
}
// Mark the allocation as unusable.
for (uint32_t i = 0; i < m_msanAllocs[ptr]; i++) {
m_msanBitmap[(ptr + i) / 8] &= ~(1 << ((ptr + i) % 8));
}
// Remove the allocation from the list of allocations.
m_msanAllocs.erase(ptr);
}

uint32_t PCSX::Memory::msanRealloc(uint32_t ptr, uint32_t size) {
if (ptr == 0) {
return msanAlloc(size);
}
if (size == 0) {
msanFree(ptr);
return 0;
}
// Check if the pointer is valid.
if (ptr < 0x20000000 || ptr >= 0x20000000 + c_msanSize) {
g_system->printf(_("Invalid pointer passed to MsanRealloc: %08x\n"), ptr);
g_system->pause();
return 0;
}
ptr -= 0x20000000;
auto it = m_msanAllocs.find(ptr);
if (it == m_msanAllocs.end()) {
g_system->printf(_("Invalid pointer passed to MsanRealloc: %08x\n"), ptr);
g_system->pause();
return 0;
}
auto oldSize = it->second;

// Allocate new memory.
uint32_t newPtr = msanAlloc(size);
if (!newPtr) return 0;
newPtr -= 0x20000000;

// Copy the old memory to the new memory.
memcpy(m_msanRAM + newPtr, m_msanRAM + ptr, std::min(size, oldSize));

// Mark the old allocation as unusable
for (uint32_t i = 0; i < oldSize; i++) {
m_msanBitmap[(ptr + i) / 8] &= ~(1 << ((ptr + i) % 8));
}
// Mark the new allocation as written to
auto toCopy = std::min(size, oldSize);
for (uint32_t i = 0; i < toCopy; i++) {
m_msanWrittenBitmap[(newPtr + i) / 8] |= 1 << ((newPtr + i) % 8);
}
// Remove the allocation from the list of allocations.
m_msanAllocs.erase(ptr);
return newPtr + 0x20000000;
}

Check warning on line 938 in src/core/psxmem.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Complex Method

PCSX::Memory::msanRealloc has a cyclomatic complexity of 9, 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.
18 changes: 18 additions & 0 deletions src/core/psxmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
#pragma once

#include <string_view>
#include <unordered_map>
#include <vector>

#include "core/psxemulator.h"
#include "support/eventbus.h"
#include "support/polyfills.h"
#include "support/sharedmem.h"

Expand All @@ -47,6 +49,7 @@ namespace PCSX {

class Memory {
public:
Memory();
int init();
void reset();
void shutdown();
Expand Down Expand Up @@ -74,6 +77,12 @@ class Memory {
static constexpr uint16_t DMA_PCR = 0x10f0;
static constexpr uint16_t DMA_ICR = 0x10f4;

void initMsan(bool reset);
bool msanInitialized() { return m_msanRAM != nullptr; }
uint32_t msanAlloc(uint32_t size);
void msanFree(uint32_t ptr);
uint32_t msanRealloc(uint32_t ptr, uint32_t size);

template <unsigned n>
void dmaInterrupt() {
uint32_t icr = readHardwareRegister<DMA_ICR>();
Expand Down Expand Up @@ -249,6 +258,15 @@ class Memory {
uint8_t **m_writeLUT = nullptr;
uint8_t **m_readLUT = nullptr;

static constexpr uint32_t c_msanSize = 1'610'612'736;
uint8_t *m_msanRAM = nullptr;
uint8_t *m_msanBitmap = nullptr;
uint8_t *m_msanWrittenBitmap = nullptr;
uint32_t m_msanPtr = 1024;
EventBus::Listener m_listener;

std::unordered_map<uint32_t, uint32_t> m_msanAllocs;

template <typename T = void>
T *getPointer(uint32_t address) {
auto lut = m_readLUT[address >> 16];
Expand Down
Loading
Loading