Austin Schuh | bb1338c | 2024-06-15 19:31:16 -0700 | [diff] [blame] | 1 | dnl mc68020 mpn_lshift -- mpn left shift. |
| 2 | |
| 3 | dnl Copyright 1996, 1999-2003 Free Software Foundation, Inc. |
| 4 | |
| 5 | dnl This file is part of the GNU MP Library. |
| 6 | dnl |
| 7 | dnl The GNU MP Library is free software; you can redistribute it and/or modify |
| 8 | dnl it under the terms of either: |
| 9 | dnl |
| 10 | dnl * the GNU Lesser General Public License as published by the Free |
| 11 | dnl Software Foundation; either version 3 of the License, or (at your |
| 12 | dnl option) any later version. |
| 13 | dnl |
| 14 | dnl or |
| 15 | dnl |
| 16 | dnl * the GNU General Public License as published by the Free Software |
| 17 | dnl Foundation; either version 2 of the License, or (at your option) any |
| 18 | dnl later version. |
| 19 | dnl |
| 20 | dnl or both in parallel, as here. |
| 21 | dnl |
| 22 | dnl The GNU MP Library is distributed in the hope that it will be useful, but |
| 23 | dnl WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 24 | dnl or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 25 | dnl for more details. |
| 26 | dnl |
| 27 | dnl You should have received copies of the GNU General Public License and the |
| 28 | dnl GNU Lesser General Public License along with the GNU MP Library. If not, |
| 29 | dnl see https://www.gnu.org/licenses/. |
| 30 | |
| 31 | include(`../config.m4') |
| 32 | |
| 33 | |
| 34 | C cycles/limb |
| 35 | C shift==1 shift>1 |
| 36 | C 68040: 5 12 |
| 37 | |
| 38 | |
| 39 | C mp_limb_t mpn_lshift (mp_ptr res_ptr, mp_srcptr s_ptr, mp_size_t s_size, |
| 40 | C unsigned cnt); |
| 41 | C |
| 42 | C The "cnt" parameter is either 16 bits or 32 bits depending on |
| 43 | C SIZEOF_UNSIGNED (see ABI notes in mpn/m68k/README). The value is of |
| 44 | C course only 1 to 31. When loaded as 16 bits there's garbage in the upper |
| 45 | C half, hence the use of cmpw. The shift instructions take the their count |
| 46 | C modulo 64, so the upper part doesn't matter to them either. |
| 47 | C |
| 48 | |
| 49 | C INPUT PARAMETERS |
| 50 | C res_ptr (sp + 4) |
| 51 | C s_ptr (sp + 8) |
| 52 | C s_size (sp + 12) |
| 53 | C cnt (sp + 16) |
| 54 | |
| 55 | define(res_ptr, `a1') |
| 56 | define(s_ptr, `a0') |
| 57 | define(s_size, `d6') |
| 58 | define(cnt, `d4') |
| 59 | |
| 60 | ifdef(`SIZEOF_UNSIGNED',, |
| 61 | `m4_error(`SIZEOF_UNSIGNED not defined, should be in config.m4 |
| 62 | ')') |
| 63 | |
| 64 | PROLOGUE(mpn_lshift) |
| 65 | C Save used registers on the stack. |
| 66 | moveml d2-d6/a2, M(-,sp) |
| 67 | |
| 68 | C Copy the arguments to registers. |
| 69 | movel M(sp,28), res_ptr |
| 70 | movel M(sp,32), s_ptr |
| 71 | movel M(sp,36), s_size |
| 72 | ifelse(SIZEOF_UNSIGNED,2, |
| 73 | ` movew M(sp,40), cnt', |
| 74 | ` movel M(sp,40), cnt') |
| 75 | |
| 76 | moveql #1, d5 |
| 77 | cmpw d5, cnt |
| 78 | bne L(Lnormal) |
| 79 | cmpl s_ptr, res_ptr |
| 80 | bls L(Lspecial) C jump if s_ptr >= res_ptr |
| 81 | |
| 82 | ifelse(scale_available_p,1,` |
| 83 | lea M(s_ptr,s_size,l,4), a2 |
| 84 | ',` |
| 85 | movel s_size, d0 |
| 86 | asll #2, d0 |
| 87 | lea M(s_ptr,d0,l), a2 |
| 88 | ') |
| 89 | cmpl res_ptr, a2 |
| 90 | bls L(Lspecial) C jump if res_ptr >= s_ptr + s_size |
| 91 | |
| 92 | L(Lnormal): |
| 93 | moveql #32, d5 |
| 94 | subl cnt, d5 |
| 95 | |
| 96 | ifelse(scale_available_p,1,` |
| 97 | lea M(s_ptr,s_size,l,4), s_ptr |
| 98 | lea M(res_ptr,s_size,l,4), res_ptr |
| 99 | ',` |
| 100 | movel s_size, d0 |
| 101 | asll #2, d0 |
| 102 | addl d0, s_ptr |
| 103 | addl d0, res_ptr |
| 104 | ') |
| 105 | movel M(-,s_ptr), d2 |
| 106 | movel d2, d0 |
| 107 | lsrl d5, d0 C compute carry limb |
| 108 | |
| 109 | lsll cnt, d2 |
| 110 | movel d2, d1 |
| 111 | subql #1, s_size |
| 112 | beq L(Lend) |
| 113 | lsrl #1, s_size |
| 114 | bcs L(L1) |
| 115 | subql #1, s_size |
| 116 | |
| 117 | L(Loop): |
| 118 | movel M(-,s_ptr), d2 |
| 119 | movel d2, d3 |
| 120 | lsrl d5, d3 |
| 121 | orl d3, d1 |
| 122 | movel d1, M(-,res_ptr) |
| 123 | lsll cnt, d2 |
| 124 | L(L1): |
| 125 | movel M(-,s_ptr), d1 |
| 126 | movel d1, d3 |
| 127 | lsrl d5, d3 |
| 128 | orl d3, d2 |
| 129 | movel d2, M(-,res_ptr) |
| 130 | lsll cnt, d1 |
| 131 | |
| 132 | dbf s_size, L(Loop) |
| 133 | subl #0x10000, s_size |
| 134 | bcc L(Loop) |
| 135 | |
| 136 | L(Lend): |
| 137 | movel d1, M(-,res_ptr) C store least significant limb |
| 138 | |
| 139 | C Restore used registers from stack frame. |
| 140 | moveml M(sp,+), d2-d6/a2 |
| 141 | rts |
| 142 | |
| 143 | C We loop from least significant end of the arrays, which is only |
| 144 | C permissable if the source and destination don't overlap, since the |
| 145 | C function is documented to work for overlapping source and destination. |
| 146 | |
| 147 | L(Lspecial): |
| 148 | clrl d0 C initialize carry |
| 149 | eorw #1, s_size |
| 150 | lsrl #1, s_size |
| 151 | bcc L(LL1) |
| 152 | subql #1, s_size |
| 153 | |
| 154 | L(LLoop): |
| 155 | movel M(s_ptr,+), d2 |
| 156 | addxl d2, d2 |
| 157 | movel d2, M(res_ptr,+) |
| 158 | L(LL1): |
| 159 | movel M(s_ptr,+), d2 |
| 160 | addxl d2, d2 |
| 161 | movel d2, M(res_ptr,+) |
| 162 | |
| 163 | dbf s_size, L(LLoop) |
| 164 | addxl d0, d0 C save cy in lsb |
| 165 | subl #0x10000, s_size |
| 166 | bcs L(LLend) |
| 167 | lsrl #1, d0 C restore cy |
| 168 | bra L(LLoop) |
| 169 | |
| 170 | L(LLend): |
| 171 | C Restore used registers from stack frame. |
| 172 | moveml M(sp,+), d2-d6/a2 |
| 173 | rts |
| 174 | |
| 175 | EPILOGUE(mpn_lshift) |