scummvm/engines/sci/engine/vm.h
2010-07-20 23:15:07 +00:00

371 lines
11 KiB
C++

/* 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$
*
*/
#ifndef SCI_ENGINE_VM_H
#define SCI_ENGINE_VM_H
/* VM and kernel declarations */
#include "sci/engine/vm_types.h" // for reg_t
#include "sci/resource.h" // for SciVersion
#include "common/util.h"
namespace Sci {
class SegManager;
struct EngineState;
class Object;
class ResourceManager;
/** Number of bytes to be allocated for the stack */
#define VM_STACK_SIZE 0x1000
/** Magical object identifier */
#define SCRIPT_OBJECT_MAGIC_NUMBER 0x1234
/** Offset of this identifier */
#define SCRIPT_OBJECT_MAGIC_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? -8 : 0)
/** Stack pointer value: Use predecessor's value */
#define CALL_SP_CARRY NULL
/** Types of selectors as returned by lookupSelector() below. */
enum SelectorType {
kSelectorNone = 0,
kSelectorVariable,
kSelectorMethod
};
struct Class {
int script; ///< number of the script the class is in, -1 for non-existing
reg_t reg; ///< offset; script-relative offset, segment: 0 if not instantiated
};
#define RAW_IS_OBJECT(datablock) (READ_SCI11ENDIAN_UINT16(((const byte *) datablock) + SCRIPT_OBJECT_MAGIC_OFFSET) == SCRIPT_OBJECT_MAGIC_NUMBER)
// A reference to an object's variable.
// The object is stored as a reg_t, the variable as an index into _variables
struct ObjVarRef {
reg_t obj;
int varindex;
reg_t* getPointer(SegManager *segMan) const;
};
enum ExecStackType {
EXEC_STACK_TYPE_CALL = 0,
EXEC_STACK_TYPE_KERNEL = 1,
EXEC_STACK_TYPE_VARSELECTOR = 2
};
struct ExecStack {
reg_t objp; ///< Pointer to the beginning of the current object
reg_t sendp; ///< Pointer to the object containing the invoked method
union {
ObjVarRef varp; // Variable pointer for r/w access
reg_t pc; // Pointer to the initial program counter. Not accurate for the TOS element
} addr;
StackPtr fp; // Frame pointer
StackPtr sp; // Stack pointer
int argc;
StackPtr variables_argp; // Argument pointer
SegmentId local_segment; // local variables etc
Selector debugSelector; // The selector which was used to call or -1 if not applicable
int debugExportId; // The exportId which was called or -1 if not applicable
int debugLocalCallOffset; // Local call offset or -1 if not applicable
int debugOrigin; // The stack frame position the call was made from, or -1 if it was the initial call
ExecStackType type;
reg_t* getVarPointer(SegManager *segMan) const;
};
enum {
VAR_GLOBAL = 0,
VAR_LOCAL = 1,
VAR_TEMP = 2,
VAR_PARAM = 3
};
/** Number of kernel calls in between gcs; should be < 50000 */
enum {
GC_INTERVAL = 32768
};
// Opcode formats
enum opcode_format {
Script_Invalid = -1,
Script_None = 0,
Script_Byte,
Script_SByte,
Script_Word,
Script_SWord,
Script_Variable,
Script_SVariable,
Script_SRelative,
Script_Property,
Script_Global,
Script_Local,
Script_Temp,
Script_Param,
Script_Offset,
Script_End
};
enum sci_opcodes {
op_bnot = 0x00, // 000
op_add = 0x01, // 001
op_sub = 0x02, // 002
op_mul = 0x03, // 003
op_div = 0x04, // 004
op_mod = 0x05, // 005
op_shr = 0x06, // 006
op_shl = 0x07, // 007
op_xor = 0x08, // 008
op_and = 0x09, // 009
op_or = 0x0a, // 010
op_neg = 0x0b, // 011
op_not = 0x0c, // 012
op_eq_ = 0x0d, // 013
op_ne_ = 0x0e, // 014
op_gt_ = 0x0f, // 015
op_ge_ = 0x10, // 016
op_lt_ = 0x11, // 017
op_le_ = 0x12, // 018
op_ugt_ = 0x13, // 019
op_uge_ = 0x14, // 020
op_ult_ = 0x15, // 021
op_ule_ = 0x16, // 022
op_bt = 0x17, // 023
op_bnt = 0x18, // 024
op_jmp = 0x19, // 025
op_ldi = 0x1a, // 026
op_push = 0x1b, // 027
op_pushi = 0x1c, // 028
op_toss = 0x1d, // 029
op_dup = 0x1e, // 030
op_link = 0x1f, // 031
op_call = 0x20, // 032
op_callk = 0x21, // 033
op_callb = 0x22, // 034
op_calle = 0x23, // 035
op_ret = 0x24, // 036
op_send = 0x25, // 037
// dummy 0x26, // 038
// dummy 0x27, // 039
op_class = 0x28, // 040
// dummy 0x29, // 041
op_self = 0x2a, // 042
op_super = 0x2b, // 043
op_rest = 0x2c, // 044
op_lea = 0x2d, // 045
op_selfID = 0x2e, // 046
// dummy 0x2f // 047
op_pprev = 0x30, // 048
op_pToa = 0x31, // 049
op_aTop = 0x32, // 050
op_pTos = 0x33, // 051
op_sTop = 0x34, // 052
op_ipToa = 0x35, // 053
op_dpToa = 0x36, // 054
op_ipTos = 0x37, // 055
op_dpTos = 0x38, // 056
op_lofsa = 0x39, // 057
op_lofss = 0x3a, // 058
op_push0 = 0x3b, // 059
op_push1 = 0x3c, // 060
op_push2 = 0x3d, // 061
op_pushSelf = 0x3e, // 062
op_line = 0x3f, // 063
op_lag = 0x40, // 064
op_lal = 0x41, // 065
op_lat = 0x42, // 066
op_lap = 0x43, // 067
op_lsg = 0x44, // 068
op_lsl = 0x45, // 069
op_lst = 0x46, // 070
op_lsp = 0x47, // 071
op_lagi = 0x48, // 072
op_lali = 0x49, // 073
op_lati = 0x4a, // 074
op_lapi = 0x4b, // 075
op_lsgi = 0x4c, // 076
op_lsli = 0x4d, // 077
op_lsti = 0x4e, // 078
op_lspi = 0x4f, // 079
op_sag = 0x50, // 080
op_sal = 0x51, // 081
op_sat = 0x52, // 082
op_sap = 0x53, // 083
op_ssg = 0x54, // 084
op_ssl = 0x55, // 085
op_sst = 0x56, // 086
op_ssp = 0x57, // 087
op_sagi = 0x58, // 088
op_sali = 0x59, // 089
op_sati = 0x5a, // 090
op_sapi = 0x5b, // 091
op_ssgi = 0x5c, // 092
op_ssli = 0x5d, // 093
op_ssti = 0x5e, // 094
op_sspi = 0x5f, // 095
op_plusag = 0x60, // 096
op_plusal = 0x61, // 097
op_plusat = 0x62, // 098
op_plusap = 0x63, // 099
op_plussg = 0x64, // 100
op_plussl = 0x65, // 101
op_plusst = 0x66, // 102
op_plussp = 0x67, // 103
op_plusagi = 0x68, // 104
op_plusali = 0x69, // 105
op_plusati = 0x6a, // 106
op_plusapi = 0x6b, // 107
op_plussgi = 0x6c, // 108
op_plussli = 0x6d, // 109
op_plussti = 0x6e, // 110
op_plusspi = 0x6f, // 111
op_minusag = 0x70, // 112
op_minusal = 0x71, // 113
op_minusat = 0x72, // 114
op_minusap = 0x73, // 115
op_minussg = 0x74, // 116
op_minussl = 0x75, // 117
op_minusst = 0x76, // 118
op_minussp = 0x77, // 119
op_minusagi = 0x78, // 120
op_minusali = 0x79, // 121
op_minusati = 0x7a, // 122
op_minusapi = 0x7b, // 123
op_minussgi = 0x7c, // 124
op_minussli = 0x7d, // 125
op_minussti = 0x7e, // 126
op_minusspi = 0x7f // 127
};
extern opcode_format g_opcode_formats[128][4];
void script_adjust_opcode_formats();
/**
* Executes function pubfunct of the specified script.
* @param[in] s The state which is to be executed with
* @param[in] script The script which is called
* @param[in] pubfunct The exported script function which is to
* be called
* @param[in] sp Stack pointer position
* @param[in] calling_obj The heap address of the object that
* executed the call
* @param[in] argc Number of arguments supplied
* @param[in] argp Pointer to the first supplied argument
* @return A pointer to the new exec stack TOS entry
*/
ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct,
StackPtr sp, reg_t calling_obj, uint16 argc, StackPtr argp);
/**
* Executes a "send" or related operation to a selector.
* @param[in] s The EngineState to operate on
* @param[in] send_obj Heap address of the object to send to
* @param[in] work_obj Heap address of the object initiating the send
* @param[in] sp Stack pointer position
* @param[in] framesize Size of the send as determined by the "send"
* operation
* @param[in] argp Pointer to the beginning of the heap block
* containing the data to be sent. This area is a
* succession of one or more sequences of
* [selector_number][argument_counter] and then
* "argument_counter" word entries with the
* parameter values.
* @return A pointer to the new execution stack TOS entry
*/
ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj,
StackPtr sp, int framesize, StackPtr argp);
/**
* This function executes SCI bytecode
* It executes the code on s->heap[pc] until it hits a 'ret' operation
* while (stack_base == stack_pos). Requires s to be set up correctly.
* @param[in] s The state to use
*/
void run_vm(EngineState *s);
/**
* Debugger functionality
* @param[in] s The state at which debugging should take place
*/
void script_debug(EngineState *s);
/**
* Looks up a selector and returns its type and value
* varindex is written to iff it is non-NULL and the selector indicates a property of the object.
* @param[in] segMan The Segment Manager
* @param[in] obj Address of the object to look the selector up in
* @param[in] selectorid The selector to look up
* @param[out] varp A reference to the selector, if it is a
* variable.
* @param[out] fptr A reference to the function described by that
* selector, if it is a valid function selector.
* fptr is written to iff it is non-NULL and the
* selector indicates a member function of that
* object.
* @return kSelectorNone if the selector was not found in
* the object or its superclasses.
* kSelectorVariable if the selector represents an
* object-relative variable.
* kSelectorMethod if the selector represents a
* method
*/
SelectorType lookupSelector(SegManager *segMan, reg_t obj, Selector selectorid,
ObjVarRef *varp, reg_t *fptr);
/**
* Read a PMachine instruction from a memory buffer and return its length.
*
* @param[in] src address from which to start parsing
* @param[out] extOpcode "extended" opcode of the parsed instruction
* @param[out] opparams parameter for the parsed instruction
* @return the length in bytes of the instruction
*
* @todo How about changing opparams from int16 to int / int32 to preserve
* unsigned 16bit words as read for Script_Word? In the past, this
* was irrelevant as only a debug opcode used Script_Word. But with
* SCI32 we are now using Script_Word for more opcodes. Maybe this is
* just a mistake and those opcodes should used Script_SWord -- but if
* not then we definitely should change this to int, else we might run
* into trouble if we encounter high value words. *If* those exist at all.
*/
int readPMachineInstruction(const byte *src, byte &extOpcode, int16 opparams[4]);
} // End of namespace Sci
#endif // SCI_ENGINE_VM_H