divmodhi.S 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /* HImode div/mod functions for the GCC support library for the Renesas RL78 processors.
  2. Copyright (C) 2012-2022 Free Software Foundation, Inc.
  3. Contributed by Red Hat.
  4. This file is part of GCC.
  5. GCC is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3, or (at your option)
  8. any later version.
  9. GCC is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. Under Section 7 of GPL version 3, you are granted additional
  14. permissions described in the GCC Runtime Library Exception, version
  15. 3.1, as published by the Free Software Foundation.
  16. You should have received a copy of the GNU General Public License and
  17. a copy of the GCC Runtime Library Exception along with this program;
  18. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. <http://www.gnu.org/licenses/>. */
  20. #include "vregs.h"
  21. #if defined __RL78_MUL_G14__
  22. START_FUNC ___divhi3
  23. ;; r8 = 4[sp] / 6[sp]
  24. ;; Test for a negative denumerator.
  25. movw ax, [sp+6]
  26. mov1 cy, a.7
  27. movw de, ax
  28. bc $__div_neg_den
  29. ;; Test for a negative numerator.
  30. movw ax, [sp+4]
  31. mov1 cy, a.7
  32. bc $__div_neg_num
  33. ;; Neither are negative - we can use the unsigned divide instruction.
  34. __div_no_convert:
  35. push psw
  36. di
  37. divhu
  38. pop psw
  39. movw r8, ax
  40. ret
  41. __div_neg_den:
  42. ;; Negate the denumerator (which is in DE)
  43. clrw ax
  44. subw ax, de
  45. movw de, ax
  46. ;; Test for a negative numerator.
  47. movw ax, [sp+4]
  48. mov1 cy, a.7
  49. ;; If it is not negative then we perform the division and then negate the result.
  50. bnc $__div_then_convert
  51. ;; Otherwise we negate the numerator and then go with an unsigned division.
  52. movw bc, ax
  53. clrw ax
  54. subw ax, bc
  55. br $__div_no_convert
  56. __div_neg_num:
  57. ;; Negate the numerator (which is in AX)
  58. ;; We know that the denumerator is positive.
  59. movw bc, ax
  60. clrw ax
  61. subw ax, bc
  62. __div_then_convert:
  63. push psw
  64. di
  65. divhu
  66. pop psw
  67. ;; Negate result and transfer into r8
  68. movw bc, ax
  69. clrw ax
  70. subw ax, bc
  71. movw r8, ax
  72. ret
  73. END_FUNC ___divhi3
  74. ;----------------------------------------------------------------------
  75. START_FUNC ___modhi3
  76. ;; r8 = 4[sp] % 6[sp]
  77. ;; Test for a negative denumerator.
  78. movw ax, [sp+6]
  79. mov1 cy, a.7
  80. movw de, ax
  81. bc $__mod_neg_den
  82. ;; Test for a negative numerator.
  83. movw ax, [sp+4]
  84. mov1 cy, a.7
  85. bc $__mod_neg_num
  86. ;; Neither are negative - we can use the unsigned divide instruction.
  87. __mod_no_convert:
  88. push psw
  89. di
  90. divhu
  91. pop psw
  92. movw ax, de
  93. movw r8, ax
  94. ret
  95. __mod_neg_den:
  96. ;; Negate the denumerator (which is in DE)
  97. clrw ax
  98. subw ax, de
  99. movw de, ax
  100. ;; Test for a negative numerator.
  101. movw ax, [sp+4]
  102. mov1 cy, a.7
  103. ;; If it is not negative then we perform the modulo operation without conversion.
  104. bnc $__mod_no_convert
  105. ;; Otherwise we negate the numerator and then go with an unsigned modulo operation.
  106. movw bc, ax
  107. clrw ax
  108. subw ax, bc
  109. br $__mod_then_convert
  110. __mod_neg_num:
  111. ;; Negate the numerator (which is in AX)
  112. ;; We know that the denumerator is positive.
  113. movw bc, ax
  114. clrw ax
  115. subw ax, bc
  116. __mod_then_convert:
  117. push psw
  118. di
  119. divhu
  120. pop psw
  121. ;; Negate result and transfer into r8
  122. clrw ax
  123. subw ax, de
  124. movw r8, ax
  125. ret
  126. END_FUNC ___modhi3
  127. ;----------------------------------------------------------------------
  128. #elif defined __RL78_MUL_G13__
  129. ;; The G13 S2 core does not have a 16 bit divide peripheral.
  130. ;; So instead we perform a 32-bit divide and twiddle the inputs
  131. ;; as necessary.
  132. ;; Hardware registers. Note - these values match the silicon, not the documentation.
  133. MDAL = 0xffff0
  134. MDAH = 0xffff2
  135. MDBL = 0xffff6
  136. MDBH = 0xffff4
  137. MDCL = 0xf00e0
  138. MDCH = 0xf00e2
  139. MDUC = 0xf00e8
  140. .macro _Negate src, dest
  141. movw ax, !\src
  142. movw bc, ax
  143. clrw ax
  144. subw ax, bc
  145. movw \dest, ax
  146. .endm
  147. ;----------------------------------------------------------------------
  148. START_FUNC ___divhi3
  149. ;; r8 = 4[sp] / 6[sp] (signed division)
  150. mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
  151. mov !MDUC, a ; This preps the peripheral for division without interrupt generation
  152. clrw ax ; Clear the top 16-bits of the divisor and dividend
  153. movw MDBH, ax
  154. movw MDAH, ax
  155. ;; Load and test for a negative denumerator.
  156. movw ax, [sp+6]
  157. movw MDBL, ax
  158. mov1 cy, a.7
  159. bc $__div_neg_den
  160. ;; Load and test for a negative numerator.
  161. movw ax, [sp+4]
  162. mov1 cy, a.7
  163. movw MDAL, ax
  164. bc $__div_neg_num
  165. ;; Neither are negative - we can use the unsigned divide hardware.
  166. __div_no_convert:
  167. mov a, #0xC1 ; Set the DIVST bit in MDUC
  168. mov !MDUC, a ; This starts the division op
  169. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  170. bt a.0, $1b
  171. movw ax, MDAL ; Read the result
  172. movw r8, ax
  173. ret
  174. __div_neg_den:
  175. ;; Negate the denumerator (which is in MDBL)
  176. _Negate MDBL MDBL
  177. ;; Load and test for a negative numerator.
  178. movw ax, [sp+4]
  179. mov1 cy, a.7
  180. movw MDAL, ax
  181. ;; If it is not negative then we perform the division and then negate the result.
  182. bnc $__div_then_convert
  183. ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
  184. _Negate MDAL MDAL
  185. br $!__div_no_convert
  186. __div_neg_num:
  187. ;; Negate the numerator (which is in MDAL)
  188. ;; We know that the denumerator is positive.
  189. _Negate MDAL MDAL
  190. __div_then_convert:
  191. mov a, #0xC1 ; Set the DIVST bit in MDUC
  192. mov !MDUC, a ; This starts the division op
  193. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  194. bt a.0, $1b
  195. ;; Negate result and transfer into r8
  196. _Negate MDAL r8
  197. ret
  198. END_FUNC ___divhi3
  199. ;----------------------------------------------------------------------
  200. START_FUNC ___modhi3
  201. ;; r8 = 4[sp] % 6[sp] (signed modulus)
  202. mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
  203. mov !MDUC, a ; This preps the peripheral for division without interrupt generation
  204. clrw ax ; Clear the top 16-bits of the divisor and dividend
  205. movw MDBH, ax
  206. movw MDAH, ax
  207. ;; Load and test for a negative denumerator.
  208. movw ax, [sp+6]
  209. movw MDBL, ax
  210. mov1 cy, a.7
  211. bc $__mod_neg_den
  212. ;; Load and test for a negative numerator.
  213. movw ax, [sp+4]
  214. mov1 cy, a.7
  215. movw MDAL, ax
  216. bc $__mod_neg_num
  217. ;; Neither are negative - we can use the unsigned divide hardware
  218. __mod_no_convert:
  219. mov a, #0xC1 ; Set the DIVST bit in MDUC
  220. mov !MDUC, a ; This starts the division op
  221. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  222. bt a.0, $1b
  223. movw ax, !MDCL ; Read the remainder
  224. movw r8, ax
  225. ret
  226. __mod_neg_den:
  227. ;; Negate the denumerator (which is in MDBL)
  228. _Negate MDBL MDBL
  229. ;; Load and test for a negative numerator.
  230. movw ax, [sp+4]
  231. mov1 cy, a.7
  232. movw MDAL, ax
  233. ;; If it is not negative then we perform the modulo operation without conversion.
  234. bnc $__mod_no_convert
  235. ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
  236. _Negate MDAL MDAL
  237. br $!__mod_then_convert
  238. __mod_neg_num:
  239. ;; Negate the numerator (which is in MDAL)
  240. ;; We know that the denumerator is positive.
  241. _Negate MDAL MDAL
  242. __mod_then_convert:
  243. mov a, #0xC1 ; Set the DIVST bit in MDUC
  244. mov !MDUC, a ; This starts the division op
  245. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  246. bt a.0, $1b
  247. _Negate MDCL r8
  248. ret
  249. END_FUNC ___modhi3
  250. ;----------------------------------------------------------------------
  251. START_FUNC ___udivhi3
  252. ;; r8 = 4[sp] / 6[sp] (unsigned division)
  253. mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
  254. mov !MDUC, a ; This preps the peripheral for division without interrupt generation
  255. movw ax, [sp+4] ; Load the divisor
  256. movw MDAL, ax
  257. movw ax, [sp+6] ; Load the dividend
  258. movw MDBL, ax
  259. clrw ax
  260. movw MDAH, ax
  261. movw MDBH, ax
  262. mov a, #0xC1 ; Set the DIVST bit in MDUC
  263. mov !MDUC, a ; This starts the division op
  264. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  265. bt a.0, $1b
  266. movw ax, !MDAL ; Read the remainder
  267. movw r8, ax
  268. ret
  269. END_FUNC ___udivhi3
  270. ;----------------------------------------------------------------------
  271. START_FUNC ___umodhi3
  272. ;; r8 = 4[sp] % 6[sp] (unsigned modulus)
  273. mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
  274. mov !MDUC, a ; This preps the peripheral for division without interrupt generation
  275. movw ax, [sp+4] ; Load the divisor
  276. movw MDAL, ax
  277. movw ax, [sp+6] ; Load the dividend
  278. movw MDBL, ax
  279. clrw ax
  280. movw MDAH, ax
  281. movw MDBH, ax
  282. mov a, #0xC1 ; Set the DIVST bit in MDUC
  283. mov !MDUC, a ; This starts the division op
  284. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  285. bt a.0, $1b
  286. movw ax, !MDCL ; Read the remainder
  287. movw r8, ax
  288. ret
  289. END_FUNC ___umodhi3
  290. ;----------------------------------------------------------------------
  291. #elif defined __RL78_MUL_NONE__
  292. .macro MAKE_GENERIC which,need_result
  293. .if \need_result
  294. quot = r8
  295. num = r10
  296. den = r12
  297. bit = r14
  298. .else
  299. num = r8
  300. quot = r10
  301. den = r12
  302. bit = r14
  303. .endif
  304. quotB0 = quot
  305. quotB1 = quot+1
  306. numB0 = num
  307. numB1 = num+1
  308. denB0 = den
  309. denB1 = den+1
  310. bitB0 = bit
  311. bitB1 = bit+1
  312. #define bit bc
  313. #define bitB0 c
  314. #define bitB1 b
  315. START_FUNC __generic_hidivmod\which
  316. num_lt_den\which:
  317. .if \need_result
  318. movw r8, #0
  319. .else
  320. movw ax, [sp+8]
  321. movw r8, ax
  322. .endif
  323. ret
  324. ;; These routines leave DE alone - the signed functions use DE
  325. ;; to store sign information that must remain intact
  326. .if \need_result
  327. .global __generic_hidiv
  328. __generic_hidiv:
  329. .else
  330. .global __generic_himod
  331. __generic_himod:
  332. .endif
  333. ;; (quot,rem) = 8[sp] /% 10[sp]
  334. movw hl, sp
  335. movw ax, [hl+10] ; denH
  336. cmpw ax, [hl+8] ; numH
  337. bh $num_lt_den\which
  338. ;; (quot,rem) = 16[sp] /% 20[sp]
  339. ;; copy numerator
  340. movw ax, [hl+8]
  341. movw num, ax
  342. ;; copy denomonator
  343. movw ax, [hl+10]
  344. movw den, ax
  345. movw ax, den
  346. cmpw ax, #0
  347. bnz $den_not_zero\which
  348. .if \need_result
  349. movw quot, #0
  350. .else
  351. movw num, #0
  352. .endif
  353. ret
  354. den_not_zero\which:
  355. .if \need_result
  356. ;; zero out quot
  357. movw quot, #0
  358. .endif
  359. ;; initialize bit to 1
  360. movw bit, #1
  361. ; while (den < num && !(den & (1L << BITS_MINUS_1)))
  362. shift_den_bit\which:
  363. movw ax, den
  364. mov1 cy,a.7
  365. bc $enter_main_loop\which
  366. cmpw ax, num
  367. bh $enter_main_loop\which
  368. ;; den <<= 1
  369. ; movw ax, den ; already has it from the cmpw above
  370. shlw ax, 1
  371. movw den, ax
  372. ;; bit <<= 1
  373. .if \need_result
  374. #ifdef bit
  375. shlw bit, 1
  376. #else
  377. movw ax, bit
  378. shlw ax, 1
  379. movw bit, ax
  380. #endif
  381. .else
  382. ;; if we don't need to compute the quotent, we don't need an
  383. ;; actual bit *mask*, we just need to keep track of which bit
  384. inc bitB0
  385. .endif
  386. br $shift_den_bit\which
  387. main_loop\which:
  388. ;; if (num >= den) (cmp den > num)
  389. movw ax, den
  390. cmpw ax, num
  391. bh $next_loop\which
  392. ;; num -= den
  393. movw ax, num
  394. subw ax, den
  395. movw num, ax
  396. .if \need_result
  397. ;; res |= bit
  398. mov a, quotB0
  399. or a, bitB0
  400. mov quotB0, a
  401. mov a, quotB1
  402. or a, bitB1
  403. mov quotB1, a
  404. .endif
  405. next_loop\which:
  406. ;; den >>= 1
  407. movw ax, den
  408. shrw ax, 1
  409. movw den, ax
  410. .if \need_result
  411. ;; bit >>= 1
  412. movw ax, bit
  413. shrw ax, 1
  414. movw bit, ax
  415. .else
  416. dec bitB0
  417. .endif
  418. enter_main_loop\which:
  419. .if \need_result
  420. movw ax, bit
  421. cmpw ax, #0
  422. .else
  423. cmp0 bitB0
  424. .endif
  425. bnz $main_loop\which
  426. main_loop_done\which:
  427. ret
  428. END_FUNC __generic_hidivmod\which
  429. .endm
  430. ;----------------------------------------------------------------------
  431. MAKE_GENERIC _d 1
  432. MAKE_GENERIC _m 0
  433. ;----------------------------------------------------------------------
  434. START_FUNC ___udivhi3
  435. ;; r8 = 4[sp] / 6[sp]
  436. call $!__generic_hidiv
  437. ret
  438. END_FUNC ___udivhi3
  439. START_FUNC ___umodhi3
  440. ;; r8 = 4[sp] % 6[sp]
  441. call $!__generic_himod
  442. ret
  443. END_FUNC ___umodhi3
  444. ;----------------------------------------------------------------------
  445. .macro NEG_AX
  446. movw hl, ax
  447. movw ax, #0
  448. subw ax, [hl]
  449. movw [hl], ax
  450. .endm
  451. ;----------------------------------------------------------------------
  452. START_FUNC ___divhi3
  453. ;; r8 = 4[sp] / 6[sp]
  454. movw de, #0
  455. mov a, [sp+5]
  456. mov1 cy, a.7
  457. bc $div_signed_num
  458. mov a, [sp+7]
  459. mov1 cy, a.7
  460. bc $div_signed_den
  461. call $!__generic_hidiv
  462. ret
  463. div_signed_num:
  464. ;; neg [sp+4]
  465. movw ax, sp
  466. addw ax, #4
  467. NEG_AX
  468. mov d, #1
  469. mov a, [sp+7]
  470. mov1 cy, a.7
  471. bnc $div_unsigned_den
  472. div_signed_den:
  473. ;; neg [sp+6]
  474. movw ax, sp
  475. addw ax, #6
  476. NEG_AX
  477. mov e, #1
  478. div_unsigned_den:
  479. call $!__generic_hidiv
  480. mov a, d
  481. cmp0 a
  482. bz $div_skip_restore_num
  483. ;; We have to restore the numerator [sp+4]
  484. movw ax, sp
  485. addw ax, #4
  486. NEG_AX
  487. mov a, d
  488. div_skip_restore_num:
  489. xor a, e
  490. bz $div_no_neg
  491. movw ax, #r8
  492. NEG_AX
  493. div_no_neg:
  494. mov a, e
  495. cmp0 a
  496. bz $div_skip_restore_den
  497. movw ax, sp
  498. addw ax, #6
  499. NEG_AX
  500. div_skip_restore_den:
  501. ret
  502. END_FUNC ___divhi3
  503. START_FUNC ___modhi3
  504. ;; r8 = 4[sp] % 6[sp]
  505. movw de, #0
  506. mov a, [sp+5]
  507. mov1 cy, a.7
  508. bc $mod_signed_num
  509. mov a, [sp+7]
  510. mov1 cy, a.7
  511. bc $mod_signed_den
  512. call $!__generic_himod
  513. ret
  514. mod_signed_num:
  515. ;; neg [sp+4]
  516. movw ax, sp
  517. addw ax, #4
  518. NEG_AX
  519. mov d, #1
  520. mov a, [sp+7]
  521. mov1 cy, a.7
  522. bnc $mod_unsigned_den
  523. mod_signed_den:
  524. ;; neg [sp+6]
  525. movw ax, sp
  526. addw ax, #6
  527. NEG_AX
  528. mod_unsigned_den:
  529. call $!__generic_himod
  530. mov a, d
  531. cmp0 a
  532. bz $mod_no_neg
  533. movw ax, #r8
  534. NEG_AX
  535. ;; Also restore numerator
  536. movw ax, sp
  537. addw ax, #4
  538. NEG_AX
  539. mod_no_neg:
  540. mov a, e
  541. cmp0 a
  542. bz $mod_skip_restore_den
  543. movw ax, sp
  544. addw ax, #6
  545. NEG_AX
  546. mod_skip_restore_den:
  547. ret
  548. END_FUNC ___modhi3
  549. ;----------------------------------------------------------------------
  550. #else
  551. #error "Unknown RL78 hardware multiply/divide support"
  552. #endif