#include "glulxe.h"
#include "opcodes.h"
#include <math.h>
#define DOUBLE_PAIR_ISINF(vhi, vlo) (((vhi) == 0x7FF00000 || (vhi) == 0xFFF00000) && (vlo) == 0)
#define DOUBLE_PAIR_ISNAN(vhi, vlo) (((vhi) & 0x7FF00000) == 0x7FF00000 && (((vhi) & 0xFFFFF) != 0 || (vlo) != 0))
void execute_loop()
{
int done_executing = FALSE;
int ix;
glui32 opcode;
const operandlist_t *oplist;
oparg_t inst[MAX_OPERANDS];
glui32 value, addr, val0, val1;
glsi32 vals0, vals1;
glui32 *arglist;
glui32 arglistfix[3];
gfloat32 valf, valf1, valf2;
glui32 val0hi, val0lo;
gfloat64 vald, vald1, vald2;
while (!done_executing) {
prevpc = pc;
opcode = Mem1(pc);
pc++;
if (opcode & 0x80) {
if (opcode & 0x40) {
opcode &= 0x3F;
opcode = (opcode << 8) | Mem1(pc);
pc++;
opcode = (opcode << 8) | Mem1(pc);
pc++;
opcode = (opcode << 8) | Mem1(pc);
pc++;
}
else {
opcode &= 0x7F;
opcode = (opcode << 8) | Mem1(pc);
pc++;
}
}
if (opcode < 0x80)
oplist = fast_operandlist[opcode];
else
oplist = lookup_operandlist(opcode);
if (!oplist)
fatal_error_i("Encountered unknown opcode.", opcode);
parse_operands(inst, oplist);
if (opcode < 0x80) {
switch (opcode) {
case op_nop:
break;
case op_add:
value = inst[0].value + inst[1].value;
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_sub:
value = inst[0].value - inst[1].value;
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_mul:
value = inst[0].value * inst[1].value;
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_div:
vals0 = inst[0].value;
vals1 = inst[1].value;
if (vals1 == 0)
trap(TRAP_INTEGER_DIVIDE_BY_ZERO);
if (vals0 == -0x80000000 && vals1 == -1) {
trap(TRAP_INTEGER_OVERFLOW);
}
if (vals0 < 0) {
val0 = (-(glui32)vals0);
if (vals1 < 0) {
val1 = (-(glui32)vals1);
value = val0 / val1;
}
else {
val1 = vals1;
value = -(val0 / val1);
}
}
else {
val0 = vals0;
if (vals1 < 0) {
val1 = (-(glui32)vals1);
value = -(val0 / val1);
}
else {
val1 = vals1;
value = val0 / val1;
}
}
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_mod:
vals0 = inst[0].value;
vals1 = inst[1].value;
if (vals1 == 0)
trap(TRAP_INTEGER_DIVIDE_BY_ZERO);
if (vals1 < 0) {
val1 = -(glui32)vals1;
}
else {
val1 = vals1;
}
if (vals0 < 0) {
val0 = (-(glui32)vals0);
value = -(val0 % val1);
}
else {
val0 = vals0;
value = val0 % val1;
}
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_neg:
vals0 = inst[0].value;
value = (-(glui32)vals0);
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_bitand:
value = (inst[0].value & inst[1].value);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_bitor:
value = (inst[0].value | inst[1].value);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_bitxor:
value = (inst[0].value ^ inst[1].value);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_bitnot:
value = ~(inst[0].value);
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_shiftl:
vals0 = inst[1].value;
if (vals0 < 0 || vals0 >= 32)
value = 0;
else
value = ((glui32)(inst[0].value) << (glui32)vals0);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_ushiftr:
vals0 = inst[1].value;
if (vals0 < 0 || vals0 >= 32)
value = 0;
else
value = ((glui32)(inst[0].value) >> (glui32)vals0);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_sshiftr:
vals0 = inst[1].value;
if (vals0 < 0 || vals0 >= 32) {
if (inst[0].value & 0x80000000)
value = 0xFFFFFFFF;
else
value = 0;
}
else {
value = ((glsi32)(inst[0].value) >> (glsi32)vals0);
}
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_jump:
value = inst[0].value;
PerformJump:
if (value == 0 || value == 1) {
leave_function();
if (stackptr == 0) {
done_executing = TRUE;
break;
}
pop_callstub(value);
}
else {
pc = (pc + value - 2);
}
break;
case op_jz:
if (inst[0].value == 0) {
value = inst[1].value;
goto PerformJump;
}
break;
case op_jnz:
if (inst[0].value != 0) {
value = inst[1].value;
goto PerformJump;
}
break;
case op_jeq:
if (inst[0].value == inst[1].value) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jne:
if (inst[0].value != inst[1].value) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jlt:
vals0 = inst[0].value;
vals1 = inst[1].value;
if (vals0 < vals1) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jgt:
vals0 = inst[0].value;
vals1 = inst[1].value;
if (vals0 > vals1) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jle:
vals0 = inst[0].value;
vals1 = inst[1].value;
if (vals0 <= vals1) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jge:
vals0 = inst[0].value;
vals1 = inst[1].value;
if (vals0 >= vals1) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jltu:
val0 = inst[0].value;
val1 = inst[1].value;
if (val0 < val1) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jgtu:
val0 = inst[0].value;
val1 = inst[1].value;
if (val0 > val1) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jleu:
val0 = inst[0].value;
val1 = inst[1].value;
if (val0 <= val1) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jgeu:
val0 = inst[0].value;
val1 = inst[1].value;
if (val0 >= val1) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_call:
value = inst[1].value;
arglist = pop_arguments(value, 0);
push_callstub(inst[2].desttype, inst[2].value);
enter_function(inst[0].value, value, arglist);
break;
case op_return:
leave_function();
if (stackptr == 0) {
done_executing = TRUE;
break;
}
pop_callstub(inst[0].value);
break;
case op_tailcall:
value = inst[1].value;
arglist = pop_arguments(value, 0);
leave_function();
enter_function(inst[0].value, value, arglist);
break;
case op_catch:
push_callstub(inst[0].desttype, inst[0].value);
value = inst[1].value;
val0 = stackptr;
store_operand(inst[0].desttype, inst[0].value, val0);
goto PerformJump;
break;
case op_throw:
value = inst[0].value;
stackptr = inst[1].value;
pop_callstub(value);
break;
case op_copy:
value = inst[0].value;
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_copys:
value = inst[0].value;
store_operand_s(inst[1].desttype, inst[1].value, value);
break;
case op_copyb:
value = inst[0].value;
store_operand_b(inst[1].desttype, inst[1].value, value);
break;
case op_sexs:
val0 = inst[0].value;
if (val0 & 0x8000)
val0 |= 0xFFFF0000;
else
val0 &= 0x0000FFFF;
store_operand(inst[1].desttype, inst[1].value, val0);
break;
case op_sexb:
val0 = inst[0].value;
if (val0 & 0x80)
val0 |= 0xFFFFFF00;
else
val0 &= 0x000000FF;
store_operand(inst[1].desttype, inst[1].value, val0);
break;
case op_aload:
value = inst[0].value;
value += 4 * inst[1].value;
val0 = Mem4(value);
store_operand(inst[2].desttype, inst[2].value, val0);
break;
case op_aloads:
value = inst[0].value;
value += 2 * inst[1].value;
val0 = Mem2(value);
store_operand(inst[2].desttype, inst[2].value, val0);
break;
case op_aloadb:
value = inst[0].value;
value += inst[1].value;
val0 = Mem1(value);
store_operand(inst[2].desttype, inst[2].value, val0);
break;
case op_aloadbit:
value = inst[0].value;
vals0 = inst[1].value;
val1 = (vals0 & 7);
if (vals0 >= 0)
value += (vals0 >> 3);
else
value -= (1 + ((-1 - vals0) >> 3));
if (Mem1(value) & (1 << val1))
val0 = 1;
else
val0 = 0;
store_operand(inst[2].desttype, inst[2].value, val0);
break;
case op_astore:
value = inst[0].value;
value += 4 * inst[1].value;
val0 = inst[2].value;
MemW4(value, val0);
break;
case op_astores:
value = inst[0].value;
value += 2 * inst[1].value;
val0 = inst[2].value;
MemW2(value, val0);
break;
case op_astoreb:
value = inst[0].value;
value += inst[1].value;
val0 = inst[2].value;
MemW1(value, val0);
break;
case op_astorebit:
value = inst[0].value;
vals0 = inst[1].value;
val1 = (vals0 & 7);
if (vals0 >= 0)
value += (vals0 >> 3);
else
value -= (1 + ((-1 - vals0) >> 3));
val0 = Mem1(value);
if (inst[2].value)
val0 |= (1 << val1);
else
val0 &= ~((glui32)(1 << val1));
MemW1(value, val0);
break;
case op_stkcount:
value = (stackptr - valstackbase) / 4;
store_operand(inst[0].desttype, inst[0].value, value);
break;
case op_stkpeek:
vals0 = inst[0].value * 4;
if (vals0 < 0 || vals0 >= (stackptr - valstackbase))
fatal_error("Stkpeek outside current stack range.");
value = Stk4(stackptr - (vals0+4));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_stkswap:
if (stackptr < valstackbase+8) {
fatal_error("Stack underflow in stkswap.");
}
val0 = Stk4(stackptr-4);
val1 = Stk4(stackptr-8);
StkW4(stackptr-4, val1);
StkW4(stackptr-8, val0);
break;
case op_stkcopy:
vals0 = inst[0].value;
if (vals0 < 0)
fatal_error("Negative operand in stkcopy.");
if (vals0 == 0)
break;
if (stackptr < valstackbase+vals0*4)
fatal_error("Stack underflow in stkcopy.");
if (stackptr + vals0*4 > stacksize)
trap(TRAP_STACK_EXHAUSTED);
addr = stackptr - vals0*4;
for (ix=0; ix<vals0; ix++) {
value = Stk4(addr + ix*4);
StkW4(stackptr + ix*4, value);
}
stackptr += vals0*4;
break;
case op_stkroll:
vals0 = inst[0].value;
vals1 = inst[1].value;
if (vals0 < 0)
fatal_error("Negative operand in stkroll.");
if (stackptr < valstackbase+vals0*4)
fatal_error("Stack underflow in stkroll.");
if (vals0 == 0)
break;
if (vals1 > 0) {
vals1 = vals1 % vals0;
vals1 = (vals0) - vals1;
}
else {
vals1 = (-(glui32)vals1) % vals0;
}
if (vals1 == 0)
break;
addr = stackptr - vals0*4;
for (ix=0; ix<vals1; ix++) {
value = Stk4(addr + ix*4);
StkW4(stackptr + ix*4, value);
}
for (ix=0; ix<vals0; ix++) {
value = Stk4(addr + (vals1+ix)*4);
StkW4(addr + ix*4, value);
}
break;
case op_streamnum:
vals0 = inst[0].value;
printf("%08x", (unsigned int)vals0);
break;
default:
fatal_error_i("Executed unknown opcode.", opcode);
}
}
else {
switch (opcode) {
case op_gestalt:
value = do_gestalt(inst[0].value, inst[1].value);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_debugtrap:
trap(inst[0].value);
break;
case op_jumpabs:
pc = inst[0].value;
break;
case op_callf:
push_callstub(inst[1].desttype, inst[1].value);
enter_function(inst[0].value, 0, arglistfix);
break;
case op_callfi:
arglistfix[0] = inst[1].value;
push_callstub(inst[2].desttype, inst[2].value);
enter_function(inst[0].value, 1, arglistfix);
break;
case op_callfii:
arglistfix[0] = inst[1].value;
arglistfix[1] = inst[2].value;
push_callstub(inst[3].desttype, inst[3].value);
enter_function(inst[0].value, 2, arglistfix);
break;
case op_callfiii:
arglistfix[0] = inst[1].value;
arglistfix[1] = inst[2].value;
arglistfix[2] = inst[3].value;
push_callstub(inst[4].desttype, inst[4].value);
enter_function(inst[0].value, 3, arglistfix);
break;
case op_getmemsize:
store_operand(inst[0].desttype, inst[0].value, endmem);
break;
case op_setmemsize:
value = change_memsize(inst[0].value, FALSE);
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_setiosys:
break;
case op_verify:
store_operand(inst[0].desttype, inst[0].value, 0);
break;
case op_quit:
done_executing = TRUE;
break;
case op_linearsearch:
value = linear_search(inst[0].value, inst[1].value, inst[2].value,
inst[3].value, inst[4].value, inst[5].value, inst[6].value);
store_operand(inst[7].desttype, inst[7].value, value);
break;
case op_binarysearch:
value = binary_search(inst[0].value, inst[1].value, inst[2].value,
inst[3].value, inst[4].value, inst[5].value, inst[6].value);
store_operand(inst[7].desttype, inst[7].value, value);
break;
case op_linkedsearch:
value = linked_search(inst[0].value, inst[1].value, inst[2].value,
inst[3].value, inst[4].value, inst[5].value);
store_operand(inst[6].desttype, inst[6].value, value);
break;
case op_mzero: {
glui32 lx;
glui32 count = inst[0].value;
addr = inst[1].value;
for (lx=0; lx<count; lx++, addr++) {
MemW1(addr, 0);
}
}
break;
case op_mcopy: {
glui32 lx;
glui32 count = inst[0].value;
glui32 addrsrc = inst[1].value;
glui32 addrdest = inst[2].value;
if (addrdest < addrsrc) {
for (lx=0; lx<count; lx++, addrsrc++, addrdest++) {
value = Mem1(addrsrc);
MemW1(addrdest, value);
}
}
else {
addrsrc += (count-1);
addrdest += (count-1);
for (lx=0; lx<count; lx++, addrsrc--, addrdest--) {
value = Mem1(addrsrc);
MemW1(addrdest, value);
}
}
}
break;
case op_malloc:
value = heap_alloc(inst[0].value);
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_mfree:
heap_free(inst[0].value);
break;
case op_accelfunc:
case op_accelparam:
break;
case op_numtof:
vals0 = inst[0].value;
value = encode_float((gfloat32)vals0);
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_ftonumz:
valf = decode_float(inst[0].value);
if (!signbit(valf)) {
if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
vals0 = 0x7FFFFFFF;
else
vals0 = (glsi32)(truncf(valf));
}
else {
if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
vals0 = 0x80000000;
else
vals0 = (glsi32)(truncf(valf));
}
store_operand(inst[1].desttype, inst[1].value, vals0);
break;
case op_ftonumn:
valf = decode_float(inst[0].value);
if (!signbit(valf)) {
if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
vals0 = 0x7FFFFFFF;
else
vals0 = (glsi32)(roundf(valf));
}
else {
if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
vals0 = 0x80000000;
else
vals0 = (glsi32)(roundf(valf));
}
store_operand(inst[1].desttype, inst[1].value, vals0);
break;
case op_fadd:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
value = encode_float(valf1 + valf2);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_fsub:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
value = encode_float(valf1 - valf2);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_fmul:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
value = encode_float(valf1 * valf2);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_fdiv:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
value = encode_float(valf1 / valf2);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_fmod:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
valf = fmodf(valf1, valf2);
val0 = encode_float(valf);
val1 = encode_float((valf1-valf) / valf2);
if (val1 == 0x0 || val1 == 0x80000000) {
val1 = (inst[0].value ^ inst[1].value) & 0x80000000;
}
store_operand(inst[2].desttype, inst[2].value, val0);
store_operand(inst[3].desttype, inst[3].value, val1);
break;
case op_floor:
valf = decode_float(inst[0].value);
value = encode_float(floorf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_ceil:
valf = decode_float(inst[0].value);
value = encode_float(ceilf(valf));
if (value == 0x0 || value == 0x80000000) {
value = inst[0].value & 0x80000000;
}
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_sqrt:
valf = decode_float(inst[0].value);
value = encode_float(sqrtf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_log:
valf = decode_float(inst[0].value);
value = encode_float(logf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_exp:
valf = decode_float(inst[0].value);
value = encode_float(expf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_pow:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
value = encode_float(glulx_powf(valf1, valf2));
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_sin:
valf = decode_float(inst[0].value);
value = encode_float(sinf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_cos:
valf = decode_float(inst[0].value);
value = encode_float(cosf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_tan:
valf = decode_float(inst[0].value);
value = encode_float(tanf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_asin:
valf = decode_float(inst[0].value);
value = encode_float(asinf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_acos:
valf = decode_float(inst[0].value);
value = encode_float(acosf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_atan:
valf = decode_float(inst[0].value);
value = encode_float(atanf(valf));
store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_atan2:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
value = encode_float(atan2f(valf1, valf2));
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_jisinf:
val0 = inst[0].value;
if (val0 == 0x7F800000 || val0 == 0xFF800000) {
value = inst[1].value;
goto PerformJump;
}
break;
case op_jisnan:
val0 = inst[0].value;
if ((val0 & 0x7F800000) == 0x7F800000 && (val0 & 0x007FFFFF) != 0) {
value = inst[1].value;
goto PerformJump;
}
break;
case op_jfeq:
if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
val0 = 0;
}
else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
&& (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
val0 = (inst[0].value == inst[1].value);
}
else {
valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
valf2 = fabsf(decode_float(inst[2].value));
val0 = (valf1 <= valf2 && valf1 >= -valf2);
}
if (val0) {
value = inst[3].value;
goto PerformJump;
}
break;
case op_jfne:
if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
val0 = 0;
}
else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
&& (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
val0 = (inst[0].value == inst[1].value);
}
else {
valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
valf2 = fabsf(decode_float(inst[2].value));
val0 = (valf1 <= valf2 && valf1 >= -valf2);
}
if (!val0) {
value = inst[3].value;
goto PerformJump;
}
break;
case op_jflt:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
if (valf1 < valf2) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jfgt:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
if (valf1 > valf2) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jfle:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
if (valf1 <= valf2) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jfge:
valf1 = decode_float(inst[0].value);
valf2 = decode_float(inst[1].value);
if (valf1 >= valf2) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_numtod:
vals0 = inst[0].value;
encode_double((gfloat64)vals0, &val0hi, &val0lo);
store_operand(inst[1].desttype, inst[1].value, val0lo);
store_operand(inst[2].desttype, inst[2].value, val0hi);
break;
case op_dtonumz:
vald = decode_double(inst[0].value, inst[1].value);
if (!signbit(vald)) {
if (isnan(vald) || isinf(vald) || (vald > 2147483647.0))
vals0 = 0x7FFFFFFF;
else
vals0 = (glsi32)(trunc(vald));
}
else {
if (isnan(vald) || isinf(vald) || (vald < -2147483647.0))
vals0 = 0x80000000;
else
vals0 = (glsi32)(trunc(vald));
}
store_operand(inst[2].desttype, inst[2].value, vals0);
break;
case op_dtonumn:
vald = decode_double(inst[0].value, inst[1].value);
if (!signbit(vald)) {
if (isnan(vald) || isinf(vald) || (vald > 2147483647.0))
vals0 = 0x7FFFFFFF;
else
vals0 = (glsi32)(round(vald));
}
else {
if (isnan(vald) || isinf(vald) || (vald < -2147483647.0))
vals0 = 0x80000000;
else
vals0 = (glsi32)(round(vald));
}
store_operand(inst[2].desttype, inst[2].value, vals0);
break;
case op_ftod:
valf = decode_float(inst[0].value);
encode_double((gfloat64)valf, &val0hi, &val0lo);
store_operand(inst[1].desttype, inst[1].value, val0lo);
store_operand(inst[2].desttype, inst[2].value, val0hi);
break;
case op_dtof:
vald = decode_double(inst[0].value, inst[1].value);
value = encode_float((gfloat32)vald);
store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_dadd:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
encode_double(vald1 + vald2, &val0hi, &val0lo);
store_operand(inst[4].desttype, inst[4].value, val0lo);
store_operand(inst[5].desttype, inst[5].value, val0hi);
break;
case op_dsub:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
encode_double(vald1 - vald2, &val0hi, &val0lo);
store_operand(inst[4].desttype, inst[4].value, val0lo);
store_operand(inst[5].desttype, inst[5].value, val0hi);
break;
case op_dmul:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
encode_double(vald1 * vald2, &val0hi, &val0lo);
store_operand(inst[4].desttype, inst[4].value, val0lo);
store_operand(inst[5].desttype, inst[5].value, val0hi);
break;
case op_ddiv:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
encode_double(vald1 / vald2, &val0hi, &val0lo);
store_operand(inst[4].desttype, inst[4].value, val0lo);
store_operand(inst[5].desttype, inst[5].value, val0hi);
break;
case op_dmodr:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
vald = fmod(vald1, vald2);
encode_double(vald, &val0hi, &val0lo);
store_operand(inst[4].desttype, inst[4].value, val0lo);
store_operand(inst[5].desttype, inst[5].value, val0hi);
break;
case op_dmodq:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
vald = fmod(vald1, vald2);
vald = (vald1-vald) / vald2;
encode_double(vald, &val0hi, &val0lo);
if ((val0hi == 0x0 || val0hi == 0x80000000) && val0lo == 0x0) {
val0hi = (inst[0].value ^ inst[2].value) & 0x80000000;
}
store_operand(inst[4].desttype, inst[4].value, val0lo);
store_operand(inst[5].desttype, inst[5].value, val0hi);
break;
case op_dfloor:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(floor(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dceil:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(ceil(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dsqrt:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(sqrt(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dlog:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(log(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dexp:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(exp(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dpow:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
encode_double(glulx_pow(vald1, vald2), &val0hi, &val0lo);
store_operand(inst[4].desttype, inst[4].value, val0lo);
store_operand(inst[5].desttype, inst[5].value, val0hi);
break;
case op_dsin:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(sin(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dcos:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(cos(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dtan:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(tan(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dasin:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(asin(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_dacos:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(acos(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_datan:
vald = decode_double(inst[0].value, inst[1].value);
encode_double(atan(vald), &val0hi, &val0lo);
store_operand(inst[2].desttype, inst[2].value, val0lo);
store_operand(inst[3].desttype, inst[3].value, val0hi);
break;
case op_datan2:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
vald = atan2(vald1, vald2);
encode_double(vald, &val0hi, &val0lo);
store_operand(inst[4].desttype, inst[4].value, val0lo);
store_operand(inst[5].desttype, inst[5].value, val0hi);
break;
case op_jdisinf:
val0 = inst[0].value;
val1 = inst[1].value;
if (DOUBLE_PAIR_ISINF(val0, val1)) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jdisnan:
val0 = inst[0].value;
val1 = inst[1].value;
if (DOUBLE_PAIR_ISNAN(val0, val1)) {
value = inst[2].value;
goto PerformJump;
}
break;
case op_jdeq:
if (DOUBLE_PAIR_ISNAN(inst[4].value, inst[5].value)) {
val0 = 0;
}
else if (DOUBLE_PAIR_ISINF(inst[0].value, inst[1].value)
&& DOUBLE_PAIR_ISINF(inst[2].value, inst[3].value)) {
val0 = (inst[0].value == inst[2].value);
}
else {
vald1 = decode_double(inst[2].value, inst[3].value) - decode_double(inst[0].value, inst[1].value);
vald2 = fabs(decode_double(inst[4].value, inst[5].value));
val0 = (vald1 <= vald2 && vald1 >= -vald2);
}
if (val0) {
value = inst[6].value;
goto PerformJump;
}
break;
case op_jdne:
if (DOUBLE_PAIR_ISNAN(inst[4].value, inst[5].value)) {
val0 = 0;
}
else if (DOUBLE_PAIR_ISINF(inst[0].value, inst[1].value)
&& DOUBLE_PAIR_ISINF(inst[2].value, inst[3].value)) {
val0 = (inst[0].value == inst[2].value);
}
else {
vald1 = decode_double(inst[2].value, inst[3].value) - decode_double(inst[0].value, inst[1].value);
vald2 = fabs(decode_double(inst[4].value, inst[5].value));
val0 = (vald1 <= vald2 && vald1 >= -vald2);
}
if (!val0) {
value = inst[6].value;
goto PerformJump;
}
break;
case op_jdlt:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
if (vald1 < vald2) {
value = inst[4].value;
goto PerformJump;
}
break;
case op_jdgt:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
if (vald1 > vald2) {
value = inst[4].value;
goto PerformJump;
}
break;
case op_jdle:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
if (vald1 <= vald2) {
value = inst[4].value;
goto PerformJump;
}
break;
case op_jdge:
vald1 = decode_double(inst[0].value, inst[1].value);
vald2 = decode_double(inst[2].value, inst[3].value);
if (vald1 >= vald2) {
value = inst[4].value;
goto PerformJump;
}
break;
default:
fatal_error_i("Executed unknown opcode.", opcode);
}
}
}
}