diff options
author | Alejandro Marzini | 2010-08-06 03:21:21 +0000 |
---|---|---|
committer | Alejandro Marzini | 2010-08-06 03:21:21 +0000 |
commit | 33e40e1a20c4cc60031854c87d6da5e461f9eb73 (patch) | |
tree | f76425d516e75d147ffbbacbec3fad49297da1b1 /engines/sci/engine/vm.cpp | |
parent | f97809a9a62a2d8840229facb2c2b6f75e37bad3 (diff) | |
parent | 6c8bcd2ba1cad1312f0a588ca284110bbbb81ccc (diff) | |
download | scummvm-rg350-33e40e1a20c4cc60031854c87d6da5e461f9eb73.tar.gz scummvm-rg350-33e40e1a20c4cc60031854c87d6da5e461f9eb73.tar.bz2 scummvm-rg350-33e40e1a20c4cc60031854c87d6da5e461f9eb73.zip |
Merged from trunk, from r51495 to r51775
svn-id: r51776
Diffstat (limited to 'engines/sci/engine/vm.cpp')
-rw-r--r-- | engines/sci/engine/vm.cpp | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index b7f6896a48..7bcc5b43a3 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -135,9 +135,13 @@ static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) { static int validate_arithmetic(reg_t reg) { if (reg.segment) { // The results of this are likely unpredictable... It most likely means that a kernel function is returning something wrong. - // If such an error occurs, we usually need to find the last kernel function called and check its return value. Check - // callKernelFunc() below - error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]. Address: %04x:%04x", reg.segment, PRINT_REG(reg)); + // If such an error occurs, we usually need to find the last kernel function called and check its return value. + if (g_sci->getGameId() == GID_QFG2 && g_sci->getEngineState()->currentRoomNumber() == 200) { + // WORKAROUND: This happens in QFG2, room 200, when talking to the astrologer (bug #3039879) - script bug. + // Returning 0 in this case. + } else { + error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]. Address: %04x:%04x", reg.segment, PRINT_REG(reg)); + } return 0; } @@ -231,7 +235,7 @@ static reg_t validate_read_var(reg_t *r, reg_t *stack_base, int type, int max, i case VAR_PARAM: // Out-of-bounds read for a parameter that goes onto stack and hits an uninitialized temp // We return 0 currently in that case - warning("Read for a parameter goes out-of-bounds, onto the stack and gets uninitialized temp"); + debugC(2, kDebugLevelVM, "[VM] Read for a parameter goes out-of-bounds, onto the stack and gets uninitialized temp"); return NULL_REG; default: break; @@ -743,6 +747,11 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) { if (kernelCall.debugLogging) logKernelCall(&kernelCall, NULL, s, argc, argv, s->r_acc); + if (kernelCall.debugBreakpoint) { + printf("Break on k%s\n", kernelCall.name); + g_sci->_debugState.debugging = true; + g_sci->_debugState.breakpointWasHit = true; + } } else { // Sub-functions available, check signature and call that one directly if (argc < 1) @@ -793,6 +802,11 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) { if (kernelSubCall.debugLogging) logKernelCall(&kernelCall, &kernelSubCall, s, argc, argv, s->r_acc); + if (kernelSubCall.debugBreakpoint) { + printf("Break on k%s\n", kernelSubCall.name); + g_sci->_debugState.debugging = true; + g_sci->_debugState.breakpointWasHit = true; + } } // Remove callk stack frame again, if there's still an execution stack @@ -923,11 +937,7 @@ void run_vm(EngineState *s) { obj = s->_segMan->getObject(s->xs->objp); local_script = s->_segMan->getScriptIfLoaded(s->xs->local_segment); if (!local_script) { - // FIXME: Why does this happen? Is the script not loaded yet at this point? - warning("Could not find local script from segment %x", s->xs->local_segment); - local_script = NULL; - s->variablesBase[VAR_LOCAL] = s->variables[VAR_LOCAL] = NULL; - s->variablesMax[VAR_LOCAL] = 0; + error("Could not find local script from segment %x", s->xs->local_segment); } else { s->variablesSegment[VAR_LOCAL] = local_script->_localsSegment; if (local_script->_localsBlock) @@ -1053,7 +1063,7 @@ void run_vm(EngineState *s) { if (validate_signedInteger(s->r_acc, value1) && validate_signedInteger(r_temp, value2)) s->r_acc = make_reg(0, value1 * value2); else - s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp); + s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeMulWorkarounds, s->r_acc, r_temp); break; } @@ -1069,11 +1079,30 @@ void run_vm(EngineState *s) { case op_mod: { // 0x05 (05) r_temp = POP32(); - int16 modulo, value; - if (validate_signedInteger(s->r_acc, modulo) && validate_signedInteger(r_temp, value)) - s->r_acc = make_reg(0, (modulo != 0 ? value % modulo : 0)); - else - s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp); + + if (getSciVersion() <= SCI_VERSION_0_LATE) { + uint16 modulo, value; + if (validate_unsignedInteger(s->r_acc, modulo) && validate_unsignedInteger(r_temp, value)) + s->r_acc = make_reg(0, (modulo != 0 ? value % modulo : 0)); + else + s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp); + } else { + // In Iceman (and perhaps from SCI0 0.000.685 onwards in general), + // handling for negative numbers was added. Since Iceman doesn't + // seem to have issues with the older code, we exclude it for now + // for simplicity's sake and use the new code for SCI01 and newer + // games. Fixes the battlecruiser mini game in SQ5 (room 850), + // bug #3035755 + int16 modulo, value, result; + if (validate_signedInteger(s->r_acc, modulo) && validate_signedInteger(r_temp, value)) { + modulo = ABS(modulo); + result = (modulo != 0 ? value % modulo : 0); + if (result < 0) + result += modulo; + s->r_acc = make_reg(0, result); + } else + s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, s->r_acc, r_temp); + } break; } @@ -1196,7 +1225,7 @@ void run_vm(EngineState *s) { if (validate_signedInteger(r_temp, compare1) && validate_signedInteger(s->r_acc, compare2)) s->r_acc = make_reg(0, compare1 >= compare2); else - s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc); + s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeGeWorkarounds, r_temp, s->r_acc); } break; |