Compare commits

..

5 Commits

Author SHA1 Message Date
c017c77365 Change ServiceNv map creation logs to the Debug level (#3058) 2022-02-18 00:41:21 +01:00
98e05ee4b7 ARMeilleure: Thumb support (All T16 instructions) (#3105)
* Decoders: Add InITBlock argument

* OpCodeTable: Minor cleanup

* OpCodeTable: Remove existing thumb instruction implementations

* OpCodeTable: Prepare for thumb instructions

* OpCodeTables: Improve thumb fast lookup

* Tests: Prepare for thumb tests

* T16: Implement BX

* T16: Implement LSL/LSR/ASR (imm)

* T16: Implement ADDS, SUBS (reg)

* T16: Implement ADDS, SUBS (3-bit immediate)

* T16: Implement MOVS, CMP, ADDS, SUBS (8-bit immediate)

* T16: Implement ANDS, EORS, LSLS, LSRS, ASRS, ADCS, SBCS, RORS, TST, NEGS, CMP, CMN, ORRS, MULS, BICS, MVNS (low registers)

* T16: Implement ADD, CMP, MOV (high reg)

* T16: Implement BLX (reg)

* T16: Implement LDR (literal)

* T16: Implement {LDR,STR}{,H,B,SB,SH} (register)

* T16: Implement {LDR,STR}{,B,H} (immediate)

* T16: Implement LDR/STR (SP)

* T16: Implement ADR

* T16: Implement Add to SP (immediate)

* T16: Implement ADD/SUB (SP)

* T16: Implement SXTH, SXTB, UXTH, UTXB

* T16: Implement CBZ, CBNZ

* T16: Implement PUSH, POP

* T16: Implement REV, REV16, REVSH

* T16: Implement NOP

* T16: Implement LDM, STM

* T16: Implement SVC

* T16: Implement B (conditional)

* T16: Implement B (unconditional)

* T16: Implement IT

* fixup! T16: Implement ADD/SUB (SP)

* fixup! T16: Implement Add to SP (immediate)

* fixup! T16: Implement IT

* CpuTestThumb: Add randomized tests

* Remove inITBlock argument

* Address nits

* Use index to handle IfThenBlockState

* Reduce line noise

* fixup

* nit
2022-02-17 19:39:45 -03:00
868919e101 misc: Update GtkSharp.Dependencies and speed up initial Windows build (#3128)
Update GtkSharp.Dependencies to fix between menu flickering and enable
the SkipInstallGtk in csproj to avoid downloading unused GTK3 install
locally.
2022-02-17 22:10:48 +01:00
9ca040c0ff Use ReadOnlySpan<byte> compiler optimization for static data (#3130) 2022-02-17 21:38:50 +01:00
7e9011673b Use a basic cubic interpolation for the audren upsampler (#3129)
Before, it was selecting nearest neighbour, which sounded terrible. This is likely temporary til the upsampling algorithm used by the switch is reversed.

Fixes bad audio in Skyward Sword HD.
2022-02-17 20:19:29 +01:00
68 changed files with 1908 additions and 129 deletions

View File

@ -195,12 +195,13 @@ namespace ARMeilleure.Decoders
ulong limitAddress) ulong limitAddress)
{ {
ulong address = block.Address; ulong address = block.Address;
int itBlockSize = 0;
OpCode opCode; OpCode opCode;
do do
{ {
if (address >= limitAddress) if (address >= limitAddress && itBlockSize == 0)
{ {
break; break;
} }
@ -210,6 +211,15 @@ namespace ARMeilleure.Decoders
block.OpCodes.Add(opCode); block.OpCodes.Add(opCode);
address += (ulong)opCode.OpCodeSizeInBytes; address += (ulong)opCode.OpCodeSizeInBytes;
if (opCode is OpCodeT16IfThen it)
{
itBlockSize = it.IfThenBlockSize;
}
else if (itBlockSize > 0)
{
itBlockSize--;
}
} }
while (!(IsBranch(opCode) || IsException(opCode))); while (!(IsBranch(opCode) || IsException(opCode)));
@ -345,7 +355,14 @@ namespace ARMeilleure.Decoders
} }
else else
{ {
return new OpCode(inst, address, opCode); if (mode == ExecutionMode.Aarch32Thumb)
{
return new OpCodeT16(inst, address, opCode);
}
else
{
return new OpCode(inst, address, opCode);
}
} }
} }
} }

View File

@ -0,0 +1,9 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Adr
{
int Rd { get; }
int Immediate { get; }
}
}

View File

@ -5,6 +5,6 @@ namespace ARMeilleure.Decoders
int Rd { get; } int Rd { get; }
int Rn { get; } int Rn { get; }
bool SetFlags { get; } bool? SetFlags { get; }
} }
} }

View File

@ -0,0 +1,9 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluImm : IOpCode32Alu
{
int Immediate { get; }
bool IsRotated { get; }
}
}

View File

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluRsImm : IOpCode32Alu
{
int Rm { get; }
int Immediate { get; }
ShiftType ShiftType { get; }
}
}

View File

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluRsReg : IOpCode32Alu
{
int Rm { get; }
int Rs { get; }
ShiftType ShiftType { get; }
}
}

View File

@ -0,0 +1,6 @@
namespace ARMeilleure.Decoders;
interface IOpCode32Exception
{
int Id { get; }
}

View File

@ -7,5 +7,9 @@ namespace ARMeilleure.Decoders
bool WBack { get; } bool WBack { get; }
bool IsLoad { get; } bool IsLoad { get; }
bool Index { get; }
bool Add { get; }
int Immediate { get; }
} }
} }

View File

@ -9,5 +9,7 @@ namespace ARMeilleure.Decoders
int PostOffset { get; } int PostOffset { get; }
bool IsLoad { get; } bool IsLoad { get; }
int Offset { get; }
} }
} }

View File

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32MemReg : IOpCode32Mem
{
int Rm { get; }
}
}

View File

@ -18,10 +18,9 @@ namespace ARMeilleure.Decoders
public OpCode(InstDescriptor inst, ulong address, int opCode) public OpCode(InstDescriptor inst, ulong address, int opCode)
{ {
Address = address;
RawOpCode = opCode;
Instruction = inst; Instruction = inst;
Address = address;
RawOpCode = opCode;
RegisterSize = RegisterSize.Int64; RegisterSize = RegisterSize.Int64;
} }

View File

@ -5,7 +5,7 @@ namespace ARMeilleure.Decoders
public int Rd { get; } public int Rd { get; }
public int Rn { get; } public int Rn { get; }
public bool SetFlags { get; } public bool? SetFlags { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Alu(inst, address, opCode); public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Alu(inst, address, opCode);

View File

@ -2,7 +2,7 @@ using ARMeilleure.Common;
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
class OpCode32AluImm : OpCode32Alu class OpCode32AluImm : OpCode32Alu, IOpCode32AluImm
{ {
public int Immediate { get; } public int Immediate { get; }

View File

@ -10,7 +10,7 @@
public bool NHigh { get; } public bool NHigh { get; }
public bool MHigh { get; } public bool MHigh { get; }
public bool R { get; } public bool R { get; }
public bool SetFlags { get; } public bool? SetFlags { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluMla(inst, address, opCode); public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluMla(inst, address, opCode);

View File

@ -1,6 +1,6 @@
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
class OpCode32AluRsImm : OpCode32Alu class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
{ {
public int Rm { get; } public int Rm { get; }
public int Immediate { get; } public int Immediate { get; }

View File

@ -1,6 +1,6 @@
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
class OpCode32AluRsReg : OpCode32Alu class OpCode32AluRsReg : OpCode32Alu, IOpCode32AluRsReg
{ {
public int Rm { get; } public int Rm { get; }
public int Rs { get; } public int Rs { get; }

View File

@ -10,7 +10,7 @@
public bool NHigh { get; } public bool NHigh { get; }
public bool MHigh { get; } public bool MHigh { get; }
public bool SetFlags { get; } public bool? SetFlags { get; }
public DataOp DataOp { get; } public DataOp DataOp { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode); public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode);

View File

@ -1,6 +1,6 @@
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
class OpCode32Exception : OpCode32 class OpCode32Exception : OpCode32, IOpCode32Exception
{ {
public int Id { get; } public int Id { get; }

View File

@ -1,6 +1,6 @@
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
class OpCode32MemReg : OpCode32Mem class OpCode32MemReg : OpCode32Mem, IOpCode32MemReg
{ {
public int Rm { get; } public int Rm { get; }

View File

@ -0,0 +1,24 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16AddSubImm3: OpCodeT16, IOpCode32AluImm
{
public int Rd { get; }
public int Rn { get; }
public bool? SetFlags => null;
public int Immediate { get; }
public bool IsRotated { get; }
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubImm3(inst, address, opCode);
public OpCodeT16AddSubImm3(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 0) & 0x7;
Rn = (opCode >> 3) & 0x7;
Immediate = (opCode >> 6) & 0x7;
IsRotated = false;
}
}
}

View File

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16AddSubReg : OpCodeT16, IOpCode32AluReg
{
public int Rm { get; }
public int Rd { get; }
public int Rn { get; }
public bool? SetFlags => null;
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubReg(inst, address, opCode);
public OpCodeT16AddSubReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 0) & 0x7;
Rn = (opCode >> 3) & 0x7;
Rm = (opCode >> 6) & 0x7;
}
}
}

View File

@ -0,0 +1,23 @@
using ARMeilleure.State;
namespace ARMeilleure.Decoders
{
class OpCodeT16AddSubSp : OpCodeT16, IOpCode32AluImm
{
public int Rd => RegisterAlias.Aarch32Sp;
public int Rn => RegisterAlias.Aarch32Sp;
public bool? SetFlags => false;
public int Immediate { get; }
public bool IsRotated => false;
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubSp(inst, address, opCode);
public OpCodeT16AddSubSp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Immediate = ((opCode >> 0) & 0x7f) << 2;
}
}
}

View File

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16Adr : OpCodeT16, IOpCode32Adr
{
public int Rd { get; }
public bool Add => true;
public int Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode);
public OpCodeT16Adr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 8) & 7;
int imm = (opCode & 0xff) << 2;
Immediate = (int)(GetPc() & 0xfffffffc) + imm;
}
}
}

View File

@ -1,22 +1,24 @@
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
class OpCodeT16AluImm8 : OpCodeT16, IOpCode32Alu class OpCodeT16AluImm8 : OpCodeT16, IOpCode32AluImm
{ {
private int _rdn; public int Rd { get; }
public int Rn { get; }
public int Rd => _rdn; public bool? SetFlags => null;
public int Rn => _rdn;
public bool SetFlags => false;
public int Immediate { get; } public int Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImm8(inst, address, opCode); public bool IsRotated { get; }
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImm8(inst, address, opCode);
public OpCodeT16AluImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) public OpCodeT16AluImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{ {
Rd = (opCode >> 8) & 0x7;
Rn = (opCode >> 8) & 0x7;
Immediate = (opCode >> 0) & 0xff; Immediate = (opCode >> 0) & 0xff;
_rdn = (opCode >> 8) & 0x7; IsRotated = false;
} }
} }
} }

View File

@ -0,0 +1,24 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16AluImmZero : OpCodeT16, IOpCode32AluImm
{
public int Rd { get; }
public int Rn { get; }
public bool? SetFlags => null;
public int Immediate { get; }
public bool IsRotated { get; }
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImmZero(inst, address, opCode);
public OpCodeT16AluImmZero(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 0) & 0x7;
Rn = (opCode >> 3) & 0x7;
Immediate = 0;
IsRotated = false;
}
}
}

View File

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16AluRegHigh : OpCodeT16, IOpCode32AluReg
{
public int Rm { get; }
public int Rd { get; }
public int Rn { get; }
public bool? SetFlags => false;
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluRegHigh(inst, address, opCode);
public OpCodeT16AluRegHigh(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = ((opCode >> 0) & 0x7) | ((opCode >> 4) & 0x8);
Rn = ((opCode >> 0) & 0x7) | ((opCode >> 4) & 0x8);
Rm = (opCode >> 3) & 0xf;
}
}
}

View File

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16AluRegLow : OpCodeT16, IOpCode32AluReg
{
public int Rm { get; }
public int Rd { get; }
public int Rn { get; }
public bool? SetFlags => null;
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluRegLow(inst, address, opCode);
public OpCodeT16AluRegLow(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 0) & 0x7;
Rn = (opCode >> 0) & 0x7;
Rm = (opCode >> 3) & 0x7;
}
}
}

View File

@ -0,0 +1,22 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16AluUx : OpCodeT16, IOpCode32AluUx
{
public int Rm { get; }
public int Rd { get; }
public int Rn { get; }
public bool? SetFlags => false;
public int RotateBits => 0;
public bool Add => false;
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluUx(inst, address, opCode);
public OpCodeT16AluUx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 0) & 0x7;
Rm = (opCode >> 3) & 0x7;
}
}
}

View File

@ -0,0 +1,15 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16BImm11 : OpCode32, IOpCode32BImm
{
public long Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImm11(inst, address, opCode);
public OpCodeT16BImm11(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
int imm = (opCode << 21) >> 20;
Immediate = GetPc() + imm;
}
}
}

View File

@ -0,0 +1,17 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16BImm8 : OpCode32, IOpCode32BImm
{
public long Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImm8(inst, address, opCode);
public OpCodeT16BImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Cond = (Condition)((opCode >> 8) & 0xf);
int imm = (opCode << 24) >> 23;
Immediate = GetPc() + imm;
}
}
}

View File

@ -0,0 +1,19 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16BImmCmp : OpCodeT16
{
public int Rn { get; }
public int Immediate { get; }
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImmCmp(inst, address, opCode);
public OpCodeT16BImmCmp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rn = (opCode >> 0) & 0x7;
int imm = ((opCode >> 2) & 0x3e) | ((opCode >> 3) & 0x40);
Immediate = (int)GetPc() + imm;
}
}
}

View File

@ -1,4 +1,4 @@
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
class OpCodeT16BReg : OpCodeT16, IOpCode32BReg class OpCodeT16BReg : OpCodeT16, IOpCode32BReg
{ {
@ -11,4 +11,4 @@ namespace ARMeilleure.Decoders
Rm = (opCode >> 3) & 0xf; Rm = (opCode >> 3) & 0xf;
} }
} }
} }

View File

@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16Exception : OpCodeT16, IOpCode32Exception
{
public int Id { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Exception(inst, address, opCode);
public OpCodeT16Exception(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Id = opCode & 0xFF;
}
}
}

View File

@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Reflection.Emit;
namespace ARMeilleure.Decoders
{
class OpCodeT16IfThen : OpCodeT16
{
public Condition[] IfThenBlockConds { get; }
public int IfThenBlockSize { get { return IfThenBlockConds.Length; } }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16IfThen(inst, address, opCode);
public OpCodeT16IfThen(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
List<Condition> conds = new();
int cond = (opCode >> 4) & 0xf;
int mask = opCode & 0xf;
conds.Add((Condition)cond);
while ((mask & 7) != 0)
{
int newLsb = (mask >> 3) & 1;
cond = (cond & 0xe) | newLsb;
mask <<= 1;
conds.Add((Condition)cond);
}
IfThenBlockConds = conds.ToArray();
}
}
}

View File

@ -0,0 +1,58 @@
using ARMeilleure.Instructions;
using System;
namespace ARMeilleure.Decoders
{
class OpCodeT16MemImm5 : OpCodeT16, IOpCode32Mem
{
public int Rt { get; }
public int Rn { get; }
public bool WBack => false;
public bool IsLoad { get; }
public bool Index => true;
public bool Add => true;
public int Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemImm5(inst, address, opCode);
public OpCodeT16MemImm5(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rt = (opCode >> 0) & 7;
Rn = (opCode >> 3) & 7;
switch (inst.Name)
{
case InstName.Ldr:
case InstName.Ldrb:
case InstName.Ldrh:
IsLoad = true;
break;
case InstName.Str:
case InstName.Strb:
case InstName.Strh:
IsLoad = false;
break;
}
switch (inst.Name)
{
case InstName.Str:
case InstName.Ldr:
Immediate = ((opCode >> 6) & 0x1f) << 2;
break;
case InstName.Strb:
case InstName.Ldrb:
Immediate = ((opCode >> 6) & 0x1f);
break;
case InstName.Strh:
case InstName.Ldrh:
Immediate = ((opCode >> 6) & 0x1f) << 1;
break;
default:
throw new InvalidOperationException();
}
}
}
}

View File

@ -0,0 +1,26 @@
using ARMeilleure.State;
namespace ARMeilleure.Decoders
{
class OpCodeT16MemLit : OpCodeT16, IOpCode32Mem
{
public int Rt { get; }
public int Rn => RegisterAlias.Aarch32Pc;
public bool WBack => false;
public bool IsLoad => true;
public bool Index => true;
public bool Add => true;
public int Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemLit(inst, address, opCode);
public OpCodeT16MemLit(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rt = (opCode >> 8) & 7;
Immediate = (opCode & 0xff) << 2;
}
}
}

View File

@ -0,0 +1,34 @@
using ARMeilleure.Instructions;
using System;
using System.Numerics;
namespace ARMeilleure.Decoders
{
class OpCodeT16MemMult : OpCodeT16, IOpCode32MemMult
{
public int Rn { get; }
public int RegisterMask { get; }
public int PostOffset { get; }
public bool IsLoad { get; }
public int Offset { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemMult(inst, address, opCode);
public OpCodeT16MemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
RegisterMask = opCode & 0xff;
Rn = (opCode >> 8) & 7;
int regCount = BitOperations.PopCount((uint)RegisterMask);
Offset = 0;
PostOffset = 4 * regCount;
IsLoad = inst.Name switch
{
InstName.Ldm => true,
InstName.Stm => false,
_ => throw new InvalidOperationException()
};
}
}
}

View File

@ -0,0 +1,27 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16MemReg : OpCodeT16, IOpCode32MemReg
{
public int Rm { get; }
public int Rt { get; }
public int Rn { get; }
public bool WBack => false;
public bool IsLoad { get; }
public bool Index => true;
public bool Add => true;
public int Immediate => throw new System.InvalidOperationException();
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemReg(inst, address, opCode);
public OpCodeT16MemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rt = (opCode >> 0) & 7;
Rn = (opCode >> 3) & 7;
Rm = (opCode >> 6) & 7;
IsLoad = ((opCode >> 9) & 7) >= 3;
}
}
}

View File

@ -0,0 +1,28 @@
using ARMeilleure.State;
namespace ARMeilleure.Decoders
{
class OpCodeT16MemSp : OpCodeT16, IOpCode32Mem
{
public int Rt { get; }
public int Rn => RegisterAlias.Aarch32Sp;
public bool WBack => false;
public bool IsLoad { get; }
public bool Index => true;
public bool Add => true;
public int Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemSp(inst, address, opCode);
public OpCodeT16MemSp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rt = (opCode >> 8) & 7;
IsLoad = ((opCode >> 11) & 1) != 0;
Immediate = ((opCode >> 0) & 0xff) << 2;
}
}
}

View File

@ -0,0 +1,42 @@
using ARMeilleure.Instructions;
using ARMeilleure.State;
using System;
using System.Numerics;
namespace ARMeilleure.Decoders
{
class OpCodeT16MemStack : OpCodeT16, IOpCode32MemMult
{
public int Rn => RegisterAlias.Aarch32Sp;
public int RegisterMask { get; }
public int PostOffset { get; }
public bool IsLoad { get; }
public int Offset { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemStack(inst, address, opCode);
public OpCodeT16MemStack(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
int extra = (opCode >> 8) & 1;
int regCount = BitOperations.PopCount((uint)opCode & 0x1ff);
switch (inst.Name)
{
case InstName.Push:
RegisterMask = (opCode & 0xff) | (extra << 14);
IsLoad = false;
Offset = -4 * regCount;
PostOffset = -4 * regCount;
break;
case InstName.Pop:
RegisterMask = (opCode & 0xff) | (extra << 15);
IsLoad = true;
Offset = 0;
PostOffset = 4 * regCount;
break;
default:
throw new InvalidOperationException();
}
}
}
}

View File

@ -0,0 +1,24 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16ShiftImm : OpCodeT16, IOpCode32AluRsImm
{
public int Rd { get; }
public int Rn { get; }
public int Rm { get; }
public int Immediate { get; }
public ShiftType ShiftType { get; }
public bool? SetFlags => null;
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16ShiftImm(inst, address, opCode);
public OpCodeT16ShiftImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 0) & 0x7;
Rm = (opCode >> 3) & 0x7;
Immediate = (opCode >> 6) & 0x1F;
ShiftType = (ShiftType)((opCode >> 11) & 3);
}
}
}

View File

@ -0,0 +1,27 @@
namespace ARMeilleure.Decoders
{
class OpCodeT16ShiftReg : OpCodeT16, IOpCode32AluRsReg
{
public int Rm { get; }
public int Rs { get; }
public int Rd { get; }
public int Rn { get; }
public ShiftType ShiftType { get; }
public bool? SetFlags => null;
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16ShiftReg(inst, address, opCode);
public OpCodeT16ShiftReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 0) & 7;
Rm = (opCode >> 0) & 7;
Rn = (opCode >> 3) & 7;
Rs = (opCode >> 3) & 7;
ShiftType = (ShiftType)(((opCode >> 6) & 1) | ((opCode >> 7) & 2));
}
}
}

View File

@ -0,0 +1,24 @@
using ARMeilleure.State;
namespace ARMeilleure.Decoders
{
class OpCodeT16SpRel : OpCodeT16, IOpCode32AluImm
{
public int Rd { get; }
public int Rn => RegisterAlias.Aarch32Sp;
public bool? SetFlags => false;
public int Immediate { get; }
public bool IsRotated => false;
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16SpRel(inst, address, opCode);
public OpCodeT16SpRel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 8) & 0x7;
Immediate = ((opCode >> 0) & 0xff) << 2;
}
}
}

View File

@ -1,5 +1,4 @@
using ARMeilleure.Instructions; using ARMeilleure.Instructions;
using ARMeilleure.State;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -29,9 +28,9 @@ namespace ARMeilleure.Decoders
} }
} }
private static List<InstInfo> AllInstA32 = new List<InstInfo>(); private static List<InstInfo> AllInstA32 = new();
private static List<InstInfo> AllInstT32 = new List<InstInfo>(); private static List<InstInfo> AllInstT32 = new();
private static List<InstInfo> AllInstA64 = new List<InstInfo>(); private static List<InstInfo> AllInstA64 = new();
private static InstInfo[][] InstA32FastLookup = new InstInfo[FastLookupSize][]; private static InstInfo[][] InstA32FastLookup = new InstInfo[FastLookupSize][];
private static InstInfo[][] InstT32FastLookup = new InstInfo[FastLookupSize][]; private static InstInfo[][] InstT32FastLookup = new InstInfo[FastLookupSize][];
@ -628,7 +627,7 @@ namespace ARMeilleure.Decoders
SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstName.Zip2_V, InstEmit.Zip2_V, OpCodeSimdReg.Create); SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstName.Zip2_V, InstEmit.Zip2_V, OpCodeSimdReg.Create);
#endregion #endregion
#region "OpCode Table (AArch32)" #region "OpCode Table (AArch32, A32)"
// Base // Base
SetA32("<<<<0010101xxxxxxxxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluImm.Create); SetA32("<<<<0010101xxxxxxxxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluImm.Create);
SetA32("<<<<0000101xxxxxxxxxxxxxxxx0xxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluRsImm.Create); SetA32("<<<<0000101xxxxxxxxxxxxxxxx0xxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluRsImm.Create);
@ -649,7 +648,6 @@ namespace ARMeilleure.Decoders
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, InstEmit32.Blx, OpCode32BImm.Create); SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, InstEmit32.Blx, OpCode32BImm.Create);
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, OpCode32BReg.Create); SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, OpCode32BReg.Create);
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, OpCode32BReg.Create); SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, OpCode32BReg.Create);
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
SetA32("11110101011111111111000000011111", InstName.Clrex, InstEmit32.Clrex, OpCode32.Create); SetA32("11110101011111111111000000011111", InstName.Clrex, InstEmit32.Clrex, OpCode32.Create);
SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, OpCode32AluReg.Create); SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, OpCode32AluReg.Create);
SetA32("<<<<00110111xxxx0000xxxxxxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluImm.Create); SetA32("<<<<00110111xxxx0000xxxxxxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluImm.Create);
@ -702,7 +700,6 @@ namespace ARMeilleure.Decoders
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsImm.Create); SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsImm.Create);
SetA32("<<<<0001101x0000xxxxxxxx0xx1xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsReg.Create); SetA32("<<<<0001101x0000xxxxxxxx0xx1xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsReg.Create);
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluImm16.Create); SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluImm16.Create);
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluImm8.Create);
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, OpCode32AluImm16.Create); SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, OpCode32AluImm16.Create);
SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, OpCode32System.Create); SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, OpCode32System.Create);
SetA32("<<<<11000101xxxxxxxx111xxxxxxxxx", InstName.Mrrc, InstEmit32.Mrrc, OpCode32System.Create); SetA32("<<<<11000101xxxxxxxx111xxxxxxxxx", InstName.Mrrc, InstEmit32.Mrrc, OpCode32System.Create);
@ -975,12 +972,85 @@ namespace ARMeilleure.Decoders
SetA32("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip, InstEmit32.Vzip, OpCode32SimdCmpZ.Create); SetA32("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip, InstEmit32.Vzip, OpCode32SimdCmpZ.Create);
#endregion #endregion
FillFastLookupTable(InstA32FastLookup, AllInstA32); #region "OpCode Table (AArch32, T16/T32)"
FillFastLookupTable(InstT32FastLookup, AllInstT32); // T16
FillFastLookupTable(InstA64FastLookup, AllInstA64); SetT16("000<<xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftImm.Create);
SetT16("0001100xxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubReg.Create);
SetT16("0001101xxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubReg.Create);
SetT16("0001110xxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubImm3.Create);
SetT16("0001111xxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubImm3.Create);
SetT16("00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluImm8.Create);
SetT16("00101xxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluImm8.Create);
SetT16("00110xxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AluImm8.Create);
SetT16("00111xxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AluImm8.Create);
SetT16("0100000000xxxxxx", InstName.And, InstEmit32.And, OpCodeT16AluRegLow.Create);
SetT16("0100000001xxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT16AluRegLow.Create);
SetT16("0100000010xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
SetT16("0100000011xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
SetT16("0100000100xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
SetT16("0100000101xxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT16AluRegLow.Create);
SetT16("0100000110xxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT16AluRegLow.Create);
SetT16("0100000111xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
SetT16("0100001000xxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT16AluRegLow.Create);
SetT16("0100001001xxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT16AluImmZero.Create);
SetT16("0100001010xxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegLow.Create);
SetT16("0100001011xxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT16AluRegLow.Create);
SetT16("0100001100xxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT16AluRegLow.Create);
SetT16("0100001101xxxxxx", InstName.Mul, InstEmit32.Mul, OpCodeT16AluRegLow.Create);
SetT16("0100001110xxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT16AluRegLow.Create);
SetT16("0100001111xxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT16AluRegLow.Create);
SetT16("01000100xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AluRegHigh.Create);
SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create);
SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create);
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blx, OpCodeT16BReg.Create);
SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create);
SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create);
SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create);
SetT16("0101010xxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT16MemReg.Create);
SetT16("0101011xxxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT16MemReg.Create);
SetT16("0101100xxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemReg.Create);
SetT16("0101101xxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT16MemReg.Create);
SetT16("0101110xxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT16MemReg.Create);
SetT16("0101111xxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT16MemReg.Create);
SetT16("01100xxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemImm5.Create);
SetT16("01101xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemImm5.Create);
SetT16("01110xxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT16MemImm5.Create);
SetT16("01111xxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT16MemImm5.Create);
SetT16("10000xxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemImm5.Create);
SetT16("10001xxxxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT16MemImm5.Create);
SetT16("10010xxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemSp.Create);
SetT16("10011xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemSp.Create);
SetT16("10100xxxxxxxxxxx", InstName.Adr, InstEmit32.Adr, OpCodeT16Adr.Create);
SetT16("10101xxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16SpRel.Create);
SetT16("101100000xxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubSp.Create);
SetT16("101100001xxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubSp.Create);
SetT16("1011001000xxxxxx", InstName.Sxth, InstEmit32.Sxth, OpCodeT16AluUx.Create);
SetT16("1011001001xxxxxx", InstName.Sxtb, InstEmit32.Sxtb, OpCodeT16AluUx.Create);
SetT16("1011001010xxxxxx", InstName.Uxth, InstEmit32.Uxth, OpCodeT16AluUx.Create);
SetT16("1011001011xxxxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCodeT16AluUx.Create);
SetT16("101100x1xxxxxxxx", InstName.Cbz, InstEmit32.Cbz, OpCodeT16BImmCmp.Create);
SetT16("1011010xxxxxxxxx", InstName.Push, InstEmit32.Stm, OpCodeT16MemStack.Create);
SetT16("1011101000xxxxxx", InstName.Rev, InstEmit32.Rev, OpCodeT16AluRegLow.Create);
SetT16("1011101001xxxxxx", InstName.Rev16, InstEmit32.Rev16, OpCodeT16AluRegLow.Create);
SetT16("1011101011xxxxxx", InstName.Revsh, InstEmit32.Revsh, OpCodeT16AluRegLow.Create);
SetT16("101110x1xxxxxxxx", InstName.Cbnz, InstEmit32.Cbnz, OpCodeT16BImmCmp.Create);
SetT16("1011110xxxxxxxxx", InstName.Pop, InstEmit32.Ldm, OpCodeT16MemStack.Create);
SetT16("10111111xxxx0000", InstName.Nop, InstEmit32.Nop, OpCodeT16.Create);
SetT16("10111111xxxx>>>>", InstName.It, InstEmit32.It, OpCodeT16IfThen.Create);
SetT16("11000xxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT16MemMult.Create);
SetT16("11001xxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT16MemMult.Create);
SetT16("1101<<<xxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT16BImm8.Create);
SetT16("11011111xxxxxxxx", InstName.Svc, InstEmit32.Svc, OpCodeT16Exception.Create);
SetT16("11100xxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT16BImm11.Create);
#endregion
FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
FillFastLookupTable(InstT32FastLookup, AllInstT32, ToFastLookupIndexT);
FillFastLookupTable(InstA64FastLookup, AllInstA64, ToFastLookupIndexA);
} }
private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts) private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts, Func<int, int> ToFastLookupIndex)
{ {
List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize]; List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
@ -1011,20 +1081,27 @@ namespace ARMeilleure.Decoders
private static void SetA32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp) private static void SetA32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
{ {
Set(encoding, ExecutionMode.Aarch32Arm, new InstDescriptor(name, emitter), makeOp); Set(encoding, AllInstA32, new InstDescriptor(name, emitter), makeOp);
}
private static void SetT16(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
{
encoding = "xxxxxxxxxxxxxxxx" + encoding;
Set(encoding, AllInstT32, new InstDescriptor(name, emitter), makeOp);
} }
private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp) private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
{ {
Set(encoding, ExecutionMode.Aarch32Thumb, new InstDescriptor(name, emitter), makeOp); encoding = encoding.Substring(16) + encoding.Substring(0, 16);
Set(encoding, AllInstT32, new InstDescriptor(name, emitter), makeOp);
} }
private static void SetA64(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp) private static void SetA64(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
{ {
Set(encoding, ExecutionMode.Aarch64, new InstDescriptor(name, emitter), makeOp); Set(encoding, AllInstA64, new InstDescriptor(name, emitter), makeOp);
} }
private static void Set(string encoding, ExecutionMode mode, InstDescriptor inst, MakeOp makeOp) private static void Set(string encoding, List<InstInfo> list, InstDescriptor inst, MakeOp makeOp)
{ {
int bit = encoding.Length - 1; int bit = encoding.Length - 1;
int value = 0; int value = 0;
@ -1073,7 +1150,7 @@ namespace ARMeilleure.Decoders
if (xBits == 0) if (xBits == 0)
{ {
InsertInst(new InstInfo(xMask, value, inst, makeOp), mode); list.Add(new InstInfo(xMask, value, inst, makeOp));
return; return;
} }
@ -1089,34 +1166,24 @@ namespace ARMeilleure.Decoders
if (mask != blacklisted) if (mask != blacklisted)
{ {
InsertInst(new InstInfo(xMask, value | mask, inst, makeOp), mode); list.Add(new InstInfo(xMask, value | mask, inst, makeOp));
} }
} }
} }
private static void InsertInst(InstInfo info, ExecutionMode mode)
{
switch (mode)
{
case ExecutionMode.Aarch32Arm: AllInstA32.Add(info); break;
case ExecutionMode.Aarch32Thumb: AllInstT32.Add(info); break;
case ExecutionMode.Aarch64: AllInstA64.Add(info); break;
}
}
public static (InstDescriptor inst, MakeOp makeOp) GetInstA32(int opCode) public static (InstDescriptor inst, MakeOp makeOp) GetInstA32(int opCode)
{ {
return GetInstFromList(InstA32FastLookup[ToFastLookupIndex(opCode)], opCode); return GetInstFromList(InstA32FastLookup[ToFastLookupIndexA(opCode)], opCode);
} }
public static (InstDescriptor inst, MakeOp makeOp) GetInstT32(int opCode) public static (InstDescriptor inst, MakeOp makeOp) GetInstT32(int opCode)
{ {
return GetInstFromList(InstT32FastLookup[ToFastLookupIndex(opCode)], opCode); return GetInstFromList(InstT32FastLookup[ToFastLookupIndexT(opCode)], opCode);
} }
public static (InstDescriptor inst, MakeOp makeOp) GetInstA64(int opCode) public static (InstDescriptor inst, MakeOp makeOp) GetInstA64(int opCode)
{ {
return GetInstFromList(InstA64FastLookup[ToFastLookupIndex(opCode)], opCode); return GetInstFromList(InstA64FastLookup[ToFastLookupIndexA(opCode)], opCode);
} }
private static (InstDescriptor inst, MakeOp makeOp) GetInstFromList(InstInfo[] insts, int opCode) private static (InstDescriptor inst, MakeOp makeOp) GetInstFromList(InstInfo[] insts, int opCode)
@ -1132,9 +1199,14 @@ namespace ARMeilleure.Decoders
return (new InstDescriptor(InstName.Und, InstEmit.Und), null); return (new InstDescriptor(InstName.Und, InstEmit.Und), null);
} }
private static int ToFastLookupIndex(int value) private static int ToFastLookupIndexA(int value)
{ {
return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0); return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0);
} }
private static int ToFastLookupIndexT(int value)
{
return (value >> 4) & 0xFFF;
}
} }
} }

View File

@ -1,13 +1,14 @@
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf // https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
using ARMeilleure.State; using ARMeilleure.State;
using System;
namespace ARMeilleure.Instructions namespace ARMeilleure.Instructions
{ {
static class CryptoHelper static class CryptoHelper
{ {
#region "LookUp Tables" #region "LookUp Tables"
private static readonly byte[] _sBox = new byte[] private static ReadOnlySpan<byte> _sBox => new byte[]
{ {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
@ -27,7 +28,7 @@ namespace ARMeilleure.Instructions
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
}; };
private static readonly byte[] _invSBox = new byte[] private static ReadOnlySpan<byte> _invSBox => new byte[]
{ {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
@ -47,7 +48,7 @@ namespace ARMeilleure.Instructions
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
}; };
private static readonly byte[] _gfMul02 = new byte[] private static ReadOnlySpan<byte> _gfMul02 => new byte[]
{ {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
@ -67,7 +68,7 @@ namespace ARMeilleure.Instructions
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
}; };
private static readonly byte[] _gfMul03 = new byte[] private static ReadOnlySpan<byte> _gfMul03 => new byte[]
{ {
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
@ -87,7 +88,7 @@ namespace ARMeilleure.Instructions
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
}; };
private static readonly byte[] _gfMul09 = new byte[] private static ReadOnlySpan<byte> _gfMul09 => new byte[]
{ {
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
@ -107,7 +108,7 @@ namespace ARMeilleure.Instructions
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
}; };
private static readonly byte[] _gfMul0B = new byte[] private static ReadOnlySpan<byte> _gfMul0B => new byte[]
{ {
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
@ -127,7 +128,7 @@ namespace ARMeilleure.Instructions
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
}; };
private static readonly byte[] _gfMul0D = new byte[] private static ReadOnlySpan<byte> _gfMul0D => new byte[]
{ {
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
@ -147,7 +148,7 @@ namespace ARMeilleure.Instructions
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
}; };
private static readonly byte[] _gfMul0E = new byte[] private static ReadOnlySpan<byte> _gfMul0E => new byte[]
{ {
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
@ -167,12 +168,12 @@ namespace ARMeilleure.Instructions
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
}; };
private static readonly byte[] _srPerm = new byte[] private static ReadOnlySpan<byte> _srPerm => new byte[]
{ {
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
}; };
private static readonly byte[] _isrPerm = new byte[] private static ReadOnlySpan<byte> _isrPerm => new byte[]
{ {
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
}; };

View File

@ -20,7 +20,7 @@ namespace ARMeilleure.Instructions
Operand res = context.Add(n, m); Operand res = context.Add(n, m);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
@ -44,7 +44,7 @@ namespace ARMeilleure.Instructions
res = context.Add(res, carry); res = context.Add(res, carry);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
Operand res = context.BitwiseAnd(n, m); Operand res = context.BitwiseAnd(n, m);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
@ -110,7 +110,7 @@ namespace ARMeilleure.Instructions
Operand res = context.BitwiseAnd(n, context.BitwiseNot(m)); Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
@ -161,7 +161,7 @@ namespace ARMeilleure.Instructions
Operand res = context.BitwiseExclusiveOr(n, m); Operand res = context.BitwiseExclusiveOr(n, m);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
Operand m = GetAluM(context); Operand m = GetAluM(context);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, m); EmitNZFlagsCheck(context, m);
} }
@ -204,7 +204,7 @@ namespace ARMeilleure.Instructions
Operand res = context.Multiply(n, m); Operand res = context.Multiply(n, m);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
@ -219,7 +219,7 @@ namespace ARMeilleure.Instructions
Operand res = context.BitwiseNot(m); Operand res = context.BitwiseNot(m);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
@ -236,7 +236,7 @@ namespace ARMeilleure.Instructions
Operand res = context.BitwiseOr(n, m); Operand res = context.BitwiseOr(n, m);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
@ -315,7 +315,7 @@ namespace ARMeilleure.Instructions
res = context.Subtract(res, borrow); res = context.Subtract(res, borrow);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
@ -335,7 +335,7 @@ namespace ARMeilleure.Instructions
Operand res = context.Subtract(m, n); Operand res = context.Subtract(m, n);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
@ -359,7 +359,7 @@ namespace ARMeilleure.Instructions
res = context.Subtract(res, borrow); res = context.Subtract(res, borrow);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
@ -420,7 +420,7 @@ namespace ARMeilleure.Instructions
Operand res = context.Subtract(n, m); Operand res = context.Subtract(n, m);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
@ -836,7 +836,7 @@ namespace ARMeilleure.Instructions
{ {
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
EmitGenericAluStoreA32(context, op.Rd, op.SetFlags, value); EmitGenericAluStoreA32(context, op.Rd, ShouldSetFlags(context), value);
} }
} }
} }

View File

@ -12,6 +12,18 @@ namespace ARMeilleure.Instructions
{ {
static class InstEmitAluHelper static class InstEmitAluHelper
{ {
public static bool ShouldSetFlags(ArmEmitterContext context)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
if (op.SetFlags == null)
{
return !context.IsInIfThenBlock;
}
return op.SetFlags.Value;
}
public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d) public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
{ {
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0))); SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
@ -183,9 +195,9 @@ namespace ARMeilleure.Instructions
switch (context.CurrOp) switch (context.CurrOp)
{ {
// ARM32. // ARM32.
case OpCode32AluImm op: case IOpCode32AluImm op:
{ {
if (op.SetFlags && op.IsRotated) if (ShouldSetFlags(context) && op.IsRotated)
{ {
SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31)); SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31));
} }
@ -195,10 +207,8 @@ namespace ARMeilleure.Instructions
case OpCode32AluImm16 op: return Const(op.Immediate); case OpCode32AluImm16 op: return Const(op.Immediate);
case OpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry); case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
case OpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry); case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
case OpCodeT16AluImm8 op: return Const(op.Immediate);
case IOpCode32AluReg op: return GetIntA32(context, op.Rm); case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
@ -249,7 +259,7 @@ namespace ARMeilleure.Instructions
} }
// ARM32 helpers. // ARM32 helpers.
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32AluRsImm op, bool setCarry) public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32AluRsImm op, bool setCarry)
{ {
Operand m = GetIntA32(context, op.Rm); Operand m = GetIntA32(context, op.Rm);
@ -267,7 +277,7 @@ namespace ARMeilleure.Instructions
if (shift != 0) if (shift != 0)
{ {
setCarry &= op.SetFlags; setCarry &= ShouldSetFlags(context);
switch (op.ShiftType) switch (op.ShiftType)
{ {
@ -305,7 +315,7 @@ namespace ARMeilleure.Instructions
return shift; return shift;
} }
public static Operand GetMShiftedByReg(ArmEmitterContext context, OpCode32AluRsReg op, bool setCarry) public static Operand GetMShiftedByReg(ArmEmitterContext context, IOpCode32AluRsReg op, bool setCarry)
{ {
Operand m = GetIntA32(context, op.Rm); Operand m = GetIntA32(context, op.Rm);
Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs)); Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
@ -314,7 +324,7 @@ namespace ARMeilleure.Instructions
Operand zeroResult = m; Operand zeroResult = m;
Operand shiftResult = m; Operand shiftResult = m;
setCarry &= op.SetFlags; setCarry &= ShouldSetFlags(context);
switch (op.ShiftType) switch (op.ShiftType)
{ {

View File

@ -20,11 +20,11 @@ namespace ARMeilleure.Instructions
private static void EmitExceptionCall(ArmEmitterContext context, string name) private static void EmitExceptionCall(ArmEmitterContext context, string name)
{ {
OpCode32Exception op = (OpCode32Exception)context.CurrOp; IOpCode32Exception op = (IOpCode32Exception)context.CurrOp;
context.StoreToContext(); context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id)); context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.LoadFromContext(); context.LoadFromContext();

View File

@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
bool isThumb = IsThumb(context.CurrOp); bool isThumb = IsThumb(context.CurrOp);
uint currentPc = isThumb uint currentPc = isThumb
? pc | 1 ? (pc - 2) | 1
: pc - 4; : pc - 4;
SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc)); SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
@ -80,5 +80,32 @@ namespace ARMeilleure.Instructions
EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm); EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
} }
public static void Cbnz(ArmEmitterContext context) => EmitCb(context, onNotZero: true);
public static void Cbz(ArmEmitterContext context) => EmitCb(context, onNotZero: false);
private static void EmitCb(ArmEmitterContext context, bool onNotZero)
{
OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
Operand value = GetIntOrZR(context, op.Rn);
Operand lblTarget = context.GetLabel((ulong)op.Immediate);
if (onNotZero)
{
context.BranchIfTrue(lblTarget, value);
}
else
{
context.BranchIfFalse(lblTarget, value);
}
}
public static void It(ArmEmitterContext context)
{
OpCodeT16IfThen op = (OpCodeT16IfThen)context.CurrOp;
context.SetIfThenBlockState(op.IfThenBlockConds);
}
} }
} }

View File

@ -32,7 +32,7 @@ namespace ARMeilleure.Instructions
public static void Ldm(ArmEmitterContext context) public static void Ldm(ArmEmitterContext context)
{ {
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp; IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
Operand n = GetIntA32(context, op.Rn); Operand n = GetIntA32(context, op.Rn);
@ -95,7 +95,7 @@ namespace ARMeilleure.Instructions
public static void Stm(ArmEmitterContext context) public static void Stm(ArmEmitterContext context)
{ {
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp; IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
Operand n = context.Copy(GetIntA32(context, op.Rn)); Operand n = context.Copy(GetIntA32(context, op.Rn));
@ -151,7 +151,7 @@ namespace ARMeilleure.Instructions
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType) private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
{ {
OpCode32Mem op = (OpCode32Mem)context.CurrOp; IOpCode32Mem op = (IOpCode32Mem)context.CurrOp;
Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn)); Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn));
Operand m = GetMemM(context, setCarry: false); Operand m = GetMemM(context, setCarry: false);
@ -255,5 +255,11 @@ namespace ARMeilleure.Instructions
} }
} }
} }
public static void Adr(ArmEmitterContext context)
{
IOpCode32Adr op = (IOpCode32Adr)context.CurrOp;
SetIntA32(context, op.Rd, Const(op.Immediate));
}
} }
} }

View File

@ -549,9 +549,9 @@ namespace ARMeilleure.Instructions
{ {
case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry); case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
case OpCode32MemReg op: return GetIntA32(context, op.Rm); case IOpCode32MemReg op: return GetIntA32(context, op.Rm);
case OpCode32Mem op: return Const(op.Immediate); case IOpCode32Mem op: return Const(op.Immediate);
case OpCode32SimdMemImm op: return Const(op.Immediate); case OpCode32SimdMemImm op: return Const(op.Immediate);

View File

@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
Operand res = context.Add(a, context.Multiply(n, m)); Operand res = context.Add(a, context.Multiply(n, m));
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
@ -250,13 +250,13 @@ namespace ARMeilleure.Instructions
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
Operand lo = context.ConvertI64ToI32(res); Operand lo = context.ConvertI64ToI32(res);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi); EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo); EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
} }
public static void Smulw_(ArmEmitterContext context) public static void Smulw_(ArmEmitterContext context)
@ -320,13 +320,13 @@ namespace ARMeilleure.Instructions
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
Operand lo = context.ConvertI64ToI32(res); Operand lo = context.ConvertI64ToI32(res);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi); EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo); EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
} }
private static void EmitMlal(ArmEmitterContext context, bool signed) private static void EmitMlal(ArmEmitterContext context, bool signed)
@ -356,13 +356,13 @@ namespace ARMeilleure.Instructions
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
Operand lo = context.ConvertI64ToI32(res); Operand lo = context.ConvertI64ToI32(res);
if (op.SetFlags) if (ShouldSetFlags(context))
{ {
EmitNZFlagsCheck(context, res); EmitNZFlagsCheck(context, res);
} }
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi); EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo); EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
} }
private static void UpdateQFlag(ArmEmitterContext context, Operand q) private static void UpdateQFlag(ArmEmitterContext context, Operand q)

View File

@ -48,6 +48,7 @@ namespace ARMeilleure.Instructions
Extr, Extr,
Hint, Hint,
Isb, Isb,
It,
Ldar, Ldar,
Ldaxp, Ldaxp,
Ldaxr, Ldaxr,
@ -512,6 +513,8 @@ namespace ARMeilleure.Instructions
Mvn, Mvn,
Pkh, Pkh,
Pld, Pld,
Pop,
Push,
Rev, Rev,
Revsh, Revsh,
Rsb, Rsb,

View File

@ -824,7 +824,7 @@ namespace ARMeilleure.Instructions
return (ulong)(size - 1); return (ulong)(size - 1);
} }
private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; private static ReadOnlySpan<byte> ClzNibbleTbl => new byte[] { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{ {

View File

@ -54,6 +54,11 @@ namespace ARMeilleure.Translation
public bool HighCq { get; } public bool HighCq { get; }
public Aarch32Mode Mode { get; } public Aarch32Mode Mode { get; }
private int _ifThenBlockStateIndex = 0;
private Condition[] _ifThenBlockState = { };
public bool IsInIfThenBlock => _ifThenBlockStateIndex < _ifThenBlockState.Length;
public Condition CurrentIfThenBlockCond => _ifThenBlockState[_ifThenBlockStateIndex];
public ArmEmitterContext( public ArmEmitterContext(
IMemoryManager memory, IMemoryManager memory,
EntryTable<uint> countTable, EntryTable<uint> countTable,
@ -196,5 +201,19 @@ namespace ARMeilleure.Translation
return default; return default;
} }
public void SetIfThenBlockState(Condition[] state)
{
_ifThenBlockState = state;
_ifThenBlockStateIndex = 0;
}
public void AdvanceIfThenBlockState()
{
if (IsInIfThenBlock)
{
_ifThenBlockStateIndex++;
}
}
} }
} }

View File

@ -380,6 +380,13 @@ namespace ARMeilleure.Translation
Operand lblPredicateSkip = default; Operand lblPredicateSkip = default;
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
{
lblPredicateSkip = Label();
InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert());
}
if (opCode is OpCode32 op && op.Cond < Condition.Al) if (opCode is OpCode32 op && op.Cond < Condition.Al)
{ {
lblPredicateSkip = Label(); lblPredicateSkip = Label();
@ -400,6 +407,11 @@ namespace ARMeilleure.Translation
{ {
context.MarkLabel(lblPredicateSkip); context.MarkLabel(lblPredicateSkip);
} }
if (context.IsInIfThenBlock && opCode.Instruction.Name != InstName.It)
{
context.AdvanceIfThenBlockState();
}
} }
} }
} }

View File

@ -600,19 +600,42 @@ namespace Ryujinx.Audio.Renderer.Dsp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount) public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount)
{ {
// TODO: use a bandwidth filter to have better resampling. // Currently a simple cubic interpolation, assuming duplicated values at edges.
// TODO: Discover and use algorithm that the switch uses.
int inputBufferIndex = 0; int inputBufferIndex = 0;
int maxIndex = inputBuffer.Length - 1;
int cubicEnd = inputBuffer.Length - 3;
for (int i = 0; i < sampleCount; i++) for (int i = 0; i < sampleCount; i++)
{ {
float outputData = inputBuffer[inputBufferIndex]; float s0, s1, s2, s3;
if (fraction > 1.0f) s1 = inputBuffer[inputBufferIndex];
if (inputBufferIndex == 0 || inputBufferIndex > cubicEnd)
{ {
outputData = inputBuffer[inputBufferIndex + 1]; // Clamp interplation values at the ends of the input buffer.
s0 = inputBuffer[Math.Max(0, inputBufferIndex - 1)];
s2 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 1)];
s3 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 2)];
}
else
{
s0 = inputBuffer[inputBufferIndex - 1];
s2 = inputBuffer[inputBufferIndex + 1];
s3 = inputBuffer[inputBufferIndex + 2];
} }
outputBuffer[i] = outputData; float a = s3 - s2 - s0 + s1;
float b = s0 - s1 - a;
float c = s2 - s0;
float d = s1;
float f2 = fraction * fraction;
float f3 = f2 * fraction;
outputBuffer[i] = a * f3 + b * f2 + c * fraction + d;
fraction += ratio; fraction += ratio;
inputBufferIndex += (int)MathF.Truncate(fraction); inputBufferIndex += (int)MathF.Truncate(fraction);

View File

@ -1,8 +1,10 @@
using System;
namespace Ryujinx.Common namespace Ryujinx.Common
{ {
public static class BitUtils public static class BitUtils
{ {
private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; private static ReadOnlySpan<byte> ClzNibbleTbl => new byte[] { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
public static uint AlignUp(uint value, int size) public static uint AlignUp(uint value, int size)
{ {

View File

@ -43,7 +43,7 @@ namespace Ryujinx.Common
Prime32_1 Prime32_1
}; };
private static readonly byte[] Xxh3KSecret = new byte[] private static ReadOnlySpan<byte> Xxh3KSecret => new byte[]
{ {
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,

View File

@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
} }
// ZigZag LUTs from libavcodec. // ZigZag LUTs from libavcodec.
private static readonly byte[] ZigZagDirect = new byte[] private static ReadOnlySpan<byte> ZigZagDirect => new byte[]
{ {
0, 1, 8, 16, 9, 2, 3, 10, 0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5, 17, 24, 32, 25, 18, 11, 4, 5,
@ -130,7 +130,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
53, 60, 61, 54, 47, 55, 62, 63 53, 60, 61, 54, 47, 55, 62, 63
}; };
private static readonly byte[] ZigZagScan = new byte[] private static ReadOnlySpan<byte> ZigZagScan => new byte[]
{ {
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, 0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4, 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
private static void WriteScalingList(ref H264BitStreamWriter writer, IArray<byte> list) private static void WriteScalingList(ref H264BitStreamWriter writer, IArray<byte> list)
{ {
byte[] scan = list.Length == 16 ? ZigZagScan : ZigZagDirect; ReadOnlySpan<byte> scan = list.Length == 16 ? ZigZagScan : ZigZagDirect;
int lastScale = 8; int lastScale = 8;

View File

@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
public ISurface CreateSurface(int width, int height) => new Surface(width, height); public ISurface CreateSurface(int width, int height) => new Surface(width, height);
private static readonly byte[] LiteralToFilter = new byte[] private static ReadOnlySpan<byte> LiteralToFilter => new byte[]
{ {
Constants.EightTapSmooth, Constants.EightTapSmooth,
Constants.EightTap, Constants.EightTap,

View File

@ -1,5 +1,6 @@
using Ryujinx.Graphics.Nvdec.Vp9.Common; using Ryujinx.Graphics.Nvdec.Vp9.Common;
using Ryujinx.Graphics.Nvdec.Vp9.Types; using Ryujinx.Graphics.Nvdec.Vp9.Types;
using System;
using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred; using static Ryujinx.Graphics.Nvdec.Vp9.Dsp.IntraPred;
namespace Ryujinx.Graphics.Nvdec.Vp9 namespace Ryujinx.Graphics.Nvdec.Vp9
@ -24,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
private const int NeedAbove = 1 << 2; private const int NeedAbove = 1 << 2;
private const int NeedAboveRight = 1 << 3; private const int NeedAboveRight = 1 << 3;
private static readonly byte[] ExtendModes = new byte[] private static ReadOnlySpan<byte> ExtendModes => new byte[]
{ {
NeedAbove | NeedLeft, // DC NeedAbove | NeedLeft, // DC
NeedAbove, // V NeedAbove, // V

View File

@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
public short Row; public short Row;
public short Col; public short Col;
private static readonly byte[] LogInBase2 = new byte[] private static ReadOnlySpan<byte> LogInBase2 => new byte[]
{ {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,

View File

@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
arguments.Handle = CreateHandleFromMap(new NvMapHandle(size)); arguments.Handle = CreateHandleFromMap(new NvMapHandle(size));
Logger.Info?.Print(LogClass.ServiceNv, $"Created map {arguments.Handle} with size 0x{size:x8}!"); Logger.Debug?.Print(LogClass.ServiceNv, $"Created map {arguments.Handle} with size 0x{size:x8}!");
return NvInternalResult.Success; return NvInternalResult.Success;
} }
@ -265,7 +265,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap
{ {
DeleteMapWithHandle(pid, handle); DeleteMapWithHandle(pid, handle);
Logger.Info?.Print(LogClass.ServiceNv, $"Deleted map {handle}!"); Logger.Debug?.Print(LogClass.ServiceNv, $"Deleted map {handle}!");
return true; return true;
} }

View File

@ -41,8 +41,8 @@ namespace Ryujinx.Tests.Unicorn
public uint PC public uint PC
{ {
get => GetRegister(Arm32Register.PC); get => GetRegister(Arm32Register.PC) & 0xfffffffeu;
set => SetRegister(Arm32Register.PC, value); set => SetRegister(Arm32Register.PC, (value & 0xfffffffeu) | (ThumbFlag ? 1u : 0u));
} }
public uint CPSR public uint CPSR
@ -87,6 +87,16 @@ namespace Ryujinx.Tests.Unicorn
set => CPSR = (CPSR & ~0x80000000u) | (value ? 0x80000000u : 0u); set => CPSR = (CPSR & ~0x80000000u) | (value ? 0x80000000u : 0u);
} }
public bool ThumbFlag
{
get => (CPSR & 0x00000020u) != 0;
set
{
CPSR = (CPSR & ~0x00000020u) | (value ? 0x00000020u : 0u);
SetRegister(Arm32Register.PC, (GetRegister(Arm32Register.PC) & 0xfffffffeu) | (value ? 1u : 0u));
}
}
public UnicornAArch32() public UnicornAArch32()
{ {
Interface.Checked(Interface.uc_open(UnicornArch.UC_ARCH_ARM, UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc)); Interface.Checked(Interface.uc_open(UnicornArch.UC_ARCH_ARM, UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc));

View File

@ -106,6 +106,18 @@ namespace Ryujinx.Tests.Cpu
_currAddress += 4; _currAddress += 4;
} }
protected void ThumbOpcode(ushort opcode)
{
_memory.Write(_currAddress, opcode);
if (_unicornAvailable)
{
_unicornEmu.MemoryWrite16(_currAddress, opcode);
}
_currAddress += 2;
}
protected ExecutionContext GetContext() => _context; protected ExecutionContext GetContext() => _context;
protected void SetContext(uint r0 = 0, protected void SetContext(uint r0 = 0,
@ -126,7 +138,8 @@ namespace Ryujinx.Tests.Cpu
bool carry = false, bool carry = false,
bool zero = false, bool zero = false,
bool negative = false, bool negative = false,
int fpscr = 0) int fpscr = 0,
bool thumb = false)
{ {
_context.SetX(0, r0); _context.SetX(0, r0);
_context.SetX(1, r1); _context.SetX(1, r1);
@ -151,6 +164,8 @@ namespace Ryujinx.Tests.Cpu
SetFpscr((uint)fpscr); SetFpscr((uint)fpscr);
_context.SetPstateFlag(PState.TFlag, thumb);
if (_unicornAvailable) if (_unicornAvailable)
{ {
_unicornEmu.R[0] = r0; _unicornEmu.R[0] = r0;
@ -175,6 +190,8 @@ namespace Ryujinx.Tests.Cpu
_unicornEmu.NegativeFlag = negative; _unicornEmu.NegativeFlag = negative;
_unicornEmu.Fpscr = fpscr; _unicornEmu.Fpscr = fpscr;
_unicornEmu.ThumbFlag = thumb;
} }
} }
@ -218,6 +235,28 @@ namespace Ryujinx.Tests.Cpu
return GetContext(); return GetContext();
} }
protected ExecutionContext SingleThumbOpcode(ushort opcode,
uint r0 = 0,
uint r1 = 0,
uint r2 = 0,
uint r3 = 0,
uint sp = 0,
bool saturation = false,
bool overflow = false,
bool carry = false,
bool zero = false,
bool negative = false,
int fpscr = 0,
bool runUnicorn = true)
{
ThumbOpcode(opcode);
ThumbOpcode(0x4770); // BX LR
SetContext(r0, r1, r2, r3, sp, default, default, default, default, default, default, default, default, saturation, overflow, carry, zero, negative, fpscr, thumb: true);
ExecuteOpcodes(runUnicorn);
return GetContext();
}
protected void SetWorkingMemory(uint offset, byte[] data) protected void SetWorkingMemory(uint offset, byte[] data)
{ {
_memory.Write(DataBaseAddress + offset, data); _memory.Write(DataBaseAddress + offset, data);

File diff suppressed because one or more lines are too long

View File

@ -9,6 +9,8 @@
<TieredCompilation>false</TieredCompilation> <TieredCompilation>false</TieredCompilation>
<TieredCompilationQuickJit>false</TieredCompilationQuickJit> <TieredCompilationQuickJit>false</TieredCompilationQuickJit>
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants> <DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
<!-- As we already provide GTK3 on Windows via GtkSharp.Dependencies this is redundant. -->
<SkipGtkInstall>true</SkipGtkInstall>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''"> <PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
@ -19,7 +21,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DiscordRichPresence" Version="1.0.175" /> <PackageReference Include="DiscordRichPresence" Version="1.0.175" />
<PackageReference Include="GtkSharp" Version="3.22.25.128" /> <PackageReference Include="GtkSharp" Version="3.22.25.128" />
<PackageReference Include="GtkSharp.Dependencies" Version="1.1.0" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="GtkSharp.Dependencies" Version="1.1.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build9" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build9" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="OpenTK.Graphics" Version="4.5.0" /> <PackageReference Include="OpenTK.Graphics" Version="4.5.0" />