2013-05-11 21:55:50 -04:00
|
|
|
namespace factor {
|
2009-05-04 02:46:13 -04:00
|
|
|
|
2011-05-20 18:11:50 -04:00
|
|
|
#ifdef FACTOR_64
|
|
|
|
#define FACTOR_CPU_STRING "ppc.64"
|
|
|
|
#else
|
|
|
|
#define FACTOR_CPU_STRING "ppc.32"
|
|
|
|
#endif
|
2009-05-02 05:04:19 -04:00
|
|
|
|
2015-01-05 06:59:54 -05:00
|
|
|
#define CALLSTACK_BOTTOM(ctx) (ctx->callstack_seg->end - 32)
|
2010-03-26 22:44:43 -04:00
|
|
|
|
2009-05-07 20:47:38 -04:00
|
|
|
/* In the instruction sequence:
|
|
|
|
|
|
|
|
LOAD32 r3,...
|
|
|
|
B blah
|
|
|
|
|
|
|
|
the offset from the immediate operand to LOAD32 to the instruction after
|
2010-01-12 09:02:10 -05:00
|
|
|
the branch is one instruction. */
|
|
|
|
static const fixnum xt_tail_pic_offset = 4;
|
2009-05-07 20:47:38 -04:00
|
|
|
|
2013-05-11 21:55:50 -04:00
|
|
|
inline static void check_call_site(cell return_address) {
|
2013-05-13 00:28:25 -04:00
|
|
|
uint32_t insn = *(uint32_t*)return_address;
|
2013-05-11 21:55:50 -04:00
|
|
|
/* Check that absolute bit is 0 */
|
|
|
|
FACTOR_ASSERT((insn & 0x2) == 0x0);
|
|
|
|
/* Check that instruction is branch */
|
|
|
|
FACTOR_ASSERT((insn >> 26) == 0x12);
|
2009-05-06 16:39:03 -04:00
|
|
|
}
|
|
|
|
|
2013-05-13 00:28:25 -04:00
|
|
|
static const uint32_t b_mask = 0x3fffffc;
|
2009-05-06 16:39:03 -04:00
|
|
|
|
2013-05-11 21:55:50 -04:00
|
|
|
inline static void* get_call_target(cell return_address) {
|
|
|
|
return_address -= 4;
|
|
|
|
check_call_site(return_address);
|
2009-05-07 20:47:38 -04:00
|
|
|
|
2013-05-13 00:28:25 -04:00
|
|
|
uint32_t insn = *(uint32_t*)return_address;
|
|
|
|
uint32_t unsigned_addr = (insn & b_mask);
|
|
|
|
int32_t signed_addr = (int32_t)(unsigned_addr << 6) >> 6;
|
2013-05-11 21:55:50 -04:00
|
|
|
return (void*)(signed_addr + return_address);
|
2009-05-06 16:39:03 -04:00
|
|
|
}
|
|
|
|
|
2015-01-07 05:51:19 -05:00
|
|
|
inline static void set_call_target(cell return_address, cell target) {
|
2013-05-11 21:55:50 -04:00
|
|
|
return_address -= 4;
|
|
|
|
check_call_site(return_address);
|
2009-05-07 20:47:38 -04:00
|
|
|
|
2013-05-13 00:28:25 -04:00
|
|
|
uint32_t insn = *(uint32_t*)return_address;
|
2009-05-07 20:47:38 -04:00
|
|
|
|
2015-01-07 05:51:19 -05:00
|
|
|
fixnum relative_address = target - return_address;
|
2013-05-11 21:55:50 -04:00
|
|
|
insn = ((insn & ~b_mask) | (relative_address & b_mask));
|
2013-05-13 00:28:25 -04:00
|
|
|
*(uint32_t*)return_address = insn;
|
2009-05-06 16:39:03 -04:00
|
|
|
|
2013-05-11 21:55:50 -04:00
|
|
|
/* Flush the cache line containing the call we just patched */
|
|
|
|
__asm__ __volatile__("icbi 0, %0\n"
|
|
|
|
"sync\n" ::"r"(return_address)
|
|
|
|
:);
|
2009-05-06 16:39:03 -04:00
|
|
|
}
|
|
|
|
|
2013-05-11 21:55:50 -04:00
|
|
|
inline static bool tail_call_site_p(cell return_address) {
|
|
|
|
return_address -= 4;
|
2013-05-13 00:28:25 -04:00
|
|
|
uint32_t insn = *(uint32_t*)return_address;
|
2013-05-11 21:55:50 -04:00
|
|
|
return (insn & 0x1) == 0;
|
2009-05-07 20:47:38 -04:00
|
|
|
}
|
|
|
|
|
2013-05-11 21:55:50 -04:00
|
|
|
inline static unsigned int fpu_status(unsigned int status) {
|
|
|
|
unsigned int r = 0;
|
|
|
|
|
|
|
|
if (status & 0x20000000)
|
|
|
|
r |= FP_TRAP_INVALID_OPERATION;
|
|
|
|
if (status & 0x10000000)
|
|
|
|
r |= FP_TRAP_OVERFLOW;
|
|
|
|
if (status & 0x08000000)
|
|
|
|
r |= FP_TRAP_UNDERFLOW;
|
|
|
|
if (status & 0x04000000)
|
|
|
|
r |= FP_TRAP_ZERO_DIVIDE;
|
|
|
|
if (status & 0x02000000)
|
|
|
|
r |= FP_TRAP_INEXACT;
|
|
|
|
|
|
|
|
return r;
|
2009-09-14 00:37:28 -04:00
|
|
|
}
|
|
|
|
|
2009-05-06 16:39:03 -04:00
|
|
|
/* Defined in assembly */
|
2009-12-21 21:42:49 -05:00
|
|
|
VM_C_API void flush_icache(cell start, cell len);
|
|
|
|
|
2009-05-04 02:46:13 -04:00
|
|
|
}
|