mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-27 14:02:19 +00:00
124 lines
5.1 KiB
C#
124 lines
5.1 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;
|
|
// all conditions are inverted here?
|
|
switch (aOpCode.OpCode) {
|
|
case ILOpCode.Code.Beq:
|
|
xTestOp = CPU.ConditionalTestEnum.Zero;
|
|
break;
|
|
case ILOpCode.Code.Bge:
|
|
xTestOp = CPU.ConditionalTestEnum.GreaterThanOrEqualTo;
|
|
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.EBX, SourceReg = CPU.Registers.EAX };
|
|
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!");
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|