GLES2N64 (from mupen64plus-ae) plugin. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / gles2n64 / src / gSPNeon.cpp
diff --git a/source/gles2n64/src/gSPNeon.cpp b/source/gles2n64/src/gSPNeon.cpp
new file mode 100644 (file)
index 0000000..109aba4
--- /dev/null
@@ -0,0 +1,563 @@
+#include "gSP.h"
+#include "OpenGL.h"
+
+#ifdef __VEC4_OPT
+static void gSPTransformVertex4NEON(u32 v, float mtx[4][4])
+{
+    float *ptr = &OGL.triangles.vertices[v].x;
+
+#if 0
+    volatile int tmp0, tmp1;
+       asm volatile (
+    "vld1.32           {d0, d1}, [%1, :128]                    \n\t"   //q0 = {x,y,z,w}
+    "add                   %1, %1, %4                          \n\t"   //q0 = {x,y,z,w}
+    "vld1.32           {d18, d19}, [%0, :128]!         \n\t"   //q9 = m
+    "vld1.32           {d2, d3}, [%1, :128]            \n\t"   //q1 = {x,y,z,w}
+    "add                   %1, %1, %4                  \n\t"   //q0 = {x,y,z,w}
+    "vld1.32           {d20, d21}, [%0, :128]!       \n\t"     //q10 = m
+    "vld1.32           {d4, d5}, [%1, :128]            \n\t"   //q2 = {x,y,z,w}
+    "add                   %1, %1, %4                  \n\t"   //q0 = {x,y,z,w}
+    "vld1.32           {d22, d23}, [%0, :128]!       \n\t"     //q11 = m
+    "vld1.32           {d6, d7}, [%1, :128]            \n\t"   //q3 = {x,y,z,w}
+    "vld1.32           {d24, d25}, [%0, :128]        \n\t"     //q12 = m
+    "sub                   %1, %1, %6                          \n\t"   //q0 = {x,y,z,w}
+
+    "vmov.f32          q13, q12                        \n\t"   //q13 = q12
+    "vmov.f32          q14, q12                        \n\t"   //q14 = q12
+    "vmov.f32          q15, q12                        \n\t"   //q15 = q12
+
+    "vmla.f32          q12, q9, d0[0]                  \n\t"   //q12 = q9*d0[0]
+    "vmla.f32          q13, q9, d2[0]                  \n\t"   //q13 = q9*d0[0]
+    "vmla.f32          q14, q9, d4[0]                  \n\t"   //q14 = q9*d0[0]
+    "vmla.f32          q15, q9, d6[0]                  \n\t"   //q15 = q9*d0[0]
+    "vmla.f32          q12, q10, d0[1]                 \n\t"   //q12 = q10*d0[1]
+    "vmla.f32          q13, q10, d2[1]                 \n\t"   //q13 = q10*d0[1]
+    "vmla.f32          q14, q10, d4[1]                 \n\t"   //q14 = q10*d0[1]
+    "vmla.f32          q15, q10, d6[1]                 \n\t"   //q15 = q10*d0[1]
+    "vmla.f32          q12, q11, d1[0]                 \n\t"   //q12 = q11*d1[0]
+    "vmla.f32          q13, q11, d3[0]                 \n\t"   //q13 = q11*d1[0]
+    "vmla.f32          q14, q11, d5[0]                 \n\t"   //q14 = q11*d1[0]
+    "vmla.f32          q15, q11, d7[0]                 \n\t"   //q15 = q11*d1[0]
+
+    "add                   %0, %1, %4                  \n\t"   //q0 = {x,y,z,w}
+    "add                   %2, %1, %5                  \n\t"   //q0 = {x,y,z,w}
+    "add                   %3, %1, %6                  \n\t"   //q0 = {x,y,z,w}
+    "vst1.32           {d24, d25}, [%1, :128]          \n\t"   //q12
+    "vst1.32           {d26, d27}, [%0, :128]      \n\t"       //q13
+    "vst1.32           {d28, d29}, [%2, :128]      \n\t"       //q14
+    "vst1.32           {d30, d31}, [%3, :128]          \n\t"   //q15
+       : "+&r"(mtx), "+&r"(ptr), "+r"(tmp0), "+r"(tmp1)
+       : "I"(sizeof(SPVertex)),"I"(2 * sizeof(SPVertex)), "I"(3 * sizeof(SPVertex))
+    : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+      "d18","d19", "d20", "d21", "d22", "d23", "d24",
+      "d25", "d26", "d27", "d28", "d29", "d30", "d31", "memory"
+       );
+#else
+       asm volatile (
+       "vld1.32                {d0, d1}, [%1]                  \n\t"   //q0 = {x,y,z,w}
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d2, d3}, [%1]          \n\t"   //q1 = {x,y,z,w}
+       "add                %1, %1, %2                  \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d4, d5}, [%1]          \n\t"   //q2 = {x,y,z,w}
+       "add                %1, %1, %2                  \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d6, d7}, [%1]          \n\t"   //q3 = {x,y,z,w}
+    "sub                   %1, %1, %3                          \n\t"   //q0 = {x,y,z,w}
+
+       "vld1.32                {d18, d19}, [%0]!               \n\t"   //q9 = m
+       "vld1.32                {d20, d21}, [%0]!       \n\t"   //q10 = m
+       "vld1.32                {d22, d23}, [%0]!       \n\t"   //q11 = m
+       "vld1.32                {d24, d25}, [%0]        \n\t"   //q12 = m
+
+       "vmov.f32               q13, q12                        \n\t"   //q13 = q12
+       "vmov.f32               q14, q12                        \n\t"   //q14 = q12
+       "vmov.f32               q15, q12                        \n\t"   //q15 = q12
+
+       "vmla.f32               q12, q9, d0[0]                  \n\t"   //q12 = q9*d0[0]
+       "vmla.f32               q13, q9, d2[0]                  \n\t"   //q13 = q9*d0[0]
+       "vmla.f32               q14, q9, d4[0]                  \n\t"   //q14 = q9*d0[0]
+       "vmla.f32               q15, q9, d6[0]                  \n\t"   //q15 = q9*d0[0]
+       "vmla.f32               q12, q10, d0[1]                 \n\t"   //q12 = q10*d0[1]
+       "vmla.f32               q13, q10, d2[1]                 \n\t"   //q13 = q10*d0[1]
+       "vmla.f32               q14, q10, d4[1]                 \n\t"   //q14 = q10*d0[1]
+       "vmla.f32               q15, q10, d6[1]                 \n\t"   //q15 = q10*d0[1]
+       "vmla.f32               q12, q11, d1[0]                 \n\t"   //q12 = q11*d1[0]
+       "vmla.f32               q13, q11, d3[0]                 \n\t"   //q13 = q11*d1[0]
+       "vmla.f32               q14, q11, d5[0]                 \n\t"   //q14 = q11*d1[0]
+       "vmla.f32               q15, q11, d7[0]                 \n\t"   //q15 = q11*d1[0]
+
+       "vst1.32                {d24, d25}, [%1]                \n\t"   //q12
+       "add                %1, %1, %2                  \n\t"   //q0 = {x,y,z,w}
+       "vst1.32                {d26, d27}, [%1]            \n\t"       //q13
+       "add                %1, %1, %2                  \n\t"   //q0 = {x,y,z,w}
+       "vst1.32                {d28, d29}, [%1]            \n\t"       //q14
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vst1.32                {d30, d31}, [%1]        \n\t"   //q15
+
+       : "+&r"(mtx), "+&r"(ptr)
+       : "I"(sizeof(SPVertex)), "I"(3 * sizeof(SPVertex))
+    : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+      "d18","d19", "d20", "d21", "d22", "d23", "d24",
+      "d25", "d26", "d27", "d28", "d29", "d30", "d31", "memory"
+       );
+#endif
+}
+
+//4x Transform normal and normalize
+static void gSPTransformNormal4NEON(u32 v, float mtx[4][4])
+{
+    void *ptr = (void*)&OGL.triangles.vertices[v].nx;
+       asm volatile (
+    "vld1.32           {d0, d1}, [%1]                  \n\t"   //q0 = {x,y,z,w}
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d2, d3}, [%1]          \n\t"   //q1 = {x,y,z,w}
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d4, d5}, [%1]          \n\t"   //q2 = {x,y,z,w}
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d6, d7}, [%1]          \n\t"   //q3 = {x,y,z,w}
+    "sub                   %1, %1, %3                          \n\t"   //q0 = {x,y,z,w}
+
+       "vld1.32                {d18, d19}, [%0]!               \n\t"   //q9 = m
+       "vld1.32                {d20, d21}, [%0]!           \n\t"       //q10 = m+16
+       "vld1.32                {d22, d23}, [%0]        \n\t"   //q11 = m+32
+
+       "vmul.f32               q12, q9, d0[0]                  \n\t"   //q12 = q9*d0[0]
+       "vmul.f32               q13, q9, d2[0]                  \n\t"   //q13 = q9*d2[0]
+    "vmul.f32          q14, q9, d4[0]                  \n\t"   //q14 = q9*d4[0]
+    "vmul.f32          q15, q9, d6[0]                  \n\t"   //q15 = q9*d6[0]
+
+    "vmla.f32          q12, q10, d0[1]                 \n\t"   //q12 += q10*q0[1]
+    "vmla.f32          q13, q10, d2[1]                 \n\t"   //q13 += q10*q2[1]
+    "vmla.f32          q14, q10, d4[1]                 \n\t"   //q14 += q10*q4[1]
+    "vmla.f32          q15, q10, d6[1]                 \n\t"   //q15 += q10*q6[1]
+
+       "vmla.f32               q12, q11, d1[0]                 \n\t"   //q12 += q11*d1[0]
+       "vmla.f32               q13, q11, d3[0]                 \n\t"   //q13 += q11*d3[0]
+       "vmla.f32               q14, q11, d5[0]                 \n\t"   //q14 += q11*d5[0]
+       "vmla.f32               q15, q11, d7[0]                 \n\t"   //q15 += q11*d7[0]
+
+    "vmul.f32          q0, q12, q12                    \n\t"   //q0 = q12*q12
+    "vmul.f32          q1, q13, q13                    \n\t"   //q1 = q13*q13
+    "vmul.f32          q2, q14, q14                    \n\t"   //q2 = q14*q14
+    "vmul.f32          q3, q15, q15                    \n\t"   //q3 = q15*q15
+
+    "vpadd.f32                 d0, d0                                  \n\t"   //d0[0] = d0[0] + d0[1]
+    "vpadd.f32                 d2, d2                                  \n\t"   //d2[0] = d2[0] + d2[1]
+    "vpadd.f32                 d4, d4                                  \n\t"   //d4[0] = d4[0] + d4[1]
+    "vpadd.f32                 d6, d6                                  \n\t"   //d6[0] = d6[0] + d6[1]
+
+    "vmov.f32          s1, s2                                  \n\t"   //d0[1] = d1[0]
+    "vmov.f32      s5, s6                              \n\t"   //d2[1] = d3[0]
+    "vmov.f32      s9, s10                             \n\t"   //d4[1] = d5[0]
+    "vmov.f32          s13, s14                                \n\t"   //d6[1] = d7[0]
+
+    "vpadd.f32                 d0, d0, d2                      \n\t"   //d0 = {d0[0] + d0[1], d2[0] + d2[1]}
+    "vpadd.f32                 d1, d4, d6                      \n\t"   //d1 = {d4[0] + d4[1], d6[0] + d6[1]}
+
+       "vmov.f32               q1, q0                                  \n\t"   //q1 = q0
+       "vrsqrte.f32    q0, q0                                  \n\t"   //q0 = ~ 1.0 / sqrt(q0)
+       "vmul.f32               q2, q0, q1                              \n\t"   //q2 = q0 * q1
+       "vrsqrts.f32    q3, q2, q0                              \n\t"   //q3 = (3 - q0 * q2) / 2
+       "vmul.f32               q0, q0, q3                              \n\t"   //q0 = q0 * q3
+       "vmul.f32               q2, q0, q1                              \n\t"   //q2 = q0 * q1
+       "vrsqrts.f32    q3, q2, q0                              \n\t"   //q3 = (3 - q0 * q2) / 2
+       "vmul.f32               q0, q0, q3                              \n\t"   //q0 = q0 * q3
+
+       "vmul.f32               q3, q15, d1[1]                  \n\t"   //q3 = q15*d1[1]
+       "vmul.f32               q2, q14, d1[0]                  \n\t"   //q2 = q14*d1[0]
+       "vmul.f32               q1, q13, d0[1]                  \n\t"   //q1 = q13*d0[1]
+       "vmul.f32               q0, q12, d0[0]                  \n\t"   //q0 = q12*d0[0]
+
+       "vst1.32                {d0, d1}, [%1]              \n\t"       //d0={nx,ny,nz,pad}
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vst1.32                {d2, d3}, [%1]              \n\t"       //d2={nx,ny,nz,pad}
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vst1.32                {d4, d5}, [%1]              \n\t"       //d4={nx,ny,nz,pad}
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+    "vst1.32           {d6, d7}, [%1]          \n\t"   //d6={nx,ny,nz,pad}
+
+    : "+&r"(mtx), "+&r"(ptr)
+    : "I"(sizeof(SPVertex)), "I"(3 * sizeof(SPVertex))
+    : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+      "d16","d17", "d18","d19", "d20", "d21", "d22",
+      "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+      "d30", "d31", "memory"
+       );
+}
+
+static void gSPLightVertex4NEON(u32 v)
+{
+    volatile float result[16];
+
+       volatile int i = gSP.numLights;
+    volatile int tmp = 0;
+    volatile void *ptr0 = &(gSP.lights[0].r);
+    volatile void *ptr1 = &(OGL.triangles.vertices[v].nx);
+    volatile void *ptr2 = result;
+       volatile void *ptr3 = gSP.matrix.modelView[gSP.matrix.modelViewi];
+       asm volatile (
+    "vld1.32           {d0, d1}, [%1]                  \n\t"   //q0 = {x,y,z,w}
+       "add                %1, %1, %2                  \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d2, d3}, [%1]          \n\t"   //q1 = {x,y,z,w}
+       "add                %1, %1, %2                  \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d4, d5}, [%1]          \n\t"   //q2 = {x,y,z,w}
+       "add                %1, %1, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d6, d7}, [%1]          \n\t"   //q3 = {x,y,z,w}
+    "sub                   %1, %1, %3                          \n\t"   //q0 = {x,y,z,w}
+
+       "vld1.32                {d18, d19}, [%0]!               \n\t"   //q9 = m
+       "vld1.32                {d20, d21}, [%0]!           \n\t"       //q10 = m+16
+       "vld1.32                {d22, d23}, [%0]        \n\t"   //q11 = m+32
+
+       "vmul.f32               q12, q9, d0[0]                  \n\t"   //q12 = q9*d0[0]
+       "vmul.f32               q13, q9, d2[0]                  \n\t"   //q13 = q9*d2[0]
+    "vmul.f32          q14, q9, d4[0]                  \n\t"   //q14 = q9*d4[0]
+    "vmul.f32          q15, q9, d6[0]                  \n\t"   //q15 = q9*d6[0]
+
+    "vmla.f32          q12, q10, d0[1]                 \n\t"   //q12 += q10*q0[1]
+    "vmla.f32          q13, q10, d2[1]                 \n\t"   //q13 += q10*q2[1]
+    "vmla.f32          q14, q10, d4[1]                 \n\t"   //q14 += q10*q4[1]
+    "vmla.f32          q15, q10, d6[1]                 \n\t"   //q15 += q10*q6[1]
+
+       "vmla.f32               q12, q11, d1[0]                 \n\t"   //q12 += q11*d1[0]
+       "vmla.f32               q13, q11, d3[0]                 \n\t"   //q13 += q11*d3[0]
+       "vmla.f32               q14, q11, d5[0]                 \n\t"   //q14 += q11*d5[0]
+       "vmla.f32               q15, q11, d7[0]                 \n\t"   //q15 += q11*d7[0]
+
+    "vmul.f32          q0, q12, q12                    \n\t"   //q0 = q12*q12
+    "vmul.f32          q1, q13, q13                    \n\t"   //q1 = q13*q13
+    "vmul.f32          q2, q14, q14                    \n\t"   //q2 = q14*q14
+    "vmul.f32          q3, q15, q15                    \n\t"   //q3 = q15*q15
+
+    "vpadd.f32                 d0, d0                                  \n\t"   //d0[0] = d0[0] + d0[1]
+    "vpadd.f32                 d2, d2                                  \n\t"   //d2[0] = d2[0] + d2[1]
+    "vpadd.f32                 d4, d4                                  \n\t"   //d4[0] = d4[0] + d4[1]
+    "vpadd.f32                 d6, d6                                  \n\t"   //d6[0] = d6[0] + d6[1]
+
+    "vmov.f32          s1, s2                                  \n\t"   //d0[1] = d1[0]
+    "vmov.f32      s5, s6                              \n\t"   //d2[1] = d3[0]
+    "vmov.f32      s9, s10                             \n\t"   //d4[1] = d5[0]
+    "vmov.f32          s13, s14                                \n\t"   //d6[1] = d7[0]
+
+    "vpadd.f32                 d0, d0, d2                      \n\t"   //d0 = {d0[0] + d0[1], d2[0] + d2[1]}
+    "vpadd.f32                 d1, d4, d6                      \n\t"   //d1 = {d4[0] + d4[1], d6[0] + d6[1]}
+
+       "vmov.f32               q1, q0                                  \n\t"   //q1 = q0
+       "vrsqrte.f32    q0, q0                                  \n\t"   //q0 = ~ 1.0 / sqrt(q0)
+       "vmul.f32               q2, q0, q1                              \n\t"   //q2 = q0 * q1
+       "vrsqrts.f32    q3, q2, q0                              \n\t"   //q3 = (3 - q0 * q2) / 2
+       "vmul.f32               q0, q0, q3                              \n\t"   //q0 = q0 * q3
+       "vmul.f32               q2, q0, q1                              \n\t"   //q2 = q0 * q1
+       "vrsqrts.f32    q3, q2, q0                              \n\t"   //q3 = (3 - q0 * q2) / 2
+       "vmul.f32               q0, q0, q3                              \n\t"   //q0 = q0 * q3
+
+       "vmul.f32               q3, q15, d1[1]                  \n\t"   //q3 = q15*d1[1]
+       "vmul.f32               q2, q14, d1[0]                  \n\t"   //q2 = q14*d1[0]
+       "vmul.f32               q1, q13, d0[1]                  \n\t"   //q1 = q13*d0[1]
+       "vmul.f32               q0, q12, d0[0]                  \n\t"   //q0 = q12*d0[0]
+
+       "vst1.32                {d0, d1}, [%1]              \n\t"       //d0={nx,ny,nz,pad}
+       "add                %1, %1, %2                      \n\t"       //q0 = {x,y,z,w}
+       "vst1.32                {d2, d3}, [%1]              \n\t"       //d2={nx,ny,nz,pad}
+       "add                %1, %1, %2                      \n\t"       //q0 = {x,y,z,w}
+       "vst1.32                {d4, d5}, [%1]              \n\t"       //d4={nx,ny,nz,pad}
+       "add                %1, %1, %2                      \n\t"       //q0 = {x,y,z,w}
+    "vst1.32           {d6, d7}, [%1]          \n\t"   //d6={nx,ny,nz,pad}
+
+    : "+&r"(ptr3), "+&r"(ptr1)
+    : "I"(sizeof(SPVertex)), "I"(3 * sizeof(SPVertex))
+    : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+      "d16","d17", "d18","d19", "d20", "d21", "d22",
+      "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+      "d30", "d31", "memory"
+       );
+    asm volatile (
+
+    "mov               %0, %5                          \n\t"   //r0=sizeof(light)
+    "mla               %0, %1, %0, %2                  \n\t"   //r0=r1*r0+r2
+
+    "vmov.f32          q8, q0                              \n\t"       //q8=q0
+    "vmov.f32          q9, q1                              \n\t"       //q9=q1
+    "vmov.f32          q10, q2                             \n\t"       //q10=q2
+    "vmov.f32          q11, q3                             \n\t"       //q11=q3
+
+    "vld1.32           {d0}, [%0]                          \n\t"       //d0={r,g}
+    "flds              s2, [%0, #8]                    \n\t"   //d1[0]={b}
+    "vmov.f32          q1, q0                              \n\t"       //q1=q0
+    "vmov.f32          q2, q0                              \n\t"       //q2=q0
+    "vmov.f32          q3, q0                              \n\t"       //q3=q0
+
+    "vmov.f32          q15, #0.0                       \n\t"   //q15=0
+    "vdup.f32          q15, d30[0]                     \n\t"   //q15=d30[0]
+
+    "cmp               %1, #0                          \n\t"   //
+    "beq               2f                              \n\t"   //(r1==0) goto 2
+
+    "1:                                                \n\t"   //
+    "vld1.32           {d8}, [%2]!                     \n\t"   //d8={r,g}
+    "flds              s18, [%2]               \n\t"   //q9[0]={b}
+    "add               %2, %2, #4              \n\t"   //q9[0]={b}
+    "vld1.32           {d10}, [%2]!                    \n\t"   //d10={x,y}
+    "flds              s22, [%2]               \n\t"   //d11[0]={z}
+    "add               %2, %2, #4              \n\t"   //q9[0]={b}
+
+    "vmov.f32          q13, q5                         \n\t"   //q13 = q5
+    "vmov.f32          q12, q4                         \n\t"   //q12 = q4
+
+    "vmul.f32          q4, q8, q13                     \n\t"   //q4 = q8*q13
+    "vmul.f32          q5, q9, q13                     \n\t"   //q5 = q9*q13
+    "vmul.f32          q6, q10, q13            \n\t"   //q6 = q10*q13
+    "vmul.f32          q7, q11, q13            \n\t"   //q7 = q11*q13
+
+    "vpadd.f32                 d8, d8                                  \n\t"   //d8[0] = d8[0] + d8[1]
+    "vpadd.f32                 d10, d10                                \n\t"   //d10[0] = d10[0] + d10[1]
+    "vpadd.f32                 d12, d12                                \n\t"   //d12[0] = d12[0] + d12[1]
+    "vpadd.f32                 d14, d14                                \n\t"   //d14[0] = d14[0] + d14[1]
+
+    "vmov.f32          s17, s18                                \n\t"   //d8[1] = d9[0]
+    "vmov.f32          s21, s22                                \n\t"   //d10[1] = d11[0]
+    "vmov.f32          s25, s26                                \n\t"   //d12[1] = d13[0]
+    "vmov.f32          s29, s30                                \n\t"   //d14[1] = d15[0]
+
+    "vpadd.f32                 d8, d8, d10                     \n\t"   //d8 = {d8[0] + d8[1], d10[0] + d10[1]}
+    "vpadd.f32                 d9, d12, d14                    \n\t"   //d9 = {d12[0] + d12[1], d14[0] + d14[1]}
+
+    "vmax.f32          q4, q4, q15                     \n\t"   //q4=max(q4, 0)
+
+    "vmla.f32          q0, q12, d8[0]                  \n\t"   //q0 +=
+    "vmla.f32          q1, q12, d8[1]                  \n\t"   //d1 = {d4[0] + d4[1], d6[0] + d6[1]}
+    "vmla.f32          q2, q12, d9[0]                  \n\t"   //d1 = {d4[0] + d4[1], d6[0] + d6[1]}
+    "vmla.f32          q3, q12, d9[1]                  \n\t"   //d1 = {d4[0] + d4[1], d6[0] + d6[1]}
+
+    "subs              %1, %1, #1                      \n\t"   //r1=r1 - 1
+    "bne               1b                              \n\t"   //(r1!=0) goto 1
+
+    "2:                                                \n\t"   //
+
+    "vmov.f32        q4, #1.0                  \n\t"   //
+    "vmin.f32          q0, q0, q4              \n\t"   //
+    "vmin.f32          q1, q1, q4              \n\t"   //
+    "vmin.f32          q2, q2, q4              \n\t"   //
+    "vmin.f32          q3, q3, q4              \n\t"   //
+    "vst1.32           {d0, d1}, [%4]!         \n\t"   //
+    "vst1.32           {d2, d3}, [%4]!             \n\t"       //
+    "vst1.32           {d4, d5}, [%4]!         \n\t"   //
+    "vst1.32           {d6, d7}, [%4]              \n\t"       //
+
+    : "+&r"(tmp), "+&r"(i), "+&r"(ptr0), "+&r"(ptr1), "+&r"(ptr2)
+    : "I"(sizeof(SPLight))
+    : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+      "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
+      "d16","d17", "d18","d19", "d20", "d21", "d22", "d23",
+      "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
+      "memory", "cc"
+    );
+    OGL.triangles.vertices[v].r = result[0];
+    OGL.triangles.vertices[v].g = result[1];
+    OGL.triangles.vertices[v].b = result[2];
+    OGL.triangles.vertices[v+1].r = result[4];
+    OGL.triangles.vertices[v+1].g = result[5];
+    OGL.triangles.vertices[v+1].b = result[6];
+    OGL.triangles.vertices[v+2].r = result[8];
+    OGL.triangles.vertices[v+2].g = result[9];
+    OGL.triangles.vertices[v+2].b = result[10];
+    OGL.triangles.vertices[v+3].r = result[12];
+    OGL.triangles.vertices[v+3].g = result[13];
+    OGL.triangles.vertices[v+3].b = result[14];
+}
+
+static void gSPBillboardVertex4NEON(u32 v)
+{
+    int i = 0;
+
+#ifdef __TRIBUFFER_OPT
+    i = OGL.triangles.indexmap[0];
+#endif
+
+    void *ptr0 = (void*)&OGL.triangles.vertices[v].x;
+    void *ptr1 = (void*)&OGL.triangles.vertices[i].x;
+    asm volatile (
+
+    "vld1.32           {d0, d1}, [%0]                  \n\t"   //q0 = {x,y,z,w}
+       "add                %0, %0, %2                      \n\t"       //q0 = {x,y,z,w}
+       "vld1.32                {d2, d3}, [%0]          \n\t"   //q1 = {x,y,z,w}
+       "add                %0, %0, %2                  \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d4, d5}, [%0]          \n\t"   //q2 = {x,y,z,w}
+       "add                %0, %0, %2                  \n\t"   //q0 = {x,y,z,w}
+       "vld1.32                {d6, d7}, [%0]          \n\t"   //q3 = {x,y,z,w}
+    "sub                   %0, %0, %3                          \n\t"   //q0 = {x,y,z,w}
+
+    "vld1.32           {d16, d17}, [%1]                \n\t"   //q2={x1,y1,z1,w1}
+    "vadd.f32          q0, q0, q8                          \n\t"       //q1=q1+q1
+    "vadd.f32          q1, q1, q8                          \n\t"       //q1=q1+q1
+    "vadd.f32          q2, q2, q8                          \n\t"       //q1=q1+q1
+    "vadd.f32          q3, q3, q8                          \n\t"       //q1=q1+q1
+    "vst1.32           {d0, d1}, [%0]              \n\t"       //
+    "add                   %0, %0, %2                          \n\t"   //q0 = {x,y,z,w}
+       "vst1.32                {d2, d3}, [%0]          \n\t"   //
+    "add                   %0, %0, %2                      \n\t"       //q0 = {x,y,z,w}
+       "vst1.32                {d4, d5}, [%0]          \n\t"   //
+    "add                   %0, %0, %2                      \n\t"       //q0 = {x,y,z,w}
+       "vst1.32                {d6, d7}, [%0]          \n\t"   //
+    : "+&r"(ptr0), "+&r"(ptr1)
+    : "I"(sizeof(SPVertex)), "I"(3 * sizeof(SPVertex))
+    : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+      "d16", "d17", "memory"
+    );
+}
+#endif
+
+static void gSPTransformVertexNEON(float vtx[4], float mtx[4][4])
+{
+//optimised using cycle analyser
+#if 0
+    volatile int tmp0, tmp1;
+       asm volatile (
+       "vld1.32                {d0, d1}, [%3, :128]            \n\t"   //q0 = *v
+       "add                %1, %0, #16                     \n\t"       //r1=r0+16
+       "vld1.32                {d18, d19}, [%0, :128]  \n\t"   //q9 = m
+       "add                %2, %0, #32                     \n\t"       //r2=r0+32
+       "vld1.32                {d20, d21}, [%1, :128]    \n\t" //q10 = m+4
+       "add                %0, %0, #48                     \n\t"       //r0=r0+48
+       "vld1.32                {d22, d23}, [%2, :128]          \n\t"   //q11 = m+8
+       "vld1.32                {d24, d25}, [%0, :128]          \n\t"   //q12 = m+12
+
+    "vmla.f32          q12, q9, d0[0]          \n\t"   //q12 = q12 + q9*Q0[0]
+    "vmul.f32          q13, q10, d0[1]         \n\t"   //q13 = Q10*Q0[1]
+    "vmul.f32          q14, q11, d1[0]         \n\t"   //q14 = Q11*Q0[2]
+    "vadd.f32          q12, q12, q13           \n\t"   //q12 = q12 + q14
+    "vadd.f32          q12, q12, q14           \n\t"   //Q12 = q12 + q15
+
+       "vst1.32                {d24, d25}, [%3, :128]  \n\t"   //*v = q12
+
+       : "+r"(mtx), "+r"(tmp0), "+r"(tmp1) : "r"(vtx)
+    : "d0", "d1", "d18","d19","d20","d21","d22","d23","d24","d25",
+       "d26", "d27", "memory"
+       );
+
+#else
+       asm volatile (
+       "vld1.32                {d0, d1}, [%1]                  \n\t"   //d8 = {x,y}
+       "vld1.32                {d18, d19}, [%0]!               \n\t"   //Q1 = m
+       "vld1.32                {d20, d21}, [%0]!       \n\t"   //Q2 = m+4
+       "vld1.32                {d22, d23}, [%0]!       \n\t"   //Q3 = m+8
+       "vld1.32                {d24, d25}, [%0]        \n\t"   //Q4 = m+12
+
+       "vmul.f32               q13, q9, d0[0]                  \n\t"   //Q5 = Q1*Q0[0]
+       "vmla.f32               q13, q10, d0[1]                 \n\t"   //Q5 += Q1*Q0[1]
+       "vmla.f32               q13, q11, d1[0]                 \n\t"   //Q5 += Q2*Q0[2]
+       "vadd.f32               q13, q13, q12                   \n\t"   //Q5 += Q3*Q0[3]
+       "vst1.32                {d26, d27}, [%1]                \n\t"   //Q4 = m+12
+
+       : "+r"(mtx) : "r"(vtx)
+    : "d0", "d1", "d18","d19","d20","d21","d22","d23","d24","d25",
+       "d26", "d27", "memory"
+       );
+#endif
+}
+
+static void gSPLightVertexNEON(u32 v)
+{
+    volatile float result[4];
+
+    volatile int tmp = 0;
+    volatile int i = gSP.numLights;
+    volatile void *ptr0 = &gSP.lights[0].r;
+    volatile void *ptr1 = &OGL.triangles.vertices[v].nx;
+    volatile void *ptr2 = result;;
+    volatile void *ptr3 = gSP.matrix.modelView[gSP.matrix.modelViewi];
+
+       asm volatile (
+       "vld1.32                {d0, d1}, [%1]                  \n\t"   //Q0 = v
+       "vld1.32                {d18, d19}, [%0]!               \n\t"   //Q1 = m
+       "vld1.32                {d20, d21}, [%0]!           \n\t"       //Q2 = m+4
+       "vld1.32                {d22, d23}, [%0]            \n\t"       //Q3 = m+8
+
+       "vmul.f32               q2, q9, d0[0]                   \n\t"   //q2 = q9*Q0[0]
+       "vmla.f32               q2, q10, d0[1]                  \n\t"   //Q5 += Q1*Q0[1]
+       "vmla.f32               q2, q11, d1[0]                  \n\t"   //Q5 += Q2*Q0[2]
+
+    "vmul.f32          d0, d4, d4                              \n\t"   //d0 = d0*d0
+       "vpadd.f32              d0, d0, d0                              \n\t"   //d0 = d[0] + d[1]
+    "vmla.f32          d0, d5, d5                              \n\t"   //d0 = d0 + d5*d5
+
+       "vmov.f32               d1, d0                                  \n\t"   //d1 = d0
+       "vrsqrte.f32    d0, d0                                  \n\t"   //d0 = ~ 1.0 / sqrt(d0)
+       "vmul.f32               d2, d0, d1                              \n\t"   //d2 = d0 * d1
+       "vrsqrts.f32    d3, d2, d0                              \n\t"   //d3 = (3 - d0 * d2) / 2
+       "vmul.f32               d0, d0, d3                              \n\t"   //d0 = d0 * d3
+       "vmul.f32               d2, d0, d1                              \n\t"   //d2 = d0 * d1
+       "vrsqrts.f32    d3, d2, d0                              \n\t"   //d3 = (3 - d0 * d3) / 2
+       "vmul.f32               d0, d0, d3                              \n\t"   //d0 = d0 * d4
+
+       "vmul.f32               q1, q2, d0[0]                   \n\t"   //q1 = d2*d4
+
+       "vst1.32                {d2, d3}, [%1]              \n\t"       //d0={nx,ny,nz,pad}
+
+       : "+&r"(ptr3): "r"(ptr1)
+    : "d0","d1","d2","d3","d18","d19","d20","d21","d22", "d23", "memory"
+       );
+
+    asm volatile (
+    "mov               %0, #24                         \n\t"   //r0=24
+    "mla               %0, %1, %0, %2                  \n\t"   //r0=r1*r0+r2
+
+    "vld1.32           {d0}, [%0]!                     \n\t"   //d0={r,g}
+    "flds              s2, [%0]                        \n\t"   //d1[0]={b}
+    "cmp            %0, #0                             \n\t"   //
+    "beq            2f                         \n\t"   //(r1==0) goto 2
+
+    "1:                                                \n\t"   //
+    "vld1.32           {d4}, [%2]!                     \n\t"   //d4={r,g}
+    "flds              s10, [%2]                       \n\t"   //q5[0]={b}
+    "add                   %2, %2, #4                  \n\t"   //r2+=4
+    "vld1.32           {d6}, [%2]!                     \n\t"   //d6={x,y}
+    "flds              s14, [%2]                       \n\t"   //d7[0]={z}
+    "add                   %2, %2, #4                  \n\t"   //r2+=4
+    "vmul.f32          d6, d2, d6                          \n\t"       //d6=d2*d6
+    "vpadd.f32                 d6, d6                              \n\t"       //d6=d6[0]+d6[1]
+    "vmla.f32          d6, d3, d7                          \n\t"       //d6=d6+d3*d7
+    "vmov.f32          d7, #0.0                        \n\t"   //d7=0
+    "vmax.f32          d6, d6, d7                  \n\t"       //d6=max(d6, d7)
+    "vmla.f32          q0, q2, d6[0]               \n\t"       //q0=q0+q2*d6[0]
+    "sub                   %1, %1, #1                  \n\t"   //r0=r0-1
+    "cmp                   %1, #0                      \n\t"   //r0=r0-1
+    "bgt                   1b                          \n\t"   //(r1!=0) ? goto 1
+    "b                     2f                          \n\t"   //(r1!=0) ? goto 1
+    "2:                                                \n\t"   //
+    "vmov.f32        q1, #1.0                  \n\t"   //
+    "vmin.f32        q0, q0, q1                        \n\t"   //
+    "vst1.32        {d0, d1}, [%3]             \n\t"   //
+
+    : "+&r"(tmp), "+&r"(i), "+&r"(ptr0), "+&r"(ptr2)
+    :: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+      "d16", "memory", "cc"
+    );
+    OGL.triangles.vertices[v].r = result[0];
+    OGL.triangles.vertices[v].g = result[1];
+    OGL.triangles.vertices[v].b = result[2];
+}
+
+static void gSPBillboardVertexNEON(u32 v, u32 i)
+{
+    asm volatile (
+    "vld1.32           {d2, d3}, [%0]                  \n\t"   //q1={x0,y0, z0, w0}
+    "vld1.32           {d4, d5}, [%1]                  \n\t"   //q2={x1,y1, z1, w1}
+    "vadd.f32          q1, q1, q2                          \n\t"       //q1=q1+q1
+    "vst1.32           {d2, d3}, [%0]              \n\t"       //
+    :: "r"(&OGL.triangles.vertices[v].x), "r"(&OGL.triangles.vertices[i].x)
+    : "d2", "d3", "d4", "d5", "memory"
+    );
+}
+
+void gSPInitNeon()
+{
+#ifdef __VEC4_OPT
+    gSPTransformVertex4 = gSPTransformVertex4NEON;
+    gSPTransformNormal4 = gSPTransformNormal4NEON;
+    gSPLightVertex4 = gSPLightVertex4NEON;
+    gSPBillboardVertex4 = gSPBillboardVertex4NEON;
+#endif
+    gSPTransformVertex = gSPTransformVertexNEON;
+    gSPLightVertex = gSPLightVertexNEON;
+    gSPBillboardVertex = gSPBillboardVertexNEON;
+}