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 #include "glk/glulx/glulx.h"
24 
25 namespace Glk {
26 namespace Glulx {
27 
execute_loop()28 void Glulx::execute_loop() {
29 	bool done_executing = false;
30 	int ix;
31 	uint opcode;
32 	const operandlist_t *oplist;
33 	oparg_t inst[MAX_OPERANDS];
34 	uint value, addr, val0, val1;
35 	int vals0, vals1;
36 	uint *arglist;
37 	uint arglistfix[3];
38 #ifdef FLOAT_SUPPORT
39 	gfloat32 valf, valf1, valf2;
40 #endif /* FLOAT_SUPPORT */
41 
42 	while (!done_executing && !g_vm->shouldQuit()) {
43 
44 		profile_tick();
45 		debugger_tick();
46 		/* Do OS-specific processing, if appropriate. */
47 		glk_tick();
48 
49 		/* Stash the current opcode's address, in case the interpreter needs to serialize the VM state out-of-band. */
50 		prevpc = pc;
51 
52 		/* Fetch the opcode number. */
53 		opcode = Mem1(pc);
54 		pc++;
55 		if (opcode & 0x80) {
56 			/* More than one-byte opcode. */
57 			if (opcode & 0x40) {
58 				/* Four-byte opcode */
59 				opcode &= 0x3F;
60 				opcode = (opcode << 8) | Mem1(pc);
61 				pc++;
62 				opcode = (opcode << 8) | Mem1(pc);
63 				pc++;
64 				opcode = (opcode << 8) | Mem1(pc);
65 				pc++;
66 			} else {
67 				/* Two-byte opcode */
68 				opcode &= 0x7F;
69 				opcode = (opcode << 8) | Mem1(pc);
70 				pc++;
71 			}
72 		}
73 
74 		/* Now we have an opcode number. */
75 
76 		/* Fetch the structure that describes how the operands for this
77 		   opcode are arranged. This is a pointer to an immutable,
78 		   static object. */
79 		if (opcode < 0x80)
80 			oplist = fast_operandlist[opcode];
81 		else
82 			oplist = lookup_operandlist(opcode);
83 
84 		if (!oplist)
85 			fatal_error_i("Encountered unknown opcode.", opcode);
86 
87 		/* Based on the oplist structure, load the actual operand values
88 		   into inst. This moves the PC up to the end of the instruction. */
89 		parse_operands(inst, oplist);
90 
91 		/* Perform the opcode. This switch statement is split in two, based
92 		   on some paranoid suspicions about the ability of compilers to
93 		   optimize large-range switches. Ignore that. */
94 
95 		if (opcode < 0x80) {
96 
97 			switch (opcode) {
98 
99 			case op_nop:
100 				break;
101 
102 			case op_add:
103 				value = inst[0].value + inst[1].value;
104 				store_operand(inst[2].desttype, inst[2].value, value);
105 				break;
106 			case op_sub:
107 				value = inst[0].value - inst[1].value;
108 				store_operand(inst[2].desttype, inst[2].value, value);
109 				break;
110 			case op_mul:
111 				value = inst[0].value * inst[1].value;
112 				store_operand(inst[2].desttype, inst[2].value, value);
113 				break;
114 			case op_div:
115 				vals0 = inst[0].value;
116 				vals1 = inst[1].value;
117 				if (vals1 == 0)
118 					fatal_error("Division by zero.");
119 				/* Since C doesn't guarantee the results of division of negative
120 				   numbers, we carefully convert everything to positive values
121 				   first. They have to be unsigned values, too, otherwise the
122 				   0x80000000 case goes wonky. */
123 				if (vals0 < 0) {
124 					val0 = (-vals0);
125 					if (vals1 < 0) {
126 						val1 = (-vals1);
127 						value = val0 / val1;
128 					} else {
129 						val1 = vals1;
130 						value = -(int)(val0 / val1);
131 					}
132 				} else {
133 					val0 = vals0;
134 					if (vals1 < 0) {
135 						val1 = (-vals1);
136 						value = -(int)(val0 / val1);
137 					} else {
138 						val1 = vals1;
139 						value = val0 / val1;
140 					}
141 				}
142 				store_operand(inst[2].desttype, inst[2].value, value);
143 				break;
144 			case op_mod:
145 				vals0 = inst[0].value;
146 				vals1 = inst[1].value;
147 				if (vals1 == 0)
148 					fatal_error("Division by zero doing remainder.");
149 				if (vals1 < 0) {
150 					val1 = -vals1;
151 				} else {
152 					val1 = vals1;
153 				}
154 				if (vals0 < 0) {
155 					val0 = (-vals0);
156 					value = -(int)(val0 % val1);
157 				} else {
158 					val0 = vals0;
159 					value = val0 % val1;
160 				}
161 				store_operand(inst[2].desttype, inst[2].value, value);
162 				break;
163 			case op_neg:
164 				vals0 = inst[0].value;
165 				value = (-vals0);
166 				store_operand(inst[1].desttype, inst[1].value, value);
167 				break;
168 
169 			case op_bitand:
170 				value = (inst[0].value & inst[1].value);
171 				store_operand(inst[2].desttype, inst[2].value, value);
172 				break;
173 			case op_bitor:
174 				value = (inst[0].value | inst[1].value);
175 				store_operand(inst[2].desttype, inst[2].value, value);
176 				break;
177 			case op_bitxor:
178 				value = (inst[0].value ^ inst[1].value);
179 				store_operand(inst[2].desttype, inst[2].value, value);
180 				break;
181 			case op_bitnot:
182 				value = ~(inst[0].value);
183 				store_operand(inst[1].desttype, inst[1].value, value);
184 				break;
185 
186 			case op_shiftl:
187 				vals0 = inst[1].value;
188 				if (vals0 < 0 || vals0 >= 32)
189 					value = 0;
190 				else
191 					value = ((uint)(inst[0].value) << (uint)vals0);
192 				store_operand(inst[2].desttype, inst[2].value, value);
193 				break;
194 			case op_ushiftr:
195 				vals0 = inst[1].value;
196 				if (vals0 < 0 || vals0 >= 32)
197 					value = 0;
198 				else
199 					value = ((uint)(inst[0].value) >> (uint)vals0);
200 				store_operand(inst[2].desttype, inst[2].value, value);
201 				break;
202 			case op_sshiftr:
203 				vals0 = inst[1].value;
204 				if (vals0 < 0 || vals0 >= 32) {
205 					if (inst[0].value & 0x80000000)
206 						value = 0xFFFFFFFF;
207 					else
208 						value = 0;
209 				} else {
210 					/* This is somewhat foolhardy -- C doesn't guarantee that
211 					   right-shifting a signed value replicates the sign bit.
212 					   We'll assume it for now. */
213 					value = ((int)(inst[0].value) >> (int)vals0);
214 				}
215 				store_operand(inst[2].desttype, inst[2].value, value);
216 				break;
217 
218 			case op_jump:
219 				value = inst[0].value;
220 				/* fall through to PerformJump label. */
221 
222 PerformJump: /* goto label for successful jumping... ironic, no? */
223 				if (value == 0 || value == 1) {
224 					/* Return from function. This is exactly what happens in
225 					   return_op, but it's only a few lines of code, so I won't
226 					   bother with a "goto". */
227 					leave_function();
228 					if (stackptr == 0) {
229 						done_executing = true;
230 						break;
231 					}
232 					pop_callstub(value); /* zero or one */
233 				} else {
234 					/* Branch to a new PC value. */
235 					pc = (pc + value - 2);
236 				}
237 				break;
238 
239 			case op_jz:
240 				if (inst[0].value == 0) {
241 					value = inst[1].value;
242 					goto PerformJump;
243 				}
244 				break;
245 			case op_jnz:
246 				if (inst[0].value != 0) {
247 					value = inst[1].value;
248 					goto PerformJump;
249 				}
250 				break;
251 			case op_jeq:
252 				if (inst[0].value == inst[1].value) {
253 					value = inst[2].value;
254 					goto PerformJump;
255 				}
256 				break;
257 			case op_jne:
258 				if (inst[0].value != inst[1].value) {
259 					value = inst[2].value;
260 					goto PerformJump;
261 				}
262 				break;
263 			case op_jlt:
264 				vals0 = inst[0].value;
265 				vals1 = inst[1].value;
266 				if (vals0 < vals1) {
267 					value = inst[2].value;
268 					goto PerformJump;
269 				}
270 				break;
271 			case op_jgt:
272 				vals0 = inst[0].value;
273 				vals1 = inst[1].value;
274 				if (vals0 > vals1) {
275 					value = inst[2].value;
276 					goto PerformJump;
277 				}
278 				break;
279 			case op_jle:
280 				vals0 = inst[0].value;
281 				vals1 = inst[1].value;
282 				if (vals0 <= vals1) {
283 					value = inst[2].value;
284 					goto PerformJump;
285 				}
286 				break;
287 			case op_jge:
288 				vals0 = inst[0].value;
289 				vals1 = inst[1].value;
290 				if (vals0 >= vals1) {
291 					value = inst[2].value;
292 					goto PerformJump;
293 				}
294 				break;
295 			case op_jltu:
296 				val0 = inst[0].value;
297 				val1 = inst[1].value;
298 				if (val0 < val1) {
299 					value = inst[2].value;
300 					goto PerformJump;
301 				}
302 				break;
303 			case op_jgtu:
304 				val0 = inst[0].value;
305 				val1 = inst[1].value;
306 				if (val0 > val1) {
307 					value = inst[2].value;
308 					goto PerformJump;
309 				}
310 				break;
311 			case op_jleu:
312 				val0 = inst[0].value;
313 				val1 = inst[1].value;
314 				if (val0 <= val1) {
315 					value = inst[2].value;
316 					goto PerformJump;
317 				}
318 				break;
319 			case op_jgeu:
320 				val0 = inst[0].value;
321 				val1 = inst[1].value;
322 				if (val0 >= val1) {
323 					value = inst[2].value;
324 					goto PerformJump;
325 				}
326 				break;
327 
328 			case op_call:
329 				value = inst[1].value;
330 				arglist = pop_arguments(value, 0);
331 				push_callstub(inst[2].desttype, inst[2].value);
332 				enter_function(inst[0].value, value, arglist);
333 				break;
334 			case op_return:
335 				leave_function();
336 				if (stackptr == 0) {
337 					done_executing = true;
338 					break;
339 				}
340 				pop_callstub(inst[0].value);
341 				break;
342 			case op_tailcall:
343 				value = inst[1].value;
344 				arglist = pop_arguments(value, 0);
345 				leave_function();
346 				enter_function(inst[0].value, value, arglist);
347 				break;
348 
349 			case op_catch:
350 				push_callstub(inst[0].desttype, inst[0].value);
351 				value = inst[1].value;
352 				val0 = stackptr;
353 				store_operand(inst[0].desttype, inst[0].value, val0);
354 				goto PerformJump;
355 				break;
356 			case op_throw:
357 				profile_fail("throw");
358 				value = inst[0].value;
359 				stackptr = inst[1].value;
360 				pop_callstub(value);
361 				break;
362 
363 			case op_copy:
364 				value = inst[0].value;
365 #ifdef TOLERATE_SUPERGLUS_BUG
366 				if (inst[1].desttype == 1 && inst[1].value == 0)
367 					inst[1].desttype = 0;
368 #endif /* TOLERATE_SUPERGLUS_BUG */
369 				store_operand(inst[1].desttype, inst[1].value, value);
370 				break;
371 			case op_copys:
372 				value = inst[0].value;
373 				store_operand_s(inst[1].desttype, inst[1].value, value);
374 				break;
375 			case op_copyb:
376 				value = inst[0].value;
377 				store_operand_b(inst[1].desttype, inst[1].value, value);
378 				break;
379 
380 			case op_sexs:
381 				val0 = inst[0].value;
382 				if (val0 & 0x8000)
383 					val0 |= 0xFFFF0000;
384 				else
385 					val0 &= 0x0000FFFF;
386 				store_operand(inst[1].desttype, inst[1].value, val0);
387 				break;
388 			case op_sexb:
389 				val0 = inst[0].value;
390 				if (val0 & 0x80)
391 					val0 |= 0xFFFFFF00;
392 				else
393 					val0 &= 0x000000FF;
394 				store_operand(inst[1].desttype, inst[1].value, val0);
395 				break;
396 
397 			case op_aload:
398 				value = inst[0].value;
399 				value += 4 * inst[1].value;
400 				val0 = Mem4(value);
401 				store_operand(inst[2].desttype, inst[2].value, val0);
402 				break;
403 			case op_aloads:
404 				value = inst[0].value;
405 				value += 2 * inst[1].value;
406 				val0 = Mem2(value);
407 				store_operand(inst[2].desttype, inst[2].value, val0);
408 				break;
409 			case op_aloadb:
410 				value = inst[0].value;
411 				value += inst[1].value;
412 				val0 = Mem1(value);
413 				store_operand(inst[2].desttype, inst[2].value, val0);
414 				break;
415 			case op_aloadbit:
416 				value = inst[0].value;
417 				vals0 = inst[1].value;
418 				val1 = (vals0 & 7);
419 				if (vals0 >= 0)
420 					value += (vals0 >> 3);
421 				else
422 					value -= (1 + ((-1 - vals0) >> 3));
423 				if (Mem1(value) & (1 << val1))
424 					val0 = 1;
425 				else
426 					val0 = 0;
427 				store_operand(inst[2].desttype, inst[2].value, val0);
428 				break;
429 
430 			case op_astore:
431 				value = inst[0].value;
432 				value += 4 * inst[1].value;
433 				val0 = inst[2].value;
434 				MemW4(value, val0);
435 				break;
436 			case op_astores:
437 				value = inst[0].value;
438 				value += 2 * inst[1].value;
439 				val0 = inst[2].value;
440 				MemW2(value, val0);
441 				break;
442 			case op_astoreb:
443 				value = inst[0].value;
444 				value += inst[1].value;
445 				val0 = inst[2].value;
446 				MemW1(value, val0);
447 				break;
448 			case op_astorebit:
449 				value = inst[0].value;
450 				vals0 = inst[1].value;
451 				val1 = (vals0 & 7);
452 				if (vals0 >= 0)
453 					value += (vals0 >> 3);
454 				else
455 					value -= (1 + ((-1 - vals0) >> 3));
456 				val0 = Mem1(value);
457 				if (inst[2].value)
458 					val0 |= (1 << val1);
459 				else
460 					val0 &= ~((uint)(1 << val1));
461 				MemW1(value, val0);
462 				break;
463 
464 			case op_stkcount:
465 				value = (stackptr - valstackbase) / 4;
466 				store_operand(inst[0].desttype, inst[0].value, value);
467 				break;
468 			case op_stkpeek:
469 				vals0 = inst[0].value * 4;
470 				if (vals0 < 0 || vals0 >= (int)(stackptr - valstackbase))
471 					fatal_error("Stkpeek outside current stack range.");
472 				value = Stk4(stackptr - (vals0 + 4));
473 				store_operand(inst[1].desttype, inst[1].value, value);
474 				break;
475 			case op_stkswap:
476 				if (stackptr < valstackbase + 8) {
477 					fatal_error("Stack underflow in stkswap.");
478 				}
479 				val0 = Stk4(stackptr - 4);
480 				val1 = Stk4(stackptr - 8);
481 				StkW4(stackptr - 4, val1);
482 				StkW4(stackptr - 8, val0);
483 				break;
484 			case op_stkcopy:
485 				vals0 = inst[0].value;
486 				if (vals0 < 0)
487 					fatal_error("Negative operand in stkcopy.");
488 				if (vals0 == 0)
489 					break;
490 				if (stackptr < valstackbase + vals0 * 4)
491 					fatal_error("Stack underflow in stkcopy.");
492 				if (stackptr + vals0 * 4 > stacksize)
493 					fatal_error("Stack overflow in stkcopy.");
494 				addr = stackptr - vals0 * 4;
495 				for (ix = 0; ix < vals0; ix++) {
496 					value = Stk4(addr + ix * 4);
497 					StkW4(stackptr + ix * 4, value);
498 				}
499 				stackptr += vals0 * 4;
500 				break;
501 			case op_stkroll:
502 				vals0 = inst[0].value;
503 				vals1 = inst[1].value;
504 				if (vals0 < 0)
505 					fatal_error("Negative operand in stkroll.");
506 				if (stackptr < valstackbase + vals0 * 4)
507 					fatal_error("Stack underflow in stkroll.");
508 				if (vals0 == 0)
509 					break;
510 				/* The following is a bit ugly. We want to do vals1 = vals0-vals1,
511 				   because rolling down is sort of easier than rolling up. But
512 				   we also want to take the result mod vals0. The % operator is
513 				   annoying for negative numbers, so we need to do this in two
514 				   cases. */
515 				if (vals1 > 0) {
516 					vals1 = vals1 % vals0;
517 					vals1 = (vals0) - vals1;
518 				} else {
519 					vals1 = (-vals1) % vals0;
520 				}
521 				if (vals1 == 0)
522 					break;
523 				addr = stackptr - vals0 * 4;
524 				for (ix = 0; ix < vals1; ix++) {
525 					value = Stk4(addr + ix * 4);
526 					StkW4(stackptr + ix * 4, value);
527 				}
528 				for (ix = 0; ix < vals0; ix++) {
529 					value = Stk4(addr + (vals1 + ix) * 4);
530 					StkW4(addr + ix * 4, value);
531 				}
532 				break;
533 
534 			case op_streamchar:
535 				profile_in(0xE0000001, stackptr, false);
536 				value = inst[0].value & 0xFF;
537 				(this->*stream_char_handler)(value);
538 				profile_out(stackptr);
539 				break;
540 			case op_streamunichar:
541 				profile_in(0xE0000002, stackptr, false);
542 				value = inst[0].value;
543 				(this->*stream_unichar_handler)(value);
544 				profile_out(stackptr);
545 				break;
546 			case op_streamnum:
547 				profile_in(0xE0000003, stackptr, false);
548 				vals0 = inst[0].value;
549 				stream_num(vals0, false, 0);
550 				profile_out(stackptr);
551 				break;
552 			case op_streamstr:
553 				profile_in(0xE0000004, stackptr, false);
554 				stream_string(inst[0].value, 0, 0);
555 				profile_out(stackptr);
556 				break;
557 
558 			default:
559 				fatal_error_i("Executed unknown opcode.", opcode);
560 			}
561 		} else {
562 
563 			switch (opcode) {
564 
565 			case op_gestalt:
566 				value = do_gestalt(inst[0].value, inst[1].value);
567 				store_operand(inst[2].desttype, inst[2].value, value);
568 				break;
569 
570 			case op_debugtrap:
571 #if VM_DEBUGGER
572 				/* We block and handle debug commands, but only if the
573 				   library has invoked debug features. (Meaning, has
574 				   the cycle handler ever been called.) */
575 				if (debugger_ever_invoked()) {
576 					debugger_block_and_debug("user debugtrap, pausing...");
577 					break;
578 				}
579 #endif /* VM_DEBUGGER */
580 				fatal_error_i("user debugtrap encountered.", inst[0].value);
581 				break;
582 
583 			case op_jumpabs:
584 				pc = inst[0].value;
585 				break;
586 
587 			case op_callf:
588 				push_callstub(inst[1].desttype, inst[1].value);
589 				enter_function(inst[0].value, 0, arglistfix);
590 				break;
591 			case op_callfi:
592 				arglistfix[0] = inst[1].value;
593 				push_callstub(inst[2].desttype, inst[2].value);
594 				enter_function(inst[0].value, 1, arglistfix);
595 				break;
596 			case op_callfii:
597 				arglistfix[0] = inst[1].value;
598 				arglistfix[1] = inst[2].value;
599 				push_callstub(inst[3].desttype, inst[3].value);
600 				enter_function(inst[0].value, 2, arglistfix);
601 				break;
602 			case op_callfiii:
603 				arglistfix[0] = inst[1].value;
604 				arglistfix[1] = inst[2].value;
605 				arglistfix[2] = inst[3].value;
606 				push_callstub(inst[4].desttype, inst[4].value);
607 				enter_function(inst[0].value, 3, arglistfix);
608 				break;
609 
610 			case op_getmemsize:
611 				store_operand(inst[0].desttype, inst[0].value, endmem);
612 				break;
613 			case op_setmemsize:
614 				value = change_memsize(inst[0].value, false);
615 				store_operand(inst[1].desttype, inst[1].value, value);
616 				break;
617 
618 			case op_getstringtbl:
619 				value = stream_get_table();
620 				store_operand(inst[0].desttype, inst[0].value, value);
621 				break;
622 			case op_setstringtbl:
623 				stream_set_table(inst[0].value);
624 				break;
625 
626 			case op_getiosys:
627 				stream_get_iosys(&val0, &val1);
628 				store_operand(inst[0].desttype, inst[0].value, val0);
629 				store_operand(inst[1].desttype, inst[1].value, val1);
630 				break;
631 			case op_setiosys:
632 				stream_set_iosys(inst[0].value, inst[1].value);
633 				break;
634 
635 			case op_glk:
636 				profile_in(0xF0000000 + inst[0].value, stackptr, false);
637 				value = inst[1].value;
638 				arglist = pop_arguments(value, 0);
639 				val0 = perform_glk(inst[0].value, value, arglist);
640 #ifdef TOLERATE_SUPERGLUS_BUG
641 				if (inst[2].desttype == 1 && inst[2].value == 0)
642 					inst[2].desttype = 0;
643 #endif /* TOLERATE_SUPERGLUS_BUG */
644 				store_operand(inst[2].desttype, inst[2].value, val0);
645 				profile_out(stackptr);
646 				break;
647 
648 			case op_random:
649 				vals0 = inst[0].value;
650 				if (vals0 == 0)
651 					value = glulx_random();
652 				else if (vals0 >= 1)
653 					value = glulx_random() % (uint)(vals0);
654 				else
655 					value = -(int)(glulx_random() % (uint)(-vals0));
656 				store_operand(inst[1].desttype, inst[1].value, value);
657 				break;
658 			case op_setrandom:
659 				glulx_setrandom(inst[0].value);
660 				break;
661 
662 			case op_verify:
663 				value = perform_verify();
664 				store_operand(inst[0].desttype, inst[0].value, value);
665 				break;
666 
667 			case op_restart:
668 				profile_fail("restart");
669 				vm_restart();
670 				break;
671 
672 			case op_protect:
673 				val0 = inst[0].value;
674 				val1 = val0 + inst[1].value;
675 				if (val0 == val1) {
676 					val0 = 0;
677 					val1 = 0;
678 				}
679 				protectstart = val0;
680 				protectend = val1;
681 				break;
682 
683 			case op_save: {
684 				push_callstub(inst[1].desttype, inst[1].value);
685 				strid_t saveStream = find_stream_by_id(inst[0].value);
686 				value = writeGameData(*saveStream).getCode() == Common::kNoError ? 0 : 1;
687 				pop_callstub(value);
688 				break;
689 			}
690 
691 			case op_restore: {
692 				strid_t stream = find_stream_by_id(inst[0].value);
693 				value = readSaveData(*stream).getCode() == Common::kNoError ? 0 : 1;
694 
695 				if (value == 0) {
696 					/* We've succeeded, and the stack now contains the callstub
697 					   saved during saveundo. Ignore this opcode's operand. */
698 					value = (uint)-1;
699 					pop_callstub(value);
700 				} else {
701 					/* We've failed, so we must store the failure in this opcode's
702 		 			   operand. */
703 					store_operand(inst[1].desttype, inst[1].value, value);
704 				}
705 				break;
706 			}
707 
708 			case op_saveundo:
709 				push_callstub(inst[0].desttype, inst[0].value);
710 				value = perform_saveundo();
711 				pop_callstub(value);
712 				break;
713 
714 			case op_restoreundo:
715 				value = perform_restoreundo();
716 				if (value == 0) {
717 					/* We've succeeded, and the stack now contains the callstub
718 					   saved during saveundo. Ignore this opcode's operand. */
719 					value = (uint) - 1;
720 					pop_callstub(value);
721 				} else {
722 					/* We've failed, so we must store the failure in this opcode's
723 					   operand. */
724 					store_operand(inst[0].desttype, inst[0].value, value);
725 				}
726 				break;
727 
728 			case op_quit:
729 				done_executing = true;
730 				break;
731 
732 			case op_linearsearch:
733 				value = linear_search(inst[0].value, inst[1].value, inst[2].value,
734 				                      inst[3].value, inst[4].value, inst[5].value, inst[6].value);
735 				store_operand(inst[7].desttype, inst[7].value, value);
736 				break;
737 			case op_binarysearch:
738 				value = binary_search(inst[0].value, inst[1].value, inst[2].value,
739 				                      inst[3].value, inst[4].value, inst[5].value, inst[6].value);
740 				store_operand(inst[7].desttype, inst[7].value, value);
741 				break;
742 			case op_linkedsearch:
743 				value = linked_search(inst[0].value, inst[1].value, inst[2].value,
744 				                      inst[3].value, inst[4].value, inst[5].value);
745 				store_operand(inst[6].desttype, inst[6].value, value);
746 				break;
747 
748 			case op_mzero: {
749 				uint lx;
750 				uint count = inst[0].value;
751 				addr = inst[1].value;
752 				for (lx = 0; lx < count; lx++, addr++) {
753 					MemW1(addr, 0);
754 				}
755 			}
756 			break;
757 			case op_mcopy: {
758 				uint lx;
759 				uint count = inst[0].value;
760 				uint addrsrc = inst[1].value;
761 				uint addrdest = inst[2].value;
762 				if (addrdest < addrsrc) {
763 					for (lx = 0; lx < count; lx++, addrsrc++, addrdest++) {
764 						value = Mem1(addrsrc);
765 						MemW1(addrdest, value);
766 					}
767 				} else {
768 					addrsrc += (count - 1);
769 					addrdest += (count - 1);
770 					for (lx = 0; lx < count; lx++, addrsrc--, addrdest--) {
771 						value = Mem1(addrsrc);
772 						MemW1(addrdest, value);
773 					}
774 				}
775 			}
776 			break;
777 			case op_malloc:
778 				value = heap_alloc(inst[0].value);
779 				store_operand(inst[1].desttype, inst[1].value, value);
780 				break;
781 			case op_mfree:
782 				heap_free(inst[0].value);
783 				break;
784 
785 			case op_accelfunc:
786 				accel_set_func(inst[0].value, inst[1].value);
787 				break;
788 			case op_accelparam:
789 				accel_set_param(inst[0].value, inst[1].value);
790 				break;
791 
792 #ifdef FLOAT_SUPPORT
793 
794 			case op_numtof:
795 				vals0 = inst[0].value;
796 				value = encode_float((gfloat32)vals0);
797 				store_operand(inst[1].desttype, inst[1].value, value);
798 				break;
799 			case op_ftonumz:
800 				valf = decode_float(inst[0].value);
801 				if (!signbit(valf)) {
802 					if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
803 						vals0 = 0x7FFFFFFF;
804 					else
805 						vals0 = (int)(truncf(valf));
806 				} else {
807 					if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
808 						vals0 = 0x80000000;
809 					else
810 						vals0 = (int)(truncf(valf));
811 				}
812 				store_operand(inst[1].desttype, inst[1].value, vals0);
813 				break;
814 			case op_ftonumn:
815 				valf = decode_float(inst[0].value);
816 				if (!signbit(valf)) {
817 					if (isnan(valf) || isinf(valf) || (valf > 2147483647.0))
818 						vals0 = 0x7FFFFFFF;
819 					else
820 						vals0 = (int)(roundf(valf));
821 				} else {
822 					if (isnan(valf) || isinf(valf) || (valf < -2147483647.0))
823 						vals0 = 0x80000000;
824 					else
825 						vals0 = (int)(roundf(valf));
826 				}
827 				store_operand(inst[1].desttype, inst[1].value, vals0);
828 				break;
829 
830 			case op_fadd:
831 				valf1 = decode_float(inst[0].value);
832 				valf2 = decode_float(inst[1].value);
833 				value = encode_float(valf1 + valf2);
834 				store_operand(inst[2].desttype, inst[2].value, value);
835 				break;
836 			case op_fsub:
837 				valf1 = decode_float(inst[0].value);
838 				valf2 = decode_float(inst[1].value);
839 				value = encode_float(valf1 - valf2);
840 				store_operand(inst[2].desttype, inst[2].value, value);
841 				break;
842 			case op_fmul:
843 				valf1 = decode_float(inst[0].value);
844 				valf2 = decode_float(inst[1].value);
845 				value = encode_float(valf1 * valf2);
846 				store_operand(inst[2].desttype, inst[2].value, value);
847 				break;
848 			case op_fdiv:
849 				valf1 = decode_float(inst[0].value);
850 				valf2 = decode_float(inst[1].value);
851 				value = encode_float(valf1 / valf2);
852 				store_operand(inst[2].desttype, inst[2].value, value);
853 				break;
854 
855 			case op_fmod:
856 				valf1 = decode_float(inst[0].value);
857 				valf2 = decode_float(inst[1].value);
858 				valf = fmodf(valf1, valf2);
859 				val0 = encode_float(valf);
860 				val1 = encode_float((valf1 - valf) / valf2);
861 				if (val1 == 0x0 || val1 == 0x80000000) {
862 					/* When the quotient is zero, the sign has been lost in the
863 					   shuffle. We'll set that by hand, based on the original
864 					   arguments. */
865 					val1 = (inst[0].value ^ inst[1].value) & 0x80000000;
866 				}
867 				store_operand(inst[2].desttype, inst[2].value, val0);
868 				store_operand(inst[3].desttype, inst[3].value, val1);
869 				break;
870 
871 			case op_floor:
872 				valf = decode_float(inst[0].value);
873 				value = encode_float(floorf(valf));
874 				store_operand(inst[1].desttype, inst[1].value, value);
875 				break;
876 			case op_ceil:
877 				valf = decode_float(inst[0].value);
878 				value = encode_float(ceilf(valf));
879 				if (value == 0x0 || value == 0x80000000) {
880 					/* When the result is zero, the sign may have been lost in the
881 					   shuffle. (This is a bug in some C libraries.) We'll set the
882 					   sign by hand, based on the original argument. */
883 					value = inst[0].value & 0x80000000;
884 				}
885 				store_operand(inst[1].desttype, inst[1].value, value);
886 				break;
887 
888 			case op_sqrt:
889 				valf = decode_float(inst[0].value);
890 				value = encode_float(sqrtf(valf));
891 				store_operand(inst[1].desttype, inst[1].value, value);
892 				break;
893 			case op_log:
894 				valf = decode_float(inst[0].value);
895 				value = encode_float(logf(valf));
896 				store_operand(inst[1].desttype, inst[1].value, value);
897 				break;
898 			case op_exp:
899 				valf = decode_float(inst[0].value);
900 				value = encode_float(expf(valf));
901 				store_operand(inst[1].desttype, inst[1].value, value);
902 				break;
903 			case op_pow:
904 				valf1 = decode_float(inst[0].value);
905 				valf2 = decode_float(inst[1].value);
906 				value = encode_float(glulx_powf(valf1, valf2));
907 				store_operand(inst[2].desttype, inst[2].value, value);
908 				break;
909 
910 			case op_sin:
911 				valf = decode_float(inst[0].value);
912 				value = encode_float(sinf(valf));
913 				store_operand(inst[1].desttype, inst[1].value, value);
914 				break;
915 			case op_cos:
916 				valf = decode_float(inst[0].value);
917 				value = encode_float(cosf(valf));
918 				store_operand(inst[1].desttype, inst[1].value, value);
919 				break;
920 			case op_tan:
921 				valf = decode_float(inst[0].value);
922 				value = encode_float(tanf(valf));
923 				store_operand(inst[1].desttype, inst[1].value, value);
924 				break;
925 			case op_asin:
926 				valf = decode_float(inst[0].value);
927 				value = encode_float(asinf(valf));
928 				store_operand(inst[1].desttype, inst[1].value, value);
929 				break;
930 			case op_acos:
931 				valf = decode_float(inst[0].value);
932 				value = encode_float(acosf(valf));
933 				store_operand(inst[1].desttype, inst[1].value, value);
934 				break;
935 			case op_atan:
936 				valf = decode_float(inst[0].value);
937 				value = encode_float(atanf(valf));
938 				store_operand(inst[1].desttype, inst[1].value, value);
939 				break;
940 			case op_atan2:
941 				valf1 = decode_float(inst[0].value);
942 				valf2 = decode_float(inst[1].value);
943 				value = encode_float(atan2f(valf1, valf2));
944 				store_operand(inst[2].desttype, inst[2].value, value);
945 				break;
946 
947 			case op_jisinf:
948 				/* Infinity is well-defined, so we don't bother to convert to
949 				   float. */
950 				val0 = inst[0].value;
951 				if (val0 == 0x7F800000 || val0 == 0xFF800000) {
952 					value = inst[1].value;
953 					goto PerformJump;
954 				}
955 				break;
956 			case op_jisnan:
957 				/* NaN is well-defined, so we don't bother to convert to
958 				   float. */
959 				val0 = inst[0].value;
960 				if ((val0 & 0x7F800000) == 0x7F800000 && (val0 & 0x007FFFFF) != 0) {
961 					value = inst[1].value;
962 					goto PerformJump;
963 				}
964 				break;
965 
966 			case op_jfeq:
967 				if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
968 					/* The delta is NaN, which can never match. */
969 					val0 = 0;
970 				} else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
971 				           && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
972 					/* Both are infinite. Opposite infinities are never equal,
973 					   even if the difference is infinite, so this is easy. */
974 					val0 = (inst[0].value == inst[1].value);
975 				} else {
976 					valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
977 					valf2 = fabs(decode_float(inst[2].value));
978 					val0 = (valf1 <= valf2 && valf1 >= -valf2);
979 				}
980 				if (val0) {
981 					value = inst[3].value;
982 					goto PerformJump;
983 				}
984 				break;
985 			case op_jfne:
986 				if ((inst[2].value & 0x7F800000) == 0x7F800000 && (inst[2].value & 0x007FFFFF) != 0) {
987 					/* The delta is NaN, which can never match. */
988 					val0 = 0;
989 				} else if ((inst[0].value == 0x7F800000 || inst[0].value == 0xFF800000)
990 				           && (inst[1].value == 0x7F800000 || inst[1].value == 0xFF800000)) {
991 					/* Both are infinite. Opposite infinities are never equal,
992 					   even if the difference is infinite, so this is easy. */
993 					val0 = (inst[0].value == inst[1].value);
994 				} else {
995 					valf1 = decode_float(inst[1].value) - decode_float(inst[0].value);
996 					valf2 = fabs(decode_float(inst[2].value));
997 					val0 = (valf1 <= valf2 && valf1 >= -valf2);
998 				}
999 				if (!val0) {
1000 					value = inst[3].value;
1001 					goto PerformJump;
1002 				}
1003 				break;
1004 
1005 			case op_jflt:
1006 				valf1 = decode_float(inst[0].value);
1007 				valf2 = decode_float(inst[1].value);
1008 				if (valf1 < valf2) {
1009 					value = inst[2].value;
1010 					goto PerformJump;
1011 				}
1012 				break;
1013 			case op_jfgt:
1014 				valf1 = decode_float(inst[0].value);
1015 				valf2 = decode_float(inst[1].value);
1016 				if (valf1 > valf2) {
1017 					value = inst[2].value;
1018 					goto PerformJump;
1019 				}
1020 				break;
1021 			case op_jfle:
1022 				valf1 = decode_float(inst[0].value);
1023 				valf2 = decode_float(inst[1].value);
1024 				if (valf1 <= valf2) {
1025 					value = inst[2].value;
1026 					goto PerformJump;
1027 				}
1028 				break;
1029 			case op_jfge:
1030 				valf1 = decode_float(inst[0].value);
1031 				valf2 = decode_float(inst[1].value);
1032 				if (valf1 >= valf2) {
1033 					value = inst[2].value;
1034 					goto PerformJump;
1035 				}
1036 				break;
1037 
1038 #endif /* FLOAT_SUPPORT */
1039 
1040 #ifdef GLULX_EXTEND_OPCODES
1041 				GLULX_EXTEND_OPCODES
1042 #endif /* GLULX_EXTEND_OPCODES */
1043 
1044 			default:
1045 				fatal_error_i("Executed unknown opcode.", opcode);
1046 			}
1047 		}
1048 	}
1049 	/* done executing */
1050 #if VM_DEBUGGER
1051 	debugger_handle_quit();
1052 #endif /* VM_DEBUGGER */
1053 }
1054 
1055 } // End of namespace Glulx
1056 } // End of namespace Glk
1057