From: George Wright Date: Wed, 24 Jun 2026 08:10:31 +0000 (-0700) Subject: arm710: Support half-word transfers X-Git-Url: http://git.gwright.org.uk/?a=commitdiff_plain;h=db6208d6f737bab84bb2f05570d092eb59e260c0;p=WindEmu.git arm710: Support half-word transfers --- diff --git a/WindCore/arm710.cpp b/WindCore/arm710.cpp index 31e16dd..1496186 100644 --- a/WindCore/arm710.cpp +++ b/WindCore/arm710.cpp @@ -163,7 +163,9 @@ uint32_t ARM710::executeInstruction(uint32_t i) { cycles += execMultiply(extract(i,21,20), extract(i,19,16), extract(i,15,12), extract(i,11,8), extract(i,3,0)); else if ((i & 0x0F8000F0) == 0x00800090 && isTVersion) cycles += execMultiplyLong(extract(i,22,20), extract(i,19,16), extract(i,15,12), extract(i,11,8), extract(i,3,0)); - else if ((i & 0x0C000000) == 0x00000000) + else if ((i & 0x0E000090) == 0x00000090) { + cycles += execSingleHalfWordDataTransfer(extract(i, 24, 20), extract(i, 19, 16), extract(i, 15, 12), extract(i, 11, 8), extract(i, 6, 5), extract(i, 3, 0)); + } else if ((i & 0x0C000000) == 0x00000000) cycles += execDataProcessing(extract1(i,25), extract(i,24,21), extract1(i,20), extract(i,19,16), extract(i,15,12), extract(i,11,0)); else raiseException(Undefined32, GPRs[15] - 8, 0x04); @@ -533,6 +535,89 @@ uint32_t ARM710::execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t R return 2; } +uint32_t ARM710::execSingleHalfWordDataTransfer(uint32_t PUIWL, uint32_t Rn, uint32_t Rd, uint32_t addrMode1, uint32_t SH, uint32_t addrMode2) +{ + bool load = extract1(PUIWL, 0); + bool writeback = extract1(PUIWL, 1); + bool immediate = extract1(PUIWL, 2); + bool up = extract1(PUIWL, 3); + bool preIndex = extract1(PUIWL, 4); + + uint32_t LSH = ((PUIWL << 2) | SH) & 0x7; + ValueSize valueSize; + bool isSigned; + + switch (LSH) { + case 0x1: + valueSize = V16; + isSigned = false; + break; + case 0x5: + valueSize = V16; + isSigned = false; + break; + case 0x6: + valueSize = V8; + isSigned = true; + break; + case 0x7: + valueSize = V16; + isSigned = true; + break; + default: + // Invalid instruction on ARMv4 as it doesn't support double word ldr/str + return 2; + } + + // calculate the offset + uint32_t calcOffset; + if (!immediate) { + // addrMode1 should be zero (SBZ) + // addrMode2 is Rm + calcOffset = GPRs[addrMode2]; + } else { + // IMMEDIATE + // No rotation or anything here + // addrMode1 is the high 4 bits + // addrMode2 is the low 4 bits + calcOffset = (addrMode1 << 4) | addrMode2; + } + + uint32_t base = GPRs[Rn]; + if (Rn == 15) base -= 4; // prefetch adjustment + uint32_t modifiedBase = up ? (base + calcOffset) : (base - calcOffset); + uint32_t transferAddr = preIndex ? modifiedBase : base; + + bool changeModes = !preIndex && writeback && isPrivileged(); + auto saveMode = currentMode(); + + MMUFault fault; + + if (load) { + if (changeModes) switchMode(User32); + auto readResult = readVirtual(transferAddr, valueSize); + if (changeModes) switchMode(saveMode); + if (readResult.first.has_value()) { + GPRs[Rd] = readResult.first.value(); + if (Rd == 15) prefetchCount = 0; + } + fault = readResult.second; + } else { + uint32_t value = GPRs[Rd]; + if (changeModes) switchMode(User32); + fault = writeVirtual(value, transferAddr, valueSize); + if (changeModes) switchMode(saveMode); + } + + if ((preIndex && writeback) || !preIndex) + GPRs[Rn] = modifiedBase; + + if (fault != NoFault) + reportFault(fault); + + return 2; +} + uint32_t ARM710::execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t registerList) { bool load = extract1(PUSWL, 0); diff --git a/WindCore/arm710.h b/WindCore/arm710.h index 0b0f048..f0fa139 100644 --- a/WindCore/arm710.h +++ b/WindCore/arm710.h @@ -26,7 +26,7 @@ typedef optional MaybeU32; class ARM710 { public: - enum ValueSize { V8 = 0, V32 = 1 }; + enum ValueSize { V8 = 0, V16 = 1, V32 = 2 }; enum MMUFault : uint64_t { // ref: datasheet 9-13 (p111) @@ -298,6 +298,7 @@ private: uint32_t execMultiplyLong(uint32_t UAS, uint32_t RdHi, uint32_t RdLo, uint32_t Rs, uint32_t Rm); uint32_t execSingleDataSwap(bool B, uint32_t Rn, uint32_t Rd, uint32_t Rm); uint32_t execSingleDataTransfer(uint32_t IPUBWL, uint32_t Rn, uint32_t Rd, uint32_t offset); + uint32_t execSingleHalfWordDataTransfer(uint32_t PUIWL, uint32_t Rn, uint32_t Rd, uint32_t addrMode1, uint32_t SH, uint32_t addrMode2); uint32_t execBlockDataTransfer(uint32_t PUSWL, uint32_t Rn, uint32_t registerList); uint32_t execBranch(bool L, uint32_t offset); uint32_t execCP15RegisterTransfer(uint32_t CPOpc, bool L, uint32_t CRn, uint32_t Rd, uint32_t CP, uint32_t CRm);