Updated interpreters
[projects/chimara/chimara.git] / interpreters / git / terp.c
index 8377c5d8b8a7ef585b4a39460fc526e3ab41e5cd..870b4f11fef8d9cde3683bde5bf1a3c5db533ae6 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "git.h"
 #include <assert.h>
+#include <math.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -29,6 +30,39 @@ Opcode* gOpcodeTable;
 #define CHECK_FREE(n) if ((top - sp) < (n)) goto stack_overflow
 #define CHECK_USED(n) if ((sp - values) < (n)) goto stack_underflow
 
+// -------------------------------------------------------------
+// Floating point support
+
+#define ENCODE_FLOAT(f) (* (git_uint32*) &f)
+#define DECODE_FLOAT(n) (* (git_float*) &n)
+
+int floatCompare(git_sint32 L1, git_sint32 L2, git_sint32 L3)
+{
+  git_float F1, F2;\r
+\r
+  if (((L3 & 0x7F800000) == 0x7F800000) && ((L3 & 0x007FFFFF) != 0))\r
+    return 0;\r
+  if ((L1 == 0x7F800000 || L1 == 0xFF800000) && (L2 == 0x7F800000 || L2 == 0xFF800000))\r
+    return (L1 == L2);\r
+\r
+  F1 = DECODE_FLOAT(L2) - DECODE_FLOAT(L1);\r
+  F2 = fabs(DECODE_FLOAT(L3));\r
+  return ((F1 <= F2) && (F1 >= -F2));\r
+}
+
+#ifdef USE_OWN_POWF\r
+float git_powf(float x, float y)\r
+{\r
+  if (x == 1.0f)\r
+    return 1.0f;\r
+  else if ((y == 0.0f) || (y == -0.0f))\r
+    return 1.0f;\r
+  else if ((x == -1.0f) && isinf(y))\r
+    return 1.0f;\r
+  return powf(x,y);\r
+}\r
+#endif
+
 // -------------------------------------------------------------
 // Functions
 
@@ -39,6 +73,7 @@ void startProgram (size_t cacheSize, enum IOMode ioMode)
     git_sint32 L1=0, L2=0, L3=0, L4=0, L5=0, L6=0, L7=0;
 #define S1 L1
 #define S2 L2
+    git_float F1=0.0f, F2=0.0f, F3=0.0f, F4=0.0f;
 
     git_sint32* base;   // Bottom of the stack.
     git_sint32* frame;  // Bottom of the current stack frame.
@@ -278,9 +313,9 @@ do_enter_function_L1: // Arg count is in L2.
     PEEPHOLE_STORE(bitor,   S1 = L1 | L2);
     PEEPHOLE_STORE(bitxor,  S1 = L1 ^ L2);
 
-    PEEPHOLE_STORE(shiftl,  if (L2 > 31) S1 = 0; else S1 = L1 << ((git_uint32) L2));
-    PEEPHOLE_STORE(sshiftr, if (L2 > 31) L2 = 31; S1 = ((git_sint32) L1) >> ((git_uint32) L2));
-    PEEPHOLE_STORE(ushiftr, if (L2 > 31) S1 = 0; else S1 = ((git_uint32) L1) >> ((git_uint32) L2));
+    PEEPHOLE_STORE(shiftl,  if (L2 > 31 || L2 < 0) S1 = 0; else S1 = L1 << ((git_uint32) L2));
+    PEEPHOLE_STORE(sshiftr, if (L2 > 31 || L2 < 0) L2 = 31; S1 = ((git_sint32) L1) >> ((git_uint32) L2));
+    PEEPHOLE_STORE(ushiftr, if (L2 > 31 || L2 < 0) S1 = 0; else S1 = ((git_uint32) L1) >> ((git_uint32) L2));
 
     PEEPHOLE_STORE(aload,   S1 = memRead32 (L1 + (L2<<2)));
     PEEPHOLE_STORE(aloads,  S1 = memRead16 (L1 + (L2<<1)));
@@ -292,6 +327,11 @@ do_enter_function_L1: // Arg count is in L2.
     PEEPHOLE_STORE(sexs,    S1 = (git_sint32)((signed short)(L1 & 0xFFFF)));
     PEEPHOLE_STORE(sexb,    S1 = (git_sint32)((signed char)(L1 & 0x00FF)));
 
+    PEEPHOLE_STORE(fadd,    F1 = DECODE_FLOAT(L1) + DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
+    PEEPHOLE_STORE(fsub,    F1 = DECODE_FLOAT(L1) - DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
+    PEEPHOLE_STORE(fmul,    F1 = DECODE_FLOAT(L1) * DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));
+    PEEPHOLE_STORE(fdiv,    F1 = DECODE_FLOAT(L1) / DECODE_FLOAT(L2); S1 = ENCODE_FLOAT(F1));\r
+
 #define PEEPHOLE_LOAD(tag,reg) \
     do_ ## tag ## _ ## reg ## _const: reg = READ_PC; goto do_ ## tag; \
     do_ ## tag ## _ ## reg ## _stack: CHECK_USED(1); reg = POP; goto do_ ## tag; \
@@ -325,24 +365,33 @@ do_enter_function_L1: // Arg count is in L2.
     do_ ## tag ## _return0: if (cond) { L1 = 0; goto do_return; } NEXT;                     \
     do_ ## tag ## _return1: if (cond) { L1 = 1; goto do_return; } NEXT
     
-    DO_JUMP(jump, L1, 1 == 1);
-    DO_JUMP(jz,   L2, L1 == 0);
-    DO_JUMP(jnz,  L2, L1 != 0);
-    DO_JUMP(jeq,  L3, L1 == L2);
-    DO_JUMP(jne,  L3, L1 != L2);
-    DO_JUMP(jlt,  L3, L1 < L2);
-    DO_JUMP(jge,  L3, L1 >= L2);
-    DO_JUMP(jgt,  L3, L1 > L2);
-    DO_JUMP(jle,  L3, L1 <= L2);
-    DO_JUMP(jltu, L3, ((git_uint32)L1 < (git_uint32)L2));
-    DO_JUMP(jgeu, L3, ((git_uint32)L1 >= (git_uint32)L2));
-    DO_JUMP(jgtu, L3, ((git_uint32)L1 > (git_uint32)L2));
-    DO_JUMP(jleu, L3, ((git_uint32)L1 <= (git_uint32)L2));
+    DO_JUMP(jump,   L1, 1 == 1);
+    DO_JUMP(jz,     L2, L1 == 0);
+    DO_JUMP(jnz,    L2, L1 != 0);
+    DO_JUMP(jeq,    L3, L1 == L2);
+    DO_JUMP(jne,    L3, L1 != L2);
+    DO_JUMP(jlt,    L3, L1 < L2);
+    DO_JUMP(jge,    L3, L1 >= L2);
+    DO_JUMP(jgt,    L3, L1 > L2);
+    DO_JUMP(jle,    L3, L1 <= L2);
+    DO_JUMP(jltu,   L3, ((git_uint32)L1 < (git_uint32)L2));
+    DO_JUMP(jgeu,   L3, ((git_uint32)L1 >= (git_uint32)L2));
+    DO_JUMP(jgtu,   L3, ((git_uint32)L1 > (git_uint32)L2));
+    DO_JUMP(jleu,   L3, ((git_uint32)L1 <= (git_uint32)L2));
+    DO_JUMP(jisnan, L2, (((L1 & 0x7F800000) == 0x7F800000) && ((L1 & 0x007FFFFF) != 0)));
+    DO_JUMP(jisinf, L2, ((L1 == 0x7F800000) || (L1 == 0xFF800000)));
+    DO_JUMP(jflt,   L3, DECODE_FLOAT(L1) < DECODE_FLOAT(L2));
+    DO_JUMP(jfge,   L3, DECODE_FLOAT(L1) >= DECODE_FLOAT(L2));
+    DO_JUMP(jfgt,   L3, DECODE_FLOAT(L1) > DECODE_FLOAT(L2));
+    DO_JUMP(jfle,   L3, DECODE_FLOAT(L1) <= DECODE_FLOAT(L2));
+    DO_JUMP(jfeq,   L4, floatCompare(L1, L2, L3) != 0);
+    DO_JUMP(jfne,   L4, floatCompare(L1, L2, L3) == 0);
 
 #undef DO_JUMP
 
     do_jumpabs: L7 = L1; goto do_jump_abs_L7; NEXT;
 
+    do_goto_L4_from_L7: L1 = L4; goto do_goto_L1_from_L7;
     do_goto_L3_from_L7: L1 = L3; goto do_goto_L1_from_L7;
     do_goto_L2_from_L7: L1 = L2; goto do_goto_L1_from_L7;
     do_goto_L1_from_L7:
@@ -505,7 +554,7 @@ finish_save_stub:
     do_catch_stub_local:
         CHECK_FREE(4);
         L7 = READ_PC;
-        memWrite32(L7, (sp-base+4)*4);
+        LOCAL(L7 / 4) = (sp-base+4)*4;
         PUSH (2);       // DestType
         goto finish_catch_stub_addr_L7;
 
@@ -952,8 +1001,8 @@ do_tailcall:
 
                     case 0xC0: case 0xC1: // Function.
                         // Retrieve arguments.
-                        for (L1 += 8, L4 = 0; L4 < L2 ; ++L4, L1+=4)
-                            args[L4] = memRead32(L1);
+                        for (L1 += 8, L4 = L2; L4 > 0 ; --L4, L1+=4)
+                            args[L4-1] = memRead32(L1);
                         // Enter function.
                         L1 = L3;
                         goto do_enter_function_L1;
@@ -1104,7 +1153,6 @@ do_tailcall:
     do_restart:
         // Reset game memory to its initial state.
         resetMemory(protectPos, protectSize);
-        resetUndo();
 
         // Reset all the stack pointers.
         frame = locals = values = sp = base;
@@ -1128,8 +1176,12 @@ do_tailcall:
             // The parameter is zero, so we should generate a
             // random number in "the full 32-bit range". The rand()
             // function might not cover the entire range, so we'll
-            // generate the high 16 bits and low 16 bits separately.
+            // generate the number with several calls.
+#if (RAND_MAX < 0xffff)
+            S1 = rand() ^ (rand() << 12) ^ (rand() << 24);
+#else
             S1 = (rand() & 0xffff) | (rand() << 16);
+#endif
         }
         NEXT;
 
@@ -1177,13 +1229,15 @@ do_tailcall:
             fatalError ("Negative number of elements to rotate in stkroll");
         if (L1 > (sp - values))
             fatalError ("Tried to rotate too many elements in stkroll");
+        if (L1 == 0)
+            NEXT;
         // Now, let's normalise L2 into the range [0..L1).
         if (L2 >= 0)
             L2 = L2 % L1;
         else
             L2 = L1 - (-L2 % L1);
         // Avoid trivial cases.
-        if (L1 == 0 || L2 == 0 || L2 == L1)
+        if (L2 == 0 || L2 == L1)
             NEXT;
         L2 = L1 - L2;
         // The problem is reduced to swapping elements [0..L2) with
@@ -1267,6 +1321,127 @@ do_tailcall:
         accel_set_param(L1, L2);
         NEXT;
         
+    // Floating point (new with glulx spec 3.1.2)
+
+    do_numtof:\r
+        F1 = (git_float) L1;\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_ftonumz:\r
+        F1 = DECODE_FLOAT(L1);\r
+        if (!signbit(F1)) {\r
+          if (isnan(F1) || isinf(F1) || (F1 > 2147483647.0))\r
+            S1 = 0x7FFFFFFF;\r
+          else\r
+            S1 = (git_sint32) truncf(F1);\r
+        } else {\r
+          if (isnan(F1) || isinf(F1) || (F1 < -2147483647.0))\r
+            S1 = 0x80000000;\r
+          else\r
+            S1 = (git_sint32) truncf(F1);\r
+        }\r
+        NEXT;\r
+\r
+    do_ftonumn:\r
+        F1 = DECODE_FLOAT(L1);\r
+        if (!signbit(F1)) {\r
+          if (isnan(F1) || isinf(F1) || (F1 > 2147483647.0))\r
+            S1 = 0x7FFFFFFF;\r
+          else\r
+            S1 = (git_sint32) roundf(F1);\r
+        } else {\r
+          if (isnan(F1) || isinf(F1) || (F1 < -2147483647.0))\r
+            S1 = 0x80000000;\r
+          else\r
+            S1 = (git_sint32) roundf(F1);\r
+        }\r
+        NEXT;\r
+\r
+    do_ceil:\r
+        F1 = ceilf(DECODE_FLOAT(L1));\r
+        L2 = ENCODE_FLOAT(F1);\r
+        if ((L2 == 0x0) || (L2 == 0x80000000))\r
+          L2 = L1 & 0x80000000;\r
+        S1 = L2;\r
+        NEXT;\r
+\r
+    do_floor:\r
+        F1 = floorf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_sqrt:\r
+        F1 = sqrtf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_exp:\r
+        F1 = expf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_log:\r
+        F1 = logf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_pow:\r
+#ifdef USE_OWN_POWF\r
+        F1 = git_powf(DECODE_FLOAT(L1), DECODE_FLOAT(L2));\r
+#else\r
+        F1 = powf(DECODE_FLOAT(L1), DECODE_FLOAT(L2));\r
+#endif\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_atan2:\r
+        F1 = atan2f(DECODE_FLOAT(L1), DECODE_FLOAT(L2));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_fmod:\r
+        F1 = DECODE_FLOAT(L1);\r
+        F2 = DECODE_FLOAT(L2);\r
+        F3 = fmodf(F1, F2);\r
+        F4 = (F1 - F3) / F2;\r
+        L4 = ENCODE_FLOAT(F4);\r
+        if ((L4 == 0) || (L4 == 0x80000000))\r
+          L4 = (L1 ^ L2) & 0x80000000;\r
+        S1 = ENCODE_FLOAT(F3);\r
+        S2 = L4;\r
+        NEXT;\r
+\r
+    do_sin:\r
+        F1 = sinf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_cos:\r
+        F1 = cosf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_tan:\r
+        F1 = tanf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_asin:\r
+        F1 = asinf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_acos:\r
+        F1 = acosf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+\r
+    do_atan:\r
+        F1 = atanf(DECODE_FLOAT(L1));\r
+        S1 = ENCODE_FLOAT(F1);\r
+        NEXT;\r
+
     // Special Git opcodes
     
     do_git_setcacheram: