mips32: Add support for mips32 DSP instruction set.

Add support for mips32 DSP and DSP revision 2 ASE.
More details about the mips32 DSP(r2) ASE:
http://www.mips.com/media/files/MD00566-2B-MIPSDSP-QRC-01.00.pdf
Applied patch provided by Maja Gagic <maja.gagic@rt-rk.com>



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13470 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_libcsetjmp.c b/coregrind/m_libcsetjmp.c
index 2b016a9..9d0d9ba 100644
--- a/coregrind/m_libcsetjmp.c
+++ b/coregrind/m_libcsetjmp.c
@@ -444,6 +444,58 @@
 
 #endif /* VGP_x86_linux || VGP_x86_darwin */
 
+#if defined(VGP_mips32_linux)
+
+__asm__(
+".text                          \n\t"
+".globl VG_MINIMAL_SETJMP;      \n\t"
+".align 2;                      \n\t"
+"VG_MINIMAL_SETJMP:             \n\t"  /* a0 = jmp_buf */
+"   sw   $s0,  0($a0)           \n\t"  /* Save registers s0-s7. */
+"   sw   $s1,  4($a0)           \n\t"
+"   sw   $s2,  8($a0)           \n\t"
+"   sw   $s3, 12($a0)           \n\t"
+"   sw   $s4, 16($a0)           \n\t"
+"   sw   $s5, 20($a0)           \n\t"
+"   sw   $s6, 24($a0)           \n\t"
+"   sw   $s7, 28($a0)           \n\t"
+"   sw   $s8, 32($a0)           \n\t"  /* Frame pointer. */
+"   sw   $ra, 36($a0)           \n\t"  /* Return address. */
+"   sw   $gp, 40($a0)           \n\t"  /* Global data pointer. */
+"   sw   $sp, 44($a0)           \n\t"  /* Stack pointer. */
+
+"   move $v0, $zero             \n\t"  /* Return zero. */
+"   j    $ra                    \n\t"
+"   nop                         \n\t"
+".end VG_MINIMAL_SETJMP;        \n\t"
+"                               \n\t"
+".globl VG_MINIMAL_LONGJMP;     \n\t"
+".align 2;                      \n\t"
+"VG_MINIMAL_LONGJMP:            \n\t"  /* a0 = jmp_buf */
+"   lw   $s0,  0($a0)           \n\t"  /* Restore registers s0-s7. */
+"   lw   $s1,  4($a0)           \n\t"
+"   lw   $s2,  8($a0)           \n\t"
+"   lw   $s3, 12($a0)           \n\t"
+"   lw   $s4, 16($a0)           \n\t"
+"   lw   $s5, 20($a0)           \n\t"
+"   lw   $s6, 24($a0)           \n\t"
+"   lw   $s7, 28($a0)           \n\t"
+"   lw   $s8, 32($a0)           \n\t"  /* Frame pointer. */
+"   lw   $ra, 36($a0)           \n\t"  /* Return address. */
+"   lw   $gp, 40($a0)           \n\t"  /* Global data pointer. */
+"   lw   $sp, 44($a0)           \n\t"  /* Stack pointer. */
+
+/* Checking whether second argument is zero. */
+"   bnez $a1, 1f                \n\t"
+"   nop                         \n\t"
+"   addi $a1, $a1, 1            \n\t"  /* We must return 1 if val=0. */
+"1:                             \n\t"
+"   move $v0, $a1               \n\t"  /* Return value of second argument. */
+"   j    $ra                    \n\t"
+".end VG_MINIMAL_SETJMP;        \n\t"
+);
+#endif  /* VGP_mips32_linux */
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index 256b793..0b16958 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -444,7 +444,7 @@
 /* For hwcaps detection on ppc32/64, s390x, and arm we'll need to do SIGILL
    testing, so we need a VG_MINIMAL_JMP_BUF. */
 #if defined(VGA_ppc32) || defined(VGA_ppc64) \
-    || defined(VGA_arm) || defined(VGA_s390x)
+    || defined(VGA_arm) || defined(VGA_s390x) || defined(VGA_mips32)
 #include "pub_tool_libcsetjmp.h"
 static VG_MINIMAL_JMP_BUF(env_unsup_insn);
 static void handler_unsup_insn ( Int x ) {
@@ -1400,11 +1400,63 @@
    {
      va = VexArchMIPS32;
      UInt model = VG_(get_machine_model)();
-     if (model== -1)
+     if (model == -1)
          return False;
 
      vai.hwcaps = model;
 
+     /* Same instruction set detection algorithm as for ppc32/arm... */
+     vki_sigset_t          saved_set, tmp_set;
+     vki_sigaction_fromK_t saved_sigill_act;
+     vki_sigaction_toK_t   tmp_sigill_act;
+
+     volatile Bool have_DSP, have_DSPr2;
+     Int r;
+
+     vg_assert(sizeof(vki_sigaction_fromK_t) == sizeof(vki_sigaction_toK_t));
+
+     VG_(sigemptyset)(&tmp_set);
+     VG_(sigaddset)(&tmp_set, VKI_SIGILL);
+
+     r = VG_(sigprocmask)(VKI_SIG_UNBLOCK, &tmp_set, &saved_set);
+     vg_assert(r == 0);
+
+     r = VG_(sigaction)(VKI_SIGILL, NULL, &saved_sigill_act);
+     vg_assert(r == 0);
+     tmp_sigill_act = saved_sigill_act;
+
+     /* NODEFER: signal handler does not return (from the kernel's point of
+        view), hence if it is to successfully catch a signal more than once,
+        we need the NODEFER flag. */
+     tmp_sigill_act.sa_flags &= ~VKI_SA_RESETHAND;
+     tmp_sigill_act.sa_flags &= ~VKI_SA_SIGINFO;
+     tmp_sigill_act.sa_flags |=  VKI_SA_NODEFER;
+     tmp_sigill_act.ksa_handler = handler_unsup_insn;
+     VG_(sigaction)(VKI_SIGILL, &tmp_sigill_act, NULL);
+
+     /* DSP instructions. */
+     have_DSP = True;
+     if (VG_MINIMAL_SETJMP(env_unsup_insn)) {
+        have_DSP = False;
+     } else {
+        __asm__ __volatile__(".word 0x7c3f44b8"); /* rddsp t0, 0x3f */
+     }
+
+     /* DSPr2 instructions. */
+     have_DSPr2 = True;
+     if (VG_MINIMAL_SETJMP(env_unsup_insn)) {
+        have_DSPr2 = False;
+     } else {
+        __asm__ __volatile__(".word 0x7d095351"); /* precr.qb.ph t2, t0, t1 */
+     }
+
+     VG_(convert_sigaction_fromK_to_toK)(&saved_sigill_act, &tmp_sigill_act);
+     VG_(sigaction)(VKI_SIGILL, &tmp_sigill_act, NULL);
+     VG_(sigprocmask)(VKI_SIG_SETMASK, &saved_set, NULL);
+
+     if (have_DSP) vai.hwcaps |= VEX_MIPS_ASE_DSP;
+     if (have_DSPr2) vai.hwcaps |= VEX_MIPS_ASE_DSP2P;
+     VG_(debugLog)(1, "machine", "hwcaps = 0x%x\n", vai.hwcaps);
      VG_(machine_get_cache_info)(&vai);
 
      return True;
diff --git a/include/pub_tool_libcsetjmp.h b/include/pub_tool_libcsetjmp.h
index 22f560b..cb81e93 100644
--- a/include/pub_tool_libcsetjmp.h
+++ b/include/pub_tool_libcsetjmp.h
@@ -108,6 +108,13 @@
 __attribute__((regparm(1))) // ditto
 void  VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env));
 
+#elif defined(VGP_mips32_linux)
+
+#define VG_MINIMAL_JMP_BUF(_name)        UInt _name [8+1+1+1+1]
+__attribute__((returns_twice))
+UWord VG_MINIMAL_SETJMP(VG_MINIMAL_JMP_BUF(_env));
+__attribute__((noreturn))
+void  VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env));
 
 #else
 
diff --git a/memcheck/mc_machine.c b/memcheck/mc_machine.c
index 2feec79..d9865ac 100644
--- a/memcheck/mc_machine.c
+++ b/memcheck/mc_machine.c
@@ -1060,7 +1060,15 @@
    if (o >= GOF(f30) && o+sz <= GOF(f30)+SZB(f30)) return GOF(f30);
    if (o >= GOF(f31) && o+sz <= GOF(f31)+SZB(f31)) return GOF(f31);
 
-   if ((o > GOF(NRADDR)) && (o <= GOF(NRADDR) +12 )) return -1; /*padding registers*/
+   /* Slot unused. */ 
+   if ((o > GOF(NRADDR)) && (o <= GOF(NRADDR) +12 )) return -1;
+
+   /* MIPS32 DSP ASE(r2) specific registers. */
+   if (o == GOF(DSPControl)  && sz == 4) return o;
+   if (o == GOF(ac0)  && sz == 8) return o;
+   if (o == GOF(ac1)  && sz == 8) return o;
+   if (o == GOF(ac2)  && sz == 8) return o;
+   if (o == GOF(ac3)  && sz == 8) return o;
 
    VG_(printf)("MC_(get_otrack_shadow_offset)(mips)(off=%d,sz=%d)\n",
                offset,szB);