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