PageRenderTime 24ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/target-arm/op_helper.c

https://github.com/concer/qemu-rabbits
C | 309 lines | 234 code | 36 blank | 39 comment | 18 complexity | 6e90b891898ca2b281e3e5dfa87e3efd MD5 | raw file
  1. /*
  2. * ARM helper routines
  3. *
  4. * Copyright (c) 2005-2007 CodeSourcery, LLC
  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, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "exec.h"
  21. void raise_exception(int tt)
  22. {
  23. env->exception_index = tt;
  24. cpu_loop_exit();
  25. }
  26. /* thread support */
  27. /* spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; */
  28. void cpu_lock(void)
  29. {
  30. /* spin_lock(&global_cpu_lock); */
  31. }
  32. void cpu_unlock(void)
  33. {
  34. /* spin_unlock(&global_cpu_lock); */
  35. }
  36. /* VFP support. */
  37. void do_vfp_abss(void)
  38. {
  39. FT0s = float32_abs(FT0s);
  40. }
  41. void do_vfp_absd(void)
  42. {
  43. FT0d = float64_abs(FT0d);
  44. }
  45. void do_vfp_sqrts(void)
  46. {
  47. FT0s = float32_sqrt(FT0s, &env->vfp.fp_status);
  48. }
  49. void do_vfp_sqrtd(void)
  50. {
  51. FT0d = float64_sqrt(FT0d, &env->vfp.fp_status);
  52. }
  53. /* XXX: check quiet/signaling case */
  54. #define DO_VFP_cmp(p, size) \
  55. void do_vfp_cmp##p(void) \
  56. { \
  57. uint32_t flags; \
  58. switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\
  59. case 0: flags = 0x6; break;\
  60. case -1: flags = 0x8; break;\
  61. case 1: flags = 0x2; break;\
  62. default: case 2: flags = 0x3; break;\
  63. }\
  64. env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\
  65. | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \
  66. FORCE_RET(); \
  67. }\
  68. \
  69. void do_vfp_cmpe##p(void) \
  70. { \
  71. uint32_t flags; \
  72. switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\
  73. case 0: flags = 0x6; break;\
  74. case -1: flags = 0x8; break;\
  75. case 1: flags = 0x2; break;\
  76. default: case 2: flags = 0x3; break;\
  77. }\
  78. env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\
  79. | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \
  80. FORCE_RET(); \
  81. }
  82. DO_VFP_cmp(s, 32)
  83. DO_VFP_cmp(d, 64)
  84. #undef DO_VFP_cmp
  85. /* Convert host exception flags to vfp form. */
  86. static inline int vfp_exceptbits_from_host(int host_bits)
  87. {
  88. int target_bits = 0;
  89. if (host_bits & float_flag_invalid)
  90. target_bits |= 1;
  91. if (host_bits & float_flag_divbyzero)
  92. target_bits |= 2;
  93. if (host_bits & float_flag_overflow)
  94. target_bits |= 4;
  95. if (host_bits & float_flag_underflow)
  96. target_bits |= 8;
  97. if (host_bits & float_flag_inexact)
  98. target_bits |= 0x10;
  99. return target_bits;
  100. }
  101. /* Convert vfp exception flags to target form. */
  102. static inline int vfp_exceptbits_to_host(int target_bits)
  103. {
  104. int host_bits = 0;
  105. if (target_bits & 1)
  106. host_bits |= float_flag_invalid;
  107. if (target_bits & 2)
  108. host_bits |= float_flag_divbyzero;
  109. if (target_bits & 4)
  110. host_bits |= float_flag_overflow;
  111. if (target_bits & 8)
  112. host_bits |= float_flag_underflow;
  113. if (target_bits & 0x10)
  114. host_bits |= float_flag_inexact;
  115. return host_bits;
  116. }
  117. void do_vfp_set_fpscr(void)
  118. {
  119. int i;
  120. uint32_t changed;
  121. changed = env->vfp.xregs[ARM_VFP_FPSCR];
  122. env->vfp.xregs[ARM_VFP_FPSCR] = (T0 & 0xffc8ffff);
  123. env->vfp.vec_len = (T0 >> 16) & 7;
  124. env->vfp.vec_stride = (T0 >> 20) & 3;
  125. changed ^= T0;
  126. if (changed & (3 << 22)) {
  127. i = (T0 >> 22) & 3;
  128. switch (i) {
  129. case 0:
  130. i = float_round_nearest_even;
  131. break;
  132. case 1:
  133. i = float_round_up;
  134. break;
  135. case 2:
  136. i = float_round_down;
  137. break;
  138. case 3:
  139. i = float_round_to_zero;
  140. break;
  141. }
  142. set_float_rounding_mode(i, &env->vfp.fp_status);
  143. }
  144. i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f);
  145. set_float_exception_flags(i, &env->vfp.fp_status);
  146. /* XXX: FZ and DN are not implemented. */
  147. }
  148. void do_vfp_get_fpscr(void)
  149. {
  150. int i;
  151. T0 = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) | (env->vfp.vec_len << 16)
  152. | (env->vfp.vec_stride << 20);
  153. i = get_float_exception_flags(&env->vfp.fp_status);
  154. T0 |= vfp_exceptbits_from_host(i);
  155. }
  156. float32 helper_recps_f32(float32 a, float32 b)
  157. {
  158. float_status *s = &env->vfp.fp_status;
  159. float32 two = int32_to_float32(2, s);
  160. return float32_sub(two, float32_mul(a, b, s), s);
  161. }
  162. float32 helper_rsqrts_f32(float32 a, float32 b)
  163. {
  164. float_status *s = &env->vfp.fp_status;
  165. float32 three = int32_to_float32(3, s);
  166. return float32_sub(three, float32_mul(a, b, s), s);
  167. }
  168. /* TODO: The architecture specifies the value that the estimate functions
  169. should return. We return the exact reciprocal/root instead. */
  170. float32 helper_recpe_f32(float32 a)
  171. {
  172. float_status *s = &env->vfp.fp_status;
  173. float32 one = int32_to_float32(1, s);
  174. return float32_div(one, a, s);
  175. }
  176. float32 helper_rsqrte_f32(float32 a)
  177. {
  178. float_status *s = &env->vfp.fp_status;
  179. float32 one = int32_to_float32(1, s);
  180. return float32_div(one, float32_sqrt(a, s), s);
  181. }
  182. uint32_t helper_recpe_u32(uint32_t a)
  183. {
  184. float_status *s = &env->vfp.fp_status;
  185. float32 tmp;
  186. tmp = int32_to_float32(a, s);
  187. tmp = float32_scalbn(tmp, -32, s);
  188. tmp = helper_recpe_f32(tmp);
  189. tmp = float32_scalbn(tmp, 31, s);
  190. return float32_to_int32(tmp, s);
  191. }
  192. uint32_t helper_rsqrte_u32(uint32_t a)
  193. {
  194. float_status *s = &env->vfp.fp_status;
  195. float32 tmp;
  196. tmp = int32_to_float32(a, s);
  197. tmp = float32_scalbn(tmp, -32, s);
  198. tmp = helper_rsqrte_f32(tmp);
  199. tmp = float32_scalbn(tmp, 31, s);
  200. return float32_to_int32(tmp, s);
  201. }
  202. void helper_neon_tbl(int rn, int maxindex)
  203. {
  204. uint32_t val;
  205. uint32_t mask;
  206. uint32_t tmp;
  207. int index;
  208. int shift;
  209. uint64_t *table;
  210. table = (uint64_t *)&env->vfp.regs[rn];
  211. val = 0;
  212. mask = 0;
  213. for (shift = 0; shift < 32; shift += 8) {
  214. index = (T1 >> shift) & 0xff;
  215. if (index <= maxindex) {
  216. tmp = (table[index >> 3] >> (index & 7)) & 0xff;
  217. val |= tmp << shift;
  218. } else {
  219. val |= T0 & (0xff << shift);
  220. }
  221. }
  222. T0 = val;
  223. }
  224. #if !defined(CONFIG_USER_ONLY)
  225. #define MMUSUFFIX _mmu
  226. #ifdef __s390__
  227. # define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
  228. #else
  229. # define GETPC() (__builtin_return_address(0))
  230. #endif
  231. #define SHIFT 0
  232. #include "softmmu_template.h"
  233. #define SHIFT 1
  234. #include "softmmu_template.h"
  235. #define SHIFT 2
  236. #include "softmmu_template.h"
  237. #define SHIFT 3
  238. #include "softmmu_template.h"
  239. /* try to fill the TLB and return an exception if error. If retaddr is
  240. NULL, it means that the function was called in C code (i.e. not
  241. from generated code or from helper.c) */
  242. /* XXX: fix it to restore all registers */
  243. void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
  244. {
  245. TranslationBlock *tb;
  246. CPUState *saved_env;
  247. unsigned long pc;
  248. int ret;
  249. unsigned char save_b_use_backdoor = b_use_backdoor;
  250. b_use_backdoor = 1;
  251. /* XXX: hack to restore env in all cases, even if not called from
  252. generated code */
  253. saved_env = env;
  254. env = cpu_single_env;
  255. ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
  256. if (__builtin_expect(ret, 0)) {
  257. if (retaddr) {
  258. /* now we have a real cpu fault */
  259. pc = (unsigned long)retaddr;
  260. tb = tb_find_pc(pc);
  261. if (tb) {
  262. /* the PC is inside the translated code. It means that we have
  263. a virtual CPU fault */
  264. cpu_restore_state(tb, env, pc, NULL);
  265. }
  266. }
  267. b_use_backdoor = save_b_use_backdoor;
  268. raise_exception(env->exception_index);
  269. }
  270. env = saved_env;
  271. b_use_backdoor = save_b_use_backdoor;
  272. }
  273. #endif