1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef SCI_ENGINE_VM_H 24 #define SCI_ENGINE_VM_H 25 26 /* VM and kernel declarations */ 27 28 #include "sci/engine/vm_types.h" // for reg_t 29 #include "sci/resource.h" // for SciVersion 30 31 #include "common/util.h" 32 33 namespace Sci { 34 35 class SegManager; 36 struct EngineState; 37 class Object; 38 class ResourceManager; 39 class Script; 40 41 /** Number of bytes to be allocated for the stack */ 42 #define VM_STACK_SIZE 0x1000 43 44 /** Magical object identifier */ 45 #define SCRIPT_OBJECT_MAGIC_NUMBER 0x1234 46 47 /** Offset of this identifier */ 48 #define SCRIPT_OBJECT_MAGIC_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? -8 : 0) 49 50 /** Stack pointer value: Use predecessor's value */ 51 #define CALL_SP_CARRY NULL 52 53 /** Types of selectors as returned by lookupSelector() below. */ 54 enum SelectorType { 55 kSelectorNone = 0, 56 kSelectorVariable, 57 kSelectorMethod 58 }; 59 60 struct Class { 61 int script; ///< number of the script the class is in, -1 for non-existing 62 reg_t reg; ///< offset; script-relative offset, segment: 0 if not instantiated 63 }; 64 65 // A reference to an object's variable. 66 // The object is stored as a reg_t, the variable as an index into _variables 67 struct ObjVarRef { 68 reg_t obj; 69 int varindex; 70 71 reg_t* getPointer(SegManager *segMan) const; 72 }; 73 74 enum ExecStackType { 75 EXEC_STACK_TYPE_CALL = 0, 76 EXEC_STACK_TYPE_KERNEL = 1, 77 EXEC_STACK_TYPE_VARSELECTOR = 2 78 }; 79 80 struct ExecStack { 81 reg_t objp; ///< Pointer to the beginning of the current object 82 reg_t sendp; ///< Pointer to the object containing the invoked method 83 84 union { 85 ObjVarRef varp; // Variable pointer for r/w access 86 reg_t pc; // Pointer to the initial program counter. Not accurate for the TOS element 87 } addr; 88 89 StackPtr fp; // Frame pointer 90 StackPtr sp; // Stack pointer 91 92 int argc; 93 StackPtr variables_argp; // Argument pointer 94 95 SegmentId local_segment; // local variables etc 96 97 Selector debugSelector; // The selector which was used to call or -1 if not applicable 98 int debugExportId; // The exportId which was called or -1 if not applicable 99 int debugLocalCallOffset; // Local call offset or -1 if not applicable 100 int debugOrigin; // The stack frame position the call was made from, or -1 if it was the initial call 101 int debugKernelFunction; // The kernel function called, or -1 if not applicable 102 int debugKernelSubFunction; // The kernel subfunction called, or -1 if not applicable 103 ExecStackType type; 104 105 reg_t* getVarPointer(SegManager *segMan) const; 106 ExecStackExecStack107 ExecStack(reg_t objp_, reg_t sendp_, StackPtr sp_, int argc_, StackPtr argp_, 108 SegmentId localsSegment_, reg_t pc_, Selector debugSelector_, 109 int debugKernelFunction_, int debugKernelSubFunction_, 110 int debugExportId_, int debugLocalCallOffset_, int debugOrigin_, 111 ExecStackType type_) { 112 objp = objp_; 113 sendp = sendp_; 114 // varp is set separately for varselector calls 115 addr.pc = pc_; 116 fp = sp = sp_; 117 argc = argc_; 118 variables_argp = argp_; 119 if (localsSegment_ != kUninitializedSegment) 120 local_segment = localsSegment_; 121 else 122 local_segment = pc_.getSegment(); 123 debugSelector = debugSelector_; 124 debugKernelFunction = debugKernelFunction_; 125 debugKernelSubFunction = debugKernelSubFunction_; 126 debugExportId = debugExportId_; 127 debugLocalCallOffset = debugLocalCallOffset_; 128 debugOrigin = debugOrigin_; 129 type = type_; 130 } 131 }; 132 133 enum { 134 VAR_GLOBAL = 0, 135 VAR_LOCAL = 1, 136 VAR_TEMP = 2, 137 VAR_PARAM = 3 138 }; 139 140 enum GlobalVar { 141 kGlobalVarEgo = 0, 142 kGlobalVarGame = 1, 143 kGlobalVarCurrentRoom = 2, 144 kGlobalVarSpeed = 3, // SCI16 145 kGlobalVarQuit = 4, 146 kGlobalVarSounds = 8, 147 kGlobalVarPlanes = 10, // SCI32 148 kGlobalVarCurrentRoomNo = 11, 149 kGlobalVarPreviousRoomNo = 12, 150 kGlobalVarNewRoomNo = 13, 151 kGlobalVarScore = 15, 152 kGlobalVarGK2MusicVolume = 76, // 0 to 127 153 kGlobalVarPhant2SecondaryVolume = 76, // 0 to 127 154 kGlobalVarFastCast = 84, // SCI16 155 kGlobalVarMessageType = 90, 156 kGlobalVarTextSpeed = 94, // SCI32; 0 is fastest, 8 is slowest 157 kGlobalVarGK1Music1 = 102, // 0 to 127 158 kGlobalVarGK1Music2 = 103, // 0 to 127 159 kGlobalVarRamaCatalogFile = 130, 160 kGlobalVarLSL6HiresGameFlags = 137, 161 kGlobalVarKQ7UpscaleVideos = 160, 162 kGlobalVarGK1NarratorMode = 166, // 0 for text, 1 for speech 163 kGlobalVarRamaMusicVolume = 176, // 0 to 16 164 kGlobalVarPhant1MusicVolume = 187, // 0 to 15 165 kGlobalVarPhant1DACVolume = 188, // 0 to 127 166 kGlobalVarLSL6HiresMusicVolume = 194, // 0 to 13 167 kGlobalVarGK1DAC1 = 207, // 0 to 127 168 kGlobalVarPhant2CensorshipFlag = 207, 169 kGlobalVarGK1DAC2 = 208, // 0 to 127 170 kGlobalVarLSL6HiresRestoreTextWindow = 210, 171 kGlobalVarGK1DAC3 = 211, // 0 to 127 172 kGlobalVarShiversFlags = 211, 173 kGlobalVarTorinMusicVolume = 227, // 0 to 100 174 kGlobalVarTorinSFXVolume = 228, // 0 to 100 175 kGlobalVarTorinSpeechVolume = 229, // 0 to 100 176 // Phant2 labels its volume slider as "music volume" but it is actually 177 // a master volume that affects both music *and* sound effects 178 kGlobalVarPhant2MasterVolume = 236, // 0 to 127 179 kGlobalVarPhant2ControlPanel = 250, 180 kGlobalVarShivers1Score = 349, 181 kGlobalVarQFG4Flags = 500, 182 kGlobalVarHoyle5MusicVolume = 897, 183 kGlobalVarHoyle5ResponseTime = 899 184 }; 185 186 /** Number of kernel calls in between gcs; should be < 50000 */ 187 enum { 188 GC_INTERVAL = 0x8000 189 }; 190 191 enum SciOpcodes { 192 op_bnot = 0x00, // 000 193 op_add = 0x01, // 001 194 op_sub = 0x02, // 002 195 op_mul = 0x03, // 003 196 op_div = 0x04, // 004 197 op_mod = 0x05, // 005 198 op_shr = 0x06, // 006 199 op_shl = 0x07, // 007 200 op_xor = 0x08, // 008 201 op_and = 0x09, // 009 202 op_or = 0x0a, // 010 203 op_neg = 0x0b, // 011 204 op_not = 0x0c, // 012 205 op_eq_ = 0x0d, // 013 206 op_ne_ = 0x0e, // 014 207 op_gt_ = 0x0f, // 015 208 op_ge_ = 0x10, // 016 209 op_lt_ = 0x11, // 017 210 op_le_ = 0x12, // 018 211 op_ugt_ = 0x13, // 019 212 op_uge_ = 0x14, // 020 213 op_ult_ = 0x15, // 021 214 op_ule_ = 0x16, // 022 215 op_bt = 0x17, // 023 216 op_bnt = 0x18, // 024 217 op_jmp = 0x19, // 025 218 op_ldi = 0x1a, // 026 219 op_push = 0x1b, // 027 220 op_pushi = 0x1c, // 028 221 op_toss = 0x1d, // 029 222 op_dup = 0x1e, // 030 223 op_link = 0x1f, // 031 224 op_call = 0x20, // 032 225 op_callk = 0x21, // 033 226 op_callb = 0x22, // 034 227 op_calle = 0x23, // 035 228 op_ret = 0x24, // 036 229 op_send = 0x25, // 037 230 op_info = 0x26, // 038 231 op_superP = 0x27, // 039 232 op_class = 0x28, // 040 233 // dummy 0x29, // 041 234 op_self = 0x2a, // 042 235 op_super = 0x2b, // 043 236 op_rest = 0x2c, // 044 237 op_lea = 0x2d, // 045 238 op_selfID = 0x2e, // 046 239 // dummy 0x2f // 047 240 op_pprev = 0x30, // 048 241 op_pToa = 0x31, // 049 242 op_aTop = 0x32, // 050 243 op_pTos = 0x33, // 051 244 op_sTop = 0x34, // 052 245 op_ipToa = 0x35, // 053 246 op_dpToa = 0x36, // 054 247 op_ipTos = 0x37, // 055 248 op_dpTos = 0x38, // 056 249 op_lofsa = 0x39, // 057 250 op_lofss = 0x3a, // 058 251 op_push0 = 0x3b, // 059 252 op_push1 = 0x3c, // 060 253 op_push2 = 0x3d, // 061 254 op_pushSelf = 0x3e, // 062 255 op_line = 0x3f, // 063 256 // 257 op_lag = 0x40, // 064 258 op_lal = 0x41, // 065 259 op_lat = 0x42, // 066 260 op_lap = 0x43, // 067 261 op_lsg = 0x44, // 068 262 op_lsl = 0x45, // 069 263 op_lst = 0x46, // 070 264 op_lsp = 0x47, // 071 265 op_lagi = 0x48, // 072 266 op_lali = 0x49, // 073 267 op_lati = 0x4a, // 074 268 op_lapi = 0x4b, // 075 269 op_lsgi = 0x4c, // 076 270 op_lsli = 0x4d, // 077 271 op_lsti = 0x4e, // 078 272 op_lspi = 0x4f, // 079 273 // 274 op_sag = 0x50, // 080 275 op_sal = 0x51, // 081 276 op_sat = 0x52, // 082 277 op_sap = 0x53, // 083 278 op_ssg = 0x54, // 084 279 op_ssl = 0x55, // 085 280 op_sst = 0x56, // 086 281 op_ssp = 0x57, // 087 282 op_sagi = 0x58, // 088 283 op_sali = 0x59, // 089 284 op_sati = 0x5a, // 090 285 op_sapi = 0x5b, // 091 286 op_ssgi = 0x5c, // 092 287 op_ssli = 0x5d, // 093 288 op_ssti = 0x5e, // 094 289 op_sspi = 0x5f, // 095 290 // 291 op_plusag = 0x60, // 096 292 op_plusal = 0x61, // 097 293 op_plusat = 0x62, // 098 294 op_plusap = 0x63, // 099 295 op_plussg = 0x64, // 100 296 op_plussl = 0x65, // 101 297 op_plusst = 0x66, // 102 298 op_plussp = 0x67, // 103 299 op_plusagi = 0x68, // 104 300 op_plusali = 0x69, // 105 301 op_plusati = 0x6a, // 106 302 op_plusapi = 0x6b, // 107 303 op_plussgi = 0x6c, // 108 304 op_plussli = 0x6d, // 109 305 op_plussti = 0x6e, // 110 306 op_plusspi = 0x6f, // 111 307 // 308 op_minusag = 0x70, // 112 309 op_minusal = 0x71, // 113 310 op_minusat = 0x72, // 114 311 op_minusap = 0x73, // 115 312 op_minussg = 0x74, // 116 313 op_minussl = 0x75, // 117 314 op_minusst = 0x76, // 118 315 op_minussp = 0x77, // 119 316 op_minusagi = 0x78, // 120 317 op_minusali = 0x79, // 121 318 op_minusati = 0x7a, // 122 319 op_minusapi = 0x7b, // 123 320 op_minussgi = 0x7c, // 124 321 op_minussli = 0x7d, // 125 322 op_minussti = 0x7e, // 126 323 op_minusspi = 0x7f // 127 324 }; 325 326 void script_adjust_opcode_formats(); 327 328 /** 329 * Executes function pubfunct of the specified script. 330 * @param[in] s The state which is to be executed with 331 * @param[in] script The script which is called 332 * @param[in] pubfunct The exported script function which is to 333 * be called 334 * @param[in] sp Stack pointer position 335 * @param[in] calling_obj The heap address of the object that 336 * executed the call 337 * @param[in] argc Number of arguments supplied 338 * @param[in] argp Pointer to the first supplied argument 339 * @return A pointer to the new exec stack TOS entry 340 */ 341 ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, 342 StackPtr sp, reg_t calling_obj, uint16 argc, StackPtr argp); 343 344 345 /** 346 * Executes a "send" or related operation to a selector. 347 * @param[in] s The EngineState to operate on 348 * @param[in] send_obj Heap address of the object to send to 349 * @param[in] work_obj Heap address of the object initiating the send 350 * @param[in] sp Stack pointer position 351 * @param[in] framesize Size of the send as determined by the "send" 352 * operation 353 * @param[in] argp Pointer to the beginning of the heap block 354 * containing the data to be sent. This area is a 355 * succession of one or more sequences of 356 * [selector_number][argument_counter] and then 357 * "argument_counter" word entries with the 358 * parameter values. 359 * @return A pointer to the new execution stack TOS entry 360 */ 361 ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, 362 StackPtr sp, int framesize, StackPtr argp); 363 364 365 /** 366 * This function executes SCI bytecode 367 * It executes the code on s->heap[pc] until it hits a 'ret' operation 368 * while (stack_base == stack_pos). Requires s to be set up correctly. 369 * @param[in] s The state to use 370 */ 371 void run_vm(EngineState *s); 372 373 /** 374 * Debugger functionality 375 * @param[in] s The state at which debugging should take place 376 */ 377 void script_debug(EngineState *s); 378 379 /** 380 * Looks up a selector and returns its type and value 381 * varindex is written to iff it is non-NULL and the selector indicates a property of the object. 382 * @param[in] segMan The Segment Manager 383 * @param[in] obj Address of the object to look the selector up in 384 * @param[in] selectorid The selector to look up 385 * @param[out] varp A reference to the selector, if it is a 386 * variable. 387 * @param[out] fptr A reference to the function described by that 388 * selector, if it is a valid function selector. 389 * fptr is written to iff it is non-NULL and the 390 * selector indicates a member function of that 391 * object. 392 * @return kSelectorNone if the selector was not found in 393 * the object or its superclasses. 394 * kSelectorVariable if the selector represents an 395 * object-relative variable. 396 * kSelectorMethod if the selector represents a 397 * method 398 */ 399 SelectorType lookupSelector(SegManager *segMan, reg_t obj, Selector selectorid, 400 ObjVarRef *varp, reg_t *fptr); 401 402 /** 403 * Read a PMachine instruction from a memory buffer and return its length. 404 * 405 * @param[in] src address from which to start parsing 406 * @param[out] extOpcode "extended" opcode of the parsed instruction 407 * @param[out] opparams parameter for the parsed instruction 408 * @return the length in bytes of the instruction 409 * 410 * @todo How about changing opparams from int16 to int / int32 to preserve 411 * unsigned 16bit words as read for Script_Word? In the past, this 412 * was irrelevant as only a debug opcode used Script_Word. But with 413 * SCI32 we are now using Script_Word for more opcodes. Maybe this is 414 * just a mistake and those opcodes should used Script_SWord -- but if 415 * not then we definitely should change this to int, else we might run 416 * into trouble if we encounter high value words. *If* those exist at all. 417 */ 418 int readPMachineInstruction(const byte *src, byte &extOpcode, int16 opparams[4]); 419 420 /** 421 * Finds the script-absolute offset of a relative object offset. 422 * 423 * @param[in] relOffset the relative object offset 424 * @param[in] scr the owner script object, used by SCI1.1+ 425 * @param[in] pcOffset the offset of the program counter, used by SCI0early and 426 * SCI3 427 */ 428 uint32 findOffset(const int16 relOffset, const Script *scr, const uint32 pcOffset); 429 430 } // End of namespace Sci 431 432 #endif // SCI_ENGINE_VM_H 433