1 /* exec.c: Glulxe code for program execution. The main interpreter loop.
2 Designed by Andrew Plotkin <erkyrath@eblong.com>
3 http://eblong.com/zarf/glulx/index.html
11 The main interpreter loop. This repeats until the program is done.
15 int done_executing = FALSE;
18 operandlist_t *oplist;
20 glui32 value, addr, val0, val1;
25 while (!done_executing) {
28 /* Do OS-specific processing, if appropriate. */
31 /* Fetch the opcode number. */
35 /* More than one-byte opcode. */
37 /* Four-byte opcode */
39 opcode = (opcode << 8) | Mem1(pc);
41 opcode = (opcode << 8) | Mem1(pc);
43 opcode = (opcode << 8) | Mem1(pc);
49 opcode = (opcode << 8) | Mem1(pc);
54 /* Now we have an opcode number. */
56 /* Fetch the structure that describes how the operands for this
57 opcode are arranged. This is a pointer to an immutable,
60 oplist = fast_operandlist[opcode];
62 oplist = lookup_operandlist(opcode);
65 fatal_error_i("Encountered unknown opcode.", opcode);
67 /* Based on the oplist structure, load the actual operand values
68 into inst. This moves the PC up to the end of the instruction. */
69 parse_operands(&inst, oplist);
71 /* Perform the opcode. This switch statement is split in two, based
72 on some paranoid suspicions about the ability of compilers to
73 optimize large-range switches. Ignore that. */
83 value = inst.value[0] + inst.value[1];
84 store_operand(inst.desttype, inst.value[2], value);
87 value = inst.value[0] - inst.value[1];
88 store_operand(inst.desttype, inst.value[2], value);
91 value = inst.value[0] * inst.value[1];
92 store_operand(inst.desttype, inst.value[2], value);
95 vals0 = inst.value[0];
96 vals1 = inst.value[1];
98 fatal_error("Division by zero.");
99 /* Since C doesn't guarantee the results of division of negative
100 numbers, we carefully convert everything to positive values
107 value = vals0 / vals1;
110 value = -((-vals0) / vals1);
112 store_operand(inst.desttype, inst.value[2], value);
115 vals0 = inst.value[0];
116 vals1 = inst.value[1];
118 fatal_error("Division by zero doing remainder.");
123 value = vals0 % vals1;
126 value = -((-vals0) % vals1);
128 store_operand(inst.desttype, inst.value[2], value);
131 vals0 = inst.value[0];
133 store_operand(inst.desttype, inst.value[1], value);
137 value = (inst.value[0] & inst.value[1]);
138 store_operand(inst.desttype, inst.value[2], value);
141 value = (inst.value[0] | inst.value[1]);
142 store_operand(inst.desttype, inst.value[2], value);
145 value = (inst.value[0] ^ inst.value[1]);
146 store_operand(inst.desttype, inst.value[2], value);
149 value = ~(inst.value[0]);
150 store_operand(inst.desttype, inst.value[1], value);
154 vals0 = inst.value[1];
155 if (vals0 < 0 || vals0 >= 32)
158 value = ((glui32)(inst.value[0]) << (glui32)vals0);
159 store_operand(inst.desttype, inst.value[2], value);
162 vals0 = inst.value[1];
163 if (vals0 < 0 || vals0 >= 32)
166 value = ((glui32)(inst.value[0]) >> (glui32)vals0);
167 store_operand(inst.desttype, inst.value[2], value);
170 vals0 = inst.value[1];
171 if (vals0 < 0 || vals0 >= 32) {
172 if (inst.value[0] & 0x80000000)
178 /* This is somewhat foolhardy -- C doesn't guarantee that
179 right-shifting a signed value replicates the sign bit.
180 We'll assume it for now. */
181 value = ((glsi32)(inst.value[0]) >> (glsi32)vals0);
183 store_operand(inst.desttype, inst.value[2], value);
187 value = inst.value[0];
188 /* fall through to PerformJump label. */
190 PerformJump: /* goto label for successful jumping... ironic, no? */
191 if (value == 0 || value == 1) {
192 /* Return from function. This is exactly what happens in
193 return_op, but it's only a few lines of code, so I won't
194 bother with a "goto". */
197 done_executing = TRUE;
200 pop_callstub(value); /* zero or one */
203 /* Branch to a new PC value. */
204 pc = (pc + value - 2);
209 if (inst.value[0] == 0) {
210 value = inst.value[1];
215 if (inst.value[0] != 0) {
216 value = inst.value[1];
221 if (inst.value[0] == inst.value[1]) {
222 value = inst.value[2];
227 if (inst.value[0] != inst.value[1]) {
228 value = inst.value[2];
233 vals0 = inst.value[0];
234 vals1 = inst.value[1];
236 value = inst.value[2];
241 vals0 = inst.value[0];
242 vals1 = inst.value[1];
244 value = inst.value[2];
249 vals0 = inst.value[0];
250 vals1 = inst.value[1];
251 if (vals0 <= vals1) {
252 value = inst.value[2];
257 vals0 = inst.value[0];
258 vals1 = inst.value[1];
259 if (vals0 >= vals1) {
260 value = inst.value[2];
265 val0 = inst.value[0];
266 val1 = inst.value[1];
268 value = inst.value[2];
273 val0 = inst.value[0];
274 val1 = inst.value[1];
276 value = inst.value[2];
281 val0 = inst.value[0];
282 val1 = inst.value[1];
284 value = inst.value[2];
289 val0 = inst.value[0];
290 val1 = inst.value[1];
292 value = inst.value[2];
298 value = inst.value[1];
299 arglist = pop_arguments(value, 0);
300 push_callstub(inst.desttype, inst.value[2]);
301 enter_function(inst.value[0], value, arglist);
306 done_executing = TRUE;
309 pop_callstub(inst.value[0]);
312 value = inst.value[1];
313 arglist = pop_arguments(value, 0);
315 enter_function(inst.value[0], value, arglist);
319 push_callstub(inst.desttype, inst.value[0]);
320 value = inst.value[1];
322 store_operand(inst.desttype, inst.value[0], val0);
326 profile_fail("throw");
327 value = inst.value[0];
328 stackptr = inst.value[1];
333 value = inst.value[0];
334 store_operand(inst.desttype, inst.value[1], value);
337 value = inst.value[0];
338 store_operand_s(inst.desttype, inst.value[1], value);
341 value = inst.value[0];
342 store_operand_b(inst.desttype, inst.value[1], value);
346 val0 = inst.value[0];
351 store_operand(inst.desttype, inst.value[1], val0);
354 val0 = inst.value[0];
359 store_operand(inst.desttype, inst.value[1], val0);
363 value = inst.value[0];
364 value += 4 * inst.value[1];
366 store_operand(inst.desttype, inst.value[2], val0);
369 value = inst.value[0];
370 value += 2 * inst.value[1];
372 store_operand(inst.desttype, inst.value[2], val0);
375 value = inst.value[0];
376 value += inst.value[1];
378 store_operand(inst.desttype, inst.value[2], val0);
381 value = inst.value[0];
382 vals0 = inst.value[1];
385 value += (vals0 >> 3);
387 value -= ((-1 - vals0) >> 3);
388 if (Mem1(value) & (1 << val1))
392 store_operand(inst.desttype, inst.value[2], val0);
396 value = inst.value[0];
397 value += 4 * inst.value[1];
398 val0 = inst.value[2];
402 value = inst.value[0];
403 value += 2 * inst.value[1];
404 val0 = inst.value[2];
408 value = inst.value[0];
409 value += inst.value[1];
410 val0 = inst.value[2];
414 value = inst.value[0];
415 vals0 = inst.value[1];
418 value += (vals0 >> 3);
420 value -= ((-1 - vals0) >> 3);
425 val0 &= ~((glui32)(1 << val1));
430 value = (stackptr - valstackbase) / 4;
431 store_operand(inst.desttype, inst.value[0], value);
434 vals0 = inst.value[0] * 4;
435 if (vals0 < 0 || vals0 >= (stackptr - valstackbase))
436 fatal_error("Stkpeek outside current stack range.");
437 value = Stk4(stackptr - (vals0+4));
438 store_operand(inst.desttype, inst.value[1], value);
441 if (stackptr < valstackbase+8) {
442 fatal_error("Stack underflow in stkswap.");
444 val0 = Stk4(stackptr-4);
445 val1 = Stk4(stackptr-8);
446 StkW4(stackptr-4, val1);
447 StkW4(stackptr-8, val0);
450 vals0 = inst.value[0];
452 fatal_error("Negative operand in stkcopy.");
455 if (stackptr < valstackbase+vals0*4)
456 fatal_error("Stack underflow in stkcopy.");
457 if (stackptr + vals0*4 > stacksize)
458 fatal_error("Stack overflow in stkcopy.");
459 addr = stackptr - vals0*4;
460 for (ix=0; ix<vals0; ix++) {
461 value = Stk4(addr + ix*4);
462 StkW4(stackptr + ix*4, value);
467 vals0 = inst.value[0];
468 vals1 = inst.value[1];
470 fatal_error("Negative operand in stkroll.");
471 if (stackptr < valstackbase+vals0*4)
472 fatal_error("Stack underflow in stkroll.");
475 /* The following is a bit ugly. We want to do vals1 = vals0-vals1,
476 because rolling down is sort of easier than rolling up. But
477 we also want to take the result mod vals0. The % operator is
478 annoying for negative numbers, so we need to do this in two
481 vals1 = vals1 % vals0;
482 vals1 = (vals0) - vals1;
485 vals1 = (-vals1) % vals0;
489 addr = stackptr - vals0*4;
490 for (ix=0; ix<vals1; ix++) {
491 value = Stk4(addr + ix*4);
492 StkW4(stackptr + ix*4, value);
494 for (ix=0; ix<vals0; ix++) {
495 value = Stk4(addr + (vals1+ix)*4);
496 StkW4(addr + ix*4, value);
501 profile_in(2, FALSE);
502 value = inst.value[0] & 0xFF;
503 (*stream_char_handler)(value);
506 case op_streamunichar:
507 profile_in(2, FALSE);
508 value = inst.value[0];
509 (*stream_unichar_handler)(value);
513 profile_in(2, FALSE);
514 vals0 = inst.value[0];
515 stream_num(vals0, FALSE, 0);
519 profile_in(2, FALSE);
520 stream_string(inst.value[0], 0, 0);
525 fatal_error_i("Executed unknown opcode.", opcode);
533 value = do_gestalt(inst.value[0], inst.value[1]);
534 store_operand(inst.desttype, inst.value[2], value);
538 fatal_error_i("user debugtrap encountered.", inst.value[0]);
545 push_callstub(inst.desttype, inst.value[1]);
546 enter_function(inst.value[0], 0, arglistfix);
549 arglistfix[0] = inst.value[1];
550 push_callstub(inst.desttype, inst.value[2]);
551 enter_function(inst.value[0], 1, arglistfix);
554 arglistfix[0] = inst.value[1];
555 arglistfix[1] = inst.value[2];
556 push_callstub(inst.desttype, inst.value[3]);
557 enter_function(inst.value[0], 2, arglistfix);
560 arglistfix[0] = inst.value[1];
561 arglistfix[1] = inst.value[2];
562 arglistfix[2] = inst.value[3];
563 push_callstub(inst.desttype, inst.value[4]);
564 enter_function(inst.value[0], 3, arglistfix);
568 store_operand(inst.desttype, inst.value[0], endmem);
571 value = change_memsize(inst.value[0], FALSE);
572 store_operand(inst.desttype, inst.value[1], value);
575 case op_getstringtbl:
576 value = stream_get_table();
577 store_operand(inst.desttype, inst.value[0], value);
579 case op_setstringtbl:
580 stream_set_table(inst.value[0]);
584 stream_get_iosys(&val0, &val1);
585 store_operand(inst.desttype, inst.value[0], val0);
586 store_operand(inst.desttype, inst.value[1], val1);
589 stream_set_iosys(inst.value[0], inst.value[1]);
593 profile_in(1, FALSE);
594 value = inst.value[1];
595 arglist = pop_arguments(value, 0);
596 val0 = perform_glk(inst.value[0], value, arglist);
597 store_operand(inst.desttype, inst.value[2], val0);
602 vals0 = inst.value[0];
604 value = glulx_random() ^ (glulx_random() << 16);
606 value = glulx_random() % (glui32)(vals0);
608 value = -(glulx_random() % (glui32)(-vals0));
609 store_operand(inst.desttype, inst.value[1], value);
612 glulx_setrandom(inst.value[0]);
616 value = perform_verify();
617 store_operand(inst.desttype, inst.value[0], value);
621 profile_fail("restart");
626 val0 = inst.value[0];
627 val1 = val0 + inst.value[1];
637 push_callstub(inst.desttype, inst.value[1]);
638 value = perform_save(find_stream_by_id(inst.value[0]));
643 profile_fail("restore");
644 value = perform_restore(find_stream_by_id(inst.value[0]));
646 /* We've succeeded, and the stack now contains the callstub
647 saved during saveundo. Ignore this opcode's operand. */
652 /* We've failed, so we must store the failure in this opcode's
654 store_operand(inst.desttype, inst.value[1], value);
659 push_callstub(inst.desttype, inst.value[0]);
660 value = perform_saveundo();
665 profile_fail("restoreundo");
666 value = perform_restoreundo();
668 /* We've succeeded, and the stack now contains the callstub
669 saved during saveundo. Ignore this opcode's operand. */
674 /* We've failed, so we must store the failure in this opcode's
676 store_operand(inst.desttype, inst.value[0], value);
681 done_executing = TRUE;
684 case op_linearsearch:
685 value = linear_search(inst.value[0], inst.value[1], inst.value[2],
686 inst.value[3], inst.value[4], inst.value[5], inst.value[6]);
687 store_operand(inst.desttype, inst.value[7], value);
689 case op_binarysearch:
690 value = binary_search(inst.value[0], inst.value[1], inst.value[2],
691 inst.value[3], inst.value[4], inst.value[5], inst.value[6]);
692 store_operand(inst.desttype, inst.value[7], value);
694 case op_linkedsearch:
695 value = linked_search(inst.value[0], inst.value[1], inst.value[2],
696 inst.value[3], inst.value[4], inst.value[5]);
697 store_operand(inst.desttype, inst.value[6], value);
702 glui32 count = inst.value[0];
703 addr = inst.value[1];
704 for (lx=0; lx<count; lx++, addr++) {
711 glui32 count = inst.value[0];
712 glui32 addrsrc = inst.value[1];
713 glui32 addrdest = inst.value[2];
714 if (addrdest < addrsrc) {
715 for (lx=0; lx<count; lx++, addrsrc++, addrdest++) {
716 value = Mem1(addrsrc);
717 MemW1(addrdest, value);
721 addrsrc += (count-1);
722 addrdest += (count-1);
723 for (lx=0; lx<count; lx++, addrsrc--, addrdest--) {
724 value = Mem1(addrsrc);
725 MemW1(addrdest, value);
731 value = heap_alloc(inst.value[0]);
732 store_operand(inst.desttype, inst.value[1], value);
735 heap_free(inst.value[0]);
739 accel_set_func(inst.value[0], inst.value[1]);
742 accel_set_param(inst.value[0], inst.value[1]);
746 fatal_error_i("Executed unknown opcode.", opcode);