#include "glulxe.h"
#include "opcodes.h"
+#ifdef FLOAT_SUPPORT
+#include <math.h>
+#endif /* FLOAT_SUPPORT */
+
/* execute_loop():
The main interpreter loop. This repeats until the program is done.
*/
int ix;
glui32 opcode;
operandlist_t *oplist;
- instruction_t inst;
+ oparg_t inst[MAX_OPERANDS];
glui32 value, addr, val0, val1;
glsi32 vals0, vals1;
glui32 *arglist;
glui32 arglistfix[3];
+#ifdef FLOAT_SUPPORT
+ gfloat32 valf, valf1, valf2;
+#endif /* FLOAT_SUPPORT */
while (!done_executing) {
/* Based on the oplist structure, load the actual operand values
into inst. This moves the PC up to the end of the instruction. */
- parse_operands(&inst, oplist);
+ parse_operands(inst, oplist);
/* Perform the opcode. This switch statement is split in two, based
on some paranoid suspicions about the ability of compilers to
break;
case op_add:
- value = inst.value[0] + inst.value[1];
- store_operand(inst.desttype, inst.value[2], value);
+ value = inst[0].value + inst[1].value;
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_sub:
- value = inst.value[0] - inst.value[1];
- store_operand(inst.desttype, inst.value[2], value);
+ value = inst[0].value - inst[1].value;
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_mul:
- value = inst.value[0] * inst.value[1];
- store_operand(inst.desttype, inst.value[2], value);
+ value = inst[0].value * inst[1].value;
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_div:
- vals0 = inst.value[0];
- vals1 = inst.value[1];
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
if (vals1 == 0)
fatal_error("Division by zero.");
/* Since C doesn't guarantee the results of division of negative
numbers, we carefully convert everything to positive values
- first. */
- if (vals1 < 0) {
- vals0 = (-vals0);
- vals1 = (-vals1);
- }
- if (vals0 >= 0) {
- value = vals0 / vals1;
+ first. They have to be unsigned values, too, otherwise the
+ 0x80000000 case goes wonky. */
+ if (vals0 < 0) {
+ val0 = (-vals0);
+ if (vals1 < 0) {
+ val1 = (-vals1);
+ value = val0 / val1;
+ }
+ else {
+ val1 = vals1;
+ value = -(val0 / val1);
+ }
}
else {
- value = -((-vals0) / vals1);
+ val0 = vals0;
+ if (vals1 < 0) {
+ val1 = (-vals1);
+ value = -(val0 / val1);
+ }
+ else {
+ val1 = vals1;
+ value = val0 / val1;
+ }
}
- store_operand(inst.desttype, inst.value[2], value);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_mod:
- vals0 = inst.value[0];
- vals1 = inst.value[1];
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
if (vals1 == 0)
fatal_error("Division by zero doing remainder.");
if (vals1 < 0) {
- vals1 = (-vals1);
+ val1 = -vals1;
}
- if (vals0 >= 0) {
- value = vals0 % vals1;
+ else {
+ val1 = vals1;
+ }
+ if (vals0 < 0) {
+ val0 = (-vals0);
+ value = -(val0 % val1);
}
else {
- value = -((-vals0) % vals1);
+ val0 = vals0;
+ value = val0 % val1;
}
- store_operand(inst.desttype, inst.value[2], value);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_neg:
- vals0 = inst.value[0];
+ vals0 = inst[0].value;
value = (-vals0);
- store_operand(inst.desttype, inst.value[1], value);
+ store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_bitand:
- value = (inst.value[0] & inst.value[1]);
- store_operand(inst.desttype, inst.value[2], value);
+ value = (inst[0].value & inst[1].value);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_bitor:
- value = (inst.value[0] | inst.value[1]);
- store_operand(inst.desttype, inst.value[2], value);
+ value = (inst[0].value | inst[1].value);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_bitxor:
- value = (inst.value[0] ^ inst.value[1]);
- store_operand(inst.desttype, inst.value[2], value);
+ value = (inst[0].value ^ inst[1].value);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_bitnot:
- value = ~(inst.value[0]);
- store_operand(inst.desttype, inst.value[1], value);
+ value = ~(inst[0].value);
+ store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_shiftl:
- vals0 = inst.value[1];
+ vals0 = inst[1].value;
if (vals0 < 0 || vals0 >= 32)
value = 0;
else
- value = ((glui32)(inst.value[0]) << (glui32)vals0);
- store_operand(inst.desttype, inst.value[2], value);
+ value = ((glui32)(inst[0].value) << (glui32)vals0);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_ushiftr:
- vals0 = inst.value[1];
+ vals0 = inst[1].value;
if (vals0 < 0 || vals0 >= 32)
value = 0;
else
- value = ((glui32)(inst.value[0]) >> (glui32)vals0);
- store_operand(inst.desttype, inst.value[2], value);
+ value = ((glui32)(inst[0].value) >> (glui32)vals0);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_sshiftr:
- vals0 = inst.value[1];
+ vals0 = inst[1].value;
if (vals0 < 0 || vals0 >= 32) {
- if (inst.value[0] & 0x80000000)
+ if (inst[0].value & 0x80000000)
value = 0xFFFFFFFF;
else
value = 0;
/* This is somewhat foolhardy -- C doesn't guarantee that
right-shifting a signed value replicates the sign bit.
We'll assume it for now. */
- value = ((glsi32)(inst.value[0]) >> (glsi32)vals0);
+ value = ((glsi32)(inst[0].value) >> (glsi32)vals0);
}
- store_operand(inst.desttype, inst.value[2], value);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_jump:
- value = inst.value[0];
+ value = inst[0].value;
/* fall through to PerformJump label. */
PerformJump: /* goto label for successful jumping... ironic, no? */
break;
case op_jz:
- if (inst.value[0] == 0) {
- value = inst.value[1];
+ if (inst[0].value == 0) {
+ value = inst[1].value;
goto PerformJump;
}
break;
case op_jnz:
- if (inst.value[0] != 0) {
- value = inst.value[1];
+ if (inst[0].value != 0) {
+ value = inst[1].value;
goto PerformJump;
}
break;
case op_jeq:
- if (inst.value[0] == inst.value[1]) {
- value = inst.value[2];
+ if (inst[0].value == inst[1].value) {
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jne:
- if (inst.value[0] != inst.value[1]) {
- value = inst.value[2];
+ if (inst[0].value != inst[1].value) {
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jlt:
- vals0 = inst.value[0];
- vals1 = inst.value[1];
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
if (vals0 < vals1) {
- value = inst.value[2];
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jgt:
- vals0 = inst.value[0];
- vals1 = inst.value[1];
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
if (vals0 > vals1) {
- value = inst.value[2];
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jle:
- vals0 = inst.value[0];
- vals1 = inst.value[1];
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
if (vals0 <= vals1) {
- value = inst.value[2];
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jge:
- vals0 = inst.value[0];
- vals1 = inst.value[1];
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
if (vals0 >= vals1) {
- value = inst.value[2];
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jltu:
- val0 = inst.value[0];
- val1 = inst.value[1];
+ val0 = inst[0].value;
+ val1 = inst[1].value;
if (val0 < val1) {
- value = inst.value[2];
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jgtu:
- val0 = inst.value[0];
- val1 = inst.value[1];
+ val0 = inst[0].value;
+ val1 = inst[1].value;
if (val0 > val1) {
- value = inst.value[2];
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jleu:
- val0 = inst.value[0];
- val1 = inst.value[1];
+ val0 = inst[0].value;
+ val1 = inst[1].value;
if (val0 <= val1) {
- value = inst.value[2];
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_jgeu:
- val0 = inst.value[0];
- val1 = inst.value[1];
+ val0 = inst[0].value;
+ val1 = inst[1].value;
if (val0 >= val1) {
- value = inst.value[2];
+ value = inst[2].value;
goto PerformJump;
}
break;
case op_call:
- value = inst.value[1];
+ value = inst[1].value;
arglist = pop_arguments(value, 0);
- push_callstub(inst.desttype, inst.value[2]);
- enter_function(inst.value[0], value, arglist);
+ push_callstub(inst[2].desttype, inst[2].value);
+ enter_function(inst[0].value, value, arglist);
break;
case op_return:
leave_function();
done_executing = TRUE;
break;
}
- pop_callstub(inst.value[0]);
+ pop_callstub(inst[0].value);
break;
case op_tailcall:
- value = inst.value[1];
+ value = inst[1].value;
arglist = pop_arguments(value, 0);
leave_function();
- enter_function(inst.value[0], value, arglist);
+ enter_function(inst[0].value, value, arglist);
break;
case op_catch:
- push_callstub(inst.desttype, inst.value[0]);
- value = inst.value[1];
+ push_callstub(inst[0].desttype, inst[0].value);
+ value = inst[1].value;
val0 = stackptr;
- store_operand(inst.desttype, inst.value[0], val0);
+ store_operand(inst[0].desttype, inst[0].value, val0);
goto PerformJump;
break;
case op_throw:
profile_fail("throw");
- value = inst.value[0];
- stackptr = inst.value[1];
+ value = inst[0].value;
+ stackptr = inst[1].value;
pop_callstub(value);
break;
case op_copy:
- value = inst.value[0];
- store_operand(inst.desttype, inst.value[1], value);
+ value = inst[0].value;
+ store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_copys:
- value = inst.value[0];
- store_operand_s(inst.desttype, inst.value[1], value);
+ value = inst[0].value;
+ store_operand_s(inst[1].desttype, inst[1].value, value);
break;
case op_copyb:
- value = inst.value[0];
- store_operand_b(inst.desttype, inst.value[1], value);
+ value = inst[0].value;
+ store_operand_b(inst[1].desttype, inst[1].value, value);
break;
case op_sexs:
- val0 = inst.value[0];
+ val0 = inst[0].value;
if (val0 & 0x8000)
val0 |= 0xFFFF0000;
else
val0 &= 0x0000FFFF;
- store_operand(inst.desttype, inst.value[1], val0);
+ store_operand(inst[1].desttype, inst[1].value, val0);
break;
case op_sexb:
- val0 = inst.value[0];
+ val0 = inst[0].value;
if (val0 & 0x80)
val0 |= 0xFFFFFF00;
else
val0 &= 0x000000FF;
- store_operand(inst.desttype, inst.value[1], val0);
+ store_operand(inst[1].desttype, inst[1].value, val0);
break;
case op_aload:
- value = inst.value[0];
- value += 4 * inst.value[1];
+ value = inst[0].value;
+ value += 4 * inst[1].value;
val0 = Mem4(value);
- store_operand(inst.desttype, inst.value[2], val0);
+ store_operand(inst[2].desttype, inst[2].value, val0);
break;
case op_aloads:
- value = inst.value[0];
- value += 2 * inst.value[1];
+ value = inst[0].value;
+ value += 2 * inst[1].value;
val0 = Mem2(value);
- store_operand(inst.desttype, inst.value[2], val0);
+ store_operand(inst[2].desttype, inst[2].value, val0);
break;
case op_aloadb:
- value = inst.value[0];
- value += inst.value[1];
+ value = inst[0].value;
+ value += inst[1].value;
val0 = Mem1(value);
- store_operand(inst.desttype, inst.value[2], val0);
+ store_operand(inst[2].desttype, inst[2].value, val0);
break;
case op_aloadbit:
- value = inst.value[0];
- vals0 = inst.value[1];
+ value = inst[0].value;
+ vals0 = inst[1].value;
val1 = (vals0 & 7);
if (vals0 >= 0)
value += (vals0 >> 3);
else
- value -= ((-1 - vals0) >> 3);
+ value -= (1 + ((-1 - vals0) >> 3));
if (Mem1(value) & (1 << val1))
val0 = 1;
else
val0 = 0;
- store_operand(inst.desttype, inst.value[2], val0);
+ store_operand(inst[2].desttype, inst[2].value, val0);
break;
case op_astore:
- value = inst.value[0];
- value += 4 * inst.value[1];
- val0 = inst.value[2];
+ value = inst[0].value;
+ value += 4 * inst[1].value;
+ val0 = inst[2].value;
MemW4(value, val0);
break;
case op_astores:
- value = inst.value[0];
- value += 2 * inst.value[1];
- val0 = inst.value[2];
+ value = inst[0].value;
+ value += 2 * inst[1].value;
+ val0 = inst[2].value;
MemW2(value, val0);
break;
case op_astoreb:
- value = inst.value[0];
- value += inst.value[1];
- val0 = inst.value[2];
+ value = inst[0].value;
+ value += inst[1].value;
+ val0 = inst[2].value;
MemW1(value, val0);
break;
case op_astorebit:
- value = inst.value[0];
- vals0 = inst.value[1];
+ value = inst[0].value;
+ vals0 = inst[1].value;
val1 = (vals0 & 7);
if (vals0 >= 0)
value += (vals0 >> 3);
else
- value -= ((-1 - vals0) >> 3);
+ value -= (1 + ((-1 - vals0) >> 3));
val0 = Mem1(value);
- if (inst.value[2])
+ if (inst[2].value)
val0 |= (1 << val1);
else
val0 &= ~((glui32)(1 << val1));
case op_stkcount:
value = (stackptr - valstackbase) / 4;
- store_operand(inst.desttype, inst.value[0], value);
+ store_operand(inst[0].desttype, inst[0].value, value);
break;
case op_stkpeek:
- vals0 = inst.value[0] * 4;
+ 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.desttype, inst.value[1], value);
+ store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_stkswap:
if (stackptr < valstackbase+8) {
StkW4(stackptr-8, val0);
break;
case op_stkcopy:
- vals0 = inst.value[0];
+ vals0 = inst[0].value;
if (vals0 < 0)
fatal_error("Negative operand in stkcopy.");
if (vals0 == 0)
stackptr += vals0*4;
break;
case op_stkroll:
- vals0 = inst.value[0];
- vals1 = inst.value[1];
+ vals0 = inst[0].value;
+ vals1 = inst[1].value;
if (vals0 < 0)
fatal_error("Negative operand in stkroll.");
if (stackptr < valstackbase+vals0*4)
break;
case op_streamchar:
- profile_in(2, FALSE);
- value = inst.value[0] & 0xFF;
+ profile_in(0xE0000001, stackptr, FALSE);
+ value = inst[0].value & 0xFF;
(*stream_char_handler)(value);
- profile_out();
+ profile_out(stackptr);
break;
case op_streamunichar:
- profile_in(2, FALSE);
- value = inst.value[0];
+ profile_in(0xE0000002, stackptr, FALSE);
+ value = inst[0].value;
(*stream_unichar_handler)(value);
- profile_out();
+ profile_out(stackptr);
break;
case op_streamnum:
- profile_in(2, FALSE);
- vals0 = inst.value[0];
+ profile_in(0xE0000003, stackptr, FALSE);
+ vals0 = inst[0].value;
stream_num(vals0, FALSE, 0);
- profile_out();
+ profile_out(stackptr);
break;
case op_streamstr:
- profile_in(2, FALSE);
- stream_string(inst.value[0], 0, 0);
- profile_out();
+ profile_in(0xE0000004, stackptr, FALSE);
+ stream_string(inst[0].value, 0, 0);
+ profile_out(stackptr);
break;
default:
switch (opcode) {
case op_gestalt:
- value = do_gestalt(inst.value[0], inst.value[1]);
- store_operand(inst.desttype, inst.value[2], value);
+ value = do_gestalt(inst[0].value, inst[1].value);
+ store_operand(inst[2].desttype, inst[2].value, value);
break;
case op_debugtrap:
- fatal_error_i("user debugtrap encountered.", inst.value[0]);
+ fatal_error_i("user debugtrap encountered.", inst[0].value);
case op_jumpabs:
- pc = inst.value[0];
+ pc = inst[0].value;
break;
case op_callf:
- push_callstub(inst.desttype, inst.value[1]);
- enter_function(inst.value[0], 0, arglistfix);
+ push_callstub(inst[1].desttype, inst[1].value);
+ enter_function(inst[0].value, 0, arglistfix);
break;
case op_callfi:
- arglistfix[0] = inst.value[1];
- push_callstub(inst.desttype, inst.value[2]);
- enter_function(inst.value[0], 1, arglistfix);
+ 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.value[1];
- arglistfix[1] = inst.value[2];
- push_callstub(inst.desttype, inst.value[3]);
- enter_function(inst.value[0], 2, arglistfix);
+ 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.value[1];
- arglistfix[1] = inst.value[2];
- arglistfix[2] = inst.value[3];
- push_callstub(inst.desttype, inst.value[4]);
- enter_function(inst.value[0], 3, arglistfix);
+ 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.desttype, inst.value[0], endmem);
+ store_operand(inst[0].desttype, inst[0].value, endmem);
break;
case op_setmemsize:
- value = change_memsize(inst.value[0], FALSE);
- store_operand(inst.desttype, inst.value[1], value);
+ value = change_memsize(inst[0].value, FALSE);
+ store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_getstringtbl:
value = stream_get_table();
- store_operand(inst.desttype, inst.value[0], value);
+ store_operand(inst[0].desttype, inst[0].value, value);
break;
case op_setstringtbl:
- stream_set_table(inst.value[0]);
+ stream_set_table(inst[0].value);
break;
case op_getiosys:
stream_get_iosys(&val0, &val1);
- store_operand(inst.desttype, inst.value[0], val0);
- store_operand(inst.desttype, inst.value[1], val1);
+ store_operand(inst[0].desttype, inst[0].value, val0);
+ store_operand(inst[1].desttype, inst[1].value, val1);
break;
case op_setiosys:
- stream_set_iosys(inst.value[0], inst.value[1]);
+ stream_set_iosys(inst[0].value, inst[1].value);
break;
case op_glk:
- profile_in(1, FALSE);
- value = inst.value[1];
+ profile_in(0xF0000000+inst[0].value, stackptr, FALSE);
+ value = inst[1].value;
arglist = pop_arguments(value, 0);
- val0 = perform_glk(inst.value[0], value, arglist);
- store_operand(inst.desttype, inst.value[2], val0);
- profile_out();
+ val0 = perform_glk(inst[0].value, value, arglist);
+ store_operand(inst[2].desttype, inst[2].value, val0);
+ profile_out(stackptr);
break;
case op_random:
- vals0 = inst.value[0];
+ vals0 = inst[0].value;
if (vals0 == 0)
- value = glulx_random() ^ (glulx_random() << 16);
+ value = glulx_random();
else if (vals0 >= 1)
value = glulx_random() % (glui32)(vals0);
else
value = -(glulx_random() % (glui32)(-vals0));
- store_operand(inst.desttype, inst.value[1], value);
+ store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_setrandom:
- glulx_setrandom(inst.value[0]);
+ glulx_setrandom(inst[0].value);
break;
case op_verify:
value = perform_verify();
- store_operand(inst.desttype, inst.value[0], value);
+ store_operand(inst[0].desttype, inst[0].value, value);
break;
case op_restart:
break;
case op_protect:
- val0 = inst.value[0];
- val1 = val0 + inst.value[1];
+ val0 = inst[0].value;
+ val1 = val0 + inst[1].value;
if (val0 == val1) {
val0 = 0;
val1 = 0;
break;
case op_save:
- push_callstub(inst.desttype, inst.value[1]);
- value = perform_save(find_stream_by_id(inst.value[0]));
+ push_callstub(inst[1].desttype, inst[1].value);
+ value = perform_save(find_stream_by_id(inst[0].value));
pop_callstub(value);
break;
case op_restore:
profile_fail("restore");
- value = perform_restore(find_stream_by_id(inst.value[0]));
+ value = perform_restore(find_stream_by_id(inst[0].value));
if (value == 0) {
/* We've succeeded, and the stack now contains the callstub
saved during saveundo. Ignore this opcode's operand. */
else {
/* We've failed, so we must store the failure in this opcode's
operand. */
- store_operand(inst.desttype, inst.value[1], value);
+ store_operand(inst[1].desttype, inst[1].value, value);
}
break;
case op_saveundo:
- push_callstub(inst.desttype, inst.value[0]);
+ push_callstub(inst[0].desttype, inst[0].value);
value = perform_saveundo();
pop_callstub(value);
break;
else {
/* We've failed, so we must store the failure in this opcode's
operand. */
- store_operand(inst.desttype, inst.value[0], value);
+ store_operand(inst[0].desttype, inst[0].value, value);
}
break;
break;
case op_linearsearch:
- value = linear_search(inst.value[0], inst.value[1], inst.value[2],
- inst.value[3], inst.value[4], inst.value[5], inst.value[6]);
- store_operand(inst.desttype, inst.value[7], value);
+ 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.value[0], inst.value[1], inst.value[2],
- inst.value[3], inst.value[4], inst.value[5], inst.value[6]);
- store_operand(inst.desttype, inst.value[7], value);
+ 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.value[0], inst.value[1], inst.value[2],
- inst.value[3], inst.value[4], inst.value[5]);
- store_operand(inst.desttype, inst.value[6], value);
+ 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.value[0];
- addr = inst.value[1];
+ 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.value[0];
- glui32 addrsrc = inst.value[1];
- glui32 addrdest = inst.value[2];
+ 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);
}
break;
case op_malloc:
- value = heap_alloc(inst.value[0]);
- store_operand(inst.desttype, inst.value[1], value);
+ value = heap_alloc(inst[0].value);
+ store_operand(inst[1].desttype, inst[1].value, value);
break;
case op_mfree:
- heap_free(inst.value[0]);
+ heap_free(inst[0].value);
break;
case op_accelfunc:
- accel_set_func(inst.value[0], inst.value[1]);
+ accel_set_func(inst[0].value, inst[1].value);
break;
case op_accelparam:
- accel_set_param(inst.value[0], inst.value[1]);
+ accel_set_param(inst[0].value, inst[1].value);
break;
+#ifdef FLOAT_SUPPORT
+
+ 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) {
+ /* When the quotient is zero, the sign has been lost in the
+ shuffle. We'll set that by hand, based on the original
+ arguments. */
+ 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) {
+ /* When the result is zero, the sign may have been lost in the
+ shuffle. (This is a bug in some C libraries.) We'll set the
+ sign by hand, based on the original argument. */
+ 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:
+ /* Infinity is well-defined, so we don't bother to convert to
+ float. */
+ val0 = inst[0].value;
+ if (val0 == 0x7F800000 || val0 == 0xFF800000) {
+ value = inst[1].value;
+ goto PerformJump;
+ }
+ break;
+ case op_jisnan:
+ /* NaN is well-defined, so we don't bother to convert to
+ float. */
+ 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) {
+ /* The delta is NaN, which can never match. */
+ val0 = 0;
+ }
+ else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
+ && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
+ /* Both are infinite. Opposite infinities are never equal,
+ even if the difference is infinite, so this is easy. */
+ val0 = (inst[0].value == inst[1].value);
+ }
+ else {
+ valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
+ valf2 = fabs(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) {
+ /* The delta is NaN, which can never match. */
+ val0 = 0;
+ }
+ else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
+ && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
+ /* Both are infinite. Opposite infinities are never equal,
+ even if the difference is infinite, so this is easy. */
+ val0 = (inst[0].value == inst[1].value);
+ }
+ else {
+ valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
+ valf2 = fabs(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;
+
+#endif /* FLOAT_SUPPORT */
+
default:
fatal_error_i("Executed unknown opcode.", opcode);
}