factor/vm/instruction_operands.cpp

172 lines
4.9 KiB
C++
Raw Normal View History

#include "master.hpp"
namespace factor
{
instruction_operand::instruction_operand(relocation_entry rel_, code_block *compiled_, cell index_) :
rel(rel_), compiled(compiled_), index(index_), pointer((cell)compiled_->entry_point() + rel_.rel_offset()) {}
/* Load a 32-bit value from a PowerPC LIS/ORI sequence */
fixnum instruction_operand::load_value_2_2()
{
2011-05-20 18:11:50 -04:00
u32 *ptr = (u32 *)pointer;
cell hi = (ptr[-2] & 0xffff);
cell lo = (ptr[-1] & 0xffff);
return hi << 16 | lo;
}
2011-05-20 18:11:50 -04:00
/* Load a 64-bit value from a PowerPC LIS/ORI/SLDI/ORIS/ORI sequence */
fixnum instruction_operand::load_value_2_2_2_2()
{
u32 *ptr = (u32 *)pointer;
u64 hhi = (ptr[-5] & 0xffff);
u64 hlo = (ptr[-4] & 0xffff);
u64 lhi = (ptr[-2] & 0xffff);
u64 llo = (ptr[-1] & 0xffff);
u64 val = hhi << 48 | hlo << 32 | lhi << 16 | llo;
return (cell)val;
}
/* Load a value from a bitfield of a PowerPC instruction */
fixnum instruction_operand::load_value_masked(cell mask, cell bits, cell shift)
{
s32 *ptr = (s32 *)(pointer - sizeof(u32));
return (((*ptr & (s32)mask) << bits) >> bits) << shift;
}
fixnum instruction_operand::load_value(cell relative_to)
{
switch(rel.rel_class())
{
case RC_ABSOLUTE_CELL:
return *(cell *)(pointer - sizeof(cell));
case RC_ABSOLUTE:
return *(u32 *)(pointer - sizeof(u32));
case RC_RELATIVE:
return *(s32 *)(pointer - sizeof(u32)) + relative_to;
case RC_ABSOLUTE_PPC_2_2:
return load_value_2_2();
case RC_ABSOLUTE_PPC_2:
2009-12-02 17:24:42 -05:00
return load_value_masked(rel_absolute_ppc_2_mask,16,0);
2011-05-20 18:11:50 -04:00
case RC_RELATIVE_PPC_2_PC:
return load_value_masked(rel_relative_ppc_2_mask,16,0) + relative_to - 4;
case RC_RELATIVE_PPC_3_PC:
return load_value_masked(rel_relative_ppc_3_mask,6,0) + relative_to - 4;
case RC_RELATIVE_ARM_3:
return load_value_masked(rel_relative_arm_3_mask,6,2) + relative_to + sizeof(cell);
case RC_INDIRECT_ARM:
return load_value_masked(rel_indirect_arm_mask,20,0) + relative_to;
case RC_INDIRECT_ARM_PC:
return load_value_masked(rel_indirect_arm_mask,20,0) + relative_to + sizeof(cell);
case RC_ABSOLUTE_2:
return *(u16 *)(pointer - sizeof(u16));
case RC_ABSOLUTE_1:
return *(u8 *)(pointer - sizeof(u8));
2011-05-20 18:11:50 -04:00
case RC_ABSOLUTE_PPC_2_2_2_2:
return load_value_2_2_2_2();
default:
critical_error("Bad rel class",rel.rel_class());
return 0;
}
}
fixnum instruction_operand::load_value()
{
return load_value(pointer);
}
code_block *instruction_operand::load_code_block(cell relative_to)
{
return ((code_block *)load_value(relative_to) - 1);
}
code_block *instruction_operand::load_code_block()
{
return load_code_block(pointer);
}
/* Store a 32-bit value into a PowerPC LIS/ORI sequence */
void instruction_operand::store_value_2_2(fixnum value)
{
2011-05-20 18:11:50 -04:00
u32 *ptr = (u32 *)pointer;
ptr[-2] = ((ptr[-2] & ~0xffff) | ((value >> 16) & 0xffff));
ptr[-1] = ((ptr[-1] & ~0xffff) | (value & 0xffff));
}
2011-05-20 18:11:50 -04:00
/* Store a 64-bit value into a PowerPC LIS/ORI/SLDI/ORIS/ORI sequence */
void instruction_operand::store_value_2_2_2_2(fixnum value)
{
u64 val = value;
u32 *ptr = (u32 *)pointer;
ptr[-5] = ((ptr[-5] & ~0xffff) | ((val >> 48) & 0xffff));
ptr[-4] = ((ptr[-4] & ~0xffff) | ((val >> 32) & 0xffff));
ptr[-2] = ((ptr[-2] & ~0xffff) | ((val >> 16) & 0xffff));
ptr[-1] = ((ptr[-1] & ~0xffff) | ((val >> 0) & 0xffff));
}
/* Store a value into a bitfield of a PowerPC instruction */
void instruction_operand::store_value_masked(fixnum value, cell mask, cell shift)
{
u32 *ptr = (u32 *)(pointer - sizeof(u32));
2010-01-24 08:17:18 -05:00
*ptr = (u32)((*ptr & ~mask) | ((value >> shift) & mask));
}
void instruction_operand::store_value(fixnum absolute_value)
{
fixnum relative_value = absolute_value - pointer;
switch(rel.rel_class())
{
case RC_ABSOLUTE_CELL:
*(cell *)(pointer - sizeof(cell)) = absolute_value;
break;
case RC_ABSOLUTE:
2010-01-24 08:17:18 -05:00
*(u32 *)(pointer - sizeof(u32)) = (u32)absolute_value;
break;
case RC_RELATIVE:
2010-01-24 08:17:18 -05:00
*(s32 *)(pointer - sizeof(s32)) = (s32)relative_value;
break;
case RC_ABSOLUTE_PPC_2_2:
store_value_2_2(absolute_value);
break;
case RC_ABSOLUTE_PPC_2:
store_value_masked(absolute_value,rel_absolute_ppc_2_mask,0);
break;
2011-05-20 18:11:50 -04:00
case RC_RELATIVE_PPC_2_PC:
store_value_masked(relative_value + 4,rel_relative_ppc_2_mask,0);
break;
2011-05-20 18:11:50 -04:00
case RC_RELATIVE_PPC_3_PC:
store_value_masked(relative_value + 4,rel_relative_ppc_3_mask,0);
break;
case RC_RELATIVE_ARM_3:
store_value_masked(relative_value - sizeof(cell),rel_relative_arm_3_mask,2);
break;
case RC_INDIRECT_ARM:
store_value_masked(relative_value,rel_indirect_arm_mask,0);
break;
case RC_INDIRECT_ARM_PC:
store_value_masked(relative_value - sizeof(cell),rel_indirect_arm_mask,0);
break;
case RC_ABSOLUTE_2:
*(u16 *)(pointer - sizeof(u16)) = (u16)absolute_value;
break;
case RC_ABSOLUTE_1:
*(u8 *)(pointer - sizeof(u8)) = (u8)absolute_value;
break;
2011-05-20 18:11:50 -04:00
case RC_ABSOLUTE_PPC_2_2_2_2:
store_value_2_2_2_2(absolute_value);
break;
default:
critical_error("Bad rel class",rel.rel_class());
break;
}
}
void instruction_operand::store_code_block(code_block *compiled)
{
store_value((cell)compiled->entry_point());
}
}