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))
45 if ((L1 == 0x7F800000 || L1 == 0xFF800000) && (L2 == 0x7F800000 || L2 == 0xFF800000))
48 F1 = DECODE_FLOAT(L2) - DECODE_FLOAT(L1);
49 F2 = fabs(DECODE_FLOAT(L3));
50 return ((F1 <= F2) && (F1 >= -F2));
54 float git_powf(float x, float y)
58 else if ((y == 0.0f) || (y == -0.0f))
60 else if ((x == -1.0f) && isinf(y))
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.
235 if (L6 == 1 || L6 == 2)
236 fatalError("Short local variables are not supported, use Glulxe");
238 fatalError("Local variable wasn't 4 bytes wide");
240 L4 += L5; // Cumulative local count.
244 // Write out the stack frame.
245 // Recall that the number of locals is stored in L4.
249 PUSH (L4*4 + 12); // FrameLen
250 PUSH (12); // LocalsPos
254 L6 = (4 << 24) | (L4 << 16);
255 PUSH (L6); // format of locals
257 // This is where the local variables start, so:
260 // Read the arguments, based on the function type.
263 case 0xC0: // arguments should be placed on the stack.
264 // argc is in L2; we'll randomly use L5 as scratch.
266 // Initialise the local variables.
267 for ( ; L4 > 0 ; --L4)
269 // This is where the temporary values start, so:
271 // Push the args onto the stack.
272 for (L5 = 0 ; L5 < L2 ; ++L5)
274 // Push the arg count.
278 case 0xC1: // arguments should be written into locals.
279 // argc is in L2, num locals is in L4.
280 // Stuff as many locals as possible with arguments.
281 for (L5 = 1 ; L5 <= L2 && L4 > 0 ; ++L5, --L4)
282 PUSH (args [L2 - L5]);
283 // Initialise any remaining locals.
284 for ( ; L4 > 0 ; --L4)
286 // This is where the temporary values start, so:
291 // This isn't a function!
292 fatalError("Not a function");
296 // Start executing the function.
302 #define PEEPHOLE_STORE(tag, code) \
303 do_ ## tag ## _discard: code; NEXT; \
304 do_ ## tag ## _S1_stack: code; goto do_S1_stack; \
305 do_ ## tag ## _S1_local: code; goto do_S1_local; \
306 do_ ## tag ## _S1_addr: code; goto do_S1_addr
308 PEEPHOLE_STORE(add, S1 = L1 + L2);
309 PEEPHOLE_STORE(sub, S1 = L1 - L2);
310 PEEPHOLE_STORE(mul, S1 = L1 * L2);
311 PEEPHOLE_STORE(div, if (L2 == 0) fatalError ("Divide by zero"); S1 = L1 / L2);
312 PEEPHOLE_STORE(mod, if (L2 == 0) fatalError ("Divide by zero"); S1 = L1 % L2);
314 PEEPHOLE_STORE(neg, S1 = -L1);
315 PEEPHOLE_STORE(bitnot, S1 = ~L1);
317 PEEPHOLE_STORE(bitand, S1 = L1 & L2);
318 PEEPHOLE_STORE(bitor, S1 = L1 | L2);
319 PEEPHOLE_STORE(bitxor, S1 = L1 ^ L2);
321 PEEPHOLE_STORE(shiftl, if (L2 > 31 || L2 < 0) S1 = 0; else S1 = L1 << ((git_uint32) L2));
322 PEEPHOLE_STORE(sshiftr, if (L2 > 31 || L2 < 0) L2 = 31; S1 = ((git_sint32) L1) >> ((git_uint32) L2));
323 PEEPHOLE_STORE(ushiftr, if (L2 > 31 || L2 < 0) S1 = 0; else S1 = ((git_uint32) L1) >> ((git_uint32) L2));
325 PEEPHOLE_STORE(aload, S1 = memRead32 (L1 + (L2<<2)));
326 PEEPHOLE_STORE(aloads, S1 = memRead16 (L1 + (L2<<1)));
327 PEEPHOLE_STORE(aloadb, S1 = memRead8 (L1 + L2));
328 PEEPHOLE_STORE(aloadbit,S1 = (memRead8 (L1 + (L2>>3)) >> (L2 & 7)) & 1);
330 PEEPHOLE_STORE(copys, S1 = L1 & 0xFFFF);
331 PEEPHOLE_STORE(copyb, S1 = L1 & 0x00FF);
332 PEEPHOLE_STORE(sexs, S1 = (git_sint32)((signed short)(L1 & 0xFFFF)));
333 PEEPHOLE_STORE(sexb, S1 = (git_sint32)((signed char)(L1 & 0x00FF)));
335 PEEPHOLE_STORE(fadd, F1 = DECODE_FLOAT(L1) + DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
336 PEEPHOLE_STORE(fsub, F1 = DECODE_FLOAT(L1) - DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
337 PEEPHOLE_STORE(fmul, F1 = DECODE_FLOAT(L1) * DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
338 PEEPHOLE_STORE(fdiv, F1 = DECODE_FLOAT(L1) / DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
340 #define PEEPHOLE_LOAD(tag,reg) \
341 do_ ## tag ## _ ## reg ## _const: reg = READ_PC; goto do_ ## tag; \
342 do_ ## tag ## _ ## reg ## _stack: CHECK_USED(1); reg = POP; goto do_ ## tag; \
343 do_ ## tag ## _ ## reg ## _local: reg = LOCAL(READ_PC); goto do_ ## tag; \
344 do_ ## tag ## _ ## reg ## _addr: reg = memRead32(READ_PC); goto do_ ## tag
346 PEEPHOLE_LOAD (return, L1);
347 PEEPHOLE_LOAD (astore, L3);
348 PEEPHOLE_LOAD (astores, L3);
349 PEEPHOLE_LOAD (astoreb, L3);
350 PEEPHOLE_LOAD (astorebit, L3);
352 #undef PEEPHOLE_STORE
354 do_astore: memWrite32 (L1 + (L2<<2), L3); NEXT;
355 do_astores: memWrite16 (L1 + (L2<<1), L3); NEXT;
356 do_astoreb: memWrite8 (L1 + L2, L3); NEXT;
358 L4 = memRead8(L1 + (L2>>3));
360 L4 &= ~(1 << (L2 & 7));
362 L4 |= (1 << (L2 & 7));
363 memWrite8(L1 + (L2>>3), L4);
366 #define DO_JUMP(tag, reg, cond) \
367 do_ ## tag ## _var: L7 = READ_PC; if (cond) goto do_goto_ ## reg ## _from_L7; NEXT; \
368 do_ ## tag ## _const: L7 = READ_PC; if (cond) goto do_jump_abs_L7; NEXT; \
369 do_ ## tag ## _by: L7 = READ_PC; if (cond) pc += L7; NEXT; \
370 do_ ## tag ## _return0: if (cond) { L1 = 0; goto do_return; } NEXT; \
371 do_ ## tag ## _return1: if (cond) { L1 = 1; goto do_return; } NEXT
373 DO_JUMP(jump, L1, 1 == 1);
374 DO_JUMP(jz, L2, L1 == 0);
375 DO_JUMP(jnz, L2, L1 != 0);
376 DO_JUMP(jeq, L3, L1 == L2);
377 DO_JUMP(jne, L3, L1 != L2);
378 DO_JUMP(jlt, L3, L1 < L2);
379 DO_JUMP(jge, L3, L1 >= L2);
380 DO_JUMP(jgt, L3, L1 > L2);
381 DO_JUMP(jle, L3, L1 <= L2);
382 DO_JUMP(jltu, L3, ((git_uint32)L1 < (git_uint32)L2));
383 DO_JUMP(jgeu, L3, ((git_uint32)L1 >= (git_uint32)L2));
384 DO_JUMP(jgtu, L3, ((git_uint32)L1 > (git_uint32)L2));
385 DO_JUMP(jleu, L3, ((git_uint32)L1 <= (git_uint32)L2));
386 DO_JUMP(jisnan, L2, (((L1 & 0x7F800000) == 0x7F800000) && ((L1 & 0x007FFFFF) != 0)));
387 DO_JUMP(jisinf, L2, ((L1 == 0x7F800000) || (L1 == 0xFF800000)));
388 DO_JUMP(jflt, L3, DECODE_FLOAT(L1) < DECODE_FLOAT(L2));
389 DO_JUMP(jfge, L3, DECODE_FLOAT(L1) >= DECODE_FLOAT(L2));
390 DO_JUMP(jfgt, L3, DECODE_FLOAT(L1) > DECODE_FLOAT(L2));
391 DO_JUMP(jfle, L3, DECODE_FLOAT(L1) <= DECODE_FLOAT(L2));
392 DO_JUMP(jfeq, L4, floatCompare(L1, L2, L3) != 0);
393 DO_JUMP(jfne, L4, floatCompare(L1, L2, L3) == 0);
397 do_jumpabs: L7 = L1; goto do_jump_abs_L7; NEXT;
399 do_goto_L4_from_L7: L1 = L4; goto do_goto_L1_from_L7;
400 do_goto_L3_from_L7: L1 = L3; goto do_goto_L1_from_L7;
401 do_goto_L2_from_L7: L1 = L2; goto do_goto_L1_from_L7;
403 if (L1 == 0 || L1 == 1) goto do_return;
404 L7 = L7 + L1 - 2; goto do_jump_abs_L7;
407 // The first argument is topmost in the stack; the count is in L2.
409 // We want to store the arguments in 'args' in the same order.
410 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
414 // Specialised versions of above:
415 do_args_stack_call_stub_discard:
417 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
419 goto do_call_stub_discard;
421 do_args_stack_call_stub_addr:
423 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
425 goto do_call_stub_addr;
427 do_args_stack_call_stub_local:
429 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
431 goto do_call_stub_local;
433 do_args_stack_call_stub_stack:
435 for (L3 = L2 - 1 ; L3 >= 0 ; --L3)
437 goto do_call_stub_stack;
461 do_undo_stub_discard:
463 PUSH (0); // DestType
464 PUSH (0); // DestAddr
465 goto finish_undo_stub;
469 PUSH (1); // DestType
470 PUSH (READ_PC); // DestAddr
471 goto finish_undo_stub;
475 PUSH (2); // DestType
476 PUSH (READ_PC); // DestAddr
477 goto finish_undo_stub;
481 PUSH (3); // DestType
482 PUSH (0); // DestAddr
483 goto finish_undo_stub;
486 PUSH (READ_PC); // PC
487 PUSH ((frame - base) * 4); // FramePtr
490 goto do_pop_call_stub;
493 if (restoreUndo (base, protectPos, protectSize) == 0)
497 goto do_pop_call_stub;
502 do_save_stub_discard:
504 PUSH (0); // DestType
505 PUSH (0); // DestAddr
506 goto finish_save_stub;
510 PUSH (1); // DestType
511 PUSH (READ_PC); // DestAddr
512 goto finish_save_stub;
516 PUSH (2); // DestType
517 PUSH (READ_PC); // DestAddr
518 goto finish_save_stub;
522 PUSH (3); // DestType
523 PUSH (0); // DestAddr
524 goto finish_save_stub;
527 PUSH (READ_PC); // PC
528 PUSH ((frame - base) * 4); // FramePtr
529 if (ioMode == IO_GLK)
530 S1 = saveToFile (base, sp, L1);
533 goto do_pop_call_stub;
537 && restoreFromFile (base, L1, protectPos, protectSize) == 0)
541 goto do_pop_call_stub;
546 do_catch_stub_discard:
549 PUSH (0); // DestType
550 goto finish_catch_stub_addr_L7;
555 memWrite32(L7, (sp-base+4)*4);
556 PUSH (1); // DestType
557 goto finish_catch_stub_addr_L7;
562 LOCAL(L7 / 4) = (sp-base+4)*4;
563 PUSH (2); // DestType
564 goto finish_catch_stub_addr_L7;
568 PUSH (3); // DestType
569 PUSH (0); // DestAddr
570 PUSH (READ_PC); // PC
571 PUSH ((frame - base) * 4); // FramePtr
572 L7 = (sp - base)*4; // Catch token.
576 finish_catch_stub_addr_L7:
577 PUSH (L7); // DestAddr
578 PUSH (READ_PC); // PC
579 PUSH ((frame - base) * 4); // FramePtr
583 if (L2 < 16 || L2 > ((sp-base)*4))
584 fatalError ("Invalid catch token in throw");
586 goto do_pop_call_stub;
588 do_call_stub_discard:
590 PUSH (0); // DestType
591 PUSH (0); // DestAddr
592 goto finish_call_stub;
596 PUSH (1); // DestType
597 PUSH (READ_PC); // DestAddr
598 goto finish_call_stub;
602 PUSH (2); // DestType
603 PUSH (READ_PC); // DestAddr
604 goto finish_call_stub;
608 PUSH (3); // DestType
609 PUSH (0); // DestAddr
610 goto finish_call_stub;
613 PUSH (READ_PC); // PC
614 PUSH ((frame - base) * 4); // FramePtr
615 goto do_enter_function_L1;
618 // Zap the current stack frame, down to its call stub.
620 // Call the function!
621 goto do_enter_function_L1;
628 do_pop_call_stub:// L1 holds the return value.
632 // We just exited the top-level function.
635 // Something nasty happened.
636 goto stack_underflow;
638 L2 = POP; // FramePtr
640 L6 = POP; // DestAddr
641 switch (POP) // DestType
643 case 0: // Do not store.
644 frame = base + L2 / 4;
645 locals = frame + frame[1]/4;
646 values = frame + frame[0]/4;
649 case 1: // Store in main memory.
650 frame = base + L2 / 4;
651 locals = frame + frame[1]/4;
652 values = frame + frame[0]/4;
656 case 2: // Store in local variable.
657 frame = base + L2 / 4;
658 locals = frame + frame[1]/4;
659 values = frame + frame[0]/4;
663 case 3: // Push on stack.
664 frame = base + L2 / 4;
665 locals = frame + frame[1]/4;
666 values = frame + frame[0]/4;
670 case 10: // Resume printing a compressed (E1) string.
671 frame = base + L2 / 4;
672 locals = frame + frame[1]/4;
673 values = frame + frame[0]/4;
674 goto resume_compressed_string_L7_bit_L6;
676 case 11: // Resume executing function code after a string completes.
677 // Don't restore the frame pointer.
680 case 12: // Resume printing a signed decimal integer.
681 frame = base + L2 / 4;
682 locals = frame + frame[1]/4;
683 values = frame + frame[0]/4;
684 goto resume_number_L7_digit_L6;
686 case 13: // Resume printing a C-style (E0) string.
687 frame = base + L2 / 4;
688 locals = frame + frame[1]/4;
689 values = frame + frame[0]/4;
690 goto resume_c_string_L7;
692 case 14: // Resume printing a Unicode (E2) string.
693 frame = base + L2 / 4;
694 locals = frame + frame[1]/4;
695 values = frame + frame[0]/4;
696 goto resume_uni_string_L7;
699 fatalError("Bad call stub");
705 S1 = sp - values; NEXT;
708 if (L1 < 0 || L1 > (sp - values))
709 fatalError("Out of bounds in stkpeek");
710 S1 = sp[-1 - L1]; NEXT;
714 L1 = POP; L2 = POP; PUSH(L1); PUSH(L2); NEXT;
718 for (L2 = L1 ; L2 > 0 ; --L2)
725 resume_number_L7_digit_L6:
729 // If the IO mode is 'null', do nothing.
730 if (ioMode == IO_NULL)
731 goto do_pop_call_stub;
733 // Write the number into the buffer.
734 L1 = (L7 < 0) ? -L7 : L7; // Absolute value of number.
735 L2 = 0; // Current buffer position.
738 buffer [L2++] = '0' + (L1 % 10);
747 goto do_pop_call_stub; // We printed the whole number already.
749 // If we're in filter mode, push a call stub
750 // and filter the next character.
751 if (ioMode == IO_FILTER)
753 // Store the next character in the args array.
754 args[0] = buffer [L2 - L6 - 1];
757 // Push a call stub to print the next character.
759 PUSH(12); // DestType
760 PUSH(L6); // DestAddr (next digit)
761 PUSH(L7); // PC (number to print)
762 PUSH ((frame - base) * 4); // FramePtr
764 // Call the filter function.
767 goto do_enter_function_L1;
771 // We're in Glk mode. Just print all the characters.
772 for ( ; L6 < L2 ; ++L6)
773 glk_put_char (buffer [L2 - L6 - 1]);
776 goto do_pop_call_stub;
779 // If the IO mode is 'null', or if we've reached the
780 // end of the string, do nothing.
782 if (L2 == 0 || ioMode == IO_NULL)
783 goto do_pop_call_stub;
784 // Otherwise we're going to have to print something,
785 // If the IO mode is 'filter', filter the next char.
786 if (ioMode == IO_FILTER)
788 // Store this character in the args array.
792 PUSH(13); // DestType (resume C string)
793 PUSH(L6); // DestAddr (ignored)
794 PUSH(L7); // PC (next char to print)
795 PUSH ((frame - base) * 4); // FramePtr
796 // Call the filter function.
799 goto do_enter_function_L1;
801 // We're in Glk mode. Just print all the characters.
804 glk_put_char ((unsigned char) L2);
807 goto do_pop_call_stub;
809 resume_uni_string_L7:
810 // If the IO mode is 'null', or if we've reached the
811 // end of the string, do nothing.
814 if (L2 == 0 || ioMode == IO_NULL)
815 goto do_pop_call_stub;
816 // Otherwise we're going to have to print something,
817 // If the IO mode is 'filter', filter the next char.
818 if (ioMode == IO_FILTER)
820 // Store this character in the args array.
824 PUSH(14); // DestType (resume Unicode string)
825 PUSH(L6); // DestAddr (ignored)
826 PUSH(L7); // PC (next char to print)
827 PUSH ((frame - base) * 4); // FramePtr
828 // Call the filter function.
831 goto do_enter_function_L1;
833 // We're in Glk mode. Just print all the characters.
836 #ifdef GLK_MODULE_UNICODE
837 glk_put_char_uni ((glui32) L2);
839 unsigned char c = (L2 > 0 && L2 < 256) ? L2 : '?';
841 #endif // GLK_MODULE_UNICODE
845 goto do_pop_call_stub;
847 resume_compressed_string_L7_bit_L6:
848 // Load the first string table node into L1.
849 // Its address is stored at stringTable + 8.
850 L1 = memRead32 (stringTable + 8);
851 // Load the node's type byte.
852 L2 = memRead8 (L1++);
853 // Is the root node a branch?
856 // We'll keep a reservoir of input bits in L5.
858 // Keep following branch nodes until we hit a leaf node.
861 // Read the next bit.
863 // If we're finished reading this byte,
864 // move on to the next one.
870 // Follow the branch.
871 L1 = memRead32(L1 + 4 * L4);
872 L2 = memRead8 (L1++);
875 else if (L2 == 2 || L2 == 3)
877 // The root node prints a single character or a string.
878 // This will produce infinite output in the Null or Glk
879 // I/O modes, so we'll catch that here.
881 if (ioMode != IO_FILTER)
882 fatalError ("String table prints infinite strings!");
884 // In Filter mode, the output will be sent to the current
885 // filter function, which can change the string table
886 // before returning, so we'll continue and see what happens.
888 // We're at a leaf node.
891 case 1: // Terminator.
892 goto do_pop_call_stub;
894 case 2: // Single char.
895 if (ioMode == IO_NULL)
897 else if (ioMode == IO_GLK)
898 glk_put_char ((unsigned char) memRead8(L1));
901 // Store this character in the args array.
902 args [0] = memRead8(L1);
905 PUSH(10); // DestType
906 PUSH(L6); // DestAddr (bit number in string)
907 PUSH(L7); // PC (byte address in string)
908 PUSH ((frame - base) * 4); // FramePtr
909 // Call the filter function.
912 goto do_enter_function_L1;
917 // Push a 'resume compressed string' call stub.
919 PUSH (10); // DestType
920 PUSH (L6); // DestAddr (bit number in string)
921 PUSH (L7); // PC (byte address in string)
922 PUSH ((frame - base) * 4); // FramePtr
923 // Print the C string.
925 goto resume_c_string_L7;
927 case 4: // Unicode char
928 if (ioMode == IO_NULL)
930 else if (ioMode == IO_GLK)
932 #ifdef GLK_MODULE_UNICODE
933 glk_put_char_uni (memRead32(L1));
935 git_uint32 c = memRead32(L1);
936 if (c > 255) c = '?';
937 glk_put_char ((unsigned char) c);
938 #endif // GLK_MODULE_UNICODE
942 // Store this character in the args array.
943 args [0] = memRead32(L1);
946 PUSH(10); // DestType
947 PUSH(L6); // DestAddr (bit number in string)
948 PUSH(L7); // PC (byte address in string)
949 PUSH ((frame - base) * 4); // FramePtr
950 // Call the filter function.
953 goto do_enter_function_L1;
957 case 5: // Unicode string.
958 // Push a 'resume compressed string' call stub.
960 PUSH (10); // DestType
961 PUSH (L6); // DestAddr (bit number in string)
962 PUSH (L7); // PC (byte address in string)
963 PUSH ((frame - base) * 4); // FramePtr
964 // Print the Unicode string.
966 goto resume_uni_string_L7;
968 case 8: // Indirect reference.
970 L2 = 0; goto indirect_L3_args_L2;
972 case 9: // Double-indirect reference.
973 L3 = memRead32(L1); L3 = memRead32(L3);
974 L2 = 0; goto indirect_L3_args_L2;
976 case 10: // Indirect reference with args.
978 L2 = memRead32(L1 + 4); goto indirect_L3_args_L2;
980 case 11: // Double-indirect reference with args.
981 L3 = memRead32(L1); L3 = memRead32(L3);
982 L2 = memRead32(L1 + 4); goto indirect_L3_args_L2;
985 // Push a 'resume compressed string' call stub.
987 PUSH (10); // DestType
988 PUSH (L6); // DestAddr (bit number in string)
989 PUSH (L7); // PC (byte address in string)
990 PUSH ((frame - base) * 4); // FramePtr
991 // Check the type of the embedded object.
992 switch (memRead8(L3))
994 case 0xE0: // C string.
996 goto resume_c_string_L7;
998 case 0xE1: // Compressed string.
1001 goto resume_compressed_string_L7_bit_L6;
1003 case 0xE2: // Unicode string.
1004 L7 = L3 + 4; // Skip extra three padding bytes.
1005 goto resume_uni_string_L7;
1007 case 0xC0: case 0xC1: // Function.
1008 // Retrieve arguments.
1009 for (L1 += 8, L4 = L2; L4 > 0 ; --L4, L1+=4)
1010 args[L4-1] = memRead32(L1);
1013 goto do_enter_function_L1;
1015 default: fatalError ("Embedded object in string has unknown type");
1019 default: fatalError ("Unknown string table node type");
1021 // Start back at the root node again.
1022 goto resume_compressed_string_L7_bit_L6;
1025 // Push a 'resume function' call stub.
1027 PUSH (11); // DestType
1029 PUSH (READ_PC); // PC
1030 PUSH ((frame - base) * 4); // FramePtr
1032 // Load the string's type byte.
1033 L2 = memRead8(L1++);
1036 // Uncompressed string.
1038 goto resume_c_string_L7;
1040 else if (L2 == 0xE1)
1042 // Compressed string.
1045 goto resume_compressed_string_L7_bit_L6;
1047 else if (L2 == 0xE2)
1049 // Uncompressed Unicode string.
1050 L7 = L1 + 3; // Skip three padding bytes.
1051 goto resume_uni_string_L7;
1055 fatalError ("Value used in streamstr was not a string");
1061 if (ioMode == IO_NULL)
1062 { /* Do nothing */ }
1063 else if (ioMode == IO_GLK)
1065 unsigned char c = (L1 & 0xff);
1070 // Store this character in the args array.
1071 args [0] = (L1 & 0xff);
1072 // Push a 'resume function' call stub.
1074 PUSH (0); // DestType
1077 PUSH ((frame - base) * 4); // FramePtr
1078 // Call the filter function.
1081 goto do_enter_function_L1;
1087 if (ioMode == IO_NULL)
1088 { /* Do nothing */ }
1089 else if (ioMode == IO_GLK)
1091 #ifdef GLK_MODULE_UNICODE
1092 glk_put_char_uni ((glui32) L1);
1094 unsigned char c = (L1 > 0 && L1 < 256) ? L1 : '?';
1096 #endif // GLK_MODULE_UNICODE
1100 // Store this character in the args array.
1102 // Push a 'resume function' call stub.
1104 PUSH (0); // DestType
1107 PUSH ((frame - base) * 4); // FramePtr
1108 // Call the filter function.
1111 goto do_enter_function_L1;
1116 // Push a 'resume function' call stub.
1118 PUSH (11); // DestType
1120 PUSH (READ_PC); // PC
1121 PUSH ((frame - base) * 4); // FramePtr
1123 // Print the number.
1126 goto resume_number_L7_digit_L6;
1145 ioMode = (enum IOMode) L1;
1150 fatalError ("Illegal I/O mode");
1159 // Reset game memory to its initial state.
1160 resetMemory(protectPos, protectSize);
1162 // Reset all the stack pointers.
1163 frame = locals = values = sp = base;
1165 // Call the first function.
1166 L1 = startPos; // Initial PC.
1167 L2 = 0; // No arguments.
1168 goto do_enter_function_L1;
1171 S1 = verifyMemory();
1178 S1 = -(rand() % -L1);
1181 // The parameter is zero, so we should generate a
1182 // random number in "the full 32-bit range". The rand()
1183 // function might not cover the entire range, so we'll
1184 // generate the number with several calls.
1185 #if (RAND_MAX < 0xffff)
1186 S1 = rand() ^ (rand() << 12) ^ (rand() << 24);
1188 S1 = (rand() & 0xffff) | (rand() << 16);
1194 srand (L1 ? L1 : time(NULL));
1198 // The first argument is topmost in the stack; count is in L2.
1200 // We want to store the arguments in 'args' in the same order.
1201 for (L3 = 0 ; L3 < L2 ; ++L3)
1204 S1 = git_perform_glk (L1, L2, (glui32*) args);
1209 S1 = git_binary_search (L1, L2, L3, L4, L5, L6, L7);
1213 S1 = git_linear_search (L1, L2, L3, L4, L5, L6, L7);
1217 S1 = git_linked_search (L1, L2, L3, L4, L5, L6);
1221 S1 = gestalt (L1, L2);
1224 do_getstringtbl: S1 = stringTable; NEXT;
1225 do_setstringtbl: stringTable = L1; NEXT;
1228 // TODO: do something useful here.
1232 // We need to rotate the top L1 elements by L2 places.
1234 fatalError ("Negative number of elements to rotate in stkroll");
1235 if (L1 > (sp - values))
1236 fatalError ("Tried to rotate too many elements in stkroll");
1239 // Now, let's normalise L2 into the range [0..L1).
1243 L2 = L1 - (-L2 % L1);
1244 // Avoid trivial cases.
1245 if (L2 == 0 || L2 == L1)
1248 // The problem is reduced to swapping elements [0..L2) with
1249 // elements [L2..L1). Let's call these two sequences A and B,
1250 // so we need to transform AB into BA. We do this sneakily
1251 // with reversals, as follows: AB -> A'B -> A'B' -> (A'B')',
1252 // where X' is the reverse of the sequence X.
1254 do { L4 = sp[(x)-L1];sp[(x)-L1]=sp[(y)-L1];sp[(y)-L1]=L4; } while (0)
1257 for (L3 = 0 ; L3 < L2/2 ; ++L3)
1259 // Reverse [L2..L1).
1260 for (L3 = L2 ; L3 < (L2 + (L1-L2)/2) ; ++L3)
1261 SWAP (L3, L1-1-(L3-L2));
1263 for (L3 = 0 ; L3 < L1/2 ; ++L3)
1271 S1 = resizeMemory (L1, 0);
1279 // Memory management (new with glulx spec 3.1)
1283 if (L2 < gRamStart || (L2 + L1) > gEndMem)
1285 memset(gRam + L2, 0, L1);
1291 if (L2 < 0 || (L2 + L1) > gEndMem)
1293 if (L3 < gRamStart || (L3 + L1) > gEndMem)
1295 // ROM and ROM are stored separately, so this is a bit fiddly...
1296 if (L2 > gRamStart) {
1297 // Only need to copy from RAM. Might be overlapping, so use memmove.
1298 memmove(gRam + L3, gRam + L2, L1);
1299 } else if ((L2 + L1) <= gRamStart) {
1300 // Only need to copy from ROM. Can't overlap, so memcpy is safe.
1301 memcpy(gRam + L3, gRom + L2, L1);
1303 // Need to copy from both ROM and RAM.
1304 L4 = (L2 + L1) - gRamStart; // Amount of ROM to copy.
1305 memcpy(gRam + L3, gRom + L2, L4);
1306 memmove(gRam + L3 + L4, gRam + L2 + L4, L1 - L4);
1312 S1 = heap_alloc(L1);
1319 // Function acceleration (new with glulx spec 3.1.1)
1322 accel_set_func(L1, L2);
1326 accel_set_param(L1, L2);
1329 // Floating point (new with glulx spec 3.1.2)
1332 F1 = (git_float) L1;
1333 S1 = ENCODE_FLOAT(F1);
1337 F1 = DECODE_FLOAT(L1);
1339 if (isnan(F1) || isinf(F1) || (F1 > 2147483647.0))
1342 S1 = (git_sint32) truncf(F1);
1344 if (isnan(F1) || isinf(F1) || (F1 < -2147483647.0))
1347 S1 = (git_sint32) truncf(F1);
1352 F1 = DECODE_FLOAT(L1);
1354 if (isnan(F1) || isinf(F1) || (F1 > 2147483647.0))
1357 S1 = (git_sint32) roundf(F1);
1359 if (isnan(F1) || isinf(F1) || (F1 < -2147483647.0))
1362 S1 = (git_sint32) roundf(F1);
1367 F1 = ceilf(DECODE_FLOAT(L1));
1368 L2 = ENCODE_FLOAT(F1);
1369 if ((L2 == 0x0) || (L2 == 0x80000000))
1370 L2 = L1 & 0x80000000;
1375 F1 = floorf(DECODE_FLOAT(L1));
1376 S1 = ENCODE_FLOAT(F1);
1380 F1 = sqrtf(DECODE_FLOAT(L1));
1381 S1 = ENCODE_FLOAT(F1);
1385 F1 = expf(DECODE_FLOAT(L1));
1386 S1 = ENCODE_FLOAT(F1);
1390 F1 = logf(DECODE_FLOAT(L1));
1391 S1 = ENCODE_FLOAT(F1);
1396 F1 = git_powf(DECODE_FLOAT(L1), DECODE_FLOAT(L2));
1398 F1 = powf(DECODE_FLOAT(L1), DECODE_FLOAT(L2));
1400 S1 = ENCODE_FLOAT(F1);
1404 F1 = atan2f(DECODE_FLOAT(L1), DECODE_FLOAT(L2));
1405 S1 = ENCODE_FLOAT(F1);
1409 F1 = DECODE_FLOAT(L1);
1410 F2 = DECODE_FLOAT(L2);
1412 F4 = (F1 - F3) / F2;
1413 L4 = ENCODE_FLOAT(F4);
1414 if ((L4 == 0) || (L4 == 0x80000000))
1415 L4 = (L1 ^ L2) & 0x80000000;
1416 S1 = ENCODE_FLOAT(F3);
1421 F1 = sinf(DECODE_FLOAT(L1));
1422 S1 = ENCODE_FLOAT(F1);
1426 F1 = cosf(DECODE_FLOAT(L1));
1427 S1 = ENCODE_FLOAT(F1);
1431 F1 = tanf(DECODE_FLOAT(L1));
1432 S1 = ENCODE_FLOAT(F1);
1436 F1 = asinf(DECODE_FLOAT(L1));
1437 S1 = ENCODE_FLOAT(F1);
1441 F1 = acosf(DECODE_FLOAT(L1));
1442 S1 = ENCODE_FLOAT(F1);
1446 F1 = atanf(DECODE_FLOAT(L1));
1447 S1 = ENCODE_FLOAT(F1);
1450 // Special Git opcodes
1453 gCacheRAM = (L1 == 0) ? 0 : 1;
1457 pruneCodeCache (L1, L2);
1460 // Error conditions:
1462 do_error_bad_opcode:
1463 fatalError ("Illegal instruction");
1467 fatalError ("Stack overflow");
1471 fatalError ("Stack underflow");
1474 // ---------------------------------