helper.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Misc Sparc helpers
  3. *
  4. * Copyright (c) 2003-2005 Fabrice Bellard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "cpu.h"
  20. #include "qemu/host-utils.h"
  21. #include "exec/helper-proto.h"
  22. #include "sysemu/sysemu.h"
  23. void helper_raise_exception(CPUSPARCState *env, int tt)
  24. {
  25. CPUState *cs = CPU(sparc_env_get_cpu(env));
  26. cs->exception_index = tt;
  27. cpu_loop_exit(cs);
  28. }
  29. void helper_debug(CPUSPARCState *env)
  30. {
  31. CPUState *cs = CPU(sparc_env_get_cpu(env));
  32. cs->exception_index = EXCP_DEBUG;
  33. cpu_loop_exit(cs);
  34. }
  35. #ifdef TARGET_SPARC64
  36. target_ulong helper_popc(target_ulong val)
  37. {
  38. return ctpop64(val);
  39. }
  40. void helper_tick_set_count(void *opaque, uint64_t count)
  41. {
  42. #if !defined(CONFIG_USER_ONLY)
  43. cpu_tick_set_count(opaque, count);
  44. #endif
  45. }
  46. uint64_t helper_tick_get_count(void *opaque)
  47. {
  48. #if !defined(CONFIG_USER_ONLY)
  49. return cpu_tick_get_count(opaque);
  50. #else
  51. return 0;
  52. #endif
  53. }
  54. void helper_tick_set_limit(void *opaque, uint64_t limit)
  55. {
  56. #if !defined(CONFIG_USER_ONLY)
  57. cpu_tick_set_limit(opaque, limit);
  58. #endif
  59. }
  60. #endif
  61. static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a,
  62. target_ulong b, int cc)
  63. {
  64. SPARCCPU *cpu = sparc_env_get_cpu(env);
  65. int overflow = 0;
  66. uint64_t x0;
  67. uint32_t x1;
  68. x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
  69. x1 = (b & 0xffffffff);
  70. if (x1 == 0) {
  71. cpu_restore_state(CPU(cpu), GETPC());
  72. helper_raise_exception(env, TT_DIV_ZERO);
  73. }
  74. x0 = x0 / x1;
  75. if (x0 > UINT32_MAX) {
  76. x0 = UINT32_MAX;
  77. overflow = 1;
  78. }
  79. if (cc) {
  80. env->cc_dst = x0;
  81. env->cc_src2 = overflow;
  82. env->cc_op = CC_OP_DIV;
  83. }
  84. return x0;
  85. }
  86. target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
  87. {
  88. return helper_udiv_common(env, a, b, 0);
  89. }
  90. target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
  91. {
  92. return helper_udiv_common(env, a, b, 1);
  93. }
  94. static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a,
  95. target_ulong b, int cc)
  96. {
  97. SPARCCPU *cpu = sparc_env_get_cpu(env);
  98. int overflow = 0;
  99. int64_t x0;
  100. int32_t x1;
  101. x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
  102. x1 = (b & 0xffffffff);
  103. if (x1 == 0) {
  104. cpu_restore_state(CPU(cpu), GETPC());
  105. helper_raise_exception(env, TT_DIV_ZERO);
  106. } else if (x1 == -1 && x0 == INT64_MIN) {
  107. x0 = INT32_MAX;
  108. overflow = 1;
  109. } else {
  110. x0 = x0 / x1;
  111. if ((int32_t) x0 != x0) {
  112. x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
  113. overflow = 1;
  114. }
  115. }
  116. if (cc) {
  117. env->cc_dst = x0;
  118. env->cc_src2 = overflow;
  119. env->cc_op = CC_OP_DIV;
  120. }
  121. return x0;
  122. }
  123. target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
  124. {
  125. return helper_sdiv_common(env, a, b, 0);
  126. }
  127. target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
  128. {
  129. return helper_sdiv_common(env, a, b, 1);
  130. }
  131. #ifdef TARGET_SPARC64
  132. int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
  133. {
  134. if (b == 0) {
  135. /* Raise divide by zero trap. */
  136. SPARCCPU *cpu = sparc_env_get_cpu(env);
  137. cpu_restore_state(CPU(cpu), GETPC());
  138. helper_raise_exception(env, TT_DIV_ZERO);
  139. } else if (b == -1) {
  140. /* Avoid overflow trap with i386 divide insn. */
  141. return -a;
  142. } else {
  143. return a / b;
  144. }
  145. }
  146. uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
  147. {
  148. if (b == 0) {
  149. /* Raise divide by zero trap. */
  150. SPARCCPU *cpu = sparc_env_get_cpu(env);
  151. cpu_restore_state(CPU(cpu), GETPC());
  152. helper_raise_exception(env, TT_DIV_ZERO);
  153. }
  154. return a / b;
  155. }
  156. #endif
  157. target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
  158. target_ulong src2)
  159. {
  160. SPARCCPU *cpu = sparc_env_get_cpu(env);
  161. target_ulong dst;
  162. /* Tag overflow occurs if either input has bits 0 or 1 set. */
  163. if ((src1 | src2) & 3) {
  164. goto tag_overflow;
  165. }
  166. dst = src1 + src2;
  167. /* Tag overflow occurs if the addition overflows. */
  168. if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
  169. goto tag_overflow;
  170. }
  171. /* Only modify the CC after any exceptions have been generated. */
  172. env->cc_op = CC_OP_TADDTV;
  173. env->cc_src = src1;
  174. env->cc_src2 = src2;
  175. env->cc_dst = dst;
  176. return dst;
  177. tag_overflow:
  178. cpu_restore_state(CPU(cpu), GETPC());
  179. helper_raise_exception(env, TT_TOVF);
  180. }
  181. target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
  182. target_ulong src2)
  183. {
  184. SPARCCPU *cpu = sparc_env_get_cpu(env);
  185. target_ulong dst;
  186. /* Tag overflow occurs if either input has bits 0 or 1 set. */
  187. if ((src1 | src2) & 3) {
  188. goto tag_overflow;
  189. }
  190. dst = src1 - src2;
  191. /* Tag overflow occurs if the subtraction overflows. */
  192. if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
  193. goto tag_overflow;
  194. }
  195. /* Only modify the CC after any exceptions have been generated. */
  196. env->cc_op = CC_OP_TSUBTV;
  197. env->cc_src = src1;
  198. env->cc_src2 = src2;
  199. env->cc_dst = dst;
  200. return dst;
  201. tag_overflow:
  202. cpu_restore_state(CPU(cpu), GETPC());
  203. helper_raise_exception(env, TT_TOVF);
  204. }
  205. #ifndef TARGET_SPARC64
  206. void helper_power_down(CPUSPARCState *env)
  207. {
  208. CPUState *cs = CPU(sparc_env_get_cpu(env));
  209. cs->halted = 1;
  210. cs->exception_index = EXCP_HLT;
  211. env->pc = env->npc;
  212. env->npc = env->pc + 4;
  213. cpu_loop_exit(cs);
  214. }
  215. #endif