2009-02-17 15:02:16 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
* $ URL $
* $ Id $
*
*/
2009-02-15 06:10:59 +00:00
2009-02-20 20:11:12 +00:00
# include "common/debug.h"
2009-04-11 09:58:30 +00:00
# include "common/stack.h"
2010-01-21 22:20:16 +00:00
# include "common/config-manager.h"
2009-02-15 06:10:59 +00:00
2009-05-14 09:12:27 +00:00
# include "sci/sci.h"
2009-07-06 10:39:22 +00:00
# include "sci/console.h"
2009-10-01 10:57:59 +00:00
# include "sci/debug.h" // for g_debugState
2009-05-15 14:07:45 +00:00
# include "sci/resource.h"
2009-02-27 02:23:40 +00:00
# include "sci/engine/state.h"
2009-02-24 05:51:55 +00:00
# include "sci/engine/kernel.h"
2009-02-15 08:34:13 +00:00
# include "sci/engine/kernel_types.h"
2009-02-16 09:23:58 +00:00
# include "sci/engine/seg_manager.h"
2010-01-29 11:05:06 +00:00
# include "sci/engine/script.h"
2009-02-15 08:34:13 +00:00
# include "sci/engine/gc.h"
2009-02-15 06:10:59 +00:00
2009-02-21 10:23:36 +00:00
namespace Sci {
2009-10-02 11:04:36 +00:00
const reg_t NULL_REG = { 0 , 0 } ;
const reg_t SIGNAL_REG = { 0 , SIGNAL_OFFSET } ;
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
//#define VM_DEBUG_SEND
2009-02-15 06:10:59 +00:00
2009-09-17 13:21:19 +00:00
ScriptState scriptState ;
2009-02-15 06:10:59 +00:00
2009-06-05 19:04:14 +00:00
int script_abort_flag = 0 ; // Set to 1 to abort execution. Set to 2 to force a replay afterwards // FIXME: Avoid non-const global vars
2009-06-04 11:28:05 +00:00
int script_step_counter = 0 ; // Counts the number of steps executed // FIXME: Avoid non-const global vars
int script_gc_interval = GC_INTERVAL ; // Number of steps in between gcs // FIXME: Avoid non-const global vars
2009-02-15 06:10:59 +00:00
2009-06-04 11:28:05 +00:00
static bool breakpointFlag = false ; // FIXME: Avoid non-const global vars
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// validation functionality
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2009-03-12 03:26:47 +00:00
static reg_t & validate_property ( Object * obj , int index ) {
2009-10-02 11:04:36 +00:00
// A static dummy reg_t, which we return if obj or index turn out to be
// invalid. Note that we cannot just return NULL_REG, because client code
// may modify the value of the return reg_t.
static reg_t dummyReg = NULL_REG ;
2009-02-15 22:28:12 +00:00
if ( ! obj ) {
2009-05-30 15:40:49 +00:00
debugC ( 2 , kDebugLevelVM , " [VM] Sending to disposed object! \n " ) ;
2009-10-02 11:04:36 +00:00
return dummyReg ;
2009-02-15 06:10:59 +00:00
}
2009-10-10 15:58:51 +00:00
if ( index < 0 | | ( uint ) index > = obj - > getVarCount ( ) ) {
2010-01-25 01:39:44 +00:00
debugC ( 2 , kDebugLevelVM , " [VM] Invalid property #%d (out of [0..%d]) requested! \n " ,
2009-10-10 15:58:51 +00:00
index , obj - > getVarCount ( ) ) ;
2009-10-02 11:04:36 +00:00
return dummyReg ;
2009-02-15 06:10:59 +00:00
}
2009-05-12 23:30:42 +00:00
return obj - > _variables [ index ] ;
2009-02-15 06:10:59 +00:00
}
2009-03-12 03:26:47 +00:00
static StackPtr validate_stack_addr ( EngineState * s , StackPtr sp ) {
2009-02-15 06:10:59 +00:00
if ( sp > = s - > stack_base & & sp < s - > stack_top )
return sp ;
2010-01-25 01:39:44 +00:00
error ( " [VM] Stack index %d out of valid range [%d..%d] " ,
2009-05-30 15:40:49 +00:00
( int ) ( sp - s - > stack_base ) , 0 , ( int ) ( s - > stack_top - s - > stack_base - 1 ) ) ;
2009-02-15 06:10:59 +00:00
return 0 ;
}
2009-03-12 03:26:47 +00:00
static int validate_arithmetic ( reg_t reg ) {
2009-02-15 06:10:59 +00:00
if ( reg . segment ) {
2010-01-27 13:14:28 +00:00
// When using a pointer in number arithmetic, we substitute a large value as
// some scripts rely on this (cf. Hoyle hack in kAbs).
2009-10-01 10:57:59 +00:00
warning ( " [VM] Attempt to read arithmetic value from non-zero segment [%04x] " , reg . segment ) ;
2010-01-27 13:14:28 +00:00
return 0x3e9 ;
2009-02-15 06:10:59 +00:00
}
return reg . offset ;
}
2009-03-12 03:26:47 +00:00
static int signed_validate_arithmetic ( reg_t reg ) {
2009-02-15 06:10:59 +00:00
if ( reg . segment ) {
2009-10-01 10:57:59 +00:00
warning ( " [VM] Attempt to read arithmetic value from non-zero segment [%04x] " , reg . segment ) ;
2010-01-27 13:14:28 +00:00
return 0x3e9 ;
2009-02-15 06:10:59 +00:00
}
2009-02-15 22:28:12 +00:00
2009-10-01 12:41:21 +00:00
if ( reg . offset & 0x8000 )
2009-02-15 22:28:12 +00:00
return ( signed ) ( reg . offset ) - 65536 ;
2009-02-15 06:10:59 +00:00
else
return reg . offset ;
}
2009-10-30 18:01:27 +00:00
static bool validate_variable ( reg_t * r , reg_t * stack_base , int type , int max , int index , int line ) {
2009-02-15 06:10:59 +00:00
const char * names [ 4 ] = { " global " , " local " , " temp " , " param " } ;
if ( index < 0 | | index > = max ) {
2009-10-12 12:03:06 +00:00
Common : : String txt = Common : : String : : printf (
2010-01-25 01:39:44 +00:00
" [VM] Attempt to use invalid %s variable %04x " ,
2009-10-12 12:03:06 +00:00
names [ type ] , index ) ;
2009-02-15 06:10:59 +00:00
if ( max = = 0 )
2009-10-02 12:44:12 +00:00
txt + = " (variable type invalid) " ;
else
txt + = Common : : String : : printf ( " (out of range [%d..%d]) " , 0 , max - 1 ) ;
2009-06-03 09:45:16 +00:00
2009-10-02 12:44:12 +00:00
warning ( " %s " , txt . c_str ( ) ) ;
2009-02-15 06:10:59 +00:00
if ( type = = VAR_PARAM | | type = = VAR_TEMP ) {
int total_offset = r - stack_base ;
if ( total_offset < 0 | | total_offset > = VM_STACK_SIZE ) {
2009-07-06 10:39:22 +00:00
warning ( " [VM] Access would be outside even of the stack (%d); access denied " , total_offset ) ;
2009-10-30 18:01:27 +00:00
return false ;
2009-02-15 06:10:59 +00:00
} else {
2009-07-06 10:39:22 +00:00
debugC ( 2 , kDebugLevelVM , " [VM] Access within stack boundaries; access granted. \n " ) ;
2009-10-30 18:01:27 +00:00
return true ;
2009-02-15 06:10:59 +00:00
}
2009-06-03 09:45:16 +00:00
}
2009-10-30 18:01:27 +00:00
return false ;
2009-02-15 06:10:59 +00:00
}
2009-10-30 18:01:27 +00:00
return true ;
2009-02-15 06:10:59 +00:00
}
2009-03-12 03:26:47 +00:00
static reg_t validate_read_var ( reg_t * r , reg_t * stack_base , int type , int max , int index , int line , reg_t default_value ) {
2009-10-30 18:01:27 +00:00
if ( validate_variable ( r , stack_base , type , max , index , line ) )
2009-02-15 06:10:59 +00:00
return r [ index ] ;
else
return default_value ;
}
2009-10-21 08:28:39 +00:00
static void validate_write_var ( reg_t * r , reg_t * stack_base , int type , int max , int index , int line , reg_t value , SegManager * segMan , Kernel * kernel ) {
2009-10-30 18:01:27 +00:00
if ( validate_variable ( r , stack_base , type , max , index , line ) ) {
2009-10-21 08:28:39 +00:00
2009-10-21 10:00:08 +00:00
// WORKAROUND: This code is needed to work around a probable script bug, or a
// limitation of the original SCI engine, which can be observed in LSL5.
//
// In some games, ego walks via the "Grooper" object, in particular its "stopGroop"
// child. In LSL5, during the game, ego is swapped from Larry to Patti. When this
// happens in the original interpreter, the new actor is loaded in the same memory
// location as the old one, therefore the client variable in the stopGroop object
// points to the new actor. This is probably why the reference of the stopGroop
// object is never updated (which is why I mentioned that this is either a script
// bug or some kind of limitation).
//
// In our implementation, each new object is loaded in a different memory location,
// and we can't overwrite the old one. This means that in our implementation,
// whenever ego is changed, we need to update the "client" variable of the
// stopGroop object, which points to ego, to the new ego object. If this is not
// done, ego's movement will not be updated properly, so the result is
// unpredictable (for example in LSL5, Patti spins around instead of walking).
2009-10-21 08:28:39 +00:00
if ( index = = 0 & & type = = VAR_GLOBAL ) { // global 0 is ego
reg_t stopGroopPos = segMan - > findObjectByName ( " stopGroop " ) ;
if ( ! stopGroopPos . isNull ( ) ) { // does the game have a stopGroop object?
2009-10-22 05:42:14 +00:00
// Find the "client" member variable of the stopGroop object, and update it
2009-10-21 08:28:39 +00:00
ObjVarRef varp ;
if ( lookup_selector ( segMan , stopGroopPos , kernel - > _selectorCache . client , & varp , NULL ) = = kSelectorVariable ) {
reg_t * clientVar = varp . getPointer ( segMan ) ;
* clientVar = value ;
}
}
}
2009-02-15 06:10:59 +00:00
r [ index ] = value ;
2009-10-21 08:28:39 +00:00
}
2009-02-15 06:10:59 +00:00
}
# else
2009-02-20 23:09:29 +00:00
// Non-validating alternatives
2009-02-15 06:10:59 +00:00
# define validate_stack_addr(s, sp) sp
# define validate_arithmetic(r) ((r).offset)
2009-02-20 23:09:29 +00:00
# define signed_validate_arithmetic(r) ((int) ((r).offset) & 0x8000 ? (signed) ((r).offset) - 65536 : ((r).offset))
2009-02-15 06:10:59 +00:00
# define validate_variable(r, sb, t, m, i, l)
2010-01-03 21:12:44 +00:00
# define validate_read_var(r, sb, t, m, i, l, dv) ((r)[i])
2009-10-21 08:28:39 +00:00
# define validate_write_var(r, sb, t, m, i, l, v, sm, k) ((r)[i] = (v))
2009-05-12 23:30:42 +00:00
# define validate_property(o, p) ((o)->_variables[p])
2009-02-15 06:10:59 +00:00
# endif
2009-07-08 10:25:37 +00:00
# define READ_VAR(type, index, def) validate_read_var(scriptState.variables[type], s->stack_base, type, scriptState.variables_max[type], index, __LINE__, def)
2009-10-21 08:28:39 +00:00
# define WRITE_VAR(type, index, value) validate_write_var(scriptState.variables[type], s->stack_base, type, scriptState.variables_max[type], index, __LINE__, value, s->_segMan, s->_kernel)
2009-02-15 06:10:59 +00:00
# define WRITE_VAR16(type, index, value) WRITE_VAR(type, index, make_reg(0, value));
# define ACC_ARITHMETIC_L(op) make_reg(0, (op validate_arithmetic(s->r_acc)))
# define ACC_AUX_LOAD() aux_acc = signed_validate_arithmetic(s->r_acc)
# define ACC_AUX_STORE() s->r_acc = make_reg(0, aux_acc)
2009-02-21 22:06:42 +00:00
# define OBJ_PROPERTY(o, p) (validate_property(o, p))
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// Operating on the stack
// 16 bit:
2009-02-15 06:10:59 +00:00
# define PUSH(v) PUSH32(make_reg(0, v))
# define POP() (validate_arithmetic(POP32()))
2009-02-20 23:09:29 +00:00
// 32 bit:
2009-07-08 10:25:37 +00:00
# define PUSH32(a) (*(validate_stack_addr(s, (scriptState.xs->sp)++)) = (a))
# define POP32() (*(validate_stack_addr(s, --(scriptState.xs->sp))))
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// Getting instruction parameters
2009-07-08 10:25:37 +00:00
# define GET_OP_BYTE() ((uint8)code_buf[(scriptState.xs->addr.pc.offset)++])
# define GET_OP_WORD() (READ_LE_UINT16(code_buf + ((scriptState.xs->addr.pc.offset) += 2) - 2))
2009-02-15 06:10:59 +00:00
# define GET_OP_FLEX() ((opcode & 1)? GET_OP_BYTE() : GET_OP_WORD())
2009-07-08 10:25:37 +00:00
# define GET_OP_SIGNED_BYTE() ((int8)(code_buf[(scriptState.xs->addr.pc.offset)++]))
# define GET_OP_SIGNED_WORD() (((int16)READ_LE_UINT16(code_buf + ((scriptState.xs->addr.pc.offset) += 2) - 2)))
2009-02-15 06:10:59 +00:00
# define GET_OP_SIGNED_FLEX() ((opcode & 1)? GET_OP_SIGNED_BYTE() : GET_OP_SIGNED_WORD())
2009-03-12 03:26:47 +00:00
ExecStack * execute_method ( EngineState * s , uint16 script , uint16 pubfunct , StackPtr sp , reg_t calling_obj , uint16 argc , StackPtr argp ) {
2009-10-04 18:38:18 +00:00
int seg = s - > _segMan - > getScriptSegment ( script ) ;
Script * scr = s - > _segMan - > getScriptIfLoaded ( seg ) ;
2009-02-15 06:10:59 +00:00
2009-09-28 20:21:09 +00:00
if ( ! scr | | scr - > isMarkedAsDeleted ( ) ) // Script not present yet?
2009-10-04 18:38:18 +00:00
seg = script_instantiate ( s - > resMan , s - > _segMan , script ) ;
2009-02-15 06:10:59 +00:00
2009-10-04 18:38:18 +00:00
const int temp = s - > _segMan - > validateExportFunc ( pubfunct , seg ) ;
2009-02-15 22:28:12 +00:00
if ( ! temp ) {
2010-01-06 14:04:56 +00:00
# ifdef ENABLE_SCI32
// HACK: Temporarily switch to a warning in SCI32 games until we can figure out why Torin has
// an invalid exported function.
if ( getSciVersion ( ) > = SCI_VERSION_2 )
warning ( " Request for invalid exported function 0x%x of script 0x%x " , pubfunct , script ) ;
else
# endif
error ( " Request for invalid exported function 0x%x of script 0x%x " , pubfunct , script ) ;
2009-02-15 06:10:59 +00:00
return NULL ;
}
2009-02-20 23:09:29 +00:00
// Check if a breakpoint is set on this method
2009-02-15 22:28:12 +00:00
if ( s - > have_bp & BREAK_EXPORT ) {
2009-02-28 11:12:59 +00:00
Breakpoint * bp ;
2009-02-21 21:16:41 +00:00
uint32 bpaddress ;
2009-02-15 22:28:12 +00:00
bpaddress = ( script < < 16 | pubfunct ) ;
bp = s - > bp_list ;
while ( bp ) {
if ( bp - > type = = BREAK_EXPORT & & bp - > data . address = = bpaddress ) {
2009-07-06 10:39:22 +00:00
Console * con = ( ( SciEngine * ) g_engine ) - > getSciDebugger ( ) ;
con - > DebugPrintf ( " Break on script %d, export %d \n " , script , pubfunct ) ;
2009-09-17 13:21:19 +00:00
g_debugState . debugging = true ;
2009-04-11 09:58:30 +00:00
breakpointFlag = true ;
2009-02-15 22:28:12 +00:00
break ;
}
bp = bp - > next ;
}
}
2009-05-18 18:15:45 +00:00
return add_exec_stack_entry ( s , make_reg ( seg , temp ) , sp , calling_obj , argc , argp , - 1 , calling_obj , s - > _executionStack . size ( ) - 1 , seg ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-22 13:11:43 +00:00
static void _exec_varselectors ( EngineState * s ) {
2009-02-20 23:09:29 +00:00
// Executes all varselector read/write ops on the TOS
2009-05-19 00:02:10 +00:00
while ( ! s - > _executionStack . empty ( ) & & s - > _executionStack . back ( ) . type = = EXEC_STACK_TYPE_VARSELECTOR ) {
ExecStack & xs = s - > _executionStack . back ( ) ;
2009-10-04 18:38:18 +00:00
reg_t * var = xs . getVarPointer ( s - > _segMan ) ;
2009-10-14 22:41:03 +00:00
if ( ! var ) {
warning ( " Invalid varselector exec stack entry " ) ;
} else {
// varselector access?
if ( xs . argc ) { // write?
* var = xs . variables_argp [ 1 ] ;
} else // No, read
s - > r_acc = * var ;
}
2009-05-19 00:02:10 +00:00
s - > _executionStack . pop_back ( ) ;
}
2009-02-15 06:10:59 +00:00
}
2009-09-17 16:56:36 +00:00
/** This struct is used to buffer the list of send calls in send_selector() */
struct CallsStruct {
reg_t addr_func ;
reg_t varp_objp ;
union {
reg_t func ;
ObjVarRef var ;
} address ;
StackPtr argp ;
int argc ;
Selector selector ;
StackPtr sp ; /**< Stack pointer */
int type ; /**< Same as ExecStack.type */
} ;
2009-02-28 11:12:59 +00:00
ExecStack * send_selector ( EngineState * s , reg_t send_obj , reg_t work_obj , StackPtr sp , int framesize , StackPtr argp ) {
2009-02-20 23:09:29 +00:00
// send_obj and work_obj are equal for anything but 'super'
// Returns a pointer to the TOS exec_stack element
2009-05-18 18:15:45 +00:00
assert ( s ) ;
2009-02-15 06:10:59 +00:00
reg_t funcp ;
int selector ;
int argc ;
2009-05-18 18:15:45 +00:00
int origin = s - > _executionStack . size ( ) - 1 ; // Origin: Used for debugging
2009-02-15 06:10:59 +00:00
int print_send_action = 0 ;
2009-02-28 11:12:59 +00:00
// We return a pointer to the new active ExecStack
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// The selector calls we catch are stored below:
2009-04-11 09:58:30 +00:00
Common : : Stack < CallsStruct > sendCalls ;
2009-02-15 06:10:59 +00:00
while ( framesize > 0 ) {
selector = validate_arithmetic ( * argp + + ) ;
argc = validate_arithmetic ( * argp ) ;
2009-02-20 23:09:29 +00:00
if ( argc > 0x800 ) { // More arguments than the stack could possibly accomodate for
2009-07-03 21:59:07 +00:00
error ( " send_selector(): More than 0x800 arguments to function call " ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-20 23:09:29 +00:00
// Check if a breakpoint is set on this method
2009-02-15 06:10:59 +00:00
if ( s - > have_bp & BREAK_SELECTOR ) {
2009-02-28 11:12:59 +00:00
Breakpoint * bp ;
2009-02-15 06:10:59 +00:00
char method_name [ 256 ] ;
2009-10-04 18:38:18 +00:00
sprintf ( method_name , " %s::%s " , s - > _segMan - > getObjectName ( send_obj ) , s - > _kernel - > getSelectorName ( selector ) . c_str ( ) ) ;
2009-02-15 06:10:59 +00:00
bp = s - > bp_list ;
while ( bp ) {
int cmplen = strlen ( bp - > data . name ) ;
if ( bp - > data . name [ cmplen - 1 ] ! = ' : ' )
cmplen = 256 ;
2009-02-15 22:28:12 +00:00
if ( bp - > type = = BREAK_SELECTOR & & ! strncmp ( bp - > data . name , method_name , cmplen ) ) {
2009-07-06 10:39:22 +00:00
Console * con = ( ( SciEngine * ) g_engine ) - > getSciDebugger ( ) ;
con - > DebugPrintf ( " Break on %s (in [%04x:%04x]) \n " , method_name , PRINT_REG ( send_obj ) ) ;
2009-05-31 15:34:23 +00:00
print_send_action = 1 ;
2009-04-11 09:58:30 +00:00
breakpointFlag = true ;
2009-09-17 13:21:19 +00:00
g_debugState . debugging = true ;
2009-02-15 06:10:59 +00:00
break ;
}
bp = bp - > next ;
}
}
# ifdef VM_DEBUG_SEND
2009-10-14 22:40:43 +00:00
printf ( " Send to %04x:%04x, selector %04x (%s): " , PRINT_REG ( send_obj ) , selector , ( ( SciEngine * ) g_engine ) - > getKernel ( ) - > getSelectorName ( selector ) . c_str ( ) ) ;
2009-02-20 23:09:29 +00:00
# endif // VM_DEBUG_SEND
2009-02-15 06:10:59 +00:00
2009-06-06 11:38:20 +00:00
ObjVarRef varp ;
2009-10-04 18:38:18 +00:00
switch ( lookup_selector ( s - > _segMan , send_obj , selector , & varp , & funcp ) ) {
2009-02-28 11:12:59 +00:00
case kSelectorNone :
2010-01-28 10:34:11 +00:00
error ( " Send to invalid selector 0x%x of object at %04x:%04x " , 0xffff & selector , PRINT_REG ( send_obj ) ) ;
2009-02-15 06:10:59 +00:00
break ;
2009-02-28 11:12:59 +00:00
case kSelectorVariable :
2009-02-15 06:10:59 +00:00
# ifdef VM_DEBUG_SEND
if ( argc )
2009-07-06 10:39:22 +00:00
printf ( " Varselector: Write %04x:%04x \n " , PRINT_REG ( argp [ 1 ] ) ) ;
2009-02-15 06:10:59 +00:00
else
2009-07-06 10:39:22 +00:00
printf ( " Varselector: Read \n " ) ;
2009-02-20 23:09:29 +00:00
# endif // VM_DEBUG_SEND
2009-02-15 06:10:59 +00:00
2009-10-01 12:41:21 +00:00
// argc == 0: read selector
// argc == 1: write selector
// argc > 1: write selector?
if ( print_send_action & & argc = = 0 ) { // read selector
printf ( " [read selector] \n " ) ;
print_send_action = 0 ;
}
2009-02-15 06:10:59 +00:00
2009-10-01 12:41:21 +00:00
if ( print_send_action & & argc > 0 ) {
2009-10-04 18:38:18 +00:00
reg_t oldReg = * varp . getPointer ( s - > _segMan ) ;
2009-10-01 12:41:21 +00:00
reg_t newReg = argp [ 1 ] ;
printf ( " [write to selector: change %04x:%04x to %04x:%04x] \n " , PRINT_REG ( oldReg ) , PRINT_REG ( newReg ) ) ;
print_send_action = 0 ;
}
if ( argc > 1 )
warning ( " send_selector(): more than 1 parameter (%d) while modifying a variable selector " , argc ) ;
{
CallsStruct call ;
call . address . var = varp ; // register the call
call . argp = argp ;
call . argc = argc ;
call . selector = selector ;
call . type = EXEC_STACK_TYPE_VARSELECTOR ; // Register as a varselector
sendCalls . push ( call ) ;
2009-02-15 06:10:59 +00:00
}
2010-01-25 01:39:44 +00:00
2009-02-15 06:10:59 +00:00
break ;
2009-02-28 11:12:59 +00:00
case kSelectorMethod :
2009-02-15 06:10:59 +00:00
# ifdef VM_DEBUG_SEND
2009-07-06 10:39:22 +00:00
printf ( " Funcselector( " ) ;
2009-05-18 18:15:45 +00:00
for ( int i = 0 ; i < argc ; i + + ) {
2009-10-14 22:40:43 +00:00
printf ( " %04x:%04x " , PRINT_REG ( argp [ i + 1 ] ) ) ;
2009-02-15 06:10:59 +00:00
if ( i + 1 < argc )
2009-07-06 10:39:22 +00:00
printf ( " , " ) ;
2009-02-15 06:10:59 +00:00
}
2009-07-06 10:39:22 +00:00
printf ( " ) at %04x:%04x \n " , PRINT_REG ( funcp ) ) ;
2009-02-20 23:09:29 +00:00
# endif // VM_DEBUG_SEND
2009-02-15 06:10:59 +00:00
if ( print_send_action ) {
2009-07-06 10:39:22 +00:00
printf ( " [invoke selector] \n " ) ;
2009-02-15 06:10:59 +00:00
print_send_action = 0 ;
}
2009-10-01 12:41:21 +00:00
{
CallsStruct call ;
call . address . func = funcp ; // register call
call . argp = argp ;
call . argc = argc ;
call . selector = selector ;
call . type = EXEC_STACK_TYPE_CALL ;
call . sp = sp ;
sp = CALL_SP_CARRY ; // Destroy sp, as it will be carried over
sendCalls . push ( call ) ;
}
2009-02-15 06:10:59 +00:00
break ;
2009-09-30 16:16:53 +00:00
} // switch (lookup_selector())
2009-02-15 06:10:59 +00:00
framesize - = ( 2 + argc ) ;
argp + = argc + 1 ;
}
2009-02-20 23:09:29 +00:00
// Iterate over all registered calls in the reverse order. This way, the first call is
// placed on the TOS; as soon as it returns, it will cause the second call to be executed.
2009-04-11 09:58:30 +00:00
while ( ! sendCalls . empty ( ) ) {
CallsStruct call = sendCalls . pop ( ) ;
if ( call . type = = EXEC_STACK_TYPE_VARSELECTOR ) // Write/read variable?
2009-04-28 15:58:19 +00:00
add_exec_stack_varselector ( s , work_obj , call . argc , call . argp ,
2009-04-11 09:58:30 +00:00
call . selector , call . address . var , origin ) ;
2009-02-15 06:10:59 +00:00
else
2009-04-28 15:58:19 +00:00
add_exec_stack_entry ( s , call . address . func , call . sp , work_obj ,
2009-04-11 09:58:30 +00:00
call . argc , call . argp ,
call . selector , send_obj , origin , SCI_XS_CALLEE_LOCALS ) ;
}
2009-02-15 06:10:59 +00:00
_exec_varselectors ( s ) ;
2009-05-18 18:15:45 +00:00
if ( s - > _executionStack . empty ( ) )
return NULL ;
return & ( s - > _executionStack . back ( ) ) ;
2009-02-15 06:10:59 +00:00
}
2009-06-06 11:38:20 +00:00
ExecStack * add_exec_stack_varselector ( EngineState * s , reg_t objp , int argc , StackPtr argp , Selector selector , const ObjVarRef & address , int origin ) {
ExecStack * xstack = add_exec_stack_entry ( s , NULL_REG , 0 , objp , argc , argp , selector , objp , origin , SCI_XS_CALLEE_LOCALS ) ;
2009-02-20 23:09:29 +00:00
// Store selector address in sp
2009-02-15 06:10:59 +00:00
xstack - > addr . varp = address ;
xstack - > type = EXEC_STACK_TYPE_VARSELECTOR ;
return xstack ;
}
2009-02-28 11:12:59 +00:00
ExecStack * add_exec_stack_entry ( EngineState * s , reg_t pc , StackPtr sp , reg_t objp , int argc ,
2009-09-16 23:32:27 +00:00
StackPtr argp , Selector selector , reg_t sendp , int origin , SegmentId _localsSegment ) {
2009-02-20 23:09:29 +00:00
// Returns new TOS element for the execution stack
2009-09-16 23:32:27 +00:00
// _localsSegment may be -1 if derived from the called object
2009-02-15 06:10:59 +00:00
2009-07-06 10:39:22 +00:00
//printf("Exec stack: [%d/%d], origin %d, at %p\n", s->execution_stack_pos, s->_executionStack.size(), origin, s->execution_stack);
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
ExecStack xstack ;
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
xstack . objp = objp ;
2009-09-16 23:32:27 +00:00
if ( _localsSegment ! = SCI_XS_CALLEE_LOCALS )
xstack . local_segment = _localsSegment ;
2009-02-15 06:10:59 +00:00
else
2009-05-18 18:15:45 +00:00
xstack . local_segment = pc . segment ;
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
xstack . sendp = sendp ;
xstack . addr . pc = pc ;
xstack . fp = xstack . sp = sp ;
xstack . argc = argc ;
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
xstack . variables_argp = argp ; // Parameters
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
* argp = make_reg ( 0 , argc ) ; // SCI code relies on the zeroeth argument to equal argc
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// Additional debug information
2009-05-18 18:15:45 +00:00
xstack . selector = selector ;
xstack . origin = origin ;
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
xstack . type = EXEC_STACK_TYPE_CALL ; // Normal call
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
s - > _executionStack . push_back ( xstack ) ;
return & ( s - > _executionStack . back ( ) ) ;
2009-02-15 06:10:59 +00:00
}
2010-01-03 21:12:44 +00:00
# ifdef DISABLE_VALIDATIONS
2009-02-15 06:10:59 +00:00
# define kernel_matches_signature(a, b, c, d) 1
# endif
2009-02-21 10:47:56 +00:00
static reg_t pointer_add ( EngineState * s , reg_t base , int offset ) {
2009-10-04 18:38:18 +00:00
SegmentObj * mobj = s - > _segMan - > getSegmentObj ( base . segment ) ;
2009-02-15 06:10:59 +00:00
if ( ! mobj ) {
2009-07-06 10:39:22 +00:00
error ( " [VM] Error: Attempt to add %d to invalid pointer %04x:%04x " , offset , PRINT_REG ( base ) ) ;
2009-02-15 06:10:59 +00:00
return NULL_REG ;
}
2009-05-03 09:30:33 +00:00
switch ( mobj - > getType ( ) ) {
2009-02-15 06:10:59 +00:00
2009-09-17 00:45:12 +00:00
case SEG_TYPE_LOCALS :
case SEG_TYPE_SCRIPT :
case SEG_TYPE_STACK :
case SEG_TYPE_DYNMEM :
2009-02-15 06:10:59 +00:00
base . offset + = offset ;
return base ;
break ;
default :
2009-10-15 15:07:47 +00:00
// Changed this to warning, because iceman does this during dancing with girl
2010-01-03 17:40:17 +00:00
warning ( " [VM] Error: Attempt to add %d to pointer %04x:%04x, type %d: Pointer arithmetics of this type unsupported " , offset , PRINT_REG ( base ) , mobj - > getType ( ) ) ;
2009-02-15 06:10:59 +00:00
return NULL_REG ;
}
}
2009-03-12 03:26:47 +00:00
static void gc_countdown ( EngineState * s ) {
2009-02-15 06:10:59 +00:00
if ( s - > gc_countdown - - < = 0 ) {
s - > gc_countdown = script_gc_interval ;
run_gc ( s ) ;
}
}
2009-03-12 03:26:58 +00:00
static const byte _fake_return_buffer [ 2 ] = { op_ret < < 1 , op_ret < < 1 } ;
2009-02-15 06:10:59 +00:00
2009-02-21 10:47:56 +00:00
void run_vm ( EngineState * s , int restoring ) {
2009-05-19 00:02:10 +00:00
assert ( s ) ;
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2009-02-20 23:09:29 +00:00
unsigned int code_buf_size = 0 ; // (Avoid spurious warning)
2009-02-15 06:10:59 +00:00
# endif
int temp ;
2009-02-21 21:16:41 +00:00
int16 aux_acc ; // Auxiliary 16 bit accumulator
2009-02-20 23:09:29 +00:00
reg_t r_temp ; // Temporary register
2009-02-28 11:12:59 +00:00
StackPtr s_temp ; // Temporary stack pointer
2009-02-21 21:16:41 +00:00
int16 opparams [ 4 ] ; // opcode parameters
2010-01-21 22:20:16 +00:00
bool loadFromGMM = ConfMan . hasKey ( " save_slot " ) ? true : false ;
if ( loadFromGMM ) {
if ( ConfMan . getInt ( " save_slot " ) < 0 )
loadFromGMM = false ; // already loaded
}
2009-02-20 23:09:29 +00:00
2009-07-11 06:19:29 +00:00
scriptState . restAdjust = s - > restAdjust ;
2009-02-20 23:09:29 +00:00
// &rest adjusts the parameter count by this value
// Current execution data:
2009-07-08 10:25:37 +00:00
scriptState . xs = & ( s - > _executionStack . back ( ) ) ;
2009-02-28 11:12:59 +00:00
ExecStack * xs_new = NULL ;
2009-10-04 18:38:18 +00:00
Object * obj = s - > _segMan - > getObject ( scriptState . xs - > objp ) ;
Script * local_script = s - > _segMan - > getScriptIfLoaded ( scriptState . xs - > local_segment ) ;
2009-02-20 23:09:29 +00:00
int old_execution_stack_base = s - > execution_stack_base ;
2009-02-22 13:11:43 +00:00
// Used to detect the stack bottom, for "physical" returns
2009-03-12 03:26:58 +00:00
const byte * code_buf = NULL ; // (Avoid spurious warning)
2009-02-15 06:10:59 +00:00
if ( ! local_script ) {
2009-07-03 21:59:07 +00:00
error ( " run_vm(): program counter gone astray (local_script pointer is null) " ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-15 22:28:12 +00:00
2009-02-15 06:10:59 +00:00
if ( ! restoring )
2009-05-18 18:15:45 +00:00
s - > execution_stack_base = s - > _executionStack . size ( ) - 1 ;
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2009-02-20 23:09:29 +00:00
// Initialize maximum variable count
2009-09-16 23:32:27 +00:00
if ( s - > script_000 - > _localsBlock )
scriptState . variables_max [ VAR_GLOBAL ] = s - > script_000 - > _localsBlock - > _locals . size ( ) ;
2009-02-15 06:10:59 +00:00
else
2009-07-08 10:25:37 +00:00
scriptState . variables_max [ VAR_GLOBAL ] = 0 ;
2009-02-15 06:10:59 +00:00
# endif
2009-09-16 23:32:27 +00:00
scriptState . variables_seg [ VAR_GLOBAL ] = s - > script_000 - > _localsSegment ;
2009-07-08 10:25:37 +00:00
scriptState . variables_seg [ VAR_TEMP ] = scriptState . variables_seg [ VAR_PARAM ] = s - > stack_segment ;
scriptState . variables_base [ VAR_TEMP ] = scriptState . variables_base [ VAR_PARAM ] = s - > stack_base ;
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// SCI code reads the zeroeth argument to determine argc
2009-09-16 23:32:27 +00:00
if ( s - > script_000 - > _localsBlock )
scriptState . variables_base [ VAR_GLOBAL ] = scriptState . variables [ VAR_GLOBAL ] = s - > script_000 - > _localsBlock - > _locals . begin ( ) ;
2009-02-15 06:10:59 +00:00
else
2009-07-08 10:25:37 +00:00
scriptState . variables_base [ VAR_GLOBAL ] = scriptState . variables [ VAR_GLOBAL ] = NULL ;
2009-02-15 06:10:59 +00:00
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ; // Force initialization
2009-02-15 06:10:59 +00:00
while ( 1 ) {
byte opcode ;
byte opnumber ;
2009-02-20 23:09:29 +00:00
int var_type ; // See description below
2009-02-15 06:10:59 +00:00
int var_number ;
2009-09-17 13:21:19 +00:00
g_debugState . old_pc_offset = scriptState . xs - > addr . pc . offset ;
g_debugState . old_sp = scriptState . xs - > sp ;
2009-02-15 06:10:59 +00:00
2009-04-28 15:58:19 +00:00
if ( s - > _executionStackPosChanged ) {
2009-02-28 11:12:59 +00:00
Script * scr ;
2009-07-08 10:25:37 +00:00
scriptState . xs = & ( s - > _executionStack . back ( ) ) ;
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = false ;
2009-02-15 06:10:59 +00:00
2009-10-04 18:38:18 +00:00
scr = s - > _segMan - > getScriptIfLoaded ( scriptState . xs - > addr . pc . segment ) ;
2009-02-15 06:10:59 +00:00
if ( ! scr ) {
2009-02-20 23:09:29 +00:00
// No script? Implicit return via fake instruction buffer
2009-07-08 10:25:37 +00:00
warning ( " Running on non-existant script in segment %x " , scriptState . xs - > addr . pc . segment ) ;
2009-02-15 06:10:59 +00:00
code_buf = _fake_return_buffer ;
# ifndef DISABLE_VALIDATIONS
code_buf_size = 2 ;
# endif
2009-07-08 10:25:37 +00:00
scriptState . xs - > addr . pc . offset = 1 ;
2009-02-15 06:10:59 +00:00
scr = NULL ;
obj = NULL ;
} else {
2009-10-04 18:38:18 +00:00
obj = s - > _segMan - > getObject ( scriptState . xs - > objp ) ;
2009-09-16 23:32:27 +00:00
code_buf = scr - > _buf ;
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2009-09-16 23:32:27 +00:00
code_buf_size = scr - > _bufSize ;
2009-02-15 06:10:59 +00:00
# endif
2009-10-04 18:38:18 +00:00
local_script = s - > _segMan - > getScriptIfLoaded ( scriptState . xs - > local_segment ) ;
2009-02-15 06:10:59 +00:00
if ( ! local_script ) {
2009-07-08 10:25:37 +00:00
warning ( " Could not find local script from segment %x " , scriptState . xs - > local_segment ) ;
2009-02-15 06:10:59 +00:00
local_script = NULL ;
2009-07-08 10:25:37 +00:00
scriptState . variables_base [ VAR_LOCAL ] = scriptState . variables [ VAR_LOCAL ] = NULL ;
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2009-07-08 10:25:37 +00:00
scriptState . variables_max [ VAR_LOCAL ] = 0 ;
2009-02-15 06:10:59 +00:00
# endif
} else {
2009-09-16 23:32:27 +00:00
scriptState . variables_seg [ VAR_LOCAL ] = local_script - > _localsSegment ;
if ( local_script - > _localsBlock )
scriptState . variables_base [ VAR_LOCAL ] = scriptState . variables [ VAR_LOCAL ] = local_script - > _localsBlock - > _locals . begin ( ) ;
2009-02-15 06:10:59 +00:00
else
2009-07-08 10:25:37 +00:00
scriptState . variables_base [ VAR_LOCAL ] = scriptState . variables [ VAR_LOCAL ] = NULL ;
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2009-09-16 23:32:27 +00:00
if ( local_script - > _localsBlock )
scriptState . variables_max [ VAR_LOCAL ] = local_script - > _localsBlock - > _locals . size ( ) ;
2009-02-15 06:10:59 +00:00
else
2009-07-08 10:25:37 +00:00
scriptState . variables_max [ VAR_LOCAL ] = 0 ;
scriptState . variables_max [ VAR_TEMP ] = scriptState . xs - > sp - scriptState . xs - > fp ;
scriptState . variables_max [ VAR_PARAM ] = scriptState . xs - > argc + 1 ;
2009-02-15 06:10:59 +00:00
# endif
}
2009-07-08 10:25:37 +00:00
scriptState . variables [ VAR_TEMP ] = scriptState . xs - > fp ;
scriptState . variables [ VAR_PARAM ] = scriptState . xs - > variables_argp ;
2009-02-15 06:10:59 +00:00
}
}
2009-07-19 10:50:14 +00:00
if ( script_abort_flag | | g_engine - > shouldQuit ( ) )
2009-02-20 23:09:29 +00:00
return ; // Emergency
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// Debug if this has been requested:
2009-07-18 12:51:12 +00:00
// TODO: re-implement sci_debug_flags
2009-09-17 13:21:19 +00:00
if ( g_debugState . debugging /* sci_debug_flags*/ ) {
2009-07-08 10:25:37 +00:00
script_debug ( s , breakpointFlag ) ;
2009-04-11 09:58:30 +00:00
breakpointFlag = false ;
2009-02-15 06:10:59 +00:00
}
2009-07-18 12:51:12 +00:00
Console * con = ( ( Sci : : SciEngine * ) g_engine ) - > getSciDebugger ( ) ;
if ( con - > isAttached ( ) ) {
con - > onFrame ( ) ;
}
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2009-07-08 10:25:37 +00:00
if ( scriptState . xs - > sp < scriptState . xs - > fp )
2009-07-03 21:59:07 +00:00
error ( " run_vm(): stack underflow " ) ;
2009-02-15 06:10:59 +00:00
2009-07-08 10:25:37 +00:00
scriptState . variables_max [ VAR_TEMP ] = scriptState . xs - > sp - scriptState . xs - > fp ;
2009-02-15 06:10:59 +00:00
2009-07-08 10:25:37 +00:00
if ( scriptState . xs - > addr . pc . offset > = code_buf_size )
2009-07-03 21:59:07 +00:00
error ( " run_vm(): program counter gone astray " ) ;
2009-02-15 06:10:59 +00:00
# endif
2009-02-20 23:09:29 +00:00
opcode = GET_OP_BYTE ( ) ; // Get opcode
2009-02-15 06:10:59 +00:00
opnumber = opcode > > 1 ;
2010-01-28 13:07:47 +00:00
for ( temp = 0 ; g_opcode_formats [ opnumber ] [ temp ] ; temp + + ) {
//printf("Opcode: 0x%x, Opnumber: 0x%x, temp: %d\n", opcode, opnumber, temp);
2009-04-20 19:28:33 +00:00
switch ( g_opcode_formats [ opnumber ] [ temp ] ) {
2009-02-15 06:10:59 +00:00
2009-02-15 22:28:12 +00:00
case Script_Byte :
opparams [ temp ] = GET_OP_BYTE ( ) ;
break ;
case Script_SByte :
opparams [ temp ] = GET_OP_SIGNED_BYTE ( ) ;
break ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:28:12 +00:00
case Script_Word :
opparams [ temp ] = GET_OP_WORD ( ) ;
break ;
case Script_SWord :
opparams [ temp ] = GET_OP_SIGNED_WORD ( ) ;
break ;
2009-02-15 06:10:59 +00:00
case Script_Variable :
case Script_Property :
case Script_Local :
case Script_Temp :
case Script_Global :
case Script_Param :
2009-02-15 22:28:12 +00:00
opparams [ temp ] = GET_OP_FLEX ( ) ;
break ;
2009-02-15 06:10:59 +00:00
case Script_SVariable :
case Script_SRelative :
2009-02-15 22:28:12 +00:00
opparams [ temp ] = GET_OP_SIGNED_FLEX ( ) ;
break ;
2009-02-15 06:10:59 +00:00
case Script_Offset :
2009-02-15 22:28:12 +00:00
opparams [ temp ] = GET_OP_FLEX ( ) ;
break ;
2009-02-15 06:10:59 +00:00
case Script_None :
case Script_End :
break ;
case Script_Invalid :
default :
2009-05-31 15:34:23 +00:00
error ( " opcode %02x: Invalid " , opcode ) ;
2009-02-15 06:10:59 +00:00
}
2010-01-28 13:07:47 +00:00
}
2009-02-15 06:10:59 +00:00
switch ( opnumber ) {
2010-01-28 13:07:47 +00:00
case op_bnot : // 0x00 (00)
2009-02-15 22:28:12 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( 0xffff ^ /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_add : // 0x01 (01)
2009-02-15 06:10:59 +00:00
r_temp = POP32 ( ) ;
if ( r_temp . segment | | s - > r_acc . segment ) {
2009-05-14 23:09:04 +00:00
reg_t r_ptr = NULL_REG ;
2009-02-15 06:10:59 +00:00
int offset ;
2009-02-20 23:09:29 +00:00
// Pointer arithmetics!
2009-02-15 06:10:59 +00:00
if ( s - > r_acc . segment ) {
if ( r_temp . segment ) {
2009-05-31 15:34:23 +00:00
error ( " Attempt to add two pointers, stack=%04x:%04x and acc=%04x:%04x " ,
2009-02-21 14:11:41 +00:00
PRINT_REG ( r_temp ) , PRINT_REG ( s - > r_acc ) ) ;
2009-02-15 06:10:59 +00:00
offset = 0 ;
} else {
2009-02-15 22:28:12 +00:00
r_ptr = s - > r_acc ;
2009-02-15 06:10:59 +00:00
offset = r_temp . offset ;
}
} else {
r_ptr = r_temp ;
offset = s - > r_acc . offset ;
}
s - > r_acc = pointer_add ( s , r_ptr , offset ) ;
} else
s - > r_acc = make_reg ( 0 , r_temp . offset + s - > r_acc . offset ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_sub : // 0x02 (02)
2009-02-15 06:10:59 +00:00
r_temp = POP32 ( ) ;
2010-01-27 12:13:39 +00:00
if ( r_temp . segment ! = s - > r_acc . segment ) {
2009-05-14 23:09:04 +00:00
reg_t r_ptr = NULL_REG ;
2009-02-15 06:10:59 +00:00
int offset ;
2009-02-20 23:09:29 +00:00
// Pointer arithmetics!
2009-02-15 06:10:59 +00:00
if ( s - > r_acc . segment ) {
if ( r_temp . segment ) {
2009-05-31 15:34:23 +00:00
error ( " Attempt to subtract two pointers, stack=%04x:%04x and acc=%04x:%04x " ,
2009-02-21 14:11:41 +00:00
PRINT_REG ( r_temp ) , PRINT_REG ( s - > r_acc ) ) ;
2009-02-15 06:10:59 +00:00
offset = 0 ;
} else {
2009-02-15 22:28:12 +00:00
r_ptr = s - > r_acc ;
2009-02-15 06:10:59 +00:00
offset = r_temp . offset ;
}
} else {
r_ptr = r_temp ;
offset = s - > r_acc . offset ;
}
s - > r_acc = pointer_add ( s , r_ptr , - offset ) ;
2010-01-27 12:13:39 +00:00
} else {
// We can subtract numbers, or pointers with the same segment,
// an operation which will yield a number like in C
2009-02-15 06:10:59 +00:00
s - > r_acc = make_reg ( 0 , r_temp . offset - s - > r_acc . offset ) ;
2010-01-27 12:13:39 +00:00
}
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_mul : // 0x03 (03)
2009-02-21 21:16:41 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( ( ( int16 ) POP ( ) ) * ( int16 ) /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_div : // 0x04 (04)
2009-02-15 06:10:59 +00:00
ACC_AUX_LOAD ( ) ;
2009-02-21 21:16:41 +00:00
aux_acc = aux_acc ! = 0 ? ( ( int16 ) POP ( ) ) / aux_acc : 0 ;
2009-02-15 06:10:59 +00:00
ACC_AUX_STORE ( ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_mod : // 0x05 (05)
2009-02-15 06:10:59 +00:00
ACC_AUX_LOAD ( ) ;
2009-02-21 21:16:41 +00:00
aux_acc = aux_acc ! = 0 ? ( ( int16 ) POP ( ) ) % aux_acc : 0 ;
2009-02-15 06:10:59 +00:00
ACC_AUX_STORE ( ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_shr : // 0x06 (06)
s - > r_acc = ACC_ARITHMETIC_L ( ( ( uint16 ) POP ( ) ) > > /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_shl : // 0x07 (07)
2009-02-21 21:16:41 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( ( ( uint16 ) POP ( ) ) < < /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_xor : // 0x08 (08)
2009-02-15 06:10:59 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( POP ( ) ^ /*acc*/ ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_and : // 0x09 (09)
2009-02-15 06:10:59 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( POP ( ) & /*acc*/ ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_or : // 0x0a (10)
2009-02-15 06:10:59 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( POP ( ) | /*acc*/ ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_neg : // 0x0b (11)
2009-02-15 06:10:59 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( - /*acc*/ ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_not : // 0x0c (12)
2009-02-15 06:10:59 +00:00
s - > r_acc = make_reg ( 0 , ! ( s - > r_acc . offset | | s - > r_acc . segment ) ) ;
2009-02-22 13:11:43 +00:00
// Must allow pointers to be negated, as this is used for checking whether objects exist
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_eq_ : // 0x0d (13)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
r_temp = POP32 ( ) ;
2009-05-21 17:18:46 +00:00
s - > r_acc = make_reg ( 0 , r_temp = = s - > r_acc ) ;
2009-02-20 23:09:29 +00:00
// Explicitly allow pointers to be compared
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_ne_ : // 0x0e (14)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
r_temp = POP32 ( ) ;
2009-05-21 17:18:46 +00:00
s - > r_acc = make_reg ( 0 , r_temp ! = s - > r_acc ) ;
2009-02-20 23:09:29 +00:00
// Explicitly allow pointers to be compared
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_gt_ : // 0x0f (15)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
2010-01-27 01:47:41 +00:00
r_temp = POP32 ( ) ;
if ( r_temp . segment & & s - > r_acc . segment ) {
// Signed pointer comparison. We do unsigned comparison instead, as that is probably what was intended.
// FIXME: Add a warning when pointers in different segments are compared
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset > s - > r_acc . offset ) ;
} else
2010-01-27 03:37:56 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( ( int16 ) validate_arithmetic ( r_temp ) > ( int16 ) /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_ge_ : // 0x10 (16)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
2010-01-27 01:47:41 +00:00
r_temp = POP32 ( ) ;
if ( r_temp . segment & & s - > r_acc . segment )
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset > = s - > r_acc . offset ) ;
else
2010-01-27 03:37:56 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( ( int16 ) validate_arithmetic ( r_temp ) > = ( int16 ) /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_lt_ : // 0x11 (17)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
2010-01-27 01:47:41 +00:00
r_temp = POP32 ( ) ;
if ( r_temp . segment & & s - > r_acc . segment )
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset < s - > r_acc . offset ) ;
else
2010-01-27 03:37:56 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( ( int16 ) validate_arithmetic ( r_temp ) < ( int16 ) /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_le_ : // 0x12 (18)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
2010-01-27 01:47:41 +00:00
r_temp = POP32 ( ) ;
if ( r_temp . segment & & s - > r_acc . segment )
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset < = s - > r_acc . offset ) ;
else
2010-01-27 03:37:56 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( ( int16 ) validate_arithmetic ( r_temp ) < = ( int16 ) /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_ugt_ : // 0x13 (19)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
r_temp = POP32 ( ) ;
2010-01-27 13:14:28 +00:00
if ( r_temp . segment & & s - > r_acc . segment )
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset > s - > r_acc . offset ) ;
else
s - > r_acc = ACC_ARITHMETIC_L ( validate_arithmetic ( r_temp ) > /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_uge_ : // 0x14 (20)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
r_temp = POP32 ( ) ;
2010-01-29 22:29:03 +00:00
// SCI0/SCI1 scripts use this to check whether a
// parameter is a pointer or a far text
// reference. It is used e.g. by the standard library
// Print function to distinguish two ways of calling it:
//
// (Print "foo") // Pointer to a string
// (Print 420 5) // Reference to the fifth message in text resource 420
// It works because in those games, the maximum resource number is 999,
// so any parameter value above that threshold must be a pointer.
2010-01-29 22:17:27 +00:00
if ( s - > r_acc = = make_reg ( 0 , 0x3e8 ) )
s - > r_acc = make_reg ( 0 , r_temp . segment ) ;
else if ( r_temp . segment & & s - > r_acc . segment )
2010-01-27 13:14:28 +00:00
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset > = s - > r_acc . offset ) ;
else
s - > r_acc = ACC_ARITHMETIC_L ( validate_arithmetic ( r_temp ) > = /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_ult_ : // 0x15 (21)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
r_temp = POP32 ( ) ;
2010-01-29 22:29:03 +00:00
// See above
2010-01-29 22:17:27 +00:00
if ( s - > r_acc = = make_reg ( 0 , 0x3e8 ) )
s - > r_acc = make_reg ( 0 , ! r_temp . segment ) ;
else if ( r_temp . segment & & s - > r_acc . segment )
2010-01-27 13:14:28 +00:00
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset < s - > r_acc . offset ) ;
else
s - > r_acc = ACC_ARITHMETIC_L ( validate_arithmetic ( r_temp ) < /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_ule_ : // 0x16 (22)
2009-02-15 06:10:59 +00:00
s - > r_prev = s - > r_acc ;
r_temp = POP32 ( ) ;
2010-01-27 13:14:28 +00:00
if ( r_temp . segment & & s - > r_acc . segment )
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset < = s - > r_acc . offset ) ;
else
s - > r_acc = ACC_ARITHMETIC_L ( validate_arithmetic ( r_temp ) < = /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_bt : // 0x17 (23)
2009-02-15 06:10:59 +00:00
if ( s - > r_acc . offset | | s - > r_acc . segment )
2009-07-08 10:25:37 +00:00
scriptState . xs - > addr . pc . offset + = opparams [ 0 ] ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_bnt : // 0x18 (24)
2009-02-15 06:10:59 +00:00
if ( ! ( s - > r_acc . offset | | s - > r_acc . segment ) )
2009-07-08 10:25:37 +00:00
scriptState . xs - > addr . pc . offset + = opparams [ 0 ] ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_jmp : // 0x19 (25)
2009-07-08 10:25:37 +00:00
scriptState . xs - > addr . pc . offset + = opparams [ 0 ] ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_ldi : // 0x1a (26)
2009-02-15 06:10:59 +00:00
s - > r_acc = make_reg ( 0 , opparams [ 0 ] ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_push : // 0x1b (27)
2009-02-15 06:10:59 +00:00
PUSH32 ( s - > r_acc ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_pushi : // 0x1c (28)
2009-02-15 06:10:59 +00:00
PUSH ( opparams [ 0 ] ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_toss : // 0x1d (29)
2009-07-08 10:25:37 +00:00
scriptState . xs - > sp - - ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_dup : // 0x1e (30)
2009-07-08 10:25:37 +00:00
r_temp = scriptState . xs - > sp [ - 1 ] ;
2009-02-15 06:10:59 +00:00
PUSH32 ( r_temp ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_link : // 0x1f (31)
for ( int i = 0 ; i < opparams [ 0 ] ; i + + )
2009-07-08 10:25:37 +00:00
scriptState . xs - > sp [ i ] = NULL_REG ;
scriptState . xs - > sp + = opparams [ 0 ] ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_call : { // 0x20 (32)
2009-02-22 13:11:43 +00:00
int argc = ( opparams [ 1 ] > > 1 ) // Given as offset, but we need count
2009-07-11 06:19:29 +00:00
+ 1 + scriptState . restAdjust ;
2009-07-08 10:25:37 +00:00
StackPtr call_base = scriptState . xs - > sp - argc ;
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp [ 1 ] . offset + = scriptState . restAdjust ;
xs_new = add_exec_stack_entry ( s , make_reg ( scriptState . xs - > addr . pc . segment ,
scriptState . xs - > addr . pc . offset + opparams [ 0 ] ) ,
2010-01-25 01:39:44 +00:00
scriptState . xs - > sp , scriptState . xs - > objp ,
2009-07-11 06:19:29 +00:00
( validate_arithmetic ( * call_base ) ) + scriptState . restAdjust ,
call_base , NULL_SELECTOR , scriptState . xs - > objp ,
s - > _executionStack . size ( ) - 1 , scriptState . xs - > local_segment ) ;
scriptState . restAdjust = 0 ; // Used up the &rest adjustment
2009-07-08 10:25:37 +00:00
scriptState . xs - > sp = call_base ;
2009-02-15 06:10:59 +00:00
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
break ;
}
2010-01-28 13:07:47 +00:00
case op_callk : { // 0x21 (33)
2009-02-15 06:10:59 +00:00
gc_countdown ( s ) ;
2009-07-08 10:25:37 +00:00
scriptState . xs - > sp - = ( opparams [ 1 ] > > 1 ) + 1 ;
2009-08-25 08:38:14 +00:00
2009-09-17 16:50:53 +00:00
bool oldScriptHeader = ( getSciVersion ( ) = = SCI_VERSION_0_EARLY ) ;
2009-09-17 13:20:58 +00:00
if ( ! oldScriptHeader ) {
scriptState . xs - > sp - = scriptState . restAdjust ;
s - > restAdjust = 0 ; // We just used up the scriptState.restAdjust, remember?
2009-02-15 06:10:59 +00:00
}
2009-09-17 17:00:36 +00:00
if ( opparams [ 0 ] > = ( int ) s - > _kernel - > _kernelFuncs . size ( ) ) {
2009-08-20 21:03:03 +00:00
error ( " Invalid kernel function 0x%x requested " , opparams [ 0 ] ) ;
2009-02-15 06:10:59 +00:00
} else {
2009-09-17 17:00:36 +00:00
const KernelFuncWithSignature & kfun = s - > _kernel - > _kernelFuncs [ opparams [ 0 ] ] ;
2009-10-01 12:41:21 +00:00
int argc = validate_arithmetic ( scriptState . xs - > sp [ 0 ] ) ;
2009-02-15 06:10:59 +00:00
2009-08-25 08:38:14 +00:00
if ( ! oldScriptHeader )
2009-07-11 06:19:29 +00:00
argc + = scriptState . restAdjust ;
2009-02-15 06:10:59 +00:00
2009-09-17 13:20:58 +00:00
if ( kfun . signature
2009-10-04 18:38:18 +00:00
& & ! kernel_matches_signature ( s - > _segMan , kfun . signature , argc , scriptState . xs - > sp + 1 ) ) {
2009-08-20 21:03:03 +00:00
error ( " [VM] Invalid arguments to kernel call %x " , opparams [ 0 ] ) ;
2009-02-15 06:10:59 +00:00
} else {
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
reg_t * argv = scriptState . xs - > sp + 1 ;
if ( ! kfun . isDummy ) {
2009-09-30 00:13:59 +00:00
// 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 ;
xstack = add_exec_stack_entry ( s , NULL_REG , NULL , NULL_REG , argc , argv - 1 , 0 , NULL_REG ,
s - > _executionStack . size ( ) - 1 , SCI_XS_CALLEE_LOCALS ) ;
2009-10-01 08:53:10 +00:00
xstack - > selector = opparams [ 0 ] ;
2009-09-30 00:13:59 +00:00
xstack - > type = EXEC_STACK_TYPE_KERNEL ;
2009-10-09 19:41:39 +00:00
//warning("callk %s", kfun.orig_name.c_str());
2010-01-21 22:20:16 +00:00
// TODO: SCI2/SCI2.1+ equivalent, once saving/loading works in SCI2/SCI2.1+
if ( loadFromGMM & & opparams [ 0 ] = = 0x8 ) {
// A game is being loaded from GMM, and kDisplay is called, all initialization has taken
// place (i.e. menus have been constructed etc). Therefore, inject a kRestoreGame call
// here, instead of the requested function
int saveSlot = ConfMan . getInt ( " save_slot " ) ;
ConfMan . setInt ( " save_slot " , - 1 ) ; // invalidate slot
loadFromGMM = false ;
if ( saveSlot < 0 )
error ( " Requested to load invalid save slot " ) ; // should never happen, really
2010-01-21 22:44:25 +00:00
reg_t restoreArgv [ 2 ] = { NULL_REG , make_reg ( 0 , saveSlot ) } ; // special GMM call (argv[0] is NULL)
kRestoreGame ( s , 2 , restoreArgv ) ;
2010-01-21 22:20:16 +00:00
} else {
// Call kernel function
s - > r_acc = kfun . fun ( s , argc , argv ) ;
}
2009-09-30 00:13:59 +00:00
// Remove callk stack frame again
s - > _executionStack . pop_back ( ) ;
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
} else {
2010-01-25 01:39:44 +00:00
Common : : String warningMsg = " Dummy function " + kfun . orig_name +
2009-10-12 12:03:06 +00:00
Common : : String : : printf ( " [0x%x] " , opparams [ 0 ] ) +
2010-01-25 01:39:44 +00:00
" invoked - ignoring. Params: " +
2009-10-12 12:03:06 +00:00
Common : : String : : printf ( " %d " , argc ) + " ( " ;
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
for ( int i = 0 ; i < argc ; i + + ) {
2009-09-30 16:00:44 +00:00
warningMsg + = Common : : String : : printf ( " %04x:%04x " , PRINT_REG ( argv [ i ] ) ) ;
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
warningMsg + = ( i = = argc - 1 ? " ) " : " , " ) ;
}
2009-10-02 15:02:57 +00:00
warning ( " %s " , warningMsg . c_str ( ) ) ;
- Changed the unimplemented debug SCI kernel functions (InspectObj, ShowSends, ShowObjs, ShowFree, StackUsage and Profiler) to be dummy functions - we have our own debugger, and don't use these functions for debugging
- Removed the function number parameter from all kernel functions, as it's no longer needed, and removed the FAKE_FUNCT_NR hack
- Removed kUnknown() and kStub()
- Dummy/unknown kernel functions are no longer invoked, and a warning is shown instead, with the paremeters passed to them
Note: there is an evil hack used for debugging scripts in invoke_selector(), which probably no longer works now
svn-id: r44461
2009-09-29 14:24:07 +00:00
}
2009-02-15 06:10:59 +00:00
}
2009-02-20 23:09:29 +00:00
// Calculate xs again: The kernel function might
2009-02-22 13:11:43 +00:00
// have spawned a new VM
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
xs_new = & ( s - > _executionStack . back ( ) ) ;
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
2009-08-25 09:02:00 +00:00
if ( ! oldScriptHeader )
scriptState . restAdjust = s - > restAdjust ;
2009-02-15 06:10:59 +00:00
}
break ;
2009-09-17 13:20:58 +00:00
}
2009-02-15 06:10:59 +00:00
2010-01-28 13:07:47 +00:00
case op_callb : // 0x22 (34)
2009-07-11 06:19:29 +00:00
temp = ( ( opparams [ 1 ] > > 1 ) + scriptState . restAdjust + 1 ) ;
2009-07-08 10:25:37 +00:00
s_temp = scriptState . xs - > sp ;
scriptState . xs - > sp - = temp ;
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp [ 0 ] . offset + = scriptState . restAdjust ;
xs_new = execute_method ( s , 0 , opparams [ 0 ] , s_temp , scriptState . xs - > objp ,
2009-07-08 10:25:37 +00:00
scriptState . xs - > sp [ 0 ] . offset , scriptState . xs - > sp ) ;
2009-07-11 06:19:29 +00:00
scriptState . restAdjust = 0 ; // Used up the &rest adjustment
2009-02-22 13:11:43 +00:00
if ( xs_new ) // in case of error, keep old stack
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
break ;
2009-02-15 22:28:12 +00:00
2010-01-28 13:07:47 +00:00
case op_calle : // 0x23 (35)
2009-07-11 06:19:29 +00:00
temp = ( ( opparams [ 2 ] > > 1 ) + scriptState . restAdjust + 1 ) ;
2009-07-08 10:25:37 +00:00
s_temp = scriptState . xs - > sp ;
scriptState . xs - > sp - = temp ;
2009-02-15 06:10:59 +00:00
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp [ 0 ] . offset + = scriptState . restAdjust ;
xs_new = execute_method ( s , opparams [ 0 ] , opparams [ 1 ] , s_temp , scriptState . xs - > objp ,
2009-07-08 10:25:37 +00:00
scriptState . xs - > sp [ 0 ] . offset , scriptState . xs - > sp ) ;
2009-07-11 06:19:29 +00:00
scriptState . restAdjust = 0 ; // Used up the &rest adjustment
2009-02-15 22:28:12 +00:00
2009-02-22 13:11:43 +00:00
if ( xs_new ) // in case of error, keep old stack
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_ret : // 0x24 (36)
2009-02-15 06:10:59 +00:00
do {
2009-07-08 10:25:37 +00:00
StackPtr old_sp2 = scriptState . xs - > sp ;
StackPtr old_fp = scriptState . xs - > fp ;
2009-05-18 18:15:45 +00:00
ExecStack * old_xs = & ( s - > _executionStack . back ( ) ) ;
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
if ( ( int ) s - > _executionStack . size ( ) - 1 = = s - > execution_stack_base ) { // Have we reached the base?
2009-02-22 13:11:43 +00:00
s - > execution_stack_base = old_execution_stack_base ; // Restore stack base
2009-02-15 06:10:59 +00:00
2009-05-18 18:15:45 +00:00
s - > _executionStack . pop_back ( ) ;
2009-02-15 06:10:59 +00:00
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-07-11 06:19:29 +00:00
s - > restAdjust = scriptState . restAdjust ; // Update &rest
2009-02-22 13:11:43 +00:00
return ; // "Hard" return
2009-02-15 06:10:59 +00:00
}
if ( old_xs - > type = = EXEC_STACK_TYPE_VARSELECTOR ) {
2009-02-22 13:11:43 +00:00
// varselector access?
2009-10-04 18:38:18 +00:00
reg_t * var = old_xs - > getVarPointer ( s - > _segMan ) ;
2009-02-22 13:11:43 +00:00
if ( old_xs - > argc ) // write?
2009-09-21 21:39:00 +00:00
* var = old_xs - > variables_argp [ 1 ] ;
2009-02-22 13:11:43 +00:00
else // No, read
2009-09-21 21:39:00 +00:00
s - > r_acc = * var ;
2009-02-15 06:10:59 +00:00
}
2009-02-22 13:11:43 +00:00
// Not reached the base, so let's do a soft return
2009-05-18 18:15:45 +00:00
s - > _executionStack . pop_back ( ) ;
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-07-08 10:25:37 +00:00
scriptState . xs = & ( s - > _executionStack . back ( ) ) ;
2009-02-15 06:10:59 +00:00
2009-07-08 10:25:37 +00:00
if ( scriptState . xs - > sp = = CALL_SP_CARRY // Used in sends to 'carry' the stack pointer
| | scriptState . xs - > type ! = EXEC_STACK_TYPE_CALL ) {
scriptState . xs - > sp = old_sp2 ;
scriptState . xs - > fp = old_fp ;
2009-02-15 06:10:59 +00:00
}
2009-07-08 10:25:37 +00:00
} while ( scriptState . xs - > type = = EXEC_STACK_TYPE_VARSELECTOR ) ;
2009-02-22 13:11:43 +00:00
// Iterate over all varselector accesses
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-07-08 10:25:37 +00:00
xs_new = scriptState . xs ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_send : // 0x25 (37)
2009-07-08 10:25:37 +00:00
s_temp = scriptState . xs - > sp ;
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp - = ( ( opparams [ 0 ] > > 1 ) + scriptState . restAdjust ) ; // Adjust stack
2009-02-15 06:10:59 +00:00
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp [ 1 ] . offset + = scriptState . restAdjust ;
xs_new = send_selector ( s , s - > r_acc , s - > r_acc , s_temp ,
( int ) ( opparams [ 0 ] > > 1 ) + ( uint16 ) scriptState . restAdjust , scriptState . xs - > sp ) ;
2009-02-15 06:10:59 +00:00
2009-07-08 10:25:37 +00:00
if ( xs_new & & xs_new ! = scriptState . xs )
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
2009-07-11 06:19:29 +00:00
scriptState . restAdjust = 0 ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case 0x26 : // (38)
case 0x27 : // (39)
error ( " Dummy opcode 0x%x called " , opnumber ) ; // should never happen
break ;
case op_class : // 0x28 (40)
2009-10-04 18:38:18 +00:00
s - > r_acc = s - > _segMan - > getClassAddress ( ( unsigned ) opparams [ 0 ] , SCRIPT_GET_LOCK ,
2009-07-08 10:25:37 +00:00
scriptState . xs - > addr . pc ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case 0x29 : // (41)
error ( " Dummy opcode 0x%x called " , opnumber ) ; // should never happen
break ;
case op_self : // 0x2a (42)
2009-07-08 10:25:37 +00:00
s_temp = scriptState . xs - > sp ;
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp - = ( ( opparams [ 0 ] > > 1 ) + scriptState . restAdjust ) ; // Adjust stack
2009-02-15 06:10:59 +00:00
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp [ 1 ] . offset + = scriptState . restAdjust ;
xs_new = send_selector ( s , scriptState . xs - > objp , scriptState . xs - > objp ,
s_temp , ( int ) ( opparams [ 0 ] > > 1 ) + ( uint16 ) scriptState . restAdjust ,
2009-07-08 10:25:37 +00:00
scriptState . xs - > sp ) ;
2009-02-15 06:10:59 +00:00
2009-07-08 10:25:37 +00:00
if ( xs_new & & xs_new ! = scriptState . xs )
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
2009-07-11 06:19:29 +00:00
scriptState . restAdjust = 0 ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_super : // 0x2b (43)
2009-10-04 18:38:18 +00:00
r_temp = s - > _segMan - > getClassAddress ( opparams [ 0 ] , SCRIPT_GET_LOAD , scriptState . xs - > addr . pc ) ;
2009-02-15 06:10:59 +00:00
if ( ! r_temp . segment )
2009-07-03 21:59:07 +00:00
error ( " [VM]: Invalid superclass in object " ) ;
2009-02-15 06:10:59 +00:00
else {
2009-07-08 10:25:37 +00:00
s_temp = scriptState . xs - > sp ;
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp - = ( ( opparams [ 1 ] > > 1 ) + scriptState . restAdjust ) ; // Adjust stack
2009-02-15 06:10:59 +00:00
2009-07-11 06:19:29 +00:00
scriptState . xs - > sp [ 1 ] . offset + = scriptState . restAdjust ;
xs_new = send_selector ( s , r_temp , scriptState . xs - > objp , s_temp ,
( int ) ( opparams [ 1 ] > > 1 ) + ( uint16 ) scriptState . restAdjust ,
2009-07-08 10:25:37 +00:00
scriptState . xs - > sp ) ;
2009-02-15 06:10:59 +00:00
2009-07-08 10:25:37 +00:00
if ( xs_new & & xs_new ! = scriptState . xs )
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
2009-07-11 06:19:29 +00:00
scriptState . restAdjust = 0 ;
2009-02-15 06:10:59 +00:00
}
break ;
2010-01-28 13:07:47 +00:00
case op_rest : // 0x2c (44)
2009-02-22 13:11:43 +00:00
temp = ( uint16 ) opparams [ 0 ] ; // First argument
2009-07-11 06:19:29 +00:00
scriptState . restAdjust = MAX < int16 > ( scriptState . xs - > argc - temp + 1 , 0 ) ; // +1 because temp counts the paramcount while argc doesn't
2009-02-15 06:10:59 +00:00
2009-07-08 10:25:37 +00:00
for ( ; temp < = scriptState . xs - > argc ; temp + + )
PUSH32 ( scriptState . xs - > variables_argp [ temp ] ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_lea : // 0x2d (45)
2009-02-21 21:16:41 +00:00
temp = ( uint16 ) opparams [ 0 ] > > 1 ;
2009-02-22 13:11:43 +00:00
var_number = temp & 0x03 ; // Get variable type
2009-02-15 06:10:59 +00:00
2009-02-22 13:11:43 +00:00
// Get variable block offset
2009-07-08 10:25:37 +00:00
r_temp . segment = scriptState . variables_seg [ var_number ] ;
r_temp . offset = scriptState . variables [ var_number ] - scriptState . variables_base [ var_number ] ;
2009-02-15 06:10:59 +00:00
2009-02-22 13:11:43 +00:00
if ( temp & 0x08 ) // Add accumulator offset if requested
2009-02-15 06:10:59 +00:00
r_temp . offset + = signed_validate_arithmetic ( s - > r_acc ) ;
2009-02-22 13:11:43 +00:00
r_temp . offset + = opparams [ 1 ] ; // Add index
2009-09-27 12:23:14 +00:00
r_temp . offset * = 2 ; // variables are 16 bit
2009-02-22 13:11:43 +00:00
// That's the immediate address now
2009-02-15 06:10:59 +00:00
s - > r_acc = r_temp ;
break ;
2010-01-28 13:07:47 +00:00
case op_selfID : // 0x2e (46)
2009-07-08 10:25:37 +00:00
s - > r_acc = scriptState . xs - > objp ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case 0x2f : // (47)
error ( " Dummy opcode 0x%x called " , opnumber ) ; // should never happen
break ;
case op_pprev : // 0x30 (48)
2009-02-15 06:10:59 +00:00
PUSH32 ( s - > r_prev ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_pToa : // 0x31 (49)
2009-02-15 06:10:59 +00:00
s - > r_acc = OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_aTop : // 0x32 (50)
2009-02-15 06:10:59 +00:00
OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) = s - > r_acc ;
break ;
2010-01-28 13:07:47 +00:00
case op_pTos : // 0x33 (51)
2009-02-15 06:10:59 +00:00
PUSH32 ( OBJ_PROPERTY ( obj , opparams [ 0 ] > > 1 ) ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_sTop : // 0x34 (52)
2009-02-15 06:10:59 +00:00
OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) = POP32 ( ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_ipToa : // 0x35 (53)
2009-02-15 06:10:59 +00:00
s - > r_acc = OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) ;
2009-02-20 23:09:29 +00:00
s - > r_acc = OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) = ACC_ARITHMETIC_L ( 1 + /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_dpToa : { // 0x36 (54)
2009-02-15 06:10:59 +00:00
s - > r_acc = OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) ;
2010-01-17 18:27:57 +00:00
#if 0
// Speed throttling is possible here as well
// although this opens other issues like mud wrestling in lsl5 uses another local variable for delays
Object * var_container = obj ;
if ( ! ( obj - > getInfoSelector ( ) . offset & SCRIPT_INFO_CLASS ) )
var_container = s - > _segMan - > getObject ( obj - > getSuperClassSelector ( ) ) ;
uint16 varSelector = var_container - > getVarSelector ( opparams [ 0 ] > > 1 ) ;
// printf("%X\n", varSelector);
// printf("%s\n", s->_kernel->getSelectorName(varSelector).c_str());
if ( ( varSelector = = 0x84 ) | | ( varSelector = = 0x92 ) ) ) {
// selectors cycles, cycleCnt from lsl5 hardcoded
uint32 curTime = g_system - > getMillis ( ) ;
if ( s - > _lastAnimateTime + 30 > curTime )
break ;
s - > _lastAnimateTime = curTime ;
}
# endif
2009-02-20 23:09:29 +00:00
s - > r_acc = OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) = ACC_ARITHMETIC_L ( - 1 + /*acc*/ ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-17 18:27:57 +00:00
}
2009-02-15 06:10:59 +00:00
2010-01-28 13:07:47 +00:00
case op_ipTos : // 0x37 (55)
2009-10-01 12:41:21 +00:00
validate_arithmetic ( OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) ) ;
2009-02-15 06:10:59 +00:00
temp = + + OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) . offset ;
PUSH ( temp ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_dpTos : // 0x38 (56)
2009-10-01 12:41:21 +00:00
validate_arithmetic ( OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) ) ;
2009-02-15 06:10:59 +00:00
temp = - - OBJ_PROPERTY ( obj , ( opparams [ 0 ] > > 1 ) ) . offset ;
PUSH ( temp ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_lofsa : // 0x39 (57)
2009-07-08 10:25:37 +00:00
s - > r_acc . segment = scriptState . xs - > addr . pc . segment ;
2009-02-15 06:10:59 +00:00
2009-08-30 14:53:58 +00:00
switch ( s - > detectLofsType ( ) ) {
case SCI_VERSION_1_1 :
2009-09-16 23:32:27 +00:00
s - > r_acc . offset = opparams [ 0 ] + local_script - > _scriptSize ;
2009-08-30 14:53:58 +00:00
break ;
case SCI_VERSION_1_MIDDLE :
s - > r_acc . offset = opparams [ 0 ] ;
break ;
default :
s - > r_acc . offset = scriptState . xs - > addr . pc . offset + opparams [ 0 ] ;
2009-05-14 12:38:50 +00:00
}
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
if ( s - > r_acc . offset > = code_buf_size ) {
2009-05-31 15:34:23 +00:00
error ( " VM: lofsa operation overflowed: %04x:%04x beyond end "
2009-02-20 23:09:29 +00:00
" of script (at %04x) \n " , PRINT_REG ( s - > r_acc ) , code_buf_size ) ;
2009-02-15 06:10:59 +00:00
}
# endif
break ;
2010-01-28 13:07:47 +00:00
case op_lofss : // 0x3a (58)
2009-07-08 10:25:37 +00:00
r_temp . segment = scriptState . xs - > addr . pc . segment ;
2009-02-15 06:10:59 +00:00
2009-08-30 14:53:58 +00:00
switch ( s - > detectLofsType ( ) ) {
case SCI_VERSION_1_1 :
2009-09-16 23:32:27 +00:00
r_temp . offset = opparams [ 0 ] + local_script - > _scriptSize ;
2009-08-30 14:53:58 +00:00
break ;
case SCI_VERSION_1_MIDDLE :
r_temp . offset = opparams [ 0 ] ;
break ;
default :
r_temp . offset = scriptState . xs - > addr . pc . offset + opparams [ 0 ] ;
2009-07-07 07:51:26 +00:00
}
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
if ( r_temp . offset > = code_buf_size ) {
2009-05-31 15:34:23 +00:00
error ( " VM: lofss operation overflowed: %04x:%04x beyond end "
2009-08-20 21:03:03 +00:00
" of script (at %04x) " , PRINT_REG ( r_temp ) , code_buf_size ) ;
2009-02-15 06:10:59 +00:00
}
# endif
PUSH32 ( r_temp ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_push0 : // 0x3b (59)
2009-02-15 06:10:59 +00:00
PUSH ( 0 ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_push1 : // 0x3c (60)
2009-02-15 06:10:59 +00:00
PUSH ( 1 ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_push2 : // 0x3d (61)
2009-02-15 06:10:59 +00:00
PUSH ( 2 ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_pushSelf : // 0x3e (62)
2010-01-28 19:22:58 +00:00
if ( ! ( opcode & 1 ) ) {
PUSH32 ( scriptState . xs - > objp ) ;
} else {
// Debug opcode op_file, skip null-terminated string (file name)
while ( GET_OP_BYTE ( ) ) ;
}
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 19:22:58 +00:00
case op_line : // 0x3f (63)
// Debug opcode (line number)
2010-01-28 13:07:47 +00:00
break ;
case op_lag : // 0x40 (64)
case op_lal : // 0x41 (65)
case op_lat : // 0x42 (66)
case op_lap : // 0x43 (67)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] ;
s - > r_acc = READ_VAR ( var_type , var_number , s - > r_acc ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_lsg : // 0x44 (68)
case op_lsl : // 0x45 (69)
case op_lst : // 0x46 (70)
case op_lsp : // 0x47 (71)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] ;
PUSH32 ( READ_VAR ( var_type , var_number , s - > r_acc ) ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_lagi : // 0x48 (72)
case op_lali : // 0x49 (73)
case op_lati : // 0x4a (74)
case op_lapi : // 0x4b (75)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] + signed_validate_arithmetic ( s - > r_acc ) ;
s - > r_acc = READ_VAR ( var_type , var_number , s - > r_acc ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_lsgi : // 0x4c (76)
case op_lsli : // 0x4d (77)
case op_lsti : // 0x4e (78)
case op_lspi : // 0x4f (79)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] + signed_validate_arithmetic ( s - > r_acc ) ;
PUSH32 ( READ_VAR ( var_type , var_number , s - > r_acc ) ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_sag : // 0x50 (80)
case op_sal : // 0x51 (81)
case op_sat : // 0x52 (82)
case op_sap : // 0x53 (83)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] ;
WRITE_VAR ( var_type , var_number , s - > r_acc ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_ssg : // 0x54 (84)
case op_ssl : // 0x55 (85)
case op_sst : // 0x56 (86)
case op_ssp : // 0x57 (87)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] ;
WRITE_VAR ( var_type , var_number , POP32 ( ) ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_sagi : // 0x58 (88)
case op_sali : // 0x59 (89)
case op_sati : // 0x5a (90)
case op_sapi : // 0x5b (91)
2009-02-20 23:09:29 +00:00
// Special semantics because it wouldn't really make a whole lot
// of sense otherwise, with acc being used for two things
2009-02-22 13:11:43 +00:00
// simultaneously...
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] + signed_validate_arithmetic ( s - > r_acc ) ;
WRITE_VAR ( var_type , var_number , s - > r_acc = POP32 ( ) ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_ssgi : // 0x5c (92)
case op_ssli : // 0x5d (93)
case op_ssti : // 0x5e (94)
case op_sspi : // 0x5f (95)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] + signed_validate_arithmetic ( s - > r_acc ) ;
WRITE_VAR ( var_type , var_number , POP32 ( ) ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_plusag : // 0x60 (96)
case op_plusal : // 0x61 (97)
case op_plusat : // 0x62 (98)
case op_plusap : // 0x63 (99)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] ;
2010-01-03 17:40:17 +00:00
r_temp = READ_VAR ( var_type , var_number , s - > r_acc ) ;
if ( r_temp . segment ) {
// Pointer arithmetics!
s - > r_acc = pointer_add ( s , r_temp , 1 ) ;
} else
s - > r_acc = make_reg ( 0 , r_temp . offset + 1 ) ;
2009-02-15 06:10:59 +00:00
WRITE_VAR ( var_type , var_number , s - > r_acc ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_plussg : // 0x64 (100)
case op_plussl : // 0x65 (101)
case op_plusst : // 0x66 (102)
case op_plussp : // 0x67 (103)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] ;
2010-01-03 17:40:17 +00:00
r_temp = READ_VAR ( var_type , var_number , s - > r_acc ) ;
if ( r_temp . segment ) {
// Pointer arithmetics!
r_temp = pointer_add ( s , r_temp , 1 ) ;
} else
r_temp = make_reg ( 0 , r_temp . offset + 1 ) ;
2009-02-15 06:10:59 +00:00
PUSH32 ( r_temp ) ;
WRITE_VAR ( var_type , var_number , r_temp ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_plusagi : // 0x68 (104)
case op_plusali : // 0x69 (105)
case op_plusati : // 0x6a (106)
case op_plusapi : // 0x6b (107)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] + signed_validate_arithmetic ( s - > r_acc ) ;
2010-01-03 17:40:17 +00:00
r_temp = READ_VAR ( var_type , var_number , s - > r_acc ) ;
if ( r_temp . segment ) {
// Pointer arithmetics!
s - > r_acc = pointer_add ( s , r_temp , 1 ) ;
} else
s - > r_acc = make_reg ( 0 , r_temp . offset + 1 ) ;
2009-02-15 06:10:59 +00:00
WRITE_VAR ( var_type , var_number , s - > r_acc ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_plussgi : // 0x6c (108)
case op_plussli : // 0x6d (109)
case op_plussti : // 0x6e (110)
case op_plusspi : // 0x6f (111)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] + signed_validate_arithmetic ( s - > r_acc ) ;
2010-01-03 17:40:17 +00:00
r_temp = READ_VAR ( var_type , var_number , s - > r_acc ) ;
if ( r_temp . segment ) {
// Pointer arithmetics!
r_temp = pointer_add ( s , r_temp , 1 ) ;
} else
r_temp = make_reg ( 0 , r_temp . offset + 1 ) ;
2009-02-15 06:10:59 +00:00
PUSH32 ( r_temp ) ;
WRITE_VAR ( var_type , var_number , r_temp ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_minusag : // 0x70 (112)
case op_minusal : // 0x71 (113)
case op_minusat : // 0x72 (114)
case op_minusap : // 0x73 (115)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] ;
2010-01-03 17:40:17 +00:00
r_temp = READ_VAR ( var_type , var_number , s - > r_acc ) ;
if ( r_temp . segment ) {
// Pointer arithmetics!
s - > r_acc = pointer_add ( s , r_temp , - 1 ) ;
} else
s - > r_acc = make_reg ( 0 , r_temp . offset - 1 ) ;
2009-02-15 06:10:59 +00:00
WRITE_VAR ( var_type , var_number , s - > r_acc ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_minussg : // 0x74 (116)
case op_minussl : // 0x75 (117)
case op_minusst : // 0x76 (118)
case op_minussp : // 0x77 (119)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] ;
2010-01-03 17:40:17 +00:00
r_temp = READ_VAR ( var_type , var_number , s - > r_acc ) ;
if ( r_temp . segment ) {
// Pointer arithmetics!
r_temp = pointer_add ( s , r_temp , - 1 ) ;
} else
r_temp = make_reg ( 0 , r_temp . offset - 1 ) ;
2009-02-15 06:10:59 +00:00
PUSH32 ( r_temp ) ;
WRITE_VAR ( var_type , var_number , r_temp ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_minusagi : // 0x78 (120)
case op_minusali : // 0x79 (121)
case op_minusati : // 0x7a (122)
case op_minusapi : // 0x7b (123)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] + signed_validate_arithmetic ( s - > r_acc ) ;
2010-01-03 17:40:17 +00:00
r_temp = READ_VAR ( var_type , var_number , s - > r_acc ) ;
if ( r_temp . segment ) {
// Pointer arithmetics!
s - > r_acc = pointer_add ( s , r_temp , - 1 ) ;
} else
s - > r_acc = make_reg ( 0 , r_temp . offset - 1 ) ;
2009-02-15 06:10:59 +00:00
WRITE_VAR ( var_type , var_number , s - > r_acc ) ;
break ;
2010-01-28 13:07:47 +00:00
case op_minussgi : // 0x7c (124)
case op_minussli : // 0x7d (125)
case op_minussti : // 0x7e (126)
case op_minusspi : // 0x7f (127)
2009-02-22 13:11:43 +00:00
var_type = ( opcode > > 1 ) & 0x3 ; // Gets the variable type: g, l, t or p
2009-02-15 06:10:59 +00:00
var_number = opparams [ 0 ] + signed_validate_arithmetic ( s - > r_acc ) ;
2010-01-03 17:40:17 +00:00
r_temp = READ_VAR ( var_type , var_number , s - > r_acc ) ;
if ( r_temp . segment ) {
// Pointer arithmetics!
r_temp = pointer_add ( s , r_temp , - 1 ) ;
} else
r_temp = make_reg ( 0 , r_temp . offset - 1 ) ;
2009-02-15 06:10:59 +00:00
PUSH32 ( r_temp ) ;
WRITE_VAR ( var_type , var_number , r_temp ) ;
break ;
default :
2009-07-03 21:59:07 +00:00
error ( " run_vm(): illegal opcode %x " , opnumber ) ;
2009-02-15 06:10:59 +00:00
2009-09-30 16:16:53 +00:00
} // switch (opcode >> 1)
2009-02-15 06:10:59 +00:00
2009-04-28 15:58:19 +00:00
if ( s - > _executionStackPosChanged ) // Force initialization
2009-07-08 10:25:37 +00:00
scriptState . xs = xs_new ;
2009-02-15 06:10:59 +00:00
2009-05-19 00:02:10 +00:00
//#ifndef DISABLE_VALIDATIONS
2009-07-08 10:25:37 +00:00
if ( scriptState . xs ! = & ( s - > _executionStack . back ( ) ) ) {
2009-05-31 10:02:16 +00:00
warning ( " xs is stale (%p vs %p); last command was %02x " ,
2009-07-08 10:25:37 +00:00
( void * ) scriptState . xs , ( void * ) & ( s - > _executionStack . back ( ) ) ,
2009-05-19 00:02:10 +00:00
opnumber ) ;
2009-02-15 06:10:59 +00:00
}
2009-05-19 00:02:10 +00:00
//#endif
2009-07-03 14:22:50 +00:00
+ + script_step_counter ;
2009-02-15 06:10:59 +00:00
}
}
2009-09-06 12:58:16 +00:00
# define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segMan->getClassAddress(id, SCRIPT_GET_LOCK, reg))
2009-02-15 06:10:59 +00:00
2009-09-06 12:57:42 +00:00
int script_instantiate_common ( ResourceManager * resMan , SegManager * segMan , int script_nr , Resource * * script , Resource * * heap , int * was_new ) {
2009-02-15 06:10:59 +00:00
* was_new = 1 ;
2009-09-02 12:02:37 +00:00
* script = resMan - > findResource ( ResourceId ( kResourceTypeScript , script_nr ) , 0 ) ;
2009-09-23 10:55:35 +00:00
if ( getSciVersion ( ) > = SCI_VERSION_1_1 )
2009-09-02 12:02:37 +00:00
* heap = resMan - > findResource ( ResourceId ( kResourceTypeHeap , script_nr ) , 0 ) ;
2009-02-15 06:10:59 +00:00
2009-09-23 10:55:35 +00:00
if ( ! * script | | ( getSciVersion ( ) > = SCI_VERSION_1_1 & & ! heap ) ) {
2009-07-06 10:39:22 +00:00
warning ( " Script 0x%x requested but not found " , script_nr ) ;
2009-09-23 10:55:35 +00:00
if ( getSciVersion ( ) > = SCI_VERSION_1_1 ) {
2009-02-15 06:10:59 +00:00
if ( * heap )
2009-07-06 10:39:22 +00:00
warning ( " Inconsistency: heap resource WAS found " ) ;
2009-02-15 06:10:59 +00:00
else if ( * script )
2009-07-06 10:39:22 +00:00
warning ( " Inconsistency: script resource WAS found " ) ;
2009-02-15 06:10:59 +00:00
}
return 0 ;
}
2009-09-17 00:46:01 +00:00
SegmentId seg_id = segMan - > getScriptSegment ( script_nr ) ;
2009-09-06 12:57:42 +00:00
Script * scr = segMan - > getScriptIfLoaded ( seg_id ) ;
2009-05-15 09:27:07 +00:00
if ( scr ) {
if ( ! scr - > isMarkedAsDeleted ( ) ) {
scr - > incrementLockers ( ) ;
return seg_id ;
2009-02-15 22:28:12 +00:00
} else {
2009-05-03 22:47:04 +00:00
scr - > freeScript ( ) ;
2009-02-15 06:10:59 +00:00
}
2009-05-15 09:27:07 +00:00
} else {
2009-09-06 12:57:42 +00:00
scr = segMan - > allocateScript ( script_nr , & seg_id ) ;
2009-05-15 09:27:07 +00:00
if ( ! scr ) { // ALL YOUR SCRIPT BASE ARE BELONG TO US
2009-05-31 15:34:23 +00:00
error ( " Not enough heap space for script size 0x%x of script 0x%x (Should this happen?) " , ( * script ) - > size , script_nr ) ;
2009-05-15 09:27:07 +00:00
return 0 ;
}
2009-02-15 06:10:59 +00:00
}
2009-09-16 23:32:48 +00:00
scr - > init ( script_nr , resMan ) ;
2009-02-15 06:10:59 +00:00
2009-09-17 00:46:01 +00:00
reg_t reg ;
2009-02-15 06:10:59 +00:00
reg . segment = seg_id ;
reg . offset = 0 ;
2009-02-22 13:11:43 +00:00
// Set heap position (beyond the size word)
2009-05-15 09:27:07 +00:00
scr - > setLockers ( 1 ) ;
scr - > setExportTableOffset ( 0 ) ;
scr - > setSynonymsOffset ( 0 ) ;
scr - > setSynonymsNr ( 0 ) ;
2009-02-15 06:10:59 +00:00
* was_new = 0 ;
return seg_id ;
}
2009-09-06 12:57:42 +00:00
int script_instantiate_sci0 ( ResourceManager * resMan , SegManager * segMan , int script_nr ) {
2009-02-15 06:10:59 +00:00
int objtype ;
unsigned int objlength ;
int relocation = - 1 ;
2009-02-22 13:11:43 +00:00
int magic_pos_adder ; // Usually 0; 2 for older SCI versions
2009-02-28 21:59:49 +00:00
Resource * script ;
2009-02-15 06:10:59 +00:00
int was_new ;
2009-09-23 10:55:35 +00:00
bool oldScriptHeader = ( getSciVersion ( ) = = SCI_VERSION_0_EARLY ) ;
2009-02-15 06:10:59 +00:00
2009-09-16 23:32:27 +00:00
const int seg_id = script_instantiate_common ( resMan , segMan , script_nr , & script , NULL , & was_new ) ;
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
if ( was_new )
return seg_id ;
2009-02-15 06:10:59 +00:00
2009-09-06 12:57:42 +00:00
Script * scr = segMan - > getScript ( seg_id ) ;
2009-05-15 09:27:07 +00:00
2009-08-18 10:01:18 +00:00
if ( oldScriptHeader ) {
2009-02-20 23:09:29 +00:00
//
2009-03-07 16:14:20 +00:00
int locals_nr = READ_LE_UINT16 ( script - > data ) ;
2009-02-15 06:10:59 +00:00
2009-02-22 13:11:43 +00:00
// Old script block
// There won't be a localvar block in this case
2009-02-20 23:09:29 +00:00
// Instead, the script starts with a 16 bit int specifying the
2009-02-22 13:11:43 +00:00
// number of locals we need; these are then allocated and zeroed.
2009-02-15 06:10:59 +00:00
2009-05-15 09:27:07 +00:00
scr - > mcpyInOut ( 0 , script - > data , script - > size ) ;
2009-02-22 13:11:43 +00:00
magic_pos_adder = 2 ; // Step over the funny prefix
2009-02-15 06:10:59 +00:00
if ( locals_nr )
2009-09-06 12:59:34 +00:00
segMan - > scriptInitialiseLocalsZero ( seg_id , locals_nr ) ;
2009-02-15 06:10:59 +00:00
} else {
2009-05-15 09:27:07 +00:00
scr - > mcpyInOut ( 0 , script - > data , script - > size ) ;
2009-02-15 06:10:59 +00:00
magic_pos_adder = 0 ;
}
2009-02-20 23:09:29 +00:00
// Now do a first pass through the script objects to find the
// export table and local variable block
2009-02-15 06:10:59 +00:00
2009-09-06 12:59:34 +00:00
reg_t reg ;
reg . segment = seg_id ;
2009-02-15 06:10:59 +00:00
reg . offset = magic_pos_adder ;
2009-09-06 12:59:34 +00:00
objlength = 0 ;
2009-02-15 06:10:59 +00:00
do {
reg_t data_base ;
reg_t addr ;
2009-02-22 13:11:43 +00:00
reg . offset + = objlength ; // Step over the last checked object
2009-05-18 12:34:03 +00:00
objtype = scr - > getHeap ( reg . offset ) ;
2009-08-26 09:36:54 +00:00
if ( ! objtype )
break ;
2009-02-15 06:10:59 +00:00
2009-05-18 12:34:03 +00:00
objlength = scr - > getHeap ( reg . offset + 2 ) ;
2009-02-15 06:10:59 +00:00
2009-08-26 16:50:22 +00:00
// This happens in some demos (e.g. the EcoQuest 1 demo). Not sure what is the
// actual cause of it, but the scripts of these demos can't be loaded properly
// and we're stuck forever in this loop, as objlength never changes
if ( ! objlength ) {
warning ( " script_instantiate_sci0: objlength is 0, unable to parse script " ) ;
return 0 ;
}
2009-02-15 06:10:59 +00:00
data_base = reg ;
data_base . offset + = 4 ;
addr = data_base ;
2009-02-15 22:28:12 +00:00
switch ( objtype ) {
2009-05-14 23:09:30 +00:00
case SCI_OBJ_EXPORTS : {
2009-05-15 09:27:07 +00:00
scr - > setExportTableOffset ( data_base . offset ) ;
2009-02-15 06:10:59 +00:00
}
2009-02-15 22:28:12 +00:00
break ;
2009-02-15 06:10:59 +00:00
2009-05-14 23:09:30 +00:00
case SCI_OBJ_SYNONYMS :
2009-05-15 09:27:07 +00:00
scr - > setSynonymsOffset ( addr . offset ) ; // +4 is to step over the header
scr - > setSynonymsNr ( ( objlength ) / 4 ) ;
2009-02-15 06:10:59 +00:00
break ;
2009-05-14 23:09:30 +00:00
case SCI_OBJ_LOCALVARS :
2009-09-06 12:57:42 +00:00
segMan - > scriptInitialiseLocals ( data_base ) ;
2009-02-15 06:10:59 +00:00
break ;
2009-05-14 23:09:30 +00:00
case SCI_OBJ_CLASS : {
2009-02-15 06:10:59 +00:00
int classpos = addr . offset - SCRIPT_OBJECT_MAGIC_OFFSET ;
int species ;
2009-05-18 12:34:03 +00:00
species = scr - > getHeap ( addr . offset - SCRIPT_OBJECT_MAGIC_OFFSET + SCRIPT_SPECIES_OFFSET ) ;
2009-09-06 12:57:42 +00:00
if ( species < 0 | | species > = ( int ) segMan - > _classtable . size ( ) ) {
2009-12-28 14:22:11 +00:00
if ( species = = ( int ) segMan - > _classtable . size ( ) ) {
// Happens in the LSL2 demo
warning ( " Applying workaround for an off-by-one invalid species access " ) ;
segMan - > _classtable . resize ( segMan - > _classtable . size ( ) + 1 ) ;
} else {
warning ( " Invalid species %d(0x%x) not in interval "
" [0,%d) while instantiating script %d \n " ,
species , species , segMan - > _classtable . size ( ) ,
script_nr ) ;
return 0 ;
}
2009-02-15 06:10:59 +00:00
}
2009-09-06 12:57:42 +00:00
segMan - > _classtable [ species ] . reg = addr ;
segMan - > _classtable [ species ] . reg . offset = classpos ;
2009-02-22 13:11:43 +00:00
// Set technical class position-- into the block allocated for it
2009-02-15 22:28:12 +00:00
}
break ;
2009-02-15 06:10:59 +00:00
default :
break ;
}
} while ( objtype ! = 0 ) ;
2009-08-26 09:36:54 +00:00
2009-02-22 13:11:43 +00:00
// And now a second pass to adjust objects and class pointers, and the general pointers
2009-02-15 06:10:59 +00:00
objlength = 0 ;
2009-02-22 13:11:43 +00:00
reg . offset = magic_pos_adder ; // Reset counter
2009-02-15 06:10:59 +00:00
do {
reg_t addr ;
2009-02-22 13:11:43 +00:00
reg . offset + = objlength ; // Step over the last checked object
2009-05-18 12:34:03 +00:00
objtype = scr - > getHeap ( reg . offset ) ;
2009-08-26 09:36:54 +00:00
if ( ! objtype )
break ;
2009-05-18 12:34:03 +00:00
objlength = scr - > getHeap ( reg . offset + 2 ) ;
2009-02-15 06:10:59 +00:00
addr = reg ;
2009-09-16 23:32:27 +00:00
addr . offset + = 4 ; // Step over header
2009-02-15 06:10:59 +00:00
switch ( objtype ) {
2009-05-14 23:09:30 +00:00
case SCI_OBJ_CODE :
2009-09-16 23:32:48 +00:00
scr - > scriptAddCodeBlock ( addr ) ;
2009-02-15 06:10:59 +00:00
break ;
2009-05-14 23:09:30 +00:00
case SCI_OBJ_OBJECT :
case SCI_OBJ_CLASS : { // object or class?
2009-09-23 10:55:35 +00:00
Object * obj = scr - > scriptObjInit ( addr ) ;
2009-02-15 06:10:59 +00:00
2009-02-22 13:11:43 +00:00
// Instantiate the superclass, if neccessary
2009-09-17 16:50:53 +00:00
obj - > setSpeciesSelector ( INST_LOOKUP_CLASS ( obj - > getSpeciesSelector ( ) . offset ) ) ;
2009-02-15 06:10:59 +00:00
2009-10-14 09:37:22 +00:00
Object * baseObj = segMan - > getObject ( obj - > getSpeciesSelector ( ) ) ;
2009-02-15 06:10:59 +00:00
2010-01-01 23:48:22 +00:00
if ( baseObj ) {
obj - > setVarCount ( baseObj - > getVarCount ( ) ) ;
// Copy base from species class, as we need its selector IDs
obj - > _baseObj = baseObj - > _baseObj ;
obj - > setSuperClassSelector ( INST_LOOKUP_CLASS ( obj - > getSuperClassSelector ( ) . offset ) ) ;
} else {
warning ( " Failed to locate base object for object at %04X:%04X; skipping " , PRINT_REG ( addr ) ) ;
scr - > scriptObjRemove ( addr ) ;
}
2009-02-22 13:11:43 +00:00
} // if object or class
2009-02-15 22:28:12 +00:00
break ;
2009-05-14 23:09:30 +00:00
case SCI_OBJ_POINTERS : // A relocation table
2009-02-15 06:10:59 +00:00
relocation = addr . offset ;
break ;
default :
break ;
}
2009-08-26 09:36:54 +00:00
} while ( objtype ! = 0 & & reg . offset < script - > size - 2 ) ;
2009-02-15 06:10:59 +00:00
if ( relocation > = 0 )
2009-09-16 23:32:48 +00:00
scr - > scriptRelocate ( make_reg ( seg_id , relocation ) ) ;
2009-02-15 06:10:59 +00:00
2009-02-22 13:11:43 +00:00
return reg . segment ; // instantiation successful
2009-02-15 06:10:59 +00:00
}
2009-09-06 12:57:42 +00:00
int script_instantiate_sci11 ( ResourceManager * resMan , SegManager * segMan , int script_nr ) {
2009-02-28 21:59:49 +00:00
Resource * script , * heap ;
2009-09-16 23:32:27 +00:00
int _heapStart ;
2009-02-15 06:10:59 +00:00
reg_t reg ;
int was_new ;
2009-09-16 23:32:27 +00:00
const int seg_id = script_instantiate_common ( resMan , segMan , script_nr , & script , & heap , & was_new ) ;
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
if ( was_new )
return seg_id ;
2009-02-15 06:10:59 +00:00
2009-09-06 12:57:42 +00:00
Script * scr = segMan - > getScript ( seg_id ) ;
2009-05-15 09:27:07 +00:00
2009-09-16 23:32:27 +00:00
_heapStart = script - > size ;
2009-02-15 06:10:59 +00:00
if ( script - > size & 2 )
2009-09-16 23:32:27 +00:00
_heapStart + + ;
2009-02-15 06:10:59 +00:00
2009-05-15 09:27:07 +00:00
scr - > mcpyInOut ( 0 , script - > data , script - > size ) ;
2009-09-16 23:32:27 +00:00
scr - > mcpyInOut ( _heapStart , heap - > data , heap - > size ) ;
2009-02-15 06:10:59 +00:00
2009-03-07 16:14:20 +00:00
if ( READ_LE_UINT16 ( script - > data + 6 ) > 0 )
2009-05-15 09:27:07 +00:00
scr - > setExportTableOffset ( 6 ) ;
2009-02-15 06:10:59 +00:00
reg . segment = seg_id ;
2009-09-16 23:32:27 +00:00
reg . offset = _heapStart + 4 ;
2009-09-06 12:57:42 +00:00
segMan - > scriptInitialiseLocals ( reg ) ;
2009-02-15 06:10:59 +00:00
2009-09-06 12:57:42 +00:00
segMan - > scriptRelocateExportsSci11 ( seg_id ) ;
segMan - > scriptInitialiseObjectsSci11 ( seg_id ) ;
2009-02-15 06:10:59 +00:00
2009-03-07 16:14:20 +00:00
reg . offset = READ_LE_UINT16 ( heap - > data ) ;
2009-09-16 23:32:48 +00:00
scr - > heapRelocate ( reg ) ;
2009-02-15 06:10:59 +00:00
return seg_id ;
}
2009-09-06 12:57:42 +00:00
int script_instantiate ( ResourceManager * resMan , SegManager * segMan , int script_nr ) {
2009-09-23 10:55:35 +00:00
if ( getSciVersion ( ) > = SCI_VERSION_1_1 )
2009-09-06 12:57:42 +00:00
return script_instantiate_sci11 ( resMan , segMan , script_nr ) ;
2009-02-15 06:10:59 +00:00
else
2009-09-06 12:57:42 +00:00
return script_instantiate_sci0 ( resMan , segMan , script_nr ) ;
2009-02-15 06:10:59 +00:00
}
2009-09-06 12:57:42 +00:00
void script_uninstantiate_sci0 ( SegManager * segMan , int script_nr , SegmentId seg ) {
2009-09-17 16:50:53 +00:00
bool oldScriptHeader = ( getSciVersion ( ) = = SCI_VERSION_0_EARLY ) ;
2009-08-25 08:38:14 +00:00
reg_t reg = make_reg ( seg , oldScriptHeader ? 2 : 0 ) ;
2009-02-15 06:10:59 +00:00
int objtype , objlength ;
2009-09-06 12:57:42 +00:00
Script * scr = segMan - > getScript ( seg ) ;
2009-02-15 06:10:59 +00:00
2009-02-22 13:11:43 +00:00
// Make a pass over the object in order uninstantiate all superclasses
2009-02-15 06:10:59 +00:00
objlength = 0 ;
do {
2009-02-22 13:11:43 +00:00
reg . offset + = objlength ; // Step over the last checked object
2009-02-15 22:28:12 +00:00
2009-05-18 12:34:03 +00:00
objtype = scr - > getHeap ( reg . offset ) ;
2009-05-15 09:27:07 +00:00
if ( ! objtype )
break ;
2009-05-18 12:34:03 +00:00
objlength = scr - > getHeap ( reg . offset + 2 ) ; // use SEG_UGET_HEAP ??
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
reg . offset + = 4 ; // Step over header
2009-02-15 06:10:59 +00:00
2009-05-14 23:09:30 +00:00
if ( ( objtype = = SCI_OBJ_OBJECT ) | | ( objtype = = SCI_OBJ_CLASS ) ) { // object or class?
2009-02-15 06:10:59 +00:00
int superclass ;
reg . offset - = SCRIPT_OBJECT_MAGIC_OFFSET ;
2009-05-18 12:34:03 +00:00
superclass = scr - > getHeap ( reg . offset + SCRIPT_SUPERCLASS_OFFSET ) ; // Get superclass...
2009-02-15 06:10:59 +00:00
if ( superclass > = 0 ) {
2009-09-06 12:57:42 +00:00
int superclass_script = segMan - > _classtable [ superclass ] . script ;
2009-02-15 06:10:59 +00:00
if ( superclass_script = = script_nr ) {
2009-05-15 09:27:07 +00:00
if ( scr - > getLockers ( ) )
scr - > decrementLockers ( ) ; // Decrease lockers if this is us ourselves
2009-02-15 06:10:59 +00:00
} else
2009-09-06 12:57:42 +00:00
script_uninstantiate ( segMan , superclass_script ) ;
2009-02-20 23:09:29 +00:00
// Recurse to assure that the superclass lockers number gets decreased
2009-02-15 06:10:59 +00:00
}
reg . offset + = SCRIPT_OBJECT_MAGIC_OFFSET ;
2009-02-20 23:09:29 +00:00
} // if object or class
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
reg . offset - = 4 ; // Step back on header
2009-02-15 06:10:59 +00:00
} while ( objtype ! = 0 ) ;
}
2009-09-06 12:57:42 +00:00
void script_uninstantiate ( SegManager * segMan , int script_nr ) {
2009-09-06 12:58:16 +00:00
SegmentId segment = segMan - > getScriptSegment ( script_nr ) ;
2009-09-06 12:57:42 +00:00
Script * scr = segMan - > getScriptIfLoaded ( segment ) ;
2009-02-15 06:10:59 +00:00
2009-05-15 09:27:07 +00:00
if ( ! scr ) { // Is it already loaded?
2009-02-28 13:41:43 +00:00
//warning("unloading script 0x%x requested although not loaded", script_nr);
2009-02-20 23:09:29 +00:00
// This is perfectly valid SCI behaviour
2009-02-15 06:10:59 +00:00
return ;
}
2009-05-15 09:27:07 +00:00
scr - > decrementLockers ( ) ; // One less locker
2009-02-15 06:10:59 +00:00
2009-05-15 09:27:07 +00:00
if ( scr - > getLockers ( ) > 0 )
2009-02-15 06:10:59 +00:00
return ;
2009-02-20 23:09:29 +00:00
// Free all classtable references to this script
2009-09-06 12:57:42 +00:00
for ( uint i = 0 ; i < segMan - > _classtable . size ( ) ; i + + )
if ( segMan - > _classtable [ i ] . reg . segment = = segment )
segMan - > _classtable [ i ] . reg = NULL_REG ;
2009-02-15 06:10:59 +00:00
2009-09-17 16:50:53 +00:00
if ( getSciVersion ( ) < SCI_VERSION_1_1 )
2009-09-06 12:57:42 +00:00
script_uninstantiate_sci0 ( segMan , script_nr , segment ) ;
2009-10-11 09:34:35 +00:00
// FIXME: Add proper script uninstantiation for SCI 1.1
2009-02-15 06:10:59 +00:00
2009-05-15 09:27:07 +00:00
if ( scr - > getLockers ( ) )
2009-02-20 23:09:29 +00:00
return ; // if xxx.lockers > 0
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// Otherwise unload it completely
// Explanation: I'm starting to believe that this work is done by SCI itself.
2009-05-15 09:27:07 +00:00
scr - > markDeleted ( ) ;
2009-02-15 06:10:59 +00:00
2009-05-30 15:40:49 +00:00
debugC ( kDebugLevelScripts , " Unloaded script 0x%x. \n " , script_nr ) ;
2009-02-15 06:10:59 +00:00
return ;
}
2009-02-28 11:12:59 +00:00
static void _init_stack_base_with_selector ( EngineState * s , Selector selector ) {
2009-02-21 21:16:41 +00:00
s - > stack_base [ 0 ] = make_reg ( 0 , ( uint16 ) selector ) ;
2009-02-15 06:10:59 +00:00
s - > stack_base [ 1 ] = NULL_REG ;
}
2009-06-07 17:18:11 +00:00
static EngineState * _game_run ( EngineState * & s , int restoring ) {
2009-02-21 10:47:56 +00:00
EngineState * successor = NULL ;
2009-02-15 06:10:59 +00:00
int game_is_finished = 0 ;
2010-01-29 01:31:05 +00:00
if ( Common : : isDebugChannelEnabled ( kDebugLevelOnStartup ) )
( ( Sci : : SciEngine * ) g_engine ) - > getSciDebugger ( ) - > attach ( ) ;
2009-02-15 06:10:59 +00:00
do {
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = false ;
2009-02-15 22:28:12 +00:00
run_vm ( s , ( successor | | restoring ) ? 1 : 0 ) ;
2009-02-20 23:09:29 +00:00
if ( s - > restarting_flags & SCI_GAME_IS_RESTARTING_NOW ) { // Restart was requested?
2009-02-26 23:13:00 +00:00
successor = NULL ;
2009-04-28 15:58:19 +00:00
s - > _executionStack . clear ( ) ;
s - > _executionStackPosChanged = false ;
2009-02-15 06:10:59 +00:00
game_exit ( s ) ;
2009-06-04 21:44:39 +00:00
script_init_engine ( s ) ;
2009-02-15 06:10:59 +00:00
game_init ( s ) ;
2009-12-19 16:19:53 +00:00
# ifdef USE_OLD_MUSIC_FUNCTIONS
2009-10-13 18:51:59 +00:00
s - > _sound . sfx_reset_player ( ) ;
2009-12-19 16:19:53 +00:00
# endif
2009-09-17 17:00:36 +00:00
_init_stack_base_with_selector ( s , s - > _kernel - > _selectorCache . play ) ;
2009-02-15 06:10:59 +00:00
2009-10-18 19:43:27 +00:00
send_selector ( s , s - > _gameObj , s - > _gameObj , s - > stack_base , 2 , s - > stack_base ) ;
2009-02-15 06:10:59 +00:00
script_abort_flag = 0 ;
2009-02-20 23:09:29 +00:00
s - > restarting_flags = SCI_GAME_WAS_RESTARTED | SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE ;
2009-02-15 06:10:59 +00:00
2009-02-15 22:28:12 +00:00
} else {
2009-02-15 06:10:59 +00:00
successor = s - > successor ;
if ( successor ) {
game_exit ( s ) ;
2009-02-24 22:25:39 +00:00
delete s ;
2009-02-15 06:10:59 +00:00
s = successor ;
2009-06-05 19:04:14 +00:00
if ( script_abort_flag = = 2 ) {
2009-07-06 10:39:22 +00:00
debugC ( 2 , kDebugLevelVM , " Restarting with replay() \n " ) ;
2009-05-18 18:15:45 +00:00
s - > _executionStack . clear ( ) ; // Restart with replay
2009-02-15 22:28:12 +00:00
2009-09-17 17:00:36 +00:00
_init_stack_base_with_selector ( s , s - > _kernel - > _selectorCache . replay ) ;
2009-02-15 06:10:59 +00:00
2009-10-18 19:43:27 +00:00
send_selector ( s , s - > _gameObj , s - > _gameObj , s - > stack_base , 2 , s - > stack_base ) ;
2009-02-15 06:10:59 +00:00
}
script_abort_flag = 0 ;
} else
game_is_finished = 1 ;
}
} while ( ! game_is_finished ) ;
return s ;
}
2009-02-21 10:47:56 +00:00
int game_run ( EngineState * * _s ) {
EngineState * s = * _s ;
2009-02-15 06:10:59 +00:00
2009-12-27 12:54:03 +00:00
debugC ( 2 , kDebugLevelVM , " Calling %s::play() \n " , s - > _gameId . c_str ( ) ) ;
2009-09-17 17:00:36 +00:00
_init_stack_base_with_selector ( s , s - > _kernel - > _selectorCache . play ) ; // Call the play selector
2009-02-15 06:10:59 +00:00
2009-02-20 23:09:29 +00:00
// Now: Register the first element on the execution stack-
2009-10-18 19:43:27 +00:00
if ( ! send_selector ( s , s - > _gameObj , s - > _gameObj , s - > stack_base , 2 , s - > stack_base ) ) {
2009-07-08 13:08:51 +00:00
Console * con = ( ( SciEngine * ) g_engine ) - > getSciDebugger ( ) ;
2009-10-18 19:43:27 +00:00
con - > printObject ( s - > _gameObj ) ;
2009-07-06 10:39:22 +00:00
warning ( " Failed to run the game! Aborting... " ) ;
2009-02-15 06:10:59 +00:00
return 1 ;
}
2009-02-20 23:09:29 +00:00
// and ENGAGE!
2009-06-07 17:18:11 +00:00
_game_run ( * _s , 0 ) ;
2009-02-15 06:10:59 +00:00
2009-07-06 10:39:22 +00:00
debugC ( 2 , kDebugLevelVM , " Game::play() finished. \n " ) ;
2009-02-20 23:09:29 +00:00
2009-02-15 06:10:59 +00:00
return 0 ;
}
2009-02-20 23:09:29 +00:00
void quit_vm ( ) {
script_abort_flag = 1 ; // Terminate VM
2009-09-17 13:21:19 +00:00
g_debugState . seeking = kDebugSeekNothing ;
g_debugState . runningStep = 0 ;
2009-02-15 06:10:59 +00:00
}
2009-02-21 10:23:36 +00:00
2009-05-28 22:42:18 +00:00
void shrink_execution_stack ( EngineState * s , uint size ) {
assert ( s - > _executionStack . size ( ) > = size ) ;
Common : : List < ExecStack > : : iterator iter ;
iter = s - > _executionStack . begin ( ) ;
for ( uint i = 0 ; i < size ; + + i )
+ + iter ;
s - > _executionStack . erase ( iter , s - > _executionStack . end ( ) ) ;
}
2009-09-06 12:57:42 +00:00
reg_t * ObjVarRef : : getPointer ( SegManager * segMan ) const {
2009-09-12 00:10:07 +00:00
Object * o = segMan - > getObject ( obj ) ;
2009-06-06 11:38:20 +00:00
if ( ! o ) return 0 ;
return & ( o - > _variables [ varindex ] ) ;
}
2009-09-06 12:57:42 +00:00
reg_t * ExecStack : : getVarPointer ( SegManager * segMan ) const {
2009-06-06 11:38:20 +00:00
assert ( type = = EXEC_STACK_TYPE_VARSELECTOR ) ;
2009-09-06 12:57:42 +00:00
return addr . varp . getPointer ( segMan ) ;
2009-06-06 11:38:20 +00:00
}
2009-05-28 22:42:18 +00:00
2009-02-21 10:23:36 +00:00
} // End of namespace Sci