mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-02-17 03:15:39 +00:00
Cheats: Use safe memory access routines
This commit is contained in:
parent
8dcd68b0a8
commit
e12474ac91
|
@ -14,6 +14,7 @@
|
|||
#include <cctype>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
Log_SetChannel(Cheats);
|
||||
static std::array<u32, 256> cht_register; // Used for D7 ,51 & 52 cheat types
|
||||
|
||||
|
@ -39,66 +40,34 @@ static bool IsValidScanAddress(PhysicalMemoryAddress address)
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
static T DoMemoryRead(PhysicalMemoryAddress address)
|
||||
static T DoMemoryRead(VirtualMemoryAddress address)
|
||||
{
|
||||
using UnsignedType = typename std::make_unsigned_t<T>;
|
||||
static_assert(std::is_same_v<UnsignedType, u8> || std::is_same_v<UnsignedType, u16> ||
|
||||
std::is_same_v<UnsignedType, u32>);
|
||||
|
||||
T result;
|
||||
|
||||
if ((address & CPU::DCACHE_LOCATION_MASK) == CPU::DCACHE_LOCATION &&
|
||||
(address & CPU::DCACHE_OFFSET_MASK) < CPU::DCACHE_SIZE)
|
||||
{
|
||||
std::memcpy(&result, &CPU::g_state.dcache[address & CPU::DCACHE_OFFSET_MASK], sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
address &= CPU::PHYSICAL_MEMORY_ADDRESS_MASK;
|
||||
|
||||
if (address < Bus::RAM_MIRROR_END)
|
||||
{
|
||||
if (Bus::g_ram != NULL)
|
||||
std::memcpy(&result, &Bus::g_ram[address & Bus::g_ram_mask], sizeof(result));
|
||||
else
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (address >= Bus::BIOS_BASE && address < (Bus::BIOS_BASE + Bus::BIOS_SIZE))
|
||||
{
|
||||
std::memcpy(&result, &Bus::g_bios[address & Bus::BIOS_MASK], sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
result = static_cast<T>(0);
|
||||
return result;
|
||||
if constexpr (std::is_same_v<UnsignedType, u8>)
|
||||
return CPU::SafeReadMemoryByte(address, &result) ? result : static_cast<T>(0);
|
||||
else if constexpr (std::is_same_v<UnsignedType, u16>)
|
||||
return CPU::SafeReadMemoryHalfWord(address, &result) ? result : static_cast<T>(0);
|
||||
else // if constexpr (std::is_same_v<UnsignedType, u32>)
|
||||
return CPU::SafeReadMemoryWord(address, &result) ? result : static_cast<T>(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void DoMemoryWrite(PhysicalMemoryAddress address, T value)
|
||||
{
|
||||
if ((address & CPU::DCACHE_LOCATION_MASK) == CPU::DCACHE_LOCATION &&
|
||||
(address & CPU::DCACHE_OFFSET_MASK) < CPU::DCACHE_SIZE)
|
||||
{
|
||||
std::memcpy(&CPU::g_state.dcache[address & CPU::DCACHE_OFFSET_MASK], &value, sizeof(value));
|
||||
return;
|
||||
}
|
||||
using UnsignedType = typename std::make_unsigned_t<T>;
|
||||
static_assert(std::is_same_v<UnsignedType, u8> || std::is_same_v<UnsignedType, u16> ||
|
||||
std::is_same_v<UnsignedType, u32>);
|
||||
|
||||
address &= CPU::PHYSICAL_MEMORY_ADDRESS_MASK;
|
||||
|
||||
if (address < Bus::RAM_MIRROR_END)
|
||||
{
|
||||
// Only invalidate code when it changes.
|
||||
T old_value;
|
||||
std::memcpy(&old_value, &Bus::g_ram[address & Bus::g_ram_mask], sizeof(old_value));
|
||||
if (old_value != value)
|
||||
{
|
||||
std::memcpy(&Bus::g_ram[address & Bus::g_ram_mask], &value, sizeof(value));
|
||||
|
||||
const u32 code_page_index = Bus::GetRAMCodePageIndex(address & Bus::g_ram_mask);
|
||||
if (Bus::IsRAMCodePage(code_page_index))
|
||||
CPU::CodeCache::InvalidateBlocksWithPageIndex(code_page_index);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if constexpr (std::is_same_v<UnsignedType, u8>)
|
||||
CPU::SafeWriteMemoryByte(address, value);
|
||||
else if constexpr (std::is_same_v<UnsignedType, u16>)
|
||||
CPU::SafeWriteMemoryHalfWord(address, value);
|
||||
else // if constexpr (std::is_same_v<UnsignedType, u32>)
|
||||
CPU::SafeWriteMemoryWord(address, value);
|
||||
}
|
||||
|
||||
static u32 GetControllerButtonBits()
|
||||
|
@ -1535,7 +1504,8 @@ void CheatCode::Apply() const
|
|||
break;
|
||||
case 0x43: // Write the u16 from cht_register[cht_reg_no2] to cht_register[cht_reg_no1]
|
||||
// and add the u16 from the address field to it
|
||||
cht_register[cht_reg_no1] = Truncate16(cht_register[cht_reg_no2] & 0xFFFFu) + Truncate16(poke_value & 0xFFFFu);
|
||||
cht_register[cht_reg_no1] =
|
||||
Truncate16(cht_register[cht_reg_no2] & 0xFFFFu) + Truncate16(poke_value & 0xFFFFu);
|
||||
break;
|
||||
case 0x44: // Write the u16 from the value stored in cht_register[cht_reg_no2] + poke_value to the address
|
||||
// stored in cht_register[cht_reg_no1]
|
||||
|
@ -1677,16 +1647,20 @@ void CheatCode::Apply() const
|
|||
switch (instructions[index].code)
|
||||
{
|
||||
case InstructionCode::CompareEqual16: // D0
|
||||
conditions_check &= (DoMemoryRead<u16>(instructions[index].address) == instructions[index].value16);
|
||||
conditions_check &=
|
||||
(DoMemoryRead<u16>(instructions[index].address) == instructions[index].value16);
|
||||
break;
|
||||
case InstructionCode::CompareNotEqual16: // D1
|
||||
conditions_check &= (DoMemoryRead<u16>(instructions[index].address) != instructions[index].value16);
|
||||
conditions_check &=
|
||||
(DoMemoryRead<u16>(instructions[index].address) != instructions[index].value16);
|
||||
break;
|
||||
case InstructionCode::CompareLess16: // D2
|
||||
conditions_check &= (DoMemoryRead<u16>(instructions[index].address) < instructions[index].value16);
|
||||
conditions_check &=
|
||||
(DoMemoryRead<u16>(instructions[index].address) < instructions[index].value16);
|
||||
break;
|
||||
case InstructionCode::CompareGreater16: // D3
|
||||
conditions_check &= (DoMemoryRead<u16>(instructions[index].address) > instructions[index].value16);
|
||||
conditions_check &=
|
||||
(DoMemoryRead<u16>(instructions[index].address) > instructions[index].value16);
|
||||
break;
|
||||
case InstructionCode::CompareEqual8: // E0
|
||||
conditions_check &= (DoMemoryRead<u8>(instructions[index].address) == instructions[index].value8);
|
||||
|
@ -1701,22 +1675,29 @@ void CheatCode::Apply() const
|
|||
conditions_check &= (DoMemoryRead<u8>(instructions[index].address) > instructions[index].value8);
|
||||
break;
|
||||
case InstructionCode::ExtCompareEqual32: // A0
|
||||
conditions_check &= (DoMemoryRead<u32>(instructions[index].address) == instructions[index].value32);
|
||||
conditions_check &=
|
||||
(DoMemoryRead<u32>(instructions[index].address) == instructions[index].value32);
|
||||
break;
|
||||
case InstructionCode::ExtCompareNotEqual32: // A1
|
||||
conditions_check &= (DoMemoryRead<u32>(instructions[index].address) != instructions[index].value32);
|
||||
conditions_check &=
|
||||
(DoMemoryRead<u32>(instructions[index].address) != instructions[index].value32);
|
||||
break;
|
||||
case InstructionCode::ExtCompareLess32: // A2
|
||||
conditions_check &= (DoMemoryRead<u32>(instructions[index].address) < instructions[index].value32);
|
||||
conditions_check &=
|
||||
(DoMemoryRead<u32>(instructions[index].address) < instructions[index].value32);
|
||||
break;
|
||||
case InstructionCode::ExtCompareGreater32: // A3
|
||||
conditions_check &= (DoMemoryRead<u32>(instructions[index].address) > instructions[index].value32);
|
||||
conditions_check &=
|
||||
(DoMemoryRead<u32>(instructions[index].address) > instructions[index].value32);
|
||||
break;
|
||||
case InstructionCode::ExtCompareBitsSet8: // E4 Internal to F6
|
||||
conditions_check &= (instructions[index].value8 == (DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8));
|
||||
conditions_check &=
|
||||
(instructions[index].value8 ==
|
||||
(DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8));
|
||||
break;
|
||||
case InstructionCode::ExtCompareBitsClear8: // E5 Internal to F6
|
||||
conditions_check &= ((DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8) == 0);
|
||||
conditions_check &=
|
||||
((DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8) == 0);
|
||||
break;
|
||||
case InstructionCode::ExtBitCompareButtons: // D7
|
||||
{
|
||||
|
@ -1730,7 +1711,8 @@ void CheatCode::Apply() const
|
|||
u32 value = value1 | value2;
|
||||
|
||||
if ((bit_comparison_type == false && check_value == (value & check_value)) // Check Bits are set
|
||||
|| (bit_comparison_type == true && check_value != (value & check_value))) //Check Bits are clear
|
||||
||
|
||||
(bit_comparison_type == true && check_value != (value & check_value))) // Check Bits are clear
|
||||
{
|
||||
cht_register[cht_reg_no] += 1;
|
||||
switch (frame_comparison)
|
||||
|
@ -1777,16 +1759,20 @@ void CheatCode::Apply() const
|
|||
switch (instructions[index].code)
|
||||
{
|
||||
case InstructionCode::CompareEqual16: // D0
|
||||
conditions_check |= (DoMemoryRead<u16>(instructions[index].address) == instructions[index].value16);
|
||||
conditions_check |=
|
||||
(DoMemoryRead<u16>(instructions[index].address) == instructions[index].value16);
|
||||
break;
|
||||
case InstructionCode::CompareNotEqual16: // D1
|
||||
conditions_check |= (DoMemoryRead<u16>(instructions[index].address) != instructions[index].value16);
|
||||
conditions_check |=
|
||||
(DoMemoryRead<u16>(instructions[index].address) != instructions[index].value16);
|
||||
break;
|
||||
case InstructionCode::CompareLess16: // D2
|
||||
conditions_check |= (DoMemoryRead<u16>(instructions[index].address) < instructions[index].value16);
|
||||
conditions_check |=
|
||||
(DoMemoryRead<u16>(instructions[index].address) < instructions[index].value16);
|
||||
break;
|
||||
case InstructionCode::CompareGreater16: // D3
|
||||
conditions_check |= (DoMemoryRead<u16>(instructions[index].address) > instructions[index].value16);
|
||||
conditions_check |=
|
||||
(DoMemoryRead<u16>(instructions[index].address) > instructions[index].value16);
|
||||
break;
|
||||
case InstructionCode::CompareEqual8: // E0
|
||||
conditions_check |= (DoMemoryRead<u8>(instructions[index].address) == instructions[index].value8);
|
||||
|
@ -1801,22 +1787,29 @@ void CheatCode::Apply() const
|
|||
conditions_check |= (DoMemoryRead<u8>(instructions[index].address) > instructions[index].value8);
|
||||
break;
|
||||
case InstructionCode::ExtCompareEqual32: // A0
|
||||
conditions_check |= (DoMemoryRead<u32>(instructions[index].address) == instructions[index].value32);
|
||||
conditions_check |=
|
||||
(DoMemoryRead<u32>(instructions[index].address) == instructions[index].value32);
|
||||
break;
|
||||
case InstructionCode::ExtCompareNotEqual32: // A1
|
||||
conditions_check |= (DoMemoryRead<u32>(instructions[index].address) != instructions[index].value32);
|
||||
conditions_check |=
|
||||
(DoMemoryRead<u32>(instructions[index].address) != instructions[index].value32);
|
||||
break;
|
||||
case InstructionCode::ExtCompareLess32: // A2
|
||||
conditions_check |= (DoMemoryRead<u32>(instructions[index].address) < instructions[index].value32);
|
||||
conditions_check |=
|
||||
(DoMemoryRead<u32>(instructions[index].address) < instructions[index].value32);
|
||||
break;
|
||||
case InstructionCode::ExtCompareGreater32: // A3
|
||||
conditions_check |= (DoMemoryRead<u32>(instructions[index].address) > instructions[index].value32);
|
||||
conditions_check |=
|
||||
(DoMemoryRead<u32>(instructions[index].address) > instructions[index].value32);
|
||||
break;
|
||||
case InstructionCode::ExtCompareBitsSet8: // E4 Internal to F6
|
||||
conditions_check |= (instructions[index].value8 == (DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8));
|
||||
conditions_check |=
|
||||
(instructions[index].value8 ==
|
||||
(DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8));
|
||||
break;
|
||||
case InstructionCode::ExtCompareBitsClear8: // E5 Internal to F6
|
||||
conditions_check |= ((DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8) == 0);
|
||||
conditions_check |=
|
||||
((DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8) == 0);
|
||||
break;
|
||||
case InstructionCode::ExtBitCompareButtons: // D7
|
||||
{
|
||||
|
@ -1830,7 +1823,8 @@ void CheatCode::Apply() const
|
|||
u32 value = value1 | value2;
|
||||
|
||||
if ((bit_comparison_type == false && check_value == (value & check_value)) // Check Bits are set
|
||||
|| (bit_comparison_type == true && check_value != (value & check_value))) //Check Bits are clear
|
||||
||
|
||||
(bit_comparison_type == true && check_value != (value & check_value))) // Check Bits are clear
|
||||
{
|
||||
cht_register[cht_reg_no] += 1;
|
||||
switch (frame_comparison)
|
||||
|
@ -2008,7 +2002,6 @@ void CheatCode::Apply() const
|
|||
}
|
||||
break;
|
||||
|
||||
|
||||
case InstructionCode::ExtCheatRegistersCompare: // 52
|
||||
{
|
||||
index++;
|
||||
|
@ -2627,8 +2620,6 @@ void CheatCode::Apply() const
|
|||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case InstructionCode::MemoryCopy:
|
||||
{
|
||||
if ((index + 1) >= instructions.size())
|
||||
|
@ -3076,8 +3067,6 @@ void MemoryScan::Result::UpdateValue(MemoryAccessSize size, bool is_signed)
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
value_changed = (value != old_value);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue