Bus: Handle CPU-internal narrow writes
The full 32-bits of the GPR are used. Fixes SoundScope in the BIOS Shell.
This commit is contained in:
parent
7fb5d6908f
commit
40731b49fc
127
src/core/bus.cpp
127
src/core/bus.cpp
|
@ -111,20 +111,17 @@ static void ReleaseMemory();
|
|||
|
||||
static void SetCodePageFastmemProtection(u32 page_index, bool writable);
|
||||
|
||||
#define FIXUP_WORD_READ_OFFSET(offset) ((offset) & ~u32(3))
|
||||
#define FIXUP_WORD_READ_VALUE(offset, value) ((value) >> (((offset)&u32(3)) * 8u))
|
||||
#define FIXUP_HALFWORD_READ_OFFSET(offset) ((offset) & ~u32(1))
|
||||
#define FIXUP_HALFWORD_READ_VALUE(offset, value) ((value) >> (((offset)&u32(1)) * 8u))
|
||||
#define FIXUP_HALFWORD_WRITE_VALUE(offset, value) ((value) << (((offset)&u32(1)) * 8u))
|
||||
#define FIXUP_HALFWORD_OFFSET(size, offset) ((size >= MemoryAccessSize::HalfWord) ? (offset) : ((offset) & ~1u))
|
||||
#define FIXUP_HALFWORD_READ_VALUE(size, offset, value) \
|
||||
((size >= MemoryAccessSize::HalfWord) ? (value) : ((value) >> (((offset)&u32(1)) * 8u)))
|
||||
#define FIXUP_HALFWORD_WRITE_VALUE(size, offset, value) \
|
||||
((size >= MemoryAccessSize::HalfWord) ? (value) : ((value) << (((offset)&u32(1)) * 8u)))
|
||||
|
||||
// Offset and value remapping for (w32) registers from nocash docs.
|
||||
// TODO: Make template function based on type, and noop for word access
|
||||
ALWAYS_INLINE static void FixupUnalignedWordAccessW32(u32& offset, u32& value)
|
||||
{
|
||||
const u32 byte_offset = offset & u32(3);
|
||||
offset &= ~u32(3);
|
||||
value <<= byte_offset * 8;
|
||||
}
|
||||
#define FIXUP_WORD_OFFSET(size, offset) ((size == MemoryAccessSize::Word) ? (offset) : ((offset) & ~3u))
|
||||
#define FIXUP_WORD_READ_VALUE(size, offset, value) \
|
||||
((size == MemoryAccessSize::Word) ? (value) : ((value) >> (((offset)&3u) * 8)))
|
||||
#define FIXUP_WORD_WRITE_VALUE(size, offset, value) \
|
||||
((size == MemoryAccessSize::Word) ? (value) : ((value) << (((offset)&3u) * 8)))
|
||||
|
||||
bool Initialize()
|
||||
{
|
||||
|
@ -971,15 +968,15 @@ ALWAYS_INLINE static TickCount DoMemoryControlAccess(u32 offset, u32& value)
|
|||
{
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
{
|
||||
value = m_MEMCTRL.regs[offset / 4];
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
value = m_MEMCTRL.regs[FIXUP_WORD_OFFSET(size, offset) / 4];
|
||||
value = FIXUP_WORD_READ_VALUE(size, offset, value);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
const u32 index = FIXUP_WORD_OFFSET(size, offset) / 4;
|
||||
value = FIXUP_WORD_WRITE_VALUE(size, offset, value);
|
||||
|
||||
const u32 index = offset / 4;
|
||||
const u32 write_mask = (index == 8) ? COMDELAY::WRITE_MASK : MEMDELAY::WRITE_MASK;
|
||||
const u32 new_value = (m_MEMCTRL.regs[index] & ~write_mask) | (value & write_mask);
|
||||
if (m_MEMCTRL.regs[index] != new_value)
|
||||
|
@ -1027,12 +1024,13 @@ ALWAYS_INLINE static TickCount DoPadAccess(u32 offset, u32& value)
|
|||
{
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
{
|
||||
value = g_pad.ReadRegister(offset);
|
||||
value = g_pad.ReadRegister(FIXUP_HALFWORD_OFFSET(size, offset));
|
||||
value = FIXUP_HALFWORD_READ_VALUE(size, offset, value);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pad.WriteRegister(offset, value);
|
||||
g_pad.WriteRegister(FIXUP_HALFWORD_OFFSET(size, offset), FIXUP_HALFWORD_WRITE_VALUE(size, offset, value));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1042,12 +1040,13 @@ ALWAYS_INLINE static TickCount DoSIOAccess(u32 offset, u32& value)
|
|||
{
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
{
|
||||
value = g_sio.ReadRegister(offset);
|
||||
value = g_sio.ReadRegister(FIXUP_HALFWORD_OFFSET(size, offset));
|
||||
value = FIXUP_HALFWORD_READ_VALUE(size, offset, value);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_sio.WriteRegister(offset, value);
|
||||
g_sio.WriteRegister(FIXUP_HALFWORD_OFFSET(size, offset), FIXUP_HALFWORD_WRITE_VALUE(size, offset, value));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1117,14 +1116,13 @@ ALWAYS_INLINE static TickCount DoGPUAccess(u32 offset, u32& value)
|
|||
{
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
{
|
||||
value = g_gpu->ReadRegister(offset);
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
value = g_gpu->ReadRegister(FIXUP_WORD_OFFSET(size, offset));
|
||||
value = FIXUP_WORD_READ_VALUE(size, offset, value);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
g_gpu->WriteRegister(offset, value);
|
||||
g_gpu->WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1134,14 +1132,13 @@ ALWAYS_INLINE static TickCount DoMDECAccess(u32 offset, u32& value)
|
|||
{
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
{
|
||||
value = g_mdec.ReadRegister(offset);
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
value = g_mdec.ReadRegister(FIXUP_WORD_OFFSET(size, offset));
|
||||
value = FIXUP_WORD_READ_VALUE(size, offset, value);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
g_mdec.WriteRegister(offset, value);
|
||||
g_mdec.WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1151,14 +1148,13 @@ ALWAYS_INLINE static TickCount DoAccessInterruptController(u32 offset, u32& valu
|
|||
{
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
{
|
||||
value = g_interrupt_controller.ReadRegister(offset);
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
value = g_interrupt_controller.ReadRegister(FIXUP_WORD_OFFSET(size, offset));
|
||||
value = FIXUP_WORD_READ_VALUE(size, offset, value);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
g_interrupt_controller.WriteRegister(offset, value);
|
||||
g_interrupt_controller.WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1168,14 +1164,13 @@ ALWAYS_INLINE static TickCount DoAccessTimers(u32 offset, u32& value)
|
|||
{
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
{
|
||||
value = g_timers.ReadRegister(offset);
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
value = g_timers.ReadRegister(FIXUP_WORD_OFFSET(size, offset));
|
||||
value = FIXUP_WORD_READ_VALUE(size, offset, value);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
g_timers.WriteRegister(offset, value);
|
||||
g_timers.WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1205,8 +1200,8 @@ ALWAYS_INLINE static TickCount DoAccessSPU(u32 offset, u32& value)
|
|||
case MemoryAccessSize::Byte:
|
||||
default:
|
||||
{
|
||||
const u16 value16 = g_spu.ReadRegister(FIXUP_HALFWORD_READ_OFFSET(offset));
|
||||
value = FIXUP_HALFWORD_READ_VALUE(offset, value16);
|
||||
const u16 value16 = g_spu.ReadRegister(FIXUP_HALFWORD_OFFSET(size, offset));
|
||||
value = FIXUP_HALFWORD_READ_VALUE(size, offset, value16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1236,7 +1231,8 @@ ALWAYS_INLINE static TickCount DoAccessSPU(u32 offset, u32& value)
|
|||
|
||||
case MemoryAccessSize::Byte:
|
||||
{
|
||||
g_spu.WriteRegister(FIXUP_HALFWORD_READ_OFFSET(offset), Truncate16(FIXUP_HALFWORD_READ_VALUE(offset, value)));
|
||||
g_spu.WriteRegister(FIXUP_HALFWORD_OFFSET(size, offset),
|
||||
Truncate16(FIXUP_HALFWORD_READ_VALUE(size, offset, value)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1250,28 +1246,13 @@ ALWAYS_INLINE static TickCount DoDMAAccess(u32 offset, u32& value)
|
|||
{
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
{
|
||||
value = FIXUP_WORD_READ_VALUE(offset, g_dma.ReadRegister(FIXUP_WORD_READ_OFFSET(offset)));
|
||||
value = g_dma.ReadRegister(FIXUP_WORD_OFFSET(size, offset));
|
||||
value = FIXUP_WORD_READ_VALUE(size, offset, value);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case MemoryAccessSize::Byte:
|
||||
case MemoryAccessSize::HalfWord:
|
||||
{
|
||||
// zero extend length register
|
||||
if ((offset & u32(0xF0)) < 7 && (offset & u32(0x0F)) == 0x4)
|
||||
value = ZeroExtend32(value);
|
||||
else
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_dma.WriteRegister(offset, value);
|
||||
g_dma.WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1782,10 +1763,9 @@ bool ReadMemoryWord(VirtualMemoryAddress addr, u32* value)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WriteMemoryByte(VirtualMemoryAddress addr, u8 value)
|
||||
bool WriteMemoryByte(VirtualMemoryAddress addr, u32 value)
|
||||
{
|
||||
u32 temp = ZeroExtend32(value);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, temp);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, value);
|
||||
if (cycles < 0)
|
||||
{
|
||||
RaiseException(Exception::DBE);
|
||||
|
@ -1796,13 +1776,12 @@ bool WriteMemoryByte(VirtualMemoryAddress addr, u8 value)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value)
|
||||
bool WriteMemoryHalfWord(VirtualMemoryAddress addr, u32 value)
|
||||
{
|
||||
if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr))
|
||||
return false;
|
||||
|
||||
u32 temp = ZeroExtend32(value);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, temp);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, value);
|
||||
if (cycles < 0)
|
||||
{
|
||||
RaiseException(Exception::DBE);
|
||||
|
@ -1972,10 +1951,9 @@ u64 ReadMemoryWord(u32 address)
|
|||
return ZeroExtend64(temp);
|
||||
}
|
||||
|
||||
u32 WriteMemoryByte(u32 address, u8 value)
|
||||
u32 WriteMemoryByte(u32 address, u32 value)
|
||||
{
|
||||
u32 temp = ZeroExtend32(value);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(address, temp);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(address, value);
|
||||
if (cycles < 0)
|
||||
return static_cast<u32>(Exception::DBE);
|
||||
|
||||
|
@ -1983,7 +1961,7 @@ u32 WriteMemoryByte(u32 address, u8 value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u32 WriteMemoryHalfWord(u32 address, u16 value)
|
||||
u32 WriteMemoryHalfWord(u32 address, u32 value)
|
||||
{
|
||||
if (!Common::IsAlignedPow2(address, 2))
|
||||
{
|
||||
|
@ -1991,8 +1969,7 @@ u32 WriteMemoryHalfWord(u32 address, u16 value)
|
|||
return static_cast<u32>(Exception::AdES);
|
||||
}
|
||||
|
||||
u32 temp = ZeroExtend32(value);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(address, temp);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(address, value);
|
||||
if (cycles < 0)
|
||||
return static_cast<u32>(Exception::DBE);
|
||||
|
||||
|
@ -2037,16 +2014,14 @@ u32 UncheckedReadMemoryWord(u32 address)
|
|||
return temp;
|
||||
}
|
||||
|
||||
void UncheckedWriteMemoryByte(u32 address, u8 value)
|
||||
void UncheckedWriteMemoryByte(u32 address, u32 value)
|
||||
{
|
||||
u32 temp = ZeroExtend32(value);
|
||||
g_state.pending_ticks += DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(address, temp);
|
||||
g_state.pending_ticks += DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(address, value);
|
||||
}
|
||||
|
||||
void UncheckedWriteMemoryHalfWord(u32 address, u16 value)
|
||||
void UncheckedWriteMemoryHalfWord(u32 address, u32 value)
|
||||
{
|
||||
u32 temp = ZeroExtend32(value);
|
||||
g_state.pending_ticks += DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(address, temp);
|
||||
g_state.pending_ticks += DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(address, value);
|
||||
}
|
||||
|
||||
void UncheckedWriteMemoryWord(u32 address, u32 value)
|
||||
|
|
|
@ -1258,11 +1258,11 @@ restart_instruction:
|
|||
if constexpr (debug)
|
||||
Cop0DataBreakpointCheck<MemoryAccessType::Write>(addr);
|
||||
|
||||
const u8 value = Truncate8(ReadReg(inst.i.rt));
|
||||
const u32 value = ReadReg(inst.i.rt);
|
||||
WriteMemoryByte(addr, value);
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::Memory)
|
||||
PGXP::CPU_SB(inst.bits, value, addr);
|
||||
PGXP::CPU_SB(inst.bits, Truncate8(value), addr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1272,11 +1272,11 @@ restart_instruction:
|
|||
if constexpr (debug)
|
||||
Cop0DataBreakpointCheck<MemoryAccessType::Write>(addr);
|
||||
|
||||
const u16 value = Truncate16(ReadReg(inst.i.rt));
|
||||
const u32 value = ReadReg(inst.i.rt);
|
||||
WriteMemoryHalfWord(addr, value);
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::Memory)
|
||||
PGXP::CPU_SH(inst.bits, value, addr);
|
||||
PGXP::CPU_SH(inst.bits, Truncate16(value), addr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -104,8 +104,8 @@ bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value);
|
|||
bool ReadMemoryByte(VirtualMemoryAddress addr, u8* value);
|
||||
bool ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value);
|
||||
bool ReadMemoryWord(VirtualMemoryAddress addr, u32* value);
|
||||
bool WriteMemoryByte(VirtualMemoryAddress addr, u8 value);
|
||||
bool WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value);
|
||||
bool WriteMemoryByte(VirtualMemoryAddress addr, u32 value);
|
||||
bool WriteMemoryHalfWord(VirtualMemoryAddress addr, u32 value);
|
||||
bool WriteMemoryWord(VirtualMemoryAddress addr, u32 value);
|
||||
void* GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size, TickCount* read_ticks);
|
||||
void* GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size);
|
||||
|
|
|
@ -1479,7 +1479,7 @@ bool CodeGenerator::Compile_Store(const CodeBlockInstruction& cbi)
|
|||
value.ViewAsSize(RegSize_8), address);
|
||||
}
|
||||
|
||||
EmitStoreGuestMemory(cbi, address, address_spec, value.ViewAsSize(RegSize_8));
|
||||
EmitStoreGuestMemory(cbi, address, address_spec, RegSize_8, value);
|
||||
|
||||
if (address_spec)
|
||||
{
|
||||
|
@ -1510,7 +1510,7 @@ bool CodeGenerator::Compile_Store(const CodeBlockInstruction& cbi)
|
|||
value.ViewAsSize(RegSize_16), address);
|
||||
}
|
||||
|
||||
EmitStoreGuestMemory(cbi, address, address_spec, value.ViewAsSize(RegSize_16));
|
||||
EmitStoreGuestMemory(cbi, address, address_spec, RegSize_16, value);
|
||||
|
||||
if (address_spec)
|
||||
{
|
||||
|
@ -1538,7 +1538,7 @@ bool CodeGenerator::Compile_Store(const CodeBlockInstruction& cbi)
|
|||
if (g_settings.gpu_pgxp_enable)
|
||||
EmitFunctionCall(nullptr, PGXP::CPU_SW, Value::FromConstantU32(cbi.instruction.bits), value, address);
|
||||
|
||||
EmitStoreGuestMemory(cbi, address, address_spec, value);
|
||||
EmitStoreGuestMemory(cbi, address, address_spec, RegSize_32, value);
|
||||
|
||||
if (address_spec)
|
||||
SpeculativeWriteMemory(*address_spec, value_spec);
|
||||
|
@ -1683,7 +1683,7 @@ bool CodeGenerator::Compile_StoreLeftRight(const CodeBlockInstruction& cbi)
|
|||
|
||||
shift.ReleaseAndClear();
|
||||
|
||||
EmitStoreGuestMemory(cbi, address, address_spec, mem);
|
||||
EmitStoreGuestMemory(cbi, address, address_spec, RegSize_32, mem);
|
||||
if (g_settings.gpu_pgxp_enable)
|
||||
EmitFunctionCall(nullptr, PGXP::CPU_SW, Value::FromConstantU32(cbi.instruction.bits), mem, address);
|
||||
|
||||
|
@ -2741,7 +2741,7 @@ bool CodeGenerator::Compile_cop2(const CodeBlockInstruction& cbi)
|
|||
else
|
||||
{
|
||||
Value value = DoGTERegisterRead(reg);
|
||||
EmitStoreGuestMemory(cbi, address, spec_address, value);
|
||||
EmitStoreGuestMemory(cbi, address, spec_address, RegSize_32, value);
|
||||
|
||||
if (g_settings.gpu_pgxp_enable)
|
||||
EmitFunctionCall(nullptr, PGXP::CPU_SWC2, Value::FromConstantU32(cbi.instruction.bits), value, address);
|
||||
|
|
|
@ -89,10 +89,11 @@ public:
|
|||
void EmitLoadGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size, Value& result,
|
||||
bool in_far_code);
|
||||
void EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const Value& address, const SpeculativeValue& address_spec,
|
||||
const Value& value);
|
||||
void EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address, const Value& value);
|
||||
void EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, const Value& value,
|
||||
bool in_far_code);
|
||||
RegSize size, const Value& value);
|
||||
void EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size,
|
||||
const Value& value);
|
||||
void EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size,
|
||||
const Value& value, bool in_far_code);
|
||||
void EmitUpdateFastmemBase();
|
||||
|
||||
// Unconditional branch to pointer. May allocate a scratch register.
|
||||
|
|
|
@ -1376,7 +1376,7 @@ void CodeGenerator::EmitLoadGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address,
|
||||
void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size,
|
||||
const Value& value)
|
||||
{
|
||||
LoadStoreBackpatchInfo bpi;
|
||||
|
@ -1408,7 +1408,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
m_register_cache.InhibitAllocation();
|
||||
bpi.host_pc = GetCurrentNearCodePointer();
|
||||
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
m_emit->strb(GetHostReg32(actual_value.host_reg), a32::MemOperand(GetHostReg32(RARG1), GetHostReg32(RARG2)));
|
||||
|
@ -1435,7 +1435,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
// generate slowmem fallback
|
||||
bpi.host_slowmem_pc = GetCurrentFarCodePointer();
|
||||
SwitchToFarCode();
|
||||
EmitStoreGuestMemorySlowmem(cbi, address, actual_value, true);
|
||||
EmitStoreGuestMemorySlowmem(cbi, address, size, actual_value, true);
|
||||
|
||||
// restore fastmem base state for the next instruction
|
||||
if (old_load_fastmem_base)
|
||||
|
@ -1451,7 +1451,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
m_block->loadstore_backpatch_info.push_back(bpi);
|
||||
}
|
||||
|
||||
void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address,
|
||||
void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size,
|
||||
const Value& value, bool in_far_code)
|
||||
{
|
||||
AddPendingCycles(true);
|
||||
|
@ -1463,7 +1463,7 @@ void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
Assert(!in_far_code);
|
||||
|
||||
Value result = m_register_cache.AllocateScratch(RegSize_32);
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
EmitFunctionCall(&result, &Thunks::WriteMemoryByte, address, value_in_hr);
|
||||
|
@ -1509,7 +1509,7 @@ void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
}
|
||||
else
|
||||
{
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
EmitFunctionCall(nullptr, &Thunks::UncheckedWriteMemoryByte, address, value_in_hr);
|
||||
|
|
|
@ -1557,7 +1557,7 @@ void CodeGenerator::EmitLoadGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address,
|
||||
void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size,
|
||||
const Value& value)
|
||||
{
|
||||
Value value_in_hr = GetValueInHostRegister(value);
|
||||
|
@ -1584,7 +1584,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
{
|
||||
bpi.host_pc = GetCurrentNearCodePointer();
|
||||
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
m_emit->strb(GetHostReg8(value_in_hr), a64::MemOperand(GetFastmemBasePtrReg(), GetHostReg32(address_reg)));
|
||||
|
@ -1612,7 +1612,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
|
||||
bpi.host_pc = GetCurrentNearCodePointer();
|
||||
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
m_emit->strb(GetHostReg32(value_in_hr.host_reg), a64::MemOperand(GetHostReg64(RARG1), GetHostReg32(RARG2)));
|
||||
|
@ -1639,7 +1639,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
bpi.host_slowmem_pc = GetCurrentFarCodePointer();
|
||||
SwitchToFarCode();
|
||||
|
||||
EmitStoreGuestMemorySlowmem(cbi, address, value_in_hr, true);
|
||||
EmitStoreGuestMemorySlowmem(cbi, address, size, value_in_hr, true);
|
||||
|
||||
// return to the block code
|
||||
EmitBranch(GetCurrentNearCodePointer(), false);
|
||||
|
@ -1650,7 +1650,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
m_block->loadstore_backpatch_info.push_back(bpi);
|
||||
}
|
||||
|
||||
void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address,
|
||||
void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size,
|
||||
const Value& value, bool in_far_code)
|
||||
{
|
||||
AddPendingCycles(true);
|
||||
|
@ -1662,7 +1662,7 @@ void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
Assert(!in_far_code);
|
||||
|
||||
Value result = m_register_cache.AllocateScratch(RegSize_32);
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
EmitFunctionCall(&result, &Thunks::WriteMemoryByte, address, value_in_hr);
|
||||
|
@ -1707,7 +1707,7 @@ void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
}
|
||||
else
|
||||
{
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
EmitFunctionCall(nullptr, &Thunks::UncheckedWriteMemoryByte, address, value_in_hr);
|
||||
|
|
|
@ -114,7 +114,7 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const
|
|||
}
|
||||
|
||||
void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const Value& address,
|
||||
const SpeculativeValue& address_spec, const Value& value)
|
||||
const SpeculativeValue& address_spec, RegSize size, const Value& value)
|
||||
{
|
||||
if (address.IsConstant() && !SpeculativeIsCacheIsolated())
|
||||
{
|
||||
|
@ -149,12 +149,12 @@ void CodeGenerator::EmitStoreGuestMemory(const CodeBlockInstruction& cbi, const
|
|||
|
||||
if (g_settings.IsUsingFastmem() && use_fastmem)
|
||||
{
|
||||
EmitStoreGuestMemoryFastmem(cbi, address, value);
|
||||
EmitStoreGuestMemoryFastmem(cbi, address, size, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_register_cache.FlushCallerSavedGuestRegisters(true, true);
|
||||
EmitStoreGuestMemorySlowmem(cbi, address, value, false);
|
||||
EmitStoreGuestMemorySlowmem(cbi, address, size, value, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2053,7 +2053,7 @@ void CodeGenerator::EmitLoadGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address,
|
||||
void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size,
|
||||
const Value& value)
|
||||
{
|
||||
// fastmem
|
||||
|
@ -2078,7 +2078,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
|
||||
m_register_cache.InhibitAllocation();
|
||||
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
{
|
||||
|
@ -2086,7 +2086,8 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
{
|
||||
if (value.IsConstant())
|
||||
{
|
||||
m_emit->mov(m_emit->byte[GetFastmemBasePtrReg() + actual_address->constant_value], value.constant_value);
|
||||
m_emit->mov(m_emit->byte[GetFastmemBasePtrReg() + actual_address->constant_value],
|
||||
value.constant_value & 0xFFu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2099,7 +2100,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
if (value.IsConstant())
|
||||
{
|
||||
m_emit->mov(m_emit->byte[GetFastmemBasePtrReg() + GetHostReg64(actual_address->host_reg)],
|
||||
value.constant_value);
|
||||
value.constant_value & 0xFFu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2116,7 +2117,8 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
{
|
||||
if (value.IsConstant())
|
||||
{
|
||||
m_emit->mov(m_emit->word[GetFastmemBasePtrReg() + actual_address->constant_value], value.constant_value);
|
||||
m_emit->mov(m_emit->word[GetFastmemBasePtrReg() + actual_address->constant_value],
|
||||
value.constant_value & 0xFFFFu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2129,7 +2131,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
if (value.IsConstant())
|
||||
{
|
||||
m_emit->mov(m_emit->word[GetFastmemBasePtrReg() + GetHostReg64(actual_address->host_reg)],
|
||||
value.constant_value);
|
||||
value.constant_value & 0xFFFFu);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2184,12 +2186,12 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
m_emit->qword[GetFastmemBasePtrReg() + GetHostReg64(RARG1) * 8 + (Bus::FASTMEM_LUT_NUM_PAGES * 8)]);
|
||||
bpi.host_pc = GetCurrentNearCodePointer();
|
||||
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
{
|
||||
if (value.IsConstant())
|
||||
m_emit->mov(m_emit->byte[GetHostReg64(RARG1) + GetHostReg64(RARG2)], value.constant_value);
|
||||
m_emit->mov(m_emit->byte[GetHostReg64(RARG1) + GetHostReg64(RARG2)], value.constant_value & 0xFFu);
|
||||
else
|
||||
m_emit->mov(m_emit->byte[GetHostReg64(RARG1) + GetHostReg64(RARG2)], GetHostReg8(value));
|
||||
}
|
||||
|
@ -2198,7 +2200,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
case RegSize_16:
|
||||
{
|
||||
if (value.IsConstant())
|
||||
m_emit->mov(m_emit->word[GetHostReg64(RARG1) + GetHostReg64(RARG2)], value.constant_value);
|
||||
m_emit->mov(m_emit->word[GetHostReg64(RARG1) + GetHostReg64(RARG2)], value.constant_value & 0xFFFFu);
|
||||
else
|
||||
m_emit->mov(m_emit->word[GetHostReg64(RARG1) + GetHostReg64(RARG2)], GetHostReg16(value));
|
||||
}
|
||||
|
@ -2230,7 +2232,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
bpi.host_slowmem_pc = GetCurrentFarCodePointer();
|
||||
SwitchToFarCode();
|
||||
|
||||
EmitStoreGuestMemorySlowmem(cbi, address, value, true);
|
||||
EmitStoreGuestMemorySlowmem(cbi, address, size, value, true);
|
||||
|
||||
// return to the block code
|
||||
m_emit->jmp(GetCurrentNearCodePointer());
|
||||
|
@ -2241,7 +2243,7 @@ void CodeGenerator::EmitStoreGuestMemoryFastmem(const CodeBlockInstruction& cbi,
|
|||
m_block->loadstore_backpatch_info.push_back(bpi);
|
||||
}
|
||||
|
||||
void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address,
|
||||
void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi, const Value& address, RegSize size,
|
||||
const Value& value, bool in_far_code)
|
||||
{
|
||||
if (g_settings.cpu_recompiler_memory_exceptions)
|
||||
|
@ -2249,7 +2251,7 @@ void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
Assert(!in_far_code);
|
||||
|
||||
Value result = m_register_cache.AllocateScratch(RegSize_32);
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
EmitFunctionCall(&result, &Thunks::WriteMemoryByte, address, value);
|
||||
|
@ -2292,7 +2294,7 @@ void CodeGenerator::EmitStoreGuestMemorySlowmem(const CodeBlockInstruction& cbi,
|
|||
}
|
||||
else
|
||||
{
|
||||
switch (value.size)
|
||||
switch (size)
|
||||
{
|
||||
case RegSize_8:
|
||||
EmitFunctionCall(nullptr, &Thunks::UncheckedWriteMemoryByte, address, value);
|
||||
|
|
|
@ -20,16 +20,16 @@ void CheckAndUpdateICache(u32 pc, u32 line_count);
|
|||
u64 ReadMemoryByte(u32 address);
|
||||
u64 ReadMemoryHalfWord(u32 address);
|
||||
u64 ReadMemoryWord(u32 address);
|
||||
u32 WriteMemoryByte(u32 address, u8 value);
|
||||
u32 WriteMemoryHalfWord(u32 address, u16 value);
|
||||
u32 WriteMemoryByte(u32 address, u32 value);
|
||||
u32 WriteMemoryHalfWord(u32 address, u32 value);
|
||||
u32 WriteMemoryWord(u32 address, u32 value);
|
||||
|
||||
// Unchecked memory access variants. No alignment or bus exceptions.
|
||||
u32 UncheckedReadMemoryByte(u32 address);
|
||||
u32 UncheckedReadMemoryHalfWord(u32 address);
|
||||
u32 UncheckedReadMemoryWord(u32 address);
|
||||
void UncheckedWriteMemoryByte(u32 address, u8 value);
|
||||
void UncheckedWriteMemoryHalfWord(u32 address, u16 value);
|
||||
void UncheckedWriteMemoryByte(u32 address, u32 value);
|
||||
void UncheckedWriteMemoryHalfWord(u32 address, u32 value);
|
||||
void UncheckedWriteMemoryWord(u32 address, u32 value);
|
||||
|
||||
} // namespace Recompiler::Thunks
|
||||
|
|
Loading…
Reference in New Issue