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