divmodsi.S 20 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. /* SImode 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 it
  6. under the terms of the GNU General Public License as published
  7. by the Free Software Foundation; either version 3, or (at your
  8. option) any later version.
  9. GCC is distributed in the hope that it will be useful, but WITHOUT
  10. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  12. 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 ___divsi3
  23. ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
  24. ;; Load and test for a negative denumerator.
  25. movw ax, [sp+8]
  26. movw de, ax
  27. movw ax, [sp+10]
  28. mov1 cy, a.7
  29. movw hl, ax
  30. bc $__div_neg_den
  31. ;; Load and test for a negative numerator.
  32. movw ax, [sp+6]
  33. mov1 cy, a.7
  34. movw bc, ax
  35. movw ax, [sp+4]
  36. bc $__div_neg_num
  37. ;; Neither are negative - we can use the unsigned divide instruction.
  38. __div_no_convert:
  39. push psw
  40. di
  41. divwu
  42. pop psw
  43. movw r8, ax
  44. movw ax, bc
  45. movw r10, ax
  46. ret
  47. __div_neg_den:
  48. ;; Negate the denumerator (which is in HLDE)
  49. clrw ax
  50. subw ax, de
  51. movw de, ax
  52. clrw ax
  53. sknc
  54. decw ax
  55. subw ax, hl
  56. movw hl, ax
  57. ;; Load and test for a negative numerator.
  58. movw ax, [sp+6]
  59. mov1 cy, a.7
  60. movw bc, ax
  61. movw ax, [sp+4]
  62. ;; If it is not negative then we perform the division and then negate the result.
  63. bnc $__div_then_convert
  64. ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
  65. ;; The negation is complicated because AX, BC, DE and HL are already in use.
  66. ;; ax: numL bc: numH r8: r10:
  67. xchw ax, bc
  68. ;; ax: numH bc: numL r8: r10:
  69. movw r8, ax
  70. ;; ax: bc: numL r8: numH r10:
  71. clrw ax
  72. ;; ax: 0 bc: numL r8: numH r10:
  73. subw ax, bc
  74. ;; ax: -numL bc: r8: numH r10:
  75. movw r10, ax
  76. ;; ax: bc: r8: numH r10: -numL
  77. movw ax, r8
  78. ;; ax: numH bc: r8: r10: -numL
  79. movw bc, ax
  80. ;; ax: bc: numH r8: r10: -numL
  81. clrw ax
  82. ;; ax: 0 bc: numH r8: r10: -numL
  83. sknc
  84. decw ax
  85. ;; ax: -1 bc: numH r8: r10: -numL
  86. subw ax, bc
  87. ;; ax: -numH bc: r8: r10: -numL
  88. movw bc, ax
  89. ;; ax: bc: -numH r8: r10: -numL
  90. movw ax, r10
  91. ;; ax: -numL bc: -numH r8: r10:
  92. br $!__div_no_convert
  93. __div_neg_num:
  94. ;; Negate the numerator (which is in BCAX)
  95. ;; We know that the denumerator is positive.
  96. ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again.
  97. movw de, ax
  98. clrw ax
  99. subw ax, de
  100. movw de, ax
  101. clrw ax
  102. sknc
  103. decw ax
  104. subw ax, bc
  105. movw bc, ax
  106. movw ax, [sp+8]
  107. xchw ax, de
  108. __div_then_convert:
  109. push psw
  110. di
  111. divwu
  112. pop psw
  113. ;; Negate result (in BCAX) and transfer into r8,r10
  114. movw de, ax
  115. clrw ax
  116. subw ax, de
  117. movw r8, ax
  118. clrw ax
  119. sknc
  120. decw ax
  121. subw ax, bc
  122. movw r10, ax
  123. ret
  124. END_FUNC ___divsi3
  125. ;----------------------------------------------------------------------
  126. START_FUNC ___udivsi3
  127. ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
  128. ;; Used when compiling with -Os specified.
  129. movw ax, [sp+10]
  130. movw hl, ax
  131. movw ax, [sp+8]
  132. movw de, ax
  133. movw ax, [sp+6]
  134. movw bc, ax
  135. movw ax, [sp+4]
  136. push psw ; Save the current interrupt status
  137. di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E
  138. divwu ; bcax = bcax / hlde
  139. pop psw ; Restore saved interrupt status
  140. movw r8, ax
  141. movw ax, bc
  142. movw r10, ax
  143. ret
  144. END_FUNC ___udivsi3
  145. ;----------------------------------------------------------------------
  146. START_FUNC ___modsi3
  147. ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
  148. ;; Load and test for a negative denumerator.
  149. movw ax, [sp+8]
  150. movw de, ax
  151. movw ax, [sp+10]
  152. mov1 cy, a.7
  153. movw hl, ax
  154. bc $__mod_neg_den
  155. ;; Load and test for a negative numerator.
  156. movw ax, [sp+6]
  157. mov1 cy, a.7
  158. movw bc, ax
  159. movw ax, [sp+4]
  160. bc $__mod_neg_num
  161. ;; Neither are negative - we can use the unsigned divide instruction.
  162. __mod_no_convert:
  163. push psw
  164. di
  165. divwu
  166. pop psw
  167. movw ax, de
  168. movw r8, ax
  169. movw ax, hl
  170. movw r10, ax
  171. ret
  172. __mod_neg_den:
  173. ;; Negate the denumerator (which is in HLDE)
  174. clrw ax
  175. subw ax, de
  176. movw de, ax
  177. clrw ax
  178. sknc
  179. decw ax
  180. subw ax, hl
  181. movw hl, ax
  182. ;; Load and test for a negative numerator.
  183. movw ax, [sp+6]
  184. mov1 cy, a.7
  185. movw bc, ax
  186. movw ax, [sp+4]
  187. ;; If it is not negative then we perform the modulo operation without conversion
  188. bnc $__mod_no_convert
  189. ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
  190. ;; The negation is complicated because AX, BC, DE and HL are already in use.
  191. xchw ax, bc
  192. movw r8, ax
  193. clrw ax
  194. subw ax, bc
  195. movw r10, ax
  196. movw ax, r8
  197. movw bc, ax
  198. clrw ax
  199. sknc
  200. decw ax
  201. subw ax, bc
  202. movw bc, ax
  203. movw ax, r10
  204. br $!__mod_then_convert
  205. __mod_neg_num:
  206. ;; Negate the numerator (which is in BCAX)
  207. ;; We know that the denumerator is positive.
  208. ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again.
  209. movw de, ax
  210. clrw ax
  211. subw ax, de
  212. movw de, ax
  213. clrw ax
  214. sknc
  215. decw ax
  216. subw ax, bc
  217. movw bc, ax
  218. movw ax, [sp+8]
  219. xchw ax, de
  220. __mod_then_convert:
  221. push psw
  222. di
  223. divwu
  224. pop psw
  225. ;; Negate result (in HLDE) and transfer into r8,r10
  226. clrw ax
  227. subw ax, de
  228. movw r8, ax
  229. clrw ax
  230. sknc
  231. decw ax
  232. subw ax, hl
  233. movw r10, ax
  234. ret
  235. END_FUNC ___modsi3
  236. ;----------------------------------------------------------------------
  237. START_FUNC ___umodsi3
  238. ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
  239. ;; Used when compiling with -Os specified.
  240. movw ax, [sp+10]
  241. movw hl, ax
  242. movw ax, [sp+8]
  243. movw de, ax
  244. movw ax, [sp+6]
  245. movw bc, ax
  246. movw ax, [sp+4]
  247. push psw ; Save the current interrupt status
  248. di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E
  249. divwu ; hlde = bcax %% hlde
  250. pop psw ; Restore saved interrupt status
  251. movw ax, de
  252. movw r8, ax
  253. movw ax, hl
  254. movw r10, ax
  255. ret
  256. END_FUNC ___umodsi3
  257. ;----------------------------------------------------------------------
  258. #elif defined __RL78_MUL_G13__
  259. ;----------------------------------------------------------------------
  260. ;; Hardware registers. Note - these values match the silicon, not the documentation.
  261. MDAL = 0xffff0
  262. MDAH = 0xffff2
  263. MDBL = 0xffff6
  264. MDBH = 0xffff4
  265. MDCL = 0xf00e0
  266. MDCH = 0xf00e2
  267. MDUC = 0xf00e8
  268. .macro _Negate low, high
  269. movw ax, \low
  270. movw bc, ax
  271. clrw ax
  272. subw ax, bc
  273. movw \low, ax
  274. movw ax, \high
  275. movw bc, ax
  276. clrw ax
  277. sknc
  278. decw ax
  279. subw ax, bc
  280. movw \high, ax
  281. .endm
  282. ;----------------------------------------------------------------------
  283. START_FUNC ___divsi3
  284. ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
  285. mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
  286. mov !MDUC, a ; This preps the peripheral for division without interrupt generation
  287. ;; Load and test for a negative denumerator.
  288. movw ax, [sp+8]
  289. movw MDBL, ax
  290. movw ax, [sp+10]
  291. mov1 cy, a.7
  292. movw MDBH, ax
  293. bc $__div_neg_den
  294. ;; Load and test for a negative numerator.
  295. movw ax, [sp+6]
  296. mov1 cy, a.7
  297. movw MDAH, ax
  298. movw ax, [sp+4]
  299. movw MDAL, ax
  300. bc $__div_neg_num
  301. ;; Neither are negative - we can use the unsigned divide hardware.
  302. __div_no_convert:
  303. mov a, #0xC1 ; Set the DIVST bit in MDUC
  304. mov !MDUC, a ; This starts the division op
  305. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  306. bt a.0, $1b
  307. movw ax, MDAL ; Read the result
  308. movw r8, ax
  309. movw ax, MDAH
  310. movw r10, ax
  311. ret
  312. __div_neg_den:
  313. ;; Negate the denumerator (which is in MDBL/MDBH)
  314. _Negate MDBL MDBH
  315. ;; Load and test for a negative numerator.
  316. movw ax, [sp+6]
  317. mov1 cy, a.7
  318. movw MDAH, ax
  319. movw ax, [sp+4]
  320. movw MDAL, ax
  321. ;; If it is not negative then we perform the division and then negate the result.
  322. bnc $__div_then_convert
  323. ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
  324. _Negate MDAL MDAH
  325. br $!__div_no_convert
  326. __div_neg_num:
  327. ;; Negate the numerator (which is in MDAL/MDAH)
  328. ;; We know that the denumerator is positive.
  329. _Negate MDAL MDAH
  330. __div_then_convert:
  331. mov a, #0xC1 ; Set the DIVST bit in MDUC
  332. mov !MDUC, a ; This starts the division op
  333. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  334. bt a.0, $1b
  335. ;; Negate result and transfer into r8,r10
  336. _Negate MDAL MDAH ; FIXME: This could be coded more efficiently.
  337. movw r10, ax
  338. movw ax, MDAL
  339. movw r8, ax
  340. ret
  341. END_FUNC ___divsi3
  342. ;----------------------------------------------------------------------
  343. START_FUNC ___modsi3
  344. ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
  345. mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
  346. mov !MDUC, a ; This preps the peripheral for division without interrupt generation
  347. ;; Load and test for a negative denumerator.
  348. movw ax, [sp+8]
  349. movw MDBL, ax
  350. movw ax, [sp+10]
  351. mov1 cy, a.7
  352. movw MDBH, ax
  353. bc $__mod_neg_den
  354. ;; Load and test for a negative numerator.
  355. movw ax, [sp+6]
  356. mov1 cy, a.7
  357. movw MDAH, ax
  358. movw ax, [sp+4]
  359. movw MDAL, ax
  360. bc $__mod_neg_num
  361. ;; Neither are negative - we can use the unsigned divide hardware
  362. __mod_no_convert:
  363. mov a, #0xC1 ; Set the DIVST bit in MDUC
  364. mov !MDUC, a ; This starts the division op
  365. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  366. bt a.0, $1b
  367. movw ax, !MDCL ; Read the remainder
  368. movw r8, ax
  369. movw ax, !MDCH
  370. movw r10, ax
  371. ret
  372. __mod_neg_den:
  373. ;; Negate the denumerator (which is in MDBL/MDBH)
  374. _Negate MDBL MDBH
  375. ;; Load and test for a negative numerator.
  376. movw ax, [sp+6]
  377. mov1 cy, a.7
  378. movw MDAH, ax
  379. movw ax, [sp+4]
  380. movw MDAL, ax
  381. ;; If it is not negative then we perform the modulo operation without conversion
  382. bnc $__mod_no_convert
  383. ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
  384. _Negate MDAL MDAH
  385. br $!__mod_then_convert
  386. __mod_neg_num:
  387. ;; Negate the numerator (which is in MDAL/MDAH)
  388. ;; We know that the denumerator is positive.
  389. _Negate MDAL MDAH
  390. __mod_then_convert:
  391. mov a, #0xC1 ; Set the DIVST bit in MDUC
  392. mov !MDUC, a ; This starts the division op
  393. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  394. bt a.0, $1b
  395. movw ax, !MDCL
  396. movw bc, ax
  397. clrw ax
  398. subw ax, bc
  399. movw r8, ax
  400. movw ax, !MDCH
  401. movw bc, ax
  402. clrw ax
  403. sknc
  404. decw ax
  405. subw ax, bc
  406. movw r10, ax
  407. ret
  408. END_FUNC ___modsi3
  409. ;----------------------------------------------------------------------
  410. START_FUNC ___udivsi3
  411. ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
  412. ;; Used when compilng with -Os specified.
  413. mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
  414. mov !MDUC, a ; This preps the peripheral for division without interrupt generation
  415. movw ax, [sp+4] ; Load the divisor
  416. movw MDAL, ax
  417. movw ax, [sp+6]
  418. movw MDAH, ax
  419. movw ax, [sp+8] ; Load the dividend
  420. movw MDBL, ax
  421. movw ax, [sp+10]
  422. movw MDBH, ax
  423. mov a, #0xC1 ; Set the DIVST bit in MDUC
  424. mov !MDUC, a ; This starts the division op
  425. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  426. bt a.0, $1b
  427. movw ax, !MDAL ; Read the result
  428. movw r8, ax
  429. movw ax, !MDAH
  430. movw r10, ax
  431. ret
  432. END_FUNC ___udivsi3
  433. ;----------------------------------------------------------------------
  434. START_FUNC ___umodsi3
  435. ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
  436. ;; Used when compilng with -Os specified.
  437. ;; Note - hardware address match the silicon, not the documentation
  438. mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
  439. mov !MDUC, a ; This preps the peripheral for division without interrupt generation
  440. movw ax, [sp+4] ; Load the divisor
  441. movw MDAL, ax
  442. movw ax, [sp+6]
  443. movw MDAH, ax
  444. movw ax, [sp+8] ; Load the dividend
  445. movw MDBL, ax
  446. movw ax, [sp+10]
  447. movw MDBH, ax
  448. mov a, #0xC1 ; Set the DIVST bit in MDUC
  449. mov !MDUC, a ; This starts the division op
  450. 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
  451. bt a.0, $1b
  452. movw ax, !MDCL ; Read the remainder
  453. movw r8, ax
  454. movw ax, !MDCH
  455. movw r10, ax
  456. ret
  457. END_FUNC ___umodsi3
  458. ;----------------------------------------------------------------------
  459. #elif defined __RL78_MUL_NONE__
  460. .macro MAKE_GENERIC which,need_result
  461. .if \need_result
  462. quot = r8
  463. num = r12
  464. den = r16
  465. bit = r20
  466. .else
  467. num = r8
  468. quot = r12
  469. den = r16
  470. bit = r20
  471. .endif
  472. quotH = quot+2
  473. quotL = quot
  474. quotB0 = quot
  475. quotB1 = quot+1
  476. quotB2 = quot+2
  477. quotB3 = quot+3
  478. numH = num+2
  479. numL = num
  480. numB0 = num
  481. numB1 = num+1
  482. numB2 = num+2
  483. numB3 = num+3
  484. #define denH bc
  485. denL = den
  486. denB0 = den
  487. denB1 = den+1
  488. #define denB2 c
  489. #define denB3 b
  490. bitH = bit+2
  491. bitL = bit
  492. bitB0 = bit
  493. bitB1 = bit+1
  494. bitB2 = bit+2
  495. bitB3 = bit+3
  496. ;----------------------------------------------------------------------
  497. START_FUNC __generic_sidivmod\which
  498. num_lt_den\which:
  499. .if \need_result
  500. movw r8, #0
  501. movw r10, #0
  502. .else
  503. movw ax, [sp+8]
  504. movw r8, ax
  505. movw ax, [sp+10]
  506. movw r10, ax
  507. .endif
  508. ret
  509. shift_den_bit16\which:
  510. movw ax, denL
  511. movw denH, ax
  512. movw denL, #0
  513. .if \need_result
  514. movw ax, bitL
  515. movw bitH, ax
  516. movw bitL, #0
  517. .else
  518. mov a, bit
  519. add a, #16
  520. mov bit, a
  521. .endif
  522. br $shift_den_bit\which
  523. ;; These routines leave DE alone - the signed functions use DE
  524. ;; to store sign information that must remain intact
  525. .if \need_result
  526. .global __generic_sidiv
  527. __generic_sidiv:
  528. .else
  529. .global __generic_simod
  530. __generic_simod:
  531. .endif
  532. ;; (quot,rem) = 8[sp] /% 12[sp]
  533. movw hl, sp
  534. movw ax, [hl+14] ; denH
  535. cmpw ax, [hl+10] ; numH
  536. movw ax, [hl+12] ; denL
  537. sknz
  538. cmpw ax, [hl+8] ; numL
  539. bh $num_lt_den\which
  540. #ifdef __RL78_G10__
  541. movw ax, denL
  542. push ax
  543. movw ax, bitL
  544. push ax
  545. movw ax, bitH
  546. push ax
  547. #else
  548. sel rb2
  549. push ax ; denL
  550. ; push bc ; denH
  551. push de ; bitL
  552. push hl ; bitH - stored in BC
  553. sel rb0
  554. #endif
  555. ;; (quot,rem) = 16[sp] /% 20[sp]
  556. ;; copy numerator
  557. movw ax, [hl+8]
  558. movw numL, ax
  559. movw ax, [hl+10]
  560. movw numH, ax
  561. ;; copy denomonator
  562. movw ax, [hl+12]
  563. movw denL, ax
  564. movw ax, [hl+14]
  565. movw denH, ax
  566. movw ax, denL
  567. or a, denB2
  568. or a, denB3 ; not x
  569. cmpw ax, #0
  570. bnz $den_not_zero\which
  571. .if \need_result
  572. movw quotL, #0
  573. movw quotH, #0
  574. .else
  575. movw numL, #0
  576. movw numH, #0
  577. .endif
  578. br $!main_loop_done_himode\which
  579. den_not_zero\which:
  580. .if \need_result
  581. ;; zero out quot
  582. movw quotL, #0
  583. movw quotH, #0
  584. .endif
  585. ;; initialize bit to 1
  586. movw bitL, #1
  587. movw bitH, #0
  588. ; while (den < num && !(den & (1L << BITS_MINUS_1)))
  589. .if 1
  590. ;; see if we can short-circuit a bunch of shifts
  591. movw ax, denH
  592. cmpw ax, #0
  593. bnz $shift_den_bit\which
  594. movw ax, denL
  595. cmpw ax, numH
  596. bnh $shift_den_bit16\which
  597. .endif
  598. shift_den_bit\which:
  599. movw ax, denH
  600. mov1 cy,a.7
  601. bc $enter_main_loop\which
  602. cmpw ax, numH
  603. movw ax, denL ; we re-use this below
  604. sknz
  605. cmpw ax, numL
  606. bh $enter_main_loop\which
  607. ;; den <<= 1
  608. ; movw ax, denL ; already has it from the cmpw above
  609. shlw ax, 1
  610. movw denL, ax
  611. ; movw ax, denH
  612. rolwc denH, 1
  613. ; movw denH, ax
  614. ;; bit <<= 1
  615. .if \need_result
  616. movw ax, bitL
  617. shlw ax, 1
  618. movw bitL, ax
  619. movw ax, bitH
  620. rolwc ax, 1
  621. movw bitH, ax
  622. .else
  623. ;; if we don't need to compute the quotent, we don't need an
  624. ;; actual bit *mask*, we just need to keep track of which bit
  625. inc bitB0
  626. .endif
  627. br $shift_den_bit\which
  628. ;; while (bit)
  629. main_loop\which:
  630. ;; if (num >= den) (cmp den > num)
  631. movw ax, numH
  632. cmpw ax, denH
  633. movw ax, numL
  634. sknz
  635. cmpw ax, denL
  636. skz
  637. bnh $next_loop\which
  638. ;; num -= den
  639. ; movw ax, numL ; already has it from the cmpw above
  640. subw ax, denL
  641. movw numL, ax
  642. movw ax, numH
  643. sknc
  644. decw ax
  645. subw ax, denH
  646. movw numH, ax
  647. .if \need_result
  648. ;; res |= bit
  649. mov a, quotB0
  650. or a, bitB0
  651. mov quotB0, a
  652. mov a, quotB1
  653. or a, bitB1
  654. mov quotB1, a
  655. mov a, quotB2
  656. or a, bitB2
  657. mov quotB2, a
  658. mov a, quotB3
  659. or a, bitB3
  660. mov quotB3, a
  661. .endif
  662. next_loop\which:
  663. ;; den >>= 1
  664. movw ax, denH
  665. shrw ax, 1
  666. movw denH, ax
  667. mov a, denB1
  668. rorc a, 1
  669. mov denB1, a
  670. mov a, denB0
  671. rorc a, 1
  672. mov denB0, a
  673. ;; bit >>= 1
  674. .if \need_result
  675. movw ax, bitH
  676. shrw ax, 1
  677. movw bitH, ax
  678. mov a, bitB1
  679. rorc a, 1
  680. mov bitB1, a
  681. mov a, bitB0
  682. rorc a, 1
  683. mov bitB0, a
  684. .else
  685. dec bitB0
  686. .endif
  687. enter_main_loop\which:
  688. .if \need_result
  689. movw ax, bitH
  690. cmpw ax, #0
  691. bnz $main_loop\which
  692. .else
  693. cmp bitB0, #15
  694. bh $main_loop\which
  695. .endif
  696. ;; bit is HImode now; check others
  697. movw ax, numH ; numerator
  698. cmpw ax, #0
  699. bnz $bit_high_set\which
  700. movw ax, denH ; denominator
  701. cmpw ax, #0
  702. bz $switch_to_himode\which
  703. bit_high_set\which:
  704. .if \need_result
  705. movw ax, bitL
  706. cmpw ax, #0
  707. .else
  708. cmp0 bitB0
  709. .endif
  710. bnz $main_loop\which
  711. switch_to_himode\which:
  712. .if \need_result
  713. movw ax, bitL
  714. cmpw ax, #0
  715. .else
  716. cmp0 bitB0
  717. .endif
  718. bz $main_loop_done_himode\which
  719. ;; From here on in, r22, r14, and r18 are all zero
  720. ;; while (bit)
  721. main_loop_himode\which:
  722. ;; if (num >= den) (cmp den > num)
  723. movw ax, denL
  724. cmpw ax, numL
  725. bh $next_loop_himode\which
  726. ;; num -= den
  727. movw ax, numL
  728. subw ax, denL
  729. movw numL, ax
  730. movw ax, numH
  731. sknc
  732. decw ax
  733. subw ax, denH
  734. movw numH, ax
  735. .if \need_result
  736. ;; res |= bit
  737. mov a, quotB0
  738. or a, bitB0
  739. mov quotB0, a
  740. mov a, quotB1
  741. or a, bitB1
  742. mov quotB1, a
  743. .endif
  744. next_loop_himode\which:
  745. ;; den >>= 1
  746. movw ax, denL
  747. shrw ax, 1
  748. movw denL, ax
  749. .if \need_result
  750. ;; bit >>= 1
  751. movw ax, bitL
  752. shrw ax, 1
  753. movw bitL, ax
  754. .else
  755. dec bitB0
  756. .endif
  757. .if \need_result
  758. movw ax, bitL
  759. cmpw ax, #0
  760. .else
  761. cmp0 bitB0
  762. .endif
  763. bnz $main_loop_himode\which
  764. main_loop_done_himode\which:
  765. #ifdef __RL78_G10__
  766. pop ax
  767. movw bitH, ax
  768. pop ax
  769. movw bitL, ax
  770. pop ax
  771. movw denL, ax
  772. #else
  773. sel rb2
  774. pop hl ; bitH - stored in BC
  775. pop de ; bitL
  776. ; pop bc ; denH
  777. pop ax ; denL
  778. sel rb0
  779. #endif
  780. ret
  781. END_FUNC __generic_sidivmod\which
  782. .endm
  783. ;----------------------------------------------------------------------
  784. MAKE_GENERIC _d 1
  785. MAKE_GENERIC _m 0
  786. ;----------------------------------------------------------------------
  787. START_FUNC ___udivsi3
  788. ;; r8 = 4[sp] / 8[sp]
  789. call $!__generic_sidiv
  790. ret
  791. END_FUNC ___udivsi3
  792. START_FUNC ___umodsi3
  793. ;; r8 = 4[sp] % 8[sp]
  794. call $!__generic_simod
  795. ret
  796. END_FUNC ___umodsi3
  797. ;----------------------------------------------------------------------
  798. .macro NEG_AX
  799. movw hl, ax
  800. movw ax, #0
  801. subw ax, [hl]
  802. movw [hl], ax
  803. movw ax, #0
  804. sknc
  805. decw ax
  806. subw ax, [hl+2]
  807. movw [hl+2], ax
  808. .endm
  809. ;----------------------------------------------------------------------
  810. START_FUNC ___divsi3
  811. ;; r8 = 4[sp] / 8[sp]
  812. movw de, #0
  813. mov a, [sp+7]
  814. mov1 cy, a.7
  815. bc $div_signed_num
  816. mov a, [sp+11]
  817. mov1 cy, a.7
  818. bc $div_signed_den
  819. call $!__generic_sidiv
  820. ret
  821. div_signed_num:
  822. ;; neg [sp+4]
  823. movw ax, sp
  824. addw ax, #4
  825. NEG_AX
  826. mov d, #1
  827. mov a, [sp+11]
  828. mov1 cy, a.7
  829. bnc $div_unsigned_den
  830. div_signed_den:
  831. ;; neg [sp+8]
  832. movw ax, sp
  833. addw ax, #8
  834. NEG_AX
  835. mov e, #1
  836. div_unsigned_den:
  837. call $!__generic_sidiv
  838. mov a, d
  839. cmp0 a
  840. bz $div_skip_restore_num
  841. ;; We have to restore the numerator [sp+4]
  842. movw ax, sp
  843. addw ax, #4
  844. NEG_AX
  845. mov a, d
  846. div_skip_restore_num:
  847. xor a, e
  848. bz $div_no_neg
  849. movw ax, #r8
  850. NEG_AX
  851. div_no_neg:
  852. mov a, e
  853. cmp0 a
  854. bz $div_skip_restore_den
  855. ;; We have to restore the denominator [sp+8]
  856. movw ax, sp
  857. addw ax, #8
  858. NEG_AX
  859. div_skip_restore_den:
  860. ret
  861. END_FUNC ___divsi3
  862. START_FUNC ___modsi3
  863. ;; r8 = 4[sp] % 8[sp]
  864. movw de, #0
  865. mov a, [sp+7]
  866. mov1 cy, a.7
  867. bc $mod_signed_num
  868. mov a, [sp+11]
  869. mov1 cy, a.7
  870. bc $mod_signed_den
  871. call $!__generic_simod
  872. ret
  873. mod_signed_num:
  874. ;; neg [sp+4]
  875. movw ax, sp
  876. addw ax, #4
  877. NEG_AX
  878. mov d, #1
  879. mov a, [sp+11]
  880. mov1 cy, a.7
  881. bnc $mod_unsigned_den
  882. mod_signed_den:
  883. ;; neg [sp+8]
  884. movw ax, sp
  885. addw ax, #8
  886. NEG_AX
  887. mov e, #1
  888. mod_unsigned_den:
  889. call $!__generic_simod
  890. mov a, d
  891. cmp0 a
  892. bz $mod_no_neg
  893. movw ax, #r8
  894. NEG_AX
  895. ;; We have to restore [sp+4] as well.
  896. movw ax, sp
  897. addw ax, #4
  898. NEG_AX
  899. mod_no_neg:
  900. .if 1
  901. mov a, e
  902. cmp0 a
  903. bz $mod_skip_restore_den
  904. movw ax, sp
  905. addw ax, #8
  906. NEG_AX
  907. mod_skip_restore_den:
  908. .endif
  909. ret
  910. END_FUNC ___modsi3
  911. ;----------------------------------------------------------------------
  912. #else
  913. #error "Unknown RL78 hardware multiply/divide support"
  914. #endif