diff options
author | dreammaster | 2019-04-17 05:41:14 +0100 |
---|---|---|
committer | Paul Gilbert | 2019-04-17 20:46:07 -0700 |
commit | 427e051f6a1d2b5740b9f3ab0c5e3df9df7494fb (patch) | |
tree | a3e142d36f94622756c14833651fd6821c578fc1 /engines/glk/glulxe/exec.cpp | |
parent | 105c9cb885990c6de50eedb9928baa840e134000 (diff) | |
download | scummvm-rg350-427e051f6a1d2b5740b9f3ab0c5e3df9df7494fb.tar.gz scummvm-rg350-427e051f6a1d2b5740b9f3ab0c5e3df9df7494fb.tar.bz2 scummvm-rg350-427e051f6a1d2b5740b9f3ab0c5e3df9df7494fb.zip |
GLK: GLULXE: astyle formatting
Diffstat (limited to 'engines/glk/glulxe/exec.cpp')
-rw-r--r-- | engines/glk/glulxe/exec.cpp | 2015 |
1 files changed, 998 insertions, 1017 deletions
diff --git a/engines/glk/glulxe/exec.cpp b/engines/glk/glulxe/exec.cpp index f314ca43e2..55cd918ebb 100644 --- a/engines/glk/glulxe/exec.cpp +++ b/engines/glk/glulxe/exec.cpp @@ -26,1042 +26,1023 @@ namespace Glk { namespace Glulxe { void Glulxe::execute_loop() { - bool done_executing = false; - int ix; - uint opcode; - const operandlist_t *oplist; - oparg_t inst[MAX_OPERANDS]; - uint value, addr, val0, val1; - int vals0, vals1; - uint *arglist; - uint arglistfix[3]; + bool done_executing = false; + int ix; + uint opcode; + const operandlist_t *oplist; + oparg_t inst[MAX_OPERANDS]; + uint value, addr, val0, val1; + int vals0, vals1; + uint *arglist; + uint arglistfix[3]; #ifdef FLOAT_SUPPORT - gfloat32 valf, valf1, valf2; + gfloat32 valf, valf1, valf2; #endif /* FLOAT_SUPPORT */ - while (!done_executing) { - - profile_tick(); - debugger_tick(); - /* Do OS-specific processing, if appropriate. */ - glk_tick(); - - /* Stash the current opcode's address, in case the interpreter needs to serialize the VM state out-of-band. */ - prevpc = pc; - - /* Fetch the opcode number. */ - opcode = Mem1(pc); - pc++; - if (opcode & 0x80) { - /* More than one-byte opcode. */ - if (opcode & 0x40) { - /* Four-byte opcode */ - opcode &= 0x3F; - opcode = (opcode << 8) | Mem1(pc); - pc++; - opcode = (opcode << 8) | Mem1(pc); - pc++; - opcode = (opcode << 8) | Mem1(pc); - pc++; - } - else { - /* Two-byte opcode */ - opcode &= 0x7F; - opcode = (opcode << 8) | Mem1(pc); - pc++; - } - } - - /* Now we have an opcode number. */ - - /* Fetch the structure that describes how the operands for this - opcode are arranged. This is a pointer to an immutable, - static object. */ - if (opcode < 0x80) - oplist = fast_operandlist[opcode]; - else - oplist = lookup_operandlist(opcode); - - if (!oplist) - fatal_error_i("Encountered unknown opcode.", opcode); - - /* 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); - - /* Perform the opcode. This switch statement is split in two, based - on some paranoid suspicions about the ability of compilers to - optimize large-range switches. Ignore that. */ - - 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) - 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. 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 = -(int)(val0 / val1); - } - } - else { - val0 = vals0; - if (vals1 < 0) { - val1 = (-vals1); - value = -(int)(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) - fatal_error("Division by zero doing remainder."); - if (vals1 < 0) { - val1 = -vals1; - } - else { - val1 = vals1; - } - if (vals0 < 0) { - val0 = (-vals0); - value = -(int)(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 = (-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 = ((uint)(inst[0].value) << (uint)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 = ((uint)(inst[0].value) >> (uint)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 { - /* 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 = ((int)(inst[0].value) >> (int)vals0); - } - store_operand(inst[2].desttype, inst[2].value, value); - break; - - case op_jump: - value = inst[0].value; - /* fall through to PerformJump label. */ - - PerformJump: /* goto label for successful jumping... ironic, no? */ - if (value == 0 || value == 1) { - /* Return from function. This is exactly what happens in - return_op, but it's only a few lines of code, so I won't - bother with a "goto". */ - leave_function(); - if (stackptr == 0) { - done_executing = true; - break; - } - pop_callstub(value); /* zero or one */ - } - else { - /* Branch to a new PC value. */ - 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: - profile_fail("throw"); - value = inst[0].value; - stackptr = inst[1].value; - pop_callstub(value); - break; - - case op_copy: - value = inst[0].value; + while (!done_executing) { + + profile_tick(); + debugger_tick(); + /* Do OS-specific processing, if appropriate. */ + glk_tick(); + + /* Stash the current opcode's address, in case the interpreter needs to serialize the VM state out-of-band. */ + prevpc = pc; + + /* Fetch the opcode number. */ + opcode = Mem1(pc); + pc++; + if (opcode & 0x80) { + /* More than one-byte opcode. */ + if (opcode & 0x40) { + /* Four-byte opcode */ + opcode &= 0x3F; + opcode = (opcode << 8) | Mem1(pc); + pc++; + opcode = (opcode << 8) | Mem1(pc); + pc++; + opcode = (opcode << 8) | Mem1(pc); + pc++; + } else { + /* Two-byte opcode */ + opcode &= 0x7F; + opcode = (opcode << 8) | Mem1(pc); + pc++; + } + } + + /* Now we have an opcode number. */ + + /* Fetch the structure that describes how the operands for this + opcode are arranged. This is a pointer to an immutable, + static object. */ + if (opcode < 0x80) + oplist = fast_operandlist[opcode]; + else + oplist = lookup_operandlist(opcode); + + if (!oplist) + fatal_error_i("Encountered unknown opcode.", opcode); + + /* 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); + + /* Perform the opcode. This switch statement is split in two, based + on some paranoid suspicions about the ability of compilers to + optimize large-range switches. Ignore that. */ + + 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) + 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. 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 = -(int)(val0 / val1); + } + } else { + val0 = vals0; + if (vals1 < 0) { + val1 = (-vals1); + value = -(int)(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) + fatal_error("Division by zero doing remainder."); + if (vals1 < 0) { + val1 = -vals1; + } else { + val1 = vals1; + } + if (vals0 < 0) { + val0 = (-vals0); + value = -(int)(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 = (-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 = ((uint)(inst[0].value) << (uint)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 = ((uint)(inst[0].value) >> (uint)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 { + /* 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 = ((int)(inst[0].value) >> (int)vals0); + } + store_operand(inst[2].desttype, inst[2].value, value); + break; + + case op_jump: + value = inst[0].value; + /* fall through to PerformJump label. */ + +PerformJump: /* goto label for successful jumping... ironic, no? */ + if (value == 0 || value == 1) { + /* Return from function. This is exactly what happens in + return_op, but it's only a few lines of code, so I won't + bother with a "goto". */ + leave_function(); + if (stackptr == 0) { + done_executing = true; + break; + } + pop_callstub(value); /* zero or one */ + } else { + /* Branch to a new PC value. */ + 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: + profile_fail("throw"); + value = inst[0].value; + stackptr = inst[1].value; + pop_callstub(value); + break; + + case op_copy: + value = inst[0].value; #ifdef TOLERATE_SUPERGLUS_BUG - if (inst[1].desttype == 1 && inst[1].value == 0) - inst[1].desttype = 0; + if (inst[1].desttype == 1 && inst[1].value == 0) + inst[1].desttype = 0; #endif /* TOLERATE_SUPERGLUS_BUG */ - 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 &= ~((uint)(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 >= (int)(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) - fatal_error("Stack overflow in stkcopy."); - 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; - /* The following is a bit ugly. We want to do vals1 = vals0-vals1, - because rolling down is sort of easier than rolling up. But - we also want to take the result mod vals0. The % operator is - annoying for negative numbers, so we need to do this in two - cases. */ - if (vals1 > 0) { - vals1 = vals1 % vals0; - vals1 = (vals0) - vals1; - } - else { - vals1 = (-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_streamchar: - profile_in(0xE0000001, stackptr, false); - value = inst[0].value & 0xFF; - (this->*stream_char_handler)(value); - profile_out(stackptr); - break; - case op_streamunichar: - profile_in(0xE0000002, stackptr, false); - value = inst[0].value; - (this->*stream_unichar_handler)(value); - profile_out(stackptr); - break; - case op_streamnum: - profile_in(0xE0000003, stackptr, false); - vals0 = inst[0].value; - stream_num(vals0, false, 0); - profile_out(stackptr); - break; - case op_streamstr: - profile_in(0xE0000004, stackptr, false); - stream_string(inst[0].value, 0, 0); - profile_out(stackptr); - 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: + 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 &= ~((uint)(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 >= (int)(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) + fatal_error("Stack overflow in stkcopy."); + 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; + /* The following is a bit ugly. We want to do vals1 = vals0-vals1, + because rolling down is sort of easier than rolling up. But + we also want to take the result mod vals0. The % operator is + annoying for negative numbers, so we need to do this in two + cases. */ + if (vals1 > 0) { + vals1 = vals1 % vals0; + vals1 = (vals0) - vals1; + } else { + vals1 = (-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_streamchar: + profile_in(0xE0000001, stackptr, false); + value = inst[0].value & 0xFF; + (this->*stream_char_handler)(value); + profile_out(stackptr); + break; + case op_streamunichar: + profile_in(0xE0000002, stackptr, false); + value = inst[0].value; + (this->*stream_unichar_handler)(value); + profile_out(stackptr); + break; + case op_streamnum: + profile_in(0xE0000003, stackptr, false); + vals0 = inst[0].value; + stream_num(vals0, false, 0); + profile_out(stackptr); + break; + case op_streamstr: + profile_in(0xE0000004, stackptr, false); + stream_string(inst[0].value, 0, 0); + profile_out(stackptr); + 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: #if VM_DEBUGGER - /* We block and handle debug commands, but only if the - library has invoked debug features. (Meaning, has - the cycle handler ever been called.) */ - if (debugger_ever_invoked()) { - debugger_block_and_debug("user debugtrap, pausing..."); - break; - } + /* We block and handle debug commands, but only if the + library has invoked debug features. (Meaning, has + the cycle handler ever been called.) */ + if (debugger_ever_invoked()) { + debugger_block_and_debug("user debugtrap, pausing..."); + break; + } #endif /* VM_DEBUGGER */ - fatal_error_i("user debugtrap encountered.", inst[0].value); - - 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_getstringtbl: - value = stream_get_table(); - store_operand(inst[0].desttype, inst[0].value, value); - break; - case op_setstringtbl: - stream_set_table(inst[0].value); - break; - - case op_getiosys: - stream_get_iosys(&val0, &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[0].value, inst[1].value); - break; - - case op_glk: - profile_in(0xF0000000+inst[0].value, stackptr, false); - value = inst[1].value; - arglist = pop_arguments(value, 0); - val0 = perform_glk(inst[0].value, value, arglist); + fatal_error_i("user debugtrap encountered.", inst[0].value); + + 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_getstringtbl: + value = stream_get_table(); + store_operand(inst[0].desttype, inst[0].value, value); + break; + case op_setstringtbl: + stream_set_table(inst[0].value); + break; + + case op_getiosys: + stream_get_iosys(&val0, &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[0].value, inst[1].value); + break; + + case op_glk: + profile_in(0xF0000000 + inst[0].value, stackptr, false); + value = inst[1].value; + arglist = pop_arguments(value, 0); + val0 = perform_glk(inst[0].value, value, arglist); #ifdef TOLERATE_SUPERGLUS_BUG - if (inst[2].desttype == 1 && inst[2].value == 0) - inst[2].desttype = 0; + if (inst[2].desttype == 1 && inst[2].value == 0) + inst[2].desttype = 0; #endif /* TOLERATE_SUPERGLUS_BUG */ - store_operand(inst[2].desttype, inst[2].value, val0); - profile_out(stackptr); - break; - - case op_random: - vals0 = inst[0].value; - if (vals0 == 0) - value = glulx_random(); - else if (vals0 >= 1) - value = glulx_random() % (uint)(vals0); - else - value = -(int)(glulx_random() % (uint)(-vals0)); - store_operand(inst[1].desttype, inst[1].value, value); - break; - case op_setrandom: - glulx_setrandom(inst[0].value); - break; - - case op_verify: - value = perform_verify(); - store_operand(inst[0].desttype, inst[0].value, value); - break; - - case op_restart: - profile_fail("restart"); - vm_restart(); - break; - - case op_protect: - val0 = inst[0].value; - val1 = val0 + inst[1].value; - if (val0 == val1) { - val0 = 0; - val1 = 0; - } - protectstart = val0; - protectend = val1; - break; - - case op_save: - 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: - value = perform_restore(find_stream_by_id(inst[0].value), false); - if (value == 0) { - /* We've succeeded, and the stack now contains the callstub - saved during saveundo. Ignore this opcode's operand. */ - value = (uint)-1; - pop_callstub(value); - } - else { - /* We've failed, so we must store the failure in this opcode's - operand. */ - store_operand(inst[1].desttype, inst[1].value, value); - } - break; - - case op_saveundo: - push_callstub(inst[0].desttype, inst[0].value); - value = perform_saveundo(); - pop_callstub(value); - break; - - case op_restoreundo: - value = perform_restoreundo(); - if (value == 0) { - /* We've succeeded, and the stack now contains the callstub - saved during saveundo. Ignore this opcode's operand. */ - value = (uint)-1; - pop_callstub(value); - } - else { - /* We've failed, so we must store the failure in this opcode's - operand. */ - store_operand(inst[0].desttype, inst[0].value, value); - } - 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: { - uint lx; - uint count = inst[0].value; - addr = inst[1].value; - for (lx=0; lx<count; lx++, addr++) { - MemW1(addr, 0); - } - } - break; - case op_mcopy: { - uint lx; - uint count = inst[0].value; - uint addrsrc = inst[1].value; - uint 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: - accel_set_func(inst[0].value, inst[1].value); - break; - case op_accelparam: - accel_set_param(inst[0].value, inst[1].value); - break; + store_operand(inst[2].desttype, inst[2].value, val0); + profile_out(stackptr); + break; + + case op_random: + vals0 = inst[0].value; + if (vals0 == 0) + value = glulx_random(); + else if (vals0 >= 1) + value = glulx_random() % (uint)(vals0); + else + value = -(int)(glulx_random() % (uint)(-vals0)); + store_operand(inst[1].desttype, inst[1].value, value); + break; + case op_setrandom: + glulx_setrandom(inst[0].value); + break; + + case op_verify: + value = perform_verify(); + store_operand(inst[0].desttype, inst[0].value, value); + break; + + case op_restart: + profile_fail("restart"); + vm_restart(); + break; + + case op_protect: + val0 = inst[0].value; + val1 = val0 + inst[1].value; + if (val0 == val1) { + val0 = 0; + val1 = 0; + } + protectstart = val0; + protectend = val1; + break; + + case op_save: + 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: + value = perform_restore(find_stream_by_id(inst[0].value), false); + if (value == 0) { + /* We've succeeded, and the stack now contains the callstub + saved during saveundo. Ignore this opcode's operand. */ + value = (uint) - 1; + pop_callstub(value); + } else { + /* We've failed, so we must store the failure in this opcode's + operand. */ + store_operand(inst[1].desttype, inst[1].value, value); + } + break; + + case op_saveundo: + push_callstub(inst[0].desttype, inst[0].value); + value = perform_saveundo(); + pop_callstub(value); + break; + + case op_restoreundo: + value = perform_restoreundo(); + if (value == 0) { + /* We've succeeded, and the stack now contains the callstub + saved during saveundo. Ignore this opcode's operand. */ + value = (uint) - 1; + pop_callstub(value); + } else { + /* We've failed, so we must store the failure in this opcode's + operand. */ + store_operand(inst[0].desttype, inst[0].value, value); + } + 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: { + uint lx; + uint count = inst[0].value; + addr = inst[1].value; + for (lx = 0; lx < count; lx++, addr++) { + MemW1(addr, 0); + } + } + break; + case op_mcopy: { + uint lx; + uint count = inst[0].value; + uint addrsrc = inst[1].value; + uint 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: + accel_set_func(inst[0].value, inst[1].value); + break; + case op_accelparam: + 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 = (int)(truncf(valf)); - } - else { - if (isnan(valf) || isinf(valf) || (valf < -2147483647.0)) - vals0 = 0x80000000; - else - vals0 = (int)(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 = (int)(roundf(valf)); - } - else { - if (isnan(valf) || isinf(valf) || (valf < -2147483647.0)) - vals0 = 0x80000000; - else - vals0 = (int)(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; + 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 = (int)(truncf(valf)); + } else { + if (isnan(valf) || isinf(valf) || (valf < -2147483647.0)) + vals0 = 0x80000000; + else + vals0 = (int)(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 = (int)(roundf(valf)); + } else { + if (isnan(valf) || isinf(valf) || (valf < -2147483647.0)) + vals0 = 0x80000000; + else + vals0 = (int)(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 */ #ifdef GLULX_EXTEND_OPCODES - GLULX_EXTEND_OPCODES + GLULX_EXTEND_OPCODES #endif /* GLULX_EXTEND_OPCODES */ - default: - fatal_error_i("Executed unknown opcode.", opcode); - } - } - } - /* done executing */ + default: + fatal_error_i("Executed unknown opcode.", opcode); + } + } + } + /* done executing */ #if VM_DEBUGGER - debugger_handle_quit(); + debugger_handle_quit(); #endif /* VM_DEBUGGER */ } |