1 | /* mc68020 __mpn_rshift -- Shift right a low-level natural-number integer. |
2 | |
3 | Copyright (C) 1996-2024 Free Software Foundation, Inc. |
4 | |
5 | This file is part of the GNU MP Library. |
6 | |
7 | The GNU MP Library is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU Lesser General Public License as published by |
9 | the Free Software Foundation; either version 2.1 of the License, or (at your |
10 | option) any later version. |
11 | |
12 | The GNU MP Library is distributed in the hope that it will be useful, but |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
14 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
15 | License for more details. |
16 | |
17 | You should have received a copy of the GNU Lesser General Public License |
18 | along with the GNU MP Library. If not, see <https://www.gnu.org/licenses/>. */ |
19 | |
20 | /* |
21 | INPUT PARAMETERS |
22 | res_ptr (sp + 4) |
23 | s_ptr (sp + 8) |
24 | s_size (sp + 16) |
25 | cnt (sp + 12) |
26 | */ |
27 | |
28 | #include "sysdep.h" |
29 | #include "asm-syntax.h" |
30 | |
31 | #define res_ptr a1 |
32 | #define s_ptr a0 |
33 | #define s_size d6 |
34 | #define cnt d4 |
35 | |
36 | TEXT |
37 | ENTRY(__mpn_rshift) |
38 | /* Save used registers on the stack. */ |
39 | moveml R(d2)-R(d6)/R(a2),MEM_PREDEC(sp) |
40 | cfi_adjust_cfa_offset (6*4) |
41 | cfi_rel_offset (R(d2), 0) |
42 | cfi_rel_offset (R(d3), 4) |
43 | cfi_rel_offset (R(d4), 8) |
44 | cfi_rel_offset (R(d5), 12) |
45 | cfi_rel_offset (R(d6), 16) |
46 | cfi_rel_offset (R(a2), 20) |
47 | |
48 | /* Copy the arguments to registers. */ |
49 | movel MEM_DISP(sp,28),R(res_ptr) |
50 | movel MEM_DISP(sp,32),R(s_ptr) |
51 | movel MEM_DISP(sp,36),R(s_size) |
52 | movel MEM_DISP(sp,40),R(cnt) |
53 | |
54 | moveql #1,R(d5) |
55 | cmpl R(d5),R(cnt) |
56 | bne L(Lnormal) |
57 | cmpl R(res_ptr),R(s_ptr) |
58 | bls L(Lspecial) /* jump if res_ptr >= s_ptr */ |
59 | #if M68K_SCALE_AVAILABLE |
60 | lea MEM_INDX1(res_ptr,s_size,l,4),R(a2) |
61 | #else |
62 | movel R(s_size),R(d0) |
63 | asll #2,R(d0) |
64 | lea MEM_INDX(res_ptr,d0,l),R(a2) |
65 | #endif |
66 | cmpl R(s_ptr),R(a2) |
67 | bls L(Lspecial) /* jump if s_ptr >= res_ptr + s_size */ |
68 | |
69 | L(Lnormal:) |
70 | moveql #32,R(d5) |
71 | subl R(cnt),R(d5) |
72 | movel MEM_POSTINC(s_ptr),R(d2) |
73 | movel R(d2),R(d0) |
74 | lsll R(d5),R(d0) /* compute carry limb */ |
75 | |
76 | lsrl R(cnt),R(d2) |
77 | movel R(d2),R(d1) |
78 | subql #1,R(s_size) |
79 | beq L(Lend) |
80 | lsrl #1,R(s_size) |
81 | bcs L(L1) |
82 | subql #1,R(s_size) |
83 | |
84 | L(Loop:) |
85 | movel MEM_POSTINC(s_ptr),R(d2) |
86 | movel R(d2),R(d3) |
87 | lsll R(d5),R(d3) |
88 | orl R(d3),R(d1) |
89 | movel R(d1),MEM_POSTINC(res_ptr) |
90 | lsrl R(cnt),R(d2) |
91 | L(L1:) |
92 | movel MEM_POSTINC(s_ptr),R(d1) |
93 | movel R(d1),R(d3) |
94 | lsll R(d5),R(d3) |
95 | orl R(d3),R(d2) |
96 | movel R(d2),MEM_POSTINC(res_ptr) |
97 | lsrl R(cnt),R(d1) |
98 | |
99 | dbf R(s_size),L(Loop) |
100 | subl #0x10000,R(s_size) |
101 | bcc L(Loop) |
102 | |
103 | L(Lend:) |
104 | movel R(d1),MEM(res_ptr) /* store most significant limb */ |
105 | |
106 | /* Restore used registers from stack frame. */ |
107 | moveml MEM_POSTINC(sp),R(d2)-R(d6)/R(a2) |
108 | cfi_remember_state |
109 | cfi_adjust_cfa_offset (-6*4) |
110 | cfi_restore (R(d2)) |
111 | cfi_restore (R(d3)) |
112 | cfi_restore (R(d4)) |
113 | cfi_restore (R(d5)) |
114 | cfi_restore (R(d6)) |
115 | cfi_restore (R(a2)) |
116 | rts |
117 | |
118 | /* We loop from most significant end of the arrays, which is only |
119 | permissible if the source and destination don't overlap, since the |
120 | function is documented to work for overlapping source and destination. */ |
121 | |
122 | cfi_restore_state |
123 | L(Lspecial:) |
124 | #if M68K_SCALE_AVAILABLE |
125 | lea MEM_INDX1(s_ptr,s_size,l,4),R(s_ptr) |
126 | lea MEM_INDX1(res_ptr,s_size,l,4),R(res_ptr) |
127 | #else |
128 | movel R(s_size),R(d0) |
129 | asll #2,R(d0) |
130 | addl R(d0),R(s_ptr) |
131 | addl R(d0),R(res_ptr) |
132 | #endif |
133 | |
134 | clrl R(d0) /* initialize carry */ |
135 | eorw #1,R(s_size) |
136 | lsrl #1,R(s_size) |
137 | bcc L(LL1) |
138 | subql #1,R(s_size) |
139 | |
140 | L(LLoop:) |
141 | movel MEM_PREDEC(s_ptr),R(d2) |
142 | roxrl #1,R(d2) |
143 | movel R(d2),MEM_PREDEC(res_ptr) |
144 | L(LL1:) |
145 | movel MEM_PREDEC(s_ptr),R(d2) |
146 | roxrl #1,R(d2) |
147 | movel R(d2),MEM_PREDEC(res_ptr) |
148 | |
149 | dbf R(s_size),L(LLoop) |
150 | roxrl #1,R(d0) /* save cy in msb */ |
151 | subl #0x10000,R(s_size) |
152 | bcs L(LLend) |
153 | addl R(d0),R(d0) /* restore cy */ |
154 | bra L(LLoop) |
155 | |
156 | L(LLend:) |
157 | /* Restore used registers from stack frame. */ |
158 | moveml MEM_POSTINC(sp),R(d2)-R(d6)/R(a2) |
159 | cfi_adjust_cfa_offset (-6*4) |
160 | cfi_restore (R(d2)) |
161 | cfi_restore (R(d3)) |
162 | cfi_restore (R(d4)) |
163 | cfi_restore (R(d5)) |
164 | cfi_restore (R(d6)) |
165 | cfi_restore (R(a2)) |
166 | rts |
167 | END(__mpn_rshift) |
168 | |