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"
2010-05-04 11:59:22 +00:00
# include "common/debug-channels.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"
2010-02-13 17:44:58 +00:00
# include "sci/engine/features.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"
2010-01-29 11:05:06 +00:00
# include "sci/engine/script.h"
2010-06-10 09:18:57 +00:00
# include "sci/engine/seg_manager.h"
# include "sci/engine/selector.h" // for SELECTOR
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
2010-02-03 01:34:39 +00:00
# define SCI_XS_CALLEE_LOCALS ((SegmentId)-1)
/**
* Adds an entry to the top of the execution stack .
*
* @ param [ in ] s The state with which to execute
* @ param [ in ] pc The initial program counter
* @ param [ in ] sp The initial stack pointer
* @ param [ in ] objp Pointer to the beginning of the current object
* @ param [ in ] argc Number of parameters to call with
* @ param [ in ] argp Heap pointer to the first parameter
* @ param [ in ] selector The selector by which it was called or
* NULL_SELECTOR if n . a . For debugging .
* @ param [ in ] sendp Pointer to the object which the message was
* sent to . Equal to objp for anything but super .
* @ param [ in ] origin Number of the execution stack element this
* entry was created by ( usually the current TOS
* number , except for multiple sends ) .
* @ param [ in ] local_segment The segment to use for local variables ,
* or SCI_XS_CALLEE_LOCALS to use obj ' s segment .
* @ return A pointer to the new exec stack TOS entry
*/
static ExecStack * add_exec_stack_entry ( Common : : List < ExecStack > & execStack , reg_t pc , StackPtr sp ,
reg_t objp , int argc , StackPtr argp , Selector selector ,
reg_t sendp , int origin , SegmentId local_segment ) ;
/**
* Adds one varselector access to the execution stack .
* This function is called from send_selector only .
* @ param [ in ] s The EngineState to use
* @ param [ in ] objp Pointer to the object owning the selector
* @ param [ in ] argc 1 for writing , 0 for reading
* @ param [ in ] argp Pointer to the address of the data to write - 2
* @ param [ in ] selector Selector name
* @ param [ in ] address Heap address of the selector
* @ param [ in ] origin Stack frame which the access originated from
* @ return Pointer to the new exec - TOS element
*/
static ExecStack * add_exec_stack_varselector ( Common : : List < ExecStack > & execStack , reg_t objp , int argc ,
StackPtr argp , Selector selector , const ObjVarRef & address ,
int origin ) ;
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
2010-02-07 17:56:57 +00:00
// may modify the value of the returned reg_t.
2009-10-02 11:04:36 +00:00
static reg_t dummyReg = NULL_REG ;
2009-02-15 22:28:12 +00:00
if ( ! obj ) {
2010-01-30 11:59:05 +00:00
debugC ( 2 , kDebugLevelVM , " [VM] Sending to disposed object! " ) ;
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-30 11:59:05 +00:00
debugC ( 2 , kDebugLevelVM , " [VM] Invalid property #%d (out of [0..%d]) requested! " ,
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
}
2010-05-26 16:30:10 +00:00
return obj - > getVariableRef ( 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-06-18 14:48:39 +00:00
// The results of this are likely unpredictable... It most likely means that a kernel function is returning something wrong.
// If such an error occurs, we usually need to find the last kernel function called and check its return value. Check
// callKernelFunc() below
error ( " [VM] Attempt to read arithmetic value from non-zero segment [%04x]. Address: %04x:%04x " , reg . segment , PRINT_REG ( reg ) ) ;
2010-01-29 22:51:22 +00:00
return 0 ;
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 ) {
2010-06-18 14:48:39 +00:00
return ( int16 ) validate_arithmetic ( reg ) ;
2009-02-15 06:10:59 +00:00
}
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-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 ) {
2010-06-17 23:50:28 +00:00
// Fatal, as the game is trying to do an OOB access
error ( " %s. [VM] Access would be outside even of the stack (%d); access denied " , txt . c_str ( ) , total_offset ) ;
2009-10-30 18:01:27 +00:00
return false ;
2009-02-15 06:10:59 +00:00
} else {
2010-06-21 15:51:04 +00:00
// WORKAROUND: Mixed-Up Mother Goose tries to use an invalid parameter in Event::new().
// Just skip around it here so we don't error out in validate_arithmetic.
if ( g_sci - > getGameId ( ) = = " mothergoose " & & getSciVersion ( ) < = SCI_VERSION_1_1 & & type = = VAR_PARAM & & index = = 1 )
return false ;
2010-01-30 11:59:05 +00:00
debugC ( 2 , kDebugLevelVM , " %s " , txt . c_str ( ) ) ;
debugC ( 2 , kDebugLevelVM , " [VM] Access within stack boundaries; access granted. " ) ;
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).
2010-06-13 22:01:10 +00:00
if ( index = = 0 & & type = = VAR_GLOBAL & & getSciVersion ( ) > SCI_VERSION_0_EARLY ) { // global 0 is ego
2009-10-21 08:28:39 +00:00
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 ;
2010-06-10 09:18:57 +00:00
if ( lookupSelector ( segMan , stopGroopPos , SELECTOR ( client ) , & varp , NULL ) = = kSelectorVariable ) {
2009-10-21 08:28:39 +00:00
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)
2010-02-07 17:56:57 +00:00
# define signed_validate_arithmetic(r) ((int16)(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
2010-06-10 11:43:20 +00:00
# define READ_VAR(type, index, def) validate_read_var(s->variables[type], s->stack_base, type, s->variablesMax[type], index, __LINE__, def)
# define WRITE_VAR(type, index, value) validate_write_var(s->variables[type], s->stack_base, type, s->variablesMax[type], index, __LINE__, value, s->_segMan, g_sci->getKernel())
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:
2010-06-06 23:00:33 +00:00
# define PUSH32(a) (*(validate_stack_addr(s, (s->xs->sp)++)) = (a))
# define POP32() (*(validate_stack_addr(s, --(s->xs->sp))))
2009-02-15 06:10:59 +00:00
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
2010-05-19 08:50:24 +00:00
if ( ! scr | | scr - > isMarkedAsDeleted ( ) ) { // Script not present yet?
2010-02-13 17:44:19 +00:00
seg = script_instantiate ( g_sci - > getResMan ( ) , s - > _segMan , script ) ;
2010-05-19 08:50:24 +00:00
scr = s - > _segMan - > getScript ( seg ) ;
}
2009-02-15 06:10:59 +00:00
2010-05-19 08:50:24 +00:00
const int temp = scr - > validateExportFunc ( pubfunct ) ;
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
2010-05-19 07:25:06 +00:00
if ( g_debugState . _activeBreakpointTypes & BREAK_EXPORT ) {
2009-02-21 21:16:41 +00:00
uint32 bpaddress ;
2009-02-15 22:28:12 +00:00
bpaddress = ( script < < 16 | pubfunct ) ;
2010-02-02 22:52:41 +00:00
Common : : List < Breakpoint > : : const_iterator bp ;
2010-05-19 07:25:06 +00:00
for ( bp = g_debugState . _breakpoints . begin ( ) ; bp ! = g_debugState . _breakpoints . end ( ) ; + + bp ) {
2010-02-02 22:52:41 +00:00
if ( bp - > type = = BREAK_EXPORT & & bp - > address = = bpaddress ) {
2010-02-13 17:42:49 +00:00
Console * con = g_sci - > getSciDebugger ( ) ;
2009-07-06 10:39:22 +00:00
con - > DebugPrintf ( " Break on script %d, export %d \n " , script , pubfunct ) ;
2009-09-17 13:21:19 +00:00
g_debugState . debugging = true ;
2010-05-18 09:18:27 +00:00
g_debugState . breakpointWasHit = true ;
2009-02-15 22:28:12 +00:00
break ;
}
}
}
2010-02-03 01:34:39 +00:00
return add_exec_stack_entry ( s - > _executionStack , 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 ) {
2010-06-17 23:50:28 +00:00
error ( " Invalid varselector exec stack entry " ) ;
2009-10-14 22:41:03 +00:00
} 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
2010-05-26 09:33:33 +00:00
bool printSendActions = false ;
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
2010-05-19 07:25:06 +00:00
if ( g_debugState . _activeBreakpointTypes & BREAK_SELECTOR ) {
2010-02-02 22:52:41 +00:00
char method_name [ 256 ] ;
2009-02-15 06:10:59 +00:00
2010-02-13 17:45:40 +00:00
sprintf ( method_name , " %s::%s " , s - > _segMan - > getObjectName ( send_obj ) , g_sci - > getKernel ( ) - > getSelectorName ( selector ) . c_str ( ) ) ;
2009-02-15 06:10:59 +00:00
2010-02-02 22:52:41 +00:00
Common : : List < Breakpoint > : : const_iterator bp ;
2010-05-19 07:25:06 +00:00
for ( bp = g_debugState . _breakpoints . begin ( ) ; bp ! = g_debugState . _breakpoints . end ( ) ; + + bp ) {
2010-02-02 22:52:41 +00:00
int cmplen = bp - > name . size ( ) ;
if ( bp - > name . lastChar ( ) ! = ' : ' )
2009-02-15 06:10:59 +00:00
cmplen = 256 ;
2010-02-02 22:52:41 +00:00
if ( bp - > type = = BREAK_SELECTOR & & ! strncmp ( bp - > name . c_str ( ) , method_name , cmplen ) ) {
2010-02-13 17:42:49 +00:00
Console * con = g_sci - > getSciDebugger ( ) ;
2009-07-06 10:39:22 +00:00
con - > DebugPrintf ( " Break on %s (in [%04x:%04x]) \n " , method_name , PRINT_REG ( send_obj ) ) ;
2010-05-26 09:33:33 +00:00
printSendActions = true ;
2009-09-17 13:21:19 +00:00
g_debugState . debugging = true ;
2010-05-18 09:18:27 +00:00
g_debugState . breakpointWasHit = true ;
2009-02-15 06:10:59 +00:00
break ;
}
}
}
# ifdef VM_DEBUG_SEND
2010-02-13 17:42:49 +00:00
printf ( " Send to %04x:%04x, selector %04x (%s): " , PRINT_REG ( send_obj ) , selector , g_sci - > 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 ;
2010-05-29 23:37:15 +00:00
switch ( lookupSelector ( 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
2010-05-26 09:33:33 +00:00
// argc != 0: write selector
if ( printSendActions & & ! argc ) { // read selector
debug ( " [read selector] \n " ) ;
printSendActions = false ;
2009-10-01 12:41:21 +00:00
}
2009-02-15 06:10:59 +00:00
2010-05-26 09:33:33 +00:00
if ( printSendActions & & argc ) {
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 ] ;
2010-05-26 09:33:33 +00:00
debug ( " [write to selector: change %04x:%04x to %04x:%04x] \n " , PRINT_REG ( oldReg ) , PRINT_REG ( newReg ) ) ;
printSendActions = false ;
2009-10-01 12:41:21 +00:00
}
2010-05-26 10:35:54 +00:00
if ( argc > 1 ) {
2010-06-17 20:52:53 +00:00
// argc can indeed be bigger than 1 in some cases, and it's usually the
// result of a script bug
const char * objectName = s - > _segMan - > getObjectName ( send_obj ) ;
if ( ! strcmp ( objectName , " Sq4GlobalNarrator " ) & & selector = = 606 ) {
// SQ4 has a script bug in the Sq4GlobalNarrator object when invoking the
// returnVal selector, which doesn't affect gameplay, thus don't diplay it
2010-06-22 18:25:15 +00:00
} else if ( ! strcmp ( objectName , " longSong " ) & & selector = = 3 & & g_sci - > getGameId ( ) = = " qfg1 " ) {
// QFG1VGA has a script bug in the longSong object when invoking the
// loop selector, which doesn't affect gameplay, thus don't diplay it
2010-06-17 20:52:53 +00:00
} else {
// Unknown script bug, show it
reg_t oldReg = * varp . getPointer ( s - > _segMan ) ;
reg_t newReg = argp [ 1 ] ;
const char * selectorName = g_sci - > getKernel ( ) - > getSelectorName ( selector ) . c_str ( ) ;
2010-06-17 23:50:28 +00:00
error ( " send_selector(): argc = %d while modifying variable selector "
2010-06-17 20:52:53 +00:00
" %x (%s) of object %04x:%04x (%s) from %04x:%04x to %04x:%04x " ,
argc , selector , selectorName , PRINT_REG ( send_obj ) ,
objectName , PRINT_REG ( oldReg ) , PRINT_REG ( newReg ) ) ;
}
2010-05-26 10:35:54 +00:00
}
2010-05-26 09:59:40 +00:00
2009-10-01 12:41:21 +00:00
{
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
2010-05-26 09:33:33 +00:00
if ( printSendActions ) {
debug ( " [invoke selector] \n " ) ;
printSendActions = false ;
2009-02-15 06:10:59 +00:00
}
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 ;
2010-05-29 23:37:15 +00:00
} // switch (lookupSelector())
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?
2010-02-03 01:34:39 +00:00
add_exec_stack_varselector ( s - > _executionStack , 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
2010-02-03 01:34:39 +00:00
add_exec_stack_entry ( s - > _executionStack , 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 ) ;
2010-05-26 09:33:33 +00:00
return s - > _executionStack . empty ( ) ? NULL : & ( s - > _executionStack . back ( ) ) ;
2009-02-15 06:10:59 +00:00
}
2010-02-03 01:34:39 +00:00
static ExecStack * add_exec_stack_varselector ( Common : : List < ExecStack > & execStack , reg_t objp , int argc , StackPtr argp , Selector selector , const ObjVarRef & address , int origin ) {
ExecStack * xstack = add_exec_stack_entry ( execStack , 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 ;
}
2010-02-03 01:34:39 +00:00
static ExecStack * add_exec_stack_entry ( Common : : List < ExecStack > & execStack , 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
2010-02-03 01:34:39 +00:00
execStack . push_back ( xstack ) ;
return & ( execStack . 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 ;
default :
2010-02-07 17:57:51 +00:00
// FIXME: Changed this to warning, because iceman does this during dancing with girl.
// Investigate why that is so and either fix the underlying issue or implement a more
// specialized workaround!
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 ;
}
}
2010-02-07 17:57:51 +00:00
static void callKernelFunc ( EngineState * s , int kernelFuncNum , int argc ) {
2010-02-13 17:45:40 +00:00
if ( kernelFuncNum > = ( int ) g_sci - > getKernel ( ) - > _kernelFuncs . size ( ) )
2010-02-07 17:57:51 +00:00
error ( " Invalid kernel function 0x%x requested " , kernelFuncNum ) ;
2010-02-13 17:45:40 +00:00
const KernelFuncWithSignature & kernelFunc = g_sci - > getKernel ( ) - > _kernelFuncs [ kernelFuncNum ] ;
2010-02-07 17:57:51 +00:00
if ( kernelFunc . signature
2010-06-06 23:00:33 +00:00
& & ! g_sci - > getKernel ( ) - > signatureMatch ( kernelFunc . signature , argc , s - > xs - > sp + 1 ) ) {
2010-02-07 17:57:51 +00:00
error ( " [VM] Invalid arguments to kernel call %x " , kernelFuncNum ) ;
}
2010-06-06 23:00:33 +00:00
reg_t * argv = s - > xs - > sp + 1 ;
2010-02-07 17:57:51 +00:00
if ( ! kernelFunc . isDummy ) {
// 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 - > _executionStack , NULL_REG , NULL , NULL_REG , argc , argv - 1 , 0 , NULL_REG ,
s - > _executionStack . size ( ) - 1 , SCI_XS_CALLEE_LOCALS ) ;
xstack - > selector = kernelFuncNum ;
xstack - > type = EXEC_STACK_TYPE_KERNEL ;
2010-06-17 23:13:54 +00:00
//warning("callk %s", kernelFunc.origName.c_str());
2010-02-07 17:57:51 +00:00
2010-05-31 12:13:50 +00:00
// TODO: SCI2.1 equivalent
2010-06-06 23:00:33 +00:00
if ( s - > loadFromLauncher > = 0 & & (
2010-05-31 12:13:50 +00:00
( kernelFuncNum = = 0x8 & & getSciVersion ( ) < = SCI_VERSION_1_1 ) | | // DrawPic
2010-05-31 12:43:28 +00:00
( kernelFuncNum = = 0x3d & & getSciVersion ( ) = = SCI_VERSION_2 ) // GetSaveDir
//(kernelFuncNum == 0x28 && getSciVersion() == SCI_VERSION_2_1) // AddPlane
) ) {
2010-05-31 12:13:50 +00:00
// A game is being loaded from the launcher, and the game is about to draw something on
// screen, hence all initialization has taken place (i.e. menus have been constructed etc).
// Therefore, inject a kRestoreGame call here, instead of the requested function.
// The restore call is injected here mainly for games which have a menu, as the menu is
// constructed when the game starts and is not reconstructed when a saved game is loaded.
2010-06-06 23:00:33 +00:00
int saveSlot = s - > loadFromLauncher ;
s - > loadFromLauncher = - 1 ; // invalidate slot, so that we don't load again
2010-05-31 12:13:50 +00:00
if ( saveSlot < 0 )
error ( " Requested to load invalid save slot " ) ; // should never happen, really
reg_t restoreArgv [ 2 ] = { NULL_REG , make_reg ( 0 , saveSlot ) } ; // special call (argv[0] is NULL)
kRestoreGame ( s , 2 , restoreArgv ) ;
2010-02-07 17:57:51 +00:00
} else {
// Call kernel function
2010-06-17 23:13:54 +00:00
s - > r_acc = kernelFunc . func ( s , argc , argv ) ;
2010-06-18 14:48:39 +00:00
#if 0
// Used for debugging
Common : : String debugMsg = kernelFunc . origName +
Common : : String : : printf ( " [0x%x] " , kernelFuncNum ) +
Common : : String : : printf ( " , %d params: " , argc ) +
" ( " ;
for ( int i = 0 ; i < argc ; i + + ) {
debugMsg + = Common : : String : : printf ( " %04x:%04x " , PRINT_REG ( argv [ i ] ) ) ;
debugMsg + = ( i = = argc - 1 ? " ) " : " , " ) ;
}
debugMsg + = " , result: " + Common : : String : : printf ( " %04x:%04x " , PRINT_REG ( s - > r_acc ) ) ;
debug ( " %s " , debugMsg . c_str ( ) ) ;
# endif
2010-02-07 17:57:51 +00:00
}
2010-06-22 18:25:15 +00:00
// Remove callk stack frame again, if there's still an execution stack
if ( s - > _executionStack . begin ( ) ! = s - > _executionStack . end ( ) )
s - > _executionStack . pop_back ( ) ;
2010-02-07 17:57:51 +00:00
} else {
2010-06-17 23:13:54 +00:00
Common : : String warningMsg = " Dummy function " + kernelFunc . origName +
2010-02-07 17:57:51 +00:00
Common : : String : : printf ( " [0x%x] " , kernelFuncNum ) +
" invoked - ignoring. Params: " +
Common : : String : : printf ( " %d " , argc ) + " ( " ;
for ( int i = 0 ; i < argc ; i + + ) {
warningMsg + = Common : : String : : printf ( " %04x:%04x " , PRINT_REG ( argv [ i ] ) ) ;
warningMsg + = ( i = = argc - 1 ? " ) " : " , " ) ;
}
warning ( " %s " , warningMsg . c_str ( ) ) ;
}
}
2010-06-10 11:43:20 +00:00
static void gcCountDown ( EngineState * s ) {
if ( s - > gcCountDown - - < = 0 ) {
s - > gcCountDown = s - > scriptGCInterval ;
2010-02-12 02:23:28 +00:00
run_gc ( s ) ;
2009-02-15 06:10:59 +00:00
}
}
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
2010-02-07 12:13:59 +00:00
int readPMachineInstruction ( const byte * src , byte & extOpcode , int16 opparams [ 4 ] ) {
uint offset = 0 ;
extOpcode = src [ offset + + ] ; // Get "extended" opcode (lower bit has special meaning)
2010-02-07 17:57:25 +00:00
const byte opcode = extOpcode > > 1 ; // get the actual opcode
2010-02-07 12:13:59 +00:00
memset ( opparams , 0 , sizeof ( opparams ) ) ;
2010-02-07 17:57:25 +00:00
for ( int i = 0 ; g_opcode_formats [ opcode ] [ i ] ; + + i ) {
//printf("Opcode: 0x%x, Opnumber: 0x%x, temp: %d\n", opcode, opcode, temp);
2010-02-07 12:13:59 +00:00
assert ( i < 4 ) ;
2010-02-07 17:57:25 +00:00
switch ( g_opcode_formats [ opcode ] [ i ] ) {
2010-02-07 12:13:59 +00:00
case Script_Byte :
opparams [ i ] = src [ offset + + ] ;
break ;
case Script_SByte :
opparams [ i ] = ( int8 ) src [ offset + + ] ;
break ;
case Script_Word :
2010-05-18 04:17:58 +00:00
opparams [ i ] = READ_SCI11ENDIAN_UINT16 ( src + offset ) ;
2010-02-07 12:13:59 +00:00
offset + = 2 ;
break ;
case Script_SWord :
2010-05-18 04:17:58 +00:00
opparams [ i ] = ( int16 ) READ_SCI11ENDIAN_UINT16 ( src + offset ) ;
2010-02-07 12:13:59 +00:00
offset + = 2 ;
break ;
case Script_Variable :
case Script_Property :
case Script_Local :
case Script_Temp :
case Script_Global :
case Script_Param :
case Script_Offset :
if ( extOpcode & 1 ) {
opparams [ i ] = src [ offset + + ] ;
} else {
2010-05-18 04:17:58 +00:00
opparams [ i ] = READ_SCI11ENDIAN_UINT16 ( src + offset ) ;
2010-02-07 12:13:59 +00:00
offset + = 2 ;
}
break ;
case Script_SVariable :
case Script_SRelative :
if ( extOpcode & 1 ) {
opparams [ i ] = ( int8 ) src [ offset + + ] ;
} else {
2010-05-18 04:17:58 +00:00
opparams [ i ] = ( int16 ) READ_SCI11ENDIAN_UINT16 ( src + offset ) ;
2010-02-07 12:13:59 +00:00
offset + = 2 ;
}
break ;
case Script_None :
case Script_End :
break ;
case Script_Invalid :
default :
error ( " opcode %02x: Invalid " , extOpcode ) ;
}
}
return offset ;
}
2010-02-03 01:33:23 +00:00
void run_vm ( EngineState * s , bool 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
2009-02-20 23:09:29 +00:00
2010-06-09 07:32:17 +00:00
s - > restAdjust = 0 ;
2009-02-20 23:09:29 +00:00
// &rest adjusts the parameter count by this value
// Current execution data:
2010-06-06 23:00:33 +00:00
s - > xs = & ( s - > _executionStack . back ( ) ) ;
2009-02-28 11:12:59 +00:00
ExecStack * xs_new = NULL ;
2010-06-06 23:00:33 +00:00
Object * obj = s - > _segMan - > getObject ( s - > xs - > objp ) ;
Script * local_script = s - > _segMan - > getScriptIfLoaded ( s - > xs - > local_segment ) ;
2010-06-10 11:18:10 +00:00
int old_executionStackBase = s - > executionStackBase ;
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 )
2010-06-10 11:18:10 +00:00
s - > executionStackBase = s - > _executionStack . size ( ) - 1 ;
2009-02-15 06:10:59 +00:00
2010-06-10 11:43:20 +00:00
s - > variablesSegment [ VAR_TEMP ] = s - > variablesSegment [ VAR_PARAM ] = s - > _segMan - > findSegmentByType ( SEG_TYPE_STACK ) ;
s - > variablesBase [ VAR_TEMP ] = s - > variablesBase [ VAR_PARAM ] = s - > stack_base ;
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 ) {
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 ;
2010-06-06 23:00:33 +00:00
g_debugState . old_pc_offset = s - > xs - > addr . pc . offset ;
g_debugState . old_sp = s - > xs - > sp ;
2009-02-15 06:10:59 +00:00
2010-06-21 20:17:59 +00:00
if ( s - > abortScriptProcessing ! = kAbortNone | | g_engine - > shouldQuit ( ) )
return ; // Stop processing
2009-04-28 15:58:19 +00:00
if ( s - > _executionStackPosChanged ) {
2009-02-28 11:12:59 +00:00
Script * scr ;
2010-06-06 23:00:33 +00:00
s - > xs = & ( s - > _executionStack . back ( ) ) ;
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = false ;
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
scr = s - > _segMan - > getScriptIfLoaded ( s - > 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
2010-06-17 23:50:28 +00:00
// FIXME: Why does this happen? Are there leftover calls in the call stack?
2010-06-06 23:00:33 +00:00
warning ( " Running on non-existant script in segment %x " , s - > 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
2010-06-06 23:00:33 +00:00
s - > xs - > addr . pc . offset = 1 ;
2009-02-15 06:10:59 +00:00
scr = NULL ;
obj = NULL ;
} else {
2010-06-06 23:00:33 +00:00
obj = s - > _segMan - > getObject ( s - > 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
2010-05-30 16:14:31 +00:00
code_buf_size = scr - > getBufSize ( ) ;
2009-02-15 06:10:59 +00:00
# endif
2010-06-06 23:00:33 +00:00
local_script = s - > _segMan - > getScriptIfLoaded ( s - > xs - > local_segment ) ;
2009-02-15 06:10:59 +00:00
if ( ! local_script ) {
2010-06-17 23:50:28 +00:00
// FIXME: Why does this happen? Is the script not loaded yet at this point?
2010-06-06 23:00:33 +00:00
warning ( " Could not find local script from segment %x " , s - > xs - > local_segment ) ;
2009-02-15 06:10:59 +00:00
local_script = NULL ;
2010-06-10 11:43:20 +00:00
s - > variablesBase [ VAR_LOCAL ] = s - > variables [ VAR_LOCAL ] = NULL ;
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2010-06-10 11:43:20 +00:00
s - > variablesMax [ VAR_LOCAL ] = 0 ;
2009-02-15 06:10:59 +00:00
# endif
} else {
2010-06-10 11:43:20 +00:00
s - > variablesSegment [ VAR_LOCAL ] = local_script - > _localsSegment ;
2009-09-16 23:32:27 +00:00
if ( local_script - > _localsBlock )
2010-06-10 11:43:20 +00:00
s - > variablesBase [ VAR_LOCAL ] = s - > variables [ VAR_LOCAL ] = local_script - > _localsBlock - > _locals . begin ( ) ;
2009-02-15 06:10:59 +00:00
else
2010-06-10 11:43:20 +00:00
s - > variablesBase [ VAR_LOCAL ] = s - > 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 )
2010-06-10 11:43:20 +00:00
s - > variablesMax [ VAR_LOCAL ] = local_script - > _localsBlock - > _locals . size ( ) ;
2009-02-15 06:10:59 +00:00
else
2010-06-10 11:43:20 +00:00
s - > variablesMax [ VAR_LOCAL ] = 0 ;
s - > variablesMax [ VAR_TEMP ] = s - > xs - > sp - s - > xs - > fp ;
s - > variablesMax [ VAR_PARAM ] = s - > xs - > argc + 1 ;
2009-02-15 06:10:59 +00:00
# endif
}
2010-06-06 23:00:33 +00:00
s - > variables [ VAR_TEMP ] = s - > xs - > fp ;
s - > variables [ VAR_PARAM ] = s - > xs - > variables_argp ;
2009-02-15 06:10:59 +00:00
}
}
2010-06-08 21:05:46 +00:00
if ( s - > abortScriptProcessing ! = kAbortNone | | g_engine - > shouldQuit ( ) )
2010-06-21 20:17:59 +00:00
return ; // Stop processing
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*/ ) {
2010-05-18 09:18:27 +00:00
script_debug ( s ) ;
g_debugState . breakpointWasHit = false ;
2009-02-15 06:10:59 +00:00
}
2010-02-13 17:42:49 +00:00
Console * con = g_sci - > getSciDebugger ( ) ;
2009-07-18 12:51:12 +00:00
if ( con - > isAttached ( ) ) {
con - > onFrame ( ) ;
}
2009-02-15 06:10:59 +00:00
# ifndef DISABLE_VALIDATIONS
2010-06-06 23:00:33 +00:00
if ( s - > xs - > sp < s - > xs - > fp )
2010-05-28 12:37:54 +00:00
error ( " run_vm(): stack underflow, sp: %04x:%04x, fp: %04x:%04x " ,
2010-06-06 23:00:33 +00:00
PRINT_REG ( * s - > xs - > sp ) , PRINT_REG ( * s - > xs - > fp ) ) ;
2009-02-15 06:10:59 +00:00
2010-06-10 11:43:20 +00:00
s - > variablesMax [ VAR_TEMP ] = s - > xs - > sp - s - > xs - > fp ;
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
if ( s - > xs - > addr . pc . offset > = code_buf_size )
2010-05-28 12:37:54 +00:00
error ( " run_vm(): program counter gone astray, addr: %d, code buffer size: %d " ,
2010-06-06 23:00:33 +00:00
s - > xs - > addr . pc . offset , code_buf_size ) ;
2009-02-15 06:10:59 +00:00
# endif
2010-02-07 12:13:59 +00:00
// Get opcode
2010-02-07 17:57:25 +00:00
byte extOpcode ;
2010-06-06 23:00:33 +00:00
s - > xs - > addr . pc . offset + = readPMachineInstruction ( code_buf + s - > xs - > addr . pc . offset , extOpcode , opparams ) ;
2010-02-07 17:57:25 +00:00
const byte opcode = extOpcode > > 1 ;
2009-02-15 06:10:59 +00:00
2010-02-07 17:57:25 +00:00
switch ( opcode ) {
2009-02-15 06:10:59 +00:00
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.
2010-02-07 17:57:25 +00:00
if ( r_temp . segment ! = s - > r_acc . segment )
warning ( " [VM] Comparing pointers in different segments (%04x:%04x vs. %04x:%04x) " , PRINT_REG ( r_temp ) , PRINT_REG ( s - > r_acc ) ) ;
2010-01-27 01:47:41 +00:00
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset > s - > r_acc . offset ) ;
} else
2010-02-07 17:57:25 +00:00
s - > r_acc = ACC_ARITHMETIC_L ( signed_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 ( ) ;
2010-02-07 17:57:25 +00:00
if ( r_temp . segment & & s - > r_acc . segment ) {
if ( r_temp . segment ! = s - > r_acc . segment )
warning ( " [VM] Comparing pointers in different segments (%04x:%04x vs. %04x:%04x) " , PRINT_REG ( r_temp ) , PRINT_REG ( s - > r_acc ) ) ;
2010-01-27 01:47:41 +00:00
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset > = s - > r_acc . offset ) ;
2010-02-07 17:57:25 +00:00
} else
s - > r_acc = ACC_ARITHMETIC_L ( signed_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 ( ) ;
2010-02-07 17:57:25 +00:00
if ( r_temp . segment & & s - > r_acc . segment ) {
if ( r_temp . segment ! = s - > r_acc . segment )
warning ( " [VM] Comparing pointers in different segments (%04x:%04x vs. %04x:%04x) " , PRINT_REG ( r_temp ) , PRINT_REG ( s - > r_acc ) ) ;
2010-01-27 01:47:41 +00:00
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset < s - > r_acc . offset ) ;
2010-02-07 17:57:25 +00:00
} else
s - > r_acc = ACC_ARITHMETIC_L ( signed_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 ( ) ;
2010-02-07 17:57:25 +00:00
if ( r_temp . segment & & s - > r_acc . segment ) {
if ( r_temp . segment ! = s - > r_acc . segment )
warning ( " [VM] Comparing pointers in different segments (%04x:%04x vs. %04x:%04x) " , PRINT_REG ( r_temp ) , PRINT_REG ( s - > r_acc ) ) ;
2010-01-27 01:47:41 +00:00
s - > r_acc = make_reg ( 0 , ( r_temp . segment = = s - > r_acc . segment ) & & r_temp . offset < = s - > r_acc . offset ) ;
2010-02-07 17:57:25 +00:00
} else
s - > r_acc = ACC_ARITHMETIC_L ( signed_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-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-02-07 17:57:25 +00:00
if ( r_temp . segment & & ( s - > r_acc = = make_reg ( 0 , 1000 ) ) )
2010-01-30 04:01:15 +00:00
s - > r_acc = make_reg ( 0 , 1 ) ;
else 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*/ ) ;
break ;
case op_uge_ : // 0x14 (20)
s - > r_prev = s - > r_acc ;
r_temp = POP32 ( ) ;
// See above
2010-02-07 17:57:25 +00:00
if ( r_temp . segment & & ( s - > r_acc = = make_reg ( 0 , 1000 ) ) )
2010-01-30 04:01:15 +00:00
s - > r_acc = make_reg ( 0 , 1 ) ;
2010-01-29 22:17:27 +00:00
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-02-07 17:57:25 +00:00
if ( r_temp . segment & & ( s - > r_acc = = make_reg ( 0 , 1000 ) ) )
2010-01-30 04:01:15 +00:00
s - > r_acc = NULL_REG ;
2010-01-29 22:17:27 +00:00
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-30 04:01:15 +00:00
// See above
2010-02-07 17:57:25 +00:00
if ( r_temp . segment & & ( s - > r_acc = = make_reg ( 0 , 1000 ) ) )
2010-01-30 04:01:15 +00:00
s - > r_acc = NULL_REG ;
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_bt : // 0x17 (23)
2009-02-15 06:10:59 +00:00
if ( s - > r_acc . offset | | s - > r_acc . segment )
2010-06-06 23:00:33 +00:00
s - > 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 ) )
2010-06-06 23:00:33 +00:00
s - > 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)
2010-06-06 23:00:33 +00:00
s - > 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)
2010-06-06 23:00:33 +00:00
s - > xs - > sp - - ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_dup : // 0x1e (30)
2010-06-06 23:00:33 +00:00
r_temp = s - > 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 + + )
2010-06-06 23:00:33 +00:00
s - > xs - > sp [ i ] = NULL_REG ;
s - > 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
2010-06-09 07:32:17 +00:00
+ 1 + s - > restAdjust ;
2010-06-06 23:00:33 +00:00
StackPtr call_base = s - > xs - > sp - argc ;
2010-06-09 07:32:17 +00:00
s - > xs - > sp [ 1 ] . offset + = s - > restAdjust ;
2010-06-06 23:00:33 +00:00
xs_new = add_exec_stack_entry ( s - > _executionStack , make_reg ( s - > xs - > addr . pc . segment ,
s - > xs - > addr . pc . offset + opparams [ 0 ] ) ,
s - > xs - > sp , s - > xs - > objp ,
2010-06-09 07:32:17 +00:00
( validate_arithmetic ( * call_base ) ) + s - > restAdjust ,
2010-06-06 23:00:33 +00:00
call_base , NULL_SELECTOR , s - > xs - > objp ,
s - > _executionStack . size ( ) - 1 , s - > xs - > local_segment ) ;
2010-06-09 07:32:17 +00:00
s - > restAdjust = 0 ; // Used up the &rest adjustment
2010-06-06 23:00:33 +00:00
s - > 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)
2010-06-10 11:43:20 +00:00
gcCountDown ( s ) ;
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
s - > 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 ) ;
2010-06-09 07:32:17 +00:00
if ( ! oldScriptHeader )
s - > xs - > sp - = s - > restAdjust ;
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
int argc = validate_arithmetic ( s - > xs - > sp [ 0 ] ) ;
- 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
2010-02-07 17:57:51 +00:00
if ( ! oldScriptHeader )
2010-06-09 07:32:17 +00:00
argc + = s - > restAdjust ;
- 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
2010-02-07 17:57:51 +00:00
callKernelFunc ( s , opparams [ 0 ] , argc ) ;
2009-02-15 06:10:59 +00:00
2010-02-07 17:57:51 +00:00
if ( ! oldScriptHeader )
2010-06-09 07:32:17 +00:00
s - > restAdjust = 0 ;
2009-02-15 06:10:59 +00:00
2010-02-07 17:57:51 +00:00
// Calculate xs again: The kernel function might
// have spawned a new VM
2009-02-15 06:10:59 +00:00
2010-02-07 17:57:51 +00:00
xs_new = & ( s - > _executionStack . back ( ) ) ;
s - > _executionStackPosChanged = true ;
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)
2010-06-09 07:32:17 +00:00
temp = ( ( opparams [ 1 ] > > 1 ) + s - > restAdjust + 1 ) ;
2010-06-06 23:00:33 +00:00
s_temp = s - > xs - > sp ;
s - > xs - > sp - = temp ;
2010-06-09 07:32:17 +00:00
s - > xs - > sp [ 0 ] . offset + = s - > restAdjust ;
2010-06-06 23:00:33 +00:00
xs_new = execute_method ( s , 0 , opparams [ 0 ] , s_temp , s - > xs - > objp ,
s - > xs - > sp [ 0 ] . offset , s - > xs - > sp ) ;
2010-06-09 07:32:17 +00:00
s - > 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)
2010-06-09 07:32:17 +00:00
temp = ( ( opparams [ 2 ] > > 1 ) + s - > restAdjust + 1 ) ;
2010-06-06 23:00:33 +00:00
s_temp = s - > xs - > sp ;
s - > xs - > sp - = temp ;
2009-02-15 06:10:59 +00:00
2010-06-09 07:32:17 +00:00
s - > xs - > sp [ 0 ] . offset + = s - > restAdjust ;
2010-06-06 23:00:33 +00:00
xs_new = execute_method ( s , opparams [ 0 ] , opparams [ 1 ] , s_temp , s - > xs - > objp ,
s - > xs - > sp [ 0 ] . offset , s - > xs - > sp ) ;
2010-06-09 07:32:17 +00:00
s - > 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 {
2010-06-06 23:00:33 +00:00
StackPtr old_sp2 = s - > xs - > sp ;
StackPtr old_fp = s - > xs - > fp ;
2009-05-18 18:15:45 +00:00
ExecStack * old_xs = & ( s - > _executionStack . back ( ) ) ;
2009-02-15 06:10:59 +00:00
2010-06-10 11:18:10 +00:00
if ( ( int ) s - > _executionStack . size ( ) - 1 = = s - > executionStackBase ) { // Have we reached the base?
s - > executionStackBase = old_executionStackBase ; // 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-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 ;
2010-06-06 23:00:33 +00:00
s - > xs = & ( s - > _executionStack . back ( ) ) ;
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
if ( s - > xs - > sp = = CALL_SP_CARRY // Used in sends to 'carry' the stack pointer
| | s - > xs - > type ! = EXEC_STACK_TYPE_CALL ) {
s - > xs - > sp = old_sp2 ;
s - > xs - > fp = old_fp ;
2009-02-15 06:10:59 +00:00
}
2010-06-06 23:00:33 +00:00
} while ( s - > 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 ;
2010-06-06 23:00:33 +00:00
xs_new = s - > xs ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_send : // 0x25 (37)
2010-06-06 23:00:33 +00:00
s_temp = s - > xs - > sp ;
2010-06-09 07:32:17 +00:00
s - > xs - > sp - = ( ( opparams [ 0 ] > > 1 ) + s - > restAdjust ) ; // Adjust stack
2009-02-15 06:10:59 +00:00
2010-06-09 07:32:17 +00:00
s - > xs - > sp [ 1 ] . offset + = s - > restAdjust ;
2009-07-11 06:19:29 +00:00
xs_new = send_selector ( s , s - > r_acc , s - > r_acc , s_temp ,
2010-06-09 07:32:17 +00:00
( int ) ( opparams [ 0 ] > > 1 ) + ( uint16 ) s - > restAdjust , s - > xs - > sp ) ;
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
if ( xs_new & & xs_new ! = s - > xs )
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
2010-06-09 07:32:17 +00:00
s - > 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)
2010-02-07 17:57:25 +00:00
error ( " Dummy opcode 0x%x called " , opcode ) ; // should never happen
2010-01-28 13:07:47 +00:00
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 ,
2010-06-06 23:00:33 +00:00
s - > xs - > addr . pc ) ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case 0x29 : // (41)
2010-02-07 17:57:25 +00:00
error ( " Dummy opcode 0x%x called " , opcode ) ; // should never happen
2010-01-28 13:07:47 +00:00
break ;
case op_self : // 0x2a (42)
2010-06-06 23:00:33 +00:00
s_temp = s - > xs - > sp ;
2010-06-09 07:32:17 +00:00
s - > xs - > sp - = ( ( opparams [ 0 ] > > 1 ) + s - > restAdjust ) ; // Adjust stack
2009-02-15 06:10:59 +00:00
2010-06-09 07:32:17 +00:00
s - > xs - > sp [ 1 ] . offset + = s - > restAdjust ;
2010-06-06 23:00:33 +00:00
xs_new = send_selector ( s , s - > xs - > objp , s - > xs - > objp ,
2010-06-09 07:32:17 +00:00
s_temp , ( int ) ( opparams [ 0 ] > > 1 ) + ( uint16 ) s - > restAdjust ,
2010-06-06 23:00:33 +00:00
s - > xs - > sp ) ;
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
if ( xs_new & & xs_new ! = s - > xs )
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
2010-06-09 07:32:17 +00:00
s - > restAdjust = 0 ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case op_super : // 0x2b (43)
2010-06-06 23:00:33 +00:00
r_temp = s - > _segMan - > getClassAddress ( opparams [ 0 ] , SCRIPT_GET_LOAD , s - > 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 {
2010-06-06 23:00:33 +00:00
s_temp = s - > xs - > sp ;
2010-06-09 07:32:17 +00:00
s - > xs - > sp - = ( ( opparams [ 1 ] > > 1 ) + s - > restAdjust ) ; // Adjust stack
2009-02-15 06:10:59 +00:00
2010-06-09 07:32:17 +00:00
s - > xs - > sp [ 1 ] . offset + = s - > restAdjust ;
2010-06-06 23:00:33 +00:00
xs_new = send_selector ( s , r_temp , s - > xs - > objp , s_temp ,
2010-06-09 07:32:17 +00:00
( int ) ( opparams [ 1 ] > > 1 ) + ( uint16 ) s - > restAdjust ,
2010-06-06 23:00:33 +00:00
s - > xs - > sp ) ;
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
if ( xs_new & & xs_new ! = s - > xs )
2009-04-28 15:58:19 +00:00
s - > _executionStackPosChanged = true ;
2009-02-15 06:10:59 +00:00
2010-06-09 07:32:17 +00:00
s - > 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
2010-06-09 07:32:17 +00:00
s - > restAdjust = MAX < int16 > ( s - > xs - > argc - temp + 1 , 0 ) ; // +1 because temp counts the paramcount while argc doesn't
2009-02-15 06:10:59 +00:00
2010-06-06 23:00:33 +00:00
for ( ; temp < = s - > xs - > argc ; temp + + )
PUSH32 ( s - > 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
2010-06-10 11:43:20 +00:00
r_temp . segment = s - > variablesSegment [ var_number ] ;
r_temp . offset = s - > variables [ var_number ] - s - > variablesBase [ 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)
2010-06-06 23:00:33 +00:00
s - > r_acc = s - > xs - > objp ;
2009-02-15 06:10:59 +00:00
break ;
2010-01-28 13:07:47 +00:00
case 0x2f : // (47)
2010-02-07 17:57:25 +00:00
error ( " Dummy opcode 0x%x called " , opcode ) ; // should never happen
2010-01-28 13:07:47 +00:00
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);
2010-02-13 17:45:40 +00:00
// printf("%s\n", g_sci->getKernel()->getSelectorName(varSelector).c_str());
2010-01-17 18:27:57 +00:00
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)
2010-06-06 23:00:33 +00:00
s - > r_acc . segment = s - > xs - > addr . pc . segment ;
2009-02-15 06:10:59 +00:00
2010-02-13 17:44:58 +00:00
switch ( g_sci - > _features - > detectLofsType ( ) ) {
2009-08-30 14:53:58 +00:00
case SCI_VERSION_1_1 :
2010-05-30 16:14:31 +00:00
s - > r_acc . offset = opparams [ 0 ] + local_script - > getScriptSize ( ) ;
2009-08-30 14:53:58 +00:00
break ;
case SCI_VERSION_1_MIDDLE :
s - > r_acc . offset = opparams [ 0 ] ;
break ;
default :
2010-06-06 23:00:33 +00:00
s - > r_acc . offset = s - > 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)
2010-06-06 23:00:33 +00:00
r_temp . segment = s - > xs - > addr . pc . segment ;
2009-02-15 06:10:59 +00:00
2010-02-13 17:44:58 +00:00
switch ( g_sci - > _features - > detectLofsType ( ) ) {
2009-08-30 14:53:58 +00:00
case SCI_VERSION_1_1 :
2010-05-30 16:14:31 +00:00
r_temp . offset = opparams [ 0 ] + local_script - > getScriptSize ( ) ;
2009-08-30 14:53:58 +00:00
break ;
case SCI_VERSION_1_MIDDLE :
r_temp . offset = opparams [ 0 ] ;
break ;
default :
2010-06-06 23:00:33 +00:00
r_temp . offset = s - > 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-02-07 17:57:25 +00:00
if ( ! ( extOpcode & 1 ) ) {
2010-06-06 23:00:33 +00:00
PUSH32 ( s - > xs - > objp ) ;
2010-01-28 19:22:58 +00:00
} else {
// Debug opcode op_file, skip null-terminated string (file name)
2010-06-06 23:00:33 +00:00
while ( code_buf [ s - > xs - > addr . pc . offset + + ] ) ;
2010-01-28 19:22:58 +00:00
}
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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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...
2010-02-07 17:57:25 +00:00
var_type = opcode & 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-02-07 17:57:25 +00:00
s - > r_acc = POP32 ( ) ;
WRITE_VAR ( var_type , var_number , s - > r_acc ) ;
2009-02-15 06:10:59 +00:00
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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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)
2010-02-07 17:57:25 +00:00
var_type = opcode & 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 :
2010-02-07 17:57:25 +00:00
error ( " run_vm(): illegal opcode %x " , opcode ) ;
2009-02-15 06:10:59 +00:00
2010-02-07 17:57:25 +00:00
} // switch (opcode)
2009-02-15 06:10:59 +00:00
2009-04-28 15:58:19 +00:00
if ( s - > _executionStackPosChanged ) // Force initialization
2010-06-06 23:00:33 +00:00
s - > xs = xs_new ;
2009-02-15 06:10:59 +00:00
2009-05-19 00:02:10 +00:00
//#ifndef DISABLE_VALIDATIONS
2010-06-06 23:00:33 +00:00
if ( s - > xs ! = & ( s - > _executionStack . back ( ) ) ) {
2010-06-17 23:50:28 +00:00
error ( " xs is stale (%p vs %p); last command was %02x " ,
2010-06-06 23:00:33 +00:00
( void * ) s - > xs , ( void * ) & ( s - > _executionStack . back ( ) ) ,
2010-02-07 17:57:25 +00:00
opcode ) ;
2009-02-15 06:10:59 +00:00
}
2009-05-19 00:02:10 +00:00
//#endif
2010-06-10 11:18:10 +00:00
+ + s - > scriptStepCounter ;
2009-02-15 06:10:59 +00:00
}
}
2010-05-26 16:30:10 +00:00
reg_t * ObjVarRef : : getPointer ( SegManager * segMan ) const {
2009-09-12 00:10:07 +00:00
Object * o = segMan - > getObject ( obj ) ;
2010-05-26 16:30:10 +00:00
return o ? & o - > getVariableRef ( varindex ) : 0 ;
2009-06-06 11:38:20 +00:00
}
2010-05-26 16:30:10 +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