Cosmos/source2/IL2PCU/Cosmos.IL2CPU.X86/IL/Branch.cs
mterwoord_cp fbee5696df
2009-09-19 08:27:33 +00:00

123 lines
5 KiB
C#

using System;
using Cosmos.IL2CPU.X86;
using CPU = Cosmos.IL2CPU.X86;
namespace Cosmos.IL2CPU.X86.IL {
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Beq)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bge)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bgt)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Ble)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Blt)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bne_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bge_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Bgt_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Ble_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Blt_Un)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Brfalse)]
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Brtrue)]
public class Branch: ILOp {
public Branch(Cosmos.IL2CPU.Assembler aAsmblr)
: base(aAsmblr) {
}
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) {
var xStackContent = Assembler.Stack.Pop();
var xIsSingleCompare = true;
switch (aOpCode.OpCode) {
case ILOpCode.Code.Beq:
case ILOpCode.Code.Bge:
case ILOpCode.Code.Bgt:
case ILOpCode.Code.Bge_Un:
case ILOpCode.Code.Bgt_Un:
case ILOpCode.Code.Ble:
case ILOpCode.Code.Ble_Un:
case ILOpCode.Code.Bne_Un:
case ILOpCode.Code.Blt:
case ILOpCode.Code.Blt_Un:
Assembler.Stack.Pop();
xIsSingleCompare = false;
break;
}
if (xStackContent.Size > 8) {
throw new Exception("StackSize > 8 not supported");
}
CPU.ConditionalTestEnum xTestOp;
switch (aOpCode.OpCode) {
case ILOpCode.Code.Beq:
xTestOp = CPU.ConditionalTestEnum.Zero;
break;
case ILOpCode.Code.Bge:
xTestOp = CPU.ConditionalTestEnum.LessThan;
break;
case ILOpCode.Code.Bgt:
xTestOp = CPU.ConditionalTestEnum.GreaterThan;
break;
case ILOpCode.Code.Ble:
xTestOp = CPU.ConditionalTestEnum.LessThanOrEqualTo;
break;
case ILOpCode.Code.Blt:
xTestOp = CPU.ConditionalTestEnum.LessThan;
break;
case ILOpCode.Code.Bne_Un:
xTestOp = CPU.ConditionalTestEnum.NotEqual;
break;
case ILOpCode.Code.Bge_Un:
xTestOp = CPU.ConditionalTestEnum.AboveOrEqual;
break;
case ILOpCode.Code.Bgt_Un:
xTestOp = CPU.ConditionalTestEnum.Above;
break;
case ILOpCode.Code.Ble_Un:
xTestOp = CPU.ConditionalTestEnum.BelowOrEqual;
break;
case ILOpCode.Code.Blt_Un:
xTestOp = CPU.ConditionalTestEnum.Below;
break;
case ILOpCode.Code.Brfalse:
xTestOp = CPU.ConditionalTestEnum.Zero;
break;
case ILOpCode.Code.Brtrue:
xTestOp = CPU.ConditionalTestEnum.NotZero;
break;
default:
throw new Exception("Unknown OpCode for conditional branch.");
}
if (!xIsSingleCompare) {
if (xStackContent.Size <= 4) {
new CPU.Pop { DestinationReg = CPU.Registers.EAX };
new CPU.Pop { DestinationReg = CPU.Registers.EBX };
new CPU.Compare { DestinationReg = CPU.Registers.EAX, SourceReg = CPU.Registers.EBX };
new CPU.ConditionalJump { Condition = xTestOp, DestinationLabel = AssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
} else {
new CPU.Pop { DestinationReg = CPU.Registers.EAX };
new CPU.Pop { DestinationReg = CPU.Registers.EBX };
new CPU.Pop { DestinationReg = CPU.Registers.ECX };
new CPU.Pop { DestinationReg = CPU.Registers.EDX };
new CPU.Xor { DestinationReg = CPU.Registers.EAX, SourceReg = CPU.Registers.ECX };
new CPU.ConditionalJump { Condition = xTestOp, DestinationLabel = AssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
new CPU.Xor { DestinationReg = CPU.Registers.EBX, SourceReg = CPU.Registers.EDX };
new CPU.ConditionalJump { Condition = xTestOp, DestinationLabel = AssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
}
} else {
// todo: improve code clarity
if (xStackContent.Size > 4) {
throw new Exception("Simple branches are not supported yet on operands > 4 bytes!");
}
new CPU.Pop { DestinationReg = CPU.Registers.EAX };
if (xTestOp == ConditionalTestEnum.Zero) {
new CPU.Compare { DestinationReg = CPU.Registers.EAX, SourceValue = 0 };
new CPU.ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = AssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
} else if (xTestOp == ConditionalTestEnum.NotZero) {
new CPU.Compare { DestinationReg = CPU.Registers.EAX, SourceValue = 0 };
new CPU.ConditionalJump { Condition = ConditionalTestEnum.NotEqual, DestinationLabel = AssemblerNasm.TmpBranchLabel(aMethod, aOpCode) };
} else {
throw new NotSupportedException("Situation not supported yet!");
}
}
}
}
}