YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
double_aeabi.S
1/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "asm_helper.S"
8#include "sf_table.h"
9#include "divider_helper.S"
10
11__pre_init __aeabi_double_init, 00020
12
13.syntax unified
14.cpu cortex-m0plus
15.thumb
16
17.macro double_section name
18#if PICO_DOUBLE_IN_RAM
19.section RAM_SECTION_NAME(\name), "ax"
20#else
21.section SECTION_NAME(\name), "ax"
22#endif
23.endm
24
25.macro _double_wrapper_func x
26 wrapper_func \x
27.endm
28
29.macro wrapper_func_d1 x
30 _double_wrapper_func \x
31#if PICO_DOUBLE_PROPAGATE_NANS
32 mov ip, lr
33 bl __check_nan_d1
34 mov lr, ip
35#endif
36.endm
37
38.macro wrapper_func_d2 x
39 _double_wrapper_func \x
40#if PICO_DOUBLE_PROPAGATE_NANS
41 mov ip, lr
42 bl __check_nan_d2
43 mov lr, ip
44#endif
45.endm
46
47.section .text
48
49#if PICO_DOUBLE_PROPAGATE_NANS
50.thumb_func
51__check_nan_d1:
52 movs r3, #1
53 lsls r3, #21
54 lsls r2, r1, #1
55 adds r2, r3
56 bhi 1f
57 bx lr
581:
59 bx ip
60
61.thumb_func
62__check_nan_d2:
63 push {r0, r2}
64 movs r2, #1
65 lsls r2, #21
66 lsls r0, r1, #1
67 adds r0, r2
68 bhi 1f
69 lsls r0, r3, #1
70 adds r0, r2
71 bhi 2f
72 pop {r0, r2}
73 bx lr
742:
75 pop {r0, r2}
76 mov r0, r2
77 mov r1, r3
78 bx ip
791:
80 pop {r0, r2}
81 bx ip
82#endif
83
84.macro table_tail_call SF_TABLE_OFFSET
85 push {r3, r4}
86#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
87#ifndef NDEBUG
88 movs r3, #0
89 mov ip, r3
90#endif
91#endif
92 ldr r3, =sd_table
93 ldr r3, [r3, #\SF_TABLE_OFFSET]
94 str r3, [sp, #4]
95 pop {r3, pc}
96.endm
97
98.macro shimmable_table_tail_call SF_TABLE_OFFSET shim
99 push {r3, r4}
100 ldr r3, =sd_table
101 ldr r3, [r3, #\SF_TABLE_OFFSET]
102#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
103 mov ip, pc
104#endif
105 str r3, [sp, #4]
106 pop {r3, pc}
107#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
108.byte \SF_TABLE_OFFSET, 0xdf
109.word \shim
110#endif
111.endm
112
113.macro double_wrapper_section func
114double_section WRAPPER_FUNC_NAME(\func)
115.endm
116
117double_section push_r8_r11
118regular_func push_r8_r11
119 mov r4,r8
120 mov r5,r9
121 mov r6,r10
122 mov r7,r11
123 push {r4-r7}
124 bx r14
125
126double_section pop_r8_r11
127regular_func pop_r8_r11
128 pop {r4-r7}
129 mov r8,r4
130 mov r9,r5
131 mov r10,r6
132 mov r11,r7
133 bx r14
134
135// note generally each function is in a separate section unless there is fall thru or branching between them
136// note fadd, fsub, fmul, fdiv are so tiny and just defer to rom so are lumped together so they can share constant pool
137
138// note functions are word aligned except where they are an odd number of linear instructions
139
140// double FUNC_NAME(__aeabi_dadd)(double, double) double-precision addition
141double_wrapper_section __aeabi_darithmetic
142// double FUNC_NAME(__aeabi_drsub)(double x, double y) double-precision reverse subtraction, y - x
143
144// frsub first because it is the only one that needs alignment
145.align 2
146wrapper_func __aeabi_drsub
147 eors r0, r1
148 eors r1, r0
149 eors r0, r1
150 // fall thru
151
152// double FUNC_NAME(__aeabi_dsub)(double x, double y) double-precision subtraction, x - y
153wrapper_func_d2 __aeabi_dsub
154#if PICO_DOUBLE_PROPAGATE_NANS
155 // we want to return nan for inf-inf or -inf - -inf, but without too much upfront cost
156 mov ip, r0
157 mov r0, r1
158 eors r0, r3
159 bmi 1f // different signs
160 mov r0, ip
161 push {r0-r3, lr}
162 bl 2f
163 b ddiv_dsub_nan_helper
1641:
165 mov r0, ip
1662:
167#endif
168 shimmable_table_tail_call SF_TABLE_FSUB dsub_shim
169
170wrapper_func_d2 __aeabi_dadd
171 shimmable_table_tail_call SF_TABLE_FADD dadd_shim
172
173// double FUNC_NAME(__aeabi_ddiv)(double n, double d) double-precision division, n / d
174wrapper_func_d2 __aeabi_ddiv
175#if PICO_DOUBLE_PROPAGATE_NANS
176 push {r0-r3, lr}
177 bl 1f
178 b ddiv_dsub_nan_helper
1791:
180#endif
181#if !PICO_DIVIDER_DISABLE_INTERRUPTS
182 // to support IRQ usage (or context switch) we must save/restore divider state around call if state is dirty
183 mov ip, r2
184 ldr r2, =(SIO_BASE)
185 ldr r2, [r2, #SIO_DIV_CSR_OFFSET]
186 lsrs r2, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
187 bcs ddiv_save_state
188 mov r2, ip
189#else
190 // to avoid worrying about IRQs (or context switches), simply disable interrupts around call
191 push {r4, lr}
192 mrs r4, PRIMASK
193 cpsid i
194 bl ddiv_shim_call
195 msr PRIMASK, r4
196 pop {r4, pc}
197#endif
198ddiv_shim_call:
199 shimmable_table_tail_call SF_TABLE_FDIV ddiv_shim
200
201#if !PICO_DIVIDER_DISABLE_INTERRUPTS
202ddiv_save_state:
203 ldr r2, =(SIO_BASE)
204 save_div_state_and_lr
205 mov r2, ip
206 bl ddiv_shim_call
207 ldr r2, =(SIO_BASE)
208 restore_div_state_and_return
209#endif
210
211ddiv_dsub_nan_helper:
212#if PICO_DOUBLE_PROPAGATE_NANS
213 // check for infinite op infinite (or rather check for infinite result with both
214 // operands being infinite)
215 lsls r2, r1, #1
216 asrs r2, r2, #21
217 adds r2, #1
218 beq 2f
219 add sp, #16
220 pop {pc}
2212:
222 ldr r2, [sp, #4]
223 ldr r3, [sp, #12]
224 lsls r2, #1
225 asrs r2, r2, #21
226 lsls r3, #1
227 asrs r3, r3, #24
228 ands r2, r3
229 adds r2, #1
230 bne 3f
231 // infinite to nan
232 movs r2, #1
233 lsls r2, #19
234 orrs r1, r2
2353:
236 add sp, #16
237 pop {pc}
238#endif
239
240// double FUNC_NAME(__aeabi_dmul)(double, double) double-precision multiplication
241wrapper_func_d2 __aeabi_dmul
242#if PICO_DOUBLE_PROPAGATE_NANS
243 push {r0-r3, lr}
244 bl 1f
245
246 // check for multiplication of infinite by zero (or rather check for infinite result with either
247 // operand 0)
248 lsls r3, r1, #1
249 asrs r3, r3, #21
250 adds r3, #1
251 beq 2f
252 add sp, #16
253 pop {pc}
2542:
255 ldr r2, [sp, #4]
256 ldr r3, [sp, #12]
257 ands r2, r3
258 bne 3f
259 // infinite to nan
260 movs r2, #1
261 lsls r2, #19
262 orrs r1, r2
2633:
264 add sp, #16
265 pop {pc}
2661:
267#endif
268 shimmable_table_tail_call SF_TABLE_FMUL dmul_shim
269
270// void FUNC_NAME(__aeabi_cdrcmple)(double, double) reversed 3-way (<, =, ?>) compare [1], result in PSR ZC flags
271double_wrapper_section __aeabi_cdcmple
272
273wrapper_func __aeabi_cdrcmple
274 push {r0-r7,r14}
275 eors r0, r2
276 eors r2, r0
277 eors r0, r2
278 eors r1, r3
279 eors r3, r1
280 eors r1, r3
281 b __aeabi_dfcmple_guts
282
283// NOTE these share an implementation as we have no excepting NaNs.
284// void FUNC_NAME(__aeabi_cdcmple)(double, double) 3-way (<, =, ?>) compare [1], result in PSR ZC flags
285// void FUNC_NAME(__aeabi_cdcmpeq)(double, double) non-excepting equality comparison [1], result in PSR ZC flags
286@ compare r0:r1 against r2:r3, returning -1/0/1 for <, =, >
287@ also set flags accordingly
288.align 2
289wrapper_func __aeabi_cdcmple
290wrapper_func __aeabi_cdcmpeq
291 push {r0-r7,r14}
292__aeabi_dfcmple_guts:
293 ldr r7,=0x7ff @ flush NaNs and denormals
294 lsls r4,r1,#1
295 lsrs r4,#21
296 beq 1f
297 cmp r4,r7
298 bne 2f
299 lsls r4, r1, #12
300 bhi 7f
3011:
302 movs r0,#0
303 lsrs r1,#20
304 lsls r1,#20
3052:
306 lsls r4,r3,#1
307 lsrs r4,#21
308 beq 1f
309 cmp r4,r7
310 bne 2f
311 lsls r4, r3, #12
312 bhi 7f
3131:
314 movs r2,#0
315 lsrs r3,#20
316 lsls r3,#20
3172:
318 movs r6,#1
319 eors r3,r1
320 bmi 4f @ opposite signs? then can proceed on basis of sign of x
321 eors r3,r1 @ restore r3
322 bpl 2f
323 cmp r3,r1
324 bne 7f
3251:
326 cmp r2,r0
3277:
328 pop {r0-r7,r15}
3292:
330 cmp r1,r3
331 bne 7b
3321:
333 cmp r0,r2
334 pop {r0-r7,r15}
3354:
336 orrs r3,r1 @ make -0==+0
337 adds r3,r3
338 orrs r3,r0
339 orrs r3,r2
340 beq 7b
341 mvns r1, r1 @ carry inverse of r1 sign
342 adds r1, r1
343 pop {r0-r7,r15}
344
345
346// int FUNC_NAME(__aeabi_dcmpeq)(double, double) result (1, 0) denotes (=, ?<>) [2], use for C == and !=
347double_wrapper_section __aeabi_dcmpeq
348.align 2
349wrapper_func __aeabi_dcmpeq
350 push {lr}
351 bl __aeabi_cdcmpeq
352 beq 1f
353 movs r0, #0
354 pop {pc}
3551:
356 movs r0, #1
357 pop {pc}
358
359// int FUNC_NAME(__aeabi_dcmplt)(double, double) result (1, 0) denotes (<, ?>=) [2], use for C <
360double_wrapper_section __aeabi_dcmplt
361.align 2
362wrapper_func __aeabi_dcmplt
363 push {lr}
364 bl __aeabi_cdcmple
365 sbcs r0, r0
366 pop {pc}
367
368// int FUNC_NAME(__aeabi_dcmple)(double, double) result (1, 0) denotes (<=, ?>) [2], use for C <=
369double_wrapper_section __aeabi_dcmple
370.align 2
371wrapper_func __aeabi_dcmple
372 push {lr}
373 bl __aeabi_cdcmple
374 bls 1f
375 movs r0, #0
376 pop {pc}
3771:
378 movs r0, #1
379 pop {pc}
380
381// int FUNC_NAME(__aeabi_dcmpge)(double, double) result (1, 0) denotes (>=, ?<) [2], use for C >=
382double_wrapper_section __aeabi_dcmpge
383.align 2
384wrapper_func __aeabi_dcmpge
385 push {lr}
386 // because of NaNs it is better to reverse the args than the result
387 bl __aeabi_cdrcmple
388 bls 1f
389 movs r0, #0
390 pop {pc}
3911:
392 movs r0, #1
393 pop {pc}
394
395// int FUNC_NAME(__aeabi_dcmpgt)(double, double) result (1, 0) denotes (>, ?<=) [2], use for C >
396double_wrapper_section __aeabi_dcmpgt
397wrapper_func __aeabi_dcmpgt
398 push {lr}
399 // because of NaNs it is better to reverse the args than the result
400 bl __aeabi_cdrcmple
401 sbcs r0, r0
402 pop {pc}
403
404// int FUNC_NAME(__aeabi_dcmpun)(double, double) result (1, 0) denotes (?, <=>) [2], use for C99 isunordered()
405double_wrapper_section __aeabi_dcmpun
406wrapper_func __aeabi_dcmpun
407 movs r0, #1
408 lsls r0, #21
409 lsls r2, r1, #1
410 adds r2, r0
411 bhi 1f
412 lsls r2, r3, #1
413 adds r2, r0
414 bhi 1f
415 movs r0, #0
416 bx lr
4171:
418 movs r0, #1
419 bx lr
420
421 movs r0, #0
422 bx lr
423
424// double FUNC_NAME(__aeabi_ui2d)(unsigned) unsigned to double (double precision) conversion
425double_wrapper_section __aeabi_ui2d
426 shimmable_table_tail_call SF_TABLE_UINT2FLOAT uint2double_shim
427
428double_wrapper_section __aeabi_i2d
429
430wrapper_func __aeabi_ui2d
431 movs r1, #0
432 cmp r0, #0
433 bne 2f
4341:
435 bx lr
436// double FUNC_NAME(__aeabi_i2d)(int) integer to double (double precision) conversion
437wrapper_func __aeabi_i2d
438 asrs r1, r0, #31
439 eors r0, r1
440 subs r0, r1
441 beq 1b
442 lsls r1, #31
4432:
444 push {r0, r1, r4, lr}
445 ldr r3, =sf_clz_func
446 ldr r3, [r3]
447 blx r3
448 pop {r2, r3}
449 adds r4, r0, #1
450 lsls r2, r4
451 lsls r0, r2, #20
452 lsrs r2, #12
453 ldr r1,=1055
454 subs r1, r4
455 lsls r1, #20
456 orrs r1, r3
457 orrs r1, r2
458 pop {r4, pc}
459
460// int FUNC_NAME(__aeabi_d2iz)(double) double (double precision) to integer C-style conversion [3]
461double_wrapper_section __aeabi_d2iz
462wrapper_func __aeabi_d2iz
463regular_func double2int_z
464 push {r4, lr}
465 lsls r4, r1, #1
466 lsrs r2, r4, #21
467 movs r3, #0x80
468 adds r2, r3
469 lsls r3, #3
470 subs r2, r3
471 lsls r3, #21
472 cmp r2, #126
473 ble 1f
474 subs r2, #158
475 bge 2f
476 asrs r4, r1, #31
477 lsls r1, #12
478 lsrs r1, #1
479 orrs r1, r3
480 negs r2, r2
481 lsrs r1, r2
482 lsls r4, #1
483 adds r4, #1
484 adds r2, #21
485 cmp r2, #32
486 bge 3f
487 lsrs r0, r2
488 orrs r0, r1
489 muls r0, r4
490 pop {r4, pc}
4911:
492 movs r0, #0
493 pop {r4, pc}
4943:
495 mov r0, r1
496 muls r0, r4
497 pop {r4, pc}
4982:
499 // overflow
500 lsrs r0, r1, #31
501 adds r0, r3
502 subs r0, #1
503 pop {r4, pc}
504
505double_section double2int
506regular_func double2int
507 shimmable_table_tail_call SF_TABLE_FLOAT2INT double2int_shim
508
509// unsigned FUNC_NAME(__aeabi_d2uiz)(double) double (double precision) to unsigned C-style conversion [3]
510double_wrapper_section __aeabi_d2uiz
511wrapper_func __aeabi_d2uiz
512regular_func double2uint
513 shimmable_table_tail_call SF_TABLE_FLOAT2UINT double2uint_shim
514
515double_section fix2double
516regular_func fix2double
517 shimmable_table_tail_call SF_TABLE_FIX2FLOAT fix2double_shim
518
519double_section ufix2double
520regular_func ufix2double
521 shimmable_table_tail_call SF_TABLE_UFIX2FLOAT ufix2double_shim
522
523double_section fix642double
524regular_func fix642double
525 shimmable_table_tail_call SF_TABLE_FIX642FLOAT fix642double_shim
526
527double_section ufix2double
528regular_func ufix642double
529 shimmable_table_tail_call SF_TABLE_UFIX642FLOAT ufix642double_shim
530
531// double FUNC_NAME(__aeabi_l2d)(long long) long long to double (double precision) conversion
532double_wrapper_section __aeabi_l2d
533wrapper_func __aeabi_l2d
534 shimmable_table_tail_call SF_TABLE_INT642FLOAT int642double_shim
535
536// double FUNC_NAME(__aeabi_l2f)(long long) long long to double (double precision) conversion
537double_wrapper_section __aeabi_ul2d
538wrapper_func __aeabi_ul2d
539 shimmable_table_tail_call SF_TABLE_UINT642FLOAT uint642double_shim
540
541// long long FUNC_NAME(__aeabi_d2lz)(double) double (double precision) to long long C-style conversion [3]
542double_wrapper_section __aeabi_d2lz
543wrapper_func __aeabi_d2lz
544regular_func double2int64_z
545 cmn r1, r1
546 bcc double2int64
547 push {lr}
548 lsls r1, #1
549 lsrs r1, #1
550 movs r2, #0
551 bl double2ufix64
552 cmp r1, #0
553 bmi 1f
554 movs r2, #0
555 negs r0, r0
556 sbcs r2, r1
557 mov r1, r2
558 pop {pc}
5591:
560 movs r1, #128
561 lsls r1, #24
562 movs r0, #0
563 pop {pc}
564
565double_section double2int64
566regular_func double2int64
567 shimmable_table_tail_call SF_TABLE_FLOAT2INT64 double2int64_shim
568
569// unsigned long long FUNC_NAME(__aeabi_d2ulz)(double) double to unsigned long long C-style conversion [3]
570double_wrapper_section __aeabi_d2ulz
571wrapper_func __aeabi_d2ulz
572 shimmable_table_tail_call SF_TABLE_FLOAT2UINT64 double2uint64_shim
573
574double_section double2fix64
575regular_func double2fix64
576 shimmable_table_tail_call SF_TABLE_FLOAT2FIX64 double2fix64_shim
577
578double_section double2ufix64
579regular_func double2ufix64
580 shimmable_table_tail_call SF_TABLE_FLOAT2UFIX64 double2ufix64_shim
581
582double_section double2fix
583regular_func double2fix
584 shimmable_table_tail_call SF_TABLE_FLOAT2FIX double2fix_shim
585
586double_section double2ufix
587regular_func double2ufix
588 shimmable_table_tail_call SF_TABLE_FLOAT2UFIX double2ufix_shim
589
590double_wrapper_section __aeabi_d2f
5911:
592#if PICO_DOUBLE_PROPAGATE_NANS
593 // copy sign bit and 23 NAN id bits into sign bit and significant id bits, also set high id bit
594
595 lsrs r0, #30
596 lsls r2, r1, #12
597 lsrs r2, #9
598 asrs r1, #22
599 lsls r1, #22
600 orrs r0, r1
601 orrs r0, r2
602 bx lr
603#endif
604wrapper_func __aeabi_d2f
605#if PICO_DOUBLE_PROPAGATE_NANS
606 movs r3, #1
607 lsls r3, #21
608 lsls r2, r1, #1
609 adds r2, r3
610 bhi 1b
611#endif
612 // note double->float in double table at same index as float->double in double table
613 shimmable_table_tail_call SF_TABLE_FLOAT2DOUBLE double2float_shim
614
615double_wrapper_section srqt
616wrapper_func_d1 sqrt
617 shimmable_table_tail_call SF_TABLE_FSQRT dsqrt_shim
618
619double_wrapper_section sincostan_remainder
620regular_func sincostan_remainder
621 ldr r2, =0x54442D18 // 2 * M_PI
622 ldr r3, =0x401921FB
623 push {lr}
624 // note remainder only uses the divider thru integer divider functions
625 // which save and restore themselves
626 bl remainder
627 pop {pc}
628
629double_wrapper_section cos
630#don't use _d1 as we're doing a range check anyway and infinites/nans are bigger than 1024
631wrapper_func cos
632 // rom version only works for -1024 < angle < 1024
633 lsls r2, r1, #2
634 bcc 1f
635 lsrs r2, #22
636 cmp r2, #9
637 bge 2f
6381:
639 shimmable_table_tail_call SF_TABLE_FCOS dcos_shim
6402:
641#if PICO_DOUBLE_PROPAGATE_NANS
642 lsls r2, r1, #1
643 asrs r2, #21
644 adds r2, #1
645 bne 3f
646 // infinite to nan
647 movs r2, #1
648 lsls r2, #19
649 orrs r1, r2
650 bx lr
6513:
652#endif
653 push {lr}
654 bl sincostan_remainder
655 pop {r2}
656 mov lr, r2
657 b 1b
658
659double_wrapper_section sin
660#don't use _d1 as we're doing a range check anyway and infinites/nans are bigger than 1024
661wrapper_func sin
662 // rom version only works for -1024 < angle < 1024
663 lsls r2, r1, #2
664 bcc 1f
665 lsrs r2, #22
666 cmp r2, #9
667 bge 2f
6681:
669 shimmable_table_tail_call SF_TABLE_FSIN dsin_shim
6702:
671#if PICO_DOUBLE_PROPAGATE_NANS
672 lsls r2, r1, #1
673 asrs r2, #21
674 adds r2, #1
675 bne 3f
676 // infinite to nan
677 movs r2, #1
678 lsls r2, #19
679 orrs r1, r2
680 bx lr
6813:
682#endif
683 push {lr}
684 bl sincostan_remainder
685 pop {r2}
686 mov lr, r2
687 b 1b
688
689double_wrapper_section sincos
690 // out of line remainder code for abs(angle)>=1024
6912:
692#if PICO_DOUBLE_PROPAGATE_NANS
693 lsls r2, r1, #1
694 asrs r2, #21
695 adds r2, #1
696 bne 3f
697 // infinite to nan
698 movs r2, #1
699 lsls r2, #19
700 orrs r1, r2
701 pop {r4-r5}
702 stmia r4!, {r0, r1}
703 stmia r5!, {r0, r1}
704 pop {r4, r5, pc}
7053:
706#endif
707 push {lr}
708 bl sincostan_remainder
709 pop {r2}
710 mov lr, r2
711 b 1f // continue with sincos
712
713wrapper_func sincos
714 push {r2-r5, lr}
715 // rom version only works for -1024 < angle < 1024
716 lsls r2, r1, #2
717 bcc 1f
718 lsrs r2, #22
719 cmp r2, #9
720 bge 2b
7211:
722 bl 2f // call the shim
723 pop {r4-r5}
724 stmia r4!, {r0, r1}
725 stmia r5!, {r2, r3}
726 pop {r4, r5, pc}
727
7282:
729 shimmable_table_tail_call SF_TABLE_V3_FSINCOS sincos_shim_bootstrap
730
731.thumb_func
732sincos_shim_bootstrap:
733 push {r2, r3, r4}
734 movs r3, #0x13
735 ldrb r3, [r3]
736#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
737 cmp r3, #1
738 bne 1f
739 ldr r3, =dsincos_shim
740 b 2f
741#endif
7421:
743 ldr r3, =dsincos_shim_v2
7442:
745 ldr r2, =sd_table
746 str r3, [r2, #SF_TABLE_V3_FSINCOS]
747 str r3, [sp, #8]
748 pop {r2, r3, pc}
749.thumb_func
750dsincos_shim_v2:
751 push {r4-r7,r14}
752 bl push_r8_r11
753 bl v2_rom_dsincos_internal
754 mov r12,r0 @ save ε
755 bl v2_rom_dcos_finish
756 push {r0,r1}
757 mov r0,r12
758 bl v2_rom_dsin_finish
759 pop {r2,r3}
760 bl pop_r8_r11
761 pop {r4-r7,r15}
762.thumb_func
763v2_rom_dsincos_internal:
764 push {r0, lr}
765 ldr r0, =0x3855
766 str r0, [sp, #4]
767 pop {r0, pc}
768.thumb_func
769v2_rom_dcos_finish:
770 push {r0, r1}
771 ldr r0, =0x389d
772 str r0, [sp, #4]
773 pop {r0, pc}
774.thumb_func
775v2_rom_dsin_finish:
776 push {r0, r1}
777 ldr r0, =0x38d9
778 str r0, [sp, #4]
779 pop {r0, pc}
780
781double_wrapper_section tan
782#don't use _d1 as we're doing a range check anyway and infinites/nans are bigger than 1024
783wrapper_func tan
784 // rom version only works for -1024 < angle < 1024
785 lsls r2, r1, #2
786 bcc dtan_in_range
787 lsrs r2, #22
788 cmp r2, #9
789 bge dtan_angle_out_of_range
790dtan_in_range:
791#if !PICO_DIVIDER_DISABLE_INTERRUPTS
792 // to support IRQ usage (or context switch) we must save/restore divider state around call if state is dirty
793 mov ip, r2
794 ldr r2, =(SIO_BASE)
795 ldr r2, [r2, #SIO_DIV_CSR_OFFSET]
796 lsrs r2, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
797 bcs dtan_save_state
798 mov r2, ip
799#else
800 // to avoid worrying about IRQs (or context switches), simply disable interrupts around call
801 push {r4, lr}
802 mrs r4, PRIMASK
803 cpsid i
804 bl dtan_shim_call
805 msr PRIMASK, r4
806 pop {r4, pc}
807#endif
808dtan_shim_call:
809 shimmable_table_tail_call SF_TABLE_FTAN dtan_shim
810#if !PICO_DIVIDER_DISABLE_INTERRUPTS
811dtan_save_state:
812 ldr r2, =(SIO_BASE)
813 save_div_state_and_lr
814 mov r2, ip
815 bl dtan_shim_call
816 ldr r2, =(SIO_BASE)
817 restore_div_state_and_return
818#endif
819dtan_angle_out_of_range:
820#if PICO_DOUBLE_PROPAGATE_NANS
821 lsls r2, r1, #1
822 asrs r2, #21
823 adds r2, #1
824 bne 3f
825 // infinite to nan
826 movs r2, #1
827 lsls r2, #19
828 orrs r1, r2
829 bx lr
8303:
831#endif
832 push {lr}
833 bl sincostan_remainder
834 pop {r2}
835 mov lr, r2
836 b dtan_in_range
837
838double_wrapper_section atan2
839wrapper_func_d2 atan2
840 shimmable_table_tail_call SF_TABLE_FATAN2 datan2_shim
841
842double_wrapper_section exp
843wrapper_func_d1 exp
844 shimmable_table_tail_call SF_TABLE_FEXP dexp_shim
845
846double_wrapper_section log
847wrapper_func_d1 log
848 shimmable_table_tail_call SF_TABLE_FLN dln_shim
849