uldivmod.S 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright 2010, Google Inc.
  4. *
  5. * Brought in from coreboot uldivmod.S
  6. */
  7. #include <linux/linkage.h>
  8. #include <asm/assembler.h>
  9. /*
  10. * A, Q = r0 + (r1 << 32)
  11. * B, R = r2 + (r3 << 32)
  12. * A / B = Q ... R
  13. */
  14. A_0 .req r0
  15. A_1 .req r1
  16. B_0 .req r2
  17. B_1 .req r3
  18. C_0 .req r4
  19. C_1 .req r5
  20. D_0 .req r6
  21. D_1 .req r7
  22. Q_0 .req r0
  23. Q_1 .req r1
  24. R_0 .req r2
  25. R_1 .req r3
  26. THUMB(
  27. TMP .req r8
  28. )
  29. .pushsection .text.__aeabi_uldivmod, "ax"
  30. ENTRY(__aeabi_uldivmod)
  31. stmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) lr}
  32. @ Test if B == 0
  33. orrs ip, B_0, B_1 @ Z set -> B == 0
  34. beq L_div_by_0
  35. @ Test if B is power of 2: (B & (B - 1)) == 0
  36. subs C_0, B_0, #1
  37. sbc C_1, B_1, #0
  38. tst C_0, B_0
  39. tsteq B_1, C_1
  40. beq L_pow2
  41. @ Test if A_1 == B_1 == 0
  42. orrs ip, A_1, B_1
  43. beq L_div_32_32
  44. L_div_64_64:
  45. /* CLZ only exists in ARM architecture version 5 and above. */
  46. #ifdef HAVE_CLZ
  47. mov C_0, #1
  48. mov C_1, #0
  49. @ D_0 = clz A
  50. teq A_1, #0
  51. clz D_0, A_1
  52. clzeq ip, A_0
  53. addeq D_0, D_0, ip
  54. @ D_1 = clz B
  55. teq B_1, #0
  56. clz D_1, B_1
  57. clzeq ip, B_0
  58. addeq D_1, D_1, ip
  59. @ if clz B - clz A > 0
  60. subs D_0, D_1, D_0
  61. bls L_done_shift
  62. @ B <<= (clz B - clz A)
  63. subs D_1, D_0, #32
  64. rsb ip, D_0, #32
  65. movmi B_1, B_1, lsl D_0
  66. ARM( orrmi B_1, B_1, B_0, lsr ip )
  67. THUMB( lsrmi TMP, B_0, ip )
  68. THUMB( orrmi B_1, B_1, TMP )
  69. movpl B_1, B_0, lsl D_1
  70. mov B_0, B_0, lsl D_0
  71. @ C = 1 << (clz B - clz A)
  72. movmi C_1, C_1, lsl D_0
  73. ARM( orrmi C_1, C_1, C_0, lsr ip )
  74. THUMB( lsrmi TMP, C_0, ip )
  75. THUMB( orrmi C_1, C_1, TMP )
  76. movpl C_1, C_0, lsl D_1
  77. mov C_0, C_0, lsl D_0
  78. L_done_shift:
  79. mov D_0, #0
  80. mov D_1, #0
  81. @ C: current bit; D: result
  82. #else
  83. @ C: current bit; D: result
  84. mov C_0, #1
  85. mov C_1, #0
  86. mov D_0, #0
  87. mov D_1, #0
  88. L_lsl_4:
  89. cmp B_1, #0x10000000
  90. cmpcc B_1, A_1
  91. cmpeq B_0, A_0
  92. bcs L_lsl_1
  93. @ B <<= 4
  94. mov B_1, B_1, lsl #4
  95. orr B_1, B_1, B_0, lsr #28
  96. mov B_0, B_0, lsl #4
  97. @ C <<= 4
  98. mov C_1, C_1, lsl #4
  99. orr C_1, C_1, C_0, lsr #28
  100. mov C_0, C_0, lsl #4
  101. b L_lsl_4
  102. L_lsl_1:
  103. cmp B_1, #0x80000000
  104. cmpcc B_1, A_1
  105. cmpeq B_0, A_0
  106. bcs L_subtract
  107. @ B <<= 1
  108. mov B_1, B_1, lsl #1
  109. orr B_1, B_1, B_0, lsr #31
  110. mov B_0, B_0, lsl #1
  111. @ C <<= 1
  112. mov C_1, C_1, lsl #1
  113. orr C_1, C_1, C_0, lsr #31
  114. mov C_0, C_0, lsl #1
  115. b L_lsl_1
  116. #endif
  117. L_subtract:
  118. @ if A >= B
  119. cmp A_1, B_1
  120. cmpeq A_0, B_0
  121. bcc L_update
  122. @ A -= B
  123. subs A_0, A_0, B_0
  124. sbc A_1, A_1, B_1
  125. @ D |= C
  126. orr D_0, D_0, C_0
  127. orr D_1, D_1, C_1
  128. L_update:
  129. @ if A == 0: break
  130. orrs ip, A_1, A_0
  131. beq L_exit
  132. @ C >>= 1
  133. movs C_1, C_1, lsr #1
  134. movs C_0, C_0, rrx
  135. @ if C == 0: break
  136. orrs ip, C_1, C_0
  137. beq L_exit
  138. @ B >>= 1
  139. movs B_1, B_1, lsr #1
  140. mov B_0, B_0, rrx
  141. b L_subtract
  142. L_exit:
  143. @ Note: A, B & Q, R are aliases
  144. mov R_0, A_0
  145. mov R_1, A_1
  146. mov Q_0, D_0
  147. mov Q_1, D_1
  148. ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
  149. L_div_32_32:
  150. @ Note: A_0 & r0 are aliases
  151. @ Q_1 r1
  152. mov r1, B_0
  153. bl __aeabi_uidivmod
  154. mov R_0, r1
  155. mov R_1, #0
  156. mov Q_1, #0
  157. ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
  158. L_pow2:
  159. #ifdef HAVE_CLZ
  160. @ Note: A, B and Q, R are aliases
  161. @ R = A & (B - 1)
  162. and C_0, A_0, C_0
  163. and C_1, A_1, C_1
  164. @ Q = A >> log2(B)
  165. @ Note: B must not be 0 here!
  166. clz D_0, B_0
  167. add D_1, D_0, #1
  168. rsbs D_0, D_0, #31
  169. bpl L_1
  170. clz D_0, B_1
  171. rsb D_0, D_0, #31
  172. mov A_0, A_1, lsr D_0
  173. add D_0, D_0, #32
  174. L_1:
  175. movpl A_0, A_0, lsr D_0
  176. ARM( orrpl A_0, A_0, A_1, lsl D_1 )
  177. THUMB( lslpl TMP, A_1, D_1 )
  178. THUMB( orrpl A_0, A_0, TMP )
  179. mov A_1, A_1, lsr D_0
  180. @ Mov back C to R
  181. mov R_0, C_0
  182. mov R_1, C_1
  183. ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
  184. #else
  185. @ Note: A, B and Q, R are aliases
  186. @ R = A & (B - 1)
  187. and C_0, A_0, C_0
  188. and C_1, A_1, C_1
  189. @ Q = A >> log2(B)
  190. @ Note: B must not be 0 here!
  191. @ Count the leading zeroes in B.
  192. mov D_0, #0
  193. orrs B_0, B_0, B_0
  194. @ If B is greater than 1 << 31, divide A and B by 1 << 32.
  195. moveq A_0, A_1
  196. moveq A_1, #0
  197. moveq B_0, B_1
  198. @ Count the remaining leading zeroes in B.
  199. movs B_1, B_0, lsl #16
  200. addeq D_0, #16
  201. moveq B_0, B_0, lsr #16
  202. tst B_0, #0xff
  203. addeq D_0, #8
  204. moveq B_0, B_0, lsr #8
  205. tst B_0, #0xf
  206. addeq D_0, #4
  207. moveq B_0, B_0, lsr #4
  208. tst B_0, #0x3
  209. addeq D_0, #2
  210. moveq B_0, B_0, lsr #2
  211. tst B_0, #0x1
  212. addeq D_0, #1
  213. @ Shift A to the right by the appropriate amount.
  214. rsb D_1, D_0, #32
  215. mov Q_0, A_0, lsr D_0
  216. ARM( orr Q_0, Q_0, A_1, lsl D_1 )
  217. THUMB( lsl A_1, D_1 )
  218. THUMB( orr Q_0, A_1 )
  219. mov Q_1, A_1, lsr D_0
  220. @ Move C to R
  221. mov R_0, C_0
  222. mov R_1, C_1
  223. ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
  224. #endif
  225. L_div_by_0:
  226. bl __div0
  227. @ As wrong as it could be
  228. mov Q_0, #0
  229. mov Q_1, #0
  230. mov R_0, #0
  231. mov R_1, #0
  232. ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
  233. ENDPROC(__aeabi_uldivmod)
  234. .popsection