fpu.S 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2012 Regents of the University of California
  4. * Copyright (C) 2017 SiFive
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation, version 2.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/linkage.h>
  16. #include <asm/asm.h>
  17. #include <asm/csr.h>
  18. #include <asm/asm-offsets.h>
  19. SYM_FUNC_START(__fstate_save)
  20. li a2, TASK_THREAD_F0
  21. add a0, a0, a2
  22. li t1, SR_FS
  23. csrs CSR_STATUS, t1
  24. frcsr t0
  25. fsd f0, TASK_THREAD_F0_F0(a0)
  26. fsd f1, TASK_THREAD_F1_F0(a0)
  27. fsd f2, TASK_THREAD_F2_F0(a0)
  28. fsd f3, TASK_THREAD_F3_F0(a0)
  29. fsd f4, TASK_THREAD_F4_F0(a0)
  30. fsd f5, TASK_THREAD_F5_F0(a0)
  31. fsd f6, TASK_THREAD_F6_F0(a0)
  32. fsd f7, TASK_THREAD_F7_F0(a0)
  33. fsd f8, TASK_THREAD_F8_F0(a0)
  34. fsd f9, TASK_THREAD_F9_F0(a0)
  35. fsd f10, TASK_THREAD_F10_F0(a0)
  36. fsd f11, TASK_THREAD_F11_F0(a0)
  37. fsd f12, TASK_THREAD_F12_F0(a0)
  38. fsd f13, TASK_THREAD_F13_F0(a0)
  39. fsd f14, TASK_THREAD_F14_F0(a0)
  40. fsd f15, TASK_THREAD_F15_F0(a0)
  41. fsd f16, TASK_THREAD_F16_F0(a0)
  42. fsd f17, TASK_THREAD_F17_F0(a0)
  43. fsd f18, TASK_THREAD_F18_F0(a0)
  44. fsd f19, TASK_THREAD_F19_F0(a0)
  45. fsd f20, TASK_THREAD_F20_F0(a0)
  46. fsd f21, TASK_THREAD_F21_F0(a0)
  47. fsd f22, TASK_THREAD_F22_F0(a0)
  48. fsd f23, TASK_THREAD_F23_F0(a0)
  49. fsd f24, TASK_THREAD_F24_F0(a0)
  50. fsd f25, TASK_THREAD_F25_F0(a0)
  51. fsd f26, TASK_THREAD_F26_F0(a0)
  52. fsd f27, TASK_THREAD_F27_F0(a0)
  53. fsd f28, TASK_THREAD_F28_F0(a0)
  54. fsd f29, TASK_THREAD_F29_F0(a0)
  55. fsd f30, TASK_THREAD_F30_F0(a0)
  56. fsd f31, TASK_THREAD_F31_F0(a0)
  57. sw t0, TASK_THREAD_FCSR_F0(a0)
  58. csrc CSR_STATUS, t1
  59. ret
  60. SYM_FUNC_END(__fstate_save)
  61. SYM_FUNC_START(__fstate_restore)
  62. li a2, TASK_THREAD_F0
  63. add a0, a0, a2
  64. li t1, SR_FS
  65. lw t0, TASK_THREAD_FCSR_F0(a0)
  66. csrs CSR_STATUS, t1
  67. fld f0, TASK_THREAD_F0_F0(a0)
  68. fld f1, TASK_THREAD_F1_F0(a0)
  69. fld f2, TASK_THREAD_F2_F0(a0)
  70. fld f3, TASK_THREAD_F3_F0(a0)
  71. fld f4, TASK_THREAD_F4_F0(a0)
  72. fld f5, TASK_THREAD_F5_F0(a0)
  73. fld f6, TASK_THREAD_F6_F0(a0)
  74. fld f7, TASK_THREAD_F7_F0(a0)
  75. fld f8, TASK_THREAD_F8_F0(a0)
  76. fld f9, TASK_THREAD_F9_F0(a0)
  77. fld f10, TASK_THREAD_F10_F0(a0)
  78. fld f11, TASK_THREAD_F11_F0(a0)
  79. fld f12, TASK_THREAD_F12_F0(a0)
  80. fld f13, TASK_THREAD_F13_F0(a0)
  81. fld f14, TASK_THREAD_F14_F0(a0)
  82. fld f15, TASK_THREAD_F15_F0(a0)
  83. fld f16, TASK_THREAD_F16_F0(a0)
  84. fld f17, TASK_THREAD_F17_F0(a0)
  85. fld f18, TASK_THREAD_F18_F0(a0)
  86. fld f19, TASK_THREAD_F19_F0(a0)
  87. fld f20, TASK_THREAD_F20_F0(a0)
  88. fld f21, TASK_THREAD_F21_F0(a0)
  89. fld f22, TASK_THREAD_F22_F0(a0)
  90. fld f23, TASK_THREAD_F23_F0(a0)
  91. fld f24, TASK_THREAD_F24_F0(a0)
  92. fld f25, TASK_THREAD_F25_F0(a0)
  93. fld f26, TASK_THREAD_F26_F0(a0)
  94. fld f27, TASK_THREAD_F27_F0(a0)
  95. fld f28, TASK_THREAD_F28_F0(a0)
  96. fld f29, TASK_THREAD_F29_F0(a0)
  97. fld f30, TASK_THREAD_F30_F0(a0)
  98. fld f31, TASK_THREAD_F31_F0(a0)
  99. fscsr t0
  100. csrc CSR_STATUS, t1
  101. ret
  102. SYM_FUNC_END(__fstate_restore)
  103. #define get_f32(which) fmv.x.s a0, which; j 2f
  104. #define put_f32(which) fmv.s.x which, a1; j 2f
  105. #if __riscv_xlen == 64
  106. # define get_f64(which) fmv.x.d a0, which; j 2f
  107. # define put_f64(which) fmv.d.x which, a1; j 2f
  108. #else
  109. # define get_f64(which) fsd which, 0(a1); j 2f
  110. # define put_f64(which) fld which, 0(a1); j 2f
  111. #endif
  112. .macro fp_access_prologue
  113. /*
  114. * Compute jump offset to store the correct FP register since we don't
  115. * have indirect FP register access
  116. */
  117. sll t0, a0, 3
  118. la t2, 1f
  119. add t0, t0, t2
  120. li t1, SR_FS
  121. csrs CSR_STATUS, t1
  122. jr t0
  123. 1:
  124. .endm
  125. .macro fp_access_epilogue
  126. 2:
  127. csrc CSR_STATUS, t1
  128. ret
  129. .endm
  130. #define fp_access_body(__access_func) \
  131. __access_func(f0); \
  132. __access_func(f1); \
  133. __access_func(f2); \
  134. __access_func(f3); \
  135. __access_func(f4); \
  136. __access_func(f5); \
  137. __access_func(f6); \
  138. __access_func(f7); \
  139. __access_func(f8); \
  140. __access_func(f9); \
  141. __access_func(f10); \
  142. __access_func(f11); \
  143. __access_func(f12); \
  144. __access_func(f13); \
  145. __access_func(f14); \
  146. __access_func(f15); \
  147. __access_func(f16); \
  148. __access_func(f17); \
  149. __access_func(f18); \
  150. __access_func(f19); \
  151. __access_func(f20); \
  152. __access_func(f21); \
  153. __access_func(f22); \
  154. __access_func(f23); \
  155. __access_func(f24); \
  156. __access_func(f25); \
  157. __access_func(f26); \
  158. __access_func(f27); \
  159. __access_func(f28); \
  160. __access_func(f29); \
  161. __access_func(f30); \
  162. __access_func(f31)
  163. #ifdef CONFIG_RISCV_MISALIGNED
  164. /*
  165. * Disable compressed instructions set to keep a constant offset between FP
  166. * load/store/move instructions
  167. */
  168. .option norvc
  169. /*
  170. * put_f32_reg - Set a FP register from a register containing the value
  171. * a0 = FP register index to be set
  172. * a1 = value to be loaded in the FP register
  173. */
  174. SYM_FUNC_START(put_f32_reg)
  175. fp_access_prologue
  176. fp_access_body(put_f32)
  177. fp_access_epilogue
  178. SYM_FUNC_END(put_f32_reg)
  179. /*
  180. * get_f32_reg - Get a FP register value and return it
  181. * a0 = FP register index to be retrieved
  182. */
  183. SYM_FUNC_START(get_f32_reg)
  184. fp_access_prologue
  185. fp_access_body(get_f32)
  186. fp_access_epilogue
  187. SYM_FUNC_END(get_f32_reg)
  188. /*
  189. * put_f64_reg - Set a 64 bits FP register from a value or a pointer.
  190. * a0 = FP register index to be set
  191. * a1 = value/pointer to be loaded in the FP register (when xlen == 32 bits, we
  192. * load the value to a pointer).
  193. */
  194. SYM_FUNC_START(put_f64_reg)
  195. fp_access_prologue
  196. fp_access_body(put_f64)
  197. fp_access_epilogue
  198. SYM_FUNC_END(put_f64_reg)
  199. /*
  200. * get_f64_reg - Get a 64 bits FP register value and returned it or store it to
  201. * a pointer.
  202. * a0 = FP register index to be retrieved
  203. * a1 = If xlen == 32, pointer which should be loaded with the FP register value
  204. * or unused if xlen == 64. In which case the FP register value is returned
  205. * through a0
  206. */
  207. SYM_FUNC_START(get_f64_reg)
  208. fp_access_prologue
  209. fp_access_body(get_f64)
  210. fp_access_epilogue
  211. SYM_FUNC_END(get_f64_reg)
  212. #endif /* CONFIG_RISCV_MISALIGNED */