divide.inc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Based on restoring division algorithm
  2. // Algorithm source document: Lecture notes by S. Galal and D. Pham, Division algorithms and hardware implementations.
  3. // Link to documentation http://www.seas.ucla.edu/~ingrid/ee213a/lectures/division_presentV2.pdf
  4. // Also refer to description on Wikipedia: https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
  5. // Note that the algorithm automatically yields the following results for special cases:
  6. // z div 0 = MAX(type)
  7. // 0 div 0 = MAX(type)
  8. // 0 div n = 0
  9. // Checks for z = 0; n = [0,1]; n = z and n > z could shortcut the algorithm for speed-ups
  10. // but would add extra code
  11. // Perhaps add the checks depending on optimization settings?
  12. // z in Ra, n in Rb, 0 in Rp
  13. function fpc_divmod_byte(n, z: byte): byte; assembler; nostackframe;
  14. label
  15. div1, div2, div3, finish;
  16. asm
  17. // Symbol Name Register(s)
  18. // z (A) dividend R22
  19. // n (B) divisor R24
  20. // p (P) remainder R20
  21. // i counter R18
  22. clr R20 // clear remainder
  23. ldi R18, 8 // iterate over 8 bits
  24. div1:
  25. lsl R22 // shift left A
  26. rol R20 // shift left P with carry from A shift
  27. sub R20, R24 // Subtract B from P, P <= P - B
  28. brlo div2
  29. ori R22, 1 // Set A[0] = 1
  30. rjmp div3
  31. div2: // negative branch, A[0] = 0 (default after shift), restore P
  32. add R20, R24 // restore old value of P
  33. div3:
  34. dec R18
  35. brne div1
  36. finish:
  37. mov R24, R22 // Move result from R22 to R24
  38. end;
  39. {$if defined(CPUAVR_16_REGS) or not(defined(CPUAVR_HAS_MOVW))}
  40. function fpc_divmod_word(n, z: word): word; assembler; nostackframe;
  41. label
  42. div1, div2, div3, finish;
  43. asm
  44. // Symbol Name Register(s)
  45. // z (A) dividend R23, R22
  46. // n (B) divisor R25, R24
  47. // p (P) remainder R21, R20
  48. // i counter R18
  49. clr R20 // clear remainder low
  50. clr R21 // clear remainder hi
  51. ldi R18, 16 // iterate over 16 bits
  52. div1:
  53. lsl R22 // shift left A_L
  54. rol R23
  55. rol R20 // shift left P with carry from A shift
  56. rol R21
  57. sub R20, R24 // Subtract B from P, P <= P - B
  58. sbc R21, R25
  59. brlo div2
  60. ori R22, 1 // Set A[0] = 1
  61. rjmp div3
  62. div2: // negative branch, A[0] = 0 (default after shift), restore P
  63. add R20, R24 // restore old value of P
  64. adc R21, R25
  65. div3:
  66. dec R18
  67. brne div1
  68. finish:
  69. mov R24, R22 // Move result from R22:R23 to R24:R25
  70. mov R25, R23 // Move result from R22:R23 to R24:R25
  71. end;
  72. function fpc_divmod_dword(n, z: dword): dword; assembler; nostackframe;
  73. label
  74. div1, div2, div3, finish;
  75. asm
  76. end;
  77. {$else defined(CPUAVR_16_REGS) or not(defined(CPUAVR_HAS_MOVW))}
  78. // z in Ra, n in Rb, 0 in Rp
  79. function fpc_divmod_word(n, z: word): word; assembler; nostackframe;
  80. label
  81. div1, div2, div3, finish;
  82. asm
  83. // Symbol Name Register(s)
  84. // z (A) dividend R23, R22
  85. // n (B) divisor R25, R24
  86. // p (P) remainder R21, R20
  87. // i counter R18
  88. clr R20 // clear remainder low
  89. clr R21 // clear remainder hi
  90. ldi R18, 16 // iterate over 16 bits
  91. div1:
  92. lsl R22 // shift left A_L
  93. rol R23
  94. rol R20 // shift left P with carry from A shift
  95. rol R21
  96. sub R20, R24 // Subtract B from P, P <= P - B
  97. sbc R21, R25
  98. brlo div2
  99. ori R22, 1 // Set A[0] = 1
  100. rjmp div3
  101. div2: // negative branch, A[0] = 0 (default after shift), restore P
  102. add R20, R24 // restore old value of P
  103. adc R21, R25
  104. div3:
  105. dec R18
  106. brne div1
  107. finish:
  108. movw R24, R22 // Move result from R22:R23 to R24:R25
  109. end;
  110. // z in Ra, n in Rb, 0 in Rp
  111. function fpc_divmod_dword(n, z: dword): dword; assembler; nostackframe;
  112. label
  113. div1, div2, div3, finish;
  114. asm
  115. // Symbol Name Register(s)
  116. // z (A) dividend R21, R20, R19, R18
  117. // n (B) divisor R25, R24, R23, R22
  118. // p (P) remainder R17, R16, R15, R14 -> Returned in R25, R24, R23, R22
  119. // i counter R26
  120. push R17
  121. push R16
  122. push R15
  123. push R14
  124. clr R14 // clear remainder
  125. clr R15 // clear remainder
  126. clr R16
  127. clr R17
  128. ldi R26, 32 // iterate over 32 bits
  129. div1:
  130. lsl R18 // shift left A_L
  131. rol R19
  132. rol R20
  133. rol R21
  134. rol R14 // shift left P with carry from A shift
  135. rol R15
  136. rol R16
  137. rol R17
  138. sub R14, R22 // Subtract B from P, P <= P - B
  139. sbc R15, R23
  140. sbc R16, R24
  141. sbc R17, R25
  142. brlo div2
  143. ori R18, 1 // Set A[0] = 1
  144. rjmp div3
  145. div2: // negative branch, A[0] = 0 (default after shift), restore P
  146. add R14, R22 // restore old value of P
  147. adc R15, R23
  148. adc R16, R24
  149. adc R17, R25
  150. div3:
  151. dec R26
  152. brne div1
  153. finish:
  154. movw R22, R14 // Move remainder into reg that is not volatile
  155. movw R24, R16
  156. pop R14
  157. pop R15
  158. pop R16
  159. pop R17
  160. end;
  161. {$endif defined(CPUAVR_16_REGS) or not(defined(CPUAVR_HAS_MOVW))}