1 // $Id: terp.c,v 1.42 2004/12/22 14:33:40 iain Exp $
12 // -------------------------------------------------------------
15 git_sint32* gStackPointer;
17 #ifdef USE_DIRECT_THREADING
21 // -------------------------------------------------------------
22 // Useful macros for manipulating the stack
24 #define LOCAL(n) (locals[(n)])
26 #define PUSH(n) *sp++ = (n)
28 #define READ_PC ((git_uint32)(*pc++))
30 #define CHECK_FREE(n) if ((top - sp) < (n)) goto stack_overflow
31 #define CHECK_USED(n) if ((sp - values) < (n)) goto stack_underflow
33 // -------------------------------------------------------------
34 // Floating point support
36 #define ENCODE_FLOAT(f) (* (git_uint32*) &f)
37 #define DECODE_FLOAT(n) (* (git_float*) &n)
39 int floatCompare(git_sint32 L1, git_sint32 L2, git_sint32 L3)
43 if (((L3 & 0x7F800000) == 0x7F800000) && ((L3 & 0x007FFFFF) != 0))
\r
45 if ((L1 == 0x7F800000 || L1 == 0xFF800000) && (L2 == 0x7F800000 || L2 == 0xFF800000))
\r
48 F1 = DECODE_FLOAT(L2) - DECODE_FLOAT(L1);
\r
49 F2 = fabs(DECODE_FLOAT(L3));
\r
50 return ((F1 <= F2) && (F1 >= -F2));
\r
54 float git_powf(float x, float y)
\r
58 else if ((y == 0.0f) || (y == -0.0f))
\r
60 else if ((x == -1.0f) && isinf(y))
\r
66 // -------------------------------------------------------------
69 void startProgram (size_t cacheSize, enum IOMode ioMode)
71 Block pc; // Program counter (pointer into dynamically generated code)
73 git_sint32 L1=0, L2=0, L3=0, L4=0, L5=0, L6=0, L7=0;
76 git_float F1=0.0f, F2=0.0f, F3=0.0f, F4=0.0f;
78 git_sint32* base; // Bottom of the stack.
79 git_sint32* frame; // Bottom of the current stack frame.
80 git_sint32* locals; // Start of the locals section of the current frame.
81 git_sint32* values; // Start of the values section of the current frame.
82 git_sint32* sp; // Next free stack slot.
83 git_sint32* top; // The top of the stack -- that is, the first unusable slot.
85 git_sint32 args [64]; // Array of arguments. Count is stored in L2.
86 git_uint32 runCounter = 0;
88 git_uint32 ioRock = 0;
90 git_uint32 stringTable = memRead32(28);
91 git_uint32 startPos = memRead32(24);
92 git_uint32 stackSize = memRead32(20);
94 git_uint32 protectPos = 0;
95 git_uint32 protectSize = 0;
97 git_uint32 glulxPC = 0;
98 git_uint32 glulxOpcode = 0;
100 acceleration_func accelfunc;
102 // Initialise the code cache.
104 #ifdef USE_DIRECT_THREADING
105 static Opcode opcodeTable [] = {
106 #define LABEL(label) &&do_ ## label,
107 #include "labels.inc"
109 gOpcodeTable = opcodeTable;
112 initCompiler (cacheSize);
114 // Initialise the random number generator.
119 base = malloc (stackSize);
121 fatalError ("Couldn't allocate stack");
123 top = base + (stackSize / 4);
124 frame = locals = values = sp = base;
126 // Call the first function.
128 L1 = startPos; // Initial PC.
129 L2 = 0; // No arguments.
130 goto do_enter_function_L1;
132 #ifdef USE_DIRECT_THREADING
133 #define NEXT do { ++runCounter; goto **(pc++); } while(0)
135 #define NEXT goto next
136 //#define NEXT do { CHECK_USED(0); CHECK_FREE(0); goto next; } while (0)
141 #define LABEL(foo) case label_ ## foo: goto do_ ## foo;
142 #include "labels.inc"
143 default: fatalError("exec: bad opcode");
148 // This opcode lets us keep track of how the compiled
149 // code relates to the original glulx code.
150 glulxPC = READ_PC; // Glulx program counter.
151 glulxOpcode = READ_PC; // Glulx opcode number.
152 // fprintf (stdout, "\nPC: 0x%08x\nOpcode: 0x%04x\n", glulxPC, glulxOpcode);
153 // fprintf (stdout, "Stack:");
154 // for (L7 = 0 ; L7 < (sp - base) ; ++L7)
155 // fprintf (stdout," 0x%x", base[L7]);
156 // fprintf (stdout, "\n");
159 #define LOAD_INSTRUCTIONS(reg) \
160 do_ ## reg ## _const: reg = READ_PC; NEXT; \
161 do_ ## reg ## _stack: CHECK_USED(1); reg = POP; NEXT; \
162 do_ ## reg ## _addr: reg = memRead32 (READ_PC); NEXT; \
163 do_ ## reg ## _local: reg = LOCAL (READ_PC); NEXT
165 LOAD_INSTRUCTIONS(L1);
166 LOAD_INSTRUCTIONS(L2);
167 LOAD_INSTRUCTIONS(L3);
168 LOAD_INSTRUCTIONS(L4);
169 LOAD_INSTRUCTIONS(L5);
170 LOAD_INSTRUCTIONS(L6);
171 LOAD_INSTRUCTIONS(L7);
173 #define STORE_INSTRUCTIONS(reg) \
174 do_ ## reg ## _stack: CHECK_FREE(1); PUSH(reg); NEXT; \
175 do_ ## reg ## _addr: memWrite32 (READ_PC, reg); NEXT; \
176 do_ ## reg ## _local: LOCAL (READ_PC) = reg; NEXT
178 STORE_INSTRUCTIONS(S1);
179 STORE_INSTRUCTIONS(S2);
181 #define DOUBLE_LOAD(mode2) \
182 do_L1_const_L2_ ## mode2: L1 = READ_PC; goto do_L2_ ## mode2; \
183 do_L1_stack_L2_ ## mode2: CHECK_USED(1); L1 = POP; goto do_L2_ ## mode2; \
184 do_L1_local_L2_ ## mode2: L1 = LOCAL (READ_PC); goto do_L2_ ## mode2; \
185 do_L1_addr_L2_ ## mode2: L1 = memRead32 (READ_PC); goto do_L2_ ## mode2
192 #undef LOAD_INSTRUCTIONS
193 #undef STORE_INSTRUCTIONS
196 do_L1_addr16: L1 = memRead16 (READ_PC); NEXT;
197 do_L1_addr8: L1 = memRead8 (READ_PC); NEXT;
198 do_S1_addr16: memWrite16 (READ_PC, S1); NEXT;
199 do_S1_addr8: memWrite8 (READ_PC, S1); NEXT;
201 #define UL7 ((git_uint32)L7)
204 gBlockHeader->runCounter = runCounter;
205 pc = compile (READ_PC);
210 gBlockHeader->runCounter = runCounter;
212 runCounter = gBlockHeader->runCounter;
215 do_enter_function_L1: // Arg count is in L2.
217 // Check for an accelerated function
218 accelfunc = accel_get_func(L1);
220 S1 = accelfunc(L2, (glui32 *) args);
221 goto do_pop_call_stub;
225 // Read the function type.
227 // Parse the local variables descriptor.
231 L6 = memRead8(L1++); // LocalType
232 L5 = memRead8(L1++); // LocalCount
233 if (L6 != 4 && L6 != 0) // We only support 4-byte locals.
234 fatalError("Local variable wasn't 4 bytes wide");
235 L4 += L5; // Cumulative local count.
239 // Write out the stack frame.
240 // Recall that the number of locals is stored in L4.
244 PUSH (L4*4 + 12); // FrameLen
245 PUSH (12); // LocalsPos
249 L6 = (4 << 24) | (L4 << 16);
250 PUSH (L6); // format of locals
252 // This is where the local variables start, so:
255 // Read the arguments, based on the function type.
258 case 0xC0: // arguments should be placed on the stack.
259 // argc is in L2; we'll randomly use L5 as scratch.
261 // Initialise the local variables.
262 for ( ; L4 > 0 ; --L4)
264 // This is where the temporary values start, so:
266 // Push the args onto the stack.
267 for (L5 = 0 ; L5 < L2 ; ++L5)
269 // Push the arg count.
273 case 0xC1: // arguments should be written into locals.
274 // argc is in L2, num locals is in L4.
275 // Stuff as many locals as possible with arguments.
276 for (L5 = 1 ; L5 <= L2 && L4 > 0 ; ++L5, --L4)
277 PUSH (args [L2 - L5]);
278 // Initialise any remaining locals.
279 for ( ; L4 > 0 ; --L4)
281 // This is where the temporary values start, so:
286 // This isn't a function!
287 fatalError("Not a function");
291 // Start executing the function.
297 #define PEEPHOLE_STORE(tag, code) \
298 do_ ## tag ## _discard: code; NEXT; \
299 do_ ## tag ## _S1_stack: code; goto do_S1_stack; \
300 do_ ## tag ## _S1_local: code; goto do_S1_local; \
301 do_ ## tag ## _S1_addr: code; goto do_S1_addr
303 PEEPHOLE_STORE(add, S1 = L1 + L2);
304 PEEPHOLE_STORE(sub, S1 = L1 - L2);
305 PEEPHOLE_STORE(mul, S1 = L1 * L2);
306 PEEPHOLE_STORE(div, if (L2 == 0) fatalError ("Divide by zero"); S1 = L1 / L2);
307 PEEPHOLE_STORE(mod, if (L2 == 0) fatalError ("Divide by zero"); S1 = L1 % L2);
309 PEEPHOLE_STORE(neg, S1 = -L1);
310 PEEPHOLE_STORE(bitnot, S1 = ~L1);
312 PEEPHOLE_STORE(bitand, S1 = L1 & L2);
313 PEEPHOLE_STORE(bitor, S1 = L1 | L2);
314 PEEPHOLE_STORE(bitxor, S1 = L1 ^ L2);
316 PEEPHOLE_STORE(shiftl, if (L2 > 31 || L2 < 0) S1 = 0; else S1 = L1 << ((git_uint32) L2));
317 PEEPHOLE_STORE(sshiftr, if (L2 > 31 || L2 < 0) L2 = 31; S1 = ((git_sint32) L1) >> ((git_uint32) L2));
318 PEEPHOLE_STORE(ushiftr, if (L2 > 31 || L2 < 0) S1 = 0; else S1 = ((git_uint32) L1) >> ((git_uint32) L2));
320 PEEPHOLE_STORE(aload, S1 = memRead32 (L1 + (L2<<2)));
321 PEEPHOLE_STORE(aloads, S1 = memRead16 (L1 + (L2<<1)));
322 PEEPHOLE_STORE(aloadb, S1 = memRead8 (L1 + L2));
323 PEEPHOLE_STORE(aloadbit,S1 = (memRead8 (L1 + (L2>>3)) >> (L2 & 7)) & 1);
325 PEEPHOLE_STORE(copys, S1 = L1 & 0xFFFF);
326 PEEPHOLE_STORE(copyb, S1 = L1 & 0x00FF);
327 PEEPHOLE_STORE(sexs, S1 = (git_sint32)((signed short)(L1 & 0xFFFF)));
328 PEEPHOLE_STORE(sexb, S1 = (git_sint32)((signed char)(L1 & 0x00FF)));
330 PEEPHOLE_STORE(fadd, F1 = DECODE_FLOAT(L1) + DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
331 PEEPHOLE_STORE(fsub, F1 = DECODE_FLOAT(L1) - DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
332 PEEPHOLE_STORE(fmul, F1 = DECODE_FLOAT(L1) * DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
333 PEEPHOLE_STORE(fdiv, F1 = DECODE_FLOAT(L1) / DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
\r
335 #define PEEPHOLE_LOAD(tag,reg) \
336 do_ ## tag ## _ ## reg ## _const: reg = READ_PC; goto do_ ## tag; \
337 do_ ## tag ## _ ## reg ## _stack: CHECK_USED(1); reg = POP; goto do_ ## tag; \
338 do_ ## tag ## _ ## reg ## _local: reg = LOCAL(READ_PC); goto do_ ## tag; \
339 do_ ## tag ## _ ## reg ## _addr: reg = memRead32(READ_PC); goto do_ ## tag
341 PEEPHOLE_LOAD (return, L1);
342 PEEPHOLE_LOAD (astore, L3);
343 PEEPHOLE_LOAD (astores, L3);
344 PEEPHOLE_LOAD (astoreb, L3);
345 PEEPHOLE_LOAD (astorebit, L3);
347 #undef PEEPHOLE_STORE
349 do_astore: memWrite32 (L1 + (L2<<2), L3); NEXT;
350 do_astores: memWrite16 (L1 + (L2<<1), L3); NEXT;
351 do_astoreb: memWrite8 (L1 + L2, L3); NEXT;
353 L4 = memRead8(L1 + (L2>>3));
355 L4 &= ~(1 << (L2 & 7));
357 L4 |= (1 << (L2 & 7));
358 memWrite8(L1 + (L2>>3), L4);
361 #define DO_JUMP(tag, reg, cond) \
362 do_ ## tag ## _var: L7 = READ_PC; if (cond) goto do_goto_ ## reg ## _from_L7; NEXT; \
363 do_ ## tag ## _const: L7 = READ_PC; if (cond) goto do_jump_abs_L7; NEXT; \
364 do_ ## tag ## _by: L7 = READ_PC; if (cond) pc += L7; NEXT; \
365 do_ ## tag ## _return0: if (cond) { L1 = 0; goto do_return; } NEXT; \
366 do_ ## tag ## _return1: if (cond) { L1 = 1; goto do_return; } NEXT
368 DO_JUMP(jump, L1, 1 == 1);
369 DO_JUMP(jz, L2, L1 == 0);
370 DO_JUMP(jnz, L2, L1 != 0);
371 DO_JUMP(jeq, L3, L1 == L2);
372 DO_JUMP(jne, L3, L1 != L2);
373 DO_JUMP(jlt, L3, L1 < L2);
374 DO_JUMP(jge, L3, L1 >= L2);
375 DO_JUMP(jgt, L3, L1 > L2);
376 DO_JUMP(jle, L3, L1 <= L2);
377 DO_JUMP(jltu, L3, ((git_uint32)L1 < (git_uint32)L2));
378 DO_JUMP(jgeu, L3, ((git_uint32)L1 >= (git_uint32)L2));
379 DO_JUMP(jgtu, L3, ((git_uint32)L1 > (git_uint32)L2));
380 DO_JUMP(jleu, L3, ((git_uint32)L1 <= (git_uint32)L2));
381 DO_JUMP(jisnan, L2, (((L1 & 0x7F800000) == 0x7F800000) && ((L1 & 0x007FFFFF) != 0)));
382 DO_JUMP(jisinf, L2, ((L1 == 0x7F800000) || (L1 == 0xFF800000)));
383 DO_JUMP(jflt, L3, DECODE_FLOAT(L1) < DECODE_FLOAT(L2));
384 DO_JUMP(jfge, L3, DECODE_FLOAT(L1) >= DECODE_FLOAT(L2));
385 DO_JUMP(jfgt, L3, DECODE_FLOAT(L1) > DECODE_FLOAT(L2));
386 DO_JUMP(jfle, L3, DECODE_FLOAT(L1) <= DECODE_FLOAT(L2));
387 DO_JUMP(jfeq, L4, floatCompare(L1, L2, L3) != 0);
388 DO_JUMP(jfne, L4, floatCompare(L1, L2, L3) == 0);
392 do_jumpabs: L7 = L1; goto do_jump_abs_L7; NEXT;
394 do_goto_L4_from_L7: L1 = L4; goto do_goto_L1_from_L7;
395 do_goto_L3_from_L7: L1 = L3; goto do_goto_L1_from_L7;
396 do_goto_L2_from_L7: L1 = L2; goto do_goto_L1_from_L7;
398 if (L1 == 0 || L1 == 1) goto do_return;
399 L7 = L7 + L1 - 2; goto do_jump_abs_L7;
402 // The first argument is topmost in the stack; the count is in L2.
404 // We want to store the arguments in 'args' in the same order.
405 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
409 // Specialised versions of above:
410 do_args_stack_call_stub_discard:
412 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
414 goto do_call_stub_discard;
416 do_args_stack_call_stub_addr:
418 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
420 goto do_call_stub_addr;
422 do_args_stack_call_stub_local:
424 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
426 goto do_call_stub_local;
428 do_args_stack_call_stub_stack:
430 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
432 goto do_call_stub_stack;
456 do_undo_stub_discard:
458 PUSH (0); // DestType
459 PUSH (0); // DestAddr
460 goto finish_undo_stub;
464 PUSH (1); // DestType
465 PUSH (READ_PC); // DestAddr
466 goto finish_undo_stub;
470 PUSH (2); // DestType
471 PUSH (READ_PC); // DestAddr
472 goto finish_undo_stub;
476 PUSH (3); // DestType
477 PUSH (0); // DestAddr
478 goto finish_undo_stub;
481 PUSH (READ_PC); // PC
482 PUSH ((frame - base) * 4); // FramePtr
485 goto do_pop_call_stub;
488 if (restoreUndo (base, protectPos, protectSize) == 0)
492 goto do_pop_call_stub;
497 do_save_stub_discard:
499 PUSH (0); // DestType
500 PUSH (0); // DestAddr
501 goto finish_save_stub;
505 PUSH (1); // DestType
506 PUSH (READ_PC); // DestAddr
507 goto finish_save_stub;
511 PUSH (2); // DestType
512 PUSH (READ_PC); // DestAddr
513 goto finish_save_stub;
517 PUSH (3); // DestType
518 PUSH (0); // DestAddr
519 goto finish_save_stub;
522 PUSH (READ_PC); // PC
523 PUSH ((frame - base) * 4); // FramePtr
524 if (ioMode == IO_GLK)
525 S1 = saveToFile (base, sp, L1);
528 goto do_pop_call_stub;
532 && restoreFromFile (base, L1, protectPos, protectSize) == 0)
536 goto do_pop_call_stub;
541 do_catch_stub_discard:
544 PUSH (0); // DestType
545 goto finish_catch_stub_addr_L7;
550 memWrite32(L7, (sp-base+4)*4);
551 PUSH (1); // DestType
552 goto finish_catch_stub_addr_L7;
557 LOCAL(L7 / 4) = (sp-base+4)*4;
558 PUSH (2); // DestType
559 goto finish_catch_stub_addr_L7;
563 PUSH (3); // DestType
564 PUSH (0); // DestAddr
565 PUSH (READ_PC); // PC
566 PUSH ((frame - base) * 4); // FramePtr
567 L7 = (sp - base)*4; // Catch token.
571 finish_catch_stub_addr_L7:
572 PUSH (L7); // DestAddr
573 PUSH (READ_PC); // PC
574 PUSH ((frame - base) * 4); // FramePtr
578 if (L2 < 16 || L2 > ((sp-base)*4))
579 fatalError ("Invalid catch token in throw");
581 goto do_pop_call_stub;
583 do_call_stub_discard:
585 PUSH (0); // DestType
586 PUSH (0); // DestAddr
587 goto finish_call_stub;
591 PUSH (1); // DestType
592 PUSH (READ_PC); // DestAddr
593 goto finish_call_stub;
597 PUSH (2); // DestType
598 PUSH (READ_PC); // DestAddr
599 goto finish_call_stub;
603 PUSH (3); // DestType
604 PUSH (0); // DestAddr
605 goto finish_call_stub;
608 PUSH (READ_PC); // PC
609 PUSH ((frame - base) * 4); // FramePtr
610 goto do_enter_function_L1;
613 // Zap the current stack frame, down to its call stub.
615 // Call the function!
616 goto do_enter_function_L1;
623 do_pop_call_stub:// L1 holds the return value.
627 // We just exited the top-level function.
630 // Something nasty happened.
631 goto stack_underflow;
633 L2 = POP; // FramePtr
635 L6 = POP; // DestAddr
636 switch (POP) // DestType
638 case 0: // Do not store.
639 frame = base + L2 / 4;
640 locals = frame + frame[1]/4;
641 values = frame + frame[0]/4;
644 case 1: // Store in main memory.
645 frame = base + L2 / 4;
646 locals = frame + frame[1]/4;
647 values = frame + frame[0]/4;
651 case 2: // Store in local variable.
652 frame = base + L2 / 4;
653 locals = frame + frame[1]/4;
654 values = frame + frame[0]/4;
658 case 3: // Push on stack.
659 frame = base + L2 / 4;
660 locals = frame + frame[1]/4;
661 values = frame + frame[0]/4;
665 case 10: // Resume printing a compressed (E1) string.
666 frame = base + L2 / 4;
667 locals = frame + frame[1]/4;
668 values = frame + frame[0]/4;
669 goto resume_compressed_string_L7_bit_L6;
671 case 11: // Resume executing function code after a string completes.
672 // Don't restore the frame pointer.
675 case 12: // Resume printing a signed decimal integer.
676 frame = base + L2 / 4;
677 locals = frame + frame[1]/4;
678 values = frame + frame[0]/4;
679 goto resume_number_L7_digit_L6;
681 case 13: // Resume printing a C-style (E0) string.
682 frame = base + L2 / 4;
683 locals = frame + frame[1]/4;
684 values = frame + frame[0]/4;
685 goto resume_c_string_L7;
687 case 14: // Resume printing a Unicode (E2) string.
688 frame = base + L2 / 4;
689 locals = frame + frame[1]/4;
690 values = frame + frame[0]/4;
691 goto resume_uni_string_L7;
694 fatalError("Bad call stub");
700 S1 = sp - values; NEXT;
703 if (L1 < 0 || L1 > (sp - values))
704 fatalError("Out of bounds in stkpeek");
705 S1 = sp[-1 - L1]; NEXT;
709 L1 = POP; L2 = POP; PUSH(L1); PUSH(L2); NEXT;
713 for (L2 = L1 ; L2 > 0 ; --L2)
720 resume_number_L7_digit_L6:
724 // If the IO mode is 'null', do nothing.
725 if (ioMode == IO_NULL)
726 goto do_pop_call_stub;
728 // Write the number into the buffer.
729 L1 = (L7 < 0) ? -L7 : L7; // Absolute value of number.
730 L2 = 0; // Current buffer position.
733 buffer [L2++] = '0' + (L1 % 10);
742 goto do_pop_call_stub; // We printed the whole number already.
744 // If we're in filter mode, push a call stub
745 // and filter the next character.
746 if (ioMode == IO_FILTER)
748 // Store the next character in the args array.
749 args[0] = buffer [L2 - L6 - 1];
752 // Push a call stub to print the next character.
754 PUSH(12); // DestType
755 PUSH(L6); // DestAddr (next digit)
756 PUSH(L7); // PC (number to print)
757 PUSH ((frame - base) * 4); // FramePtr
759 // Call the filter function.
762 goto do_enter_function_L1;
766 // We're in Glk mode. Just print all the characters.
767 for ( ; L6 < L2 ; ++L6)
768 glk_put_char (buffer [L2 - L6 - 1]);
771 goto do_pop_call_stub;
774 // If the IO mode is 'null', or if we've reached the
775 // end of the string, do nothing.
777 if (L2 == 0 || ioMode == IO_NULL)
778 goto do_pop_call_stub;
779 // Otherwise we're going to have to print something,
780 // If the IO mode is 'filter', filter the next char.
781 if (ioMode == IO_FILTER)
783 // Store this character in the args array.
787 PUSH(13); // DestType (resume C string)
788 PUSH(L6); // DestAddr (ignored)
789 PUSH(L7); // PC (next char to print)
790 PUSH ((frame - base) * 4); // FramePtr
791 // Call the filter function.
794 goto do_enter_function_L1;
796 // We're in Glk mode. Just print all the characters.
799 glk_put_char ((unsigned char) L2);
802 goto do_pop_call_stub;
804 resume_uni_string_L7:
805 // If the IO mode is 'null', or if we've reached the
806 // end of the string, do nothing.
809 if (L2 == 0 || ioMode == IO_NULL)
810 goto do_pop_call_stub;
811 // Otherwise we're going to have to print something,
812 // If the IO mode is 'filter', filter the next char.
813 if (ioMode == IO_FILTER)
815 // Store this character in the args array.
819 PUSH(14); // DestType (resume Unicode string)
820 PUSH(L6); // DestAddr (ignored)
821 PUSH(L7); // PC (next char to print)
822 PUSH ((frame - base) * 4); // FramePtr
823 // Call the filter function.
826 goto do_enter_function_L1;
828 // We're in Glk mode. Just print all the characters.
831 #ifdef GLK_MODULE_UNICODE
832 glk_put_char_uni ((glui32) L2);
834 unsigned char c = (L2 > 0 && L2 < 256) ? L2 : '?';
836 #endif // GLK_MODULE_UNICODE
840 goto do_pop_call_stub;
842 resume_compressed_string_L7_bit_L6:
843 // Load the first string table node into L1.
844 // Its address is stored at stringTable + 8.
845 L1 = memRead32 (stringTable + 8);
846 // Load the node's type byte.
847 L2 = memRead8 (L1++);
848 // Is the root node a branch?
851 // We'll keep a reservoir of input bits in L5.
853 // Keep following branch nodes until we hit a leaf node.
856 // Read the next bit.
858 // If we're finished reading this byte,
859 // move on to the next one.
865 // Follow the branch.
866 L1 = memRead32(L1 + 4 * L4);
867 L2 = memRead8 (L1++);
870 else if (L2 == 2 || L2 == 3)
872 // The root node prints a single character or a string.
873 // This will produce infinite output in the Null or Glk
874 // I/O modes, so we'll catch that here.
876 if (ioMode != IO_FILTER)
877 fatalError ("String table prints infinite strings!");
879 // In Filter mode, the output will be sent to the current
880 // filter function, which can change the string table
881 // before returning, so we'll continue and see what happens.
883 // We're at a leaf node.
886 case 1: // Terminator.
887 goto do_pop_call_stub;
889 case 2: // Single char.
890 if (ioMode == IO_NULL)
892 else if (ioMode == IO_GLK)
893 glk_put_char ((unsigned char) memRead8(L1));
896 // Store this character in the args array.
897 args [0] = memRead8(L1);
900 PUSH(10); // DestType
901 PUSH(L6); // DestAddr (bit number in string)
902 PUSH(L7); // PC (byte address in string)
903 PUSH ((frame - base) * 4); // FramePtr
904 // Call the filter function.
907 goto do_enter_function_L1;
912 // Push a 'resume compressed string' call stub.
914 PUSH (10); // DestType
915 PUSH (L6); // DestAddr (bit number in string)
916 PUSH (L7); // PC (byte address in string)
917 PUSH ((frame - base) * 4); // FramePtr
918 // Print the C string.
920 goto resume_c_string_L7;
922 case 4: // Unicode char
923 if (ioMode == IO_NULL)
925 else if (ioMode == IO_GLK)
927 #ifdef GLK_MODULE_UNICODE
928 glk_put_char_uni (memRead32(L1));
930 git_uint32 c = memRead32(L1);
931 if (c > 255) c = '?';
932 glk_put_char ((unsigned char) c);
933 #endif // GLK_MODULE_UNICODE
937 // Store this character in the args array.
938 args [0] = memRead32(L1);
941 PUSH(10); // DestType
942 PUSH(L6); // DestAddr (bit number in string)
943 PUSH(L7); // PC (byte address in string)
944 PUSH ((frame - base) * 4); // FramePtr
945 // Call the filter function.
948 goto do_enter_function_L1;
952 case 5: // Unicode string.
953 // Push a 'resume compressed string' call stub.
955 PUSH (10); // DestType
956 PUSH (L6); // DestAddr (bit number in string)
957 PUSH (L7); // PC (byte address in string)
958 PUSH ((frame - base) * 4); // FramePtr
959 // Print the Unicode string.
961 goto resume_uni_string_L7;
963 case 8: // Indirect reference.
965 L2 = 0; goto indirect_L3_args_L2;
967 case 9: // Double-indirect reference.
968 L3 = memRead32(L1); L3 = memRead32(L3);
969 L2 = 0; goto indirect_L3_args_L2;
971 case 10: // Indirect reference with args.
973 L2 = memRead32(L1 + 4); goto indirect_L3_args_L2;
975 case 11: // Double-indirect reference with args.
976 L3 = memRead32(L1); L3 = memRead32(L3);
977 L2 = memRead32(L1 + 4); goto indirect_L3_args_L2;
980 // Push a 'resume compressed string' call stub.
982 PUSH (10); // DestType
983 PUSH (L6); // DestAddr (bit number in string)
984 PUSH (L7); // PC (byte address in string)
985 PUSH ((frame - base) * 4); // FramePtr
986 // Check the type of the embedded object.
987 switch (memRead8(L3))
989 case 0xE0: // C string.
991 goto resume_c_string_L7;
993 case 0xE1: // Compressed string.
996 goto resume_compressed_string_L7_bit_L6;
998 case 0xE2: // Unicode string.
999 L7 = L3 + 4; // Skip extra three padding bytes.
1000 goto resume_uni_string_L7;
1002 case 0xC0: case 0xC1: // Function.
1003 // Retrieve arguments.
1004 for (L1 += 8, L4 = L2; L4 > 0 ; --L4, L1+=4)
1005 args[L4-1] = memRead32(L1);
1008 goto do_enter_function_L1;
1010 default: fatalError ("Embedded object in string has unknown type");
1014 default: fatalError ("Unknown string table node type");
1016 // Start back at the root node again.
1017 goto resume_compressed_string_L7_bit_L6;
1020 // Push a 'resume function' call stub.
1022 PUSH (11); // DestType
1024 PUSH (READ_PC); // PC
1025 PUSH ((frame - base) * 4); // FramePtr
1027 // Load the string's type byte.
1028 L2 = memRead8(L1++);
1031 // Uncompressed string.
1033 goto resume_c_string_L7;
1035 else if (L2 == 0xE1)
1037 // Compressed string.
1040 goto resume_compressed_string_L7_bit_L6;
1042 else if (L2 == 0xE2)
1044 // Uncompressed Unicode string.
1045 L7 = L1 + 3; // Skip three padding bytes.
1046 goto resume_uni_string_L7;
1050 fatalError ("Value used in streamstr was not a string");
1056 if (ioMode == IO_NULL)
1057 { /* Do nothing */ }
1058 else if (ioMode == IO_GLK)
1060 unsigned char c = (L1 & 0xff);
1065 // Store this character in the args array.
1066 args [0] = (L1 & 0xff);
1067 // Push a 'resume function' call stub.
1069 PUSH (0); // DestType
1072 PUSH ((frame - base) * 4); // FramePtr
1073 // Call the filter function.
1076 goto do_enter_function_L1;
1082 if (ioMode == IO_NULL)
1083 { /* Do nothing */ }
1084 else if (ioMode == IO_GLK)
1086 #ifdef GLK_MODULE_UNICODE
1087 glk_put_char_uni ((glui32) L1);
1089 unsigned char c = (L1 > 0 && L1 < 256) ? L1 : '?';
1091 #endif // GLK_MODULE_UNICODE
1095 // Store this character in the args array.
1097 // Push a 'resume function' call stub.
1099 PUSH (0); // DestType
1102 PUSH ((frame - base) * 4); // FramePtr
1103 // Call the filter function.
1106 goto do_enter_function_L1;
1111 // Push a 'resume function' call stub.
1113 PUSH (11); // DestType
1115 PUSH (READ_PC); // PC
1116 PUSH ((frame - base) * 4); // FramePtr
1118 // Print the number.
1121 goto resume_number_L7_digit_L6;
1140 ioMode = (enum IOMode) L1;
1145 fatalError ("Illegal I/O mode");
1154 // Reset game memory to its initial state.
1155 resetMemory(protectPos, protectSize);
1157 // Reset all the stack pointers.
1158 frame = locals = values = sp = base;
1160 // Call the first function.
1161 L1 = startPos; // Initial PC.
1162 L2 = 0; // No arguments.
1163 goto do_enter_function_L1;
1166 S1 = verifyMemory();
1173 S1 = -(rand() % -L1);
1176 // The parameter is zero, so we should generate a
1177 // random number in "the full 32-bit range". The rand()
1178 // function might not cover the entire range, so we'll
1179 // generate the number with several calls.
1180 #if (RAND_MAX < 0xffff)
1181 S1 = rand() ^ (rand() << 12) ^ (rand() << 24);
1183 S1 = (rand() & 0xffff) | (rand() << 16);
1189 srand (L1 ? L1 : time(NULL));
1193 // The first argument is topmost in the stack; count is in L2.
1195 // We want to store the arguments in 'args' in the same order.
1196 for (L3 = 0 ; L3 < L2 ; ++L3)
1199 S1 = git_perform_glk (L1, L2, (glui32*) args);
1204 S1 = git_binary_search (L1, L2, L3, L4, L5, L6, L7);
1208 S1 = git_linear_search (L1, L2, L3, L4, L5, L6, L7);
1212 S1 = git_linked_search (L1, L2, L3, L4, L5, L6);
1216 S1 = gestalt (L1, L2);
1219 do_getstringtbl: S1 = stringTable; NEXT;
1220 do_setstringtbl: stringTable = L1; NEXT;
1223 // TODO: do something useful here.
1227 // We need to rotate the top L1 elements by L2 places.
1229 fatalError ("Negative number of elements to rotate in stkroll");
1230 if (L1 > (sp - values))
1231 fatalError ("Tried to rotate too many elements in stkroll");
1234 // Now, let's normalise L2 into the range [0..L1).
1238 L2 = L1 - (-L2 % L1);
1239 // Avoid trivial cases.
1240 if (L2 == 0 || L2 == L1)
1243 // The problem is reduced to swapping elements [0..L2) with
1244 // elements [L2..L1). Let's call these two sequences A and B,
1245 // so we need to transform AB into BA. We do this sneakily
1246 // with reversals, as follows: AB -> A'B -> A'B' -> (A'B')',
1247 // where X' is the reverse of the sequence X.
1249 do { L4 = sp[(x)-L1];sp[(x)-L1]=sp[(y)-L1];sp[(y)-L1]=L4; } while (0)
1252 for (L3 = 0 ; L3 < L2/2 ; ++L3)
1254 // Reverse [L2..L1).
1255 for (L3 = L2 ; L3 < (L2 + (L1-L2)/2) ; ++L3)
1256 SWAP (L3, L1-1-(L3-L2));
1258 for (L3 = 0 ; L3 < L1/2 ; ++L3)
1266 S1 = resizeMemory (L1, 0);
1274 // Memory management (new with glulx spec 3.1)
1278 if (L2 < gRamStart || (L2 + L1) > gEndMem)
1280 memset(gRam + L2, 0, L1);
1286 if (L2 < 0 || (L2 + L1) > gEndMem)
1288 if (L3 < gRamStart || (L3 + L1) > gEndMem)
1290 // ROM and ROM are stored separately, so this is a bit fiddly...
1291 if (L2 > gRamStart) {
1292 // Only need to copy from RAM. Might be overlapping, so use memmove.
1293 memmove(gRam + L3, gRam + L2, L1);
1294 } else if ((L2 + L1) <= gRamStart) {
1295 // Only need to copy from ROM. Can't overlap, so memcpy is safe.
1296 memcpy(gRam + L3, gRom + L2, L1);
1298 // Need to copy from both ROM and RAM.
1299 L4 = (L2 + L1) - gRamStart; // Amount of ROM to copy.
1300 memcpy(gRam + L3, gRom + L2, L4);
1301 memmove(gRam + L3 + L4, gRam + L2 + L4, L1 - L4);
1307 S1 = heap_alloc(L1);
1314 // Function acceleration (new with glulx spec 3.1.1)
1317 accel_set_func(L1, L2);
1321 accel_set_param(L1, L2);
1324 // Floating point (new with glulx spec 3.1.2)
1327 F1 = (git_float) L1;
\r
1328 S1 = ENCODE_FLOAT(F1);
\r
1332 F1 = DECODE_FLOAT(L1);
\r
1333 if (!signbit(F1)) {
\r
1334 if (isnan(F1) || isinf(F1) || (F1 > 2147483647.0))
\r
1337 S1 = (git_sint32) truncf(F1);
\r
1339 if (isnan(F1) || isinf(F1) || (F1 < -2147483647.0))
\r
1342 S1 = (git_sint32) truncf(F1);
\r
1347 F1 = DECODE_FLOAT(L1);
\r
1348 if (!signbit(F1)) {
\r
1349 if (isnan(F1) || isinf(F1) || (F1 > 2147483647.0))
\r
1352 S1 = (git_sint32) roundf(F1);
\r
1354 if (isnan(F1) || isinf(F1) || (F1 < -2147483647.0))
\r
1357 S1 = (git_sint32) roundf(F1);
\r
1362 F1 = ceilf(DECODE_FLOAT(L1));
\r
1363 L2 = ENCODE_FLOAT(F1);
\r
1364 if ((L2 == 0x0) || (L2 == 0x80000000))
\r
1365 L2 = L1 & 0x80000000;
\r
1370 F1 = floorf(DECODE_FLOAT(L1));
\r
1371 S1 = ENCODE_FLOAT(F1);
\r
1375 F1 = sqrtf(DECODE_FLOAT(L1));
\r
1376 S1 = ENCODE_FLOAT(F1);
\r
1380 F1 = expf(DECODE_FLOAT(L1));
\r
1381 S1 = ENCODE_FLOAT(F1);
\r
1385 F1 = logf(DECODE_FLOAT(L1));
\r
1386 S1 = ENCODE_FLOAT(F1);
\r
1390 #ifdef USE_OWN_POWF
\r
1391 F1 = git_powf(DECODE_FLOAT(L1), DECODE_FLOAT(L2));
\r
1393 F1 = powf(DECODE_FLOAT(L1), DECODE_FLOAT(L2));
\r
1395 S1 = ENCODE_FLOAT(F1);
\r
1399 F1 = atan2f(DECODE_FLOAT(L1), DECODE_FLOAT(L2));
\r
1400 S1 = ENCODE_FLOAT(F1);
\r
1404 F1 = DECODE_FLOAT(L1);
\r
1405 F2 = DECODE_FLOAT(L2);
\r
1406 F3 = fmodf(F1, F2);
\r
1407 F4 = (F1 - F3) / F2;
\r
1408 L4 = ENCODE_FLOAT(F4);
\r
1409 if ((L4 == 0) || (L4 == 0x80000000))
\r
1410 L4 = (L1 ^ L2) & 0x80000000;
\r
1411 S1 = ENCODE_FLOAT(F3);
\r
1416 F1 = sinf(DECODE_FLOAT(L1));
\r
1417 S1 = ENCODE_FLOAT(F1);
\r
1421 F1 = cosf(DECODE_FLOAT(L1));
\r
1422 S1 = ENCODE_FLOAT(F1);
\r
1426 F1 = tanf(DECODE_FLOAT(L1));
\r
1427 S1 = ENCODE_FLOAT(F1);
\r
1431 F1 = asinf(DECODE_FLOAT(L1));
\r
1432 S1 = ENCODE_FLOAT(F1);
\r
1436 F1 = acosf(DECODE_FLOAT(L1));
\r
1437 S1 = ENCODE_FLOAT(F1);
\r
1441 F1 = atanf(DECODE_FLOAT(L1));
\r
1442 S1 = ENCODE_FLOAT(F1);
\r
1445 // Special Git opcodes
1448 gCacheRAM = (L1 == 0) ? 0 : 1;
1452 pruneCodeCache (L1, L2);
1455 // Error conditions:
1457 do_error_bad_opcode:
1458 fatalError ("Illegal instruction");
1462 fatalError ("Stack overflow");
1466 fatalError ("Stack underflow");
1469 // ---------------------------------