cleanup: remove cpu ctrl files, move tests
[gpsp.git] / gp2x / test / load_imm_test.c
diff --git a/gp2x/test/load_imm_test.c b/gp2x/test/load_imm_test.c
new file mode 100644 (file)
index 0000000..b850d56
--- /dev/null
@@ -0,0 +1,135 @@
+#include <stdio.h>\r
+\r
+typedef unsigned int u32;\r
+\r
+u32 arm_imm_find_nonzero(u32 imm, u32 start_bit)\r
+{\r
+  u32 i;\r
+\r
+  for(i = start_bit; i < 32; i += 2)\r
+  {\r
+    if((imm >> i) & 0x03)\r
+      break;\r
+  }\r
+\r
+  return i;\r
+}\r
+\r
+u32 arm_disect_imm_32bit(u32 imm, u32 *stores, u32 *rotations)\r
+{\r
+  u32 store_count = 0;\r
+  u32 left_shift = 0;\r
+\r
+  // Otherwise it'll return 0 things to store because it'll never\r
+  // find anything.\r
+  if(imm == 0)\r
+  {\r
+    rotations[0] = 0;\r
+    stores[0] = 0;\r
+    return 1;\r
+  }\r
+\r
+  // Find chunks of non-zero data at 2 bit alignments.\r
+  while(1)\r
+  {\r
+    left_shift = arm_imm_find_nonzero(imm, left_shift);\r
+\r
+    if(left_shift == 32)\r
+    {\r
+      // We've hit the end of the useful data.\r
+      return store_count;\r
+    }\r
+\r
+    // Hit the end, it might wrap back around to the beginning.\r
+    if(left_shift >= 24)\r
+    {\r
+      // Make a mask for the residual bits. IE, if we have\r
+      // 5 bits of data at the end we can wrap around to 3\r
+      // bits of data in the beginning. Thus the first\r
+      // thing, after being shifted left, has to be less\r
+      // than 111b, 0x7, or (1 << 3) - 1.\r
+      u32 top_bits = 32 - left_shift;\r
+      u32 residual_bits = 8 - top_bits;\r
+      u32 residual_mask = (1 << residual_bits) - 1;\r
+\r
+      if((store_count > 1) && (left_shift > 24) &&\r
+       ((stores[0] << (32 - rotations[0])) < residual_mask))\r
+      {\r
+        // Then we can throw out the last bit and tack it on\r
+        // to the first bit.\r
+        u32 initial_bits = rotations[0];\r
+        stores[0] = (stores[0] << (top_bits + (32 - rotations[0]))) |\r
+         ((imm >> left_shift) & 0xFF);\r
+        rotations[0] = top_bits;\r
+\r
+        return store_count;\r
+      }\r
+      else\r
+      {\r
+        // There's nothing to wrap over to in the beginning\r
+        stores[store_count] = (imm >> left_shift) & 0xFF;\r
+        rotations[store_count] = (32 - left_shift) & 0x1F;\r
+        return store_count + 1;\r
+      }\r
+      break;\r
+    }\r
+\r
+    stores[store_count] = (imm >> left_shift) & 0xFF;\r
+    rotations[store_count] = (32 - left_shift) & 0x1F;\r
+\r
+    store_count++;\r
+    left_shift += 8;\r
+  }\r
+}\r
+\r
+#define ror(value, shift)                                                     \\r
+  ((value) >> shift) | ((value) << (32 - shift))                              \\r
+\r
+u32 arm_assemble_imm_32bit(u32 *stores, u32 *rotations, u32 store_count)\r
+{\r
+  u32 n = ror(stores[0], rotations[0]);\r
+  u32 i;\r
+  printf("%x : %x\n", stores[0], rotations[0]);\r
+\r
+  for(i = 1; i < store_count; i++)\r
+  {\r
+    printf("%x : %x\n", stores[i], rotations[i]);\r
+    n |= ror(stores[i], rotations[i]);\r
+  }\r
+\r
+  return n;\r
+}\r
+\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+  u32 n = 0;\r
+  u32 stores[4];\r
+  u32 rotations[4];\r
+  u32 store_count;\r
+  u32 n2;\r
+\r
+  if(argc != 1)\r
+  {\r
+    n = strtoul(argv[1], NULL, 16);\r
+    store_count = arm_disect_imm_32bit(n, stores, rotations);\r
+    n2 = arm_assemble_imm_32bit(stores, rotations, store_count);\r
+    printf("%08x -> %08x (%d stores)\n", n, n2, store_count);\r
+    return 0;\r
+  }\r
+\r
+  do\r
+  {\r
+    store_count = arm_disect_imm_32bit(n, stores, rotations);\r
+    n2 = arm_assemble_imm_32bit(stores, rotations, store_count);\r
+    if(n != n2)\r
+    {\r
+      printf("Failure: %08x -/-> %08x\n", n, n2);\r
+      return -1;\r
+    }\r
+    n++;\r
+  } while(n != 0);\r
+\r
+  printf("Done!\n");\r
+  return 0;\r
+}\r