]>
Commit | Line | Data |
---|---|---|
f1717362 | 1 | ; Copyright (C) 2014-2016 Free Software Foundation, Inc. |
6dd4126d | 2 | ; Contributed by Red Hat. |
3 | ; | |
4 | ; This file is free software; you can redistribute it and/or modify it | |
5 | ; under the terms of the GNU General Public License as published by the | |
6 | ; Free Software Foundation; either version 3, or (at your option) any | |
7 | ; later version. | |
8 | ; | |
9 | ; This file is distributed in the hope that it will be useful, but | |
10 | ; WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | ; General Public License for more details. | |
13 | ; | |
14 | ; Under Section 7 of GPL version 3, you are granted additional | |
15 | ; permissions described in the GCC Runtime Library Exception, version | |
16 | ; 3.1, as published by the Free Software Foundation. | |
17 | ; | |
18 | ; You should have received a copy of the GNU General Public License and | |
19 | ; a copy of the GCC Runtime Library Exception along with this program; | |
20 | ; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
21 | ; <http://www.gnu.org/licenses/>. | |
22 | ||
7ed86ba5 | 23 | ;; Macro to start a multiply function. Each function has three |
24 | ;; names, and hence three entry points - although they all go | |
25 | ;; through the same code. The first name is the version generated | |
26 | ;; by GCC. The second is the MSP430 EABI mandated name for the | |
27 | ;; *software* version of the function. The third is the EABI | |
28 | ;; mandated name for the *hardware* version of the function. | |
29 | ;; | |
30 | ;; Since we are using the hardware and software names to point | |
31 | ;; to the same code this effectively means that we are mapping | |
32 | ;; the software function onto the hardware function. Thus if | |
33 | ;; the library containing this code is linked into an application | |
34 | ;; (before the libgcc.a library) *all* multiply functions will | |
35 | ;; be mapped onto the hardware versions. | |
36 | ;; | |
37 | ;; We construct each function in its own section so that linker | |
38 | ;; garbage collection can be used to delete any unused functions | |
39 | ;; from this file. | |
40 | .macro start_func gcc_name eabi_soft_name eabi_hard_name | |
41 | .pushsection .text.\gcc_name,"ax",@progbits | |
c0b6819e | 42 | .p2align 1 |
7ed86ba5 | 43 | .global \eabi_hard_name |
44 | .type \eabi_hard_name , @function | |
45 | \eabi_hard_name: | |
46 | .global \eabi_soft_name | |
47 | .type \eabi_soft_name , @function | |
48 | \eabi_soft_name: | |
49 | .global \gcc_name | |
50 | .type \gcc_name , @function | |
51 | \gcc_name: | |
6dd4126d | 52 | PUSH.W sr ; Save current interrupt state |
53 | DINT ; Disable interrupts | |
54 | NOP ; Account for latency | |
55 | .endm | |
56 | ||
7ed86ba5 | 57 | |
58 | ;; End a function started with the start_func macro. | |
6dd4126d | 59 | .macro end_func name |
60 | #ifdef __MSP430X_LARGE__ | |
61 | POP.W sr | |
62 | RETA | |
63 | #else | |
64 | RETI | |
65 | #endif | |
66 | .size \name , . - \name | |
67 | .popsection | |
68 | .endm | |
69 | ||
7ed86ba5 | 70 | |
71 | ;; Like the start_func macro except that it is used to | |
72 | ;; create a false entry point that just jumps to the | |
73 | ;; software function (implemented elsewhere). | |
74 | .macro fake_func gcc_name eabi_soft_name eabi_hard_name | |
75 | .pushsection .text.\gcc_name,"ax",@progbits | |
76 | .p2align 1 | |
77 | .global \eabi_hard_name | |
78 | .type \eabi_hard_name , @function | |
79 | \eabi_hard_name: | |
80 | .global \gcc_name | |
81 | .type \gcc_name , @function | |
82 | \gcc_name: | |
83 | #ifdef __MSP430X_LARGE__ | |
84 | BRA \eabi_soft_name | |
85 | #else | |
86 | BR \eabi_soft_name | |
87 | #endif | |
88 | .size \gcc_name , . - \gcc_name | |
89 | .popsection | |
90 | .endm | |
91 | ||
92 | ||
6dd4126d | 93 | .macro mult16 OP1, OP2, RESULT |
94 | ;* * 16-bit hardware multiply: int16 = int16 * int16 | |
95 | ;* | |
96 | ;* - Operand 1 is in R12 | |
97 | ;* - Operand 2 is in R13 | |
98 | ;* - Result is in R12 | |
99 | ;* | |
100 | ;* To ensure that the multiply is performed atomically, interrupts are | |
101 | ;* disabled upon routine entry. Interrupt state is restored upon exit. | |
102 | ;* | |
103 | ;* Registers used: R12, R13 | |
104 | ;* | |
105 | ;* Macro arguments are the memory locations of the hardware registers. | |
106 | ||
107 | MOV.W r12, &\OP1 ; Load operand 1 into multiplier | |
108 | MOV.W r13, &\OP2 ; Load operand 2 which triggers MPY | |
109 | MOV.W &\RESULT, r12 ; Move result into return register | |
110 | .endm | |
111 | ||
112 | .macro mult1632 OP1, OP2, RESULT_LO, RESULT_HI | |
113 | ;* * 16-bit hardware multiply with a 32-bit result: | |
114 | ;* int32 = int16 * int16 | |
115 | ;* uint32 = uint16 * uint16 | |
116 | ;* | |
117 | ;* - Operand 1 is in R12 | |
118 | ;* - Operand 2 is in R13 | |
119 | ;* - Result is in R12, R13 | |
120 | ;* | |
121 | ;* To ensure that the multiply is performed atomically, interrupts are | |
122 | ;* disabled upon routine entry. Interrupt state is restored upon exit. | |
123 | ;* | |
124 | ;* Registers used: R12, R13 | |
125 | ;* | |
126 | ;* Macro arguments are the memory locations of the hardware registers. | |
127 | ||
128 | MOV.W r12, &\OP1 ; Load operand 1 into multiplier | |
129 | MOV.W r13, &\OP2 ; Load operand 2 which triggers MPY | |
130 | MOV.W &\RESULT_LO, r12 ; Move low result into return register | |
131 | MOV.W &\RESULT_HI, r13 ; Move high result into return register | |
132 | .endm | |
133 | ||
134 | .macro mult32 OP1, OP2, MAC_OP1, MAC_OP2, RESULT_LO, RESULT_HI | |
135 | ;* * 32-bit hardware multiply with a 32-bit result using 16 multiply and accumulate: | |
136 | ;* int32 = int32 * int32 | |
137 | ;* | |
138 | ;* - Operand 1 is in R12, R13 | |
139 | ;* - Operand 2 is in R14, R15 | |
140 | ;* - Result is in R12, R13 | |
141 | ;* | |
142 | ;* To ensure that the multiply is performed atomically, interrupts are | |
143 | ;* disabled upon routine entry. Interrupt state is restored upon exit. | |
144 | ;* | |
145 | ;* Registers used: R12, R13, R14, R15 | |
146 | ;* | |
147 | ;* Macro arguments are the memory locations of the hardware registers. | |
148 | ||
149 | MOV.W r12, &\OP1 ; Load operand 1 Low into multiplier | |
150 | MOV.W r14, &\OP2 ; Load operand 2 Low which triggers MPY | |
151 | MOV.W r12, &\MAC_OP1 ; Load operand 1 Low into mac | |
152 | MOV.W &\RESULT_LO, r12 ; Low 16-bits of result ready for return | |
153 | MOV.W &\RESULT_HI, &\RESULT_LO; MOV intermediate mpy high into low | |
154 | MOV.W r15, &\MAC_OP2 ; Load operand 2 High, trigger MAC | |
155 | MOV.W r13, &\MAC_OP1 ; Load operand 1 High | |
156 | MOV.W r14, &\MAC_OP2 ; Load operand 2 Lo, trigger MAC | |
157 | MOV.W &\RESULT_LO, r13 ; Upper 16-bits result ready for return | |
158 | .endm | |
159 | ||
160 | ||
161 | .macro mult32_hw OP1_LO OP1_HI OP2_LO OP2_HI RESULT_LO RESULT_HI | |
162 | ;* * 32-bit hardware multiply with a 32-bit result | |
163 | ;* int32 = int32 * int32 | |
164 | ;* | |
165 | ;* - Operand 1 is in R12, R13 | |
166 | ;* - Operand 2 is in R14, R15 | |
167 | ;* - Result is in R12, R13 | |
168 | ;* | |
169 | ;* To ensure that the multiply is performed atomically, interrupts are | |
170 | ;* disabled upon routine entry. Interrupt state is restored upon exit. | |
171 | ;* | |
172 | ;* Registers used: R12, R13, R14, R15 | |
173 | ;* | |
174 | ;* Macro arguments are the memory locations of the hardware registers. | |
175 | ||
176 | MOV.W r12, &\OP1_LO ; Load operand 1 Low into multiplier | |
177 | MOV.W r13, &\OP1_HI ; Load operand 1 High into multiplier | |
178 | MOV.W r14, &\OP2_LO ; Load operand 2 Low into multiplier | |
179 | MOV.W r15, &\OP2_HI ; Load operand 2 High, trigger MPY | |
180 | MOV.W &\RESULT_LO, r12 ; Ready low 16-bits for return | |
181 | MOV.W &\RESULT_HI, r13 ; Ready high 16-bits for return | |
182 | .endm | |
183 | ||
184 | .macro mult3264_hw OP1_LO OP1_HI OP2_LO OP2_HI RES0 RES1 RES2 RES3 | |
185 | ;* * 32-bit hardware multiply with a 64-bit result | |
186 | ;* int64 = int32 * int32 | |
187 | ;* uint64 = uint32 * uint32 | |
188 | ;* | |
189 | ;* - Operand 1 is in R12, R13 | |
190 | ;* - Operand 2 is in R14, R15 | |
191 | ;* - Result is in R12, R13, R14, R15 | |
192 | ;* | |
193 | ;* To ensure that the multiply is performed atomically, interrupts are | |
194 | ;* disabled upon routine entry. Interrupt state is restored upon exit. | |
195 | ;* | |
196 | ;* Registers used: R12, R13, R14, R15 | |
197 | ;* | |
198 | ;* Macro arguments are the memory locations of the hardware registers. | |
199 | ||
200 | MOV.W r12, &\OP1_LO ; Load operand 1 Low into multiplier | |
201 | MOV.W r13, &\OP1_HI ; Load operand 1 High into multiplier | |
202 | MOV.W r14, &\OP2_LO ; Load operand 2 Low into multiplier | |
203 | MOV.W r15, &\OP2_HI ; Load operand 2 High, trigger MPY | |
204 | MOV.W &\RES0, R12 ; Ready low 16-bits for return | |
205 | MOV.W &\RES1, R13 ; | |
206 | MOV.W &\RES2, R14 ; | |
207 | MOV.W &\RES3, R15 ; Ready high 16-bits for return | |
208 | .endm | |
209 | ||
210 | ||
7ed86ba5 | 211 | ;; EABI mandated names: |
212 | ;; | |
213 | ;; int16 __mspabi_mpyi (int16 x, int16 y) | |
214 | ;; Multiply int by int. | |
215 | ;; int16 __mspabi_mpyi_hw (int16 x, int16 y) | |
216 | ;; Multiply int by int. Uses hardware MPY16 or MPY32. | |
217 | ;; int16 __mspabi_mpyi_f5hw (int16 x, int16 y) | |
218 | ;; Multiply int by int. Uses hardware MPY32 (F5xx devices and up). | |
219 | ;; | |
220 | ;; int32 __mspabi_mpyl (int32 x, int32 y); | |
221 | ;; Multiply long by long. | |
222 | ;; int32 __mspabi_mpyl_hw (int32 x, int32 y) | |
223 | ;; Multiply long by long. Uses hardware MPY16. | |
224 | ;; int32 __mspabi_mpyl_hw32 (int32 x, int32 y) | |
225 | ;; Multiply long by long. Uses hardware MPY32 (F4xx devices). | |
226 | ;; int32 __mspabi_mpyl_f5hw (int32 x, int32 y) | |
227 | ;; Multiply long by long. Uses hardware MPY32 (F5xx devices and up). | |
228 | ;; | |
229 | ;; int64 __mspabi_mpyll (int64 x, int64 y) | |
230 | ;; Multiply long long by long long. | |
231 | ;; int64 __mspabi_mpyll_hw (int64 x, int64 y) | |
232 | ;; Multiply long long by long long. Uses hardware MPY16. | |
233 | ;; int64 __mspabi_mpyll_hw32 (int64 x, int64 y) | |
234 | ;; Multiply long long by long long. Uses hardware MPY32 (F4xx devices). | |
235 | ;; int64 __mspabi_mpyll_f5hw (int64 x, int64 y) | |
236 | ;; Multiply long long by long long. Uses hardware MPY32 (F5xx devices and up). | |
237 | ;; | |
238 | ;; int32 __mspabi_mpysl (int16 x, int16 y) | |
239 | ;; Multiply int by int; result is long. | |
240 | ;; int32 __mspabi_mpysl_hw(int16 x, int16 y) | |
241 | ;; Multiply int by int; result is long. Uses hardware MPY16 or MPY32 | |
242 | ;; int32 __mspabi_mpysl_f5hw(int16 x, int16 y) | |
243 | ;; Multiply int by int; result is long. Uses hardware MPY32 (F5xx devices and up). | |
244 | ;; | |
245 | ;; int64 __mspabi_mpysll(int32 x, int32 y) | |
246 | ;; Multiply long by long; result is long long. | |
247 | ;; int64 __mspabi_mpysll_hw(int32 x, int32 y) | |
248 | ;; Multiply long by long; result is long long. Uses hardware MPY16. | |
249 | ;; int64 __mspabi_mpysll_hw32(int32 x, int32 y) | |
250 | ;; Multiply long by long; result is long long. Uses hardware MPY32 (F4xx devices). | |
251 | ;; int64 __mspabi_mpysll_f5hw(int32 x, int32 y) | |
252 | ;; Multiply long by long; result is long long. Uses hardware MPY32 (F5xx devices and up). | |
253 | ;; | |
254 | ;; uint32 __mspabi_mpyul(uint16 x, uint16 y) | |
255 | ;; Multiply unsigned int by unsigned int; result is unsigned long. | |
256 | ;; uint32 __mspabi_mpyul_hw(uint16 x, uint16 y) | |
257 | ;; Multiply unsigned int by unsigned int; result is unsigned long. Uses hardware MPY16 or MPY32 | |
258 | ;; uint32 __mspabi_mpyul_f5hw(uint16 x, uint16 y) | |
259 | ;; Multiply unsigned int by unsigned int; result is unsigned long. Uses hardware MPY32 (F5xx devices and up). | |
260 | ;; | |
261 | ;; uint64 __mspabi_mpyull(uint32 x, uint32 y) | |
262 | ;; Multiply unsigned long by unsigned long; result is unsigned long long. | |
263 | ;; uint64 __mspabi_mpyull_hw(uint32 x, uint32 y) | |
264 | ;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY16 | |
265 | ;; uint64 __mspabi_mpyull_hw32(uint32 x, uint32 y) | |
266 | ;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F4xx devices). | |
267 | ;; uint64 _ _mspabi_mpyull_f5hw(uint32 x, uint32 y) | |
268 | ;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F5xx devices and up) | |
269 | ||
270 | ||
6dd4126d | 271 | |
272 | .set MPY_OP1, 0x0130 | |
273 | .set MPY_OP1_S, 0x0132 | |
274 | .set MAC_OP1, 0x0134 | |
275 | .set MPY_OP2, 0x0138 | |
276 | .set MAC_OP2, 0x0138 | |
277 | .set RESULT_LO, 0x013A | |
278 | .set RESULT_HI, 0x013C | |
7ed86ba5 | 279 | |
280 | #if defined MUL_16 | |
281 | ;; First generation MSP430 hardware multiplies ... | |
282 | ||
283 | start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw | |
6dd4126d | 284 | mult16 MPY_OP1, MPY_OP2, RESULT_LO |
7ed86ba5 | 285 | end_func __mulhi2 |
6dd4126d | 286 | |
7ed86ba5 | 287 | start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_hw |
6dd4126d | 288 | mult1632 MPY_OP1_S, MPY_OP2, RESULT_LO, RESULT_HI |
7ed86ba5 | 289 | end_func __mulsihi2 |
6dd4126d | 290 | |
7ed86ba5 | 291 | start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_hw |
6dd4126d | 292 | mult1632 MPY_OP1, MPY_OP2, RESULT_LO, RESULT_HI |
7ed86ba5 | 293 | end_func __umulsihi2 |
6dd4126d | 294 | |
7ed86ba5 | 295 | start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_hw |
6dd4126d | 296 | mult32 MPY_OP1, MPY_OP2, MAC_OP1, MAC_OP2, RESULT_LO, RESULT_HI |
7ed86ba5 | 297 | end_func __mulsi2 |
6dd4126d | 298 | |
7ed86ba5 | 299 | ;; FIXME: We do not have hardware implementations of these |
300 | ;; routines, so just jump to the software versions instead. | |
301 | fake_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_hw | |
302 | fake_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_hw | |
303 | fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw | |
304 | ||
305 | #elif defined MUL_32 | |
306 | ;; Second generation MSP430 hardware multiplies ... | |
307 | ||
308 | start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw | |
309 | mult16 MPY_OP1, MPY_OP2, RESULT_LO | |
310 | end_func __mulhi2 | |
311 | ||
312 | start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_hw | |
313 | mult1632 MPY_OP1_S, MPY_OP2, RESULT_LO, RESULT_HI | |
314 | end_func __mulsihi2 | |
315 | ||
316 | start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_hw | |
317 | mult1632 MPY_OP1, MPY_OP2, RESULT_LO, RESULT_HI | |
318 | end_func __umulsihi2 | |
319 | ||
320 | start_func __mulsi2_hw32 __mspabi_mpyl __mspabi_mpyl_hw32 | |
6dd4126d | 321 | mult32_hw 0x0140, 0x0142, 0x0150, 0x0152, 0x0154, 0x0156 |
7ed86ba5 | 322 | end_func __mulsi2_hw32 |
6dd4126d | 323 | |
7ed86ba5 | 324 | start_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_hw32 |
6dd4126d | 325 | mult3264_hw 0x0144, 0x146, 0x0150, 0x0152, 0x0154, 0x0156, 0x0158, 0x015A |
7ed86ba5 | 326 | end_func __muldisi2 |
6dd4126d | 327 | |
7ed86ba5 | 328 | start_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_hw32 |
6dd4126d | 329 | mult3264_hw 0x0140, 0x142, 0x0150, 0x0152, 0x0154, 0x0156, 0x0158, 0x015A |
7ed86ba5 | 330 | end_func __umuldisi2 |
331 | ||
332 | ;; FIXME: Add a hardware version of this function. | |
333 | fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw32 | |
6dd4126d | 334 | |
7ed86ba5 | 335 | #elif defined MUL_F5 |
336 | /* The F5xxx series of MCUs support the same 16-bit and 32-bit multiply | |
337 | as the second generation hardware, but they are accessed from different | |
338 | memory registers. */ | |
339 | ||
340 | start_func __mulhi2_f5 __mspabi_mpyi __mspabi_mpyi_f5hw | |
6dd4126d | 341 | mult16 0x04C0, 0x04C8, 0x04CA |
7ed86ba5 | 342 | end_func __mulhi2_f5 |
6dd4126d | 343 | |
7ed86ba5 | 344 | start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_f5hw |
6dd4126d | 345 | mult1632 0x04C2, 0x04C8, 0x04CA, 0x04CC |
7ed86ba5 | 346 | end_func __mulsihi2 |
6dd4126d | 347 | |
7ed86ba5 | 348 | start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_f5hw |
6dd4126d | 349 | mult1632 0x04C0, 0x04C8, 0x04CA, 0x04CC |
7ed86ba5 | 350 | end_func __umulsihi2 |
6dd4126d | 351 | |
7ed86ba5 | 352 | start_func __mulsi2_f5 __mspabi_mpyl __mspabi_mpyl_f5hw |
6dd4126d | 353 | mult32_hw 0x04D0, 0x04D2, 0x04E0, 0x04E2, 0x04E4, 0x04E6 |
7ed86ba5 | 354 | end_func __mulsi2_f5 |
6dd4126d | 355 | |
7ed86ba5 | 356 | start_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_f5hw |
6dd4126d | 357 | mult3264_hw 0x04D4, 0x04D6, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA |
7ed86ba5 | 358 | end_func __muldisi2 |
6dd4126d | 359 | |
7ed86ba5 | 360 | start_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_f5hw |
6dd4126d | 361 | mult3264_hw 0x04D0, 0x04D2, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA |
7ed86ba5 | 362 | end_func __umuldisi2 |
363 | ||
364 | ;; FIXME: Add a hardware version of this function. | |
365 | fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_f5hw | |
366 | ||
367 | #else | |
368 | #error MUL type not defined | |
369 | #endif |