]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/msp430/lib2hw_mul.S
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / msp430 / lib2hw_mul.S
CommitLineData
7adcbafe 1; Copyright (C) 2014-2022 Free Software Foundation, Inc.
df2b279c
NC
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
04a9ae28
NC
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
9afebea2 42 .p2align 1
04a9ae28
NC
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:
df2b279c
NC
52 PUSH.W sr ; Save current interrupt state
53 DINT ; Disable interrupts
54 NOP ; Account for latency
55.endm
56
04a9ae28
NC
57
58 ;; End a function started with the start_func macro.
df2b279c
NC
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
04a9ae28
NC
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__
91c64455 84 BRA #\eabi_soft_name
04a9ae28 85#else
91c64455 86 BR #\eabi_soft_name
04a9ae28
NC
87#endif
88 .size \gcc_name , . - \gcc_name
89 .popsection
90.endm
91
92
df2b279c
NC
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
91c64455 112.macro mult1632 OP1, OP2, RESLO, RESHI
df2b279c
NC
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
91c64455
JL
130 MOV.W &\RESLO, r12 ; Move low result into return register
131 MOV.W &\RESHI, r13 ; Move high result into return register
df2b279c
NC
132.endm
133
91c64455 134.macro mult32 OP1, OP2, MAC_OP1, MAC_OP2, RESLO, RESHI
df2b279c
NC
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
91c64455
JL
152 MOV.W &\RESLO, r12 ; Low 16-bits of result ready for return
153 MOV.W &\RESHI, &\RESLO ; MOV intermediate mpy high into low
df2b279c
NC
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
91c64455 157 MOV.W &\RESLO, r13 ; Upper 16-bits result ready for return
df2b279c
NC
158.endm
159
160
91c64455 161.macro mult32_hw OP1_LO OP1_HI OP2_LO OP2_HI RESLO RESHI
df2b279c
NC
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
91c64455
JL
180 MOV.W &\RESLO, r12 ; Ready low 16-bits for return
181 MOV.W &\RESHI, r13 ; Ready high 16-bits for return
df2b279c
NC
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
bf7b94d4
JL
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
213;*
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
217;*
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)
221;*
222;* The left shift by 32 is handled with minimal cost by saving the two low
223;* words and discarding the two high words.
224;*
225;* To ensure that the multiply is performed atomically, interrupts are
226;* disabled upon routine entry. Interrupt state is restored upon exit.
227;*
228;* Registers used: R6, R7, R8, R9, R10, R11, R12, R13, R14, R15
229;*
230;* Macro arguments are the memory locations of the hardware registers.
231;*
232#if defined(__MSP430X_LARGE__)
233 PUSHM.A #5, R10
234#elif defined(__MSP430X__)
235 PUSHM.W #5, R10
236#else
237 PUSH R10 { PUSH R9 { PUSH R8 { PUSH R7 { PUSH R6
238#endif
239 ; Multiply the low 32-bits of op0 and the high 32-bits of op1.
240 MOV.W R8, &\MPY32_LO
241 MOV.W R9, &\MPY32_HI
242 MOV.W R14, &\OP2_LO
243 MOV.W R15, &\OP2_HI
244 ; Save the low 32-bits of the result.
245 MOV.W &\RES0, R6
246 MOV.W &\RES1, R7
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
250 MOV.W R12, &\OP2_LO
251 MOV.W R13, &\OP2_HI
252 ; Add the low 32-bits of the result to the previously saved result.
253 ADD.W &\RES0, R6
254 ADDC.W &\RES1, R7
255 ; Multiply the low 32-bits of op0 and op1.
256 MOV.W R8, &\MPY32_LO
257 MOV.W R9, &\MPY32_HI
258 MOV.W R12, &\OP2_LO
259 MOV.W R13, &\OP2_HI
260 ; Write the return values
261 MOV.W &\RES0, R12
262 MOV.W &\RES1, R13
263 MOV.W &\RES2, R14
264 MOV.W &\RES3, R15
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.
267 ADD.W R6, R14
268 ADDC.W R7, R15
269#if defined(__MSP430X_LARGE__)
270 POPM.A #5, R10
271#elif defined(__MSP430X__)
272 POPM.W #5, R10
273#else
274 POP R6 { POP R7 { POP R8 { POP R9 { POP R10
275#endif
276.endm
df2b279c 277
04a9ae28
NC
278;; EABI mandated names:
279;;
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).
286;;
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).
295;;
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).
304;;
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).
311;;
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).
320;;
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).
327;;
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).
91c64455 334;; uint64 __mspabi_mpyull_f5hw(uint32 x, uint32 y)
04a9ae28
NC
335;; Multiply unsigned long by unsigned long; result is unsigned long long. Uses hardware MPY32 (F5xx devices and up)
336
91c64455
JL
337;;;; The register names below are the standardised versions used across TI
338;;;; literature.
339
340;; Hardware multiply register addresses for devices with 16-bit hardware
341;; multiply.
342.set MPY, 0x0130
343.set MPYS, 0x0132
344.set MAC, 0x0134
345.set OP2, 0x0138
346.set RESLO, 0x013A
347.set RESHI, 0x013C
348;; Hardware multiply register addresses for devices with 32-bit (non-f5)
349;; hardware multiply.
350.set MPY32L, 0x0140
351.set MPY32H, 0x0142
352.set MPYS32L, 0x0144
353.set MPYS32H, 0x0146
354.set OP2L, 0x0150
355.set OP2H, 0x0152
356.set RES0, 0x0154
357.set RES1, 0x0156
358.set RES2, 0x0158
359.set RES3, 0x015A
360;; Hardware multiply register addresses for devices with f5series hardware
361;; multiply.
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
364;; memory registers.
365;; These names AREN'T standard. We've appended _F5 to the standard names.
366.set MPY_F5, 0x04C0
367.set MPYS_F5, 0x04C2
368.set MAC_F5, 0x04C4
369.set OP2_F5, 0x04C8
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
376.set OP2L_F5, 0x04E0
377.set OP2H_F5, 0x04E2
378.set RES0_F5, 0x04E4
379.set RES1_F5, 0x04E6
380.set RES2_F5, 0x04E8
381.set RES3_F5, 0x04EA
04a9ae28
NC
382
383#if defined MUL_16
384;; First generation MSP430 hardware multiplies ...
385
386 start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw
91c64455 387 mult16 MPY, OP2, RESLO
04a9ae28 388 end_func __mulhi2
df2b279c 389
91c64455
JL
390 start_func __mulhisi2 __mspabi_mpysl __mspabi_mpysl_hw
391 mult1632 MPYS, OP2, RESLO, RESHI
392 end_func __mulhisi2
df2b279c 393
91c64455
JL
394 start_func __umulhisi2 __mspabi_mpyul __mspabi_mpyul_hw
395 mult1632 MPY, OP2, RESLO, RESHI
396 end_func __umulhisi2
df2b279c 397
04a9ae28 398 start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_hw
91c64455 399 mult32 MPY, OP2, MAC, OP2, RESLO, RESHI
04a9ae28 400 end_func __mulsi2
df2b279c 401
04a9ae28
NC
402 ;; FIXME: We do not have hardware implementations of these
403 ;; routines, so just jump to the software versions instead.
91c64455
JL
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
04a9ae28
NC
407
408#elif defined MUL_32
409;; Second generation MSP430 hardware multiplies ...
410
411 start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_hw
91c64455 412 mult16 MPY, OP2, RESLO
04a9ae28
NC
413 end_func __mulhi2
414
91c64455
JL
415 start_func __mulhisi2 __mspabi_mpysl __mspabi_mpysl_hw
416 mult1632 MPYS, OP2, RESLO, RESHI
417 end_func __mulhisi2
04a9ae28 418
91c64455
JL
419 start_func __umulhisi2 __mspabi_mpyul __mspabi_mpyul_hw
420 mult1632 MPY, OP2, RESLO, RESHI
421 end_func __umulhisi2
04a9ae28 422
c746fc40 423 start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_hw32
91c64455 424 mult32_hw MPY32L, MPY32H, OP2L, OP2H, RES0, RES1
c746fc40 425 end_func __mulsi2
df2b279c 426
91c64455
JL
427 start_func __mulsidi2 __mspabi_mpysll __mspabi_mpysll_hw32
428 mult3264_hw MPYS32L, MPYS32H, OP2L, OP2H, RES0, RES1, RES2, RES3
429 end_func __mulsidi2
df2b279c 430
91c64455
JL
431 start_func __umulsidi2 __mspabi_mpyull __mspabi_mpyull_hw32
432 mult3264_hw MPY32L, MPY32H, OP2L, OP2H, RES0, RES1, RES2, RES3
433 end_func __umulsidi2
04a9ae28 434
bf7b94d4
JL
435 start_func __muldi3 __mspabi_mpyll __mspabi_mpyll_hw32
436 mult64_hw MPY32L, MPY32H, OP2L, OP2H, RES0, RES1, RES2, RES3
437 end_func __muldi3
91c64455 438
04a9ae28
NC
439#elif defined MUL_F5
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
442 memory registers. */
443
c746fc40 444 start_func __mulhi2 __mspabi_mpyi __mspabi_mpyi_f5hw
91c64455 445 mult16 MPY_F5, OP2_F5, RESLO_F5
c746fc40 446 end_func __mulhi2
df2b279c 447
91c64455
JL
448 start_func __mulhisi2 __mspabi_mpysl __mspabi_mpysl_f5hw
449 mult1632 MPYS_F5, OP2_F5, RESLO_F5, RESHI_F5
450 end_func __mulhisi2
451
452 start_func __umulhisi2 __mspabi_mpyul __mspabi_mpyul_f5hw
453 mult1632 MPY_F5, OP2_F5, RESLO_F5, RESHI_F5
454 end_func __umulhisi2
df2b279c 455
c746fc40 456 start_func __mulsi2 __mspabi_mpyl __mspabi_mpyl_f5hw
91c64455 457 mult32_hw MPY32L_F5, MPY32H_F5, OP2L_F5, OP2H_F5, RES0_F5, RES1_F5
c746fc40 458 end_func __mulsi2
91c64455
JL
459
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
462 end_func __mulsidi2
463
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
466 end_func __umulsidi2
04a9ae28 467
bf7b94d4
JL
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
470 end_func __muldi3
04a9ae28
NC
471
472#else
473#error MUL type not defined
474#endif