Misc cleanup (#708)
* Fix typos * Remove unneeded using statements * Enforce var style more * Remove redundant qualifiers * Fix some indentation * Disable naming warnings on files with external enum names * Fix build * Mass find & replace for comments with no spacing * Standardize todo capitalization and for/if spacing
This commit is contained in:
parent
a250878bfe
commit
25e6a2e0ea
32 changed files with 212 additions and 212 deletions
|
@ -24,8 +24,8 @@ namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
public static Condition Invert(this Condition cond)
|
public static Condition Invert(this Condition cond)
|
||||||
{
|
{
|
||||||
//Bit 0 of all conditions is basically a negation bit, so
|
// Bit 0 of all conditions is basically a negation bit, so
|
||||||
//inverting this bit has the effect of inverting the condition.
|
// inverting this bit has the effect of inverting the condition.
|
||||||
return (Condition)((int)cond ^ 1);
|
return (Condition)((int)cond ^ 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,12 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
if (IsBranch(lastOp) && !IsCall(lastOp) && lastOp is IOpCodeBImm op)
|
if (IsBranch(lastOp) && !IsCall(lastOp) && lastOp is IOpCodeBImm op)
|
||||||
{
|
{
|
||||||
//It's possible that the branch on this block lands on the middle of the block.
|
// It's possible that the branch on this block lands on the middle of the block.
|
||||||
//This is more common on tight loops. In this case, we can improve the codegen
|
// This is more common on tight loops. In this case, we can improve the codegen
|
||||||
//a bit by changing the CFG and either making the branch point to the same block
|
// a bit by changing the CFG and either making the branch point to the same block
|
||||||
//(which indicates that the block is a loop that jumps back to the start), and the
|
// (which indicates that the block is a loop that jumps back to the start), and the
|
||||||
//other possible case is a jump somewhere on the middle of the block, which is
|
// other possible case is a jump somewhere on the middle of the block, which is
|
||||||
//also a loop, but in this case we need to split the block in half.
|
// also a loop, but in this case we need to split the block in half.
|
||||||
if ((ulong)op.Imm == address)
|
if ((ulong)op.Imm == address)
|
||||||
{
|
{
|
||||||
block.Branch = block;
|
block.Branch = block;
|
||||||
|
@ -79,7 +79,7 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
while (workQueue.TryDequeue(out Block currBlock))
|
while (workQueue.TryDequeue(out Block currBlock))
|
||||||
{
|
{
|
||||||
//Check if the current block is inside another block.
|
// Check if the current block is inside another block.
|
||||||
if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex))
|
if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex))
|
||||||
{
|
{
|
||||||
Block nBlock = blocks[nBlkIndex];
|
Block nBlock = blocks[nBlkIndex];
|
||||||
|
@ -96,7 +96,7 @@ namespace ChocolArm64.Decoders
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we have a block after the current one, set the limit address.
|
// If we have a block after the current one, set the limit address.
|
||||||
ulong limitAddress = ulong.MaxValue;
|
ulong limitAddress = ulong.MaxValue;
|
||||||
|
|
||||||
if (nBlkIndex != blocks.Count)
|
if (nBlkIndex != blocks.Count)
|
||||||
|
@ -119,10 +119,10 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
if (currBlock.OpCodes.Count != 0)
|
if (currBlock.OpCodes.Count != 0)
|
||||||
{
|
{
|
||||||
//Set child blocks. "Branch" is the block the branch instruction
|
// Set child blocks. "Branch" is the block the branch instruction
|
||||||
//points to (when taken), "Next" is the block at the next address,
|
// points to (when taken), "Next" is the block at the next address,
|
||||||
//executed when the branch is not taken. For Unconditional Branches
|
// executed when the branch is not taken. For Unconditional Branches
|
||||||
//(except BL/BLR that are sub calls) or end of executable, Next is null.
|
// (except BL/BLR that are sub calls) or end of executable, Next is null.
|
||||||
OpCode64 lastOp = currBlock.GetLastOp();
|
OpCode64 lastOp = currBlock.GetLastOp();
|
||||||
|
|
||||||
bool isCall = IsCall(lastOp);
|
bool isCall = IsCall(lastOp);
|
||||||
|
@ -138,7 +138,7 @@ namespace ChocolArm64.Decoders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Insert the new block on the list (sorted by address).
|
// Insert the new block on the list (sorted by address).
|
||||||
if (blocks.Count != 0)
|
if (blocks.Count != 0)
|
||||||
{
|
{
|
||||||
Block nBlock = blocks[nBlkIndex];
|
Block nBlock = blocks[nBlkIndex];
|
||||||
|
@ -236,25 +236,25 @@ namespace ChocolArm64.Decoders
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Note: On ARM32, most instructions have conditional execution,
|
// Note: On ARM32, most instructions have conditional execution,
|
||||||
//so there's no "Always" (unconditional) branch like on ARM64.
|
// so there's no "Always" (unconditional) branch like on ARM64.
|
||||||
//We need to check if the condition is "Always" instead.
|
// We need to check if the condition is "Always" instead.
|
||||||
return IsAarch32Branch(op) && op.Cond >= Condition.Al;
|
return IsAarch32Branch(op) && op.Cond >= Condition.Al;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsAarch32Branch(OpCode64 opCode)
|
private static bool IsAarch32Branch(OpCode64 opCode)
|
||||||
{
|
{
|
||||||
//Note: On ARM32, most ALU operations can write to R15 (PC),
|
// Note: On ARM32, most ALU operations can write to R15 (PC),
|
||||||
//so we must consider such operations as a branch in potential aswell.
|
// so we must consider such operations as a branch in potential as well.
|
||||||
if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc)
|
if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Same thing for memory operations. We have the cases where PC is a target
|
// Same thing for memory operations. We have the cases where PC is a target
|
||||||
//register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is
|
// register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is
|
||||||
//a write back to PC (wback == true && Rn == 15), however the later may
|
// a write back to PC (wback == true && Rn == 15), however the later may
|
||||||
//be "undefined" depending on the CPU, so compilers should not produce that.
|
// be "undefined" depending on the CPU, so compilers should not produce that.
|
||||||
if (opCode is IOpCode32Mem || opCode is IOpCode32MemMult)
|
if (opCode is IOpCode32Mem || opCode is IOpCode32MemMult)
|
||||||
{
|
{
|
||||||
int rt, rn;
|
int rt, rn;
|
||||||
|
@ -268,8 +268,8 @@ namespace ChocolArm64.Decoders
|
||||||
wBack = opMem.WBack;
|
wBack = opMem.WBack;
|
||||||
isLoad = opMem.IsLoad;
|
isLoad = opMem.IsLoad;
|
||||||
|
|
||||||
//For the dual load, we also need to take into account the
|
// For the dual load, we also need to take into account the
|
||||||
//case were Rt2 == 15 (PC).
|
// case were Rt2 == 15 (PC).
|
||||||
if (rt == 14 && opMem.Emitter == InstEmit32.Ldrd)
|
if (rt == 14 && opMem.Emitter == InstEmit32.Ldrd)
|
||||||
{
|
{
|
||||||
rt = RegisterAlias.Aarch32Pc;
|
rt = RegisterAlias.Aarch32Pc;
|
||||||
|
@ -296,14 +296,14 @@ namespace ChocolArm64.Decoders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Explicit branch instructions.
|
// Explicit branch instructions.
|
||||||
return opCode is IOpCode32BImm ||
|
return opCode is IOpCode32BImm ||
|
||||||
opCode is IOpCode32BReg;
|
opCode is IOpCode32BReg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsCall(OpCode64 opCode)
|
private static bool IsCall(OpCode64 opCode)
|
||||||
{
|
{
|
||||||
//TODO (CQ): ARM32 support.
|
// TODO (CQ): ARM32 support.
|
||||||
return opCode.Emitter == InstEmit.Bl ||
|
return opCode.Emitter == InstEmit.Bl ||
|
||||||
opCode.Emitter == InstEmit.Blr;
|
opCode.Emitter == InstEmit.Blr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
public uint GetPc()
|
public uint GetPc()
|
||||||
{
|
{
|
||||||
//Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline,
|
// Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline,
|
||||||
//the PC actually points 2 instructions ahead.
|
// the PC actually points 2 instructions ahead.
|
||||||
return (uint)Position + (uint)OpCodeSizeInBytes * 2;
|
return (uint)Position + (uint)OpCodeSizeInBytes * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
uint pc = GetPc();
|
uint pc = GetPc();
|
||||||
|
|
||||||
//When the codition is never, the instruction is BLX to Thumb mode.
|
// When the condition is never, the instruction is BLX to Thumb mode.
|
||||||
if (Cond != Condition.Nv)
|
if (Cond != Condition.Nv)
|
||||||
{
|
{
|
||||||
pc &= ~3u;
|
pc &= ~3u;
|
||||||
|
|
|
@ -23,16 +23,16 @@ namespace ChocolArm64.Decoders
|
||||||
Extend64 = ((opCode >> 22) & 3) == 2;
|
Extend64 = ((opCode >> 22) & 3) == 2;
|
||||||
WBack = ((opCode >> 24) & 1) == 0;
|
WBack = ((opCode >> 24) & 1) == 0;
|
||||||
|
|
||||||
//The type is not valid for the Unsigned Immediate 12-bits encoding,
|
// The type is not valid for the Unsigned Immediate 12-bits encoding,
|
||||||
//because the bits 11:10 are used for the larger Immediate offset.
|
// because the bits 11:10 are used for the larger Immediate offset.
|
||||||
MemOp type = WBack ? (MemOp)((opCode >> 10) & 3) : MemOp.Unsigned;
|
MemOp type = WBack ? (MemOp)((opCode >> 10) & 3) : MemOp.Unsigned;
|
||||||
|
|
||||||
PostIdx = type == MemOp.PostIndexed;
|
PostIdx = type == MemOp.PostIndexed;
|
||||||
Unscaled = type == MemOp.Unscaled ||
|
Unscaled = type == MemOp.Unscaled ||
|
||||||
type == MemOp.Unprivileged;
|
type == MemOp.Unprivileged;
|
||||||
|
|
||||||
//Unscaled and Unprivileged doesn't write back,
|
// Unscaled and Unprivileged doesn't write back,
|
||||||
//but they do use the 9-bits Signed Immediate.
|
// but they do use the 9-bits Signed Immediate.
|
||||||
if (Unscaled)
|
if (Unscaled)
|
||||||
{
|
{
|
||||||
WBack = false;
|
WBack = false;
|
||||||
|
@ -40,12 +40,12 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
if (WBack || Unscaled)
|
if (WBack || Unscaled)
|
||||||
{
|
{
|
||||||
//9-bits Signed Immediate.
|
// 9-bits Signed Immediate.
|
||||||
Imm = (opCode << 11) >> 23;
|
Imm = (opCode << 11) >> 23;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//12-bits Unsigned Immediate.
|
// 12-bits Unsigned Immediate.
|
||||||
Imm = ((opCode >> 10) & 0xfff) << Size;
|
Imm = ((opCode >> 10) & 0xfff) << Size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,14 @@ namespace ChocolArm64.Decoders
|
||||||
switch (op | (modeLow << 1))
|
switch (op | (modeLow << 1))
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
//64-bits Immediate.
|
// 64-bits Immediate.
|
||||||
//Transform abcd efgh into abcd efgh abcd efgh ...
|
// Transform abcd efgh into abcd efgh abcd efgh ...
|
||||||
imm = (long)((ulong)imm * 0x0101010101010101);
|
imm = (long)((ulong)imm * 0x0101010101010101);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
//64-bits Immediate.
|
// 64-bits Immediate.
|
||||||
//Transform abcd efgh into aaaa aaaa bbbb bbbb ...
|
// Transform abcd efgh into aaaa aaaa bbbb bbbb ...
|
||||||
imm = (imm & 0xf0) >> 4 | (imm & 0x0f) << 4;
|
imm = (imm & 0xf0) >> 4 | (imm & 0x0f) << 4;
|
||||||
imm = (imm & 0xcc) >> 2 | (imm & 0x33) << 2;
|
imm = (imm & 0xcc) >> 2 | (imm & 0x33) << 2;
|
||||||
imm = (imm & 0xaa) >> 1 | (imm & 0x55) << 1;
|
imm = (imm & 0xaa) >> 1 | (imm & 0x55) << 1;
|
||||||
|
@ -52,29 +52,29 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
//Floating point Immediate.
|
// Floating point Immediate.
|
||||||
imm = DecoderHelper.DecodeImm8Float(imm, Size);
|
imm = DecoderHelper.DecodeImm8Float(imm, Size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((modeHigh & 0b110) == 0b100)
|
else if ((modeHigh & 0b110) == 0b100)
|
||||||
{
|
{
|
||||||
//16-bits shifted Immediate.
|
// 16-bits shifted Immediate.
|
||||||
Size = 1; imm <<= (modeHigh & 1) << 3;
|
Size = 1; imm <<= (modeHigh & 1) << 3;
|
||||||
}
|
}
|
||||||
else if ((modeHigh & 0b100) == 0b000)
|
else if ((modeHigh & 0b100) == 0b000)
|
||||||
{
|
{
|
||||||
//32-bits shifted Immediate.
|
// 32-bits shifted Immediate.
|
||||||
Size = 2; imm <<= modeHigh << 3;
|
Size = 2; imm <<= modeHigh << 3;
|
||||||
}
|
}
|
||||||
else if ((modeHigh & 0b111) == 0b110)
|
else if ((modeHigh & 0b111) == 0b110)
|
||||||
{
|
{
|
||||||
//32-bits shifted Immediate (fill with ones).
|
// 32-bits shifted Immediate (fill with ones).
|
||||||
Size = 2; imm = ShlOnes(imm, 8 << modeLow);
|
Size = 2; imm = ShlOnes(imm, 8 << modeLow);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//8 bits without shift.
|
// 8 bits without shift.
|
||||||
Size = 0;
|
Size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace ChocolArm64.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.EmitLdint(InstEmit32Helper.GetRegisterAlias(context.Mode, register));
|
context.EmitLdint(GetRegisterAlias(context.Mode, register));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void Extr(ILEmitterCtx context)
|
public static void Extr(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//TODO: Ensure that the Shift is valid for the Is64Bits.
|
// TODO: Ensure that the Shift is valid for the Is64Bits.
|
||||||
OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp;
|
OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp;
|
||||||
|
|
||||||
context.EmitLdintzr(op.Rm);
|
context.EmitLdintzr(op.Rm);
|
||||||
|
@ -309,7 +309,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void EmitDiv(ILEmitterCtx context, OpCode ilOp)
|
private static void EmitDiv(ILEmitterCtx context, OpCode ilOp)
|
||||||
{
|
{
|
||||||
//If Rm == 0, Rd = 0 (division by zero).
|
// If Rm == 0, Rd = 0 (division by zero).
|
||||||
context.EmitLdc_I(0);
|
context.EmitLdc_I(0);
|
||||||
|
|
||||||
EmitAluLoadRm(context);
|
EmitAluLoadRm(context);
|
||||||
|
@ -323,7 +323,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
if (ilOp == OpCodes.Div)
|
if (ilOp == OpCodes.Div)
|
||||||
{
|
{
|
||||||
//If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow).
|
// If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow).
|
||||||
long intMin = 1L << (context.CurrOp.GetBitsCount() - 1);
|
long intMin = 1L << (context.CurrOp.GetBitsCount() - 1);
|
||||||
|
|
||||||
context.EmitLdc_I(intMin);
|
context.EmitLdc_I(intMin);
|
||||||
|
@ -381,10 +381,10 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.And);
|
context.Emit(OpCodes.And);
|
||||||
|
|
||||||
//Note: Only 32-bits shift values are valid, so when the value is 64-bits
|
// Note: Only 32-bits shift values are valid, so when the value is 64-bits
|
||||||
//we need to cast it to a 32-bits integer. This is fine because we
|
// we need to cast it to a 32-bits integer. This is fine because we
|
||||||
//AND the value and only keep the lower 5 or 6 bits anyway -- it
|
// AND the value and only keep the lower 5 or 6 bits anyway -- it
|
||||||
//could very well fit on a byte.
|
// could very well fit on a byte.
|
||||||
if (context.CurrOp.RegisterSize != RegisterSize.Int32)
|
if (context.CurrOp.RegisterSize != RegisterSize.Int32)
|
||||||
{
|
{
|
||||||
context.Emit(OpCodes.Conv_I4);
|
context.Emit(OpCodes.Conv_I4);
|
||||||
|
|
|
@ -87,7 +87,7 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
if (op.SetFlags)
|
if (op.SetFlags)
|
||||||
{
|
{
|
||||||
//TODO: Load SPSR etc.
|
// TODO: Load SPSR etc.
|
||||||
|
|
||||||
context.EmitLdflg((int)PState.TBit);
|
context.EmitLdflg((int)PState.TBit);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
public static void EmitAdcsCCheck(ILEmitterCtx context)
|
public static void EmitAdcsCCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//C = (Rd == Rn && CIn) || Rd < Rn
|
// C = (Rd == Rn && CIn) || Rd < Rn
|
||||||
context.EmitSttmp();
|
context.EmitSttmp();
|
||||||
context.EmitLdtmp();
|
context.EmitLdtmp();
|
||||||
context.EmitLdtmp();
|
context.EmitLdtmp();
|
||||||
|
@ -35,7 +35,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void EmitAddsCCheck(ILEmitterCtx context)
|
public static void EmitAddsCCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//C = Rd < Rn
|
// C = Rd < Rn
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
EmitAluLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
@ -47,7 +47,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void EmitAddsVCheck(ILEmitterCtx context)
|
public static void EmitAddsVCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
|
// V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
EmitAluLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
@ -69,7 +69,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void EmitSbcsCCheck(ILEmitterCtx context)
|
public static void EmitSbcsCCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//C = (Rn == Rm && CIn) || Rn > Rm
|
// C = (Rn == Rm && CIn) || Rn > Rm
|
||||||
EmitAluLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Ceq);
|
context.Emit(OpCodes.Ceq);
|
||||||
|
@ -88,7 +88,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void EmitSubsCCheck(ILEmitterCtx context)
|
public static void EmitSubsCCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
|
// C = Rn == Rm || Rn > Rm = !(Rn < Rm)
|
||||||
EmitAluLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Clt_Un);
|
context.Emit(OpCodes.Clt_Un);
|
||||||
|
@ -102,7 +102,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void EmitSubsVCheck(ILEmitterCtx context)
|
public static void EmitSubsVCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//V = (Rd ^ Rn) & (Rn ^ Rm) < 0
|
// V = (Rd ^ Rn) & (Rn ^ Rm) < 0
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
EmitAluLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
@ -170,7 +170,7 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
switch (context.CurrOp)
|
switch (context.CurrOp)
|
||||||
{
|
{
|
||||||
//ARM32.
|
// ARM32.
|
||||||
case OpCode32AluImm op:
|
case OpCode32AluImm op:
|
||||||
context.EmitLdc_I4(op.Imm);
|
context.EmitLdc_I4(op.Imm);
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ namespace ChocolArm64.Instructions
|
||||||
context.EmitLdc_I4(op.Imm);
|
context.EmitLdc_I4(op.Imm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//ARM64.
|
// ARM64.
|
||||||
case IOpCodeAluImm64 op:
|
case IOpCodeAluImm64 op:
|
||||||
context.EmitLdc_I(op.Imm);
|
context.EmitLdc_I(op.Imm);
|
||||||
break;
|
break;
|
||||||
|
@ -245,7 +245,7 @@ namespace ChocolArm64.Instructions
|
||||||
context.EmitStflg((int)PState.NBit);
|
context.EmitStflg((int)PState.NBit);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ARM32 helpers.
|
// ARM32 helpers.
|
||||||
private static void EmitLoadRmShiftedByImmediate(ILEmitterCtx context, OpCode32AluRsImm op, bool setCarry)
|
private static void EmitLoadRmShiftedByImmediate(ILEmitterCtx context, OpCode32AluRsImm op, bool setCarry)
|
||||||
{
|
{
|
||||||
int shift = op.Imm;
|
int shift = op.Imm;
|
||||||
|
@ -432,7 +432,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void EmitRrxC(ILEmitterCtx context, bool setCarry)
|
private static void EmitRrxC(ILEmitterCtx context, bool setCarry)
|
||||||
{
|
{
|
||||||
//Rotate right by 1 with carry.
|
// Rotate right by 1 with carry.
|
||||||
if (setCarry)
|
if (setCarry)
|
||||||
{
|
{
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
if (op.Pos < op.Shift)
|
if (op.Pos < op.Shift)
|
||||||
{
|
{
|
||||||
//BFI.
|
// BFI.
|
||||||
context.EmitLdintzr(op.Rn);
|
context.EmitLdintzr(op.Rn);
|
||||||
|
|
||||||
int shift = op.GetBitsCount() - op.Shift;
|
int shift = op.GetBitsCount() - op.Shift;
|
||||||
|
@ -39,7 +39,7 @@ namespace ChocolArm64.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//BFXIL.
|
// BFXIL.
|
||||||
context.EmitLdintzr(op.Rn);
|
context.EmitLdintzr(op.Rn);
|
||||||
|
|
||||||
context.EmitLsr(op.Shift);
|
context.EmitLsr(op.Shift);
|
||||||
|
|
|
@ -31,8 +31,8 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitPrivateCall(typeof(CpuThreadState), mthdName);
|
context.EmitPrivateCall(typeof(CpuThreadState), mthdName);
|
||||||
|
|
||||||
//Check if the thread should still be running, if it isn't then we return 0
|
// Check if the thread should still be running, if it isn't then we return 0
|
||||||
//to force a return to the dispatcher and then exit the thread.
|
// to force a return to the dispatcher and then exit the thread.
|
||||||
context.EmitLdarg(TranslatedSub.StateArgIdx);
|
context.EmitLdarg(TranslatedSub.StateArgIdx);
|
||||||
|
|
||||||
context.EmitCallPropGet(typeof(CpuThreadState), nameof(CpuThreadState.Running));
|
context.EmitCallPropGet(typeof(CpuThreadState), nameof(CpuThreadState.Running));
|
||||||
|
|
|
@ -66,8 +66,8 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitStint(GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr));
|
context.EmitStint(GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr));
|
||||||
|
|
||||||
//If x is true, then this is a branch with link and exchange.
|
// If x is true, then this is a branch with link and exchange.
|
||||||
//In this case we need to swap the mode between Arm <-> Thumb.
|
// In this case we need to swap the mode between Arm <-> Thumb.
|
||||||
if (x)
|
if (x)
|
||||||
{
|
{
|
||||||
context.EmitLdc_I4(isThumb ? 0 : 1);
|
context.EmitLdc_I4(isThumb ? 0 : 1);
|
||||||
|
|
|
@ -90,10 +90,10 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
if (isJump)
|
if (isJump)
|
||||||
{
|
{
|
||||||
//The tail prefix allows the JIT to jump to the next function,
|
// The tail prefix allows the JIT to jump to the next function,
|
||||||
//while releasing the stack space used by the current one.
|
// while releasing the stack space used by the current one.
|
||||||
//This is ideal for BR ARM instructions, which are
|
// This is ideal for BR ARM instructions, which are
|
||||||
//basically indirect tail calls.
|
// basically indirect tail calls.
|
||||||
context.Emit(OpCodes.Tailcall);
|
context.Emit(OpCodes.Tailcall);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,10 +114,10 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void EmitContinueOrReturnCheck(ILEmitterCtx context)
|
private static void EmitContinueOrReturnCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//Note: The return value of the called method will be placed
|
// Note: The return value of the called method will be placed
|
||||||
//at the Stack, the return value is always a Int64 with the
|
// at the Stack, the return value is always a Int64 with the
|
||||||
//return address of the function. We check if the address is
|
// return address of the function. We check if the address is
|
||||||
//correct, if it isn't we keep returning until we reach the dispatcher.
|
// correct, if it isn't we keep returning until we reach the dispatcher.
|
||||||
if (context.CurrBlock.Next != null)
|
if (context.CurrBlock.Next != null)
|
||||||
{
|
{
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
|
@ -192,7 +192,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
if (!op.PostIdx)
|
if (!op.PostIdx)
|
||||||
{
|
{
|
||||||
//Pre-indexing.
|
// Pre-indexing.
|
||||||
context.EmitLdc_I(op.Imm);
|
context.EmitLdc_I(op.Imm);
|
||||||
|
|
||||||
context.Emit(OpCodes.Add);
|
context.Emit(OpCodes.Add);
|
||||||
|
@ -213,7 +213,7 @@ namespace ChocolArm64.Instructions
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save address to Scratch var since the register value may change.
|
// Save address to Scratch var since the register value may change.
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
context.EmitSttmp();
|
context.EmitSttmp();
|
||||||
|
@ -221,8 +221,8 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void EmitWBackIfNeeded(ILEmitterCtx context)
|
private static void EmitWBackIfNeeded(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//Check whenever the current OpCode has post-indexed write back, if so write it.
|
// Check whenever the current OpCode has post-indexed write back, if so write it.
|
||||||
//Note: AOpCodeMemPair inherits from AOpCodeMemImm, so this works for both.
|
// Note: AOpCodeMemPair inherits from AOpCodeMemImm, so this works for both.
|
||||||
if (context.CurrOp is OpCodeMemImm64 op && op.WBack)
|
if (context.CurrOp is OpCodeMemImm64 op && op.WBack)
|
||||||
{
|
{
|
||||||
context.EmitLdtmp();
|
context.EmitLdtmp();
|
||||||
|
|
|
@ -137,15 +137,15 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
EmitWriteCall(context, WordSizeLog2);
|
EmitWriteCall(context, WordSizeLog2);
|
||||||
|
|
||||||
//Note: If Rn is also specified on the register list,
|
// Note: If Rn is also specified on the register list,
|
||||||
//and Rn is the first register on this list, then the
|
// and Rn is the first register on this list, then the
|
||||||
//value that is written to memory is the unmodified value,
|
// value that is written to memory is the unmodified value,
|
||||||
//before the write back. If it is on the list, but it's
|
// before the write back. If it is on the list, but it's
|
||||||
//not the first one, then the value written to memory
|
// not the first one, then the value written to memory
|
||||||
//varies between CPUs.
|
// varies between CPUs.
|
||||||
if (offset == 0 && op.PostOffset != 0)
|
if (offset == 0 && op.PostOffset != 0)
|
||||||
{
|
{
|
||||||
//Emit write back after the first write.
|
// Emit write back after the first write.
|
||||||
EmitLoadFromRegister(context, op.Rn);
|
EmitLoadFromRegister(context, op.Rn);
|
||||||
|
|
||||||
context.EmitLdc_I4(op.PostOffset);
|
context.EmitLdc_I4(op.PostOffset);
|
||||||
|
@ -233,7 +233,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.Brtrue_S, lblBigEndian);
|
context.Emit(OpCodes.Brtrue_S, lblBigEndian);
|
||||||
|
|
||||||
//Little endian mode.
|
// Little endian mode.
|
||||||
context.Emit(OpCodes.Conv_U4);
|
context.Emit(OpCodes.Conv_U4);
|
||||||
|
|
||||||
EmitStoreToRegister(context, op.Rt);
|
EmitStoreToRegister(context, op.Rt);
|
||||||
|
@ -246,7 +246,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.Br_S, lblEnd);
|
context.Emit(OpCodes.Br_S, lblEnd);
|
||||||
|
|
||||||
//Big endian mode.
|
// Big endian mode.
|
||||||
context.MarkLabel(lblBigEndian);
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
context.EmitLsr(32);
|
context.EmitLsr(32);
|
||||||
|
@ -288,7 +288,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.Brtrue_S, lblBigEndian);
|
context.Emit(OpCodes.Brtrue_S, lblBigEndian);
|
||||||
|
|
||||||
//Little endian mode.
|
// Little endian mode.
|
||||||
EmitLoadFromRegister(context, op.Rt | 1);
|
EmitLoadFromRegister(context, op.Rt | 1);
|
||||||
|
|
||||||
context.Emit(OpCodes.Conv_U8);
|
context.Emit(OpCodes.Conv_U8);
|
||||||
|
@ -299,7 +299,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.Br_S, lblEnd);
|
context.Emit(OpCodes.Br_S, lblEnd);
|
||||||
|
|
||||||
//Big endian mode.
|
// Big endian mode.
|
||||||
context.MarkLabel(lblBigEndian);
|
context.MarkLabel(lblBigEndian);
|
||||||
|
|
||||||
context.EmitLsl(32);
|
context.EmitLsl(32);
|
||||||
|
|
|
@ -89,10 +89,10 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
if (pair)
|
if (pair)
|
||||||
{
|
{
|
||||||
//Exclusive loads should be atomic. For pairwise loads, we need to
|
// Exclusive loads should be atomic. For pairwise loads, we need to
|
||||||
//read all the data at once. For a 32-bits pairwise load, we do a
|
// read all the data at once. For a 32-bits pairwise load, we do a
|
||||||
//simple 64-bits load, for a 128-bits load, we need to call a special
|
// simple 64-bits load, for a 128-bits load, we need to call a special
|
||||||
//method to read 128-bits atomically.
|
// method to read 128-bits atomically.
|
||||||
if (op.Size == 2)
|
if (op.Size == 2)
|
||||||
{
|
{
|
||||||
context.EmitLdtmp();
|
context.EmitLdtmp();
|
||||||
|
@ -101,7 +101,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
//Mask low half.
|
// Mask low half.
|
||||||
context.Emit(OpCodes.Conv_U4);
|
context.Emit(OpCodes.Conv_U4);
|
||||||
|
|
||||||
if (exclusive)
|
if (exclusive)
|
||||||
|
@ -111,7 +111,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitStintzr(op.Rt);
|
context.EmitStintzr(op.Rt);
|
||||||
|
|
||||||
//Shift high half.
|
// Shift high half.
|
||||||
context.EmitLsr(32);
|
context.EmitLsr(32);
|
||||||
context.Emit(OpCodes.Conv_U4);
|
context.Emit(OpCodes.Conv_U4);
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
//Load low part of the vector.
|
// Load low part of the vector.
|
||||||
context.EmitLdc_I4(0);
|
context.EmitLdc_I4(0);
|
||||||
context.EmitLdc_I4(3);
|
context.EmitLdc_I4(3);
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitStintzr(op.Rt);
|
context.EmitStintzr(op.Rt);
|
||||||
|
|
||||||
//Load high part of the vector.
|
// Load high part of the vector.
|
||||||
context.EmitLdc_I4(1);
|
context.EmitLdc_I4(1);
|
||||||
context.EmitLdc_I4(3);
|
context.EmitLdc_I4(3);
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ namespace ChocolArm64.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//8, 16, 32 or 64-bits (non-pairwise) load.
|
// 8, 16, 32 or 64-bits (non-pairwise) load.
|
||||||
context.EmitLdtmp();
|
context.EmitLdtmp();
|
||||||
|
|
||||||
EmitReadZxCall(context, op.Size);
|
EmitReadZxCall(context, op.Size);
|
||||||
|
@ -180,7 +180,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void Pfrm(ILEmitterCtx context)
|
public static void Pfrm(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//Memory Prefetch, execute as no-op.
|
// Memory Prefetch, execute as no-op.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Stlr(ILEmitterCtx context) => EmitStr(context, AccessType.Ordered);
|
public static void Stlr(ILEmitterCtx context) => EmitStr(context, AccessType.Ordered);
|
||||||
|
@ -223,13 +223,13 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.Brtrue_S, lblEx);
|
context.Emit(OpCodes.Brtrue_S, lblEx);
|
||||||
|
|
||||||
//Address check failed, set error right away and do not store anything.
|
// Address check failed, set error right away and do not store anything.
|
||||||
context.EmitLdc_I4(1);
|
context.EmitLdc_I4(1);
|
||||||
context.EmitStintzr(op.Rs);
|
context.EmitStintzr(op.Rs);
|
||||||
|
|
||||||
context.Emit(OpCodes.Br, lblEnd);
|
context.Emit(OpCodes.Br, lblEnd);
|
||||||
|
|
||||||
//Address check passsed.
|
// Address check passed.
|
||||||
context.MarkLabel(lblEx);
|
context.MarkLabel(lblEx);
|
||||||
|
|
||||||
context.EmitLdarg(TranslatedSub.MemoryArgIdx);
|
context.EmitLdarg(TranslatedSub.MemoryArgIdx);
|
||||||
|
@ -241,7 +241,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
void EmitCast()
|
void EmitCast()
|
||||||
{
|
{
|
||||||
//The input should be always int64.
|
// The input should be always int64.
|
||||||
switch (op.Size)
|
switch (op.Size)
|
||||||
{
|
{
|
||||||
case 0: context.Emit(OpCodes.Conv_U1); break;
|
case 0: context.Emit(OpCodes.Conv_U1); break;
|
||||||
|
@ -293,10 +293,10 @@ namespace ChocolArm64.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//The value returned is a bool, true if the values compared
|
// The value returned is a bool, true if the values compared
|
||||||
//were equal and the new value was written, false otherwise.
|
// were equal and the new value was written, false otherwise.
|
||||||
//We need to invert this result, as on ARM 1 indicates failure,
|
// We need to invert this result, as on ARM 1 indicates failure,
|
||||||
//and 0 success on those instructions.
|
// and 0 success on those instructions.
|
||||||
context.EmitLdc_I4(1);
|
context.EmitLdc_I4(1);
|
||||||
|
|
||||||
context.Emit(OpCodes.Xor);
|
context.Emit(OpCodes.Xor);
|
||||||
|
@ -305,7 +305,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitStintzr(op.Rs);
|
context.EmitStintzr(op.Rs);
|
||||||
|
|
||||||
//Only clear the exclusive monitor if the store was successful (Rs = false).
|
// Only clear the exclusive monitor if the store was successful (Rs = false).
|
||||||
context.Emit(OpCodes.Brtrue_S, lblEnd);
|
context.Emit(OpCodes.Brtrue_S, lblEnd);
|
||||||
|
|
||||||
Clrex(context);
|
Clrex(context);
|
||||||
|
@ -341,9 +341,9 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void EmitBarrier(ILEmitterCtx context)
|
private static void EmitBarrier(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//Note: This barrier is most likely not necessary, and probably
|
// Note: This barrier is most likely not necessary, and probably
|
||||||
//doesn't make any difference since we need to do a ton of stuff
|
// doesn't make any difference since we need to do a ton of stuff
|
||||||
//(software MMU emulation) to read or write anything anyway.
|
// (software MMU emulation) to read or write anything anyway.
|
||||||
context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier));
|
context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void EmitReadCall(ILEmitterCtx context, Extension ext, int size)
|
private static void EmitReadCall(ILEmitterCtx context, Extension ext, int size)
|
||||||
{
|
{
|
||||||
//Save the address into a temp.
|
// Save the address into a temp.
|
||||||
context.EmitStint(_tempIntAddress);
|
context.EmitStint(_tempIntAddress);
|
||||||
|
|
||||||
bool isSimd = IsSimd(context);
|
bool isSimd = IsSimd(context);
|
||||||
|
@ -99,7 +99,7 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
bool isSimd = IsSimd(context);
|
bool isSimd = IsSimd(context);
|
||||||
|
|
||||||
//Save the value into a temp.
|
// Save the value into a temp.
|
||||||
if (isSimd)
|
if (isSimd)
|
||||||
{
|
{
|
||||||
context.EmitStvec(_tempVecValue);
|
context.EmitStvec(_tempVecValue);
|
||||||
|
@ -109,7 +109,7 @@ namespace ChocolArm64.Instructions
|
||||||
context.EmitStint(_tempIntValue);
|
context.EmitStint(_tempIntValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Save the address into a temp.
|
// Save the address into a temp.
|
||||||
context.EmitStint(_tempIntAddress);
|
context.EmitStint(_tempIntAddress);
|
||||||
|
|
||||||
if (size < 0 || size > (isSimd ? 4 : 3))
|
if (size < 0 || size > (isSimd ? 4 : 3))
|
||||||
|
|
|
@ -1298,8 +1298,8 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
if (Optimizations.UseSse41 && size == 0)
|
if (Optimizations.UseSse41 && size == 0)
|
||||||
{
|
{
|
||||||
//If the type is float, we can perform insertion and
|
// If the type is float, we can perform insertion and
|
||||||
//zero the upper bits with a single instruction (INSERTPS);
|
// zero the upper bits with a single instruction (INSERTPS);
|
||||||
context.EmitLdvec(reg);
|
context.EmitLdvec(reg);
|
||||||
|
|
||||||
VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41VectorInsertScalarSingle));
|
VectorHelper.EmitCall(context, nameof(VectorHelper.Sse41VectorInsertScalarSingle));
|
||||||
|
|
|
@ -96,7 +96,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
if (op.Replicate)
|
if (op.Replicate)
|
||||||
{
|
{
|
||||||
//Only loads uses the replicate mode.
|
// Only loads uses the replicate mode.
|
||||||
if (!isLoad)
|
if (!isLoad)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
|
|
|
@ -11,12 +11,12 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
public static void Hint(ILEmitterCtx context)
|
public static void Hint(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//Execute as no-op.
|
// Execute as no-op.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Isb(ILEmitterCtx context)
|
public static void Isb(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//Execute as no-op.
|
// Execute as no-op.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mrs(ILEmitterCtx context)
|
public static void Mrs(ILEmitterCtx context)
|
||||||
|
@ -85,21 +85,21 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void Nop(ILEmitterCtx context)
|
public static void Nop(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sys(ILEmitterCtx context)
|
public static void Sys(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//This instruction is used to do some operations on the CPU like cache invalidation,
|
// This instruction is used to do some operations on the CPU like cache invalidation,
|
||||||
//address translation and the like.
|
// address translation and the like.
|
||||||
//We treat it as no-op here since we don't have any cache being emulated anyway.
|
// We treat it as no-op here since we don't have any cache being emulated anyway.
|
||||||
OpCodeSystem64 op = (OpCodeSystem64)context.CurrOp;
|
OpCodeSystem64 op = (OpCodeSystem64)context.CurrOp;
|
||||||
|
|
||||||
switch (GetPackedId(op))
|
switch (GetPackedId(op))
|
||||||
{
|
{
|
||||||
case 0b11_011_0111_0100_001:
|
case 0b11_011_0111_0100_001:
|
||||||
{
|
{
|
||||||
//DC ZVA
|
// DC ZVA
|
||||||
for (int offs = 0; offs < (4 << CpuThreadState.DczSizeLog2); offs += 8)
|
for (int offs = 0; offs < (4 << CpuThreadState.DczSizeLog2); offs += 8)
|
||||||
{
|
{
|
||||||
context.EmitLdintzr(op.Rt);
|
context.EmitLdintzr(op.Rt);
|
||||||
|
@ -115,7 +115,7 @@ namespace ChocolArm64.Instructions
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//No-op
|
// No-op
|
||||||
case 0b11_011_0111_1110_001: //DC CIVAC
|
case 0b11_011_0111_1110_001: //DC CIVAC
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -583,9 +583,9 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
if (Sse41.IsSupported)
|
if (Sse41.IsSupported)
|
||||||
{
|
{
|
||||||
//Note: The if/else if is necessary to enable the JIT to
|
// Note: The if/else if is necessary to enable the JIT to
|
||||||
//produce a single INSERTPS instruction instead of the
|
// produce a single INSERTPS instruction instead of the
|
||||||
//jump table fallback.
|
// jump table fallback.
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
{
|
{
|
||||||
return Sse41.Insert(vector, value, 0x00);
|
return Sse41.Insert(vector, value, 0x00);
|
||||||
|
@ -628,7 +628,7 @@ namespace ChocolArm64.Instructions
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Vector128<float> Sse41VectorInsertScalarSingle(float value, Vector128<float> vector)
|
public static Vector128<float> Sse41VectorInsertScalarSingle(float value, Vector128<float> vector)
|
||||||
{
|
{
|
||||||
//Note: 0b1110 is the mask to zero the upper bits.
|
// Note: 0b1110 is the mask to zero the upper bits.
|
||||||
return Sse41.Insert(vector, value, 0b1110);
|
return Sse41.Insert(vector, value, 0b1110);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,9 +96,9 @@ namespace ChocolArm64.Memory
|
||||||
IntPtr[] addresses,
|
IntPtr[] addresses,
|
||||||
out ulong count)
|
out ulong count)
|
||||||
{
|
{
|
||||||
//This is only supported on windows, but returning
|
// This is only supported on windows, but returning
|
||||||
//false (failed) is also valid for platforms without
|
// false (failed) is also valid for platforms without
|
||||||
//write tracking support on the OS.
|
// write tracking support on the OS.
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
return MemoryManagementWindows.GetModifiedPages(address, size, addresses, out count);
|
return MemoryManagementWindows.GetModifiedPages(address, size, addresses, out count);
|
||||||
|
|
|
@ -30,22 +30,22 @@ namespace ChocolArm64.Memory
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Reprotect(IntPtr address, ulong size, Memory.MemoryProtection protection)
|
public static bool Reprotect(IntPtr address, ulong size, MemoryProtection protection)
|
||||||
{
|
{
|
||||||
MmapProts prot = GetProtection(protection);
|
MmapProts prot = GetProtection(protection);
|
||||||
|
|
||||||
return Syscall.mprotect(address, size, prot) == 0;
|
return Syscall.mprotect(address, size, prot) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MmapProts GetProtection(Memory.MemoryProtection protection)
|
private static MmapProts GetProtection(MemoryProtection protection)
|
||||||
{
|
{
|
||||||
switch (protection)
|
switch (protection)
|
||||||
{
|
{
|
||||||
case Memory.MemoryProtection.None: return MmapProts.PROT_NONE;
|
case MemoryProtection.None: return MmapProts.PROT_NONE;
|
||||||
case Memory.MemoryProtection.Read: return MmapProts.PROT_READ;
|
case MemoryProtection.Read: return MmapProts.PROT_READ;
|
||||||
case Memory.MemoryProtection.ReadAndWrite: return MmapProts.PROT_READ | MmapProts.PROT_WRITE;
|
case MemoryProtection.ReadAndWrite: return MmapProts.PROT_READ | MmapProts.PROT_WRITE;
|
||||||
case Memory.MemoryProtection.ReadAndExecute: return MmapProts.PROT_READ | MmapProts.PROT_EXEC;
|
case MemoryProtection.ReadAndExecute: return MmapProts.PROT_READ | MmapProts.PROT_EXEC;
|
||||||
case Memory.MemoryProtection.Execute: return MmapProts.PROT_EXEC;
|
case MemoryProtection.Execute: return MmapProts.PROT_EXEC;
|
||||||
|
|
||||||
default: throw new ArgumentException($"Invalid permission \"{protection}\".");
|
default: throw new ArgumentException($"Invalid permission \"{protection}\".");
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,12 +50,12 @@ namespace ChocolArm64.Memory
|
||||||
AddressSpaceBits = addressSpaceBits;
|
AddressSpaceBits = addressSpaceBits;
|
||||||
AddressSpaceSize = 1L << addressSpaceBits;
|
AddressSpaceSize = 1L << addressSpaceBits;
|
||||||
|
|
||||||
//When flat page table is requested, we use a single
|
// When flat page table is requested, we use a single
|
||||||
//array for the mappings of the entire address space.
|
// array for the mappings of the entire address space.
|
||||||
//This has better performance, but also high memory usage.
|
// This has better performance, but also high memory usage.
|
||||||
//The multi level page table uses 9 bits per level, so
|
// The multi level page table uses 9 bits per level, so
|
||||||
//the memory usage is lower, but the performance is also
|
// the memory usage is lower, but the performance is also
|
||||||
//lower, since each address translation requires multiple reads.
|
// lower, since each address translation requires multiple reads.
|
||||||
if (useFlatPageTable)
|
if (useFlatPageTable)
|
||||||
{
|
{
|
||||||
PtLevelBits = addressSpaceBits - PageBits;
|
PtLevelBits = addressSpaceBits - PageBits;
|
||||||
|
@ -237,13 +237,13 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
if (nextPtr == IntPtr.Zero)
|
if (nextPtr == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
//Entry does not yet exist, allocate a new one.
|
// Entry does not yet exist, allocate a new one.
|
||||||
IntPtr newPtr = Allocate((ulong)(PtLevelSize * IntPtr.Size));
|
IntPtr newPtr = Allocate((ulong)(PtLevelSize * IntPtr.Size));
|
||||||
|
|
||||||
//Try to swap the current pointer (should be zero), with the allocated one.
|
// Try to swap the current pointer (should be zero), with the allocated one.
|
||||||
nextPtr = Interlocked.Exchange(ref *ptePtr, newPtr);
|
nextPtr = Interlocked.Exchange(ref *ptePtr, newPtr);
|
||||||
|
|
||||||
//If the old pointer is not null, then another thread already has set it.
|
// If the old pointer is not null, then another thread already has set it.
|
||||||
if (nextPtr != IntPtr.Zero)
|
if (nextPtr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Free(newPtr);
|
Free(newPtr);
|
||||||
|
@ -533,7 +533,7 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
private void AbortWithAlignmentFault(long position)
|
private void AbortWithAlignmentFault(long position)
|
||||||
{
|
{
|
||||||
//TODO: Abort mode and exception support on the CPU.
|
// TODO: Abort mode and exception support on the CPU.
|
||||||
throw new InvalidOperationException($"Tried to compare exchange a misaligned address 0x{position:X16}.");
|
throw new InvalidOperationException($"Tried to compare exchange a misaligned address 0x{position:X16}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,7 +726,7 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
public void ReadBytes(long position, byte[] data, int startIndex, int size)
|
public void ReadBytes(long position, byte[] data, int startIndex, int size)
|
||||||
{
|
{
|
||||||
//Note: This will be moved later.
|
// Note: This will be moved later.
|
||||||
long endAddr = position + size;
|
long endAddr = position + size;
|
||||||
|
|
||||||
if ((ulong)size > int.MaxValue)
|
if ((ulong)size > int.MaxValue)
|
||||||
|
@ -924,7 +924,7 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
public void WriteBytes(long position, byte[] data, int startIndex, int size)
|
public void WriteBytes(long position, byte[] data, int startIndex, int size)
|
||||||
{
|
{
|
||||||
//Note: This will be moved later.
|
// Note: This will be moved later.
|
||||||
long endAddr = position + size;
|
long endAddr = position + size;
|
||||||
|
|
||||||
if ((ulong)endAddr < (ulong)position)
|
if ((ulong)endAddr < (ulong)position)
|
||||||
|
@ -954,7 +954,7 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
public void CopyBytes(long src, long dst, long size)
|
public void CopyBytes(long src, long dst, long size)
|
||||||
{
|
{
|
||||||
//Note: This will be moved later.
|
// Note: This will be moved later.
|
||||||
if (IsContiguous(src, size) &&
|
if (IsContiguous(src, size) &&
|
||||||
IsContiguous(dst, size))
|
IsContiguous(dst, size))
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace ChocolArm64
|
||||||
static OpCodeTable()
|
static OpCodeTable()
|
||||||
{
|
{
|
||||||
#region "OpCode Table (AArch32)"
|
#region "OpCode Table (AArch32)"
|
||||||
//Integer
|
// Integer
|
||||||
SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Add, typeof(OpCode32AluImm));
|
SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Add, typeof(OpCode32AluImm));
|
||||||
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Add, typeof(OpCode32AluRsImm));
|
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Add, typeof(OpCode32AluRsImm));
|
||||||
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.B, typeof(OpCode32BImm));
|
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.B, typeof(OpCode32BImm));
|
||||||
|
@ -66,7 +66,7 @@ namespace ChocolArm64
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "OpCode Table (AArch64)"
|
#region "OpCode Table (AArch64)"
|
||||||
//Integer
|
// Integer
|
||||||
SetA64("x0011010000xxxxx000000xxxxxxxxxx", InstEmit.Adc, typeof(OpCodeAluRs64));
|
SetA64("x0011010000xxxxx000000xxxxxxxxxx", InstEmit.Adc, typeof(OpCodeAluRs64));
|
||||||
SetA64("x0111010000xxxxx000000xxxxxxxxxx", InstEmit.Adcs, typeof(OpCodeAluRs64));
|
SetA64("x0111010000xxxxx000000xxxxxxxxxx", InstEmit.Adcs, typeof(OpCodeAluRs64));
|
||||||
SetA64("x00100010xxxxxxxxxxxxxxxxxxxxxxx", InstEmit.Add, typeof(OpCodeAluImm64));
|
SetA64("x00100010xxxxxxxxxxxxxxxxxxxxxxx", InstEmit.Add, typeof(OpCodeAluImm64));
|
||||||
|
@ -217,7 +217,7 @@ namespace ChocolArm64
|
||||||
SetA64("10011011101xxxxx1xxxxxxxxxxxxxxx", InstEmit.Umsubl, typeof(OpCodeMul64));
|
SetA64("10011011101xxxxx1xxxxxxxxxxxxxxx", InstEmit.Umsubl, typeof(OpCodeMul64));
|
||||||
SetA64("10011011110xxxxx0xxxxxxxxxxxxxxx", InstEmit.Umulh, typeof(OpCodeMul64));
|
SetA64("10011011110xxxxx0xxxxxxxxxxxxxxx", InstEmit.Umulh, typeof(OpCodeMul64));
|
||||||
|
|
||||||
//Vector
|
// Vector
|
||||||
SetA64("0101111011100000101110xxxxxxxxxx", InstEmit.Abs_S, typeof(OpCodeSimd64));
|
SetA64("0101111011100000101110xxxxxxxxxx", InstEmit.Abs_S, typeof(OpCodeSimd64));
|
||||||
SetA64("0>001110<<100000101110xxxxxxxxxx", InstEmit.Abs_V, typeof(OpCodeSimd64));
|
SetA64("0>001110<<100000101110xxxxxxxxxx", InstEmit.Abs_V, typeof(OpCodeSimd64));
|
||||||
SetA64("01011110111xxxxx100001xxxxxxxxxx", InstEmit.Add_S, typeof(OpCodeSimdReg64));
|
SetA64("01011110111xxxxx100001xxxxxxxxxx", InstEmit.Add_S, typeof(OpCodeSimdReg64));
|
||||||
|
@ -656,12 +656,12 @@ namespace ChocolArm64
|
||||||
|
|
||||||
for (int index = 0; index < encoding.Length; index++, bit--)
|
for (int index = 0; index < encoding.Length; index++, bit--)
|
||||||
{
|
{
|
||||||
//Note: < and > are used on special encodings.
|
// Note: < and > are used on special encodings.
|
||||||
//The < means that we should never have ALL bits with the '<' set.
|
// The < means that we should never have ALL bits with the '<' set.
|
||||||
//So, when the encoding has <<, it means that 00, 01, and 10 are valid,
|
// So, when the encoding has <<, it means that 00, 01, and 10 are valid,
|
||||||
//but not 11. <<< is 000, 001, ..., 110 but NOT 111, and so on...
|
// but not 11. <<< is 000, 001, ..., 110 but NOT 111, and so on...
|
||||||
//For >, the invalid value is zero. So, for >> 01, 10 and 11 are valid,
|
// For >, the invalid value is zero. So, for >> 01, 10 and 11 are valid,
|
||||||
//but 00 isn't.
|
// but 00 isn't.
|
||||||
char chr = encoding[index];
|
char chr = encoding[index];
|
||||||
|
|
||||||
if (chr == '1')
|
if (chr == '1')
|
||||||
|
|
|
@ -126,8 +126,8 @@ namespace ChocolArm64.State
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal bool Synchronize()
|
internal bool Synchronize()
|
||||||
{
|
{
|
||||||
//Firing a interrupt frequently is expensive, so we only
|
// Firing a interrupt frequently is expensive, so we only
|
||||||
//do it after a given number of instructions has executed.
|
// do it after a given number of instructions has executed.
|
||||||
_syncCount++;
|
_syncCount++;
|
||||||
|
|
||||||
if (_syncCount >= MinCountForCheck)
|
if (_syncCount >= MinCountForCheck)
|
||||||
|
|
|
@ -56,10 +56,10 @@ namespace ChocolArm64.Translation
|
||||||
private OpCode64 _optOpLastCompare;
|
private OpCode64 _optOpLastCompare;
|
||||||
private OpCode64 _optOpLastFlagSet;
|
private OpCode64 _optOpLastFlagSet;
|
||||||
|
|
||||||
//This is the index of the temporary register, used to store temporary
|
// This is the index of the temporary register, used to store temporary
|
||||||
//values needed by some functions, since IL doesn't have a swap instruction.
|
// values needed by some functions, since IL doesn't have a swap instruction.
|
||||||
//You can use any value here as long it doesn't conflict with the indices
|
// You can use any value here as long it doesn't conflict with the indices
|
||||||
//for the other registers. Any value >= 64 or < 0 will do.
|
// for the other registers. Any value >= 64 or < 0 will do.
|
||||||
private const int ReservedLocalsCount = 64;
|
private const int ReservedLocalsCount = 64;
|
||||||
|
|
||||||
private const int RorTmpIndex = ReservedLocalsCount + 0;
|
private const int RorTmpIndex = ReservedLocalsCount + 0;
|
||||||
|
@ -69,7 +69,7 @@ namespace ChocolArm64.Translation
|
||||||
private const int IntGpTmp2Index = ReservedLocalsCount + 4;
|
private const int IntGpTmp2Index = ReservedLocalsCount + 4;
|
||||||
private const int UserIntTempStart = ReservedLocalsCount + 5;
|
private const int UserIntTempStart = ReservedLocalsCount + 5;
|
||||||
|
|
||||||
//Vectors are part of another "set" of locals.
|
// Vectors are part of another "set" of locals.
|
||||||
private const int VecGpTmp1Index = ReservedLocalsCount + 0;
|
private const int VecGpTmp1Index = ReservedLocalsCount + 0;
|
||||||
private const int VecGpTmp2Index = ReservedLocalsCount + 1;
|
private const int VecGpTmp2Index = ReservedLocalsCount + 1;
|
||||||
private const int VecGpTmp3Index = ReservedLocalsCount + 2;
|
private const int VecGpTmp3Index = ReservedLocalsCount + 2;
|
||||||
|
@ -139,10 +139,10 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public void ResetBlockStateForPredicatedOp()
|
public void ResetBlockStateForPredicatedOp()
|
||||||
{
|
{
|
||||||
//Check if this is a predicated instruction that modifies flags,
|
// Check if this is a predicated instruction that modifies flags,
|
||||||
//in this case the value of the flags is unknown as we don't know
|
// in this case the value of the flags is unknown as we don't know
|
||||||
//in advance if the instruction is going to be executed or not.
|
// in advance if the instruction is going to be executed or not.
|
||||||
//So, we reset the block state to prevent an invalid optimization.
|
// So, we reset the block state to prevent an invalid optimization.
|
||||||
if (CurrOp == _optOpLastFlagSet)
|
if (CurrOp == _optOpLastFlagSet)
|
||||||
{
|
{
|
||||||
ResetBlockState();
|
ResetBlockState();
|
||||||
|
@ -167,8 +167,8 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public bool TryOptEmitSubroutineCall()
|
public bool TryOptEmitSubroutineCall()
|
||||||
{
|
{
|
||||||
//Calls should always have a next block, unless
|
// Calls should always have a next block, unless
|
||||||
//we're translating a single basic block.
|
// we're translating a single basic block.
|
||||||
if (_currBlock.Next == null)
|
if (_currBlock.Next == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -239,15 +239,15 @@ namespace ChocolArm64.Translation
|
||||||
&& cond != Condition.GtUn
|
&& cond != Condition.GtUn
|
||||||
&& cond != Condition.LeUn)
|
&& cond != Condition.LeUn)
|
||||||
{
|
{
|
||||||
//There are several limitations that needs to be taken into account for CMN comparisons:
|
// There are several limitations that needs to be taken into account for CMN comparisons:
|
||||||
//- The unsigned comparisons are not valid, as they depend on the
|
// - The unsigned comparisons are not valid, as they depend on the
|
||||||
//carry flag value, and they will have different values for addition and
|
// carry flag value, and they will have different values for addition and
|
||||||
//subtraction. For addition, it's carry, and for subtraction, it's borrow.
|
// subtraction. For addition, it's carry, and for subtraction, it's borrow.
|
||||||
//So, we need to make sure we're not doing a unsigned compare for the CMN case.
|
// So, we need to make sure we're not doing a unsigned compare for the CMN case.
|
||||||
//- We can only do the optimization for the immediate variants,
|
// - We can only do the optimization for the immediate variants,
|
||||||
//because when the second operand value is exactly INT_MIN, we can't
|
// because when the second operand value is exactly INT_MIN, we can't
|
||||||
//negate the value as theres no positive counterpart.
|
// negate the value as theres no positive counterpart.
|
||||||
//Such invalid values can't be encoded on the immediate encodings.
|
// Such invalid values can't be encoded on the immediate encodings.
|
||||||
if (_optOpLastCompare is IOpCodeAluImm64 op)
|
if (_optOpLastCompare is IOpCodeAluImm64 op)
|
||||||
{
|
{
|
||||||
Ldloc(CmpOptTmp1Index, RegisterType.Int, _optOpLastCompare.RegisterSize);
|
Ldloc(CmpOptTmp1Index, RegisterType.Int, _optOpLastCompare.RegisterSize);
|
||||||
|
@ -513,11 +513,11 @@ namespace ChocolArm64.Translation
|
||||||
public void EmitLdflg(int index) => Ldloc(index, RegisterType.Flag);
|
public void EmitLdflg(int index) => Ldloc(index, RegisterType.Flag);
|
||||||
public void EmitStflg(int index)
|
public void EmitStflg(int index)
|
||||||
{
|
{
|
||||||
//Set this only if any of the NZCV flag bits were modified.
|
// Set this only if any of the NZCV flag bits were modified.
|
||||||
//This is used to ensure that when emiting a direct IL branch
|
// This is used to ensure that when emiting a direct IL branch
|
||||||
//instruction for compare + branch sequences, we're not expecting
|
// instruction for compare + branch sequences, we're not expecting
|
||||||
//to use comparison values from an old instruction, when in fact
|
// to use comparison values from an old instruction, when in fact
|
||||||
//the flags were already overwritten by another instruction further along.
|
// the flags were already overwritten by another instruction further along.
|
||||||
if (index >= (int)PState.VBit)
|
if (index >= (int)PState.VBit)
|
||||||
{
|
{
|
||||||
_optOpLastFlagSet = CurrOp;
|
_optOpLastFlagSet = CurrOp;
|
||||||
|
|
|
@ -153,7 +153,7 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public static long ClearCallerSavedIntRegs(long mask, ExecutionMode mode)
|
public static long ClearCallerSavedIntRegs(long mask, ExecutionMode mode)
|
||||||
{
|
{
|
||||||
//TODO: ARM32 support.
|
// TODO: ARM32 support.
|
||||||
if (mode == ExecutionMode.Aarch64)
|
if (mode == ExecutionMode.Aarch64)
|
||||||
{
|
{
|
||||||
mask &= ~(CallerSavedIntRegistersMask | PStateNzcvFlagsMask);
|
mask &= ~(CallerSavedIntRegistersMask | PStateNzcvFlagsMask);
|
||||||
|
@ -164,7 +164,7 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public static long ClearCallerSavedVecRegs(long mask, ExecutionMode mode)
|
public static long ClearCallerSavedVecRegs(long mask, ExecutionMode mode)
|
||||||
{
|
{
|
||||||
//TODO: ARM32 support.
|
// TODO: ARM32 support.
|
||||||
if (mode == ExecutionMode.Aarch64)
|
if (mode == ExecutionMode.Aarch64)
|
||||||
{
|
{
|
||||||
mask &= ~CallerSavedVecRegistersMask;
|
mask &= ~CallerSavedVecRegistersMask;
|
||||||
|
|
|
@ -10,9 +10,9 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
class TranslatedSub
|
class TranslatedSub
|
||||||
{
|
{
|
||||||
//This is the minimum amount of calls needed for the method
|
// This is the minimum amount of calls needed for the method
|
||||||
//to be retranslated with higher quality code. It's only worth
|
// to be retranslated with higher quality code. It's only worth
|
||||||
//doing that for hot code.
|
// doing that for hot code.
|
||||||
private const int MinCallCountForOpt = 30;
|
private const int MinCallCountForOpt = 30;
|
||||||
|
|
||||||
public ArmSubroutine Delegate { get; private set; }
|
public ArmSubroutine Delegate { get; private set; }
|
||||||
|
@ -32,7 +32,7 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public TranslatedSub(DynamicMethod method, TranslationTier tier, bool rejit)
|
public TranslatedSub(DynamicMethod method, TranslationTier tier, bool rejit)
|
||||||
{
|
{
|
||||||
Method = method ?? throw new ArgumentNullException(nameof(method));;
|
Method = method ?? throw new ArgumentNullException(nameof(method));
|
||||||
Tier = tier;
|
Tier = tier;
|
||||||
_rejit = rejit;
|
_rejit = rejit;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ namespace ChocolArm64.Translation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Only return true once, so that it is added to the queue only once.
|
// Only return true once, so that it is added to the queue only once.
|
||||||
_rejit = false;
|
_rejit = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -209,11 +209,11 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
context.ResetBlockStateForPredicatedOp();
|
context.ResetBlockStateForPredicatedOp();
|
||||||
|
|
||||||
//If this is the last op on the block, and there's no "next" block
|
// If this is the last op on the block, and there's no "next" block
|
||||||
//after this one, then we have to return right now, with the address
|
// after this one, then we have to return right now, with the address
|
||||||
//of the next instruction to be executed (in the case that the condition
|
// of the next instruction to be executed (in the case that the condition
|
||||||
//is false, and the branch was not taken, as all basic blocks should end
|
// is false, and the branch was not taken, as all basic blocks should end
|
||||||
//with some kind of branch).
|
// with some kind of branch).
|
||||||
if (isLastOp && block.Next == null)
|
if (isLastOp && block.Next == null)
|
||||||
{
|
{
|
||||||
context.EmitStoreContext();
|
context.EmitStoreContext();
|
||||||
|
|
|
@ -8,13 +8,13 @@ namespace ChocolArm64.Translation
|
||||||
{
|
{
|
||||||
class TranslatorCache
|
class TranslatorCache
|
||||||
{
|
{
|
||||||
//Maximum size of the cache, the unit used is completely arbitrary.
|
// Maximum size of the cache, the unit used is completely arbitrary.
|
||||||
private const int MaxTotalSize = 0x800000;
|
private const int MaxTotalSize = 0x800000;
|
||||||
|
|
||||||
//Minimum time required in milliseconds for a method to be eligible for deletion.
|
// Minimum time required in milliseconds for a method to be eligible for deletion.
|
||||||
private const int MinTimeDelta = 2 * 60000;
|
private const int MinTimeDelta = 2 * 60000;
|
||||||
|
|
||||||
//Minimum number of calls required to update the timestamp.
|
// Minimum number of calls required to update the timestamp.
|
||||||
private const int MinCallCountForUpdate = 250;
|
private const int MinCallCountForUpdate = 250;
|
||||||
|
|
||||||
private class CacheBucket
|
private class CacheBucket
|
||||||
|
@ -122,10 +122,10 @@ namespace ChocolArm64.Translation
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//The bucket value on the dictionary may have changed between the
|
// The bucket value on the dictionary may have changed between the
|
||||||
//time we get the value from the dictionary, and we acquire the
|
// time we get the value from the dictionary, and we acquire the
|
||||||
//lock. So we need to ensure we are working with the latest value,
|
// lock. So we need to ensure we are working with the latest value,
|
||||||
//we can do that by getting the value again, inside the lock.
|
// we can do that by getting the value again, inside the lock.
|
||||||
if (_cache.TryGetValue(position, out CacheBucket latestBucket))
|
if (_cache.TryGetValue(position, out CacheBucket latestBucket))
|
||||||
{
|
{
|
||||||
latestBucket.CallCount = 0;
|
latestBucket.CallCount = 0;
|
||||||
|
|
Loading…
Reference in a new issue