PowerPC: Pass on full 32-bit register contents for 8/16-bit writes

This commit is contained in:
JosJuice 2021-07-26 14:59:20 +02:00
parent c56526d5f8
commit ecbce0a204
3 changed files with 105 additions and 93 deletions

View File

@ -323,14 +323,14 @@ void Interpreter::lwzu(UGeckoInstruction inst)
void Interpreter::stb(UGeckoInstruction inst) void Interpreter::stb(UGeckoInstruction inst)
{ {
PowerPC::Write_U8((u8)rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst)); PowerPC::Write_U8(rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst));
} }
void Interpreter::stbu(UGeckoInstruction inst) void Interpreter::stbu(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
PowerPC::Write_U8((u8)rGPR[inst.RS], address); PowerPC::Write_U8(rGPR[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; rGPR[inst.RA] = address;
@ -399,14 +399,14 @@ void Interpreter::stfsu(UGeckoInstruction inst)
void Interpreter::sth(UGeckoInstruction inst) void Interpreter::sth(UGeckoInstruction inst)
{ {
PowerPC::Write_U16((u16)rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst)); PowerPC::Write_U16(rGPR[inst.RS], Helper_Get_EA(PowerPC::ppcState, inst));
} }
void Interpreter::sthu(UGeckoInstruction inst) void Interpreter::sthu(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_U(PowerPC::ppcState, inst);
PowerPC::Write_U16((u16)rGPR[inst.RS], address); PowerPC::Write_U16(rGPR[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; rGPR[inst.RA] = address;
@ -731,7 +731,7 @@ void Interpreter::stbux(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
PowerPC::Write_U8((u8)rGPR[inst.RS], address); PowerPC::Write_U8(rGPR[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; rGPR[inst.RA] = address;
@ -740,7 +740,7 @@ void Interpreter::stbux(UGeckoInstruction inst)
void Interpreter::stbx(UGeckoInstruction inst) void Interpreter::stbx(UGeckoInstruction inst)
{ {
PowerPC::Write_U8((u8)rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst)); PowerPC::Write_U8(rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst));
} }
void Interpreter::stfdux(UGeckoInstruction inst) void Interpreter::stfdux(UGeckoInstruction inst)
@ -819,14 +819,14 @@ void Interpreter::stfsx(UGeckoInstruction inst)
void Interpreter::sthbrx(UGeckoInstruction inst) void Interpreter::sthbrx(UGeckoInstruction inst)
{ {
PowerPC::Write_U16(Common::swap16((u16)rGPR[inst.RS]), Helper_Get_EA_X(PowerPC::ppcState, inst)); PowerPC::Write_U16_Swap(rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst));
} }
void Interpreter::sthux(UGeckoInstruction inst) void Interpreter::sthux(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_UX(PowerPC::ppcState, inst);
PowerPC::Write_U16((u16)rGPR[inst.RS], address); PowerPC::Write_U16(rGPR[inst.RS], address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{ {
rGPR[inst.RA] = address; rGPR[inst.RA] = address;
@ -835,7 +835,7 @@ void Interpreter::sthux(UGeckoInstruction inst)
void Interpreter::sthx(UGeckoInstruction inst) void Interpreter::sthx(UGeckoInstruction inst)
{ {
PowerPC::Write_U16((u16)rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst)); PowerPC::Write_U16(rGPR[inst.RS], Helper_Get_EA_X(PowerPC::ppcState, inst));
} }
// lswi - bizarro string instruction // lswi - bizarro string instruction
@ -968,7 +968,7 @@ void Interpreter::stwbrx(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst); const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
PowerPC::Write_U32(Common::swap32(rGPR[inst.RS]), address); PowerPC::Write_U32_Swap(rGPR[inst.RS], address);
} }
// The following two instructions are for SMP communications. On a single // The following two instructions are for SMP communications. On a single

View File

@ -8,6 +8,7 @@
#include <cstring> #include <cstring>
#include <string> #include <string>
#include "Common/Assert.h"
#include "Common/BitUtils.h" #include "Common/BitUtils.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -256,9 +257,26 @@ static T ReadFromHardware(u32 em_address)
return 0; return 0;
} }
template <XCheckTLBFlag flag, typename T, bool never_translate = false> template <XCheckTLBFlag flag, bool never_translate = false>
static void WriteToHardware(u32 em_address, const T data) static void WriteToHardware(u32 em_address, const u32 data, const u32 size)
{ {
DEBUG_ASSERT(size <= 4);
const u32 em_address_start_page = em_address & ~(HW_PAGE_SIZE - 1);
const u32 em_address_end_page = (em_address + size - 1) & ~(HW_PAGE_SIZE - 1);
if (em_address_start_page != em_address_end_page)
{
// The write crosses a page boundary. Break it up into two writes.
// TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions.
// Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned!
const u32 first_half_size = em_address_end_page - em_address;
const u32 second_half_size = size - first_half_size;
WriteToHardware<flag, never_translate>(
em_address, Common::RotateRight(data, second_half_size * 8), first_half_size);
WriteToHardware<flag, never_translate>(em_address_end_page, data, second_half_size);
return;
}
if (!never_translate && MSR.DR) if (!never_translate && MSR.DR)
{ {
auto translated_addr = TranslateAddress<flag>(em_address); auto translated_addr = TranslateAddress<flag>(em_address);
@ -268,51 +286,24 @@ static void WriteToHardware(u32 em_address, const T data)
GenerateDSIException(em_address, true); GenerateDSIException(em_address, true);
return; return;
} }
if ((em_address & (sizeof(T) - 1)) &&
(em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T))
{
// This could be unaligned down to the byte level... hopefully this is rare, so doing it this
// way isn't too terrible.
// TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions.
// Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned!
u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1);
auto addr_next_page = TranslateAddress<flag>(em_address_next_page);
if (!addr_next_page.Success())
{
if (flag == XCheckTLBFlag::Write)
GenerateDSIException(em_address_next_page, true);
return;
}
T val = bswap(data);
u32 addr_translated = translated_addr.address;
for (size_t i = 0; i < sizeof(T); i++, addr_translated++)
{
if (em_address + i == em_address_next_page)
addr_translated = addr_next_page.address;
WriteToHardware<flag, u8, true>(addr_translated, static_cast<u8>(val >> (i * 8)));
}
return;
}
em_address = translated_addr.address; em_address = translated_addr.address;
} }
// TODO: Make sure these are safe for unaligned addresses. const u32 swapped_data = Common::swap32(Common::RotateRight(data, size * 8));
if (Memory::m_pRAM && (em_address & 0xF8000000) == 0x00000000) if (Memory::m_pRAM && (em_address & 0xF8000000) == 0x00000000)
{ {
// Handle RAM; the masking intentionally discards bits (essentially creating // Handle RAM; the masking intentionally discards bits (essentially creating
// mirrors of memory). // mirrors of memory).
// TODO: Only the first GetRamSizeReal() is supposed to be backed by actual memory. // TODO: Only the first GetRamSizeReal() is supposed to be backed by actual memory.
const T swapped_data = bswap(data); std::memcpy(&Memory::m_pRAM[em_address & Memory::GetRamMask()], &swapped_data, size);
std::memcpy(&Memory::m_pRAM[em_address & Memory::GetRamMask()], &swapped_data, sizeof(T));
return; return;
} }
if (Memory::m_pEXRAM && (em_address >> 28) == 0x1 && if (Memory::m_pEXRAM && (em_address >> 28) == 0x1 &&
(em_address & 0x0FFFFFFF) < Memory::GetExRamSizeReal()) (em_address & 0x0FFFFFFF) < Memory::GetExRamSizeReal())
{ {
const T swapped_data = bswap(data); std::memcpy(&Memory::m_pEXRAM[em_address & 0x0FFFFFFF], &swapped_data, size);
std::memcpy(&Memory::m_pEXRAM[em_address & 0x0FFFFFFF], &swapped_data, sizeof(T));
return; return;
} }
@ -320,8 +311,7 @@ static void WriteToHardware(u32 em_address, const T data)
if (Memory::m_pL1Cache && (em_address >> 28 == 0xE) && if (Memory::m_pL1Cache && (em_address >> 28 == 0xE) &&
(em_address < (0xE0000000 + Memory::GetL1CacheSize()))) (em_address < (0xE0000000 + Memory::GetL1CacheSize())))
{ {
const T swapped_data = bswap(data); std::memcpy(&Memory::m_pL1Cache[em_address & 0x0FFFFFFF], &swapped_data, size);
std::memcpy(&Memory::m_pL1Cache[em_address & 0x0FFFFFFF], &swapped_data, sizeof(T));
return; return;
} }
@ -330,9 +320,7 @@ static void WriteToHardware(u32 em_address, const T data)
// [0x7E000000, 0x80000000). // [0x7E000000, 0x80000000).
if (Memory::m_pFakeVMEM && ((em_address & 0xFE000000) == 0x7E000000)) if (Memory::m_pFakeVMEM && ((em_address & 0xFE000000) == 0x7E000000))
{ {
const T swapped_data = bswap(data); std::memcpy(&Memory::m_pFakeVMEM[em_address & Memory::GetFakeVMemMask()], &swapped_data, size);
std::memcpy(&Memory::m_pFakeVMEM[em_address & Memory::GetFakeVMemMask()], &swapped_data,
sizeof(T));
return; return;
} }
@ -341,19 +329,24 @@ static void WriteToHardware(u32 em_address, const T data)
// Pac-Man World 3 in particular is affected by this. // Pac-Man World 3 in particular is affected by this.
if (flag == XCheckTLBFlag::Write && (em_address & 0xFFFFF000) == 0x0C008000) if (flag == XCheckTLBFlag::Write && (em_address & 0xFFFFF000) == 0x0C008000)
{ {
switch (sizeof(T)) switch (size)
{ {
case 1: case 1:
GPFifo::Write8((u8)data); GPFifo::Write8(static_cast<u8>(data));
return; return;
case 2: case 2:
GPFifo::Write16((u16)data); GPFifo::Write16(static_cast<u16>(data));
return; return;
case 4: case 4:
GPFifo::Write32((u32)data); GPFifo::Write32(data);
return; return;
case 8: default:
GPFifo::Write64((u64)data); // Some kind of misaligned write. TODO: Does this match how the actual hardware handles it?
for (size_t i = size * 8; i > 0;)
{
i -= 8;
GPFifo::Write8(static_cast<u8>(data >> i));
}
return; return;
} }
} }
@ -362,12 +355,28 @@ static void WriteToHardware(u32 em_address, const T data)
{ {
if (em_address < 0x0c000000) if (em_address < 0x0c000000)
{ {
EFB_Write((u32)data, em_address); EFB_Write(data, em_address);
return; return;
} }
else
switch (size)
{ {
Memory::mmio_mapping->Write(em_address, data); case 1:
Memory::mmio_mapping->Write<u8>(em_address, static_cast<u8>(data));
return;
case 2:
Memory::mmio_mapping->Write<u16>(em_address, static_cast<u16>(data));
return;
case 4:
Memory::mmio_mapping->Write<u32>(em_address, data);
return;
default:
// Some kind of misaligned write. TODO: Does this match how the actual hardware handles it?
for (size_t i = size * 8; i > 0; em_address++)
{
i -= 8;
Memory::mmio_mapping->Write<u8>(em_address, static_cast<u8>(data >> i));
}
return; return;
} }
} }
@ -608,42 +617,40 @@ u32 Read_U16_ZX(const u32 address)
return Read_U16(address); return Read_U16(address);
} }
void Write_U8(const u8 var, const u32 address) void Write_U8(const u32 var, const u32 address)
{ {
Memcheck(address, var, true, 1); Memcheck(address, var, true, 1);
WriteToHardware<XCheckTLBFlag::Write, u8>(address, var); WriteToHardware<XCheckTLBFlag::Write>(address, var, 1);
} }
void Write_U16(const u16 var, const u32 address) void Write_U16(const u32 var, const u32 address)
{ {
Memcheck(address, var, true, 2); Memcheck(address, var, true, 2);
WriteToHardware<XCheckTLBFlag::Write, u16>(address, var); WriteToHardware<XCheckTLBFlag::Write>(address, var, 2);
} }
void Write_U16_Swap(const u16 var, const u32 address) void Write_U16_Swap(const u32 var, const u32 address)
{ {
Memcheck(address, var, true, 2); Write_U16((var & 0xFFFF0000) | Common::swap16(static_cast<u16>(var)), address);
Write_U16(Common::swap16(var), address);
} }
void Write_U32(const u32 var, const u32 address) void Write_U32(const u32 var, const u32 address)
{ {
Memcheck(address, var, true, 4); Memcheck(address, var, true, 4);
WriteToHardware<XCheckTLBFlag::Write, u32>(address, var); WriteToHardware<XCheckTLBFlag::Write>(address, var, 4);
} }
void Write_U32_Swap(const u32 var, const u32 address) void Write_U32_Swap(const u32 var, const u32 address)
{ {
Memcheck(address, var, true, 4);
Write_U32(Common::swap32(var), address); Write_U32(Common::swap32(var), address);
} }
void Write_U64(const u64 var, const u32 address) void Write_U64(const u64 var, const u32 address)
{ {
Memcheck(address, (u32)var, true, 8); Memcheck(address, (u32)var, true, 8);
WriteToHardware<XCheckTLBFlag::Write, u64>(address, var); WriteToHardware<XCheckTLBFlag::Write>(address, static_cast<u32>(var >> 32), 4);
WriteToHardware<XCheckTLBFlag::Write>(address + sizeof(u32), static_cast<u32>(var), 4);
} }
void Write_U64_Swap(const u64 var, const u32 address) void Write_U64_Swap(const u64 var, const u32 address)
{ {
Memcheck(address, (u32)var, true, 8);
Write_U64(Common::swap64(var), address); Write_U64(Common::swap64(var), address);
} }
@ -688,24 +695,25 @@ double HostRead_F64(const u32 address)
return Common::BitCast<double>(integral); return Common::BitCast<double>(integral);
} }
void HostWrite_U8(const u8 var, const u32 address) void HostWrite_U8(const u32 var, const u32 address)
{ {
WriteToHardware<XCheckTLBFlag::NoException, u8>(address, var); WriteToHardware<XCheckTLBFlag::NoException>(address, var, 1);
} }
void HostWrite_U16(const u16 var, const u32 address) void HostWrite_U16(const u32 var, const u32 address)
{ {
WriteToHardware<XCheckTLBFlag::NoException, u16>(address, var); WriteToHardware<XCheckTLBFlag::NoException>(address, var, 2);
} }
void HostWrite_U32(const u32 var, const u32 address) void HostWrite_U32(const u32 var, const u32 address)
{ {
WriteToHardware<XCheckTLBFlag::NoException, u32>(address, var); WriteToHardware<XCheckTLBFlag::NoException>(address, var, 4);
} }
void HostWrite_U64(const u64 var, const u32 address) void HostWrite_U64(const u64 var, const u32 address)
{ {
WriteToHardware<XCheckTLBFlag::NoException, u64>(address, var); WriteToHardware<XCheckTLBFlag::NoException>(address, static_cast<u32>(var >> 32), 4);
WriteToHardware<XCheckTLBFlag::NoException>(address + sizeof(u32), static_cast<u32>(var), 4);
} }
void HostWrite_F32(const float var, const u32 address) void HostWrite_F32(const float var, const u32 address)
@ -722,8 +730,8 @@ void HostWrite_F64(const double var, const u32 address)
HostWrite_U64(integral, address); HostWrite_U64(integral, address);
} }
template <typename T> static TryWriteResult HostTryWriteUX(const u32 var, const u32 address, const u32 size,
static TryWriteResult HostTryWriteUX(const T var, const u32 address, RequestedAddressSpace space) RequestedAddressSpace space)
{ {
if (!HostIsRAMAddress(address, space)) if (!HostIsRAMAddress(address, space))
return TryWriteResult(); return TryWriteResult();
@ -731,15 +739,15 @@ static TryWriteResult HostTryWriteUX(const T var, const u32 address, RequestedAd
switch (space) switch (space)
{ {
case RequestedAddressSpace::Effective: case RequestedAddressSpace::Effective:
WriteToHardware<XCheckTLBFlag::NoException, T>(address, var); WriteToHardware<XCheckTLBFlag::NoException>(address, var, size);
return TryWriteResult(!!MSR.DR); return TryWriteResult(!!MSR.DR);
case RequestedAddressSpace::Physical: case RequestedAddressSpace::Physical:
WriteToHardware<XCheckTLBFlag::NoException, T, true>(address, var); WriteToHardware<XCheckTLBFlag::NoException, true>(address, var, size);
return TryWriteResult(false); return TryWriteResult(false);
case RequestedAddressSpace::Virtual: case RequestedAddressSpace::Virtual:
if (!MSR.DR) if (!MSR.DR)
return TryWriteResult(); return TryWriteResult();
WriteToHardware<XCheckTLBFlag::NoException, T>(address, var); WriteToHardware<XCheckTLBFlag::NoException>(address, var, size);
return TryWriteResult(true); return TryWriteResult(true);
} }
@ -747,24 +755,28 @@ static TryWriteResult HostTryWriteUX(const T var, const u32 address, RequestedAd
return TryWriteResult(); return TryWriteResult();
} }
TryWriteResult HostTryWriteU8(const u8 var, const u32 address, RequestedAddressSpace space) TryWriteResult HostTryWriteU8(const u32 var, const u32 address, RequestedAddressSpace space)
{ {
return HostTryWriteUX<u8>(var, address, space); return HostTryWriteUX(var, address, 1, space);
} }
TryWriteResult HostTryWriteU16(const u16 var, const u32 address, RequestedAddressSpace space) TryWriteResult HostTryWriteU16(const u32 var, const u32 address, RequestedAddressSpace space)
{ {
return HostTryWriteUX<u16>(var, address, space); return HostTryWriteUX(var, address, 2, space);
} }
TryWriteResult HostTryWriteU32(const u32 var, const u32 address, RequestedAddressSpace space) TryWriteResult HostTryWriteU32(const u32 var, const u32 address, RequestedAddressSpace space)
{ {
return HostTryWriteUX<u32>(var, address, space); return HostTryWriteUX(var, address, 4, space);
} }
TryWriteResult HostTryWriteU64(const u64 var, const u32 address, RequestedAddressSpace space) TryWriteResult HostTryWriteU64(const u64 var, const u32 address, RequestedAddressSpace space)
{ {
return HostTryWriteUX<u64>(var, address, space); const TryWriteResult result = HostTryWriteUX(static_cast<u32>(var >> 32), address, 4, space);
if (!result)
return result;
return HostTryWriteUX(static_cast<u32>(var), address + 4, 4, space);
} }
TryWriteResult HostTryWriteF32(const float var, const u32 address, RequestedAddressSpace space) TryWriteResult HostTryWriteF32(const float var, const u32 address, RequestedAddressSpace space)
@ -1001,8 +1013,8 @@ void ClearCacheLine(u32 address)
// TODO: This isn't precisely correct for non-RAM regions, but the difference // TODO: This isn't precisely correct for non-RAM regions, but the difference
// is unlikely to matter. // is unlikely to matter.
for (u32 i = 0; i < 32; i += 8) for (u32 i = 0; i < 32; i += 4)
WriteToHardware<XCheckTLBFlag::Write, u64, true>(address + i, 0); WriteToHardware<XCheckTLBFlag::Write, true>(address + i, 0, 4);
} }
u32 IsOptimizableMMIOAccess(u32 address, u32 access_size) u32 IsOptimizableMMIOAccess(u32 address, u32 access_size)

View File

@ -86,8 +86,8 @@ HostTryReadString(u32 address, size_t size = 0,
// Writes a value to emulated memory using the currently active MMU settings. // Writes a value to emulated memory using the currently active MMU settings.
// If the write fails (eg. address does not correspond to a mapped address in the current address // If the write fails (eg. address does not correspond to a mapped address in the current address
// space), a PanicAlert will be shown to the user. // space), a PanicAlert will be shown to the user.
void HostWrite_U8(u8 var, u32 address); void HostWrite_U8(u32 var, u32 address);
void HostWrite_U16(u16 var, u32 address); void HostWrite_U16(u32 var, u32 address);
void HostWrite_U32(u32 var, u32 address); void HostWrite_U32(u32 var, u32 address);
void HostWrite_U64(u64 var, u32 address); void HostWrite_U64(u64 var, u32 address);
void HostWrite_F32(float var, u32 address); void HostWrite_F32(float var, u32 address);
@ -111,9 +111,9 @@ struct TryWriteResult
// If the write succeeds, the returned TryWriteResult contains information on whether the given // If the write succeeds, the returned TryWriteResult contains information on whether the given
// address had to be translated or not. Unlike the HostWrite functions, this does not raise a // address had to be translated or not. Unlike the HostWrite functions, this does not raise a
// user-visible alert on failure. // user-visible alert on failure.
TryWriteResult HostTryWriteU8(u8 var, const u32 address, TryWriteResult HostTryWriteU8(u32 var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
TryWriteResult HostTryWriteU16(u16 var, const u32 address, TryWriteResult HostTryWriteU16(u32 var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
TryWriteResult HostTryWriteU32(u32 var, const u32 address, TryWriteResult HostTryWriteU32(u32 var, const u32 address,
RequestedAddressSpace space = RequestedAddressSpace::Effective); RequestedAddressSpace space = RequestedAddressSpace::Effective);
@ -158,12 +158,12 @@ double Read_F64(u32 address);
u32 Read_U8_ZX(u32 address); u32 Read_U8_ZX(u32 address);
u32 Read_U16_ZX(u32 address); u32 Read_U16_ZX(u32 address);
void Write_U8(u8 var, u32 address); void Write_U8(u32 var, u32 address);
void Write_U16(u16 var, u32 address); void Write_U16(u32 var, u32 address);
void Write_U32(u32 var, u32 address); void Write_U32(u32 var, u32 address);
void Write_U64(u64 var, u32 address); void Write_U64(u64 var, u32 address);
void Write_U16_Swap(u16 var, u32 address); void Write_U16_Swap(u32 var, u32 address);
void Write_U32_Swap(u32 var, u32 address); void Write_U32_Swap(u32 var, u32 address);
void Write_U64_Swap(u64 var, u32 address); void Write_U64_Swap(u64 var, u32 address);