public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { // IDT is already initialized but just for base hooks, and asm only. // ie Int 1, 3 and GPF // This routine updates the IDT now that we have C# running to allow C# hooks to handle // the other INTs // We are updating the IDT, disable interrupts XS.ClearInterruptFlag(); for (int i = 0; i < 256; i++) { // These are already mapped, don't remap them. // Maybe in the future we can look at ones that are present // and skip them, but some we may want to overwrite anyways. if (i == 1 || i == 3) { continue; } XS.Set(EAX, "__ISR_Handler_" + i.ToString("X2")); XS.Set("_NATIVE_IDT_Contents", AL, destinationDisplacement: (i * 8) + 0); XS.Set("_NATIVE_IDT_Contents", AH, destinationDisplacement: (i * 8) + 1); XS.Set("_NATIVE_IDT_Contents", 0x8, destinationDisplacement: (i * 8) + 2, size: RegisterSize.Byte8); XS.Set("_NATIVE_IDT_Contents", 0x8E, destinationDisplacement: (i * 8) + 5, size: RegisterSize.Byte8); XS.ShiftRight(EAX, 16); XS.Set("_NATIVE_IDT_Contents", AL, destinationDisplacement: (i * 8) + 6); XS.Set("_NATIVE_IDT_Contents", AH, destinationDisplacement: (i * 8) + 7); } XS.Jump("__AFTER__ALL__ISR__HANDLER__STUBS__"); var xInterruptsWithParam = new[] { 8, 10, 11, 12, 13, 14 }; for (int j = 0; j < 256; j++) { XS.Label("__ISR_Handler_" + j.ToString("X2")); XS.Call("__INTERRUPT_OCCURRED__"); if (Array.IndexOf(xInterruptsWithParam, j) == -1) { XS.Push(0); } XS.Push((uint)j); XS.PushAllRegisters(); XS.Sub(ESP, 4); XS.Set(EAX, ESP); // preserve old stack address for passing to interrupt handler // store floating point data XS.And(ESP, 0xfffffff0); // fxsave needs to be 16-byte alligned XS.Sub(ESP, 512); // fxsave needs 512 bytes XS.SSE.FXSave(ESP, isIndirect: true); // save the registers XS.Set(EAX, ESP, destinationIsIndirect: true); XS.Push(EAX); // XS.Push(EAX); // pass old stack address (pointer to InterruptContext struct) to the interrupt handler XS.JumpToSegment(8, "__ISR_Handler_" + j.ToString("X2") + "_SetCS"); XS.Label("__ISR_Handler_" + j.ToString("X2") + "_SetCS"); MethodBase xHandler = GetInterruptHandler((byte)j); if (xHandler == null) { xHandler = GetMethodDef(typeof(INTs).Assembly, typeof(INTs).FullName, "HandleInterrupt_Default", true); } XS.Call(LabelName.Get(xHandler)); XS.Pop(EAX); XS.SSE.FXRestore(ESP, isIndirect: true); XS.Set(ESP, EAX); // this restores the stack for the FX stuff, except the pointer to the FX data XS.Add(ESP, 4); // "pop" the pointer XS.PopAllRegisters(); XS.Add(ESP, 8); XS.Label("__ISR_Handler_" + j.ToString("X2") + "_END"); XS.InterruptReturn(); } XS.Label("__INTERRUPT_OCCURRED__"); XS.Return(); XS.Label("__AFTER__ALL__ISR__HANDLER__STUBS__"); XS.Noop(); XS.Set(EAX, EBP, sourceDisplacement: 8); XS.Compare(EAX, 0); XS.Jump(ConditionalTestEnum.Zero, ".__AFTER_ENABLE_INTERRUPTS"); // reload interrupt list XS.Set(EAX, "_NATIVE_IDT_Pointer"); XS.Set(AsmMarker.Labels[AsmMarker.Type.Processor_IntsEnabled], 1, destinationIsIndirect: true, size: RegisterSize.Byte8); XS.LoadIdt(EAX, isIndirect: true); // Reenable interrupts XS.EnableInterrupts(); XS.Label(".__AFTER_ENABLE_INTERRUPTS"); }
public static void DoAssemble(Type type) { if (type == null) { throw new ArgumentNullException(nameof(type)); } XS.Pop(EAX); var xObjSize = SizeOfType(type); if (xObjSize < 4 && TypeIsSigned(type)) { if (xObjSize == 1) { XS.MoveSignExtend(EBX, EAX, sourceIsIndirect: true, size: RegisterSize.Byte8); } else if (xObjSize == 2) { XS.MoveSignExtend(EBX, EAX, sourceIsIndirect: true, size: RegisterSize.Short16); } XS.Push(EBX); return; } switch (xObjSize % 4) { case 1: { XS.Xor(EBX, EBX); XS.Set(BL, EAX, sourceDisplacement: (int)(xObjSize - 1)); //XS.ShiftLeft(XSRegisters.EBX, 24); XS.Push(EBX); break; } case 2: { XS.Xor(EBX, EBX); XS.Set(BX, EAX, sourceDisplacement: (int)(xObjSize - 2)); //XS.ShiftLeft(XSRegisters.EBX, 16); XS.Push(EBX); break; } case 3: { XS.Set(EBX, EAX, sourceDisplacement: (int)(xObjSize - 3)); XS.And(EBX, 0xFFFFFF); XS.Push(EBX); break; } case 0: { break; } default: throw new Exception("Remainder not supported!"); } xObjSize -= (xObjSize % 4); for (int i = 1; i <= (xObjSize / 4); i++) { XS.Push(EAX, displacement: (int)(xObjSize - (i * 4))); } }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItemIsFloat = TypeIsFloat(xStackItem); if (xStackItemSize > 8) { throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Clt_Un.cs->Error: StackSizes > 8 not supported"); } string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelTrue = BaseLabel + "True"; string LabelFalse = BaseLabel + "False"; if (xStackItemSize > 4) { // Using SSE registers (that do NOT branch!) This is needed only for long now #if false XS.Set(XSRegisters.ESI, 1); // esi = 1 XS.Xor(XSRegisters.EDI, XSRegisters.EDI); // edi = 0 #endif if (xStackItemIsFloat) { // Please note that SSE supports double operations only from version 2 XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true); // Increment ESP to get the value of the next double XS.Add(ESP, 8); XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true); XS.SSE2.CompareSD(XMM1, XMM0, comparision: LessThan); XS.SSE2.MoveD(EBX, XMM1); XS.And(EBX, 1); // We need to move the stack pointer of 4 Byte to "eat" the second double that is yet in the stack or we get a corrupted stack! XS.Add(ESP, 4); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { XS.Set(ESI, 1); // esi = 1 XS.Xor(EDI, EDI); // edi = 0 XS.Pop(EAX); XS.Pop(EDX); //value2: EDX:EAX XS.Pop(EBX); XS.Pop(ECX); //value1: ECX:EBX XS.Sub(EBX, EAX); XS.SubWithCarry(ECX, EDX); //result = value1 - value2 new ConditionalMove { Condition = ConditionalTestEnum.Below, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; XS.Push(XSRegisters.EDI); } } else { if (xStackItemIsFloat) { XS.Comment("TEST TODO"); XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.CompareSS(XMM1, XMM0, comparision: LessThan); XS.SSE2.MoveD(EBX, XMM1); XS.And(ESP, 1, destinationIsIndirect: true); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { XS.Pop(ECX); XS.Pop(XSRegisters.EAX); XS.Push(XSRegisters.ECX); XS.Compare(EAX, ESP, sourceIsIndirect: true); XS.Jump(ConditionalTestEnum.Below, LabelTrue); XS.Jump(LabelFalse); XS.Label(LabelTrue); XS.Add(XSRegisters.ESP, 4); XS.Push(1); new Jump { DestinationLabel = GetLabel(aMethod, aOpCode.NextPosition) }; XS.Label(LabelFalse); XS.Add(XSRegisters.ESP, 4); XS.Push(0); } } }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem_ShiftAmount = aOpCode.StackPopTypes[0]; var xStackItem_Value = aOpCode.StackPopTypes[1]; var xStackItem_Value_Size = SizeOfType(xStackItem_Value); XS.Pop(XSRegisters.ECX); // shift amount #if DOTNETCOMPATIBLE if (xStackItem_Value.Size == 4) #else if (xStackItem_Value_Size <= 4) #endif { // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight! //XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32); XS.ShiftRightArithmetic(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32); } #if DOTNETCOMPATIBLE else if (xStackItem_Value_Size == 8) #else else if (xStackItem_Value_Size <= 8) #endif { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string HighPartIsZero = BaseLabel + "HighPartIsZero"; string End_Shr = BaseLabel + "End_Shr"; // [ESP] is low part // [ESP + 4] is high part // move high part in EAX XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8); XS.Jump(CPU.ConditionalTestEnum.AboveOrEqual, HighPartIsZero); // shift lower part XS.ShiftRightDouble(ESP, EAX, CL, destinationIsIndirect: true); // shift higher part // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight! //XS.ShiftRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32); XS.ShiftRightArithmetic(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32); XS.Jump(End_Shr); XS.Label(HighPartIsZero); // remove bits >= 32, so that CL max value could be only 31 XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8); // shift high part and move it in low part // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight! XS.ShiftRightArithmetic(XSRegisters.EAX, XSRegisters.CL); XS.Set(ESP, EAX, destinationIsIndirect: true); // replace unknown high part with a zero XS.Set(ESP, 0, destinationIsIndirect: true, destinationDisplacement: 4); //new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 0}; XS.Label(End_Shr); } else { throw new NotSupportedException("A size bigger 8 not supported at Shr!"); } /*string xLabelName = AppAssembler.TmpPosLabel(aMethod, aOpCode); * var xStackItem_ShiftAmount = Assembler.Stack.Pop(); * var xStackItem_Value = Assembler.Stack.Peek(); * if( xStackItem_Value.Size <= 4 ) * { * XS.Pop(XSRegisters.ECX); // shift amount * XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true); * } * else if( xStackItem_Value.Size <= 8 ) * { * XS.Pop(XSRegisters.ECX); // shift amount * // [ESP] is high part * // [ESP + 4] is low part * XS.Mov(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); * // shift low part * new CPUx86.ShiftRightDouble { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX, ArgumentReg = CPUx86.Registers.CL }; * // shift high part * XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32); * }*/ }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xSize = Math.Max(SizeOfType(xStackItem), SizeOfType(aOpCode.StackPopTypes[1])); var xIsFloat = TypeIsFloat(xStackItem); var xBaseLabel = GetLabel(aMethod, aOpCode); var xNoDivideByZeroExceptionLabel = xBaseLabel + "_NoDivideByZeroException"; if (xSize > 8) { throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Div.cs->Error: StackSize > 8 not supported"); } else if (xSize > 4) { if (xIsFloat) { XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 8); XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true); XS.SSE2.DivSD(XMM1, XMM0); XS.SSE2.MoveSD(ESP, XMM1, destinationIsIndirect: true); } else { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelShiftRight = BaseLabel + "ShiftRightLoop"; string LabelNoLoop = BaseLabel + "NoLoop"; string LabelEnd = BaseLabel + "End"; // divisor // low XS.Pop(ESI); // high XS.Pop(EDI); XS.Xor(EAX, EAX); XS.Or(EAX, ESI); XS.Or(EAX, EDI); XS.Jump(ConditionalTestEnum.NotZero, xNoDivideByZeroExceptionLabel); XS.Call(GetLabel(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef)); XS.Label(xNoDivideByZeroExceptionLabel); // dividend // low XS.Pop(EAX); // high XS.Pop(EDX); // set flags XS.Or(EDI, EDI); // if high dword of divisor is already zero, we dont need the loop XS.Jump(ConditionalTestEnum.Zero, LabelNoLoop); // set ecx to zero for counting the shift operations XS.Xor(ECX, ECX); // push most significant bit of result XS.Set(EBX, EDI); XS.Xor(EBX, EDX); XS.Push(EBX); XS.Compare(EDI, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "divisor_no_neg"); XS.Negate(ESI); XS.AddWithCarry(EDI, 0); XS.Negate(EDI); XS.Label(BaseLabel + "divisor_no_neg"); XS.Compare(EDX, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "dividend_no_neg"); XS.Negate(EAX); XS.AddWithCarry(EDX, 0); XS.Negate(EDX); XS.Label(BaseLabel + "dividend_no_neg"); XS.Label(LabelShiftRight); // shift divisor 1 bit right XS.ShiftRightDouble(ESI, EDI, 1); XS.ShiftRight(EDI, 1); // increment shift counter XS.Increment(ECX); // set flags //XS.Or(EDI, EDI); XS.Set(EBX, ESI); XS.And(EBX, 0x80000000); XS.Or(EBX, EDI); // loop while high dword of divisor is not zero or most significant bit of low dword of divisor is set XS.Jump(ConditionalTestEnum.NotZero, LabelShiftRight); // shift the dividend now in one step XS.ShiftRightDouble(EAX, EDX, CL); // shift dividend CL bits right XS.ShiftRight(EDX, CL); // so we shifted both, so we have near the same relation as original values // divide this XS.IntegerDivide(ESI); // pop most significant bit of result XS.Pop(EBX); XS.Compare(EBX, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "_result_no_neg"); XS.Negate(EAX); XS.Label(BaseLabel + "_result_no_neg"); // sign extend XS.SignExtendAX(RegisterSize.Int32); // save result to stack XS.Push(EDX); XS.Push(EAX); //TODO: implement proper derivation correction and overflow detection XS.Jump(LabelEnd); XS.Label(LabelNoLoop); // save high dividend XS.Set(ECX, EAX); XS.Set(EAX, EDX); // extend that sign is in edx XS.SignExtendAX(RegisterSize.Int32); // divide high part XS.IntegerDivide(ESI); // save high result XS.Push(EAX); XS.Set(EAX, ECX); // divide low part XS.Divide(ESI); // save low result XS.Push(EAX); XS.Label(LabelEnd); } } else { if (xIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.DivSS(XMM1, XMM0); XS.SSE.MoveSS(ESP, XMM1, destinationIsIndirect: true); } else { XS.Pop(ECX); XS.Test(ECX, ECX); XS.Jump(ConditionalTestEnum.NotZero, xNoDivideByZeroExceptionLabel); XS.Call(GetLabel(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef)); XS.Label(xNoDivideByZeroExceptionLabel); XS.Pop(EAX); XS.SignExtendAX(RegisterSize.Int32); XS.IntegerDivide(ECX); XS.Push(EAX); } } }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItemIsFloat = TypeIsFloat(xStackItem); var xStackItem2 = aOpCode.StackPopTypes[1]; var xStackItem2Size = SizeOfType(xStackItem2); var xStackItem2IsFloat = TypeIsFloat(xStackItem2); var xSize = Math.Max(xStackItemSize, xStackItem2Size); var xNextLabel = GetLabel(aMethod, aOpCode.NextPosition); if (xSize > 8) { throw new Exception("Cosmos.IL2CPU.x86->IL->Ceq.cs->Error: StackSizes > 8 not supported"); } else if (xSize <= 4) { if (xStackItemIsFloat) // float { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.CompareSS(XMM1, XMM0, comparision: Equal); XS.SSE2.MoveD(EBX, XMM1); XS.And(EBX, 1); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { XS.Pop(EAX); XS.Compare(EAX, ESP, sourceIsIndirect: true); XS.Jump(ConditionalTestEnum.Equal, Label.LastFullLabel + ".True"); XS.Jump(Label.LastFullLabel + ".False"); XS.Label(".True"); XS.Add(ESP, 4); XS.Push(1); XS.Jump(xNextLabel); XS.Label(".False"); XS.Add(ESP, 4); XS.Push(0); XS.Jump(xNextLabel); } } else if (xSize > 4) { if (xStackItemIsFloat) { // Please note that SSE supports double operations only from version 2 XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true); // Increment ESP to get the value of the next double XS.Add(ESP, 8); XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true); XS.SSE2.CompareSD(XMM1, XMM0, comparision: Equal); XS.SSE2.MoveD(EBX, XMM1); XS.And(EBX, 1); // We need to move the stack pointer of 4 Byte to "eat" the second double that is yet in the stack or we get a corrupted stack! XS.Add(ESP, 4); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { if (TypeIsReferenceType(xStackItem) && TypeIsReferenceType(xStackItem2)) { XS.Comment(xStackItem.Name); XS.Add(ESP, 4); XS.Pop(EAX); XS.Comment(xStackItem2.Name); XS.Add(ESP, 4); XS.Pop(EBX); XS.Compare(EAX, EBX); XS.Jump(ConditionalTestEnum.NotEqual, Label.LastFullLabel + ".False"); // equal XS.Push(1); XS.Jump(xNextLabel); XS.Label(Label.LastFullLabel + ".False"); //not equal XS.Push(0); XS.Jump(xNextLabel); } else { XS.Pop(EAX); XS.Compare(EAX, ESP, sourceDisplacement: 4); XS.Pop(EAX); XS.Jump(ConditionalTestEnum.NotEqual, Label.LastFullLabel + ".False"); XS.Xor(EAX, ESP, sourceDisplacement: 4); XS.Jump(ConditionalTestEnum.NotZero, Label.LastFullLabel + ".False"); //they are equal XS.Add(ESP, 8); XS.Push(1); XS.Jump(xNextLabel); XS.Label(Label.LastFullLabel + ".False"); //not equal XS.Add(ESP, 8); XS.Push(0); XS.Jump(xNextLabel); } } } else { throw new Exception("Cosmos.IL2CPU.x86->IL->Ceq.cs->Error: Case not handled!"); } }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItemIsFloat = TypeIsFloat(xStackItem); if (xStackItemSize > 8) { throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Clt_Un.cs->Error: StackSizes > 8 not supported"); } string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelTrue = BaseLabel + "True"; string LabelFalse = BaseLabel + "False"; if (xStackItemSize > 4) { XS.Set(XSRegisters.ESI, 1); // esi = 1 XS.Xor(XSRegisters.EDI, XSRegisters.EDI); // edi = 0 if (xStackItemIsFloat) { // value 2 XS.FPU.FloatLoad(ESP, destinationIsIndirect: true, size: RegisterSize.Long64); // value 1 new FloatLoad { DestinationReg = RegistersEnum.ESP, Size = 64, DestinationDisplacement = 8, DestinationIsIndirect = true }; XS.FPU.FloatCompareAndSet(ST1); // if carry is set, ST(0) < ST(i) new ConditionalMove { Condition = ConditionalTestEnum.Below, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; // pops fpu stack XS.FPU.FloatStoreAndPop(ST0); XS.FPU.FloatStoreAndPop(ST0); XS.Add(XSRegisters.ESP, 16); } else { XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EDX); //value2: EDX:EAX XS.Pop(XSRegisters.EBX); XS.Pop(XSRegisters.ECX); //value1: ECX:EBX XS.Sub(XSRegisters.EBX, XSRegisters.EAX); XS.SubWithCarry(XSRegisters.ECX, XSRegisters.EDX); //result = value1 - value2 new ConditionalMove { Condition = ConditionalTestEnum.Below, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; } XS.Push(XSRegisters.EDI); } else { if (xStackItemIsFloat) { #warning THIS NEEDS TO BE TESTED!!! XS.Comment("TEST TODO"); XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); new CompareSS { DestinationReg = RegistersEnum.XMM1, SourceReg = RegistersEnum.XMM0, pseudoOpcode = (byte)ComparePseudoOpcodes.LessThan }; XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.And(ESP, 1, destinationIsIndirect: true); } else { XS.Pop(XSRegisters.ECX); XS.Pop(XSRegisters.EAX); XS.Push(XSRegisters.ECX); XS.Compare(EAX, ESP, sourceIsIndirect: true); XS.Jump(ConditionalTestEnum.Below, LabelTrue); XS.Jump(LabelFalse); XS.Label(LabelTrue); XS.Add(XSRegisters.ESP, 4); XS.Push(1); new Jump { DestinationLabel = GetLabel(aMethod, aOpCode.NextPosition) }; XS.Label(LabelFalse); XS.Add(XSRegisters.ESP, 4); XS.Push(0); } } }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItemIsFloat = TypeIsFloat(xStackItem); if (xStackItemSize > 8) { //EmitNotImplementedException( Assembler, GetServiceProvider(), "Cgt: StackSizes>8 not supported", CurInstructionLabel, mMethodInfo, mCurrentOffset, NextInstructionLabel ); throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Cgt.cs->Error: StackSizes > 8 not supported"); //return; } string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelTrue = BaseLabel + "True"; string LabelFalse = BaseLabel + "False"; var xNextLabel = GetLabel(aMethod, aOpCode.NextPosition); if (xStackItemSize > 4) { XS.Set(XSRegisters.ESI, 1); // esi = 1 XS.Xor(XSRegisters.EDI, XSRegisters.EDI); // edi = 0 if (xStackItemIsFloat) { // value 1 new FloatLoad { DestinationReg = RegistersEnum.ESP, Size = 64, DestinationDisplacement = 8, DestinationIsIndirect = true }; // value 2 XS.FPU.FloatLoad(ESP, destinationIsIndirect: true, size: RegisterSize.Long64); XS.FPU.FloatCompareAndSet(ST1); // if carry is set, ST(0) < ST(i) new ConditionalMove { Condition = ConditionalTestEnum.Below, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; // pops fpu stack XS.FPU.FloatStoreAndPop(ST0); XS.FPU.FloatStoreAndPop(ST0); XS.Add(XSRegisters.ESP, 16); } else { XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EDX); //value2: EDX:EAX XS.Pop(XSRegisters.EBX); XS.Pop(XSRegisters.ECX); //value1: ECX:EBX XS.Compare(XSRegisters.ECX, XSRegisters.EDX); XS.Jump(ConditionalTestEnum.GreaterThan, LabelTrue); XS.Jump(ConditionalTestEnum.LessThan, LabelFalse); XS.Compare(XSRegisters.EBX, XSRegisters.EAX); XS.Label(LabelTrue); new ConditionalMove { Condition = ConditionalTestEnum.GreaterThan, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; XS.Label(LabelFalse); } XS.Push(XSRegisters.EDI); /* * XS.Jump(ConditionalTestEnum.GreaterThan, LabelTrue); * XS.Label(LabelFalse); * XS.Push(0); * XS.Jump(xNextLabel); * XS.Label(LabelTrue ); * XS.Push(1);*/ } else { if (xStackItemIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); new CompareSS { DestinationReg = RegistersEnum.XMM1, SourceReg = RegistersEnum.XMM0, pseudoOpcode = (byte)ComparePseudoOpcodes.NotLessThanOrEqualTo }; XS.SSE2.MoveD(XMM1, EBX); XS.And(XSRegisters.EBX, 1); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { XS.Pop(XSRegisters.EAX); XS.Compare(EAX, ESP, sourceIsIndirect: true); XS.Jump(ConditionalTestEnum.LessThan, LabelTrue); XS.Jump(LabelFalse); XS.Label(LabelTrue); XS.Add(XSRegisters.ESP, 4); XS.Push(1); XS.Jump(xNextLabel); XS.Label(LabelFalse); XS.Add(XSRegisters.ESP, 4); XS.Push(0); } } }
public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { XS.Mov(XSRegisters.EAX, XSRegisters.CPUx86.Registers.CR0); XS.And(XSRegisters.EAX, 0x7FFFFFFF); XS.Mov(XSRegisters.CR0, XSRegisters.CPUx86.Registers.EAX); }
public static void Assemble(Assembler aAssembler, uint aElementSize, _MethodInfo aMethod, ILOpCode aOpCode, bool debugEnabled) { DoNullReferenceCheck(aAssembler, debugEnabled, (int)(8 + Align(aElementSize, 4))); uint xStackSize = aElementSize; if (xStackSize % 4 != 0) { xStackSize += 4 - xStackSize % 4; } // Do index out of range check var xBaseLabel = GetLabel(aMethod, aOpCode); var xNoIndexOutOfRangeExeptionLabel = xBaseLabel + "_NoIndexOutOfRangeException"; var xIndexOutOfRangeExeptionLabel = xBaseLabel + "_IndexOutOfRangeException"; XS.Push(ESP, displacement: 4 + 4 + (int)xStackSize); // _, array, 0, index, value * n => _, array, 0, index, value * n, array XS.Push(0); // _, array, 0, index, value * n, array => _, array, 0, index, value * n, array, 0 Ldlen.Assemble(aAssembler, debugEnabled, false); // _, array, 0, index, value * n, array, 0 -> _, array, 0, index, value * n, length XS.Pop(EAX); //Length of array _, array, 0, index, value * n, length -> _, array, 0, index, value * n XS.Compare(EAX, ESP, sourceIsIndirect: true, sourceDisplacement: (int)xStackSize); XS.Jump(CPUx86.ConditionalTestEnum.LessThanOrEqualTo, xIndexOutOfRangeExeptionLabel); XS.Compare(EAX, 0); XS.Jump(CPUx86.ConditionalTestEnum.GreaterThanOrEqualTo, xNoIndexOutOfRangeExeptionLabel); XS.Label(xIndexOutOfRangeExeptionLabel); XS.Exchange(BX, BX); Call.DoExecute(aAssembler, aMethod, ExceptionHelperRefs.ThrowIndexOutOfRangeException, aOpCode, xNoIndexOutOfRangeExeptionLabel, debugEnabled); XS.Label(xNoIndexOutOfRangeExeptionLabel); // calculate element offset into array memory (including header) XS.Set(EAX, ESP, sourceDisplacement: (int)xStackSize); // the index XS.Set(EDX, aElementSize); XS.Multiply(EDX); XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); XS.Set(EDX, ESP, sourceDisplacement: (int)xStackSize + 8); // the array XS.Add(EDX, EAX); XS.Push(EDX); XS.Pop(ECX); //get bytes var bytes = aElementSize / 4; for (uint i = bytes; i > 0; i -= 1) { new Comment(aAssembler, "Start 1 dword"); XS.Pop(EBX); XS.Set(ECX, EBX, destinationIsIndirect: true); XS.Add(ECX, 4); } switch (aElementSize % 4) { case 1: { new Comment(aAssembler, "Start 1 byte"); XS.Pop(EBX); XS.Set(ECX, BL, destinationIsIndirect: true); break; } case 2: { new Comment(aAssembler, "Start 1 word"); XS.Pop(EBX); XS.Set(ECX, BX, destinationIsIndirect: true); break; } case 3: { new Comment(aAssembler, "Start 3 word"); XS.Pop(EBX); XS.And(EBX, 0xFFFFFF); // Only take the value of the lower three bytes XS.Set(ECX, EBX, destinationIsIndirect: true); break; } case 0: { break; } default: throw new Exception("Remainder size " + (aElementSize % 4) + " not supported!"); } XS.Add(ESP, 12); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem_ShiftAmount = aOpCode.StackPopTypes[0]; var xStackItem_Value = aOpCode.StackPopTypes[1]; var xStackItem_Value_Size = SizeOfType(xStackItem_Value); XS.Pop(XSRegisters.ECX); // shift amount #if DOTNETCOMPATIBLE if (xStackItem_Value.Size == 4) #else if (xStackItem_Value_Size <= 4) #endif { XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32); } #if DOTNETCOMPATIBLE else if (xStackItem_Value_Size == 8) #else else if (xStackItem_Value_Size <= 8) #endif { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string HighPartIsZero = BaseLabel + "HighPartIsZero"; string End_Shr = BaseLabel + "End_Shr"; // [ESP] is low part // [ESP + 4] is high part // move high part in EAX XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8); XS.Jump(CPU.ConditionalTestEnum.AboveOrEqual, HighPartIsZero); // shift lower part XS.ShiftRightDouble(ESP, EAX, CL, destinationIsIndirect: true); // shift higher part XS.ShiftRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32); XS.Jump(End_Shr); XS.Label(HighPartIsZero); // remove bits >= 32, so that CL max value could be only 31 XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8); // shift high part and move it in low part XS.ShiftRight(XSRegisters.EAX, XSRegisters.CL); XS.Set(ESP, EAX, destinationIsIndirect: true); // replace unknown high part with a zero new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 0 }; XS.Label(End_Shr); } else { throw new NotSupportedException("A size bigger 8 not supported at Shr!"); } /*string xLabelName = AppAssembler.TmpPosLabel(aMethod, aOpCode); * var xStackItem_ShiftAmount = Assembler.Stack.Pop(); * var xStackItem_Value = Assembler.Stack.Peek(); * if( xStackItem_Value.Size <= 4 ) * { * XS.Pop(XSRegisters.ECX); // shift amount * XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true); * } * else if( xStackItem_Value.Size <= 8 ) * { * XS.Pop(XSRegisters.ECX); // shift amount * // [ESP] is high part * // [ESP + 4] is low part * XS.Mov(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); * // shift low part * new CPUx86.ShiftRightDouble { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX, ArgumentReg = CPUx86.Registers.CL }; * // shift high part * XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32); * }*/ #if false XS.Pop(XSRegisters.ECX); // shift amount string xBaseLabel = GetLabel(aMethod, aOpCode) + "."; var xStackItem_ShiftAmount = aOpCode.StackPopTypes[0]; var xStackItem_Value = aOpCode.StackPopTypes[1]; if (TypeIsFloat(xStackItem_Value)) { throw new NotImplementedException("Floats not yet supported!"); } var xStackItem_Value_Size = SizeOfType(xStackItem_Value); if (xStackItem_Value_Size <= 4) { XS.Pop(XSRegisters.EAX); // shift amount XS.Pop(XSRegisters.EBX); // value XS.Set(XSRegisters.CL, XSRegisters.AL); XS.ShiftRight(XSRegisters.EBX, CL); XS.Push(XSRegisters.EBX); return; } if (xStackItem_Value_Size <= 8) { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string HighPartIsZero = BaseLabel + "HighPartIsZero"; string End_Shr = BaseLabel + "End_Shr"; // [ESP] is low part // [ESP + 4] is high part // move high part in EAX XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8); XS.Jump(CPU.ConditionalTestEnum.AboveOrEqual, HighPartIsZero); // shift lower part XS.ShiftRightDouble(ESP, EAX, CL, destinationIsIndirect: true); // shift higher part XS.ShiftRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32); XS.Jump(End_Shr); XS.Label(HighPartIsZero); // remove bits >= 32, so that CL max value could be only 31 XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8); // shift high part and move it in low part XS.ShiftRight(XSRegisters.EAX, XSRegisters.CL); XS.Set(ESP, EAX, destinationIsIndirect: true); // replace unknown high part with a zero, if <= 32 new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 0 }; XS.Label(End_Shr); #if false XS.Pop(XSRegisters.EDX); XS.Set(XSRegisters.EAX, 0); XS.Label(xBaseLabel + "__StartLoop"); XS.Compare(XSRegisters.EDX, XSRegisters.EAX); XS.Jump(CPUx86.ConditionalTestEnum.Equal, xBaseLabel + "__EndLoop"); XS.Set(EBX, ESP, sourceIsIndirect: true); XS.Set(XSRegisters.CL, 1); XS.ShiftRight(XSRegisters.EBX, CL); XS.Set(ESP, EBX, destinationIsIndirect: true); XS.Set(XSRegisters.CL, 1); XS.RotateThroughCarryRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32); XS.Add(XSRegisters.EAX, 1); new CPUx86.Jump { DestinationLabel = xBaseLabel + "__StartLoop" }; XS.Label(xBaseLabel + "__EndLoop"); #endif return; #endif } }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItemIsFloat = TypeIsFloat(xStackItem); if (xStackItemSize > 8) { //EmitNotImplementedException( Assembler, GetServiceProvider(), "Cgt: StackSizes>8 not supported", CurInstructionLabel, mMethodInfo, mCurrentOffset, NextInstructionLabel ); throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Cgt.cs->Error: StackSizes > 8 not supported"); //return; } string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelTrue = BaseLabel + "True"; string LabelFalse = BaseLabel + "False"; var xNextLabel = GetLabel(aMethod, aOpCode.NextPosition); if (xStackItemSize > 4) { // Using SSE registers (that do NOT branch!) This is needed only for long now #if false XS.Set(XSRegisters.ESI, 1); // esi = 1 XS.Xor(XSRegisters.EDI, XSRegisters.EDI); // edi = 0 #endif if (xStackItemIsFloat) { // Please note that SSE supports double operations only from version 2 XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true); // Increment ESP to get the value of the next double XS.Add(ESP, 8); XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true); XS.SSE2.CompareSD(XMM1, XMM0, comparision: NotLessThanOrEqualTo); XS.SSE2.MoveD(EBX, XMM1); XS.And(EBX, 1); // We need to move the stack pointer of 4 Byte to "eat" the second double that is yet in the stack or we get a corrupted stack! XS.Add(ESP, 4); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { XS.Set(ESI, 1); // esi = 1 XS.Xor(EDI, EDI); // edi = 0 XS.Pop(EAX); XS.Pop(EDX); //value2: EDX:EAX XS.Pop(EBX); XS.Pop(ECX); //value1: ECX:EBX XS.Compare(ECX, EDX); XS.Jump(ConditionalTestEnum.GreaterThan, LabelTrue); XS.Jump(ConditionalTestEnum.LessThan, LabelFalse); XS.Compare(EBX, EAX); XS.Label(LabelTrue); new ConditionalMove { Condition = ConditionalTestEnum.GreaterThan, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; XS.Label(LabelFalse); XS.Push(EDI); } /* * XS.Jump(ConditionalTestEnum.GreaterThan, LabelTrue); * XS.Label(LabelFalse); * XS.Push(0); * XS.Jump(xNextLabel); * XS.Label(LabelTrue ); * XS.Push(1);*/ } else { if (xStackItemIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.CompareSS(XMM1, XMM0, comparision: NotLessThanOrEqualTo); XS.SSE2.MoveD(EBX, XMM1); XS.And(XSRegisters.EBX, 1); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { XS.Pop(EAX); XS.Compare(EAX, ESP, sourceIsIndirect: true); XS.Jump(ConditionalTestEnum.LessThan, LabelTrue); XS.Jump(LabelFalse); XS.Label(LabelTrue); XS.Add(XSRegisters.ESP, 4); XS.Push(1); XS.Jump(xNextLabel); XS.Label(LabelFalse); XS.Add(XSRegisters.ESP, 4); XS.Push(0); } } }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItemIsFloat = TypeIsFloat(xStackItem); var xStackItem2 = aOpCode.StackPopTypes[1]; var xStackItem2Size = SizeOfType(xStackItem2); var xStackItem2IsFloat = TypeIsFloat(xStackItem2); var xSize = Math.Max(xStackItemSize, xStackItem2Size); var xNextLabel = GetLabel(aMethod, aOpCode.NextPosition); if (xSize > 8) { throw new Exception("Cosmos.IL2CPU.x86->IL->Ceq.cs->Error: StackSizes > 8 not supported"); } else if (xSize <= 4) { if (xStackItemIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); new CompareSS { DestinationReg = RegistersEnum.XMM1, SourceReg = RegistersEnum.XMM0, pseudoOpcode = (byte)ComparePseudoOpcodes.Equal }; XS.SSE2.MoveD(XMM1, EBX); XS.And(XSRegisters.EBX, 1); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { XS.Pop(XSRegisters.EAX); XS.Compare(EAX, ESP, sourceIsIndirect: true); XS.Jump(ConditionalTestEnum.Equal, Label.LastFullLabel + ".True"); XS.Jump(Label.LastFullLabel + ".False"); XS.Label(".True"); XS.Add(XSRegisters.ESP, 4); XS.Push(1); XS.Jump(xNextLabel); XS.Label(".False"); XS.Add(XSRegisters.ESP, 4); XS.Push(0); XS.Jump(xNextLabel); } } else if (xSize > 4) { if (xStackItemIsFloat) { XS.Set(XSRegisters.ESI, 1); // esi = 1 XS.Xor(XSRegisters.EDI, XSRegisters.EDI); // edi = 0 // value 1 new FloatLoad { DestinationReg = RegistersEnum.ESP, Size = 64, DestinationDisplacement = 8, DestinationIsIndirect = true }; // value 2 XS.FPU.FloatLoad(ESP, destinationIsIndirect: true, size: RegisterSize.Long64); XS.FPU.FloatCompareAndSet(ST1); // if zero is set, ST(0) == ST(i) new ConditionalMove { Condition = ConditionalTestEnum.Equal, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; // pops fpu stack XS.FPU.FloatStoreAndPop(ST0); XS.FPU.FloatStoreAndPop(ST0); XS.Add(XSRegisters.ESP, 16); XS.Push(XSRegisters.EDI); } else { XS.Pop(XSRegisters.EAX); XS.Compare(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); XS.Pop(XSRegisters.EAX); XS.Jump(ConditionalTestEnum.NotEqual, Label.LastFullLabel + ".False"); XS.Xor(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); XS.Jump(ConditionalTestEnum.NotZero, Label.LastFullLabel + ".False"); //they are equal, eax == 0 XS.Add(XSRegisters.ESP, 8); XS.Add(XSRegisters.EAX, 1); XS.Push(XSRegisters.EAX); XS.Jump(xNextLabel); XS.Label(Label.LastFullLabel + ".False"); //eax = 0 XS.Add(XSRegisters.ESP, 8); XS.Xor(XSRegisters.EAX, XSRegisters.EAX); XS.Push(XSRegisters.EAX); XS.Jump(xNextLabel); } } else { throw new Exception("Cosmos.IL2CPU.x86->IL->Ceq.cs->Error: Case not handled!"); } }