mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-08-31 17:55:23 +02:00
Interpreter: Add correct alignment checks to loads/stores, cleanup
This commit is contained in:
@@ -124,7 +124,7 @@ void WebSocketMemoryReadU8(DebuggerRequest &req) {
|
||||
Core_RunOnCPUThread([&] {
|
||||
AutoDisabledReplacements memLock = LockMemory(true);
|
||||
JsonWriter &json = req.Respond();
|
||||
json.writeUint("value", Memory::Read_U8(addr));
|
||||
json.writeUint("value", Memory::ReadUnchecked_U8(addr));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ void WebSocketMemoryReadU16(DebuggerRequest &req) {
|
||||
return req.Fail("CPU not started");
|
||||
// This only depends on addr, not on anything CPU-thread-owned, so fail fast here rather than
|
||||
// making a round trip through the queue for a request we already know is invalid.
|
||||
if (!Memory::IsValidAddress(addr))
|
||||
if (!Memory::IsValidRange(addr, 2))
|
||||
return req.Fail("Invalid address");
|
||||
|
||||
// Route the actual memory read to the CPU thread instead of poking at it directly
|
||||
@@ -153,7 +153,7 @@ void WebSocketMemoryReadU16(DebuggerRequest &req) {
|
||||
Core_RunOnCPUThread([&] {
|
||||
AutoDisabledReplacements memLock = LockMemory(true);
|
||||
JsonWriter &json = req.Respond();
|
||||
json.writeUint("value", Memory::Read_U16(addr));
|
||||
json.writeUint("value", Memory::ReadUnchecked_U16(addr));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ void WebSocketMemoryReadU32(DebuggerRequest &req) {
|
||||
return req.Fail("CPU not started");
|
||||
// This only depends on addr, not on anything CPU-thread-owned, so fail fast here rather than
|
||||
// making a round trip through the queue for a request we already know is invalid.
|
||||
if (!Memory::IsValidAddress(addr))
|
||||
if (!Memory::IsValidRange(addr, 4))
|
||||
return req.Fail("Invalid address");
|
||||
|
||||
// Route the actual memory read to the CPU thread instead of poking at it directly
|
||||
|
||||
+117
-39
@@ -293,8 +293,7 @@ namespace MIPSInt
|
||||
|
||||
void Int_JumpRegType(MIPSOpcode op)
|
||||
{
|
||||
if (mipsr4k.inDelaySlot)
|
||||
{
|
||||
if (mipsr4k.inDelaySlot) {
|
||||
// There's one of these in Star Soldier at 0881808c, which seems benign.
|
||||
ERROR_LOG(Log::CPU, "Jump in delay slot :(");
|
||||
}
|
||||
@@ -318,8 +317,7 @@ namespace MIPSInt
|
||||
}
|
||||
}
|
||||
|
||||
void Int_IType(MIPSOpcode op)
|
||||
{
|
||||
void Int_IType(MIPSOpcode op) {
|
||||
u32 uimm = op & 0xFFFF;
|
||||
u32 suimm = SignExtend16ToU32(op);
|
||||
s32 simm = SignExtend16ToS32(op);
|
||||
@@ -349,9 +347,8 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_StoreSync(MIPSOpcode op)
|
||||
{
|
||||
int imm = (signed short)(op&0xFFFF);
|
||||
void Int_StoreSync(MIPSOpcode op) {
|
||||
int imm = (signed short)(op & 0xFFFF);
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
u32 addr = R(rs) + imm;
|
||||
@@ -360,12 +357,20 @@ namespace MIPSInt
|
||||
{
|
||||
case 48: // ll
|
||||
if (rt != 0) {
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::READ_WORD, "ll");
|
||||
return;
|
||||
}
|
||||
R(rt) = Memory::Read_U32(addr);
|
||||
}
|
||||
currentMIPS->llBit = 1;
|
||||
break;
|
||||
case 56: // sc
|
||||
if (currentMIPS->llBit) {
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "sc");
|
||||
return;
|
||||
}
|
||||
Memory::Write_U32(R(rt), addr);
|
||||
if (rt != 0) {
|
||||
R(rt) = 1;
|
||||
@@ -382,21 +387,18 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_RType3(MIPSOpcode op)
|
||||
{
|
||||
void Int_RType3(MIPSOpcode op) {
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
int rd = _RD;
|
||||
|
||||
// Don't change $zr.
|
||||
if (rd == 0)
|
||||
{
|
||||
if (rd == 0) {
|
||||
PC += 4;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (op & 63)
|
||||
{
|
||||
switch (op & 63) {
|
||||
case 10: if (R(rt) == 0) R(rd) = R(rs); break; //movz
|
||||
case 11: if (R(rt) != 0) R(rd) = R(rs); break; //movn
|
||||
case 32: R(rd) = R(rs) + R(rt); break; //add (exception on overflow)
|
||||
@@ -419,12 +421,11 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
|
||||
void Int_ITypeMem(MIPSOpcode op)
|
||||
{
|
||||
void Int_ITypeMem(MIPSOpcode op) {
|
||||
int imm = (signed short)(op&0xFFFF);
|
||||
int rt = _RT;
|
||||
int rs = _RS;
|
||||
u32 addr = R(rs) + imm;
|
||||
const u32 addr = R(rs) + imm;
|
||||
|
||||
if (((op >> 29) & 1) == 0 && rt == 0) {
|
||||
// Don't load anything into $zr
|
||||
@@ -432,23 +433,75 @@ namespace MIPSInt
|
||||
return;
|
||||
}
|
||||
|
||||
switch (op >> 26)
|
||||
{
|
||||
case 32: R(rt) = SignExtend8ToU32(Memory::Read_U8(addr)); break; //lb
|
||||
case 33: R(rt) = SignExtend16ToU32(Memory::Read_U16(addr)); break; //lh
|
||||
case 35: R(rt) = Memory::Read_U32(addr); break; //lw
|
||||
case 36: R(rt) = Memory::Read_U8 (addr); break; //lbu
|
||||
case 37: R(rt) = Memory::Read_U16(addr); break; //lhu
|
||||
case 40: Memory::Write_U8(R(rt), addr); break; //sb
|
||||
case 41: Memory::Write_U16(R(rt), addr); break; //sh
|
||||
case 43: Memory::Write_U32(R(rt), addr); break; //sw
|
||||
switch (op >> 26) {
|
||||
case 32:
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
Core_MemoryException(addr, 1, PC, MemoryExceptionType::READ_WORD, "lb");
|
||||
return;
|
||||
}
|
||||
R(rt) = SignExtend8ToU32(Memory::ReadUnchecked_U8(addr));
|
||||
break; //lb
|
||||
case 33:
|
||||
if (!Memory::IsValid2AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 2, PC, MemoryExceptionType::READ_WORD, "lh");
|
||||
return;
|
||||
}
|
||||
R(rt) = SignExtend16ToU32(Memory::ReadUnchecked_U16(addr));
|
||||
break; //lh
|
||||
case 35:
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::READ_WORD, "lw");
|
||||
return;
|
||||
}
|
||||
R(rt) = Memory::ReadUnchecked_U32(addr);
|
||||
break; //lw
|
||||
case 36:
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
Core_MemoryException(addr, 1, PC, MemoryExceptionType::READ_WORD, "lbu");
|
||||
return;
|
||||
}
|
||||
R(rt) = Memory::Read_U8 (addr);
|
||||
break; //lbu
|
||||
case 37:
|
||||
if (!Memory::IsValid2AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 2, PC, MemoryExceptionType::READ_WORD, "lhu");
|
||||
return;
|
||||
}
|
||||
R(rt) = Memory::Read_U16(addr);
|
||||
break; //lhu
|
||||
case 40:
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
Core_MemoryException(addr, 1, PC, MemoryExceptionType::WRITE_WORD, "sb");
|
||||
return;
|
||||
}
|
||||
Memory::Write_U8(R(rt), addr);
|
||||
break; //sb
|
||||
case 41:
|
||||
if (!Memory::IsValid2AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 2, PC, MemoryExceptionType::WRITE_WORD, "sh");
|
||||
return;
|
||||
}
|
||||
Memory::Write_U16(R(rt), addr);
|
||||
break; //sh
|
||||
case 43:
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "sw");
|
||||
return;
|
||||
}
|
||||
Memory::Write_U32(R(rt), addr);
|
||||
break; //sw
|
||||
|
||||
// When there's an LWL and an LWR together, we should be able to peephole optimize that
|
||||
// into a single non-alignment-checking LW.
|
||||
case 34: //lwl
|
||||
{
|
||||
// Not checking for alignment here - the actual read will be aligned.
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::READ_WORD, "lwl");
|
||||
return;
|
||||
}
|
||||
u32 shift = (addr & 3) * 8;
|
||||
u32 mem = Memory::Read_U32(addr & 0xfffffffc);
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 result = ( u32(R(rt)) & (0x00ffffff >> shift) ) | ( mem << (24 - shift) );
|
||||
R(rt) = result;
|
||||
}
|
||||
@@ -456,8 +509,13 @@ namespace MIPSInt
|
||||
|
||||
case 38: //lwr
|
||||
{
|
||||
// Not checking for alignment here - the actual read will be aligned.
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::READ_WORD, "lwr");
|
||||
return;
|
||||
}
|
||||
u32 shift = (addr & 3) * 8;
|
||||
u32 mem = Memory::Read_U32(addr & 0xfffffffc);
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 regval = R(rt);
|
||||
u32 result = ( regval & (0xffffff00 << (24 - shift)) ) | ( mem >> shift );
|
||||
R(rt) = result;
|
||||
@@ -466,19 +524,29 @@ namespace MIPSInt
|
||||
|
||||
case 42: //swl
|
||||
{
|
||||
// Not checking for alignment here - the actual read/write will be aligned.
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "swl");
|
||||
return;
|
||||
}
|
||||
u32 shift = (addr & 3) * 8;
|
||||
u32 mem = Memory::Read_U32(addr & 0xfffffffc);
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 result = ( ( u32(R(rt)) >> (24 - shift) ) ) | ( mem & (0xffffff00 << shift) );
|
||||
Memory::Write_U32(result, (addr & 0xfffffffc));
|
||||
Memory::WriteUnchecked_U32(result, (addr & 0xfffffffc));
|
||||
}
|
||||
break;
|
||||
|
||||
case 46: //swr
|
||||
{
|
||||
// Not checking for alignment here - the actual read/write will be aligned.
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "swr");
|
||||
return;
|
||||
}
|
||||
u32 shift = (addr & 3) << 3;
|
||||
u32 mem = Memory::Read_U32(addr & 0xfffffffc);
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 result = ( ( u32(R(rt)) << shift ) | (mem & (0x00ffffff >> (24 - shift)) ) );
|
||||
Memory::Write_U32(result, (addr & 0xfffffffc));
|
||||
Memory::WriteUnchecked_U32(result, (addr & 0xfffffffc));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -489,17 +557,27 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_FPULS(MIPSOpcode op)
|
||||
{
|
||||
s32 offset = (s16)(op&0xFFFF);
|
||||
void Int_FPULS(MIPSOpcode op) {
|
||||
s32 offset = (s16)(op & 0xFFFF);
|
||||
int ft = _FT;
|
||||
int rs = _RS;
|
||||
u32 addr = R(rs) + offset;
|
||||
|
||||
switch(op >> 26)
|
||||
{
|
||||
case 49: FI(ft) = Memory::Read_U32(addr); break; //lwc1
|
||||
case 57: Memory::Write_U32(FI(ft), addr); break; //swc1
|
||||
switch (op >> 26) {
|
||||
case 49:
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::READ_WORD, "lwc1");
|
||||
return;
|
||||
}
|
||||
FI(ft) = Memory::Read_U32(addr);
|
||||
break; //lwc1
|
||||
case 57:
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "swc1");
|
||||
return;
|
||||
}
|
||||
Memory::Write_U32(FI(ft), addr);
|
||||
break; //swc1
|
||||
default:
|
||||
_dbg_assert_msg_(false,"Trying to interpret FPULS instruction that can't be interpreted");
|
||||
break;
|
||||
|
||||
+46
-49
@@ -200,8 +200,7 @@ namespace MIPSInt
|
||||
PC += 4;
|
||||
}
|
||||
|
||||
void Int_SVQ(MIPSOpcode op)
|
||||
{
|
||||
void Int_SVQ(MIPSOpcode op) {
|
||||
int imm = SignExtend16ToS32(op & 0xFFFC);
|
||||
int rs = _RS;
|
||||
int vt = (((op >> 16) & 0x1f)) | ((op&1) << 5);
|
||||
@@ -210,31 +209,29 @@ namespace MIPSInt
|
||||
float *f;
|
||||
const float *cf;
|
||||
|
||||
switch (op >> 26)
|
||||
{
|
||||
switch (op >> 26) {
|
||||
case 53: //lvl.q/lvr.q
|
||||
{
|
||||
if (addr & 0x3)
|
||||
{
|
||||
_dbg_assert_msg_( 0, "Misaligned lvX.q at %08x (pc = %08x)", addr, PC);
|
||||
}
|
||||
float d[4];
|
||||
ReadVector(d, V_Quad, vt);
|
||||
int offset = (addr >> 2) & 3;
|
||||
if ((op & 2) == 0)
|
||||
{
|
||||
if ((op & 2) == 0) {
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 16, PC, MemoryExceptionType::READ_WORD, "lvl.q");
|
||||
return;
|
||||
}
|
||||
// It's an LVL
|
||||
for (int i = 0; i < offset + 1; i++)
|
||||
{
|
||||
d[3 - i] = Memory::Read_Float(addr - 4 * i);
|
||||
for (int i = 0; i < offset + 1; i++) {
|
||||
d[3 - i] = Memory::ReadUnchecked_Float(addr - 4 * i);
|
||||
}
|
||||
} else {
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 16, PC, MemoryExceptionType::READ_WORD, "lvr.q");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's an LVR
|
||||
for (int i = 0; i < (3 - offset) + 1; i++)
|
||||
{
|
||||
d[i] = Memory::Read_Float(addr + 4 * i);
|
||||
for (int i = 0; i < (3 - offset) + 1; i++) {
|
||||
d[i] = Memory::ReadUnchecked_Float(addr + 4 * i);
|
||||
}
|
||||
}
|
||||
WriteVector(d, V_Quad, vt);
|
||||
@@ -242,21 +239,21 @@ namespace MIPSInt
|
||||
break;
|
||||
|
||||
case 54: //lv.q
|
||||
if (addr & 0xF)
|
||||
{
|
||||
_dbg_assert_msg_( 0, "Misaligned lv.q at %08x (pc = %08x)", addr, PC);
|
||||
if ((addr & 0xF) || !Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 16, PC, MemoryExceptionType::READ_WORD, "lv.q");
|
||||
}
|
||||
|
||||
#ifndef COMMON_BIG_ENDIAN
|
||||
cf = reinterpret_cast<const float *>(Memory::GetPointerRange(addr, 16));
|
||||
cf = reinterpret_cast<const float *>(Memory::GetPointerUnchecked(addr));
|
||||
if (cf)
|
||||
WriteVector(cf, V_Quad, vt);
|
||||
#else
|
||||
float lvqd[4];
|
||||
|
||||
lvqd[0] = Memory::Read_Float(addr);
|
||||
lvqd[1] = Memory::Read_Float(addr + 4);
|
||||
lvqd[2] = Memory::Read_Float(addr + 8);
|
||||
lvqd[3] = Memory::Read_Float(addr + 12);
|
||||
lvqd[0] = Memory::ReadUnchecked_Float(addr);
|
||||
lvqd[1] = Memory::ReadUnchecked_Float(addr + 4);
|
||||
lvqd[2] = Memory::ReadUnchecked_Float(addr + 8);
|
||||
lvqd[3] = Memory::ReadUnchecked_Float(addr + 12);
|
||||
|
||||
WriteVector(lvqd, V_Quad, vt);
|
||||
#endif
|
||||
@@ -264,49 +261,49 @@ namespace MIPSInt
|
||||
|
||||
case 61: // svl.q/svr.q
|
||||
{
|
||||
if (addr & 0x3)
|
||||
{
|
||||
_dbg_assert_msg_( 0, "Misaligned svX.q at %08x (pc = %08x)", addr, PC);
|
||||
}
|
||||
float d[4];
|
||||
ReadVector(d, V_Quad, vt);
|
||||
int offset = (addr >> 2) & 3;
|
||||
if ((op&2) == 0)
|
||||
{
|
||||
if ((op & 2) == 0) {
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 16, PC, MemoryExceptionType::WRITE_WORD, "svl.q");
|
||||
return;
|
||||
}
|
||||
// It's an SVL
|
||||
for (int i = 0; i < offset + 1; i++)
|
||||
{
|
||||
Memory::Write_Float(d[3 - i], addr - i * 4);
|
||||
Memory::WriteUnchecked_Float(d[3 - i], addr - i * 4);
|
||||
}
|
||||
} else {
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 16, PC, MemoryExceptionType::WRITE_WORD, "svr.q");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's an SVR
|
||||
for (int i = 0; i < (3 - offset) + 1; i++)
|
||||
{
|
||||
Memory::Write_Float(d[i], addr + 4 * i);
|
||||
for (int i = 0; i < (3 - offset) + 1; i++) {
|
||||
Memory::WriteUnchecked_Float(d[i], addr + 4 * i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 62: //sv.q
|
||||
if (addr & 0xF)
|
||||
{
|
||||
_dbg_assert_msg_( 0, "Misaligned sv.q at %08x (pc = %08x)", addr, PC);
|
||||
if ((addr & 0xF) || !Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 16, PC, MemoryExceptionType::WRITE_WORD, "sv.q");
|
||||
}
|
||||
#ifndef COMMON_BIG_ENDIAN
|
||||
f = reinterpret_cast<float *>(Memory::GetPointerWriteRange(addr, 16));
|
||||
if (f)
|
||||
f = reinterpret_cast<float *>(Memory::GetPointerWriteUnchecked(addr));
|
||||
if (f) {
|
||||
ReadVector(f, V_Quad, vt);
|
||||
}
|
||||
#else
|
||||
float svqd[4];
|
||||
ReadVector(svqd, V_Quad, vt);
|
||||
|
||||
Memory::Write_Float(svqd[0], addr);
|
||||
Memory::Write_Float(svqd[1], addr + 4);
|
||||
Memory::Write_Float(svqd[2], addr + 8);
|
||||
Memory::Write_Float(svqd[3], addr + 12);
|
||||
Memory::WriteUnchecked_Float(svqd[0], addr);
|
||||
Memory::WriteUnchecked_Float(svqd[1], addr + 4);
|
||||
Memory::WriteUnchecked_Float(svqd[2], addr + 8);
|
||||
Memory::WriteUnchecked_Float(svqd[3], addr + 12);
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
+14
-8
@@ -238,14 +238,6 @@ inline void WriteUnchecked_U8(u8 data, u32 address) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline float Read_Float(u32 address)
|
||||
{
|
||||
u32 ifloat = Read_U32(address);
|
||||
float f;
|
||||
memcpy(&f, &ifloat, sizeof(float));
|
||||
return f;
|
||||
}
|
||||
|
||||
// used by JIT. Return zero-extended 32bit values
|
||||
u32 Read_U8_ZX(const u32 address);
|
||||
u32 Read_U16_ZX(const u32 address);
|
||||
@@ -325,6 +317,20 @@ inline bool IsValidAddress(const u32 address) {
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IsValid2AlignedAddress(const u32 address) {
|
||||
if ((address & 0x3E000001) == 0x08000000) {
|
||||
return true;
|
||||
} else if ((address & 0x3F800001) == 0x04000000) {
|
||||
return address < 0x80000000; // Let's disallow kernel-flagged VRAM. We don't have it mapped and I am not sure if it's accessible.
|
||||
} else if ((address & 0xBFFFC001) == 0x00010000) {
|
||||
return true;
|
||||
} else if ((address & 0x3F000000) >= 0x08000000 && (address & 0x3F000000) < 0x08000000 + g_MemorySize) {
|
||||
return (address & 1) == 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IsValid4AlignedAddress(const u32 address) {
|
||||
if ((address & 0x3E000003) == 0x08000000) {
|
||||
return true;
|
||||
|
||||
@@ -516,7 +516,7 @@ void ImMemView::PopupMenu() {
|
||||
|
||||
if (ImGui::MenuItem("Copy value (float32)")) {
|
||||
char temp[64];
|
||||
snprintf(temp, sizeof(temp), "%f", Memory::IsValidAddress(curAddress_) ? Memory::Read_Float(curAddress_) : NAN);
|
||||
snprintf(temp, sizeof(temp), "%f", Memory::IsValid4AlignedAddress(curAddress_) ? Memory::ReadUnchecked_Float(curAddress_) : NAN);
|
||||
System_CopyStringToClipboard(temp);
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -597,7 +597,7 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) {
|
||||
{
|
||||
auto memLock = Memory::Lock();
|
||||
std::ostringstream stream;
|
||||
stream << (Memory::IsValidAddress(curAddress_) ? Memory::Read_Float(curAddress_) : NAN);
|
||||
stream << (Memory::IsValid4AlignedAddress(curAddress_) ? Memory::ReadUnchecked_Float(curAddress_) : NAN);
|
||||
auto temp_string = stream.str();
|
||||
W32Util::CopyTextToClipboard(wnd, temp_string);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user