From bd9ac0fdaadd233e778a872c48f7f628b5a68c93 Mon Sep 17 00:00:00 2001 From: merry Date: Fri, 4 Mar 2022 22:05:08 +0000 Subject: [PATCH] T32: Implement B, B.cond, BL, BLX (#3155) * Decoders: Make IsThumb a function of OpCode32 * OpCode32: Fix GetPc * T32: Implement B, B.cond, BL, BLX * rm usings --- ARMeilleure/Decoders/OpCode32.cs | 16 +- ARMeilleure/Decoders/OpCodeT32BImm20.cs | 29 +++ ARMeilleure/Decoders/OpCodeT32BImm24.cs | 35 ++++ ARMeilleure/Decoders/OpCodeTable.cs | 4 + ARMeilleure/Instructions/InstEmitAluHelper.cs | 2 +- ARMeilleure/Instructions/InstEmitFlow32.cs | 4 +- ARMeilleure/Instructions/InstEmitHelper.cs | 5 - Ryujinx.Tests/Cpu/CpuTestT32Flow.cs | 167 ++++++++++++++++++ 8 files changed, 253 insertions(+), 9 deletions(-) create mode 100644 ARMeilleure/Decoders/OpCodeT32BImm20.cs create mode 100644 ARMeilleure/Decoders/OpCodeT32BImm24.cs create mode 100644 Ryujinx.Tests/Cpu/CpuTestT32Flow.cs diff --git a/ARMeilleure/Decoders/OpCode32.cs b/ARMeilleure/Decoders/OpCode32.cs index 0d8ad1fd..92487c6e 100644 --- a/ARMeilleure/Decoders/OpCode32.cs +++ b/ARMeilleure/Decoders/OpCode32.cs @@ -13,11 +13,25 @@ namespace ARMeilleure.Decoders Cond = (Condition)((uint)opCode >> 28); } + public bool IsThumb() + { + return this is OpCodeT16 || this is OpCodeT32; + } + public uint GetPc() { // Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline, // the PC actually points 2 instructions ahead. - return (uint)Address + (uint)OpCodeSizeInBytes * 2; + if (IsThumb()) + { + // PC is ahead by 4 in thumb mode whether or not the current instruction + // is 16 or 32 bit. + return (uint)Address + 4u; + } + else + { + return (uint)Address + 8u; + } } } } \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT32BImm20.cs b/ARMeilleure/Decoders/OpCodeT32BImm20.cs new file mode 100644 index 00000000..8ed4b4b1 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT32BImm20.cs @@ -0,0 +1,29 @@ +using ARMeilleure.Instructions; + +namespace ARMeilleure.Decoders +{ + class OpCodeT32BImm20 : OpCodeT32, IOpCode32BImm + { + public long Immediate { get; } + + public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32BImm20(inst, address, opCode); + + public OpCodeT32BImm20(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + uint pc = GetPc(); + + int imm11 = (opCode >> 0) & 0x7ff; + int j2 = (opCode >> 11) & 1; + int j1 = (opCode >> 13) & 1; + int imm6 = (opCode >> 16) & 0x3f; + int s = (opCode >> 26) & 1; + + int imm32 = imm11 | (imm6 << 11) | (j1 << 17) | (j2 << 18) | (s << 19); + imm32 = (imm32 << 13) >> 12; + + Immediate = pc + imm32; + + Cond = (Condition)((opCode >> 22) & 0xf); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT32BImm24.cs b/ARMeilleure/Decoders/OpCodeT32BImm24.cs new file mode 100644 index 00000000..4381be47 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT32BImm24.cs @@ -0,0 +1,35 @@ +using ARMeilleure.Instructions; + +namespace ARMeilleure.Decoders +{ + class OpCodeT32BImm24 : OpCodeT32, IOpCode32BImm + { + public long Immediate { get; } + + public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32BImm24(inst, address, opCode); + + public OpCodeT32BImm24(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + uint pc = GetPc(); + + if (inst.Name == InstName.Blx) + { + pc &= ~3u; + } + + int imm11 = (opCode >> 0) & 0x7ff; + int j2 = (opCode >> 11) & 1; + int j1 = (opCode >> 13) & 1; + int imm10 = (opCode >> 16) & 0x3ff; + int s = (opCode >> 26) & 1; + + int i1 = j1 ^ s ^ 1; + int i2 = j2 ^ s ^ 1; + + int imm32 = imm11 | (imm10 << 11) | (i2 << 21) | (i1 << 22) | (s << 23); + imm32 = (imm32 << 9) >> 8; + + Immediate = pc + imm32; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index d290e554..ad696104 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -1050,7 +1050,11 @@ namespace ARMeilleure.Decoders SetT32("11101011010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluRsImm.Create); SetT32("11101011000