From a0add53c6003a8ed42324d4bacc7f4745ee25543 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 15 Jun 2012 22:24:35 +0300 Subject: SCI: Change getClassAddress() to only require the caller segment The caller offset is never actually used inside the function --- engines/sci/engine/vm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines/sci/engine/vm.cpp') diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 162dce9fcc..7dc397c11e 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -996,7 +996,7 @@ void run_vm(EngineState *s) { case op_class: // 0x28 (40) // Get class address s->r_acc = s->_segMan->getClassAddress((unsigned)opparams[0], SCRIPT_GET_LOCK, - s->xs->addr.pc); + s->xs->addr.pc.segment); break; case 0x29: // (41) @@ -1021,7 +1021,7 @@ void run_vm(EngineState *s) { case op_super: // 0x2b (43) // Send to any class - r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc); + r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc.segment); if (!r_temp.isPointer()) error("[VM]: Invalid superclass in object"); -- cgit v1.2.3 From 2b50824133ced47f1d8fb6407a1e0212a7eeb41c Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 18 Jun 2012 05:21:59 +0300 Subject: SCI: Add setter/getter methods to reg_t's No functionality change has been made with this commit. This avoids setting and getting the reg_t members directly, and is the basis of any future work on large SCI3 scripts (larger than 64KB) --- engines/sci/engine/vm.cpp | 89 +++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 45 deletions(-) (limited to 'engines/sci/engine/vm.cpp') diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 7dc397c11e..89f59eaa14 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -119,7 +119,7 @@ extern const char *opcodeNames[]; // from scriptdebug.cpp static reg_t read_var(EngineState *s, int type, int index) { if (validate_variable(s->variables[type], s->stack_base, type, s->variablesMax[type], index)) { - if (s->variables[type][index].segment == 0xffff) { + if (s->variables[type][index].getSegment() == 0xffff) { switch (type) { case VAR_TEMP: { // Uninitialized read on a temp @@ -195,8 +195,8 @@ static void write_var(EngineState *s, int type, int index, reg_t value) { // this happens at least in sq1/room 44 (slot-machine), because a send is missing parameters, then // those parameters are taken from uninitialized stack and afterwards they are copied back into temps // if we don't remove the segment, we would get false-positive uninitialized reads later - if (type == VAR_TEMP && value.segment == 0xffff) - value.segment = 0; + if (type == VAR_TEMP && value.getSegment() == 0xffff) + value.setSegment(0); s->variables[type][index] = value; @@ -578,16 +578,16 @@ void run_vm(EngineState *s) { int var_type; // See description below int var_number; - g_sci->_debugState.old_pc_offset = s->xs->addr.pc.offset; + g_sci->_debugState.old_pc_offset = s->xs->addr.pc.getOffset(); g_sci->_debugState.old_sp = s->xs->sp; if (s->abortScriptProcessing != kAbortNone) return; // Stop processing if (s->_executionStackPosChanged) { - scr = s->_segMan->getScriptIfLoaded(s->xs->addr.pc.segment); + scr = s->_segMan->getScriptIfLoaded(s->xs->addr.pc.getSegment()); if (!scr) - error("No script in segment %d", s->xs->addr.pc.segment); + error("No script in segment %d", s->xs->addr.pc.getSegment()); s->xs = &(s->_executionStack.back()); s->_executionStackPosChanged = false; @@ -624,13 +624,13 @@ void run_vm(EngineState *s) { s->variablesMax[VAR_TEMP] = s->xs->sp - s->xs->fp; - if (s->xs->addr.pc.offset >= scr->getBufSize()) + if (s->xs->addr.pc.getOffset() >= scr->getBufSize()) error("run_vm(): program counter gone astray, addr: %d, code buffer size: %d", - s->xs->addr.pc.offset, scr->getBufSize()); + s->xs->addr.pc.getOffset(), scr->getBufSize()); // Get opcode byte extOpcode; - s->xs->addr.pc.offset += readPMachineInstruction(scr->getBuf() + s->xs->addr.pc.offset, extOpcode, opparams); + s->xs->addr.pc.incOffset(readPMachineInstruction(scr->getBuf(s->xs->addr.pc.getOffset()), extOpcode, opparams)); const byte opcode = extOpcode >> 1; //debug("%s: %d, %d, %d, %d, acc = %04x:%04x, script %d, local script %d", opcodeNames[opcode], opparams[0], opparams[1], opparams[2], opparams[3], PRINT_REG(s->r_acc), scr->getScriptNumber(), local_script->getScriptNumber()); @@ -705,7 +705,7 @@ void run_vm(EngineState *s) { break; case op_not: // 0x0c (12) - s->r_acc = make_reg(0, !(s->r_acc.offset || s->r_acc.segment)); + s->r_acc = make_reg(0, !(s->r_acc.getOffset() || s->r_acc.getSegment())); // Must allow pointers to be negated, as this is used for checking whether objects exist break; @@ -765,30 +765,30 @@ void run_vm(EngineState *s) { case op_bt: // 0x17 (23) // Branch relative if true - if (s->r_acc.offset || s->r_acc.segment) - s->xs->addr.pc.offset += opparams[0]; + if (s->r_acc.getOffset() || s->r_acc.getSegment()) + s->xs->addr.pc.incOffset(opparams[0]); - if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize()) error("[VM] op_bt: request to jump past the end of script %d (offset %d, script is %d bytes)", - local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); + local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize()); break; case op_bnt: // 0x18 (24) // Branch relative if not true - if (!(s->r_acc.offset || s->r_acc.segment)) - s->xs->addr.pc.offset += opparams[0]; + if (!(s->r_acc.getOffset() || s->r_acc.getSegment())) + s->xs->addr.pc.incOffset(opparams[0]); - if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize()) error("[VM] op_bnt: request to jump past the end of script %d (offset %d, script is %d bytes)", - local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); + local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize()); break; case op_jmp: // 0x19 (25) - s->xs->addr.pc.offset += opparams[0]; + s->xs->addr.pc.incOffset(opparams[0]); - if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + if (s->xs->addr.pc.getOffset() >= local_script->getScriptSize()) error("[VM] op_jmp: request to jump past the end of script %d (offset %d, script is %d bytes)", - local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); + local_script->getScriptNumber(), s->xs->addr.pc.getOffset(), local_script->getScriptSize()); break; case op_ldi: // 0x1a (26) @@ -831,13 +831,13 @@ void run_vm(EngineState *s) { int argc = (opparams[1] >> 1) // Given as offset, but we need count + 1 + s->r_rest; StackPtr call_base = s->xs->sp - argc; - s->xs->sp[1].offset += s->r_rest; + s->xs->sp[1].incOffset(s->r_rest); - uint16 localCallOffset = s->xs->addr.pc.offset + opparams[0]; + uint16 localCallOffset = s->xs->addr.pc.getOffset() + opparams[0]; ExecStack xstack(s->xs->objp, s->xs->objp, s->xs->sp, (call_base->requireUint16()) + s->r_rest, call_base, - s->xs->local_segment, make_reg(s->xs->addr.pc.segment, localCallOffset), + s->xs->local_segment, make_reg(s->xs->addr.pc.getSegment(), localCallOffset), NULL_SELECTOR, -1, localCallOffset, s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL); @@ -894,9 +894,9 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= temp; - s->xs->sp[0].offset += s->r_rest; + s->xs->sp[0].incOffset(s->r_rest); xs_new = execute_method(s, 0, opparams[0], s_temp, s->xs->objp, - s->xs->sp[0].offset, s->xs->sp); + s->xs->sp[0].getOffset(), s->xs->sp); s->r_rest = 0; // Used up the &rest adjustment if (xs_new) // in case of error, keep old stack s->_executionStackPosChanged = true; @@ -908,11 +908,10 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= temp; - s->xs->sp[0].offset += s->r_rest; + s->xs->sp[0].incOffset(s->r_rest); xs_new = execute_method(s, opparams[0], opparams[1], s_temp, s->xs->objp, - s->xs->sp[0].offset, s->xs->sp); + s->xs->sp[0].getOffset(), s->xs->sp); s->r_rest = 0; // Used up the &rest adjustment - if (xs_new) // in case of error, keep old stack s->_executionStackPosChanged = true; break; @@ -965,7 +964,7 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= ((opparams[0] >> 1) + s->r_rest); // Adjust stack - s->xs->sp[1].offset += s->r_rest; + s->xs->sp[1].incOffset(s->r_rest); xs_new = send_selector(s, s->r_acc, s->r_acc, s_temp, (int)(opparams[0] >> 1) + (uint16)s->r_rest, s->xs->sp); @@ -996,7 +995,7 @@ void run_vm(EngineState *s) { case op_class: // 0x28 (40) // Get class address s->r_acc = s->_segMan->getClassAddress((unsigned)opparams[0], SCRIPT_GET_LOCK, - s->xs->addr.pc.segment); + s->xs->addr.pc.getSegment()); break; case 0x29: // (41) @@ -1008,7 +1007,7 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= ((opparams[0] >> 1) + s->r_rest); // Adjust stack - s->xs->sp[1].offset += s->r_rest; + s->xs->sp[1].incOffset(s->r_rest); xs_new = send_selector(s, s->xs->objp, s->xs->objp, s_temp, (int)(opparams[0] >> 1) + (uint16)s->r_rest, s->xs->sp); @@ -1021,7 +1020,7 @@ void run_vm(EngineState *s) { case op_super: // 0x2b (43) // Send to any class - r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc.segment); + r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc.getSegment()); if (!r_temp.isPointer()) error("[VM]: Invalid superclass in object"); @@ -1029,7 +1028,7 @@ void run_vm(EngineState *s) { s_temp = s->xs->sp; s->xs->sp -= ((opparams[1] >> 1) + s->r_rest); // Adjust stack - s->xs->sp[1].offset += s->r_rest; + s->xs->sp[1].incOffset(s->r_rest); xs_new = send_selector(s, r_temp, s->xs->objp, s_temp, (int)(opparams[1] >> 1) + (uint16)s->r_rest, s->xs->sp); @@ -1058,14 +1057,14 @@ void run_vm(EngineState *s) { var_number = temp & 0x03; // Get variable type // Get variable block offset - r_temp.segment = s->variablesSegment[var_number]; - r_temp.offset = s->variables[var_number] - s->variablesBase[var_number]; + r_temp.setSegment(s->variablesSegment[var_number]); + r_temp.setOffset(s->variables[var_number] - s->variablesBase[var_number]); if (temp & 0x08) // Add accumulator offset if requested - r_temp.offset += s->r_acc.requireSint16(); + r_temp.incOffset(s->r_acc.requireSint16()); - r_temp.offset += opparams[1]; // Add index - r_temp.offset *= 2; // variables are 16 bit + r_temp.incOffset(opparams[1]); // Add index + r_temp.setOffset(r_temp.getOffset() * 2); // variables are 16 bit // That's the immediate address now s->r_acc = r_temp; break; @@ -1129,28 +1128,28 @@ void run_vm(EngineState *s) { case op_lofsa: // 0x39 (57) case op_lofss: // 0x3a (58) // Load offset to accumulator or push to stack - r_temp.segment = s->xs->addr.pc.segment; + r_temp.setSegment(s->xs->addr.pc.getSegment()); switch (g_sci->_features->detectLofsType()) { case SCI_VERSION_0_EARLY: - r_temp.offset = s->xs->addr.pc.offset + opparams[0]; + r_temp.setOffset(s->xs->addr.pc.getOffset() + opparams[0]); break; case SCI_VERSION_1_MIDDLE: - r_temp.offset = opparams[0]; + r_temp.setOffset(opparams[0]); break; case SCI_VERSION_1_1: - r_temp.offset = opparams[0] + local_script->getScriptSize(); + r_temp.setOffset(opparams[0] + local_script->getScriptSize()); break; case SCI_VERSION_3: // In theory this can break if the variant with a one-byte argument is // used. For now, assume it doesn't happen. - r_temp.offset = local_script->relocateOffsetSci3(s->xs->addr.pc.offset-2); + r_temp.setOffset(local_script->relocateOffsetSci3(s->xs->addr.pc.getOffset() - 2)); break; default: error("Unknown lofs type"); } - if (r_temp.offset >= scr->getBufSize()) + if (r_temp.getOffset() >= scr->getBufSize()) error("VM: lofsa/lofss operation overflowed: %04x:%04x beyond end" " of script (at %04x)", PRINT_REG(r_temp), scr->getBufSize()); -- cgit v1.2.3 From c1eb93bc5a9866787f27add5ca1d821e1470a4be Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 23 Jun 2012 21:20:43 +0300 Subject: SCI: Clean up validateExportFunc() and related functions Also renamed some SCI3 related code to indicate when it's SCI3 specific --- engines/sci/engine/vm.cpp | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'engines/sci/engine/vm.cpp') diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 89f59eaa14..a42606a6a6 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -225,30 +225,15 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP scr = s->_segMan->getScript(seg); } - int temp = scr->validateExportFunc(pubfunct, false); - - if (getSciVersion() == SCI_VERSION_3) - temp += scr->getCodeBlockOffset(); - - if (!temp) { -#ifdef ENABLE_SCI32 - if (g_sci->getGameId() == GID_TORIN && script == 64036) { - // Script 64036 in Torin's Passage is empty and contains an invalid - // (empty) export - } else if (g_sci->getGameId() == GID_RAMA && script == 64908) { - // Script 64908 in the demo of RAMA contains an invalid (empty) - // export - } else -#endif - error("Request for invalid exported function 0x%x of script %d", pubfunct, script); + uint32 exportAddr = scr->validateExportFunc(pubfunct, false); + if (!exportAddr) return NULL; - } - + // Check if a breakpoint is set on this method g_sci->checkExportBreakpoint(script, pubfunct); ExecStack xstack(calling_obj, calling_obj, sp, argc, argp, - seg, make_reg(seg, temp), -1, pubfunct, -1, + seg, make_reg(seg, exportAddr), -1, pubfunct, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL); s->_executionStack.push_back(xstack); return &(s->_executionStack.back()); -- cgit v1.2.3 From 20b677080881580706652b17dd5a4c3ed3e36c07 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 23 Jun 2012 21:38:46 +0300 Subject: SCI: Change the program counter (PC) to be a 32-bit variable This is needed for future support of large SCI3 scripts. The program counter is isolated and does not interfere with other parts of the VM, plus it does not get stored in saved games, so it's pretty straightforward to convert --- engines/sci/engine/vm.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'engines/sci/engine/vm.cpp') diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index a42606a6a6..5a2a39def2 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -233,7 +233,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP g_sci->checkExportBreakpoint(script, pubfunct); ExecStack xstack(calling_obj, calling_obj, sp, argc, argp, - seg, make_reg(seg, exportAddr), -1, pubfunct, -1, + seg, make_reg32(seg, exportAddr), -1, pubfunct, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL); s->_executionStack.push_back(xstack); return &(s->_executionStack.back()); @@ -289,11 +289,12 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt ExecStackType stackType = EXEC_STACK_TYPE_VARSELECTOR; StackPtr curSP = NULL; - reg_t curFP = NULL_REG; + reg32_t curFP = make_reg32(0, 0); if (selectorType == kSelectorMethod) { stackType = EXEC_STACK_TYPE_CALL; curSP = sp; - curFP = funcp; + // TODO: Will this offset suffice for large SCI3 scripts? + curFP = make_reg32(funcp.getSegment(), funcp.getOffset()); sp = CALL_SP_CARRY; // Destroy sp, as it will be carried over } @@ -327,7 +328,7 @@ static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int argc, // Add stack frame to indicate we're executing a callk. // This is useful in debugger backtraces if this // kernel function calls a script itself. - ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, 0xFFFF, NULL_REG, + ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, 0xFFFF, make_reg32(0, 0), kernelCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL); s->_executionStack.push_back(xstack); } @@ -818,11 +819,11 @@ void run_vm(EngineState *s) { StackPtr call_base = s->xs->sp - argc; s->xs->sp[1].incOffset(s->r_rest); - uint16 localCallOffset = s->xs->addr.pc.getOffset() + opparams[0]; + uint32 localCallOffset = s->xs->addr.pc.getOffset() + opparams[0]; ExecStack xstack(s->xs->objp, s->xs->objp, s->xs->sp, (call_base->requireUint16()) + s->r_rest, call_base, - s->xs->local_segment, make_reg(s->xs->addr.pc.getSegment(), localCallOffset), + s->xs->local_segment, make_reg32(s->xs->addr.pc.getSegment(), localCallOffset), NULL_SELECTOR, -1, localCallOffset, s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL); @@ -1117,7 +1118,7 @@ void run_vm(EngineState *s) { switch (g_sci->_features->detectLofsType()) { case SCI_VERSION_0_EARLY: - r_temp.setOffset(s->xs->addr.pc.getOffset() + opparams[0]); + r_temp.setOffset((uint16)s->xs->addr.pc.getOffset() + opparams[0]); break; case SCI_VERSION_1_MIDDLE: r_temp.setOffset(opparams[0]); -- cgit v1.2.3 From 34d00f59365cf05a8817ade955a6440ab3019860 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 26 Jul 2012 11:06:19 +0300 Subject: SCI: Add some debug code to op_line --- engines/sci/engine/vm.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'engines/sci/engine/vm.cpp') diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 5a2a39def2..3f43966976 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -1173,6 +1173,7 @@ void run_vm(EngineState *s) { case op_line: // 0x3f (63) // Debug opcode (line number) + //debug("Script %d, line %d", scr->getScriptNumber(), opparams[0]); break; case op_lag: // 0x40 (64) -- cgit v1.2.3 From 89abab97e3124fa25eb4c7d3e8b38501747a8d17 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 26 Sep 2012 04:17:31 +0200 Subject: JANITORIAL: Remove trailing whitespaces. Powered by: git ls-files "*.cpp" "*.h" "*.m" "*.mm" | xargs sed -i -e 's/[ \t]*$//' --- engines/sci/engine/vm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/sci/engine/vm.cpp') diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 3f43966976..ef8f165084 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -228,7 +228,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP uint32 exportAddr = scr->validateExportFunc(pubfunct, false); if (!exportAddr) return NULL; - + // Check if a breakpoint is set on this method g_sci->checkExportBreakpoint(script, pubfunct); -- cgit v1.2.3