I'm working on a JIT compiler for a MIPS machine emulation. I'm working on getting a nearly hard-coded Shift method, but whenever I try to execute the operation instruction on a value loaded from memory it fails.
This is the code that fails giving the Common Language Runtime detected an invalid program exception message:
private unsafe bool Shift(ILGenerator il, MipsInstruction inst, OpCode ilOpCode)
{
long baseAddress = (long)_cpu.RegisterFile.Regs;
long regAddress = baseAddress + ((int)inst.RT * sizeof(T));
// Push Address
if (IntPtr.Size == 4) il.Emit(OpCodes.Ldc_I4, (int)regAddress);
else il.Emit(OpCodes.Ldc_I8, regAddress);
il.Emit(OpCodes.Conv_I);
// Load the value from memory
il.Emit(OpCodes.Ldind_U4);
// Load shift amount
il.Emit(OpCodes.Ldc_I4, inst.ShiftAmount);
// Apply shift
il.Emit(ilOpCode);
// Pop value (not even trying to store yet)
il.Emit(OpCodes.Pop);
return false;
}
_cpu.RegisterFile.Regs is a T* where T is either a uint or a ulong depending on if the configurated MIPS version is 32 or 64 bit. In my testing I've been using MIPS32R2, so it's a uint.
For additional info, the following two methods do not give the
private unsafe bool Shift(ILGenerator il, MipsInstruction inst, OpCode ilOpCode)
{
il.Emit(OpCodes.Ldc_I4, inst.ShiftAmount);
il.Emit(OpCodes.Ldc_I4, inst.ShiftAmount);
il.Emit(ilOpCode);
il.Emit(OpCodes.Pop);
return false;
}
private unsafe bool Shift(ILGenerator il, MipsInstruction inst, OpCode ilOpCode)
{
long baseAddress = (long)_cpu.RegisterFile.Regs;
long regAddress = baseAddress + ((int)inst.RT * sizeof(T));
// Push Address
if (IntPtr.Size == 4) il.Emit(OpCodes.Ldc_I4, (int)regAddress);
else il.Emit(OpCodes.Ldc_I8, regAddress);
il.Emit(OpCodes.Conv_I);
// Load the value from memory
il.Emit(OpCodes.Ldind_U4);
il.Emit(OpCodes.Pop);
return false;
}
Finally, here is a permalink to a still broken version, which contains the surrounding code: permalink