aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorFilippos Karapetis2012-06-23 21:38:46 +0300
committerFilippos Karapetis2012-06-23 21:45:26 +0300
commit20b677080881580706652b17dd5a4c3ed3e36c07 (patch)
tree299521363c9962767c2acc7f28a6bb4f8aa747de /engines/sci
parentc1eb93bc5a9866787f27add5ca1d821e1470a4be (diff)
downloadscummvm-rg350-20b677080881580706652b17dd5a4c3ed3e36c07.tar.gz
scummvm-rg350-20b677080881580706652b17dd5a4c3ed3e36c07.tar.bz2
scummvm-rg350-20b677080881580706652b17dd5a4c3ed3e36c07.zip
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
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/console.cpp14
-rw-r--r--engines/sci/console.h2
-rw-r--r--engines/sci/engine/script.cpp4
-rw-r--r--engines/sci/engine/script.h2
-rw-r--r--engines/sci/engine/scriptdebug.cpp4
-rw-r--r--engines/sci/engine/vm.cpp15
-rw-r--r--engines/sci/engine/vm.h4
-rw-r--r--engines/sci/engine/vm_types.h43
8 files changed, 69 insertions, 19 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index b0ed7e6225..40a6fd1415 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -2913,7 +2913,8 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
if (jumpTarget > farthestTarget)
farthestTarget = jumpTarget;
}
- addr = disassemble(_engine->_gamestate, addr, printBWTag, printBytecode);
+ // TODO: Use a true 32-bit reg_t for the position (addr)
+ addr = disassemble(_engine->_gamestate, make_reg32(addr.getSegment(), addr.getOffset()), printBWTag, printBytecode);
if (addr.isNull() && prevAddr < farthestTarget)
addr = prevAddr + 1; // skip past the ret
} while (addr.getOffset() > 0);
@@ -2961,7 +2962,8 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) {
}
do {
- vpc = disassemble(_engine->_gamestate, vpc, printBWTag, printBytes);
+ // TODO: Use a true 32-bit reg_t for the position (vpc)
+ vpc = disassemble(_engine->_gamestate, make_reg32(vpc.getSegment(), vpc.getOffset()), printBWTag, printBytes);
} while ((vpc.getOffset() > 0) && (vpc.getOffset() + 6 < size) && (--opCount));
return true;
@@ -3652,10 +3654,14 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV
relativeOffset = true;
if (!scumm_strnicmp(str + 1, "PC", 2)) {
- *dest = s->_executionStack.back().addr.pc;
+ // TODO: Handle 32-bit PC addresses
+ reg32_t pc = s->_executionStack.back().addr.pc;
+ *dest = make_reg(pc.getSegment(), (uint16)pc.getOffset());
offsetStr = str + 3;
} else if (!scumm_strnicmp(str + 1, "P", 1)) {
- *dest = s->_executionStack.back().addr.pc;
+ // TODO: Handle 32-bit PC addresses
+ reg32_t pc = s->_executionStack.back().addr.pc;
+ *dest = make_reg(pc.getSegment(), (uint16)pc.getOffset());
offsetStr = str + 2;
} else if (!scumm_strnicmp(str + 1, "PREV", 4)) {
*dest = s->r_prev;
diff --git a/engines/sci/console.h b/engines/sci/console.h
index be17fdb728..1c54748842 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -33,7 +33,7 @@ namespace Sci {
class SciEngine;
struct List;
-reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode);
+reg_t disassemble(EngineState *s, reg32_t pos, bool printBWTag, bool printBytecode);
bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpOffset);
class Console : public GUI::Debugger {
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 80aaedfece..57334b89aa 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -385,7 +385,7 @@ void Script::setLockers(int lockers) {
_lockers = lockers;
}
-uint16 Script::validateExportFunc(int pubfunct, bool relocateSci3) {
+uint32 Script::validateExportFunc(int pubfunct, bool relocateSci3) {
bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
if (_numExports <= pubfunct) {
@@ -396,7 +396,7 @@ uint16 Script::validateExportFunc(int pubfunct, bool relocateSci3) {
if (exportsAreWide)
pubfunct *= 2;
- uint16 offset;
+ uint32 offset;
if (getSciVersion() != SCI_VERSION_3) {
offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h
index 9747f072c5..1fc8caf313 100644
--- a/engines/sci/engine/script.h
+++ b/engines/sci/engine/script.h
@@ -201,7 +201,7 @@ public:
* @return NULL if the public function is invalid, its
* offset into the script's segment otherwise
*/
- uint16 validateExportFunc(int pubfunct, bool relocateSci3);
+ uint32 validateExportFunc(int pubfunct, bool relocateSci3);
/**
* Marks the script as deleted.
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 04cbf1d97c..d3abb9ff41 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -68,7 +68,7 @@ const char *opcodeNames[] = {
#endif // REDUCE_MEMORY_USAGE
// Disassembles one command from the heap, returns address of next command or 0 if a ret was encountered.
-reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode) {
+reg_t disassemble(EngineState *s, reg32_t pos, bool printBWTag, bool printBytecode) {
SegmentObj *mobj = s->_segMan->getSegment(pos.getSegment(), SEG_TYPE_SCRIPT);
Script *script_entity = NULL;
const byte *scr;
@@ -347,7 +347,7 @@ void SciEngine::scriptDebug() {
}
if (_debugState.seeking != kDebugSeekNothing) {
- const reg_t pc = s->xs->addr.pc;
+ const reg32_t pc = s->xs->addr.pc;
SegmentObj *mobj = s->_segMan->getSegment(pc.getSegment(), SEG_TYPE_SCRIPT);
if (mobj) {
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]);
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index f2d225b1d8..a0fd6689df 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -82,7 +82,7 @@ struct ExecStack {
union {
ObjVarRef varp; // Variable pointer for r/w access
- reg_t pc; // Pointer to the initial program counter. Not accurate for the TOS element
+ reg32_t pc; // Pointer to the initial program counter. Not accurate for the TOS element
} addr;
StackPtr fp; // Frame pointer
@@ -102,7 +102,7 @@ struct ExecStack {
reg_t* getVarPointer(SegManager *segMan) const;
ExecStack(reg_t objp_, reg_t sendp_, StackPtr sp_, int argc_, StackPtr argp_,
- SegmentId localsSegment_, reg_t pc_, Selector debugSelector_,
+ SegmentId localsSegment_, reg32_t pc_, Selector debugSelector_,
int debugExportId_, int debugLocalCallOffset_, int debugOrigin_,
ExecStackType type_) {
objp = objp_;
diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h
index 2995ba3c12..9a7589e9a7 100644
--- a/engines/sci/engine/vm_types.h
+++ b/engines/sci/engine/vm_types.h
@@ -169,6 +169,49 @@ static inline reg_t make_reg(SegmentId segment, uint16 offset) {
#define PRINT_REG(r) (0xffff) & (unsigned) (r).getSegment(), (unsigned) (r).getOffset()
+// A true 32-bit reg_t
+struct reg32_t {
+ // Segment and offset. These should never be accessed directly
+ SegmentId _segment;
+ uint32 _offset;
+
+ inline SegmentId getSegment() const {
+ return _segment;
+ }
+
+ inline void setSegment(SegmentId segment) {
+ _segment = segment;
+ }
+
+ inline uint32 getOffset() const {
+ return _offset;
+ }
+
+ inline void setOffset(uint32 offset) {
+ _offset = offset;
+ }
+
+ inline void incOffset(int32 offset) {
+ setOffset(getOffset() + offset);
+ }
+
+ // Comparison operators
+ bool operator==(const reg32_t &x) const {
+ return (getOffset() == x.getOffset()) && (getSegment() == x.getSegment());
+ }
+
+ bool operator!=(const reg32_t &x) const {
+ return (getOffset() != x.getOffset()) || (getSegment() != x.getSegment());
+ }
+};
+
+static inline reg32_t make_reg32(SegmentId segment, uint32 offset) {
+ reg32_t r;
+ r.setSegment(segment);
+ r.setOffset(offset);
+ return r;
+}
+
// Stack pointer type
typedef reg_t *StackPtr;