mips.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright (c) 2005,2007 Thiemo Seufer <ths@networkno.de>
  3. *
  4. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  5. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  6. *
  7. * Permission is hereby granted to use or copy this program
  8. * for any purpose, provided the above notices are retained on all copies.
  9. * Permission to modify the code and to distribute modified code is granted,
  10. * provided the above notices are retained, and a notice that the code was
  11. * modified is included with the above copyright notice.
  12. */
  13. /*
  14. * FIXME: This should probably make finer distinctions. SGI MIPS is
  15. * much more strongly ordered, and in fact closer to sequentially
  16. * consistent. This is really aimed at modern embedded implementations.
  17. * It looks to me like this assumes a 32-bit ABI. -HB
  18. */
  19. #include "../all_aligned_atomic_load_store.h"
  20. #include "../test_and_set_t_is_ao_t.h"
  21. /* Data dependence does not imply read ordering. */
  22. #define AO_NO_DD_ORDERING
  23. #ifdef AO_ICE9A1_LLSC_WAR
  24. /* ICE9 rev A1 chip (used in very few systems) is reported to */
  25. /* have a low-frequency bug that causes LL to fail. */
  26. /* To workaround, just issue the second 'LL'. */
  27. # define AO_MIPS_LL_FIX(args_str) \
  28. " ll " args_str "\n"
  29. #else
  30. # define AO_MIPS_LL_FIX(args_str) ""
  31. #endif
  32. AO_INLINE void
  33. AO_nop_full(void)
  34. {
  35. __asm__ __volatile__(
  36. " .set push \n"
  37. " .set mips2 \n"
  38. " .set noreorder \n"
  39. " .set nomacro \n"
  40. " sync \n"
  41. " .set pop "
  42. : : : "memory");
  43. }
  44. #define AO_HAVE_nop_full
  45. #ifndef AO_PREFER_GENERALIZED
  46. AO_INLINE AO_t
  47. AO_fetch_and_add(volatile AO_t *addr, AO_t incr)
  48. {
  49. register int result;
  50. register int temp;
  51. __asm__ __volatile__(
  52. " .set push\n"
  53. " .set mips2\n"
  54. " .set noreorder\n"
  55. " .set nomacro\n"
  56. "1: ll %0, %2\n"
  57. AO_MIPS_LL_FIX("%0, %2")
  58. " addu %1, %0, %3\n"
  59. " sc %1, %2\n"
  60. " beqz %1, 1b\n"
  61. " nop\n"
  62. " .set pop "
  63. : "=&r" (result), "=&r" (temp), "+m" (*addr)
  64. : "Ir" (incr)
  65. : "memory");
  66. return (AO_t)result;
  67. }
  68. #define AO_HAVE_fetch_and_add
  69. AO_INLINE AO_TS_VAL_t
  70. AO_test_and_set(volatile AO_TS_t *addr)
  71. {
  72. register int oldval;
  73. register int temp;
  74. __asm__ __volatile__(
  75. " .set push\n"
  76. " .set mips2\n"
  77. " .set noreorder\n"
  78. " .set nomacro\n"
  79. "1: ll %0, %2\n"
  80. AO_MIPS_LL_FIX("%0, %2")
  81. " move %1, %3\n"
  82. " sc %1, %2\n"
  83. " beqz %1, 1b\n"
  84. " nop\n"
  85. " .set pop "
  86. : "=&r" (oldval), "=&r" (temp), "+m" (*addr)
  87. : "r" (1)
  88. : "memory");
  89. return (AO_TS_VAL_t)oldval;
  90. }
  91. #define AO_HAVE_test_and_set
  92. /* TODO: Implement AO_and/or/xor primitives directly. */
  93. #endif /* !AO_PREFER_GENERALIZED */
  94. #ifndef AO_GENERALIZE_ASM_BOOL_CAS
  95. AO_INLINE int
  96. AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val)
  97. {
  98. register int was_equal = 0;
  99. register int temp;
  100. __asm__ __volatile__(
  101. " .set push \n"
  102. " .set mips2 \n"
  103. " .set noreorder \n"
  104. " .set nomacro \n"
  105. "1: ll %0, %1 \n"
  106. AO_MIPS_LL_FIX("%0, %1")
  107. " bne %0, %4, 2f \n"
  108. " move %0, %3 \n"
  109. " sc %0, %1 \n"
  110. " .set pop \n"
  111. " beqz %0, 1b \n"
  112. " li %2, 1 \n"
  113. "2: "
  114. : "=&r" (temp), "+m" (*addr), "+r" (was_equal)
  115. : "r" (new_val), "r" (old)
  116. : "memory");
  117. return was_equal;
  118. }
  119. # define AO_HAVE_compare_and_swap
  120. #endif /* !AO_GENERALIZE_ASM_BOOL_CAS */
  121. AO_INLINE AO_t
  122. AO_fetch_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val)
  123. {
  124. register int fetched_val;
  125. register int temp;
  126. __asm__ __volatile__(
  127. " .set push\n"
  128. " .set mips2\n"
  129. " .set noreorder\n"
  130. " .set nomacro\n"
  131. "1: ll %0, %2\n"
  132. AO_MIPS_LL_FIX("%0, %2")
  133. " bne %0, %4, 2f\n"
  134. " move %1, %3\n"
  135. " sc %1, %2\n"
  136. " beqz %1, 1b\n"
  137. " nop\n"
  138. " .set pop\n"
  139. "2:"
  140. : "=&r" (fetched_val), "=&r" (temp), "+m" (*addr)
  141. : "r" (new_val), "Jr" (old)
  142. : "memory");
  143. return (AO_t)fetched_val;
  144. }
  145. #define AO_HAVE_fetch_compare_and_swap
  146. /* #include "../standard_ao_double_t.h" */
  147. /* TODO: Implement double-wide operations if available. */
  148. /* CAS primitives with acquire, release and full semantics are */
  149. /* generated automatically (and AO_int_... primitives are */
  150. /* defined properly after the first generalization pass). */
  151. /* FIXME: 32-bit ABI is assumed. */
  152. #define AO_T_IS_INT