1 ; Copyright (C) 2014-2018 Free Software Foundation, Inc.
2 ; Contributed by Red Hat.
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
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.
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.
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/>.
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.
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.
37 ;; We construct each function in its own section so that linker
38 ;; garbage collection can be used to delete any unused functions
40 .macro start_func gcc_name eabi_soft_name eabi_hard_name
41 .pushsection .text.\gcc_name,"ax",@progbits
43 .global \eabi_hard_name
44 .type \eabi_hard_name , @function
46 .global \eabi_soft_name
47 .type \eabi_soft_name , @function
50 .type \gcc_name , @function
52 PUSH.W sr ; Save current interrupt state
53 DINT ; Disable interrupts
54 NOP ; Account for latency
58 ;; End a function started with the start_func macro.
60 #ifdef __MSP430X_LARGE__
66 .size \name , . - \name
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
77 .global \eabi_hard_name
78 .type \eabi_hard_name , @function
81 .type \gcc_name , @function
83 #ifdef __MSP430X_LARGE__
88 .size \gcc_name , . - \gcc_name
93 .macro mult16 OP1, OP2, RESULT
94 ;* * 16-bit hardware multiply: int16 = int16 * int16
96 ;* - Operand 1 is in R12
97 ;* - Operand 2 is in R13
100 ;* To ensure that the multiply is performed atomically, interrupts are
101 ;* disabled upon routine entry. Interrupt state is restored upon exit.
103 ;* Registers used: R12, R13
105 ;* Macro arguments are the memory locations of the hardware registers.
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
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
117 ;* - Operand 1 is in R12
118 ;* - Operand 2 is in R13
119 ;* - Result is in R12, R13
121 ;* To ensure that the multiply is performed atomically, interrupts are
122 ;* disabled upon routine entry. Interrupt state is restored upon exit.
124 ;* Registers used: R12, R13
126 ;* Macro arguments are the memory locations of the hardware registers.
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
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
138 ;* - Operand 1 is in R12, R13
139 ;* - Operand 2 is in R14, R15
140 ;* - Result is in R12, R13
142 ;* To ensure that the multiply is performed atomically, interrupts are
143 ;* disabled upon routine entry. Interrupt state is restored upon exit.
145 ;* Registers used: R12, R13, R14, R15
147 ;* Macro arguments are the memory locations of the hardware registers.
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
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
165 ;* - Operand 1 is in R12, R13
166 ;* - Operand 2 is in R14, R15
167 ;* - Result is in R12, R13
169 ;* To ensure that the multiply is performed atomically, interrupts are
170 ;* disabled upon routine entry. Interrupt state is restored upon exit.
172 ;* Registers used: R12, R13, R14, R15
174 ;* Macro arguments are the memory locations of the hardware registers.
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
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
189 ;* - Operand 1 is in R12, R13
190 ;* - Operand 2 is in R14, R15
191 ;* - Result is in R12, R13, R14, R15
193 ;* To ensure that the multiply is performed atomically, interrupts are
194 ;* disabled upon routine entry. Interrupt state is restored upon exit.
196 ;* Registers used: R12, R13, R14, R15
198 ;* Macro arguments are the memory locations of the hardware registers.
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
207 MOV.W &\RES3, R15 ; Ready high 16-bits for return
211 ;; EABI mandated names:
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).
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).
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).
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).
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).
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).
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)
273 .set MPY_OP1_S, 0x0132
277 .set RESULT_LO, 0x013A
278 .set RESULT_HI, 0x013C
281 ;; First generation MSP430 hardware multiplies ...
283 start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw
284 mult16 MPY_OP1, MPY_OP2, RESULT_LO
287 start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_hw
288 mult1632 MPY_OP1_S, MPY_OP2, RESULT_LO, RESULT_HI
291 start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_hw
292 mult1632 MPY_OP1, MPY_OP2, RESULT_LO, RESULT_HI
295 start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_hw
296 mult32 MPY_OP1, MPY_OP2, MAC_OP1, MAC_OP2, RESULT_LO, RESULT_HI
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
306 ;; Second generation MSP430 hardware multiplies ...
308 start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw
309 mult16 MPY_OP1, MPY_OP2, RESULT_LO
312 start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_hw
313 mult1632 MPY_OP1_S, MPY_OP2, RESULT_LO, RESULT_HI
316 start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_hw
317 mult1632 MPY_OP1, MPY_OP2, RESULT_LO, RESULT_HI
320 start_func __mulsi2_hw32 __mspabi_mpyl __mspabi_mpyl_hw32
321 mult32_hw 0x0140, 0x0142, 0x0150, 0x0152, 0x0154, 0x0156
322 end_func __mulsi2_hw32
324 start_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_hw32
325 mult3264_hw 0x0144, 0x146, 0x0150, 0x0152, 0x0154, 0x0156, 0x0158, 0x015A
328 start_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_hw32
329 mult3264_hw 0x0140, 0x142, 0x0150, 0x0152, 0x0154, 0x0156, 0x0158, 0x015A
332 ;; FIXME: Add a hardware version of this function.
333 fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw32
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
340 start_func __mulhi2_f5 __mspabi_mpyi __mspabi_mpyi_f5hw
341 mult16 0x04C0, 0x04C8, 0x04CA
344 start_func __mulsihi2 __mspabi_mpysl __mspabi_mpysl_f5hw
345 mult1632 0x04C2, 0x04C8, 0x04CA, 0x04CC
348 start_func __umulsihi2 __mspabi_mpyul _mspabi_mpyul_f5hw
349 mult1632 0x04C0, 0x04C8, 0x04CA, 0x04CC
352 start_func __mulsi2_f5 __mspabi_mpyl __mspabi_mpyl_f5hw
353 mult32_hw 0x04D0, 0x04D2, 0x04E0, 0x04E2, 0x04E4, 0x04E6
356 start_func __muldisi2 __mspabi_mpysll __mspabi_mpysll_f5hw
357 mult3264_hw 0x04D4, 0x04D6, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA
360 start_func __umuldisi2 __mspabi_mpyull __mspabi_mpyull_f5hw
361 mult3264_hw 0x04D0, 0x04D2, 0x04E0, 0x04E2, 0x04E4, 0x04E6, 0x04E8, 0x04EA
364 ;; FIXME: Add a hardware version of this function.
365 fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_f5hw
368 #error MUL type not defined