1 ; Copyright (C) 2014-2024 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, RESLO, RESHI
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 &\RESLO, r12 ; Move low result into return register
131 MOV.W &\RESHI, r13 ; Move high result into return register
134 .macro mult32 OP1, OP2, MAC_OP1, MAC_OP2, RESLO, RESHI
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 &\RESLO, r12 ; Low 16-bits of result ready for return
153 MOV.W &\RESHI, &\RESLO ; 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 &\RESLO, r13 ; Upper 16-bits result ready for return
161 .macro mult32_hw OP1_LO OP1_HI OP2_LO OP2_HI RESLO RESHI
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 &\RESLO, r12 ; Ready low 16-bits for return
181 MOV.W &\RESHI, 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
210 .macro mult64_hw MPY32_LO MPY32_HI OP2_LO OP2_HI RES0 RES1 RES2 RES3
211 ;* * 64-bit hardware multiply with a 64-bit result
212 ;* int64 = int64 * int64
214 ;* - Operand 1 is in R8, R9, R10, R11
215 ;* - Operand 2 is in R12, R13, R14, R15
216 ;* - Result is in R12, R13, R14, R15
218 ;* 64-bit multiplication is achieved using the 32-bit hardware multiplier with
219 ;* the following equation:
220 ;* R12:R15 = (R8:R9 * R12:R13) + ((R8:R9 * R14:R15) << 32) + ((R10:R11 * R12:R13) << 32)
222 ;* The left shift by 32 is handled with minimal cost by saving the two low
223 ;* words and discarding the two high words.
225 ;* To ensure that the multiply is performed atomically, interrupts are
226 ;* disabled upon routine entry. Interrupt state is restored upon exit.
228 ;* Registers used: R6, R7, R8, R9, R10, R11, R12, R13, R14, R15
230 ;* Macro arguments are the memory locations of the hardware registers.
232 #if defined(__MSP430X_LARGE__)
234 #elif defined(__MSP430X__)
237 PUSH R10 { PUSH R9 { PUSH R8 { PUSH R7 { PUSH R6
239 ; Multiply the low 32-bits of op0 and the high 32-bits of op1.
244 ; Save the low 32-bits of the result.
247 ; Multiply the high 32-bits of op0 and the low 32-bits of op1.
248 MOV.W R10, &\MPY32_LO
249 MOV.W R11, &\MPY32_HI
252 ; Add the low 32-bits of the result to the previously saved result.
255 ; Multiply the low 32-bits of op0 and op1.
260 ; Write the return values
265 ; Add the saved low 32-bit results from earlier to the high 32-bits of
266 ; this result, effectively shifting those two results left by 32 bits.
269 #if defined(__MSP430X_LARGE__)
271 #elif defined(__MSP430X__)
274 POP R6 { POP R7 { POP R8 { POP R9 { POP R10
278 ;; EABI mandated names:
280 ;; int16 __mspabi_mpyi (int16 x, int16 y)
281 ;; Multiply int by int.
282 ;; int16 __mspabi_mpyi_hw (int16 x, int16 y)
283 ;; Multiply int by int. Uses hardware MPY16 or MPY32.
284 ;; int16 __mspabi_mpyi_f5hw (int16 x, int16 y)
285 ;; Multiply int by int. Uses hardware MPY32 (F5xx devices and up).
287 ;; int32 __mspabi_mpyl (int32 x, int32 y);
288 ;; Multiply long by long.
289 ;; int32 __mspabi_mpyl_hw (int32 x, int32 y)
290 ;; Multiply long by long. Uses hardware MPY16.
291 ;; int32 __mspabi_mpyl_hw32 (int32 x, int32 y)
292 ;; Multiply long by long. Uses hardware MPY32 (F4xx devices).
293 ;; int32 __mspabi_mpyl_f5hw (int32 x, int32 y)
294 ;; Multiply long by long. Uses hardware MPY32 (F5xx devices and up).
296 ;; int64 __mspabi_mpyll (int64 x, int64 y)
297 ;; Multiply long long by long long.
298 ;; int64 __mspabi_mpyll_hw (int64 x, int64 y)
299 ;; Multiply long long by long long. Uses hardware MPY16.
300 ;; int64 __mspabi_mpyll_hw32 (int64 x, int64 y)
301 ;; Multiply long long by long long. Uses hardware MPY32 (F4xx devices).
302 ;; int64 __mspabi_mpyll_f5hw (int64 x, int64 y)
303 ;; Multiply long long by long long. Uses hardware MPY32 (F5xx devices and up).
305 ;; int32 __mspabi_mpysl (int16 x, int16 y)
306 ;; Multiply int by int; result is long.
307 ;; int32 __mspabi_mpysl_hw(int16 x, int16 y)
308 ;; Multiply int by int; result is long. Uses hardware MPY16 or MPY32
309 ;; int32 __mspabi_mpysl_f5hw(int16 x, int16 y)
310 ;; Multiply int by int; result is long. Uses hardware MPY32 (F5xx devices and up).
312 ;; int64 __mspabi_mpysll(int32 x, int32 y)
313 ;; Multiply long by long; result is long long.
314 ;; int64 __mspabi_mpysll_hw(int32 x, int32 y)
315 ;; Multiply long by long; result is long long. Uses hardware MPY16.
316 ;; int64 __mspabi_mpysll_hw32(int32 x, int32 y)
317 ;; Multiply long by long; result is long long. Uses hardware MPY32 (F4xx devices).
318 ;; int64 __mspabi_mpysll_f5hw(int32 x, int32 y)
319 ;; Multiply long by long; result is long long. Uses hardware MPY32 (F5xx devices and up).
321 ;; uint32 __mspabi_mpyul(uint16 x, uint16 y)
322 ;; Multiply unsigned int by unsigned int; result is unsigned long.
323 ;; uint32 __mspabi_mpyul_hw(uint16 x, uint16 y)
324 ;; Multiply unsigned int by unsigned int; result is unsigned long. Uses hardware MPY16 or MPY32
325 ;; uint32 __mspabi_mpyul_f5hw(uint16 x, uint16 y)
326 ;; Multiply unsigned int by unsigned int; result is unsigned long. Uses hardware MPY32 (F5xx devices and up).
328 ;; uint64 __mspabi_mpyull(uint32 x, uint32 y)
329 ;; Multiply unsigned long by unsigned long; result is unsigned long long.
330 ;; uint64 __mspabi_mpyull_hw(uint32 x, uint32 y)
331 ;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY16
332 ;; uint64 __mspabi_mpyull_hw32(uint32 x, uint32 y)
333 ;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F4xx devices).
334 ;; uint64 __mspabi_mpyull_f5hw(uint32 x, uint32 y)
335 ;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F5xx devices and up)
337 ;;;; The register names below are the standardised versions used across TI
340 ;; Hardware multiply register addresses for devices with 16-bit hardware
348 ;; Hardware multiply register addresses for devices with 32-bit (non-f5)
349 ;; hardware multiply.
360 ;; Hardware multiply register addresses for devices with f5series hardware
362 ;; The F5xxx series of MCUs support the same 16-bit and 32-bit multiply
363 ;; as the second generation hardware, but they are accessed from different
365 ;; These names AREN'T standard. We've appended _F5 to the standard names.
370 .set RESLO_F5, 0x04CA
371 .set RESHI_F5, 0x04CC
372 .set MPY32L_F5, 0x04D0
373 .set MPY32H_F5, 0x04D2
374 .set MPYS32L_F5, 0x04D4
375 .set MPYS32H_F5, 0x04D6
384 ;; First generation MSP430 hardware multiplies ...
386 start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw
387 mult16 MPY, OP2, RESLO
390 start_func __mulhisi2 __mspabi_mpysl __mspabi_mpysl_hw
391 mult1632 MPYS, OP2, RESLO, RESHI
394 start_func __umulhisi2 __mspabi_mpyul __mspabi_mpyul_hw
395 mult1632 MPY, OP2, RESLO, RESHI
398 start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_hw
399 mult32 MPY, OP2, MAC, OP2, RESLO, RESHI
402 ;; FIXME: We do not have hardware implementations of these
403 ;; routines, so just jump to the software versions instead.
404 fake_func __mulsidi2 __mspabi_mpysll __mspabi_mpysll_hw
405 fake_func __umulsidi2 __mspabi_mpyull __mspabi_mpyull_hw
406 fake_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw
409 ;; Second generation MSP430 hardware multiplies ...
411 start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw
412 mult16 MPY, OP2, RESLO
415 start_func __mulhisi2 __mspabi_mpysl __mspabi_mpysl_hw
416 mult1632 MPYS, OP2, RESLO, RESHI
419 start_func __umulhisi2 __mspabi_mpyul __mspabi_mpyul_hw
420 mult1632 MPY, OP2, RESLO, RESHI
423 start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_hw32
424 mult32_hw MPY32L, MPY32H, OP2L, OP2H, RES0, RES1
427 start_func __mulsidi2 __mspabi_mpysll __mspabi_mpysll_hw32
428 mult3264_hw MPYS32L, MPYS32H, OP2L, OP2H, RES0, RES1, RES2, RES3
431 start_func __umulsidi2 __mspabi_mpyull __mspabi_mpyull_hw32
432 mult3264_hw MPY32L, MPY32H, OP2L, OP2H, RES0, RES1, RES2, RES3
435 start_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw32
436 mult64_hw MPY32L, MPY32H, OP2L, OP2H, RES0, RES1, RES2, RES3
440 /* The F5xxx series of MCUs support the same 16-bit and 32-bit multiply
441 as the second generation hardware, but they are accessed from different
444 start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_f5hw
445 mult16 MPY_F5, OP2_F5, RESLO_F5
448 start_func __mulhisi2 __mspabi_mpysl __mspabi_mpysl_f5hw
449 mult1632 MPYS_F5, OP2_F5, RESLO_F5, RESHI_F5
452 start_func __umulhisi2 __mspabi_mpyul __mspabi_mpyul_f5hw
453 mult1632 MPY_F5, OP2_F5, RESLO_F5, RESHI_F5
456 start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_f5hw
457 mult32_hw MPY32L_F5, MPY32H_F5, OP2L_F5, OP2H_F5, RES0_F5, RES1_F5
460 start_func __mulsidi2 __mspabi_mpysll __mspabi_mpysll_f5hw
461 mult3264_hw MPYS32L_F5, MPYS32H_F5, OP2L_F5, OP2H_F5, RES0_F5, RES1_F5, RES2_F5, RES3_F5
464 start_func __umulsidi2 __mspabi_mpyull __mspabi_mpyull_f5hw
465 mult3264_hw MPY32L_F5, MPY32H_F5, OP2L_F5, OP2H_F5, RES0_F5, RES1_F5, RES2_F5, RES3_F5
468 start_func __muldi3 __mspabi_mpyll __mspabi_mpyll_f5hw
469 mult64_hw MPY32L_F5, MPY32H_F5, OP2L_F5, OP2H_F5, RES0_F5, RES1_F5, RES2_F5, RES3_F5
473 #error MUL type not defined