In /vm_test.asm add floating-point printing routine, in /vm.c fix order of operands...
authorNick Downing <nick@ndcode.org>
Mon, 18 Dec 2023 06:11:48 +0000 (17:11 +1100)
committerNick Downing <nick@ndcode.org>
Mon, 18 Dec 2023 06:13:29 +0000 (17:13 +1100)
vm.c
vm_asm.py
vm_test.asm

diff --git a/vm.c b/vm.c
index 26c5ad6..2184a1d 100644 (file)
--- a/vm.c
+++ b/vm.c
@@ -111,6 +111,10 @@ enum op {
   OP_DIV_R,
   OP_DIV_U,
   OP_DIV_U_R,
+  OP_MOD,
+  OP_MOD_R,
+  OP_MOD_U,
+  OP_MOD_U_R,
   OP_SHL_I8,
   OP_SHL_I16,
   OP_SHL_I32,
@@ -261,6 +265,10 @@ char *mnemonics[N_OP] = {
   "div.r",
   "div.u",
   "div.u.r",
+  "mod",
+  "mod.r",
+  "mod.u",
+  "mod.u.r",
   "shl.i8",
   "shl.i16",
   "shl.i32",
@@ -384,7 +392,7 @@ int main(int argc, char **argv) {
   iy = 0;
   while (true) {
     enum op op = (uint8_t)mem->i8[pc++ & mem_mask];
-    //fprintf(stderr, "w=%08x(%d) sp=%08x(%08x) pc=%08x(%02x %s)\n", w_reg.i32, w_type, sp, mem->i32[sp >> 2], pc - 1, op, op < N_OP ? mnemonics[op] : "???");
+    //fprintf(stderr, "w=%08x(%d) sp=%08x ix=%08x iy=%08x pc=%08x(%02x %s)\n", w_reg.i32, w_type, sp, ix, iy, pc - 1, op, op < N_OP ? mnemonics[op] : "???");
     switch (op) {
     // w register access
     case OP_IMM_I8:
@@ -1327,41 +1335,41 @@ int main(int argc, char **argv) {
     case OP_SUB:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 -= mem->i8[sp++ & mem_mask];
+        w_reg.i8 = mem->i8[sp++ & mem_mask] - w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i16 -= mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i16 = mem->i16[(sp & mem_mask) >> 1] - w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i32 -= mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i32 = mem->i32[(sp & mem_mask) >> 2] - w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i64 -= mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i64 = mem->i64[(sp & mem_mask) >> 3] - w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i128 -= mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i128 = mem->i128[(sp & mem_mask) >> 4] - w_reg.i128;
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.f32 -= mem->f32[(sp & mem_mask) >> 2];
+        w_reg.f32 = mem->f32[(sp & mem_mask) >> 2] - w_reg.f32;
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.f64 -= mem->f64[(sp & mem_mask) >> 3];
+        w_reg.f64 = mem->f64[(sp & mem_mask) >> 3] - w_reg.f64;
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.f128 -= mem->f128[(sp & mem_mask) >> 4];
+        w_reg.f128 = mem->f128[(sp & mem_mask) >> 4] - w_reg.f128;
         sp += 0x10;
         break;
       default:
@@ -1371,41 +1379,41 @@ int main(int argc, char **argv) {
     case OP_SUB_R:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = mem->i8[sp++ & mem_mask] - w_reg.i8;
+        w_reg.i8 -= mem->i8[sp++ & mem_mask];
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i16 = mem->i16[(sp & mem_mask) >> 1] - w_reg.i16;
+        w_reg.i16 -= mem->i16[(sp & mem_mask) >> 1];
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i32 = mem->i32[(sp & mem_mask) >> 2] - w_reg.i32;
+        w_reg.i32 -= mem->i32[(sp & mem_mask) >> 2];
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i64 = mem->i64[(sp & mem_mask) >> 3] - w_reg.i64;
+        w_reg.i64 -= mem->i64[(sp & mem_mask) >> 3];
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i128 = mem->i128[(sp & mem_mask) >> 4] - w_reg.i128;
+        w_reg.i128 -= mem->i128[(sp & mem_mask) >> 4];
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.f32 = mem->f32[(sp & mem_mask) >> 2] - w_reg.f32;
+        w_reg.f32 -= mem->f32[(sp & mem_mask) >> 2];
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.f64 = mem->f64[(sp & mem_mask) >> 3] - w_reg.f64;
+        w_reg.f64 -= mem->f64[(sp & mem_mask) >> 3];
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.f128 = mem->f128[(sp & mem_mask) >> 4] - w_reg.f128;
+        w_reg.f128 -= mem->f128[(sp & mem_mask) >> 4];
         sp += 0x10;
         break;
       default:
@@ -1459,41 +1467,41 @@ int main(int argc, char **argv) {
     case OP_DIV:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 /= mem->i8[sp++ & mem_mask];
+        w_reg.i8 = mem->i8[sp++ & mem_mask] / w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i16 /= mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i16 = mem->i16[(sp & mem_mask) >> 1] / w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i32 /= mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i32 = mem->i32[(sp & mem_mask) >> 2] / w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i64 /= mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i64 = mem->i64[(sp & mem_mask) >> 3] / w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i128 /= mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i128 = mem->i128[(sp & mem_mask) >> 4] / w_reg.i128;
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.f32 /= mem->f32[(sp & mem_mask) >> 2];
+        w_reg.f32 = mem->f32[(sp & mem_mask) >> 2] / w_reg.f32;
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.f64 /= mem->f64[(sp & mem_mask) >> 3];
+        w_reg.f64 = mem->f64[(sp & mem_mask) >> 3] / w_reg.f64;
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.f128 /= mem->f128[(sp & mem_mask) >> 4];
+        w_reg.f128 = mem->f128[(sp & mem_mask) >> 4] / w_reg.f128;
         sp += 0x10;
         break;
       default:
@@ -1503,41 +1511,41 @@ int main(int argc, char **argv) {
     case OP_DIV_R:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = mem->i8[sp++ & mem_mask] / w_reg.i8;
+        w_reg.i8 /= mem->i8[sp++ & mem_mask];
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i16 = mem->i16[(sp & mem_mask) >> 1] / w_reg.i16;
+        w_reg.i16 /= mem->i16[(sp & mem_mask) >> 1];
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i32 = mem->i32[(sp & mem_mask) >> 2] / w_reg.i32;
+        w_reg.i32 /= mem->i32[(sp & mem_mask) >> 2];
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i64 = mem->i64[(sp & mem_mask) >> 3] / w_reg.i64;
+        w_reg.i64 /= mem->i64[(sp & mem_mask) >> 3];
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i128 = mem->i128[(sp & mem_mask) >> 4] / w_reg.i128;
+        w_reg.i128 /= mem->i128[(sp & mem_mask) >> 4];
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.f32 = mem->f32[(sp & mem_mask) >> 2] / w_reg.f32;
+        w_reg.f32 /= mem->f32[(sp & mem_mask) >> 2];
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.f64 = mem->f64[(sp & mem_mask) >> 3] / w_reg.f64;
+        w_reg.f64 /= mem->f64[(sp & mem_mask) >> 3];
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.f128 = mem->f128[(sp & mem_mask) >> 4] / w_reg.f128;
+        w_reg.f128 /= mem->f128[(sp & mem_mask) >> 4];
         sp += 0x10;
         break;
       default:
@@ -1545,6 +1553,35 @@ int main(int argc, char **argv) {
       }
       break;
     case OP_DIV_U:
+      switch (w_type) {
+      case W_TYPE_I8:
+        w_reg.i8 = (int8_t)((uint8_t)mem->i8[sp++ & mem_mask] / (uint8_t)w_reg.i8);
+        break;
+      case W_TYPE_I16:
+        sp = (sp + 1) & ~1;
+        w_reg.i16 = (int16_t)((uint16_t)mem->i16[(sp & mem_mask) >> 1] / (uint16_t)w_reg.i16);
+        sp += 2;
+        break;
+      case W_TYPE_I32:
+        sp = (sp + 3) & ~3;
+        w_reg.i32 = (int32_t)((uint32_t)mem->i32[(sp & mem_mask) >> 2] / (uint32_t)w_reg.i32);
+        sp += 4;
+        break;
+      case W_TYPE_I64:
+        sp = (sp + 7) & ~7;
+        w_reg.i64 = (int64_t)((uint64_t)mem->i64[(sp & mem_mask) >> 3] / (uint64_t)w_reg.i64);
+        sp += 8;
+        break;
+      case W_TYPE_I128:
+        sp = (sp + 0xf) & ~0xf;
+        w_reg.i128 = (int128_t)((uint128_t)mem->i128[(sp & mem_mask) >> 4] / (uint128_t)w_reg.i128);
+        sp += 0x10;
+        break;
+      default:
+        abort();
+      }
+      break;
+    case OP_DIV_U_R:
       switch (w_type) {
       case W_TYPE_I8:
         w_reg.i8 = (int8_t)((uint8_t)w_reg.i8 / (uint8_t)mem->i8[sp++ & mem_mask]);
@@ -1573,29 +1610,116 @@ int main(int argc, char **argv) {
         abort();
       }
       break;
-    case OP_DIV_U_R:
+    case OP_MOD:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = (int8_t)((uint8_t)mem->i8[sp++ & mem_mask] / (uint8_t)w_reg.i8);
+        w_reg.i8 = mem->i8[sp++ & mem_mask] % w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i16 = (int16_t)((uint16_t)mem->i16[(sp & mem_mask) >> 1] / (uint16_t)w_reg.i16);
+        w_reg.i16 = mem->i16[(sp & mem_mask) >> 1] % w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i32 = (int32_t)((uint32_t)mem->i32[(sp & mem_mask) >> 2] / (uint32_t)w_reg.i32);
+        w_reg.i32 = mem->i32[(sp & mem_mask) >> 2] % w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i64 = (int64_t)((uint64_t)mem->i64[(sp & mem_mask) >> 3] / (uint64_t)w_reg.i64);
+        w_reg.i64 = mem->i64[(sp & mem_mask) >> 3] % w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i128 = (int128_t)((uint128_t)mem->i128[(sp & mem_mask) >> 4] / (uint128_t)w_reg.i128);
+        w_reg.i128 = mem->i128[(sp & mem_mask) >> 4] % w_reg.i128;
+        sp += 0x10;
+        break;
+      default:
+        abort();
+      }
+      break;
+    case OP_MOD_R:
+      switch (w_type) {
+      case W_TYPE_I8:
+        w_reg.i8 %= mem->i8[sp++ & mem_mask];
+        break;
+      case W_TYPE_I16:
+        sp = (sp + 1) & ~1;
+        w_reg.i16 %= mem->i16[(sp & mem_mask) >> 1];
+        sp += 2;
+        break;
+      case W_TYPE_I32:
+        sp = (sp + 3) & ~3;
+        w_reg.i32 %= mem->i32[(sp & mem_mask) >> 2];
+        sp += 4;
+        break;
+      case W_TYPE_I64:
+        sp = (sp + 7) & ~7;
+        w_reg.i64 %= mem->i64[(sp & mem_mask) >> 3];
+        sp += 8;
+        break;
+      case W_TYPE_I128:
+        sp = (sp + 0xf) & ~0xf;
+        w_reg.i128 %= mem->i128[(sp & mem_mask) >> 4];
+        sp += 0x10;
+        break;
+      default:
+        abort();
+      }
+      break;
+    case OP_MOD_U:
+      switch (w_type) {
+      case W_TYPE_I8:
+        w_reg.i8 = (int8_t)((uint8_t)mem->i8[sp++ & mem_mask] % (uint8_t)w_reg.i8);
+        break;
+      case W_TYPE_I16:
+        sp = (sp + 1) & ~1;
+        w_reg.i16 = (int16_t)((uint16_t)mem->i16[(sp & mem_mask) >> 1] % (uint16_t)w_reg.i16);
+        sp += 2;
+        break;
+      case W_TYPE_I32:
+        sp = (sp + 3) & ~3;
+        w_reg.i32 = (int32_t)((uint32_t)mem->i32[(sp & mem_mask) >> 2] % (uint32_t)w_reg.i32);
+        sp += 4;
+        break;
+      case W_TYPE_I64:
+        sp = (sp + 7) & ~7;
+        w_reg.i64 = (int64_t)((uint64_t)mem->i64[(sp & mem_mask) >> 3] % (uint64_t)w_reg.i64);
+        sp += 8;
+        break;
+      case W_TYPE_I128:
+        sp = (sp + 0xf) & ~0xf;
+        w_reg.i128 = (int128_t)((uint128_t)mem->i128[(sp & mem_mask) >> 4] % (uint128_t)w_reg.i128);
+        sp += 0x10;
+        break;
+      default:
+        abort();
+      }
+      break;
+    case OP_MOD_U_R:
+      switch (w_type) {
+      case W_TYPE_I8:
+        w_reg.i8 = (int8_t)((uint8_t)w_reg.i8 % (uint8_t)mem->i8[sp++ & mem_mask]);
+        break;
+      case W_TYPE_I16:
+        sp = (sp + 1) & ~1;
+        w_reg.i16 = (int16_t)((uint16_t)w_reg.i16 % (uint16_t)mem->i16[(sp & mem_mask) >> 1]);
+        sp += 2;
+        break;
+      case W_TYPE_I32:
+        sp = (sp + 3) & ~3;
+        w_reg.i32 = (int32_t)((uint32_t)w_reg.i32 % (uint32_t)mem->i32[(sp & mem_mask) >> 2]);
+        sp += 4;
+        break;
+      case W_TYPE_I64:
+        sp = (sp + 7) & ~7;
+        w_reg.i64 = (int64_t)((uint64_t)w_reg.i64 % (uint64_t)mem->i64[(sp & mem_mask) >> 3]);
+        sp += 8;
+        break;
+      case W_TYPE_I128:
+        sp = (sp + 0xf) & ~0xf;
+        w_reg.i128 = (int128_t)((uint128_t)w_reg.i128 % (uint128_t)mem->i128[(sp & mem_mask) >> 4]);
         sp += 0x10;
         break;
       default:
@@ -1940,41 +2064,41 @@ int main(int argc, char **argv) {
     case OP_EQ:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = w_reg.i8 == mem->i8[sp++ & mem_mask];
+        w_reg.i8 = mem->i8[sp++ & mem_mask] == w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = w_reg.i16 == mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = mem->i16[(sp & mem_mask) >> 1] == w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.i32 == mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->i32[(sp & mem_mask) >> 2] == w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.i64 == mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->i64[(sp & mem_mask) >> 3] == w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.i128 == mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->i128[(sp & mem_mask) >> 4] == w_reg.i128;
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.f32 == mem->f32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->f32[(sp & mem_mask) >> 2] == w_reg.f32;
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.f64 == mem->f64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->f64[(sp & mem_mask) >> 3] == w_reg.f64;
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.f128 == mem->f128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->f128[(sp & mem_mask) >> 4] == w_reg.f128;
         sp += 0x10;
         break;
       default:
@@ -1985,41 +2109,41 @@ int main(int argc, char **argv) {
     case OP_NE:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = w_reg.i8 != mem->i8[sp++ & mem_mask];
+        w_reg.i8 = mem->i8[sp++ & mem_mask] != w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = w_reg.i16 != mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = mem->i16[(sp & mem_mask) >> 1] != w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.i32 != mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->i32[(sp & mem_mask) >> 2] != w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.i64 != mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->i64[(sp & mem_mask) >> 3] != w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.i128 != mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->i128[(sp & mem_mask) >> 4] != w_reg.i128;
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.f32 != mem->f32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->f32[(sp & mem_mask) >> 2] != w_reg.f32;
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.f64 != mem->f64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->f64[(sp & mem_mask) >> 3] != w_reg.f64;
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.f128 != mem->f128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->f128[(sp & mem_mask) >> 4] != w_reg.f128;
         sp += 0x10;
         break;
       default:
@@ -2030,41 +2154,41 @@ int main(int argc, char **argv) {
     case OP_LT:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = w_reg.i8 < mem->i8[sp++ & mem_mask];
+        w_reg.i8 = mem->i8[sp++ & mem_mask] < w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = w_reg.i16 < mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = mem->i16[(sp & mem_mask) >> 1] < w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.i32 < mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->i32[(sp & mem_mask) >> 2] < w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.i64 < mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->i64[(sp & mem_mask) >> 3] < w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.i128 < mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->i128[(sp & mem_mask) >> 4] < w_reg.i128;
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.f32 < mem->f32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->f32[(sp & mem_mask) >> 2] < w_reg.f32;
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.f64 < mem->f64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->f64[(sp & mem_mask) >> 3] < w_reg.f64;
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.f128 < mem->f128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->f128[(sp & mem_mask) >> 4] < w_reg.f128;
         sp += 0x10;
         break;
       default:
@@ -2075,26 +2199,26 @@ int main(int argc, char **argv) {
     case OP_LT_U:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = (uint8_t)w_reg.i8 < (uint8_t)mem->i8[sp++ & mem_mask];
+        w_reg.i8 = (uint8_t)mem->i8[sp++ & mem_mask] < (uint8_t)w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = (uint16_t)w_reg.i16 < (uint16_t)mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = (uint16_t)mem->i16[(sp & mem_mask) >> 1] < (uint16_t)w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = (uint32_t)w_reg.i32 < (uint32_t)mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = (uint32_t)mem->i32[(sp & mem_mask) >> 2] < (uint32_t)w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = (uint64_t)w_reg.i64 < (uint64_t)mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = (uint64_t)mem->i64[(sp & mem_mask) >> 3] < (uint64_t)w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = (uint128_t)w_reg.i128 < (uint128_t)mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = (uint128_t)mem->i128[(sp & mem_mask) >> 4] < (uint128_t)w_reg.i128;
         sp += 0x10;
         break;
       default:
@@ -2105,41 +2229,41 @@ int main(int argc, char **argv) {
     case OP_LE:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = w_reg.i8 <= mem->i8[sp++ & mem_mask];
+        w_reg.i8 = mem->i8[sp++ & mem_mask] <= w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = w_reg.i16 <= mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = mem->i16[(sp & mem_mask) >> 1] <= w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.i32 <= mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->i32[(sp & mem_mask) >> 2] <= w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.i64 <= mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->i64[(sp & mem_mask) >> 3] <= w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.i128 <= mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->i128[(sp & mem_mask) >> 4] <= w_reg.i128;
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.f32 <= mem->f32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->f32[(sp & mem_mask) >> 2] <= w_reg.f32;
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.f64 <= mem->f64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->f64[(sp & mem_mask) >> 3] <= w_reg.f64;
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.f128 <= mem->f128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->f128[(sp & mem_mask) >> 4] <= w_reg.f128;
         sp += 0x10;
         break;
       default:
@@ -2150,26 +2274,26 @@ int main(int argc, char **argv) {
     case OP_LE_U:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = (uint8_t)w_reg.i8 <= (uint8_t)mem->i8[sp++ & mem_mask];
+        w_reg.i8 = (uint8_t)mem->i8[sp++ & mem_mask] <= (uint8_t)w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = (uint16_t)w_reg.i16 <= (uint16_t)mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = (uint16_t)mem->i16[(sp & mem_mask) >> 1] <= (uint16_t)w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = (uint32_t)w_reg.i32 <= (uint32_t)mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = (uint32_t)mem->i32[(sp & mem_mask) >> 2] <= (uint32_t)w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = (uint64_t)w_reg.i64 <= (uint64_t)mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = (uint64_t)mem->i64[(sp & mem_mask) >> 3] <= (uint64_t)w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = (uint128_t)w_reg.i128 <= (uint128_t)mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = (uint128_t)mem->i128[(sp & mem_mask) >> 4] <= (uint128_t)w_reg.i128;
         sp += 0x10;
         break;
       default:
@@ -2180,41 +2304,41 @@ int main(int argc, char **argv) {
     case OP_GT:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = w_reg.i8 > mem->i8[sp++ & mem_mask];
+        w_reg.i8 = mem->i8[sp++ & mem_mask] > w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = w_reg.i16 > mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = mem->i16[(sp & mem_mask) >> 1] > w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.i32 > mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->i32[(sp & mem_mask) >> 2] > w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.i64 > mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->i64[(sp & mem_mask) >> 3] > w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.i128 > mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->i128[(sp & mem_mask) >> 4] > w_reg.i128;
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.f32 > mem->f32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->f32[(sp & mem_mask) >> 2] > w_reg.f32;
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.f64 > mem->f64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->f64[(sp & mem_mask) >> 3] > w_reg.f64;
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.f128 > mem->f128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->f128[(sp & mem_mask) >> 4] > w_reg.f128;
         sp += 0x10;
         break;
       default:
@@ -2225,26 +2349,26 @@ int main(int argc, char **argv) {
     case OP_GT_U:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = (uint8_t)w_reg.i8 > (uint8_t)mem->i8[sp++ & mem_mask];
+        w_reg.i8 = (uint8_t)mem->i8[sp++ & mem_mask] > (uint8_t)w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = (uint16_t)w_reg.i16 > (uint16_t)mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = (uint16_t)mem->i16[(sp & mem_mask) >> 1] > (uint16_t)w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = (uint32_t)w_reg.i32 > (uint32_t)mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = (uint32_t)mem->i32[(sp & mem_mask) >> 2] > (uint32_t)w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = (uint64_t)w_reg.i64 > (uint64_t)mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = (uint64_t)mem->i64[(sp & mem_mask) >> 3] > (uint64_t)w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = (uint128_t)w_reg.i128 > (uint128_t)mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = (uint128_t)mem->i128[(sp & mem_mask) >> 4] > (uint128_t)w_reg.i128;
         sp += 0x10;
         break;
       default:
@@ -2255,41 +2379,41 @@ int main(int argc, char **argv) {
     case OP_GE:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = w_reg.i8 >= mem->i8[sp++ & mem_mask];
+        w_reg.i8 = mem->i8[sp++ & mem_mask] >= w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = w_reg.i16 >= mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = mem->i16[(sp & mem_mask) >> 1] >= w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.i32 >= mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->i32[(sp & mem_mask) >> 2] >= w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.i64 >= mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->i64[(sp & mem_mask) >> 3] >= w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.i128 >= mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->i128[(sp & mem_mask) >> 4] >= w_reg.i128;
         sp += 0x10;
         break;
       case W_TYPE_F32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = w_reg.f32 >= mem->f32[(sp & mem_mask) >> 2];
+        w_reg.i8 = mem->f32[(sp & mem_mask) >> 2] >= w_reg.f32;
         sp += 4;
         break;
       case W_TYPE_F64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = w_reg.f64 >= mem->f64[(sp & mem_mask) >> 3];
+        w_reg.i8 = mem->f64[(sp & mem_mask) >> 3] >= w_reg.f64;
         sp += 8;
         break;
       case W_TYPE_F128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = w_reg.f128 >= mem->f128[(sp & mem_mask) >> 4];
+        w_reg.i8 = mem->f128[(sp & mem_mask) >> 4] >= w_reg.f128;
         sp += 0x10;
         break;
       default:
@@ -2300,26 +2424,26 @@ int main(int argc, char **argv) {
     case OP_GE_U:
       switch (w_type) {
       case W_TYPE_I8:
-        w_reg.i8 = (uint8_t)w_reg.i8 >= (uint8_t)mem->i8[sp++ & mem_mask];
+        w_reg.i8 = (uint8_t)mem->i8[sp++ & mem_mask] >= (uint8_t)w_reg.i8;
         break;
       case W_TYPE_I16:
         sp = (sp + 1) & ~1;
-        w_reg.i8 = (uint16_t)w_reg.i16 >= (uint16_t)mem->i16[(sp & mem_mask) >> 1];
+        w_reg.i8 = (uint16_t)mem->i16[(sp & mem_mask) >> 1] >= (uint16_t)w_reg.i16;
         sp += 2;
         break;
       case W_TYPE_I32:
         sp = (sp + 3) & ~3;
-        w_reg.i8 = (uint32_t)w_reg.i32 >= (uint32_t)mem->i32[(sp & mem_mask) >> 2];
+        w_reg.i8 = (uint32_t)mem->i32[(sp & mem_mask) >> 2] >= (uint32_t)w_reg.i32;
         sp += 4;
         break;
       case W_TYPE_I64:
         sp = (sp + 7) & ~7;
-        w_reg.i8 = (uint64_t)w_reg.i64 >= (uint64_t)mem->i64[(sp & mem_mask) >> 3];
+        w_reg.i8 = (uint64_t)mem->i64[(sp & mem_mask) >> 3] >= (uint64_t)w_reg.i64;
         sp += 8;
         break;
       case W_TYPE_I128:
         sp = (sp + 0xf) & ~0xf;
-        w_reg.i8 = (uint128_t)w_reg.i128 >= (uint128_t)mem->i128[(sp & mem_mask) >> 4];
+        w_reg.i8 = (uint128_t)mem->i128[(sp & mem_mask) >> 4] >= (uint128_t)w_reg.i128;
         sp += 0x10;
         break;
       default:
index 9be17ed..e83f277 100755 (executable)
--- a/vm_asm.py
+++ b/vm_asm.py
@@ -137,58 +137,62 @@ mnemonics = {
   'div.r':             (0x57, OPERAND_TYPE_NONE),
   'div.u':             (0x58, OPERAND_TYPE_NONE),
   'div.u.r':           (0x59, OPERAND_TYPE_NONE),
-  'shl.i8':            (0x5a, OPERAND_TYPE_NONE),
-  'shl.i16':           (0x5b, OPERAND_TYPE_NONE),
-  'shl.i32':           (0x5c, OPERAND_TYPE_NONE),
-  'shl.i64':           (0x5d, OPERAND_TYPE_NONE),
-  'shl.i128':          (0x5e, OPERAND_TYPE_NONE),
-  'shl.r':             (0x5f, OPERAND_TYPE_NONE),
-  'shr.i8':            (0x60, OPERAND_TYPE_NONE),
-  'shr.i16':           (0x61, OPERAND_TYPE_NONE),
-  'shr.i32':           (0x62, OPERAND_TYPE_NONE),
-  'shr.i64':           (0x63, OPERAND_TYPE_NONE),
-  'shr.i128':          (0x64, OPERAND_TYPE_NONE),
-  'shr.r':             (0x65, OPERAND_TYPE_NONE),
-  'shr.u.i8':          (0x66, OPERAND_TYPE_NONE),
-  'shr.u.i16':         (0x67, OPERAND_TYPE_NONE),
-  'shr.u.i32':         (0x68, OPERAND_TYPE_NONE),
-  'shr.u.i64':         (0x69, OPERAND_TYPE_NONE),
-  'shr.u.i128':                (0x6a, OPERAND_TYPE_NONE),
-  'shr.u.r':           (0x6b, OPERAND_TYPE_NONE),
-  'neg':               (0x6c, OPERAND_TYPE_NONE),
-  'and':               (0x6d, OPERAND_TYPE_NONE),
-  'or':                        (0x6e, OPERAND_TYPE_NONE),
-  'xor':               (0x6f, OPERAND_TYPE_NONE),
-  'not':               (0x70, OPERAND_TYPE_NONE),
+  'mod':               (0x5a, OPERAND_TYPE_NONE),
+  'mod.r':             (0x5b, OPERAND_TYPE_NONE),
+  'mod.u':             (0x5c, OPERAND_TYPE_NONE),
+  'mod.u.r':           (0x5d, OPERAND_TYPE_NONE),
+  'shl.i8':            (0x5e, OPERAND_TYPE_NONE),
+  'shl.i16':           (0x5f, OPERAND_TYPE_NONE),
+  'shl.i32':           (0x60, OPERAND_TYPE_NONE),
+  'shl.i64':           (0x61, OPERAND_TYPE_NONE),
+  'shl.i128':          (0x62, OPERAND_TYPE_NONE),
+  'shl.r':             (0x63, OPERAND_TYPE_NONE),
+  'shr.i8':            (0x64, OPERAND_TYPE_NONE),
+  'shr.i16':           (0x65, OPERAND_TYPE_NONE),
+  'shr.i32':           (0x66, OPERAND_TYPE_NONE),
+  'shr.i64':           (0x67, OPERAND_TYPE_NONE),
+  'shr.i128':          (0x68, OPERAND_TYPE_NONE),
+  'shr.r':             (0x69, OPERAND_TYPE_NONE),
+  'shr.u.i8':          (0x6a, OPERAND_TYPE_NONE),
+  'shr.u.i16':         (0x6b, OPERAND_TYPE_NONE),
+  'shr.u.i32':         (0x6c, OPERAND_TYPE_NONE),
+  'shr.u.i64':         (0x6d, OPERAND_TYPE_NONE),
+  'shr.u.i128':                (0x6e, OPERAND_TYPE_NONE),
+  'shr.u.r':           (0x6f, OPERAND_TYPE_NONE),
+  'neg':               (0x70, OPERAND_TYPE_NONE),
+  'and':               (0x71, OPERAND_TYPE_NONE),
+  'or':                        (0x72, OPERAND_TYPE_NONE),
+  'xor':               (0x73, OPERAND_TYPE_NONE),
+  'not':               (0x74, OPERAND_TYPE_NONE),
 
   # relational
-  'eq':                        (0x71, OPERAND_TYPE_NONE),
-  'ne':                        (0x72, OPERAND_TYPE_NONE),
-  'lt':                        (0x73, OPERAND_TYPE_NONE),
-  'lt.u':              (0x74, OPERAND_TYPE_NONE),
-  'le':                        (0x75, OPERAND_TYPE_NONE),
-  'le.u':              (0x76, OPERAND_TYPE_NONE),
-  'gt':                        (0x77, OPERAND_TYPE_NONE),
-  'gt.u':              (0x78, OPERAND_TYPE_NONE),
-  'ge':                        (0x79, OPERAND_TYPE_NONE),
-  'ge.u':              (0x7a, OPERAND_TYPE_NONE),
+  'eq':                        (0x75, OPERAND_TYPE_NONE),
+  'ne':                        (0x76, OPERAND_TYPE_NONE),
+  'lt':                        (0x77, OPERAND_TYPE_NONE),
+  'lt.u':              (0x78, OPERAND_TYPE_NONE),
+  'le':                        (0x79, OPERAND_TYPE_NONE),
+  'le.u':              (0x7a, OPERAND_TYPE_NONE),
+  'gt':                        (0x7b, OPERAND_TYPE_NONE),
+  'gt.u':              (0x7c, OPERAND_TYPE_NONE),
+  'ge':                        (0x7d, OPERAND_TYPE_NONE),
+  'ge.u':              (0x7e, OPERAND_TYPE_NONE),
 
   # control flow
-  'adjpc.f':           (0x7b, OPERAND_TYPE_AUTO),
-  'adjpc.f.i8':                (0x7b, OPERAND_TYPE_I8),
-  'adjpc.f.i16':       (0x7c, OPERAND_TYPE_I16),
-  'adjpc.f.i32':       (0x7d, OPERAND_TYPE_I32),
-  'adjpc.t':           (0x7e, OPERAND_TYPE_AUTO),
-  'adjpc.t.i8':                (0x7e, OPERAND_TYPE_I8),
-  'adjpc.t.i16':       (0x7f, OPERAND_TYPE_I16),
-  'adjpc.t.i32':       (0x80, OPERAND_TYPE_I32),
-  'call.w':            (0x81, OPERAND_TYPE_NONE),
-  'call':              (0x82, OPERAND_TYPE_AUTO),
-  'call.i8':           (0x82, OPERAND_TYPE_I8),
-  'call.i16':          (0x83, OPERAND_TYPE_I16),
-  'call.i32':          (0x84, OPERAND_TYPE_I32),
-  'ret':               (0x85, OPERAND_TYPE_NONE),
-  'trap':              (0x86, OPERAND_TYPE_NONE),
+  'adjpc.f':           (0x7f, OPERAND_TYPE_AUTO),
+  'adjpc.f.i8':                (0x7f, OPERAND_TYPE_I8),
+  'adjpc.f.i16':       (0x80, OPERAND_TYPE_I16),
+  'adjpc.f.i32':       (0x81, OPERAND_TYPE_I32),
+  'adjpc.t':           (0x82, OPERAND_TYPE_AUTO),
+  'adjpc.t.i8':                (0x82, OPERAND_TYPE_I8),
+  'adjpc.t.i16':       (0x83, OPERAND_TYPE_I16),
+  'adjpc.t.i32':       (0x84, OPERAND_TYPE_I32),
+  'call.w':            (0x85, OPERAND_TYPE_NONE),
+  'call':              (0x86, OPERAND_TYPE_AUTO),
+  'call.i8':           (0x86, OPERAND_TYPE_I8),
+  'call.i16':          (0x87, OPERAND_TYPE_I16),
+  'call.i32':          (0x88, OPERAND_TYPE_I32),
+  'ret':               (0x89, OPERAND_TYPE_NONE),
+  'trap':              (0x8a, OPERAND_TYPE_NONE),
 }
 
 # for auto operands
@@ -324,6 +328,18 @@ while True:
             fuzz += waste - autos[auto]
             autos[auto] = waste
           auto += 1 
+        elif mnemonic == '.space':
+          assert len(fields) == 1
+          operand_str = fields[0]
+          assert operand_str[:1] in digit_set
+          operand_int = int(operand_str, 0)
+
+          if flist is not None:
+            flist.write(f'{pc:08x}\t\t\t\t\t{mnemonic:s} {operand_str:s}\n')
+
+          pc += operand_int
+          if fout is not None:
+            fout.write(bytes([0] * operand_int))
         else:
           op, operand_type = mnemonics[mnemonic]
           if operand_type == OPERAND_TYPE_NONE:
index 9b4ec89..fde68f6 100644 (file)
@@ -5,35 +5,98 @@ putchar = -3
 main: ; stack alignment 16
        imm.i32 hello_world
        call print_str@
+
        adjsp -0xc
        imm.i128 0x0123456789abcdeffedcba9876543210
        call print_hex_i128@
-       imm.i128 0x0123456789abcdeffedcba9876543210
-       call print_hex_i128@
        adjsp 0xc
        imm.i32 0xa
        push
        call putchar@
        adjsp 4
+
+       adjsp -0xc
+       imm.i128 0
+       call print_dec_i128@
+       adjsp 0xc
+       imm.i32 0xa
+       push
+       call putchar@
+       adjsp 4
+
+       adjsp -0xc
+       imm.i128 12345678901234567890123456789
+       call print_dec_i128@
+       adjsp 0xc
+       imm.i32 0xa
+       push
+       call putchar@
+       adjsp 4
+
+       adjsp -0xc
+       imm.i128 -12345678901234567890123456789
+       call print_dec_i128@
+       adjsp 0xc
+       imm.i32 0xa
+       push
+       call putchar@
+       adjsp 4
+
+       adjsp -0xc
+       imm.f128 0
+       call print_sci_f128@
+       adjsp 0xc
+       imm.i32 0xa
+       push
+       call putchar@
+       adjsp 4
+
+       adjsp -0xc
+       imm.f128 1.234567890123456789012345678901234567e999
+       call print_sci_f128@
+       adjsp 0xc
+       imm.i32 0xa
+       push
+       call putchar@
+       adjsp 4
+
+       adjsp -0xc
+       imm.f128 -1.234567890123456789012345678901234567e-999
+       call print_sci_f128@
+       adjsp 0xc
+       imm.i32 0xa
+       push
+       call putchar@
+       adjsp 4
+
+       adjsp -0xc
+       imm.f128 6.475175119438025110924438958227646552e-4966
+       call print_sci_f128@
+       adjsp 0xc
+       imm.i32 0xa
+       push
+       call putchar@
+       adjsp 4
+
        imm.i32 0
        push
        call exit@
 
 hello_world:
-       .i8     'h
-       .i8     'e
-       .i8     'l
-       .i8     'l
-       .i8     'o
-       .i8     ',
-       .i8     0x20
-       .i8     'w
-       .i8     'o
-       .i8     'r
-       .i8     'l
-       .i8     'd
-       .i8     0xa
-       .i8     0
+       .i8 'h
+       .i8 'e
+       .i8 'l
+       .i8 'l
+       .i8 'o
+       .i8 ',
+       .i8 0x20
+       .i8 'w
+       .i8 'o
+       .i8 'r
+       .i8 'l
+       .i8 'd
+       .i8 0xa
+       .i8 0
 
 print_str:
        setix
@@ -53,6 +116,7 @@ print_str_done:
 
 print_hex_i128: ; stack alignment 16
        push
+
        push
        imm.i8 64
        shr.i128
@@ -60,77 +124,431 @@ print_hex_i128: ; stack alignment 16
        adjsp -4
        call print_hex_i64@
        adjsp 4
+
        pop.i128
        cvt.i64
+       ; fallthru
+
 print_hex_i64: ; stack alignment 8
        push
+
        push
        imm.i8 32
        shr.i64
        cvt.i32
        call print_hex_i32@
+
        pop.i64
        cvt.i32
+       ; fallthru
+
 print_hex_i32:
        push
+
        push
        imm.i8 16
        shr.i32
        cvt.i16
        call print_hex_i16@
+
        pop.i32
        cvt.i16
+       ; fallthru
+
 print_hex_i16:
        push
+
        push
        imm.i8 8
        shr.i16
        cvt.i8
        call print_hex_i8@
        adjsp 2
+
        pop.i16
        cvt.i8
+       ; fallthru
+
 print_hex_i8:
        push
+
        push
        imm.i8 4
        shr.i8
        call print_hex_nibble@
        adjsp 3
+
        pop.i8
+       ; fallthru
+
 print_hex_nibble:
        push
        imm.i8 0xf
        and
        cvt.i32
+
        push
-       imm.i32 hex_table
+       imm.i32 print_hex_table
        add
        ld.i8
+
        cvt.i32
        push
        call putchar@
        adjsp 4
+
        ret
 
-hex_table:
-       .i8     '0
-       .i8     '1
-       .i8     '2
-       .i8     '3
-       .i8     '4
-       .i8     '5
-       .i8     '6
-       .i8     '7
-       .i8     '8
-       .i8     '9
-       .i8     'a
-       .i8     'b
-       .i8     'c
-       .i8     'd
-       .i8     'e
-       .i8     'f
-
-       .f128 1.234567890123456789012345678901234567e999
-       .f128 -1.234567890123456789012345678901234567e-999
-       .f128 6.475175119438025110924438958227646552e-4966
+print_hex_table:
+       .i8 '0
+       .i8 '1
+       .i8 '2
+       .i8 '3
+       .i8 '4
+       .i8 '5
+       .i8 '6
+       .i8 '7
+       .i8 '8
+       .i8 '9
+       .i8 'a
+       .i8 'b
+       .i8 'c
+       .i8 'd
+       .i8 'e
+       .i8 'f
+
+print_dec_i128: ; stack alignment 16
+       push
+
+       push
+       imm.i128 0
+       lt
+       adjpc.f print_dec_pos@
+
+       imm.i32 '-
+       push
+       call putchar@
+       adjsp 4
+
+       pop.i128
+       neg
+       push
+
+print_dec_pos:
+       imm.i32 print_dec_buf_end
+       setix
+
+       pop.i128
+print_dec_loop0:
+       push
+
+       push
+       imm.i128 10
+       mod.u
+       cvt.i8
+       push
+       imm.i8 '0
+       add
+       push
+       adjix -1
+       getix
+       st.r.i8
+
+       imm.i128 10
+       div.u
+       adjpc.t print_dec_loop0@
+
+print_dec_loop1:
+       getix
+       ld.i8
+       cvt.i32
+       push
+       call putchar@
+       adjsp 4
+
+       adjix 1
+       getix
+       push
+       imm.i32 print_dec_buf_end
+       lt.u
+       adjpc.t print_dec_loop1@
+
+       ret
+
+       .space 39 ; 1 << 127 == 170141183460469231731687303715884105728
+print_dec_buf_end:
+
+print_sci_f128:
+       push
+
+       push
+       imm.f128 0
+       lt
+       adjpc.f print_sci_pos@
+
+       imm.i32 '-
+       push
+       call putchar@
+       adjsp 4
+
+       pop.f128
+       neg
+       push
+
+print_sci_pos:
+       ; ix points to table of exponents
+       ; when dividing it down:
+       ; entry is struct with threshold value (> 1) then scaling value (< 1)
+       ; when multiplying it up:
+       ; entry is struct with scaling value (> 1) then threshold value (< 1)
+       imm.i32 print_sci_table
+       setix
+
+       ; if number is >= 1, exponent is positive and we'll divide it down
+       ; if number is < 1, exponent is negative and we'll multiply it up
+       pop.f128
+       push
+
+       push
+       imm.f128 1
+       lt
+       adjpc.t print_sci_multiply@
+
+       ; dividing it down case
+
+       ; iy is shift register for exponent bits
+       imm.i32 0
+       setiy
+
+print_sci_loop0:
+       ; calculate next exponent bit
+       pop.f128
+       push
+
+       push
+       getix
+       ld.f128
+       ge
+       push
+
+       ; shift exponent bit into iy
+       cvt.i32
+       push
+       getiy
+       push
+       imm.i8 1
+       shl.i32
+       or
+       setiy
+       adjsp 3
+
+       ; if exponent bit is 1, divide
+       pop.i8
+       adjpc.f print_sci_no_div@
+
+       offix 0x10
+       ld.f128
+       mul
+       push
+
+print_sci_no_div:
+       adjix 0x20
+       getix
+       push
+       imm.i32 print_sci_table_end
+       lt.u
+       adjpc.t print_sci_loop0@
+
+       imm.f128 1e36 ; factor to shift left by 36 decimal places
+       adjpc print_sci_normalized@
+
+print_sci_multiply:
+       ; multiplying it up case
+
+       ; iy is shift register for exponent bits
+       ; we will build negative exponent directly, starting with all ones
+       imm.i32 -1
+       setiy
+
+print_sci_loop1:
+       ; calculate next exponent bit
+       pop.f128
+       push
+
+       push
+       offix 0x10
+       ld.f128
+       ge
+       push
+
+       ; shift exponent bit into iy
+       cvt.i32
+       push
+       getiy
+       push
+       imm.i8 1
+       shl.i32
+       or
+       setiy
+       adjsp 3
+
+       ; if exponent bit is 0, multiply
+       pop.i8
+       adjpc.t print_sci_no_mul@
+
+       getix
+       ld.f128
+       mul
+       push
+
+print_sci_no_mul:
+       adjix 0x20
+       getix
+       push
+       imm.i32 print_sci_table_end
+       lt.u
+       adjpc.t print_sci_loop1@
+
+       ; at this point the number is still < 1, do final multiply by 10
+       ; we used "not exponent" rather than "neg exponent" for extra -1
+       imm.f128 1e37 ; 10 * factor to shift left by 36 decimal places
+
+print_sci_normalized:
+       ; convert mantissa to 37 digit integer with 36 decimal places
+       mul
+       push
+       imm.f128 .5
+       add
+       cvt.i128
+       push
+
+       ; if mantissa is zero, zero out exponent as well
+       adjpc.t print_sci_not_zero@
+
+       imm.i32 0
+       setiy
+       adjpc print_sci_no_overflow@
+
+print_sci_not_zero:
+       ; check for 38-digit integer (rounding overflow)
+       push
+       imm.i128 10000000000000000000000000000000000000
+       ge.u
+       adjpc.f print_sci_no_overflow@
+
+       ; move along one digit position and bump exponent
+       ; note: no rounding is needed, as low order digit must be 0
+       imm.i128 10
+       div.u
+       push
+       adjiy 1
+
+print_sci_no_overflow:
+       ; render all 37 digits backwards into buffer
+       imm.i32 print_sci_buf_end
+       setix
+
+print_sci_loop2:
+       pop.i128
+       push
+
+       push
+       imm.i128 10
+       mod.u
+       cvt.i8
+       push
+       imm.i8 '0
+       add
+       push
+       adjix -1
+       getix
+       st.r.i8
+
+       imm.i128 10
+       div.u
+       push
+
+       getix
+       push
+       imm.i32 print_sci_buf
+       gt.u
+       adjpc.t print_sci_loop2@
+
+       pop.i128 ; should be 0, discard
+
+       ; print first digit
+       getix
+       ld.i8
+       cvt.i32
+
+       push
+       call putchar@
+       adjsp 4
+
+       adjix 1
+
+       ; print decimal point
+       imm.i32 '.
+       push
+       call putchar@
+       adjsp 4
+
+       ; print remaining digits
+print_sci_loop3:
+       getix
+       ld.i8
+       cvt.i32
+       push
+       call putchar@
+       adjsp 4
+
+       adjix 1
+       getix
+       push
+       imm.i32 print_sci_buf_end
+       lt.u
+       adjpc.t print_sci_loop3@
+
+       ; print exponent part
+       imm.i32 'e
+       push
+       call putchar@
+       adjsp 4
+
+       getiy
+       cvt.i128
+       adjpc print_dec_i128@
+
+print_sci_buf:
+       .space 37
+print_sci_buf_end:
+
+       .align 0x10
+print_sci_table:
+       .f128 1e4096
+       .f128 1e-4096
+       .f128 1e2048
+       .f128 1e-2048
+       .f128 1e1024
+       .f128 1e-1024
+       .f128 1e512
+       .f128 1e-512
+       .f128 1e256
+       .f128 1e-256
+       .f128 1e128
+       .f128 1e-128
+       .f128 1e64
+       .f128 1e-64
+       .f128 1e32
+       .f128 1e-32
+       .f128 1e16
+       .f128 1e-16
+       .f128 1e8
+       .f128 1e-8
+       .f128 1e4
+       .f128 1e-4
+       .f128 1e2
+       .f128 1e-2
+       .f128 1e1
+       .f128 1e-1
+print_sci_table_end: