home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / CLISP / CLISPSRC.TAR / clisp-1995-01-01 / src / ariarm.d < prev    next >
Encoding:
Text File  |  1994-12-21  |  78.1 KB  |  1,816 lines

  1. # ariarm.d (c) Copyright 1994 P.J.Burwood
  2. # external routines for arilev1.d
  3. # Processor: ARM in APCS mode
  4. # Assembler-Syntax: ObjAsm
  5. # Assumptions: intCsize=32, intDsize=32.
  6. # Parameter passing conventions: APCS means that registers a1-a4 and ip do not
  7. #   have to be preserved across function calls.
  8. # Note: A sequence of up to 4 conditional instructions is used in preference
  9. #   to a branch.
  10.  
  11. #ifdef INCLUDED_FROM_C
  12.  
  13.   #define COPY_LOOPS
  14.   #define FILL_LOOPS
  15.   #define CLEAR_LOOPS
  16.   #define LOG_LOOPS
  17.   #define TEST_LOOPS
  18.   #define ADDSUB_LOOPS
  19.   #define SHIFT_LOOPS
  20.   #define MUL_LOOPS
  21.  
  22. #else
  23.  
  24. a1      RN      0
  25. a2      RN      1
  26. a3      RN      2
  27. a4      RN      3
  28. v1      RN      4
  29. v2      RN      5
  30. v3      RN      6
  31. v4      RN      7
  32. v5      RN      8
  33. v6      RN      9
  34. sl      RN      10
  35. fp      RN      11
  36. ip      RN      12
  37. sp      RN      13
  38. lr      RN      14
  39. pc      RN      15
  40.  
  41. f0      FN      0
  42. f1      FN      1
  43. f2      FN      2
  44. f3      FN      3
  45. f4      FN      4
  46. f5      FN      5
  47. f6      FN      6
  48. f7      FN      7
  49.  
  50.         AREA    |C$$code|,CODE,READONLY
  51.  
  52. /* with GNU C we pass the second value in a2, don't need a global variable */
  53. #ifndef __GNUC__
  54. ptr_mulu32_high
  55.         IMPORT  mulu32_high
  56.         DCD     mulu32_high
  57. #endif
  58. ptr_divu_16_rest
  59.         IMPORT  divu_16_rest
  60.         DCD     divu_16_rest
  61. #ifndef __GNUC__
  62. ptr_divu_32_rest
  63.         IMPORT  divu_32_rest
  64.         DCD     divu_32_rest
  65. #endif
  66.  
  67. # extern uint32 mulu32_ (uint32 arg1, uint32 arg2);
  68. #       entry
  69. #               a1 = x
  70. #               a2 = y
  71. #       exit
  72. #               a1 = low32(x*y)
  73. #               a2 = high32(x*y)
  74. #               mulu32_high = high32(x*y)
  75. #               a3,a4,ip destroyed
  76.         EXPORT  mulu32_
  77. mulu32_
  78.         MOV     ip,a1,LSR #16           # temp := top half of x
  79.         MOV     a3,a2,LSR #16           # hi := top half of y
  80.         BIC     a1,a1,ip,LSL #16        # x  := bottom half of x
  81.         BIC     a2,a2,a3,LSL #16        # y  := bottom half of y
  82.         MUL     a4,a1,a2                # low section of result
  83.         MUL     a2,ip,a2                # ) middle sections
  84.         MUL     a1,a3,a1                # )   of result
  85.         MUL     a3,ip,a3                # high section of result
  86.         ADDS    a2,a2,a1                # add middle sections
  87.                                         # (can't use mla as we need carry)
  88.         ADDCS   a3,a3,#&10000           # carry from above add
  89.         ADDS    a1,a4,a2,LSL #16        # x is now bottom 32 bits of result
  90.         ADC     a2,a3,a2,LSR #16        # hi is top 32 bits
  91. #ifndef __GNUC__
  92.         LDR     a3,[pc,#ptr_mulu32_high-.-8]
  93.         STR     a2,[a3,#0]
  94. #endif
  95.         MOVS    pc,lr
  96.  
  97.         EXPORT  divu_3216_1616_
  98. divu_3216_1616_
  99.         MOV     a2,a2,LSL#15            # multiply divisor by 2^15
  100.         RSB     a2,a2,#0                # negate divisor
  101.         ADDS    a1,a2,a1                # dividend = dividend + -divisor/2
  102.         SUBCC   a1,a1,a2                # dividend = dividend - -divisor/2
  103.         ADCS    a1,a2,a1,LSL#1          # dividend = dividend*2 + -divisor
  104.                                         # and shift quotient
  105.         SUBCC   a1,a1,a2                # do this another 15 times
  106.         ADCS    a1,a2,a1,LSL#1
  107.         SUBCC   a1,a1,a2
  108.         ADCS    a1,a2,a1,LSL#1
  109.         SUBCC   a1,a1,a2
  110.         ADCS    a1,a2,a1,LSL#1
  111.         SUBCC   a1,a1,a2
  112.         ADCS    a1,a2,a1,LSL#1
  113.         SUBCC   a1,a1,a2
  114.         ADCS    a1,a2,a1,LSL#1
  115.         SUBCC   a1,a1,a2
  116.         ADCS    a1,a2,a1,LSL#1
  117.         SUBCC   a1,a1,a2
  118.         ADCS    a1,a2,a1,LSL#1
  119.         SUBCC   a1,a1,a2
  120.         ADCS    a1,a2,a1,LSL#1
  121.         SUBCC   a1,a1,a2
  122.         ADCS    a1,a2,a1,LSL#1
  123.         SUBCC   a1,a1,a2
  124.         ADCS    a1,a2,a1,LSL#1
  125.         SUBCC   a1,a1,a2
  126.         ADCS    a1,a2,a1,LSL#1
  127.         SUBCC   a1,a1,a2
  128.         ADCS    a1,a2,a1,LSL#1
  129.         SUBCC   a1,a1,a2
  130.         ADCS    a1,a2,a1,LSL#1
  131.         SUBCC   a1,a1,a2
  132.         ADCS    a1,a2,a1,LSL#1
  133.         SUBCC   a1,a1,a2
  134.         MOV     a2,a1,LSR#15            # move remainder into a2 and shift
  135.         ADC     a1,a1,a1                # move last bit of quotient in
  136.         MOV     a1,a1,LSL#16            # AND out top 16 bits by shifting up
  137.         MOV     a1,a1,LSR#16            # and back down again
  138.         LDR     a3,[pc,#ptr_divu_16_rest-.-8]   # save rest so can be picked up later
  139.         STR     a2,[a3,#0]              # the result is 16 bits
  140.         MOVS    pc, lr
  141.  
  142. # extern uint32 divu_6432_3232_ (uint32 x, uint32 y); # -> Quotient q
  143. # extern uint32 divu_32_rest;                         # -> Rest r
  144. #       see arilev0 for algorithm
  145. #       entry
  146. #               a1 = xhi (dividend)
  147. #               a2 = xlo (dividend)
  148. #               a3 = y (divisor)
  149. #       exit
  150. #               a1 = 32 bit quotient
  151. #               a2 = 32 bit remainder
  152. #               a3, a4 destroyed
  153.         EXPORT  divu_6432_3232_
  154. divu_6432_3232_
  155.         STMFD   sp!, {v1,v2,v3,v4,v5,v6,lr}
  156.         MOV     v2, a2                  # = xlo
  157.         MOV     v1, a3                  # = y
  158.         CMP     a3,#&10000              # y <= (uint32)(bit(16)-1)
  159.         BCS     |L0005b0.J4.divu_6432_3232_|
  160.         MOV     a2, v2, LSR #16
  161.         ORR     a1, a2, a1, ASL #16     # = highlow32(low16(xhi),high16(xlo))
  162.         MOV     a2, v1
  163.         BL      divu_3216_1616_
  164.         MOV     v3, a1                  # = q1
  165.         MOV     a1, v2, ASL #16
  166.         MOV     a1, a1, LSR #16
  167.         ORR     a1, a1, a2, ASL #16     # = highlow32(r1,low16(xlo))
  168.         MOV     a2, v1
  169.         BL      divu_3216_1616_
  170.         ORR     a1, a1, v3, ASL #16     # = highlow32(q1,q0)
  171. #ifndef __GNUC__
  172.         LDR     a4,[pc,#ptr_divu_32_rest-.-8]
  173.         STR     a2,[a4,#0]              # divu_32_rest = remainder
  174. #endif
  175.         LDMFD   sp!, {v1,v2,v3,v4,v5,v6,pc}^
  176.  
  177. |L0005b0.J4.divu_6432_3232_|
  178.         MOV     v3, #0                  # s = 0
  179.         MOVS    a4, v1, LSR #16         # while ((sint32)y >= 0)
  180.         ADDEQ   v3, v3, #16             #   { y = y<<1; s++; }
  181.         MOVEQ   v1, v1, ASL #16
  182.         MOVS    a4, v1, LSR #24
  183.         ADDEQ   v3, v3, #8
  184.         MOVEQ   v1, v1, ASL #8
  185.         MOVS    a4, v1, LSR #28
  186.         ADDEQ   v3, v3, #4
  187.         MOVEQ   v1, v1, ASL #4
  188.         MOVS    a4, v1, LSR #30
  189.         ADDEQ   v3, v3, #2
  190.         MOVEQ   v1, v1, ASL #2
  191.         MOVS    a4, v1, LSR #31
  192.         ADDEQ   v3, v3, #1
  193.         MOVEQ   v1, v1, ASL #1
  194.  
  195.         CMPS    v3, #0
  196.         MOVNE   a2, a1, ASL v3          # if (!(s==0))
  197.         RSBNE   a1, v3, #32             #   { xhi = (xhi << s)
  198.         ORRNE   a1, a2, v2, LSR a1      #         | (xlo >> (32-s));
  199.         MOVNE   v2, v2, ASL v3          #     xlo = xlo << s; }
  200.         ADD     a2, v1, #&10000         # y1_1 = high16(y)+1
  201.         MOVS    v5, a2, LSR #16         # if (y1_1 = 0)
  202.         MOVEQ   v4, a1, ASL #16         # r16 = low16(xhi) * 2^16
  203.         MOVEQ   a1, a1, LSR #16         # q1 = high16(xhi)
  204.         MOVNE   a2, v5
  205.         BLNE    divu_3216_1616_         # divu_3216_1616(xhi,y1_1, q1=,r16=)
  206.         MOVNE   v4, a2, ASL #16         # r16 = r16 * 2^16
  207.         ORR     v4, v4, v2, LSR #16     # r = highlow32(r16,high16(xlo))
  208.         MOV     a4, v1, ASL #16         # tmp = mulu16(low16(y),q1)
  209.         MOV     a4, a4, LSR #16
  210.         MUL     a3, a4, a1
  211.         RSB     a3, a3, a1, ASL #16     # r2 = highlow32_0(q1) - tmp
  212.         MOV     v6, a1                  # = q1
  213.         ADDS    a1, v4, a3              # r += r2
  214.         ADDCS   v6, v6, #1              # if ( r < r2 ) { q1 += 1
  215.         SUBCS   a1, a1, v1              #                 r -= y }
  216.         CMP     a1, v1                  # if (r >= y)
  217.         ADDCS   v6, v6, #1              #     { q1 += 1
  218.         SUBCS   a1, a1, v1              #       r -= y }
  219.         CMP     v5, #0                  # if (y1_1 = 0)
  220.         MOVEQ   v4, a1, ASL #16         #    { r16 = low16(r) * 2^16
  221.         MOVEQ   a1, a1, LSR #16         #      q0  = high16(r) }
  222.         MOVNE   a2, v5
  223.         BLNE    divu_3216_1616_         # divu_3216_1616(r,y1_1, q0=,r16=)
  224.         MOVNE   v4, a2, ASL #16         # r16 = r16 * 2^16
  225.         MOV     v2, v2, ASL #16
  226.         ORR     v4, v4, v2, LSR #16     # r = highlow32(r16,low16(xlo))
  227.         MOV     a4, v1, ASL #16         # tmp = mulu16(low16(y),q0)
  228.         MOV     a4, a4, LSR #16
  229.         MUL     a3, a4, a1
  230.         RSB     a3, a3, a1, ASL #16     # r2 = highlow32_0(q0) - tmp
  231.         ADDS    v4, v4, a3              # r += r2
  232.         ADDCS   a1, a1, #1              # if ( r < r2 ) { q0 += 1
  233.         SUBCS   v4, v4, v1              #                 r -= y }
  234.         CMP     v4, v1                  # if (r >= y)
  235.         ADDCS   a1, a1, #1              #     { q0 += 1
  236.         SUBCS   v4, v4, v1              #       r -= y }
  237.         MOV     a2, v4, LSR v3          # remainder = r >> s
  238.         ORR     a1, a1, v6, ASL #16     # return highlow32(q1,q0)
  239. #ifndef __GNUC__
  240.         LDR     a3,[pc,#ptr_divu_32_rest-.-8]
  241.         STR     a2,[a3,#0]              # divu_32_rest = remainder
  242. #endif
  243.         LDMFD   sp!, {v1,v2,v3,v4,v5,v6,pc}^
  244.  
  245. # extern uintD* copy_loop_up (uintD* sourceptr, uintD* destptr, uintC count);
  246. #       entry
  247. #               a1 = source pointer
  248. #               a2 = destination pointer
  249. #               a3 = count of words to store
  250. #       exit
  251. #               a1 = address of last word stored + 1
  252. #               a2 - a4, ip destroyed
  253.         EXPORT  |copy_loop_up|          # word aligned copy loop up
  254. #       NAME    |copy_loop_up|
  255. |copy_loop_up|
  256.         ANDS    a4,a3,#3                # multiple of 4 words ?
  257.         BEQ     |copy_loop_up_l1|       # yup, so branch
  258.         CMP     a4,#2                   # copy the first 1-3 words
  259.         LDR     a4,[a1],#4              # to align the total to a multiple
  260.         STR     a4,[a2],#4              # of 4 words
  261.         LDRGE   a4,[a1],#4
  262.         STRGE   a4,[a2],#4
  263.         LDRGT   a4,[a1],#4
  264.         STRGT   a4,[a2],#4
  265. |copy_loop_up_l1|
  266.         BICS    a4,a3,#3                # set counter to multiple of 4
  267.         MOVEQ   a1,a2                   # return addr of last word stored
  268.         MOVEQS  pc,lr                   # if zero then we're done
  269.         STMFD   sp!,{v1,lr}             # save work regs
  270. |copy_loop_up_l2|
  271.         LDMIA   a1!,{a3,v1,ip,lr}       # copy 4 words in one go
  272.         STMIA   a2!,{a3,v1,ip,lr}
  273.         SUBS    a4,a4,#8                # decrement counter by 8
  274.         LDMGEIA a1!,{a3,v1,ip,lr}       # if count still positive then copy
  275.         STMGEIA a2!,{a3,v1,ip,lr}       # 4 more words
  276.         BGT     |copy_loop_up_l2|       # and loop
  277.         MOV     a1,a2                   # return addr of last word stored
  278.         LDMFD   sp!,{v1,pc}^            # restore work regs and return
  279.  
  280. # extern uintD* copy_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
  281. #       entry
  282. #               a1 = source pointer
  283. #               a2 = destination pointer
  284. #               a3 = count of words to store
  285. #       exit
  286. #               a1 = address of last word stored
  287. #               a2 - a4, ip destroyed
  288.         EXPORT  |copy_loop_down|        # word aligned copy loop down
  289. #       NAME    |copy_loop_down|
  290. |copy_loop_down|
  291.         ANDS    a4,a3,#3                # multiple of 4 words ?
  292.         BEQ     |copy_loop_down_l1|     # yup, so branch
  293.         CMP     a4,#2                   # copy the first 1-3 words
  294.         LDR     a4,[a1,#-4]!            # to align the total to a multiple
  295.         STR     a4,[a2,#-4]!            # of 4 words
  296.         LDRGE   a4,[a1,#-4]!
  297.         STRGE   a4,[a2,#-4]!
  298.         LDRGT   a4,[a1,#-4]!
  299.         STRGT   a4,[a2,#-4]!
  300. |copy_loop_down_l1|
  301.         BICS    a4,a3,#3                # set counter to multiple of 4
  302.         MOVEQ   a1,a2                   # return addr of last word stored
  303.         MOVEQS  pc,lr                   # if zero then we're done
  304.         STMFD   sp!,{v1,lr}             # save work regs
  305. |copy_loop_down_l2|
  306.         LDMDB   a1!,{a3,v1,ip,lr}       # copy 4 words in one go
  307.         STMDB   a2!,{a3,v1,ip,lr}
  308.         SUBS    a4,a4,#8                # decrement counter by 8
  309.         LDMGEDB a1!,{a3,v1,ip,lr}       # if count still positive then copy
  310.         STMGEDB a2!,{a3,v1,ip,lr}       # 4 more words
  311.         BGT     |copy_loop_down_l2|     # and loop
  312.         MOV     a1,a2                   # return addr of last word stored
  313.         LDMFD   sp!,{v1,pc}^            # restore work regs and return
  314.  
  315. # extern uintD* clear_loop_up (uintD* destptr, uintC count);
  316. #       entry
  317. #               a1 = destination pointer
  318. #               a2 = count of words to store
  319. #       exit
  320. #               a1 = address of last word stored + 1
  321. #               a2 - a4, ip destroyed
  322.         EXPORT  |clear_loop_up|         # word aligned clear loop up
  323. |clear_loop_up|
  324.         MOV     a3,#0                   # set filler to 0
  325.                                         # and drop into fill_loop_up
  326.  
  327. # extern uintD* fill_loop_up (uintD* destptr, uintC count, uintD filler);
  328. #       entry
  329. #               a1 = destination pointer
  330. #               a2 = count of words to store
  331. #               a3 = word to store
  332. #       exit
  333. #               a1 = address of last word stored + 1
  334. #               a2 - a4, ip destroyed
  335.         EXPORT  |fill_loop_up|          # word aligned fill loop up
  336. |fill_loop_up|
  337.         ANDS    a4,a2,#3                # multiple of 4 words ?
  338.         BEQ     |fill_loop_up_l1|       # yup, so branch
  339.         CMP     a4,#2                   # store the first 1-3 words
  340.         STR     a3,[a1],#4              # to align the total to a multiple
  341.         STRGE   a3,[a1],#4              # of 4 words
  342.         STRGT   a3,[a1],#4
  343. |fill_loop_up_l1|
  344.         BICS    a4,a2,#3                # set counter to multiple of 4
  345.         MOVEQS  pc,lr                   # if zero then we're done
  346.         STMFD   sp!,{v1,lr}             # save work regs
  347.         MOV     v1,a3                   # copy filler to three other
  348.         MOV     ip,a3                   # registers
  349.         MOV     lr,a3
  350. |fill_loop_up_l2|
  351.         STMIA   a1!,{a3,v1,ip,lr}       # store 4 fillers in one go
  352.         SUBS    a4,a4,#8                # decrement counter by 8
  353.         STMGEIA a1!,{a3,v1,ip,lr}       # if count still positive then store 4
  354.         BGT     |fill_loop_up_l2|       # more and loop
  355.         LDMFD   sp!,{v1,pc}^            # restore work regs and return
  356.  
  357.  
  358. # extern uintD* clear_loop_down (uintD* destptr, uintC count);
  359. #       entry
  360. #               a1 = destination pointer
  361. #               a2 = count of words to store
  362. #       exit
  363. #               a1 = address of last word stored + 1
  364. #               a2 - a4, ip destroyed
  365.         EXPORT  |clear_loop_down|       # word aligned clear loop down
  366. |clear_loop_down|
  367.         MOV     a3,#0                   # set filler to 0
  368.                                         # and drop into fill_loop_down
  369.  
  370. # extern uintD* fill_loop_down (uintD* destptr, uintC count, uintD filler);
  371. #       entry
  372. #               a1 = destination pointer
  373. #               a2 = count of words to store
  374. #               a3 = word to store
  375. #       exit
  376. #               a1 = address of last word stored
  377. #               a2 - a4, ip destroyed
  378.         EXPORT  |fill_loop_down|        # word aligned fill loop down
  379. |fill_loop_down|
  380.         ANDS    a4,a2,#3                # multiple of 4 words ?
  381.         BEQ     |fill_loop_down_l1|     # yup, so branch
  382.         CMP     a4,#2                   # store the first 1-3 words
  383.         STR     a3,[a1,#-4]!            # to align the total to a multiple
  384.         STRGE   a3,[a1,#-4]!            # of 4 words
  385.         STRGT   a3,[a1,#-4]!
  386. |fill_loop_down_l1|
  387.         BICS    a4,a2,#3                # set counter to multiple of 4
  388.         MOVEQS  pc,lr                   # if zero then we're done
  389.         STMFD   sp!,{v1,lr}             # save work regs
  390.         MOV     v1,a3                   # copy filler to three other
  391.         MOV     ip,a3                   # registers
  392.         MOV     lr,a3
  393. |fill_loop_down_l2|
  394.         STMDB   a1!,{a3,v1,ip,lr}       # store 4 fillers in one go
  395.         SUBS    a4,a4,#8                # decrement counter by 8
  396.         STMGEDB a1!,{a3,v1,ip,lr}       # if count still positive then store 4
  397.         BGT     |fill_loop_down_l2|     # more and loop
  398.         LDMFD   sp!,{v1,pc}^            # restore work regs and return
  399.  
  400. # extern void or_loop_up (uintD* xptr, uintD* yptr, uintC count);
  401. #       entry
  402. #               a1 = xptr
  403. #               a2 = yptr
  404. #               a3 = count of words to be ORed
  405. #       exit
  406. #               xptr |= yptr for count words
  407. #               a1 - a4, ip destroyed
  408.         EXPORT  |or_loop_up|            # word aligned or loop up
  409. |or_loop_up|
  410.         ANDS    a4,a3,#3                # multiple of 4 words ?
  411.         BEQ     |or_loop_up_l1|         # yup, so branch
  412.         CMP     a4,#2                   # OR the first 1-3 words
  413.         LDR     a4,[a2],#4              # to align the total to a multiple
  414.         LDR     ip,[a1]                 # of 4 words
  415.         ORR     ip,ip,a4
  416.         STR     ip,[a1],#4
  417.         BLT     |or_loop_up_l1|         # better to branch than skip instrs.
  418.         LDRGE   a4,[a2],#4
  419.         LDRGE   ip,[a1]
  420.         ORRGE   ip,ip,a4
  421.         STRGE   ip,[a1],#4
  422.         LDRGT   a4,[a2],#4
  423.         LDRGT   ip,[a1]
  424.         ORRGT   ip,ip,a4
  425.         STRGT   ip,[a1],#4
  426. |or_loop_up_l1|
  427.         BICS    a4,a3,#3                # set counter to multiple of 4
  428.         MOVEQS  pc,lr                   # if zero then we're done
  429.         STMFD   sp!,{v1-v5,lr}          # save work regs
  430. |or_loop_up_l2|
  431.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  432.         LDMIA   a1,{v3,v4,v5,lr}        # load target words
  433.         ORR     v3,v3,a3                # OR the four words
  434.         ORR     v4,v4,v1
  435.         ORR     v5,v5,v2
  436.         ORR     lr,lr,ip
  437.         STMIA   a1!,{v3,v4,v5,lr}       # store 4 results
  438.         SUBS    a4,a4,#4                # decrement counter by 4
  439.         BGT     |or_loop_up_l2|         # if count still positive then loop
  440.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  441.  
  442.  
  443. # extern void xor_loop_up (uintD* xptr, uintD* yptr, uintC count);
  444. #       entry
  445. #               a1 = xptr
  446. #               a2 = yptr
  447. #               a3 = count of words to be XORed
  448. #       exit
  449. #               xptr ^= yptr for count words
  450. #               a1 - a4, ip destroyed
  451.         EXPORT  |xor_loop_up|           # word aligned xor loop up
  452. |xor_loop_up|
  453.         ANDS    a4,a3,#3                # multiple of 4 words ?
  454.         BEQ     |xor_loop_up_l1|        # yup, so branch
  455.         CMP     a4,#2                   # XOR the first 1-3 words
  456.         LDR     a4,[a2],#4              # to align the total to a multiple
  457.         LDR     ip,[a1]                 # of 4 words
  458.         EOR     ip,ip,a4
  459.         STR     ip,[a1],#4
  460.         BLT     |xor_loop_up_l1|        # better to branch than skip instrs.
  461.         LDRGE   a4,[a2],#4
  462.         LDRGE   ip,[a1]
  463.         EORGE   ip,ip,a4
  464.         STRGE   ip,[a1],#4
  465.         LDRGT   a4,[a2],#4
  466.         LDRGT   ip,[a1]
  467.         EORGT   ip,ip,a4
  468.         STRGT   ip,[a1],#4
  469. |xor_loop_up_l1|
  470.         BICS    a4,a3,#3                # set counter to multiple of 4
  471.         MOVEQS  pc,lr                   # if zero then we're done
  472.         STMFD   sp!,{v1-v5,lr}          # save work regs
  473. |xor_loop_up_l2|
  474.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  475.         LDMIA   a1,{v3,v4,v5,lr}        # load target words
  476.         EOR     v3,v3,a3                # XOR the four words
  477.         EOR     v4,v4,v1
  478.         EOR     v5,v5,v2
  479.         EOR     lr,lr,ip
  480.         STMIA   a1!,{v3,v4,v5,lr}       # store 4 results
  481.         SUBS    a4,a4,#4                # decrement counter by 4
  482.         BGT     |xor_loop_up_l2|        # if count still positive then loop
  483.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  484.  
  485. # extern void and_loop_up (uintD* xptr, uintD* yptr, uintC count);
  486. #       entry
  487. #               a1 = xptr
  488. #               a2 = yptr
  489. #               a3 = count of words to be ANDed
  490. #       exit
  491. #               xptr &= yptr for count words
  492. #               a1 - a4, ip destroyed
  493.         EXPORT  |and_loop_up|           # word aligned and loop up
  494. |and_loop_up|
  495.         ANDS    a4,a3,#3                # multiple of 4 words ?
  496.         BEQ     |and_loop_up_l1|        # yup, so branch
  497.         CMP     a4,#2                   # AND the first 1-3 words
  498.         LDR     a4,[a2],#4              # to align the total to a multiple
  499.         LDR     ip,[a1]                 # of 4 words
  500.         AND     ip,ip,a4
  501.         STR     ip,[a1],#4
  502.         BLT     |and_loop_up_l1|        # better to branch than skip instrs.
  503.         LDRGE   a4,[a2],#4
  504.         LDRGE   ip,[a1]
  505.         ANDGE   ip,ip,a4
  506.         STRGE   ip,[a1],#4
  507.         LDRGT   a4,[a2],#4
  508.         LDRGT   ip,[a1]
  509.         ANDGT   ip,ip,a4
  510.         STRGT   ip,[a1],#4
  511. |and_loop_up_l1|
  512.         BICS    a4,a3,#3                # set counter to multiple of 4
  513.         MOVEQS  pc,lr                   # if zero then we're done
  514.         STMFD   sp!,{v1-v5,lr}          # save work regs
  515. |and_loop_up_l2|
  516.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  517.         LDMIA   a1,{v3,v4,v5,lr}        # load target words
  518.         AND     v3,v3,a3                # AND the four words
  519.         AND     v4,v4,v1
  520.         AND     v5,v5,v2
  521.         AND     lr,lr,ip
  522.         STMIA   a1!,{v3,v4,v5,lr}       # store 4 results
  523.         SUBS    a4,a4,#4                # decrement counter by 4
  524.         BGT     |and_loop_up_l2|        # if count still positive then loop
  525.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  526.  
  527. # extern void eqv_loop_up (uintD* xptr, uintD* yptr, uintC count);
  528. #       entry
  529. #               a1 = xptr
  530. #               a2 = yptr
  531. #               a3 = count of words to be XORed
  532. #       exit
  533. #               xptr = ~(xptr ^ yptr) for count words
  534. #               a1 - a4, ip destroyed
  535.         EXPORT  |eqv_loop_up|           # word aligned eqv loop up
  536. |eqv_loop_up|
  537.         ANDS    a4,a3,#3                # multiple of 4 words ?
  538.         BEQ     |eqv_loop_up_l1|        # yup, so branch
  539.         CMP     a4,#2                   # EQV the first 1-3 words
  540.         LDR     a4,[a2],#4              # to align the total to a multiple
  541.         LDR     ip,[a1]                 # of 4 words
  542.         EOR     ip,ip,a4
  543.         MVN     ip,ip
  544.         STR     ip,[a1],#4
  545.         BLT     |eqv_loop_up_l1|        # better to branch than skip instrs.
  546.         LDRGE   a4,[a2],#4
  547.         LDRGE   ip,[a1]
  548.         EORGE   ip,ip,a4
  549.         MVNGE   ip,ip
  550.         STRGE   ip,[a1],#4
  551.         BLE     |eqv_loop_up_l1|        # better to branch than skip instrs.
  552.         LDRGT   a4,[a2],#4
  553.         LDRGT   ip,[a1]
  554.         EORGT   ip,ip,a4
  555.         MVNGT   ip,ip
  556.         STRGT   ip,[a1],#4
  557. |eqv_loop_up_l1|
  558.         BICS    a4,a3,#3                # set counter to multiple of 4
  559.         MOVEQS  pc,lr                   # if zero then we're done
  560.         STMFD   sp!,{v1-v5,lr}          # save work regs
  561. |eqv_loop_up_l2|
  562.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  563.         LDMIA   a1,{v3,v4,v5,lr}        # load target words
  564.         EOR     v3,v3,a3                # EVQ the four words
  565.         MVN     v3,v3
  566.         EOR     v4,v4,v1
  567.         MVN     v4,v4
  568.         EOR     v5,v5,v2
  569.         MVN     v5,v5
  570.         EOR     lr,lr,ip
  571.         MVN     lr,lr
  572.         STMIA   a1!,{v3,v4,v5,lr}       # store 4 results
  573.         SUBS    a4,a4,#4                # decrement counter by 4
  574.         BGT     |eqv_loop_up_l2|        # if count still positive then loop
  575.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  576.  
  577. # extern void nand_loop_up (uintD* xptr, uintD* yptr, uintC count);
  578. #       entry
  579. #               a1 = xptr
  580. #               a2 = yptr
  581. #               a3 = count of words to be NANDed
  582. #       exit
  583. #               xptr = ~(xptr & yptr) for count words
  584. #               a1 - a4, ip destroyed
  585.         EXPORT  |nand_loop_up|          # word aligned nand loop up
  586. |nand_loop_up|
  587.         ANDS    a4,a3,#3                # multiple of 4 words ?
  588.         BEQ     |nand_loop_up_l1|       # yup, so branch
  589.         CMP     a4,#2                   # NAND the first 1-3 words
  590.         LDR     a4,[a2],#4              # to align the total to a multiple
  591.         LDR     ip,[a1]                 # of 4 words
  592.         AND     ip,ip,a4
  593.         MVN     ip,ip
  594.         STR     ip,[a1],#4
  595.         BLT     |nand_loop_up_l1|       # better to branch than skip instrs.
  596.         LDRGE   a4,[a2],#4
  597.         LDRGE   ip,[a1]
  598.         ANDGE   ip,ip,a4
  599.         MVNGE   ip,ip
  600.         STRGE   ip,[a1],#4
  601.         BLE     |nand_loop_up_l1|       # better to branch than skip instrs.
  602.         LDRGT   a4,[a2],#4
  603.         LDRGT   ip,[a1]
  604.         ANDGT   ip,ip,a4
  605.         MVNGT   ip,ip
  606.         STRGT   ip,[a1],#4
  607. |nand_loop_up_l1|
  608.         BICS    a4,a3,#3                # set counter to multiple of 4
  609.         MOVEQS  pc,lr                   # if zero then we're done
  610.         STMFD   sp!,{v1-v5,lr}          # save work regs
  611. |nand_loop_up_l2|
  612.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  613.         LDMIA   a1,{v3,v4,v5,lr}        # load target words
  614.         AND     v3,v3,a3                # NAND the four words
  615.         MVN     v3,v3
  616.         AND     v4,v4,v1
  617.         MVN     v4,v4
  618.         AND     v5,v5,v2
  619.         MVN     v5,v5
  620.         AND     lr,lr,ip
  621.         MVN     lr,lr
  622.         STMIA   a1!,{v3,v4,v5,lr}       # store 4 results
  623.         SUBS    a4,a4,#4                # decrement counter by 4
  624.         BGT     |nand_loop_up_l2|       # if count still positive then loop
  625.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  626.  
  627. # extern void nor_loop_up (uintD* xptr, uintD* yptr, uintC count);
  628. #       entry
  629. #               a1 = xptr
  630. #               a2 = yptr
  631. #               a3 = count of words to be NORed
  632. #       exit
  633. #               xptr = ~(xptr | yptr) for count words
  634. #               a1 - a4, ip destroyed
  635.         EXPORT  |nor_loop_up|           # word aligned nor loop up
  636. |nor_loop_up|
  637.         ANDS    a4,a3,#3                # multiple of 4 words ?
  638.         BEQ     |nor_loop_up_l1|        # yup, so branch
  639.         CMP     a4,#2                   # NOR the first 1-3 words
  640.         LDR     a4,[a2],#4              # to align the total to a multiple
  641.         LDR     ip,[a1]                 # of 4 words
  642.         ORR     ip,ip,a4
  643.         MVN     ip,ip
  644.         STR     ip,[a1],#4
  645.         BLT     |nor_loop_up_l1|        # better to branch than skip instrs.
  646.         LDRGE   a4,[a2],#4
  647.         LDRGE   ip,[a1]
  648.         ORRGE   ip,ip,a4
  649.         MVNGE   ip,ip
  650.         STRGE   ip,[a1],#4
  651.         BLE     |nor_loop_up_l1|        # better to branch than skip instrs.
  652.         LDRGT   a4,[a2],#4
  653.         LDRGT   ip,[a1]
  654.         ORRGT   ip,ip,a4
  655.         MVNGT   ip,ip
  656.         STRGT   ip,[a1],#4
  657. |nor_loop_up_l1|
  658.         BICS    a4,a3,#3                # set counter to multiple of 4
  659.         MOVEQS  pc,lr                   # if zero then we're done
  660.         STMFD   sp!,{v1-v5,lr}          # save work regs
  661. |nor_loop_up_l2|
  662.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  663.         LDMIA   a1,{v3,v4,v5,lr}        # load target words
  664.         ORR     v3,v3,a3                # NOR the four words
  665.         MVN     v3,v3
  666.         ORR     v4,v4,v1
  667.         MVN     v4,v4
  668.         ORR     v5,v5,v2
  669.         MVN     v5,v5
  670.         ORR     lr,lr,ip
  671.         MVN     lr,lr
  672.         STMIA   a1!,{v3,v4,v5,lr}       # store 4 results
  673.         SUBS    a4,a4,#4                # decrement counter by 4
  674.         BGT     |nor_loop_up_l2|        # if count still positive then loop
  675.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  676.  
  677. # extern void andc2_loop_up (uintD* xptr, uintD* yptr, uintC count);
  678. #       entry
  679. #               a1 = xptr
  680. #               a2 = yptr
  681. #               a3 = count of words to be ANDC2ed
  682. #       exit
  683. #               xptr = xptr & ~yptr for count words
  684. #               a1 - a4, ip destroyed
  685.         EXPORT  |andc2_loop_up|         # word aligned andc2 loop up
  686. |andc2_loop_up|
  687.         ANDS    a4,a3,#3                # multiple of 4 words ?
  688.         BEQ     |andc2_loop_up_l1|      # yup, so branch
  689.         CMP     a4,#2                   # ANDC2 the first 1-3 words
  690.         LDR     a4,[a2],#4              # to align the total to a multiple
  691.         LDR     ip,[a1]                 # of 4 words
  692.         BIC     ip,ip,a4
  693.         STR     ip,[a1],#4
  694.         BLT     |andc2_loop_up_l1|      # better to branch than skip instrs.
  695.         LDRGE   a4,[a2],#4
  696.         LDRGE   ip,[a1]
  697.         BICGE   ip,ip,a4
  698.         STRGE   ip,[a1],#4
  699.         LDRGT   a4,[a2],#4
  700.         LDRGT   ip,[a1]
  701.         BICGT   ip,ip,a4
  702.         STRGT   ip,[a1],#4
  703. |andc2_loop_up_l1|
  704.         BICS    a4,a3,#3                # set counter to multiple of 4
  705.         MOVEQS  pc,lr                   # if zero then we're done
  706.         STMFD   sp!,{v1-v5,lr}          # save work regs
  707. |andc2_loop_up_l2|
  708.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  709.         LDMIA   a1,{v3,v4,v5,lr}        # load target words
  710.         BIC     v3,v3,a3                # ANDC2 the four words
  711.         BIC     v4,v4,v1
  712.         BIC     v5,v5,v2
  713.         BIC     lr,lr,ip
  714.         STMIA   a1!,{v3,v4,v5,lr}       # store 4 results
  715.         SUBS    a4,a4,#4                # decrement counter by 4
  716.         BGT     |andc2_loop_up_l2|      # if count still positive then loop
  717.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  718.  
  719. # extern void orc2_loop_up (uintD* xptr, uintD* yptr, uintC count);
  720. #       entry
  721. #               a1 = xptr
  722. #               a2 = yptr
  723. #               a3 = count of words to be XORed
  724. #       exit
  725. #               xptr = xptr | ~yptr for count words
  726. #               a1 - a4, ip destroyed
  727.         EXPORT  |orc2_loop_up|          # word aligned orc2 loop up
  728. |orc2_loop_up|
  729.         ANDS    a4,a3,#3                # multiple of 4 words ?
  730.         BEQ     |orc2_loop_up_l1|       # yup, so branch
  731.         CMP     a4,#2                   # ORC2 the first 1-3 words
  732.         LDR     a4,[a2],#4              # to align the total to a multiple
  733.         LDR     ip,[a1]                 # of 4 words
  734.         MVN     a4,a4
  735.         ORR     ip,ip,a4
  736.         STR     ip,[a1],#4
  737.         BLT     |orc2_loop_up_l1|       # better to branch than skip instrs.
  738.         LDRGE   a4,[a2],#4
  739.         LDRGE   ip,[a1]
  740.         MVNGE   a4,a4
  741.         ORRGE   ip,ip,a4
  742.         STRGE   ip,[a1],#4
  743.         BLE     |orc2_loop_up_l1|       # better to branch than skip instrs.
  744.         LDRGT   a4,[a2],#4
  745.         LDRGT   ip,[a1]
  746.         MVNGT   a4,a4
  747.         ORRGT   ip,ip,a4
  748.         STRGT   ip,[a1],#4
  749. |orc2_loop_up_l1|
  750.         BICS    a4,a3,#3                # set counter to multiple of 4
  751.         MOVEQS  pc,lr                   # if zero then we're done
  752.         STMFD   sp!,{v1-v5,lr}          # save work regs
  753. |orc2_loop_up_l2|
  754.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  755.         LDMIA   a1,{v3,v4,v5,lr}        # load target words
  756.         MVN     a3,a3                   # ORC2 the four words
  757.         ORR     v3,v3,a3
  758.         MVN     v1,v1
  759.         ORR     v4,v4,v1
  760.         MVN     v2,v2
  761.         ORR     v5,v5,v2
  762.         MVN     ip,ip
  763.         ORR     lr,lr,ip
  764.         STMIA   a1!,{v3,v4,v5,lr}       # store 4 results
  765.         SUBS    a4,a4,#4                # decrement counter by 4
  766.         BGT     |orc2_loop_up_l2|       # if count still positive then loop
  767.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  768.  
  769. # extern void not_loop_up (uintD* xptr, uintC count);
  770. #       entry
  771. #               a1 = xptr
  772. #               a2 = count of words to be NOTed
  773. #       exit
  774. #               xptr = ~xptr for count words
  775. #               a1 - a4, ip destroyed
  776.         EXPORT  |not_loop_up|           # word aligned not loop up
  777. |not_loop_up|
  778.         ANDS    a3,a2,#3                # multiple of 4 words ?
  779.         BEQ     |not_loop_up_l1|        # yup, so branch
  780.         CMP     a3,#2                   # NOT the first 1-3 words
  781.         LDR     a3,[a1]                 # to align the total to a multiple
  782.         MVN     a3,a3                   # of 4 words
  783.         STR     a3,[a1],#4
  784.         BLT     |not_loop_up_l1|        # better to branch than skip instrs.
  785.         LDRGE   a3,[a1]
  786.         MVNGE   a3,a3
  787.         STRGE   a3,[a1],#4
  788.         LDRGT   a3,[a1]
  789.         MVNGT   a3,a3
  790.         STRGT   a3,[a1],#4
  791. |not_loop_up_l1|
  792.         BICS    a4,a2,#3                # set counter to multiple of 4
  793.         MOVEQS  pc,lr                   # if zero then we're done
  794.         STMFD   sp!,{lr}                # save work regs
  795. |not_loop_up_l2|
  796.         LDMIA   a1,{a2,a3,ip,lr}        # load 4 words in one go,NO writeback
  797.         MVN     a2,a2                   # NOT the four words
  798.         MVN     a3,a3
  799.         MVN     ip,ip
  800.         MVN     lr,lr
  801.         STMIA   a1!,{a2,a3,ip,lr}       # store 4 results
  802.         SUBS    a4,a4,#4                # decrement counter by 4
  803.         BGT     |not_loop_up_l2|        # if count still positive then loop
  804.         LDMFD   sp!,{pc}^               # restore work regs and return
  805.  
  806. # extern void and_test_loop_up (uintD* xptr, uintD* yptr, uintC count);
  807. #       entry
  808. #               a1 = xptr
  809. #               a2 = yptr
  810. #               a3 = count of words to be AND_TESTed
  811. #       exit
  812. #               a1 = TRUE if any words ANDed together are non-zero else FALSE
  813. #               a2 - a4, ip destroyed
  814.         EXPORT  |and_test_loop_up|      # word aligned and_test loop up
  815. |and_test_loop_up|
  816.         ANDS    a4,a3,#3                # multiple of 4 words ?
  817.         BEQ     |and_test_loop_up_l1|   # yup, so branch
  818.         CMP     a4,#2
  819.         LDR     a4,[a2],#4              # AND_TEST the first 1-3 words
  820.         LDR     ip,[a1],#4              # to align the total to a multiple
  821.         TST     ip,a4                   # of 4 words
  822.         MOVNE   a1,#1                   # return TRUE if AND_TEST ok
  823.         MOVNES  pc,lr
  824.         BCC     |and_test_loop_up_l1|   # better to branch than skip instrs.
  825.         LDRGE   a4,[a2],#4
  826.         LDRGE   ip,[a1],#4
  827.         TSTGE   ip,a4
  828.         MOVNE   a1,#1
  829.         MOVNES  pc,lr
  830.         ANDS    a4,a3,#3
  831.         CMP     a4,#2
  832.         BLE     |and_test_loop_up_l1|   # better to branch than skip instrs.
  833.         LDRGT   a4,[a2],#4
  834.         LDRGT   ip,[a1],#4
  835.         TSTGT   ip,a4
  836.         MOVNE   a1,#1
  837.         MOVNES  pc,lr
  838. |and_test_loop_up_l1|
  839.         BICS    a4,a3,#3                # set counter to multiple of 4
  840.         MOVEQ   a1,#0                   # return FALSE
  841.         MOVEQS  pc,lr                   # if zero then we're done
  842.         STMFD   sp!,{v1-v5,lr}          # save work regs
  843.         MOV     v6,a1                   # move xptr to v6
  844.         MOV     a1,#1                   # set result to TRUE
  845. |and_test_loop_up_l2|
  846.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  847.         LDMIA   v6!,{v3,v4,v5,lr}       # load target words
  848.         TST     v3,a3                   # AND_TEST the four words
  849.         TSTEQ   v4,v1
  850.         TSTEQ   v5,v2
  851.         TSTEQ   lr,ip
  852.         LDMNEFD sp!,{v1-v6,pc}^
  853.         SUBS    a4,a4,#4                # decrement counter by 4
  854.         BGT     |and_test_loop_up_l2|   # if count still positive then loop
  855.         MOV     a1,#0
  856.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  857.  
  858. # extern void test_loop_up (uintD* xptr, uintC count);
  859. #       entry
  860. #               a1 = xptr
  861. #               a2 = count of words to be TESTed
  862. #       exit
  863. #               a1 = TRUE if any words are non-zero else FALSE
  864. #               a2 - a4, ip destroyed
  865.         EXPORT  |test_loop_up|          # word aligned test loop up
  866. |test_loop_up|
  867.         MOV     ip,a1                   # move xptr to ip
  868.         MOV     a1,#1                   # set result to TRUE
  869.         ANDS    a3,a2,#3                # multiple of 4 words ?
  870.         BEQ     |test_loop_up_l1|       # yup, so branch
  871.         LDR     a4,[ip],#4              # TEST the first 1-3 words
  872.         TEQ     a4,#0                   # align the total to a multiple of 4
  873.         MOVNES  pc,lr                   # return TRUE if AND_TEST ok
  874.         CMP     a3,#2
  875.         BLT     |test_loop_up_l1|       # need to branch 'cos PSR set
  876.         LDRGE   a4,[ip],#4              # when checking against zero
  877.         TEQGE   a4,#0
  878.         MOVNES  pc,lr
  879.         CMP     a3,#2
  880.         BLE     |test_loop_up_l1|       # need to branch 'cos PSR set
  881.         LDRGT   a4,[ip],#4              # when checking against zero
  882.         TEQGT   a4,#0
  883.         MOVNES  pc,lr
  884. |test_loop_up_l1|
  885.         BICS    a4,a2,#3                # set counter to multiple of 4
  886.         MOVEQ   a1,#0                   # return FALSE
  887.         MOVEQS  pc,lr                   # if zero then we're done
  888.         STMFD   sp!,{v1,lr}             # save work regs
  889. |test_loop_up_l2|
  890.         LDMIA   ip!,{a2,a3,v1,lr}       # load 4 words in one go
  891.         TEQ     a2,#0                   # TEST the four words
  892.         TEQEQ   a3,#0
  893.         TEQEQ   v1,#0
  894.         TEQEQ   lr,#0
  895.         LDMNEFD sp!,{v1,pc}^
  896.         SUBS    a4,a4,#4                # decrement counter by 4
  897.         BGT     |test_loop_up_l2|       # if count still positive then loop
  898.         MOV     a1,#0
  899.         LDMFD   sp!,{v1,pc}^            # restore work regs and return
  900.  
  901. # extern void compare_loop_up (uintD* xptr, uintD* yptr, uintC count);
  902. #       entry
  903. #               a1 = xptr
  904. #               a2 = yptr
  905. #               a3 = count of words to be COMPAREd
  906. #       exit
  907. #               a1 = +1 if first non-equal word in xptr[] and yptr[]
  908. #                       xptr[i] > yptr[i]
  909. #                    -1 if xptr[i] < yptr[i]
  910. #                     0 otherwise
  911. #               a2 - a4, ip destroyed
  912.         EXPORT  |compare_loop_up|       # word aligned compare loop up
  913. |compare_loop_up|
  914.         ANDS    a4,a3,#3                # multiple of 4 words ?
  915.         BEQ     |compare_loop_up_l1|    # yup, so branch
  916.         LDR     a4,[a2],#4              # COMPARE the first 1-3 words
  917.         LDR     ip,[a1],#4              # to align the total to a multiple
  918.         CMP     ip,a4                   # of 4 words
  919.         MVNLO   a1,#0                   # x < y -> -1
  920.         MOVHI   a1,#1                   # x > y -> +1
  921.         MOVNES  pc,lr                   # and return result if not equal
  922.         ANDS    a4,a3,#3
  923.         CMP     a4,#2
  924.         BLT     |compare_loop_up_l1|    # need to branch 'cos PSR used
  925.         LDR     a4,[a2],#4
  926.         LDR     ip,[a1],#4
  927.         CMP     ip,a4
  928.         MVNLO   a1,#0
  929.         MOVHI   a1,#1
  930.         MOVNES  pc,lr
  931.         ANDS    a4,a3,#3
  932.         CMP     a4,#2
  933.         BLE     |compare_loop_up_l1|    # need to branch 'cos PSR used
  934.         LDR     a4,[a2],#4
  935.         LDR     ip,[a1],#4
  936.         CMP     ip,a4
  937.         MVNLO   a1,#0
  938.         MOVHI   a1,#1
  939.         MOVNES  pc,lr
  940. |compare_loop_up_l1|
  941.         BICS    a4,a3,#3                # set counter to multiple of 4
  942.         MOVEQ   a1,#0                   # xptr[] == yptr[] -> 0
  943.         MOVEQS  pc,lr                   # if zero then we're done
  944.         STMFD   sp!,{v1-v6,lr}          # save work regs
  945.         MOV     v6,a1                   # move xptr to v6
  946.         MOV     a1,#1                   # set result to +1
  947. |compare_loop_up_l2|
  948.         LDMIA   a2!,{a3,v1,v2,ip}       # load 4 words in one go
  949.         LDMIA   v6!,{v3,v4,v5,lr}       # load test words
  950.         CMP     v3,a3                   # COMPARE the four words
  951.         CMPEQ   v4,v1
  952.         CMPEQ   v5,v2
  953.         CMPEQ   lr,ip
  954.         MVNLO   a1,#0                   # x < y -> -1 (a1 already holds +1)
  955.         LDMNEFD sp!,{v1-v6,pc}^
  956.         SUBS    a4,a4,#4                # decrement counter by 4
  957.         BGT     |compare_loop_up_l2|    # if count still positive then loop
  958.         MOV     a1,#0
  959.         LDMFD   sp!,{v1-v6,pc}^         # restore work regs and return
  960.  
  961. # extern uintD addto_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
  962. #       entry
  963. #               a1 = sourceptr
  964. #               a2 = destptr
  965. #               a3 = count of words to be added
  966. #       exit
  967. #               destptr[] = sourceptr[] + destptr[]
  968. #               a1 = last carry
  969. #               a2 - a4, ip destroyed
  970.         EXPORT  |addto_loop_down|       # word aligned addto loop down
  971. |addto_loop_down|
  972.                 MOV     a4,a3           # set regs for a call
  973.                 MOV     a3,a2           # to add_loop_down
  974.                                         # and drop into add_loop_down
  975.  
  976. # extern uintD add_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count);
  977. #       entry
  978. #               a1 = sourceptr1
  979. #               a2 = sourceptr2
  980. #               a3 = destptr
  981. #               a4 = count of words to be added
  982. #       exit
  983. #               destptr[] = sourceptr1[] + sourceptr2[]
  984. #               a1 = last carry
  985. #               a2 - a4, ip destroyed
  986.         EXPORT  |add_loop_down|         # word aligned add loop down
  987. |add_loop_down|
  988.         ANDS    ip,a4,#3                # multiple of 4 words ?
  989.         BEQ     |add_loop_down_l1|      # yup, so branch
  990.         STMFD   sp!,{v6,lr}
  991.         LDR     v6,[a2,#-4]!            # add the first 1-3 words
  992.         LDR     lr,[a1,#-4]!            # to align the total to a multiple
  993.         ADDS    lr,lr,v6                # of 4 words
  994.         STR     lr,[a3,#-4]!
  995.         TEQ     ip,#1
  996.         BEQ     |add_loop_down_l0|      # need to branch 'cos PSR used
  997.         LDR     v6,[a2,#-4]!
  998.         LDR     lr,[a1,#-4]!
  999.         ADCS    lr,lr,v6
  1000.         STR     lr,[a3,#-4]!
  1001.         TEQ     ip,#2
  1002.         BEQ     |add_loop_down_l0|      # need to branch 'cos PSR used
  1003.         LDR     v6,[a2,#-4]!
  1004.         LDR     lr,[a1,#-4]!
  1005.         ADCS    lr,lr,v6
  1006.         STR     lr,[a3,#-4]!
  1007. |add_loop_down_l0|                      # at least one add has happened
  1008.         BICS    a4,a4,#3                # set counter to multiple of 4
  1009.         BNE     |add_loop_down_l3|      # branch if more adds to do
  1010.         ADCEQ   a1,a4,a4                # set result to Carry (a4 is 0)
  1011.         LDMEQFD sp!,{v6,pc}^            # and return
  1012. |add_loop_down_l1|
  1013.         BICS    a4,a4,#3                # set counter to multiple of 4
  1014.         MOVEQ   a1,#0                   # no adds, so C = 0
  1015.         MOVEQS  pc,lr                   # if zero then we're done
  1016.         CMN     a4,#0                   # clear carry bit
  1017.         STMFD   sp!,{v6,lr}
  1018. |add_loop_down_l3|
  1019.         STMFD   sp!,{v1-v5}             # save work regs
  1020. |add_loop_down_l2|
  1021.         LDMDB   a2!,{v1,v2,v3,ip}       # load 4 words in one go
  1022.         LDMDB   a1!,{v4,v5,v6,lr}       # and from source2
  1023.         ADCS    lr,lr,ip                # add the four words with carry
  1024.         ADCS    v6,v6,v3
  1025.         ADCS    v5,v5,v2
  1026.         ADCS    v4,v4,v1
  1027.         STMDB   a3!,{v4,v5,v6,lr}       # store 4 results
  1028.         SUB     a4,a4,#4                # decrement counter by 4, preserve C
  1029.         TEQ     a4,#0                   # are we done ?
  1030.         BNE     |add_loop_down_l2|      # if count non-zero then loop
  1031.         ADC     a1,a4,a4                # set result to Carry (a4 is 0)
  1032.         LDMFD   sp!,{v1-v6,pc}^         # restore work regs and return
  1033.  
  1034. # extern uintD inc_loop_down (uintD* ptr, uintC count);
  1035. #       entry
  1036. #               a1 = ptr
  1037. #               a2 = count of words to be INCed
  1038. #       exit
  1039. #               a1 = 0 if any words are non-zero after increment else 1
  1040. #                      stop incrementing when first word becomes non-zero
  1041. #               a2 - a4, ip destroyed
  1042.         EXPORT  |inc_loop_down|         # word aligned inc loop down
  1043. |inc_loop_down|
  1044.         ANDS    a3,a2,#1                # multiple of 2 words ?
  1045.         BEQ     |inc_loop_down_l1|      # yup, so branch
  1046.         LDR     a4,[a1,#-4]!            # INC the first word
  1047.         ADDS    a4,a4,#1                # align the total to a multiple of 2
  1048.         STR     a4,[a1]
  1049.         MOVNE   a1,#0                   # set result to 0
  1050.         MOVNES  pc,lr                   # return 0 if non-zero result
  1051. |inc_loop_down_l1|
  1052.         BICS    a4,a2,#1                # set counter to multiple of 2
  1053.         MOVEQ   a1,#1                   # return 1
  1054.         MOVEQS  pc,lr                   # if zero then we're done
  1055.         MOV     ip,a1                   # move ptr to ip
  1056.         MOV     a1,#0                   # set result to 0
  1057.         ANDS    a3,a4,#3
  1058.         BEQ     |inc_loop_down_l3|
  1059.         LDMDB   ip,{a2,a3}              # load 2 words in one go
  1060.         ADDS    a3,a3,#1                # INC the two words
  1061.         ADDEQS  a2,a2,#1                # stopping when first word non-zero
  1062.         STMDB   ip!,{a2,a3}             # store 2 results
  1063.         MOVNES  pc,lr                   # return 0 if any result non-zero
  1064.         SUBS    a4,a4,#2                # decrement counter by 2
  1065.         MOVEQ   a1,#1                   # if finished loop then
  1066.         MOVEQS  pc,lr                   # return 1
  1067. |inc_loop_down_l3|                      # now a multiple of 4 words
  1068.         STMFD   sp!,{v1,lr}             # save work regs
  1069. |inc_loop_down_l2|
  1070.         LDMDB   ip,{a2,a3,v1,lr}        # load 4 words in one go
  1071.         ADDS    lr,lr,#1                # INC the four words
  1072.         ADDEQS  v1,v1,#1                # stopping when first word non-zero
  1073.         ADDEQS  a3,a3,#1
  1074.         ADDEQS  a2,a2,#1
  1075.         STMDB   ip!,{a2,a3,v1,lr}       # store 4 results
  1076.         LDMNEFD sp!,{v1,pc}^            # return 0 if any result non-zero
  1077.         SUBS    a4,a4,#4                # decrement counter by 4
  1078.         BGT     |inc_loop_down_l2|      # if count still positive then loop
  1079.         MOV     a1,#1
  1080.         LDMFD   sp!,{v1,pc}^            # restore work regs and return 1
  1081.  
  1082. # extern uintD sub_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count);
  1083. #       entry
  1084. #               a1 = sourceptr1
  1085. #               a2 = sourceptr2
  1086. #               a3 = destptr
  1087. #               a4 = count of words to be subtracted
  1088. #       exit
  1089. #               destptr[] = sourceptr1[] -  sourceptr2[]
  1090. #               a1 = last carry
  1091. #               a2 - a4, ip destroyed
  1092.         EXPORT  |sub_loop_down|         # word aligned sub loop down
  1093. |sub_loop_down|
  1094.         ANDS    ip,a4,#3                # multiple of 4 words ?
  1095.         BEQ     |sub_loop_down_l1|      # yup, so branch
  1096.         STMFD   sp!,{v6,lr}
  1097.         LDR     v6,[a2,#-4]!            # subtract the first 1-3 words
  1098.         LDR     lr,[a1,#-4]!            # to align the total to a multiple
  1099.         SUBS    lr,lr,v6                # of 4 words
  1100.         STR     lr,[a3,#-4]!
  1101.         TEQ     ip,#1
  1102.         BNE     |sub_loop_down_l0|      # branch if more than one subtract
  1103. |sub_loop_down_l4|                      # drop through for better instr. timings
  1104.         BICS    a4,a4,#3                # set counter to multiple of 4
  1105.         SBCEQ   a1,a4,a4                # set result to Carry (a4 is 0)
  1106.         LDMEQFD sp!,{v6,pc}^            # and return
  1107.         STMFD   sp!,{v1-v5}             # save work regs
  1108.         B       |sub_loop_down_l2|      # branch if more subtracts to do
  1109. |sub_loop_down_l0|
  1110.         LDR     v6,[a2,#-4]!
  1111.         LDR     lr,[a1,#-4]!
  1112.         SBCS    lr,lr,v6
  1113.         STR     lr,[a3,#-4]!
  1114.         TEQ     ip,#2
  1115.         BEQ     |sub_loop_down_l4|      # need to branch 'cos PSR used
  1116.         LDR     v6,[a2,#-4]!
  1117.         LDR     lr,[a1,#-4]!
  1118.         SBCS    lr,lr,v6
  1119.         STR     lr,[a3,#-4]!
  1120.         B       |sub_loop_down_l4|
  1121. |sub_loop_down_l1|
  1122.         BICS    a4,a4,#3                # set counter to multiple of 4
  1123.         MOVEQ   a1,#0                   # no subtracts, so C = 0
  1124.         MOVEQS  pc,lr                   # if zero then we're done
  1125.         CMP     a4,#0                   # set carry bit, since a4 > 0
  1126.         STMFD   sp!,{v1-v6,lr}          # save work regs
  1127. |sub_loop_down_l2|
  1128.         LDMDB   a2!,{v1,v2,v3,ip}       # load 4 words in one go
  1129.         LDMDB   a1!,{v4,v5,v6,lr}       # and from source2
  1130.         SBCS    lr,lr,ip                # subtract the four words with carry
  1131.         SBCS    v6,v6,v3
  1132.         SBCS    v5,v5,v2
  1133.         SBCS    v4,v4,v1
  1134.         STMDB   a3!,{v4,v5,v6,lr}       # store 4 results
  1135.         SUB     a4,a4,#4                # decrement counter by 4, preserve C
  1136.         TEQ     a4,#0                   # are we done ?
  1137.         BNE     |sub_loop_down_l2|      # if count non-zero then loop
  1138.         SBC     a1,a4,a4                # set result to Carry (a4 is 0)
  1139.         LDMFD   sp!,{v1-v6,pc}^         # restore work regs and return
  1140.  
  1141. # extern uintD subx_loop_down (uintD* sourceptr1, uintD* sourceptr2, uintD* destptr, uintC count, uintD carry);
  1142. #       entry
  1143. #               a1 = sourceptr1
  1144. #               a2 = sourceptr2
  1145. #               a3 = destptr
  1146. #               a4 = count of words to be subtracted
  1147. #               [sp] = carry
  1148. #       exit
  1149. #               destptr[] = sourceptr1[] -  sourceptr2[]
  1150. #               a1 = last carry
  1151. #               a2 - a4, ip destroyed
  1152.         EXPORT  |subx_loop_down|        # word aligned xsub loop down
  1153. |subx_loop_down|
  1154.         LDR     ip,[sp]                 # get starting value of carry
  1155. |subx_loop_down_lsub|
  1156.         RSBS    ip,ip,#0                # set carry in PSR
  1157.         ANDS    ip,a4,#3                # multiple of 4 words ?
  1158.         BEQ     |subx_loop_down_l1|     # yup, so branch
  1159.         STMFD   sp!,{v6,lr}
  1160.         LDR     v6,[a2,#-4]!            # subtract the first 1-3 words
  1161.         LDR     lr,[a1,#-4]!            # to align the total to a multiple
  1162.         SBCS    lr,lr,v6                # of 4 words
  1163.         STR     lr,[a3,#-4]!
  1164.         TEQ     ip,#1
  1165.         BNE     |subx_loop_down_l0|     # branch if more than one subtract
  1166. |subx_loop_down_l4|                     # drop through for better instr. timings
  1167.         BICS    a4,a4,#3                # set counter to multiple of 4
  1168.         SBCEQ   a1,a4,a4                # set result to Carry (a4 is 0)
  1169.         LDMEQFD sp!,{v6,pc}^            # and return
  1170.         STMFD   sp!,{v1-v5}             # save work regs
  1171.         B       |subx_loop_down_l2|     # branch if more subtracts to do
  1172. |subx_loop_down_l0|
  1173.         LDR     v6,[a2,#-4]!
  1174.         LDR     lr,[a1,#-4]!
  1175.         SBCS    lr,lr,v6
  1176.         STR     lr,[a3,#-4]!
  1177.         TEQ     ip,#2
  1178.         BEQ     |subx_loop_down_l4|     # need to branch 'cos PSR used
  1179.         LDR     v6,[a2,#-4]!
  1180.         LDR     lr,[a1,#-4]!
  1181.         SBCS    lr,lr,v6
  1182.         STR     lr,[a3,#-4]!
  1183.         B       |subx_loop_down_l4|
  1184. |subx_loop_down_l1|
  1185.         BICS    a4,a4,#3                # set counter to multiple of 4
  1186.         SBCEQ   a1,a4,a4                # set result to Carry (a4 is 0)
  1187.         MOVEQS  pc,lr                   # if zero then we're done
  1188.         STMFD   sp!,{v1-v6,lr}          # save work regs
  1189. |subx_loop_down_l2|
  1190.         LDMDB   a2!,{v1,v2,v3,ip}       # load 4 words in one go
  1191.         LDMDB   a1!,{v4,v5,v6,lr}       # and from source2
  1192.         SBCS    lr,lr,ip                # subtract the four words with carry
  1193.         SBCS    v6,v6,v3
  1194.         SBCS    v5,v5,v2
  1195.         SBCS    v4,v4,v1
  1196.         STMDB   a3!,{v4,v5,v6,lr}       # store 4 results
  1197.         SUB     a4,a4,#4                # decrement counter by 4, preserve C
  1198.         TEQ     a4,#0                   # are we done ?
  1199.         BNE     |subx_loop_down_l2|     # if count non-zero then loop
  1200.         SBC     a1,a4,a4                # set result to Carry (a4 is 0)
  1201.         LDMFD   sp!,{v1-v6,pc}^         # restore work regs and return
  1202.  
  1203. # extern uintD subfrom_loop_down (uintD* sourceptr, uintD* destptr, uintC count);
  1204. #       entry
  1205. #               a1 = sourceptr
  1206. #               a2 = destptr
  1207. #               a3 = count of words to be subtracted
  1208. #       exit
  1209. #               destptr[] = destptr[] - sourceptr[]
  1210. #               a1 = last carry
  1211. #               a2 - a4, ip destroyed
  1212.         EXPORT  |subfrom_loop_down|
  1213. |subfrom_loop_down|                     # word aligned subfrom loop down
  1214.         ANDS    ip,a3,#3                # multiple of 4 words ?
  1215.         BEQ     |subfrom_loop_down_l1|  # yup, so branch
  1216.         STMFD   sp!,{lr}
  1217.         LDR     a4,[a1,#-4]!            # subtract the first 1-3 words
  1218.         LDR     lr,[a2,#-4]!            # to align the total to a multiple
  1219.         SUBS    lr,lr,a4                # of 4 words
  1220.         STR     lr,[a2]
  1221.         TEQ     ip,#1
  1222.         BNE     |subfrom_loop_down_l0|  # branch if more than one subtract
  1223. |subfrom_loop_down_l4|                  # drop through for better instr. timings
  1224.         BICS    a4,a3,#3                # set counter to multiple of 4
  1225.         SBCEQ   a1,a4,a4                # set result to Carry (a4 is 0)
  1226.         LDMEQFD sp!,{pc}^               # and return
  1227.         STMFD   sp!,{v1-v5}             # save work regs
  1228.         B       |subfrom_loop_down_l2|  # branch if more subtracts to do
  1229. |subfrom_loop_down_l0|
  1230.         LDR     a4,[a1,#-4]!
  1231.         LDR     lr,[a2,#-4]!
  1232.         SBCS    lr,lr,a4
  1233.         STR     lr,[a2]
  1234.         TEQ     ip,#2
  1235.         BEQ     |subfrom_loop_down_l4|  # need to branch 'cos PSR used
  1236.         LDR     a4,[a1,#-4]!
  1237.         LDR     lr,[a2,#-4]!
  1238.         SBCS    lr,lr,a4
  1239.         STR     lr,[a2]
  1240.         B       |subfrom_loop_down_l4|
  1241. |subfrom_loop_down_l1|
  1242.         BICS    a4,a3,#3                # set counter to multiple of 4
  1243.         MOVEQ   a1,#0                   # no subtracts, so C = 0
  1244.         MOVEQS  pc,lr                   # if zero then we're done
  1245.         CMP     a4,#0                   # set carry bit, since a4 > 0
  1246.         STMFD   sp!,{v1-v5,lr}          # save work regs
  1247. |subfrom_loop_down_l2|
  1248.         LDMDB   a1!,{a3,v1,v2,ip}       # load 4 words in one go
  1249.         LDMDB   a2,{v3,v4,v5,lr}        # and from destptr
  1250.         SBCS    lr,lr,ip                # subtract the four words with carry
  1251.         SBCS    v5,v5,v2
  1252.         SBCS    v4,v4,v1
  1253.         SBCS    v3,v3,a3
  1254.         STMDB   a2!,{v3,v4,v5,lr}       # store 4 results
  1255.         SUB     a4,a4,#4                # decrement counter by 4, preserve C
  1256.         TEQ     a4,#0                   # are we done ?
  1257.         BNE     |subfrom_loop_down_l2|  # if count non-zero then loop
  1258.         SBC     a1,a4,a4                # set result to Carry (a4 is 0)
  1259.         LDMFD   sp!,{v1-v5,pc}^         # restore work regs and return
  1260.  
  1261. # extern uintD dec_loop_down (uintD* ptr, uintC count);
  1262. #       entry
  1263. #               a1 = ptr
  1264. #               a2 = count of words to be DECed
  1265. #       exit
  1266. #               a1 = 0 if any words are non-zero before decrement else -1
  1267. #                      stop decrementing when first word is non-zero
  1268. #               a2 - a4, ip destroyed
  1269.         EXPORT  |dec_loop_down|
  1270. |dec_loop_down|                         # word aligned dec loop down
  1271.         ANDS    a3,a2,#1                # multiple of 2 words ?
  1272.         BEQ     |dec_loop_down_l1|      # yup, so branch
  1273.         LDR     a4,[a1,#-4]!            # DEC the first word
  1274.         SUBS    a4,a4,#1                # align the total to a multiple of 2
  1275.         STR     a4,[a1]
  1276.         MOVCS   a1,#0                   # set result to 0
  1277.         MOVCSS  pc,lr                   # return 0 if non-zero result
  1278. |dec_loop_down_l1|
  1279.         BICS    a4,a2,#1                # set counter to multiple of 2
  1280.         MVNEQ   a1,#0                   # return -1
  1281.         MOVEQS  pc,lr                   # if zero then we're done
  1282.         MOV     ip,a1                   # move ptr to ip
  1283.         MOV     a1,#0                   # set result to 0
  1284.         ANDS    a3,a4,#3
  1285.         BEQ     |dec_loop_down_l3|
  1286.         LDMDB   ip,{a2,a3}              # load 2 words in one go
  1287.         SUBS    a3,a3,#1                # DEC the two words
  1288.         SUBCCS  a2,a2,#1                # stopping when first word non-zero
  1289.         STMDB   ip!,{a2,a3}             # store 2 results
  1290.         MOVCSS  pc,lr                   # return 0 if any result non-zero
  1291.         SUBS    a4,a4,#2                # decrement counter by 2
  1292.         MVNEQ   a1,#0                   # if finished loop then
  1293.         MOVEQS  pc,lr                   # return -1
  1294. |dec_loop_down_l3|                      # now a multiple of 4 words
  1295.         STMFD   sp!,{v1,lr}             # save work regs
  1296. |dec_loop_down_l2|
  1297.         LDMDB   ip,{a2,a3,v1,lr}        # load 4 words in one go
  1298.         SUBS    lr,lr,#1                # DEC the four words
  1299.         SUBCCS  v1,v1,#1                # stopping when first word non-zero
  1300.         SUBCCS  a3,a3,#1
  1301.         SUBCCS  a2,a2,#1
  1302.         STMDB   ip!,{a2,a3,v1,lr}       # store 4 results
  1303.         LDMCSFD sp!,{v1,pc}^            # return 0 if any carry
  1304.         SUBS    a4,a4,#4                # decrement counter by 4
  1305.         BGT     |dec_loop_down_l2|      # if count still positive then loop
  1306.         MVN     a1,#0
  1307.         LDMFD   sp!,{v1,pc}^            # restore work regs and return -1
  1308.  
  1309. # extern void neg_loop_down (uintD* ptr, uintC count);
  1310. #       entry
  1311. #               a1 = ptr
  1312. #               a2 = count of words. The long integer is to be NEGated
  1313. #       exit
  1314. #               ptr[] = -ptr[] for count words
  1315. #               a1 = last carry
  1316. #               a2 - a4, ip destroyed
  1317.         EXPORT  |neg_loop_down|
  1318. |neg_loop_down|                         # word aligned neg loop down
  1319.         CMPS    a2,#0                   # count = 0 ?
  1320.         MOVEQ   a1,#0                   # yup, so return 0
  1321.         MOVEQS  pc,lr
  1322. |neg_loop_down_l1|                      # skip all the zero words first
  1323.         LDR     a3,[a1,#-4]!            # compare words against zero
  1324.         CMPS    a3,#0                   # downwards in memory
  1325.         BNE     |neg_loop_down_l2|      # non-zero, so negate rest of words
  1326.         SUBS    a2,a2,#1                # reduce count of words
  1327.         BNE     |neg_loop_down_l1|      # more ?, so loop
  1328.         MOV     a1,#0                   # return 0
  1329.         MOVS    pc,lr
  1330. |neg_loop_down_l2|
  1331.         RSB     a3,a3,#0                # first non-zero word = -word
  1332.         STR     a3,[a1]
  1333.         SUBS    a2,a2,#1
  1334.         MVNEQ   a1,#0                   # done ? -> return -1
  1335.         MOVEQS  pc,lr
  1336.                                         # now NOT rest of the words
  1337.         ANDS    a3,a2,#3                # multiple of 4 words ?
  1338.         BEQ     |neg_loop_down_l3|      # yup, so branch
  1339.         CMP     a3,#2                   # NOT the first 1-3 words
  1340.         LDR     a3,[a1,#-4]!            # to align the total to a multiple
  1341.         MVN     a3,a3                   # of 4 words
  1342.         STR     a3,[a1]
  1343.         BLT     |neg_loop_down_l3|      # better to branch than skip instrs.
  1344.         LDRGE   a3,[a1,#-4]!
  1345.         MVNGE   a3,a3
  1346.         STRGE   a3,[a1]
  1347.         LDRGT   a3,[a1,#-4]!
  1348.         MVNGT   a3,a3
  1349.         STRGT   a3,[a1]
  1350. |neg_loop_down_l3|
  1351.         BICS    a4,a2,#3                # set counter to multiple of 4
  1352.         MVNEQ   a1,#0                   # set result to -1
  1353.         MOVEQS  pc,lr                   # if zero then we're done
  1354.         STMFD   sp!,{lr}                # save work regs
  1355. |neg_loop_down_l4|
  1356.         LDMDB   a1,{a2,a3,ip,lr}        # load 4 words in one go,NO writeback
  1357.         MVN     a2,a2                   # NOT the four words
  1358.         MVN     a3,a3
  1359.         MVN     ip,ip
  1360.         MVN     lr,lr
  1361.         STMDB   a1!,{a2,a3,ip,lr}       # store 4 results
  1362.         SUBS    a4,a4,#4                # decrement counter by 4
  1363.         BGT     |neg_loop_down_l4|      # if count still positive then loop
  1364.         MVN     a1,#0                   # set result to -1
  1365.         LDMFD   sp!,{pc}^               # restore work regs and return -1
  1366.  
  1367. # extern uintD shift1left_loop_down (uintD* ptr, uintC count);
  1368. #       entry
  1369. #               a1 = ptr
  1370. #               a2 = count of words to be shifted left
  1371. #       exit
  1372. #               a1 = carry out from last shift left
  1373. #               a2 - a4, ip destroyed
  1374.         EXPORT  |shift1left_loop_down|
  1375. |shift1left_loop_down|                  # word aligned shift1left loop down
  1376.         CMN     a1,#0                   # clear carry bit, since a1 > 0
  1377.         ANDS    a3,a2,#1                # multiple of 2 words ?
  1378.         BEQ     |shift1left_loop_down_l1|       # yup, so branch
  1379.         LDR     a4,[a1,#-4]!            # shift left the first word
  1380.         ADDS    a4,a4,a4
  1381.         STR     a4,[a1]
  1382. |shift1left_loop_down_l1|
  1383.         BICS    a4,a2,#1                # set counter to multiple of 2
  1384.         ADCEQ   a1,a4,a4                # if zero set result to C (a4 is 0)
  1385.         MOVEQS  pc,lr                   # and return
  1386.         ANDS    a3,a4,#3                # multiple of 4 words ?
  1387.         BEQ     |shift1left_loop_down_l3|       # yup, so branch
  1388.         LDMDB   a1,{a2,a3}              # load 2 words in one go
  1389.         ADCS    a3,a3,a3                # shift left the two words
  1390.         ADCS    a2,a2,a2
  1391.         STMDB   a1!,{a2,a3}             # store 2 results
  1392.         BICS    a4,a4,#2                # decrement counter by 2
  1393.         ADCEQ   a1,a4,a4                # set result to Carry (a4 is 0)
  1394.         MOVEQS  pc,lr                   # and return
  1395. |shift1left_loop_down_l3|               # now a multiple of 4 words
  1396.         STMFD   sp!,{lr}                # save work regs
  1397. |shift1left_loop_down_l2|
  1398.         LDMDB   a1,{a2,a3,ip,lr}        # load 4 words in one go
  1399.         ADCS    lr,lr,lr                # shift left the four words
  1400.         ADCS    ip,ip,ip
  1401.         ADCS    a3,a3,a3
  1402.         ADCS    a2,a2,a2
  1403.         STMDB   a1!,{a2,a3,ip,lr}       # store 4 results
  1404.         SUB     a4,a4,#4                # decrement counter by 4
  1405.         TEQ     a4,#0                   # are we done ?
  1406.         BNE     |shift1left_loop_down_l2|       # if count non-zero then loop
  1407.         ADC     a1,a4,a4                # set result to Carry (a4 is 0)
  1408.         LDMFD   sp!,{pc}^               # restore work regs and return 1
  1409.  
  1410. # extern uintD shiftleft_loop_down (uintD* ptr, uintC count, uintC i, uintD carry);
  1411. #       entry
  1412. #               a1 = ptr
  1413. #               a2 = count of words to be shifted left
  1414. #               a3 = size of left shift
  1415. #               a4 = value to ORR in for first shift
  1416. #       exit
  1417. #               a1 = shift out from last shift left
  1418. #               a2 - a4, ip destroyed
  1419.         EXPORT  |shiftleft_loop_down|
  1420. |shiftleft_loop_down|                   # word aligned shiftleft loop down
  1421.         STMFD   sp!,{v6,lr}
  1422.         RSB     v6,a3,#32               # size of complementary right shift
  1423.         ANDS    ip,a2,#3                # multiple of 4 words ?
  1424.         BEQ     |shiftleft_loop_down_l1|        # yup, so branch
  1425.         LDR     lr,[a1,#-4]!            # shiftleft the first 1-3 words
  1426.         ORR     a4,a4,lr,ASL a3         # to align the total to a multiple
  1427.         STR     a4,[a1,#0]              # of 4 words
  1428.         MOV     a4,lr,LSR v6
  1429.         CMP     ip,#2
  1430.         BLT     |shiftleft_loop_down_l1|        # better to branch than skip instrs.
  1431.         LDRGE   lr,[a1,#-4]!
  1432.         ORRGE   a4,a4,lr,ASL a3
  1433.         STRGE   a4,[a1,#0]
  1434.         MOVGE   a4,lr,LSR v6
  1435.         LDRGT   lr,[a1,#-4]!
  1436.         ORRGT   a4,a4,lr,ASL a3
  1437.         STRGT   a4,[a1,#0]
  1438.         MOVGT   a4,lr,LSR v6
  1439. |shiftleft_loop_down_l1|
  1440.         BICS    ip,a2,#3                # set counter to multiple of 4
  1441.         MOVEQ   a1,a4                   # if zero then we're done
  1442.         LDMEQFD sp!,{v6,pc}^            # so return last shift out
  1443.         STMFD   sp!,{v1-v3}             # save work regs
  1444. |shiftleft_loop_down_l2|
  1445.         LDMDB   a1,{a2,v1,v2,v3}        # load 4 words in one go
  1446.         ORR     lr,a4,v3,ASL a3         # shiftleft the four words
  1447.         MOV     a4,v3,LSR v6            # keep carry in a4
  1448.         ORR     v3,a4,v2,ASL a3         # and store results up a register
  1449.         MOV     a4,v2,LSR v6            # to regs v1-v3,lr
  1450.         ORR     v2,a4,v1,ASL a3
  1451.         MOV     a4,v1,LSR v6
  1452.         ORR     v1,a4,a2,ASL a3
  1453.         MOV     a4,a2,LSR v6
  1454.         STMDB   a1!,{v1,v2,v3,lr}       # store 4 results
  1455.         SUBS    ip,ip,#4                # decrement counter by 4
  1456.         BGT     |shiftleft_loop_down_l2|        # if count still positive then loop
  1457.         MOV     a1,a4                   # result = last shift out
  1458.         LDMFD   sp!,{v1-v3,v6,pc}^      # restore work regs and return
  1459.  
  1460. # extern uintD shiftleftcopy_loop_down (uintD* sourceptr, uintD* destptr, uintC count, uintC i);
  1461. #       entry
  1462. #               a1 = sourceptr
  1463. #               a2 = destptr
  1464. #               a3 = count of words to be shifted left
  1465. #               a4 = size of left shift
  1466. #       exit
  1467. #               a1 = shift out from last shift left
  1468. #               a2 - a4, ip destroyed
  1469.         EXPORT  |shiftleftcopy_loop_down|
  1470. |shiftleftcopy_loop_down|               # word aligned shiftleftcopy loop down
  1471.         STMFD   sp!,{v5,v6,lr}
  1472.         MOV     v5,#0                   # initial shift carry
  1473.         RSB     v6,a4,#32               # size of complementary right shift
  1474.         ANDS    ip,a3,#3                # multiple of 4 words ?
  1475.         BEQ     |shiftleftcopy_loop_down_l1|    # yup, so branch
  1476.         LDR     lr,[a1,#-4]!            # shiftleft the first 1-3 words
  1477.         ORR     v5,v5,lr,ASL a4         # to align the total to a multiple
  1478.         STR     v5,[a2,#-4]!            # of 4 words
  1479.         MOV     v5,lr,LSR v6
  1480.         CMP     ip,#2
  1481.         BLT     |shiftleftcopy_loop_down_l1|    # better to branch than skip instrs.
  1482.         LDRGE   lr,[a1,#-4]!
  1483.         ORRGE   v5,v5,lr,ASL a4
  1484.         STRGE   v5,[a2,#-4]!
  1485.         MOVGE   v5,lr,LSR v6
  1486.         LDRGT   lr,[a1,#-4]!
  1487.         ORRGT   v5,v5,lr,ASL a4
  1488.         STRGT   v5,[a2,#-4]!
  1489.         MOVGT   v5,lr,LSR v6
  1490. |shiftleftcopy_loop_down_l1|
  1491.         BICS    ip,a3,#3                # set counter to multiple of 4
  1492.         MOVEQ   a1,v5                   # if zero then we're done
  1493.         LDMEQFD sp!,{v5,v6,pc}^         # so return last shift out
  1494.         STMFD   sp!,{v1-v3}             # save work regs
  1495. |shiftleftcopy_loop_down_l2|
  1496.         LDMDB   a1!,{a3,v1,v2,v3}       # load 4 words in one go
  1497.         ORR     lr,v5,v3,ASL a4         # shiftleft the four words
  1498.         MOV     v5,v3,LSR v6            # keep carry in a4
  1499.         ORR     v3,v5,v2,ASL a4         # and store results up a register
  1500.         MOV     v5,v2,LSR v6            # to regs v1-v3,lr
  1501.         ORR     v2,v5,v1,ASL a4
  1502.         MOV     v5,v1,LSR v6
  1503.         ORR     v1,v5,a3,ASL a4
  1504.         MOV     v5,a3,LSR v6
  1505.         STMDB   a2!,{v1,v2,v3,lr}       # store 4 results
  1506.         SUBS    ip,ip,#4                # decrement counter by 4
  1507.         BGT     |shiftleftcopy_loop_down_l2|    # if count still positive then loop
  1508.         MOV     a1,v5                   # result = last shift out
  1509.         LDMFD   sp!,{v1-v3,v5,v6,pc}^   # restore work regs and return
  1510.  
  1511. # extern uintD shift1right_loop_up (uintD* ptr, uintC count, uintD carry);
  1512. #       entry
  1513. #               a1 = ptr
  1514. #               a2 = count of words to be shifted right
  1515. #               a3 = carry
  1516. #       exit
  1517. #               a1 = carry out from last shift right
  1518. #               a2 - a4, ip destroyed
  1519.         EXPORT  |shift1right_loop_up|
  1520. |shift1right_loop_up|                   # word aligned shift1right loop up
  1521.         MOVS    a3,a3,LSR #1            # set carry
  1522.         ANDS    a3,a2,#1                # multiple of 2 words ?
  1523.         BEQ     |shift1right_loop_up_l1|        # yup, so branch
  1524.         LDR     a4,[a1]                 # shift right the first word
  1525.         MOVS    a4,a4,RRX
  1526.         STR     a4,[a1],#4
  1527. |shift1right_loop_up_l1|
  1528.         BICS    a4,a2,#1                # set counter to multiple of 2
  1529.         MOVEQ   a1,a4,RRX               # if zero set result to C (a4 is 0)
  1530.         MOVEQS  pc,lr                   # and return
  1531.         ANDS    a3,a4,#3                # multiple of 4 words ?
  1532.         BEQ     |shift1right_loop_up_l3|        # yup, so branch
  1533.         LDMIA   a1,{a2,a3}              # load 2 words in one go
  1534.         MOVS    a2,a2,RRX               # shift right the two words
  1535.         MOVS    a3,a3,RRX
  1536.         STMIA   a1!,{a2,a3}             # store 2 results
  1537.         BICS    a4,a4,#2                # decrement counter by 2
  1538.         ADCEQ   a1,a4,a4                # set result to Carry (a4 is 0)
  1539.         MOVEQS  pc,lr                   # and return
  1540. |shift1right_loop_up_l3|                # now a multiple of 4 words
  1541.         STMFD   sp!,{lr}                # save work regs
  1542. |shift1right_loop_up_l2|
  1543.         LDMIA   a1,{a2,a3,ip,lr}        # load 4 words in one go
  1544.         MOVS    a2,a2,RRX               # shift right the four words
  1545.         MOVS    a3,a3,RRX
  1546.         MOVS    ip,ip,RRX
  1547.         MOVS    lr,lr,RRX
  1548.         STMIA   a1!,{a2,a3,ip,lr}       # store 4 results
  1549.         SUB     a4,a4,#4                # decrement counter by 4
  1550.         TEQ     a4,#0                   # are we done ?
  1551.         BNE     |shift1right_loop_up_l2|        # if count non-zero then loop
  1552.         MOV     a1,a4,RRX               # set result to Carry (a4 is 0)
  1553.         LDMFD   sp!,{pc}^               # restore work regs and return 1
  1554.  
  1555. # extern uintD shiftright_loop_up (uintD* ptr, uintC count, uintC i);
  1556. #       entry
  1557. #               a1 = ptr
  1558. #               a2 = count of words to be shifted right
  1559. #               a3 = size of right shift
  1560. #       exit
  1561. #               a1 = shift out from last shift right
  1562. #               a2 - a4, ip destroyed
  1563.         EXPORT  |shiftright_loop_up|
  1564. |shiftright_loop_up|                    # word aligned shiftright loop up
  1565.         STMFD   sp!,{v6,lr}
  1566.         MOV     a4,#0                   # initial shift carry
  1567.         RSB     v6,a3,#32               # size of complementary left shift
  1568. |shiftright_loop_up_l0|
  1569.         ANDS    ip,a2,#3                # multiple of 4 words ?
  1570.         BEQ     |shiftright_loop_up_l1| # yup, so branch
  1571.         LDR     lr,[a1]                 # shiftright the first 1-3 words
  1572.         ORR     a4,a4,lr,LSR a3         # to align the total to a multiple
  1573.         STR     a4,[a1],#4              # of 4 words
  1574.         MOV     a4,lr,ASL v6
  1575.         CMP     ip,#2
  1576.         BLT     |shiftright_loop_up_l1| # better to branch than skip instrs.
  1577.         LDRGE   lr,[a1]
  1578.         ORRGE   a4,a4,lr,LSR a3
  1579.         STRGE   a4,[a1],#4
  1580.         MOVGE   a4,lr,ASL v6
  1581.         LDRGT   lr,[a1]
  1582.         ORRGT   a4,a4,lr,LSR a3
  1583.         STRGT   a4,[a1],#4
  1584.         MOVGT   a4,lr,ASL v6
  1585. |shiftright_loop_up_l1|
  1586.         BICS    ip,a2,#3                # set counter to multiple of 4
  1587.         MOVEQ   a1,a4                   # if zero then we're done
  1588.         LDMEQFD sp!,{v6,pc}^            # so return last shift out
  1589.         STMFD   sp!,{v1-v3}             # save work regs
  1590. |shiftright_loop_up_l2|
  1591.         LDMIA   a1,{v1,v2,v3,lr}        # load 4 words in one go
  1592.         ORR     a2,a4,v1,LSR a3         # shiftright the four words
  1593.         MOV     a4,v1,ASL v6            # keep carry in a4
  1594.         ORR     v1,a4,v2,LSR a3         # and store results down a register
  1595.         MOV     a4,v2,ASL v6            # to regs a2,v1-v3
  1596.         ORR     v2,a4,v3,LSR a3
  1597.         MOV     a4,v3,ASL v6
  1598.         ORR     v3,a4,lr,LSR a3
  1599.         MOV     a4,lr,ASL v6
  1600.         STMIA   a1!,{a2,v1,v2,v3}       # store 4 results
  1601.         SUBS    ip,ip,#4                # decrement counter by 4
  1602.         BGT     |shiftright_loop_up_l2| # if count still positive then loop
  1603.         MOV     a1,a4                   # result = last shift out
  1604.         LDMFD   sp!,{v1-v3,v6,pc}^      # restore work regs and return
  1605.  
  1606. # extern uintD shiftrightsigned_loop_up (uintD* ptr, uintC count, uintC i);
  1607. #       entry
  1608. #               a1 = ptr
  1609. #               a2 = count of words to be shifted right signed
  1610. #               a3 = size of right shift
  1611. #       exit
  1612. #               a1 = shift out from last shift right
  1613. #               a2 - a4, ip destroyed
  1614.         EXPORT  |shiftrightsigned_loop_up|
  1615. |shiftrightsigned_loop_up|              # word aligned shiftrightsigned loop up
  1616.         STMFD   sp!,{v6,lr}
  1617.         RSB     v6,a3,#32               # size of complementary left shift
  1618.         LDR     lr,[a1]                 # setup carry for first shift.
  1619.         MOV     a4,lr,ASR #31           # this is the sign extended bits
  1620.         AND     a4,a4,a4,LSL v6         # 31->(32-i) of the first word
  1621.         B       |shiftright_loop_up_l0| # use right shift code now
  1622.  
  1623. # extern uintD shiftrightcopy_loop_up (uintD* sourceptr, uintD* destptr, uintC count, uintC i, uintD carry);
  1624. #       entry
  1625. #               a1 = sourceptr
  1626. #               a2 = destptr
  1627. #               a3 = count of words to be shifted right
  1628. #               a4 = size of right shift
  1629. #               [sp] = carry for first shift
  1630. #       exit
  1631. #               a1 = shift out from last shift right
  1632. #               a2 - a4, ip destroyed
  1633.         EXPORT  |shiftrightcopy_loop_up|
  1634. |shiftrightcopy_loop_up|                # word aligned shiftrightcopy loop up
  1635.         STMFD   sp!,{v5,v6,lr}
  1636.         LDR     v5,[sp,#12]             # initial shift carry
  1637.         RSB     v6,a4,#32               # size of complementary left shift
  1638.         MOV     v5,v5,ASL v6
  1639. |shiftrightcopy_loop_up_l0|
  1640.         ANDS    ip,a3,#3                # multiple of 4 words ?
  1641.         BEQ     |shiftrightcopy_loop_up_l1|     # yup, so branch
  1642.         LDR     lr,[a1],#4              # shiftright the first 1-3 words
  1643.         ORR     v5,v5,lr,LSR a4         # to align the total to a multiple
  1644.         STR     v5,[a2],#4              # of 4 words
  1645.         MOV     v5,lr,ASL v6
  1646.         CMP     ip,#2
  1647.         BLT     |shiftrightcopy_loop_up_l1|     # better to branch than skip instrs.
  1648.         LDRGE   lr,[a1],#4
  1649.         ORRGE   v5,v5,lr,LSR a4
  1650.         STRGE   v5,[a2],#4
  1651.         MOVGE   v5,lr,ASL v6
  1652.         LDRGT   lr,[a1],#4
  1653.         ORRGT   v5,v5,lr,LSR a4
  1654.         STRGT   v5,[a2],#4
  1655.         MOVGT   v5,lr,ASL v6
  1656. |shiftrightcopy_loop_up_l1|
  1657.         BICS    ip,a3,#3                # set counter to multiple of 4
  1658.         MOVEQ   a1,v5                   # if zero then we're done
  1659.         LDMEQFD sp!,{v5,v6,pc}^         # so return last shift out
  1660.         STMFD   sp!,{v1-v3}             # save work regs
  1661. |shiftrightcopy_loop_up_l2|
  1662.         LDMIA   a1!,{v1,v2,v3,lr}       # load 4 words in one go
  1663.         ORR     a3,v5,v1,LSR a4         # shiftright the four words
  1664.         MOV     v5,v1,ASL v6            # keep carry in a4
  1665.         ORR     v1,v5,v2,LSR a4         # and store results down a register
  1666.         MOV     v5,v2,ASL v6            # to regs a2,v1-v3
  1667.         ORR     v2,v5,v3,LSR a4
  1668.         MOV     v5,v3,ASL v6
  1669.         ORR     v3,v5,lr,LSR a4
  1670.         MOV     v5,lr,ASL v6
  1671.         STMIA   a2!,{a3,v1,v2,v3}       # store 4 results
  1672.         SUBS    ip,ip,#4                # decrement counter by 4
  1673.         BGT     |shiftrightcopy_loop_up_l2|     # if count still positive then loop
  1674.         MOV     a1,v5                   # result = last shift out
  1675.         LDMFD   sp!,{v1-v3,v5,v6,pc}^   # restore work regs and return
  1676.  
  1677. # mulu32_64_vregs
  1678. #       entry
  1679. #               a1 = x
  1680. #               ip = y
  1681. #       exit
  1682. #               v1 = low32(x*y)
  1683. #               ip = high32(x*y)
  1684. #               v2,v3,v4 destroyed
  1685. mulu32_64_vregs
  1686.         MOV     v1,a1,LSR #16           # temp := top half of x
  1687.         MOV     v2,ip,LSR #16           # hi := top half of y
  1688.         BIC     v3,a1,v1,LSL #16        # x  := bottom half of x
  1689.         BIC     ip,ip,v2,LSL #16        # y  := bottom half of y
  1690.         MUL     v4,v3,ip                # low section of result
  1691.         MUL     ip,v1,ip                # ) middle sections
  1692.         MUL     v3,v2,v3                # )   of result
  1693.         MUL     v2,v1,v2                # high section of result
  1694.         ADDS    ip,ip,v3                # add middle sections
  1695.                                         # (can't use mla as we need carry)
  1696.         ADDCS   v2,v2,#&10000           # carry from above add
  1697.         ADDS    v1,v4,ip,LSL #16        # x is now bottom 32 bits of result
  1698.         ADC     ip,v2,ip,LSR #16        # hi is top 32 bits
  1699.         MOVS    pc,lr
  1700.  
  1701. # extern uintD mulusmall_loop_down (uintD digit, uintD* ptr, uintC len, uintD newdigit);
  1702. #       entry
  1703. #               a1 = digit
  1704. #               a2 = ptr
  1705. #               a3 = count of words to be multiplied down
  1706. #               a4 = new digit = carry
  1707. #       exit
  1708. #               a1 = final carry of multiply
  1709. #               a2 - a4, ip destroyed
  1710.         EXPORT  |mulusmall_loop_down|
  1711. mulusmall_loop_down
  1712.         CMP     a3,#0
  1713.         MOVEQ   a1,a4
  1714.         MOVEQS  pc,lr
  1715.         STMFD   sp!,{v1-v2,lr}
  1716. mulusmall_loop_down_l1
  1717.         LDR     ip,[a2,#-4]!
  1718.  
  1719. #       BL      mulu32_64_vregs         # muluD(digit,*--ptr,hi=,lo=)
  1720. # replaced by multiplication of a small x = a1 and a big y = ip :
  1721.         MOV     v1,ip,LSR #16           # top half of y
  1722.         BIC     ip,ip,v1,LSL #16        # bottom half of y
  1723.         MUL     v2,a1,v1                # middle section of result
  1724.         MUL     v1,a1,ip                # low section of result
  1725.         MOV     ip,#0                   # high section of result
  1726.         ADDS    v1,v1,v2,LSL #16        # bottom 32 bits of result
  1727.         ADC     ip,ip,v2,LSR #16        # top 32 bits of result
  1728.  
  1729.         ADDS    v1,v1,a4                # lo += carry
  1730.         ADC     a4,ip,#0                # if (lo<carry) { hi += 1 }; carry=hi
  1731.         STR     v1,[a2,#0]              # *ptr = lo
  1732.         SUBS    a3,a3,#1                # len--
  1733.         BNE     mulusmall_loop_down_l1  # until len==0
  1734.         MOV     a1,a4                   # return carry
  1735.         LDMFD   sp!,{v1-v2,pc}^
  1736.  
  1737. # extern void mulu_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
  1738. #       entry
  1739. #               a1 = digit
  1740. #               a2 = sourceptr
  1741. #               a3 = destptr
  1742. #               a4 = count of words to be multiplied down
  1743. #       exit
  1744. #               a1 - a4, ip destroyed
  1745.         EXPORT  |mulu_loop_down|
  1746. mulu_loop_down
  1747.         STMFD   sp!,{v1-v5,lr}
  1748.         MOV     v5,#0
  1749. mulu_loop_down_l1
  1750.         LDR     ip,[a2,#-4]!
  1751.         BL      mulu32_64_vregs         # muluD(digit,*--sourceptr,hi=,lo=)
  1752.         ADDS    v1,v1,v5                # lo += carry
  1753.         ADC     v5,ip,#0                # if (lo<carry) { hi += 1 }; carry=hi
  1754.         STR     v1,[a3,#-4]!            # *--destptr = lo
  1755.         SUBS    a4,a4,#1                # len--
  1756.         BNE     mulu_loop_down_l1       # until len==0
  1757.         STR     v5,[a3,#-4]!            # *--destptr = carry
  1758.         LDMFD   sp!,{v1-v5,pc}^
  1759.  
  1760. # extern void muluadd_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
  1761. #       entry
  1762. #               a1 = digit
  1763. #               a2 = sourceptr
  1764. #               a3 = destptr
  1765. #               a4 = count of words to be multiplied added down
  1766. #       exit
  1767. #               a1 - a4, ip destroyed
  1768.         EXPORT  |muluadd_loop_down|
  1769. muluadd_loop_down
  1770.         STMFD   sp!,{v1-v5,lr}
  1771.         MOV     v5,#0
  1772. muluadd_loop_down_l1
  1773.         LDR     ip,[a2,#-4]!
  1774.         BL      mulu32_64_vregs         # muluD(digit,*--sourceptr,hi=,lo=)
  1775.         ADDS    v1,v1,v5                # lo += carry
  1776.         ADCCS   ip,ip,#0                # if (lo<carry) { hi += 1 };
  1777.         LDR     v5,[a3,#-4]!            # carry = *--destptr
  1778.         ADDS    v1,v1,v5                # lo += carry
  1779.         ADC     v5,ip,#0                # if (lo<carry) { hi += 1 }; carry=hi
  1780.         STR     v1,[a3,#0]              # *destptr = lo
  1781.         SUBS    a4,a4,#1                # len--
  1782.         BNE     muluadd_loop_down_l1    # until len==0
  1783.         MOV     a1,v5                   # return carry
  1784.         LDMFD   sp!,{v1-v5,pc}^
  1785.  
  1786. # extern void mulusub_loop_down (uintD digit, uintD* sourceptr, uintD* destptr, uintC len);
  1787. #       entry
  1788. #               a1 = digit
  1789. #               a2 = sourceptr
  1790. #               a3 = destptr
  1791. #               a4 = count of words to be multiplied subtracted down
  1792. #       exit
  1793. #               a1 - a4, ip destroyed
  1794.         EXPORT  |mulusub_loop_down|
  1795. mulusub_loop_down
  1796.         STMFD   sp!,{v1-v5,lr}
  1797.         MOV     v5,#0
  1798. mulusub_loop_down_l1
  1799.         LDR     ip,[a2,#-4]!
  1800.         BL      mulu32_64_vregs         # muluD(digit,*--sourceptr,hi=,lo=)
  1801.         ADDS    v1,v1,v5                # lo += carry
  1802.         ADCCS   ip,ip,#0                # if (lo<carry) { hi += 1 };
  1803.         LDR     v5,[a3,#-4]!            # carry = *--destptr
  1804.         SUBS    v4,v5,v1
  1805.         STR     v4,[a3,#0]              # *destptr = carry - lo
  1806.         ADDCC   v5,ip,#1                # if (carry<lo) { hi += 1 }; carry=hi
  1807.         MOVCS   v5,ip
  1808.         SUBS    a4,a4,#1                # len--
  1809.         BNE     mulusub_loop_down_l1    # until len==0
  1810.         MOV     a1,v5                   # return carry
  1811.         LDMFD   sp!,{v1-v5,pc}^
  1812.  
  1813.         END
  1814.  
  1815. #endif
  1816.