Beispiel #1
0
 /// <summary>
 /// Sets the mem address to the given int (word)
 /// </summary>
 protected static void SetWordMemAddr(InternalVMData vmData, int address, int value)
 {
     vmData.Memory[address + 3] = (byte)(value >> 24);
     vmData.Memory[address + 2] = (byte)(value >> 16);
     vmData.Memory[address + 1] = (byte)(value >> 8);
     vmData.Memory[address]     = (byte)(value);
 }
Beispiel #2
0
        private readonly IDictionary <OperationCodes, InstructionEmiter> instructionEmiters;                                                                            //The instruction emiters
        #endregion

        #region Constructors
        /// <summary>
        /// Creates a new JIT compiler
        /// </summary>
        /// <param name="virtualMachine">The virtual machine</param>
        public BaseJITCompiler(VirtualMachine virtualMachine)
        {
            this.virtualMachine = virtualMachine;
            this.vmData         = this.virtualMachine.GetInternalData();

            this.registerField = typeof(InternalVMData).GetField("Registers",
                                                                 BindingFlags.Instance | BindingFlags.Public);

            this.memoryField = typeof(InternalVMData).GetField("Memory",
                                                               BindingFlags.Instance | BindingFlags.Public);

            this.convertToInt   = typeof(BaseJITCompiler).GetMethod("ConvertToInt", BindingFlags.NonPublic | BindingFlags.Static);
            this.setWordMemAddr = typeof(BaseJITCompiler).GetMethod("SetWordMemAddr", BindingFlags.NonPublic | BindingFlags.Static);

            this.instructionEmiters = new Dictionary <OperationCodes, InstructionEmiter>();

            #region Emiters

            #region Generators
            //Creates R-format emiters
            Func <OpCode, RFormatInstructionEmiter> rFormatEmiterGenerator = opCode =>
            {
                return((i, inst, genData) =>
                {
                    var gen = genData.ILGenerator;

                    //Push reg C
                    this.EmitRegRef(gen, inst.RegisterC);

                    //Load the value of reg A
                    this.EmitRegRef(gen, inst.RegisterA);
                    this.EmitLoadRef(gen);

                    //Load the value of reg B
                    this.EmitRegRef(gen, inst.RegisterB);
                    this.EmitLoadRef(gen);

                    //Apply the operation
                    gen.Emit(opCode);

                    //Store in reg C
                    this.EmitSaveRef(gen);
                });
            };

            Func <OpCode, IFormatInstructionEmiter> iFormatEmiterGenerator = opCode =>
            {
                return((i, inst, genData) =>
                {
                    var gen = genData.ILGenerator;

                    //Push reg B
                    this.EmitRegRef(gen, inst.RegisterB);

                    //Load the value of reg A
                    this.EmitRegRef(gen, inst.RegisterA);
                    this.EmitLoadRef(gen);

                    //Push the imm value
                    gen.Emit(OpCodes.Ldc_I4, inst.SignedImmediate);

                    //Apply the operation
                    gen.Emit(opCode);

                    //Store in reg B
                    this.EmitSaveRef(gen);
                });
            };
            #endregion

            #region Arithmetic
            //The addi instruction
            this.AddIFormatEmiter(OperationCodes.Addi, iFormatEmiterGenerator(OpCodes.Add));

            //The add instruction
            this.AddRFormatEmiter(OperationCodes.Add, OperationXCodes.Add, rFormatEmiterGenerator(OpCodes.Add));

            //The sub instruction
            this.AddRFormatEmiter(OperationCodes.Sub, OperationXCodes.Sub, rFormatEmiterGenerator(OpCodes.Sub));
            #endregion

            #region Logic
            //The and instruction
            this.AddRFormatEmiter(OperationCodes.And, OperationXCodes.And, rFormatEmiterGenerator(OpCodes.And));

            //The andi instruction
            this.AddIFormatEmiter(OperationCodes.Andi, iFormatEmiterGenerator(OpCodes.And));

            //The or instruction
            this.AddRFormatEmiter(OperationCodes.Or, OperationXCodes.Or, rFormatEmiterGenerator(OpCodes.Or));

            //The ori instruction
            this.AddIFormatEmiter(OperationCodes.Ori, iFormatEmiterGenerator(OpCodes.Or));

            //The xor instruction
            this.AddRFormatEmiter(OperationCodes.Xor, OperationXCodes.Xor, rFormatEmiterGenerator(OpCodes.Xor));

            //The xori instruction
            this.AddIFormatEmiter(OperationCodes.Xori, iFormatEmiterGenerator(OpCodes.Xor));

            //The nor instruction
            this.AddRFormatEmiter(OperationCodes.Nor, OperationXCodes.Nor, (i, inst, genData) =>
            {
                var gen = genData.ILGenerator;

                //Push reg C
                this.EmitRegRef(gen, inst.RegisterC);

                //Load the value of reg A
                this.EmitRegRef(gen, inst.RegisterA);
                this.EmitLoadRef(gen);

                //Load the value of reg B
                this.EmitRegRef(gen, inst.RegisterB);
                this.EmitLoadRef(gen);

                //OR them
                gen.Emit(OpCodes.Or);

                //Invert them
                gen.Emit(OpCodes.Not);

                //Store in reg C
                this.EmitSaveRef(gen);
            });
            #endregion

            #region Shift
            //The sll instruction
            this.AddRFormatEmiter(OperationCodes.Sll, OperationXCodes.Sll, rFormatEmiterGenerator(OpCodes.Shl));

            //The sll instruction
            this.AddRFormatEmiter(OperationCodes.Srl, OperationXCodes.Srl, rFormatEmiterGenerator(OpCodes.Shr));

            Func <OpCode, RFormatInstructionEmiter> shiftImmGenerator = opCode =>
            {
                return((i, inst, genData) =>
                {
                    var gen = genData.ILGenerator;

                    //Push reg C
                    this.EmitRegRef(gen, inst.RegisterC);

                    //Load the value of reg A
                    this.EmitRegRef(gen, inst.RegisterA);
                    this.EmitLoadRef(gen);

                    //Push the imm field, stored in the OPX code
                    gen.Emit(OpCodes.Ldc_I4, inst.OpxCode & 0x1F);

                    //Apply the operation
                    gen.Emit(opCode);

                    //Store in reg C
                    this.EmitSaveRef(gen);
                });
            };

            //The slli instruction
            this.AddRFormatEmiter(OperationCodes.Slli, OperationXCodes.Slli, shiftImmGenerator(OpCodes.Shl), ~0x1F);

            //The srli instruction
            this.AddRFormatEmiter(OperationCodes.Srli, OperationXCodes.Srli, shiftImmGenerator(OpCodes.Shr), ~0x1F);
            #endregion

            #region Compare
            //The cmpeq instruction
            this.AddRFormatEmiter(OperationCodes.Cmpeq, OperationXCodes.Cmpeq, rFormatEmiterGenerator(OpCodes.Ceq));

            //The cmpne instruction
            this.AddRFormatEmiter(OperationCodes.Cmpne, OperationXCodes.Cmpne, (i, inst, genData) =>
            {
                var gen = genData.ILGenerator;

                //Push reg C
                this.EmitRegRef(gen, inst.RegisterC);

                //Load the value of reg A
                this.EmitRegRef(gen, inst.RegisterA);
                this.EmitLoadRef(gen);

                //Load the value of reg B
                this.EmitRegRef(gen, inst.RegisterB);
                this.EmitLoadRef(gen);

                Label end    = gen.DefineLabel();
                Label setOne = gen.DefineLabel();

                //Branch if A == B
                gen.Emit(OpCodes.Beq, setOne);
                gen.Emit(OpCodes.Ldc_I4_1);                 //A != B, push 1
                gen.Emit(OpCodes.Br, end);

                gen.MarkLabel(setOne);
                gen.Emit(OpCodes.Ldc_I4_0);                 //A == B, push 0

                gen.MarkLabel(end);

                //Store in reg C
                this.EmitSaveRef(gen);
            });

            //The cmplt instruction
            this.AddRFormatEmiter(OperationCodes.Cmplt, OperationXCodes.Cmplt, rFormatEmiterGenerator(OpCodes.Clt));

            //The cmpge instruction
            this.AddRFormatEmiter(OperationCodes.Cmpge, OperationXCodes.Cmpge, (i, inst, genData) =>
            {
                var gen = genData.ILGenerator;

                //Push reg C
                this.EmitRegRef(gen, inst.RegisterC);

                //Load the value of reg A
                this.EmitRegRef(gen, inst.RegisterA);
                this.EmitLoadRef(gen);

                //Load the value of reg B
                this.EmitRegRef(gen, inst.RegisterB);
                this.EmitLoadRef(gen);

                Label end    = gen.DefineLabel();
                Label setOne = gen.DefineLabel();

                //Branch if A >= B
                gen.Emit(OpCodes.Bge, setOne);
                gen.Emit(OpCodes.Ldc_I4_0);                 //A < B, push 0
                gen.Emit(OpCodes.Br, end);

                gen.MarkLabel(setOne);
                gen.Emit(OpCodes.Ldc_I4_1);                 //A >= B, push 1

                gen.MarkLabel(end);

                //Store in reg C
                this.EmitSaveRef(gen);
            });
            #endregion

            #region Branch
            //The br instruction
            this.AddIFormatEmiter(OperationCodes.Br, (i, inst, genData) =>
            {
                var gen = genData.ILGenerator;

                //Emit the jump
                int label = i + (inst.SignedImmediate / 4) + 1;
                gen.Emit(OpCodes.Br, genData.GetLabel(label));
            });

            //Create branch emiters
            Func <OpCode, IFormatInstructionEmiter> branchEmiterGenerator = opCode =>
            {
                return((i, inst, genData) =>
                {
                    var gen = genData.ILGenerator;

                    //Load the value of reg A
                    this.EmitRegRef(gen, inst.RegisterA);
                    this.EmitLoadRef(gen);

                    //Load the value of reg B
                    this.EmitRegRef(gen, inst.RegisterB);
                    this.EmitLoadRef(gen);

                    //Emit the jump
                    int label = (i + inst.SignedImmediate / 4) + 1;
                    gen.Emit(opCode, genData.GetLabel(label));
                });
            };

            //The beq instruction
            this.AddIFormatEmiter(OperationCodes.Beq, branchEmiterGenerator(OpCodes.Beq));

            //The bne instruction
            this.AddIFormatEmiter(OperationCodes.Bne, branchEmiterGenerator(OpCodes.Bne_Un));

            //The bge instruction
            this.AddIFormatEmiter(OperationCodes.Bge, branchEmiterGenerator(OpCodes.Bge));

            //The blt instruction
            this.AddIFormatEmiter(OperationCodes.Blt, branchEmiterGenerator(OpCodes.Blt));
            #endregion

            #region Memory
            //The ldw instruction
            this.AddIFormatEmiter(OperationCodes.Ldw, (i, inst, genData) =>
            {
                var gen = genData.ILGenerator;

                //Emit reference to reg B
                this.EmitRegRef(gen, inst.RegisterB);

                for (int offset = 0; offset < 4; offset++)
                {
                    //Emit the memory reference
                    this.EmitMemRef(gen);

                    //Load the value of reg A (base address)
                    this.EmitRegRef(gen, inst.RegisterA);
                    this.EmitLoadRef(gen);

                    //Push the imm value (offset)
                    gen.Emit(OpCodes.Ldc_I4, inst.SignedImmediate + offset);

                    //Compute the effective address
                    gen.Emit(OpCodes.Add);

                    //Load from memory
                    this.EmitLoadMem(gen);
                }

                //Convert the top 4 bytes to a int
                gen.EmitCall(OpCodes.Call, this.convertToInt, null);

                //Store in reg B
                this.EmitSaveRef(gen);
            });

            //The stw instruction
            this.AddIFormatEmiter(OperationCodes.Stw, (i, inst, genData) =>
            {
                var gen = genData.ILGenerator;

                //Push the vm data
                this.LoadVMData(gen);

                //Load the value of reg A (base addr)
                this.EmitRegRef(gen, inst.RegisterA);
                this.EmitLoadRef(gen);

                //Push the imm value (offset)
                gen.Emit(OpCodes.Ldc_I4, inst.SignedImmediate);

                //Compute the effective address
                gen.Emit(OpCodes.Add);

                //Load the value of reg B (value)
                this.EmitRegRef(gen, inst.RegisterB);
                this.EmitLoadRef(gen);

                //Store in memory
                gen.EmitCall(OpCodes.Call, this.setWordMemAddr, null);
            });

            //The ldb instruction
            this.AddIFormatEmiter(OperationCodes.Ldb, (i, inst, genData) =>
            {
                var gen = genData.ILGenerator;

                //Emit reference to reg B
                this.EmitRegRef(gen, inst.RegisterB);

                //Emit the memory reference
                this.EmitMemRef(gen);

                //Load the value of reg A (base address)
                this.EmitRegRef(gen, inst.RegisterA);
                this.EmitLoadRef(gen);

                //Push the imm value (offset)
                gen.Emit(OpCodes.Ldc_I4, inst.SignedImmediate);

                //Compute the effective address
                gen.Emit(OpCodes.Add);

                //Load from memory
                this.EmitLoadMem(gen);

                //Store in reg B
                this.EmitSaveRef(gen);
            });

            //The stb instruction
            this.AddIFormatEmiter(OperationCodes.Stb, (i, inst, genData) =>
            {
                var gen = genData.ILGenerator;

                //Emit the reference to the memory field
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldfld, this.memoryField);

                //Load the value of reg A (base addr)
                this.EmitRegRef(gen, inst.RegisterA);
                this.EmitLoadRef(gen);

                //Push the imm value (offset)
                gen.Emit(OpCodes.Ldc_I4, inst.SignedImmediate);

                //Compute the effective address
                gen.Emit(OpCodes.Add);

                //Load the value of reg B (value)
                this.EmitRegRef(gen, inst.RegisterB);
                this.EmitLoadRef(gen);

                //Store in memory
                gen.Emit(OpCodes.Stelem_I1);
            });
            #endregion

            #endregion
        }