Home | History | Annotate | Line # | Download | only in libf7
      1 ;; Copyright (C) 2019-2022 Free Software Foundation, Inc.
      2 ;;
      3 ;; This file is part of LIBF7, which is part of GCC.
      4 ;;
      5 ;; GCC is free software; you can redistribute it and/or modify it under
      6 ;; the terms of the GNU General Public License as published by the Free
      7 ;; Software Foundation; either version 3, or (at your option) any later
      8 ;; version.
      9 ;;
     10 ;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     11 ;; WARRANTY; without even the implied warranty of MERCHANTABILITY or
     12 ;; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     13 ;; for more details.
     14 ;;
     15 ;; Under Section 7 of GPL version 3, you are granted additional
     16 ;; permissions described in the GCC Runtime Library Exception, version
     17 ;; 3.1, as published by the Free Software Foundation.
     18 ;;
     19 ;; You should have received a copy of the GNU General Public License and
     20 ;; a copy of the GCC Runtime Library Exception along with this program;
     21 ;; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     22 ;; <http://www.gnu.org/licenses/>.  */
     23 
     24 #ifndef __AVR_TINY__
     25 
     26 #define ASM_DEFS_HAVE_DEFUN
     27 
     28 #include "asm-defs.h"
     29 #include "libf7.h"
     30 
     31 #define ZERO __zero_reg__
     32 #define TMP  __tmp_reg__
     33 
     34 #define F7(name)   F7_(name##_asm)
     35 
     36 .macro F7call name
     37     .global F7(\name\())
     38     XCALL   F7(\name\())
     39 .endm
     40 
     41 .macro F7jmp name
     42     .global F7(\name\())
     43     XJMP    F7(\name\())
     44 .endm
     45 
     46 ;; Just for visibility in disassembly.
     47 .macro LLL name
     48     .global LLL.\name
     49     LLL.\name:
     50     nop
     51 .endm
     52 
     53 .macro DEFUN name
     54     .section .text.libf7.asm.\name, "ax", @progbits
     55     .global F7(\name\())
     56     .func F7(\name\())
     57     F7(\name\()) :
     58 .endm
     59 
     60 .macro ENDF name
     61     .size F7(\name\()), . - F7(\name\())
     62     .endfunc
     63 .endm
     64 
     65 .macro LABEL name
     66     .global F7(\name\())
     67     F7(\name\()) :
     68 .endm
     69 
     70 .macro _DEFUN name
     71     .section .text.libf7.asm.\name, "ax", @progbits
     72     .weak \name
     73     .type \name, @function
     74     \name :
     75 .endm
     76 
     77 .macro _ENDF name
     78     .size \name, . - \name
     79 .endm
     80 
     81 .macro _LABEL name
     82     .weak \name
     83     .type \name, @function
     84     \name :
     85 .endm
     86 
     87 #define F7_NAME(X)   F7_(X)
     88 
     89 ;; Make a weak alias.
     90 .macro  ALIAS  sym
     91     .weak \sym
     92     .type \sym, @function
     93     \sym:
     94 .endm
     95 
     96 ;; Make a weak alias if double is 64 bits wide.
     97 .macro  DALIAS  sym
     98 #if defined (WITH_LIBF7_MATH_SYMBOLS) && __SIZEOF_DOUBLE__ == 8
     99 ALIAS \sym
    100 #endif
    101 .endm
    102 
    103 ;; Make a weak alias if long double is 64 bits wide.
    104 .macro  LALIAS  sym
    105 #if defined (WITH_LIBF7_MATH_SYMBOLS) && __SIZEOF_LONG_DOUBLE__ == 8
    106 ALIAS \sym
    107 #endif
    108 .endm
    109 
    110 #define     Off 1
    111 #define     Expo (Off + F7_MANT_BYTES)
    112 
    113 #ifdef F7MOD_classify_
    114 ;;  r24 = classify (*Z)
    115 ;;  NaN  ->  F7_FLAG_nan
    116 ;;  INF  ->  F7_FLAG_inf [ | F7_FLAG_sign ]
    117 ;;  ==0  ->  F7_FLAG_zero
    118 ;;  ...  ->  0 [ | F7_FLAG_sign ]
    119 
    120 ;; Clobbers:  None (no TMP, no T).
    121 DEFUN classify
    122 
    123     ld      r24,    Z
    124     lsr     r24
    125     brne .Lnan_or_inf
    126 
    127     ldd     r24,    Z+6+Off
    128     tst     r24
    129     brpl 0f
    130     sbc     r24,    r24
    131     andi    r24,    F7_FLAG_sign
    132     ret
    133 
    134 0:  ldi     r24,    F7_FLAG_zero
    135     ret
    136 
    137 .Lnan_or_inf:
    138     rol     r24
    139     ret
    140 
    141 ENDF classify
    142 #endif /* F7MOD_classify_ */
    143 
    144 #ifdef F7MOD_clr_
    145 DEFUN clr
    146     std     Z+0,     ZERO
    147     std     Z+0+Off, ZERO
    148     std     Z+1+Off, ZERO
    149     std     Z+2+Off, ZERO
    150     std     Z+3+Off, ZERO
    151     std     Z+4+Off, ZERO
    152     std     Z+5+Off, ZERO
    153     std     Z+6+Off, ZERO
    154     std     Z+0+Expo, ZERO
    155     std     Z+1+Expo, ZERO
    156     ret
    157 ENDF clr
    158 
    159 #endif /* F7MOD_clr_ */
    160 
    161 #ifdef F7MOD_clz_
    162 ;; The libcc CLZ implementations like __clzsi2 aka. __builtin_clzl are
    163 ;; not very well suited for out purpose, so implement our own.
    164 
    165 #define ZBITS   r26
    166 .macro  .test.byte  reg
    167     or      ZERO,   \reg
    168     brne    .Loop_bit
    169     subi    ZBITS, -8
    170 .endm
    171 
    172 ;; R26 = CLZ (uint64_t R18);  CLZ (0) = 64.
    173 ;; Unchanged: T
    174 DEFUN clzdi2
    175     clr     ZBITS
    176     ;; Catch the common case of normalized .mant for speed-up.
    177     tst     r25
    178     brmi 9f
    179     .test.byte  r25
    180     .test.byte  r24
    181     .test.byte  r23
    182     .test.byte  r22
    183     .test.byte  r21
    184     .test.byte  r20
    185     .test.byte  r19
    186     .test.byte  r18
    187 .Ldone:
    188     clr     ZERO
    189 9:  ret
    190 
    191 .Loop_bit:
    192     lsl     ZERO
    193     brcs .Ldone
    194     inc     ZBITS
    195     rjmp .Loop_bit
    196 
    197 ENDF clzdi2
    198 #undef  ZBITS
    199 #endif /* F7MOD_clz_ */
    200 
    201 #ifdef F7MOD_cmp_mant_
    202 DEFUN cmp_mant
    203 
    204     adiw    X,   6 + Off
    205     ld      r24, X      $ ldd   TMP, Z+6+Off    $ SUB   r24, TMP
    206     brne .Lunequal
    207 
    208     sbiw    X,  6
    209     ld      r24, X+     $ ldd   TMP, Z+0+Off    $ SUB   r24, TMP
    210     ld      r24, X+     $ ldd   TMP, Z+1+Off    $ sbc   r24, TMP
    211     ld      r24, X+     $ ldd   TMP, Z+2+Off    $ sbc   r24, TMP
    212     ld      r24, X+     $ ldd   TMP, Z+3+Off    $ sbc   r24, TMP
    213     ld      r24, X+     $ ldd   TMP, Z+4+Off    $ sbc   r24, TMP
    214     ld      r24, X+     $ ldd   TMP, Z+5+Off    $ sbc   r24, TMP
    215     ;; MSBs are already known to be equal
    216     breq 9f
    217 .Lunequal:
    218     sbc     r24,    r24
    219     sbci    r24,    -1
    220 9:  sbiw    X,      6 + Off
    221     ret
    222 ENDF cmp_mant
    223 #endif /* F7MOD_cmp_mant_ */
    224 
    225 #define     CA      18
    226 #define     C0      CA+1
    227 #define     C1      C0+1
    228 #define     C2      C0+2
    229 #define     C3      C0+3
    230 #define     C4      C0+4
    231 #define     C5      C0+5
    232 #define     C6      C0+6
    233 #define     Carry   r16
    234 #define     Flags   18
    235 
    236 #ifdef F7MOD_store_
    237 ;; Z->flags = CA.
    238 ;; Z->mant  = C[7].
    239 DEFUN store_mant.with_flags
    240     st      Z,      CA
    241 
    242 ;; Z->mant = C[7].
    243 LABEL store_mant
    244     std     Z+0+Off, C0
    245     std     Z+1+Off, C1
    246     std     Z+2+Off, C2
    247     std     Z+3+Off, C3
    248     std     Z+4+Off, C4
    249     std     Z+5+Off, C5
    250     std     Z+6+Off, C6
    251     ret
    252 ENDF store_mant.with_flags
    253 #endif /* F7MOD_store_ */
    254 
    255 #ifdef F7MOD_load_
    256 ;; CA   = Z->flags
    257 ;; C[7] = Z->mant
    258 DEFUN load_mant.with_flags
    259     ld      CA,     Z
    260     skipnext
    261 
    262 ;; CA   = 0
    263 ;; C[7] = Z->mant
    264 LABEL load_mant.clr_CA
    265 LABEL load_mant.clr_flags
    266     clr     CA      ; May be skipped
    267 
    268 ;; C[7] = Z->mant
    269 LABEL load_mant
    270     ldd     C0,     Z+0+Off
    271     ldd     C1,     Z+1+Off
    272     ldd     C2,     Z+2+Off
    273     ldd     C3,     Z+3+Off
    274     ldd     C4,     Z+4+Off
    275     ldd     C5,     Z+5+Off
    276     ldd     C6,     Z+6+Off
    277     ret
    278 ENDF load_mant.with_flags
    279 #endif /* F7MOD_load_ */
    280 
    281 #ifdef F7MOD_copy_
    282 DEFUN copy
    283     cp      XL,     ZL
    284     cpc     XH,     ZH
    285     breq 9f
    286     adiw    XL,     10
    287     adiw    ZL,     10
    288     set
    289     bld     ZERO,   1
    290     bld     ZERO,   3   ; ZERO = 0b1010 = 10.
    291 .Loop:
    292     ld      TMP,    -X
    293     st      -Z,     TMP
    294     dec     ZERO
    295     brne .Loop
    296 9:  ret
    297 ENDF copy
    298 #endif /* F7MOD_copy_ */
    299 
    300 #ifdef F7MOD_copy_P_
    301 DEFUN copy_P
    302     set
    303     bld     ZERO,   1
    304     bld     ZERO,   3   ; ZERO = 0b1010 = 10.
    305 .Loop:
    306 #ifdef __AVR_HAVE_LPMX__
    307     lpm     TMP,    Z+
    308 #else
    309     lpm
    310     adiw    Z,      1
    311 #endif /* Have LPMx */
    312     st      X+,     TMP
    313     dec     ZERO
    314     brne .Loop
    315     sbiw    X,      10
    316     sbiw    Z,      10
    317     ret
    318 ENDF copy_P
    319 #endif /* F7MOD_copy_P_ */
    320 
    321 #ifdef F7MOD_copy_mant_
    322 DEFUN copy_mant
    323     cp      XL,     ZL
    324     cpc     XH,     ZH
    325     breq 9f
    326     adiw    XL,     1
    327     adiw    ZL,     1
    328     set
    329     bld     ZERO,   3
    330     dec     ZERO        ; ZERO = 7
    331 .Loop:
    332     ld      TMP,    X+
    333     st      Z+,     TMP
    334     dec     ZERO
    335     brne    .Loop
    336     sbiw    XL,     8
    337     sbiw    ZL,     8
    338 9:  ret
    339 ENDF copy_mant
    340 #endif /* F7MOD_copy_mant_ */
    341 
    342 
    343 #ifdef F7MOD_clr_mant_lsbs_
    344 DEFUN clr_mant_lsbs
    345     push    r16
    346     mov     r16,    r20
    347     wmov    XL,     r24
    348 
    349     wmov    ZL,     r22
    350     F7call  load_mant
    351 
    352     F7call  lshrdi3
    353 
    354     clr     CA
    355 
    356     F7call   ashldi3
    357 
    358     pop     r16
    359 
    360     wmov    ZL,     XL
    361     F7jmp  store_mant
    362 
    363 ENDF clr_mant_lsbs
    364 #endif /* F7MOD_clr_mant_lsbs_ */
    365 
    366 
    367 #ifdef F7MOD_normalize_with_carry_
    368 ;; Z = &f7_t
    369 ;; C[] = .mant may be not normalized
    370 ;; Carry === r16 = Addend to Z->expo in [-64, 128).
    371 ;; Normalize C[], set Flags, and adjust Z->expo.
    372 ;; Return CA (after normalization) in TMP.
    373 ;; Unchanged: T
    374 #define Addend  r17
    375 #define Zbits   r26
    376 #define expL    r26
    377 #define expH    r27
    378 DEFUN normalize_with_carry
    379     mov     Addend, Carry
    380     tst     C6
    381     brmi .Lshift.0
    382     ;; r26 = CLZ (uint64_t R18)
    383     F7call  clzdi2
    384     cpi     Zbits,  64
    385     breq .Lclr
    386     sub     Addend, Zbits
    387     mov     r16,    Zbits
    388 
    389     F7call  ashldi3
    390     ;; Assert (R25.7 == 1)
    391 .Lshift.0:
    392     mov     TMP,    CA
    393     ld      Flags,  Z
    394 
    395     ;; .expo += Addend
    396     ldd     expL,   Z+0+Expo
    397     ldd     expH,   Z+1+Expo
    398     ;; Sign-extend Addend
    399     clr     r16
    400     sbrc    Addend, 7
    401     com     r16
    402 
    403     ;; exp += (int8_t) Addend, i.e. sign-extend Addend.
    404     add     expL,   Addend
    405     adc     expH,   r16
    406     brvc .Lnormal
    407     tst     r16
    408     brmi .Lclr
    409     ;; Overflow
    410 #if F7_HAVE_Inf == 1
    411     ori     Flags,  F7_FLAG_inf
    412 #else
    413     ldi     Flags,  F7_FLAG_nan
    414 #endif /* Have Inf */
    415     ret
    416 
    417 .Lnormal:
    418     std     Z+0+Expo,   expL
    419     std     Z+1+Expo,   expH
    420     ret
    421 
    422 .Lclr:
    423     ;; Underflow or Zero.
    424     clr     TMP
    425     .global __clr_8
    426     XJMP    __clr_8
    427 
    428 LABEL normalize.store_with_flags
    429     ;; no rounding
    430     set
    431     skipnext
    432 LABEL normalize.round.store_with_flags
    433     ;; with rounding
    434     clt     ; skipped ?
    435 LABEL normalize.maybe_round.store_with_flags
    436     F7call  normalize_with_carry
    437     ;; We have:
    438     ;; Z   = &f7_t
    439     ;; X   = .expo
    440     ;; C[] = .mant
    441     ;; R18 = .flags
    442     ;; TMP = byte below .mant after normalization
    443     ;; T = 1  =>  no rounding.
    444     brts .Lstore
    445     lsl     TMP
    446     adc     C0,     ZERO
    447     brcc .Lstore
    448     adc     C1,     ZERO
    449     adc     C2,     ZERO
    450     adc     C3,     ZERO
    451     adc     C4,     ZERO
    452     adc     C5,     ZERO
    453     adc     C6,     ZERO
    454     brcc .Lstore
    455     ;; We only come here if C6 overflowed, i.e. C[] is 0 now.
    456     ;; .mant = 1.0 by restoring the MSbit.
    457     ror     C6
    458     ;; .expo += 1 and override the .expo stored during normalize.
    459     adiw    expL,   1
    460     std     Z+0+Expo,   expL
    461     std     Z+1+Expo,   expH
    462 
    463 .Lstore:
    464     F7call  store_mant.with_flags
    465 
    466     ;; Return the byte below .mant after normalization.
    467     ;; This is only useful without rounding; the caller will know.
    468     mov     R24,    TMP
    469     ret
    470 ENDF normalize_with_carry
    471 #endif /* F7MOD_normalize_with_carry_ */
    472 
    473 
    474 #ifdef F7MOD_normalize_
    475 ;; Using above functionality from C.
    476 ;; f7_t* normalize (f7_t *cc)
    477 ;; Adjusts cc->expo
    478 ;; Clears cc->flags
    479 DEFUN normalize
    480     push    r17
    481     push    r16
    482     wmov    ZL,     r24
    483     F7call  load_mant.clr_CA
    484     clr     Carry
    485     st      Z,      ZERO
    486     F7call  normalize.store_with_flags
    487     wmov    r24,    Z
    488     pop     r16
    489     pop     r17
    490     ret
    491 ENDF normalize
    492 #endif /* F7MOD_normalize_ */
    493 
    494 
    495 #ifdef F7MOD_store_expo_
    496 #define Done    r24
    497 #define expLO   r24
    498 #define expHI   r25
    499 ;; expo == INT16_MAX  =>  *Z = Inf,         return Done = true.
    500 ;; expo == INT16_MIN  =>  *Z = 0x0,         return Done = true.
    501 ;; else               =>  Z->expo = expo,   return Done = false.
    502 DEFUN store_expo
    503     cpi     expHI,   0x80
    504     cpc     expLO,  ZERO
    505     breq .Ltiny
    506     adiw    expLO,  1
    507     brvs .Lhuge
    508     sbiw    expLO,  1
    509     std     Z+0+Expo,   expLO
    510     std     Z+1+Expo,   expHI
    511     ldi     Done,   0
    512     ret
    513 
    514 .Lhuge:
    515 #if F7_HAVE_Inf == 1
    516     ld      Done,   Z
    517     andi    Done,   F7_FLAG_sign
    518     ori     Done,   F7_FLAG_inf
    519 #else
    520     ldi     Done,   F7_FLAG_nan
    521 #endif /* Have Inf */
    522     st      Z,      Done
    523     ldi     Done,   1
    524     ret
    525 
    526 .Ltiny:
    527     ldi     Done,   1
    528     F7jmp   clr
    529 ENDF store_expo
    530 #endif /* F7MOD_store_expo_ */
    531 
    532 
    533 #ifdef F7MOD_set_u64_
    534 DEFUN set_s64
    535     set
    536     skipnext
    537     ;; ...
    538 LABEL set_u64
    539     clt     ; Skipped?
    540     wmov    Zl,     r16
    541     ;; TMP holds .flags.
    542     clr     TMP
    543     brtc .Lnot.negative
    544 
    545     bst     C6,     7
    546     brtc .Lnot.negative
    547     bld     TMP,    F7_FLAGNO_sign
    548     .global __negdi2
    549     XCALL   __negdi2
    550 
    551 .Lnot.negative:
    552     st      Z,          TMP
    553     std     Z+0+Expo,   ZERO
    554     std     Z+1+Expo,   ZERO
    555     ldi     Carry,      63
    556     F7call  normalize.round.store_with_flags
    557     wmov    r24,        Z
    558     wmov    r16,        Z   ; Unclobber r16.
    559     ret
    560 ENDF set_s64
    561 #endif /* F7MOD_set_u64_ */
    562 
    563 
    564 #ifdef F7MOD_to_integer_
    565 #define Mask    r26
    566 DEFUN to_integer
    567     wmov    ZL,     r24
    568     mov     Mask,   r22
    569 
    570     F7call  load_mant.with_flags
    571 
    572     sbrc    Flags, F7_FLAGNO_nan
    573     rjmp .Lset_0x8000
    574 
    575     sbrc    Flags, F7_FLAGNO_inf
    576     rjmp .Lsaturate
    577 
    578     sbrs    C6, 7
    579     rjmp .Lset_0x0000
    580 
    581     bst     Flags, F7_FLAGNO_sign
    582     ldd     r27,    Z+0+Expo
    583     ;; Does .expo have bits outside Mask? ...
    584     mov     TMP,    Mask
    585     com     TMP
    586     and     TMP,    r27
    587     ldd     r27,    Z+1+Expo
    588     tst     r27
    589     brmi .Lset_0x0000       ; ...yes: .expo is < 0  =>  return 0
    590     or      TMP,    r27
    591     brne .Lsaturate.T       ; ...yes: .expo > Mask  =>  saturate
    592 
    593     ;; ...no:  Shift right to meet .expo = 0.
    594     PUSH    r16
    595     ldd     r16,    Z+0+Expo
    596     eor     r16,    Mask
    597     and     r16,    Mask
    598     clr     CA
    599     F7call  lshrdi3
    600     POP     r16
    601     tst     C6
    602     brmi    .Lsaturate.T    ;   > INTxx_MAX  =>  saturate
    603 
    604     brtc 9f                 ;   >= 0         =>  return
    605     sbrc    Mask,   5
    606     .global __negdi2
    607     XJMP    __negdi2
    608     sbrc    Mask,   4
    609     .global __negsi2
    610     XJMP    __negsi2
    611     neg     C6
    612     neg     C5
    613     sbci    C6,     0
    614 9:  ret
    615 
    616 .Lsaturate:
    617     bst     Flags, F7_FLAGNO_sign
    618 .Lsaturate.T:
    619 
    620 #if F7_HAVE_Inf
    621     brtc .Lset_0x7fff
    622     ;; -Inf  =>  return 1 + INTxx_MIN
    623     mov     ZL,     Flags
    624     .global __clr_8
    625     XCALL   __clr_8
    626     ldi     C6,     0x80
    627 
    628     ldi     CA+0,   0x01
    629 
    630     sbrs    Mask,   5
    631     ldi     CA+4,   0x01
    632 
    633     sbrs    Mask,   4
    634     ldi     CA+6,   0x01
    635     ret
    636 
    637 .Lset_0x7fff:
    638     ;; +Inf  =>  return INTxx_MAX
    639     sec
    640     .global __sbc_8
    641     XCALL   __sbc_8
    642     ldi     C6,     0x7f
    643     ret
    644 #endif /* F7_HAVE_Inf */
    645 
    646 .Lset_0x8000:
    647     ;; NaN  =>  return INTxx_MIN
    648     .global __clr_8
    649     XCALL   __clr_8
    650     ldi     C6,     0x80
    651     ret
    652 
    653 .Lset_0x0000:
    654     ;; Small value  =>  return 0x0
    655     .global __clr_8
    656     XJMP    __clr_8
    657 
    658 ENDF to_integer
    659 #endif /* F7MOD_to_integer_ */
    660 
    661 
    662 #ifdef F7MOD_to_unsigned_
    663 #define Mask    r26
    664 DEFUN to_unsigned
    665     wmov    ZL,     r24
    666     mov     Mask,   r22
    667 
    668     F7call  load_mant.with_flags
    669 
    670     sbrc    Flags, F7_FLAGNO_nan
    671     rjmp .Lset_0xffff
    672 
    673     sbrc    Flags, F7_FLAGNO_sign
    674     rjmp .Lset_0x0000
    675 
    676     sbrc    Flags, F7_FLAGNO_inf
    677     rjmp .Lset_0xffff
    678 
    679     sbrs    C6, 7
    680     rjmp .Lset_0x0000
    681 
    682     ldd     r27,    Z+0+Expo
    683     ;; Does .expo have bits outside Mask? ...
    684     mov     TMP,    Mask
    685     com     TMP
    686     and     TMP,    r27
    687     ldd     r27,    Z+1+Expo
    688     tst     r27
    689     brmi .Lset_0x0000       ; ...yes: .expo is < 0  =>  return 0
    690     or      TMP,    r27
    691     brne .Lset_0xffff       ; ...yes: .expo > Mask  =>  saturate
    692 
    693     ;; ...no:  Shift right to meet .expo = 0.
    694     PUSH    r16
    695     ldd     r16,    Z+0+Expo
    696     eor     r16,    Mask
    697     and     r16,    Mask
    698     clr     CA
    699     F7call  lshrdi3
    700     POP     r16
    701     ret
    702 
    703 .Lset_0xffff:
    704     ;; return UINTxx_MAX
    705     sec
    706     .global __sbc_8
    707     XJMP    __sbc_8
    708 
    709 .Lset_0x0000:
    710     ;; Small value  =>  return 0x0
    711     .global __clr_8
    712     XJMP    __clr_8
    713 
    714 ENDF to_unsigned
    715 #endif /* F7MOD_to_unsigned_ */
    716 
    717 
    718 #ifdef F7MOD_addsub_mant_scaled_
    719 ;; int8_t f7_addsub_mant_scaled_asm (f7_t *r24, const f7_t *r22, const f7_t 20*,
    720 ;;                                   uint8_t r18);
    721 ;; R18.0 = 1 : ADD
    722 ;; R18.0 = 0 : SUB
    723 ;; R18[7..1] : Scale
    724 ;; Compute *R24 = *R22 + *R20 >> R18[7..1].
    725 
    726 #define     BA      10
    727 #define     B0      BA+1
    728 #define     B1      B0+1
    729 #define     B2      B0+2
    730 #define     B3      B0+3
    731 #define     B4      B0+4
    732 #define     B5      B0+5
    733 #define     B6      B0+6
    734 
    735 DEFUN addsub_mant_scaled
    736     do_prologue_saves  10
    737 
    738     bst     r18,    0  ;; ADD ?
    739     lsr     r18
    740     mov     r16,    r18
    741 
    742     wmov    ZL,     r20
    743     wmov    YL,     r22
    744     ;; C[] = bb >> shift
    745     wmov    XL,     r24
    746 
    747     F7call  load_mant.clr_CA
    748     F7call  lshrdi3
    749 
    750     wmov    BA,     CA
    751     wmov    B1,     C1
    752     wmov    B3,     C3
    753     wmov    B5,     C5
    754     wmov    ZL,     YL
    755     F7call  load_mant.clr_CA
    756 
    757     wmov    ZL,     XL
    758 
    759     brts .Ladd
    760 
    761     .global __subdi3
    762     XCALL   __subdi3
    763 
    764     breq .Lzero
    765     brcc .Lround
    766     ;; C = 1: Can underflow happen at all ?
    767 .Lzero:
    768     F7call  clr
    769     rjmp .Lepilogue
    770 
    771 .Ladd:
    772     .global __adddi3
    773     XCALL   __adddi3
    774     brcc .Lround
    775     ldi     Carry,  1
    776     .global __lshrdi3
    777     XCALL   __lshrdi3
    778     ori     C6, 1 << 7
    779     skipnext
    780 .Lround:
    781     clr     Carry   ; skipped?
    782     F7call  normalize.round.store_with_flags
    783 
    784 .Lepilogue:
    785     do_epilogue_restores 10
    786 
    787 ENDF addsub_mant_scaled
    788 
    789 #if !defined (__AVR_HAVE_MOVW__) || !defined (__AVR_HAVE_JMP_CALL__)
    790 DEFUN lshrdi3
    791     .global __lshrdi3
    792     XJMP    __lshrdi3
    793 ENDF lshrdi3
    794 DEFUN ashldi3
    795     .global __ashldi3
    796     XJMP    __ashldi3
    797 ENDF ashldi3
    798 #else
    799 
    800 # Basically just a wrapper around libgcc's __lshrdi3.
    801 DEFUN lshrdi3
    802     ;; Handle bit 5 of shift offset.
    803     sbrs    r16,    5
    804     rjmp 4f
    805     wmov    CA,     C3
    806     wmov    C1,     C5
    807     clr     C6          $   clr     C5  $   wmov    C3, C5
    808 4:
    809     ;; Handle bit 4 of shift offset.
    810     sbrs    r16,    4
    811     rjmp 3f
    812     wmov CA, C1
    813     wmov C1, C3
    814     wmov C3, C5
    815     clr     C6          $   clr     C5
    816 3:
    817     ;; Handle bits 3...0 of shift offset.
    818     push    r16
    819     andi    r16,    0xf
    820     breq 0f
    821 
    822     .global __lshrdi3
    823     XCALL   __lshrdi3
    824 0:
    825     pop     r16
    826     ret
    827 ENDF lshrdi3
    828 
    829 # Basically just a wrapper around libgcc's __ashldi3.
    830 DEFUN ashldi3
    831     ;; Handle bit 5 of shift offset.
    832     sbrs    r16,    5
    833     rjmp 4f
    834     wmov    C5,     C1
    835     wmov    C3,     CA
    836     clr     C2          $   clr     C1  $   wmov    CA, C1
    837 4:
    838     ;; Handle bit 4 of shift offset.
    839     sbrs    r16,    4
    840     rjmp 3f
    841     wmov C5, C3
    842     wmov C3, C1
    843     wmov C1, CA
    844     clr     CA          $   clr     C0
    845 3:
    846     ;; Handle bits 3...0 of shift offset.
    847     push    r16
    848     andi    r16,    0xf
    849     breq 0f
    850 
    851     .global __ashldi3
    852     XCALL   __ashldi3
    853 0:
    854     pop     r16
    855     ret
    856 ENDF ashldi3
    857 #endif /* Small device */
    858 
    859 #endif /* F7MOD_addsub_mant_scaled_ */
    860 
    861 #if defined F7MOD_mul_mant_ && defined (__AVR_HAVE_MUL__)
    862     #define     A0      11
    863     #define     A1      A0+1
    864     #define     A2      A0+2
    865     #define     A3      A0+3
    866     #define     A4      A0+4
    867     #define     A5      A0+5
    868     #define     A6      A0+6
    869 
    870     #define     TT0     26
    871     #define     TT1     TT0+1
    872     #define     TT2     28
    873     #define     TT3     TT2+1
    874 
    875     #define     BB      10
    876 
    877 ;; R18.0 = 1: No rounding.
    878 
    879 DEFUN mul_mant
    880     do_prologue_saves 10
    881     bst     r18,    0
    882     push    r25
    883     push    r24
    884     movw    ZL,     r22
    885     LDD     A0,     Z+0+Off
    886     LDD     A1,     Z+1+Off
    887     LDD     A2,     Z+2+Off
    888     LDD     A3,     Z+3+Off
    889     LDD     A4,     Z+4+Off
    890     LDD     A5,     Z+5+Off
    891     LDD     A6,     Z+6+Off
    892     movw    ZL,     r20
    893 
    894     ;; 6 * 6 -> 6:5
    895     ;; 4 * 6 -> 4:3
    896     ;; 2 * 6 -> 2:1
    897     ;; 0 * 6 -> 0:a
    898     ldd     BB, Z+6+Off
    899     mul     A6, BB      $   movw    C5, r0
    900     mul     A4, BB      $   movw    C3, r0
    901     mul     A2, BB      $   movw    C1, r0
    902     mul     A0, BB      $   movw    CA, r0
    903 
    904     ;; 5 * 6 -> 5:4
    905     ;; 3 * 6 -> 3:2
    906     ;; 1 * 6 -> 1:0
    907     mul     A5, BB      $   movw    TT2, r0
    908     mul     A3, BB      $   movw    TT0, r0
    909     mul     A1, BB
    910     ADD     C0, r0      $   adc     C1, r1
    911     adc     C2, TT0     $   adc     C3, TT1
    912     adc     C4, TT2     $   adc     C5, TT3     $   clr ZERO
    913     adc     C6, ZERO
    914     ;; Done B6
    915 
    916     ;; 3 * 3 -> 0:a
    917     ;; 4 * 4 -> 2:1
    918     ;; 5 * 5 -> 4:3
    919     ldd     BB, Z+3+Off $   mul     A3, BB      $   movw    TT0, r0
    920     ldd     BB, Z+4+Off $   mul     A4, BB      $   movw    TT2, r0
    921     ldd     BB, Z+5+Off $   mul     A5, BB
    922 
    923     ADD     CA, TT0     $   adc     C0, TT1
    924     adc     C1, TT2     $   adc     C2, TT3
    925     adc     C3, r0      $   adc     C4, r1
    926     brcc .+2
    927     adiw    C5, 1
    928 
    929     ;; 6 * 5 -> 5:4
    930     ;; 4 * 5 -> 3:2
    931     ;; 2 * 5 -> 1:0
    932     ;; 0 * 5 -> a:-
    933     mul     A0, BB
    934     ;; A0 done
    935 #define Atmp A0
    936 
    937     mov     Atmp, r1
    938     mul     A6, BB      $   movw    TT2, r0
    939     mul     A4, BB      $   movw    TT0, r0
    940     mul     A2, BB
    941 
    942     ADD     CA, Atmp
    943     adc     C0, r0      $   adc     C1, r1
    944     adc     C2, TT0     $   adc     C3, TT1
    945     adc     C4, TT2     $   adc     C5, TT3     $   clr ZERO
    946     adc     C6, ZERO
    947 
    948     ;; 1 * 5 -> 0:a
    949     ;; 3 * 5 -> 2:1
    950     ;; 6 * 4 -> 4:3
    951     mul     A1, BB      $   movw    TT0, r0
    952     mul     A3, BB      $   movw    TT2, r0
    953     ldd     BB, Z+4+Off
    954     mul     A6, BB
    955 
    956     ADD     CA, TT0     $   adc     C0, TT1
    957     adc     C1, TT2     $   adc     C2, TT3
    958     adc     C3, r0      $   adc     C4, r1      $   clr ZERO
    959     adc     C5, ZERO    $   adc     C6, ZERO
    960     ;; B5 done
    961 
    962     ;; 6 * 3 -> 3:2
    963     ;; 6 * 1 -> 1:0
    964     ;; 4 * 1 -> a:-
    965     mov     TT0, A6     $   ldd TMP,  Z+3+Off
    966     mov     BB,  A4     $   ldd Atmp, Z+1+Off
    967     rcall   .Lmul.help.3
    968 
    969     ;; 5 * 4 -> 3:2
    970     ;; 5 * 2 -> 1:0
    971     ;; 3 * 2 -> a:-
    972     mov     TT0, A5     $   ldd TMP,  Z+4+Off
    973     mov     BB,  A3     $   ldd Atmp, Z+2+Off
    974     rcall   .Lmul.help.3
    975 
    976     ;; 4 *   -> 3:2 (=0)
    977     ;; 4 * 3 -> 1:0
    978     ;; 2 * 3 -> a:-
    979     mov     TT0, A4     $   clr TMP
    980     mov     BB,  A2     $   ldd Atmp, Z+3+Off
    981     rcall   .Lmul.help.3
    982 
    983     ;; 3 * . -> 3:2 (=0)
    984     ;; 3 * 4 -> 1:0
    985     ;; 1 * 4 -> a:-
    986     mov     TT0, A3     $   clr TMP
    987     mov     BB,  A1     $   ldd Atmp, Z+4+Off
    988     rcall   .Lmul.help.3
    989 
    990     ;; . * ? -> 3:2 (=0)
    991     ;; . * 0 -> 1:0 (=0)
    992     ;; 5 * 0 -> a:-
    993     clr     TT0
    994     mov     BB,  A5     $   ldd Atmp, Z+0+Off
    995     rcall   .Lmul.help.3
    996 
    997     clr TT3  ;; Asserted by .Lmul.help.2
    998     ;; 6 * 2 -> 2:1
    999     ;; 6 * 0 -> 0:a
   1000                         $   ldd TMP,  Z+2+Off
   1001     mov     BB, A6     ;$   ldd Atmp, Z+0+Off
   1002     rcall   .Lmul.help.2
   1003 
   1004     ;; 5 * 3 -> 2:1
   1005     ;; 5 * 1 -> 0:a
   1006                         $   ldd TMP,  Z+3+Off
   1007     mov     BB, A5      $   ldd Atmp, Z+1+Off
   1008     rcall   .Lmul.help.2
   1009 
   1010     ;; 4 * . -> 2:1 (=0)
   1011     ;; 4 * 2 -> 0:a
   1012                         $   clr TMP
   1013     mov     BB, A4      $   ldd Atmp, Z+2+Off
   1014     rcall   .Lmul.help.2
   1015 
   1016     ;; 2 * . -> 2:1 (=0)
   1017     ;; 2 * 4 -> 0:a
   1018                         $   clr TMP
   1019     mov     BB, A2      $   ldd Atmp, Z+4+Off
   1020     rcall   .Lmul.help.2
   1021 
   1022     ;; Finally...
   1023 
   1024     pop     ZL
   1025     pop     ZH
   1026     ;; The high byte is at least 0x40 and at most 0xfe.
   1027     ;; The result has to be left-shifted by one in order to scale it
   1028     ;; correctly.
   1029 
   1030     ldi     Carry,  1
   1031     F7call  normalize.maybe_round.store_with_flags
   1032 
   1033     do_epilogue_restores 10
   1034 
   1035 ;; TT0 * Tmp  -> 3:2
   1036 ;; TT0 * Atmp -> 1:0
   1037 ;; BB  * Atmp -> a:-
   1038 ;;
   1039 ;; Clobbers : TMP, TT0...TT3.
   1040 ;; Sets     : ZERO = 0.
   1041 .Lmul.help.3:
   1042     mul     TT0, TMP    $   movw    TT2, r0
   1043     mul     TT0, Atmp   $   movw    TT0, r0
   1044     mul     BB,  Atmp
   1045 
   1046     ADD     CA, r1
   1047     adc     C0, TT0     $   adc     C1, TT1
   1048     adc     C2, TT2
   1049 .Lmul.help.3.C3:        $   adc     C3, TT3     $ clr ZERO
   1050     adc     C4, ZERO    $   adc     C5, ZERO
   1051     adc     C6, ZERO
   1052     ret
   1053 
   1054 ;; BB * TMP  -> 2:1
   1055 ;; BB * Atmp -> 0:a
   1056 ;;
   1057 ;; Asserts  : TT3 = 0
   1058 ;; Clobbers : TMP, TT0, TT1.
   1059 ;; Sets     : ZERO = 0.
   1060 .Lmul.help.2:
   1061     mul     BB, TMP     $   movw    TT0, r0
   1062     mul     BB, Atmp
   1063     ADD     CA, r0      $   adc     C0, r1
   1064     adc     C1, TT0     $   adc     C2, TT1
   1065     rjmp .Lmul.help.3.C3
   1066 
   1067 ENDF mul_mant
   1068 #endif /* F7MOD_mul_mant_ && MUL */
   1069 
   1070 
   1071 #if defined (F7MOD_div_)
   1072 
   1073 ;; Dividend is C[]
   1074 
   1075 ;; Divisor
   1076 #define A0       9
   1077 #define A1      10
   1078 #define A2      11
   1079 #define A3      12
   1080 #define A4      13
   1081 #define A5      14
   1082 #define A6      15
   1083 
   1084 ;; Quotient
   1085 #define Q0      0       /* === TMP  */
   1086 #define Q1      Q0+1    /* === ZERO */
   1087 #define Q2      26
   1088 #define Q3      Q2+1
   1089 #define Q4      28
   1090 #define Q5      Q4+1
   1091 #define Q6      16
   1092 #define Q7      Q6+1
   1093 
   1094 #define Cnt     CA
   1095 #define QBits   r8
   1096 
   1097 DEFUN div
   1098     do_prologue_saves 12
   1099 
   1100     ;; Number of bits requested for the quotient.
   1101     ;; This is usually 2 + F7_MANT_BITS.
   1102     mov     QBits,  r20
   1103     wmov    ZL,     r22
   1104     LDD     A0,     Z+0+Off
   1105     LDD     A1,     Z+1+Off
   1106     LDD     A2,     Z+2+Off
   1107     LDD     A3,     Z+3+Off
   1108     LDD     A4,     Z+4+Off
   1109     LDD     A5,     Z+5+Off
   1110     LDD     A6,     Z+6+Off
   1111     wmov    ZL,     r24
   1112     F7call  load_mant
   1113 
   1114     ;; Clear quotient Q[].
   1115     clr     Q0      ; === TMP
   1116     ;clr    Q1      ; === ZERO
   1117     wmov    Q2,     Q0
   1118     wmov    Q4,     Q0
   1119     wmov    Q6,     Q0
   1120 
   1121     ;; C[] and A[] are valid mantissae, i.e. their MSBit is set.  Therefore,
   1122     ;; quotient Q[] will be in  [0x0.ff..., 0x0.40...]  and to adjust Q[] we
   1123     ;; need at most 1 left-shift.  Compute F7_MANT_BITS + 2 bits of the
   1124     ;; quotient:  One bit is used for rounding, and one bit might be consumed
   1125     ;; by the mentioned left-shift.
   1126     mov     Cnt,    QBits
   1127     rjmp .Loop_start
   1128 
   1129 .Loop:
   1130     ;; Shift dividend.
   1131     LSL     C0
   1132     rol     C1
   1133     rol     C2
   1134     rol     C3
   1135     rol     C4
   1136     rol     C5
   1137     rol     C6
   1138     brcs .Lfits
   1139     ;; Compare dividend against divisor.
   1140 .Loop_start:
   1141     CP      C0,     A0
   1142     cpc     C1,     A1
   1143     cpc     C2,     A2
   1144     cpc     C3,     A3
   1145     cpc     C4,     A4
   1146     cpc     C5,     A5
   1147     cpc     C6,     A6
   1148     ;; Shift 0 into quotient.
   1149     brlo 1f
   1150 .Lfits:
   1151     ;; Divisor fits into dividend.
   1152     SUB     C0,     A0
   1153     sbc     C1,     A1
   1154     sbc     C2,     A2
   1155     sbc     C3,     A3
   1156     sbc     C4,     A4
   1157     sbc     C5,     A5
   1158     sbc     C6,     A6
   1159     ;; Shift 1 into quotient.
   1160     sec
   1161     rol     Q0
   1162     skipnext
   1163 1:  lsl     Q0
   1164     rol     Q1
   1165     rol     Q2
   1166     rol     Q3
   1167     rol     Q4
   1168     rol     Q5
   1169     rol     Q6
   1170     rol     Q7
   1171     dec     Cnt
   1172     brne .Loop
   1173 
   1174     wmov    CA,     Q0
   1175     wmov    C1,     Q2
   1176     wmov    C3,     Q4
   1177     wmov    C5,     Q6
   1178     clr     ZERO
   1179 
   1180     ldi     Carry,  64
   1181     sub     Carry,  QBits
   1182     F7call  normalize.round.store_with_flags
   1183 
   1184     do_epilogue_restores 12
   1185 ENDF div
   1186 
   1187 #endif /* F7MOD_div_ */
   1188 
   1189 
   1190 #if defined (F7MOD_sqrt16_) && defined (__AVR_HAVE_MUL__)
   1191 
   1192 #define     Mask    C6
   1193 #define     Q0      C3      /*  = R22  */
   1194 #define     Q1      C4      /*  = R23  */
   1195 
   1196 ;; uint16_t R24 = sqrt16_XXX (uint16_t R24);
   1197 ;; Clobbers:   R22, R23, TMP.
   1198 ;;
   1199 ;; XXX = floor:  Return integral part of square-root of R25:R24 with R25 = 0.
   1200 ;;               Error is in [0, -1 LSB).
   1201 ;; XXX = round:  Return quare-root of R25:R24 rounded to nearest integer.
   1202 ;;               R25 = (Q[] >= 65281) = (Q > 0xff00),  i.e. if Q[] is not
   1203 ;;               bigger than 0xff00, then the result fits in 8 bits.
   1204 ;;               Return C = 0 if the result is the same as for XXX = floor,
   1205 ;;               error in [0, -1/2 LSB)
   1206 ;;               Return C = 1 if the result is one higher than for XXX = floor,
   1207 ;;               error in [1/2 LSB, 0).
   1208 DEFUN sqrt16_round
   1209     set
   1210     skipnext
   1211     ;; ...
   1212 LABEL sqrt16_floor
   1213     clt ; Skipped?
   1214     movw    Q0,     r24
   1215     clr     C5
   1216     ldi     Mask,   1 << 7
   1217 
   1218 .Loop_mask:
   1219     add     C5,     Mask
   1220     mul     C5,     C5
   1221     cp      Q0,     R0
   1222     cpc     Q1,     R1
   1223     brsh 1f
   1224     sub     C5,     Mask
   1225 1:  lsr     Mask
   1226     brne .Loop_mask
   1227 
   1228     brtc .Ldone             ; No rounding  =>  C6 will be 0.
   1229 
   1230     ;; Rounding:  (X + 1/2)^2  =  X^2 + X + 1/4,  thus probing
   1231     ;; for bit -1 is testing Q[] against  C5^2 + C5.
   1232     mul     C5,     C5
   1233     add     R0,     C5
   1234     adc     R1,     C6      ; Exploit C6 === Mask = 0.
   1235     cp      R0,     Q0
   1236     cpc     R1,     Q1
   1237     brcc .Ldone
   1238     ;; If  C5^2 + C5 + 1/4  fits into Q[], then round up and C = 1.
   1239     adiw    C5,     1       ; Exploit C6 === Mask = 0.
   1240     sec
   1241 
   1242 .Ldone:
   1243     clr     __zero_reg__
   1244     ret
   1245 ENDF sqrt16_round
   1246 #undef Mask
   1247 #undef Q0
   1248 #undef Q1
   1249 #endif /* F7MOD_sqrt16_ && MUL */
   1250 
   1251 #ifdef F7MOD_sqrt_approx_
   1252 DEFUN sqrt_approx
   1253     push    r17
   1254     push    r16
   1255     wmov    XL,     r24
   1256     wmov    ZL,     r22
   1257 
   1258     ;; C[] = 0.
   1259     .global __clr_8
   1260     XCALL   __clr_8
   1261 
   1262     ldd     C5,     Z+5+Off
   1263     ldd     C6,     Z+6+Off
   1264 
   1265     ldd     Carry,  Z+0+Expo
   1266     ldd     TMP,    Z+1+Expo
   1267     wmov    ZL,     XL
   1268 
   1269     st      Z,      ZERO
   1270 
   1271     asr     TMP
   1272     ror     Carry
   1273     std     Z+1+Expo,   TMP
   1274     std     Z+0+Expo,   Carry
   1275 
   1276     ;; Re-interpreting our Q-format 1.xx mantissa as Q2.yy, we have to shift
   1277     ;; the mantissa to the right by 1.  As we need an even exponent, multiply
   1278     ;; the mantissa by 2 for odd exponents, i.e. only right-shift if .expo
   1279     ;; is even.
   1280 
   1281     brcs 1f
   1282     lsr     C6
   1283     ror     C5
   1284 
   1285 1:
   1286     F7call  sqrt16_round
   1287 
   1288     ;; sqrt16_round() returns:   C = 0:  error in [0, -1/2 LSB).
   1289     ;;                           C = 1:  error in [1/2 LSB, 0)
   1290 
   1291     brcc 2f
   1292     ;; Undo the round-up from sqrt16_round(); this will transform to
   1293     ;; error in [-1/2 LSB, -1 LSB).
   1294     sbiw    C5,     1
   1295     ;; Together with the correct bit C4.7, the error is in  [0, -1/2 LSB).
   1296     ori     C4,     1 << 7
   1297 
   1298 2:  ;; Setting C4.6 adds 1/4 LSB and the error is now in [1/4 LSB, -1/4 LSB)
   1299     ;; in either case.
   1300     ori     C4,     1 << 6
   1301 
   1302     ;; ????????????
   1303     ;; sqrt16_round() runs on integers which means that it computes the
   1304     ;; square root of  mant * 2^14  if we regard  mant as Q-format 2.yy,
   1305     ;; i.e. 2 integral bits.  The result is  sqrt(mant) * 2^7,
   1306     ;; and in order to get the same scaling like the input, .expo has to
   1307     ;; be adjusted by 7. ???????????????
   1308 
   1309     ldi     Carry,  8
   1310     F7call  normalize.store_with_flags
   1311 
   1312     pop     r16
   1313     pop     r17
   1314     ret
   1315 
   1316 ENDF sqrt_approx
   1317 #endif /* F7MOD_sqrt_approx_ */
   1318 
   1319 
   1320 #undef CA
   1321 #undef C0
   1322 #undef C1
   1323 #undef C2
   1324 #undef C3
   1325 #undef C4
   1326 #undef C5
   1327 #undef C6
   1328 #undef Carry
   1329 
   1330 
   1331 #ifdef F7MOD_D_fabs_
   1332 _DEFUN __fabs
   1333     DALIAS fabs
   1334     LALIAS fabsl
   1335     andi    R25,    0b01111111
   1336     ret
   1337 _ENDF __fabs
   1338 #endif /* F7MOD_D_fabs_ */
   1339 
   1340 
   1341 #ifdef F7MOD_D_neg_
   1342 _DEFUN __neg
   1343 _LABEL __negdf2
   1344     subi    R25,    0b10000000
   1345     ret
   1346 _ENDF __neg
   1347 #endif /* F7MOD_D_neg_ */
   1348 
   1349 
   1350 #ifdef F7MOD_D_signbit_
   1351 _DEFUN __signbit
   1352     DALIAS signbit
   1353     LALIAS signbitl
   1354     bst     R25,    7
   1355     clr     R25
   1356     clr     R24
   1357     bld     R24,    0
   1358     ret
   1359 _ENDF __signbit
   1360 #endif /* F7MOD_D_signbit_ */
   1361 
   1362 
   1363 #ifdef F7MOD_D_copysign_
   1364 _DEFUN __copysign
   1365     DALIAS copysign
   1366     LALIAS copysignl
   1367     bst     R17,    7
   1368     bld     R25,    7
   1369     ret
   1370 _ENDF __copysign
   1371 #endif /* F7MOD_D_copysign_ */
   1372 
   1373 
   1374 #ifdef F7MOD_D_isinf_
   1375 _DEFUN __isinf
   1376     DALIAS isinf
   1377     LALIAS isinfl
   1378     F7call  class_D
   1379     ;; Inf: T = Z = 1.
   1380     brtc 0f
   1381     ldi     R24,    1
   1382     breq 1f
   1383 0:
   1384     clr     R24
   1385 1:
   1386     clr     R25
   1387     ret
   1388 _ENDF __isinf
   1389 #endif /* F7MOD_D_isinf_ */
   1390 
   1391 
   1392 #ifdef F7MOD_D_isnan_
   1393 _DEFUN __isnan
   1394     DALIAS isnan
   1395     LALIAS isnanl
   1396     F7call  class_D
   1397     ;; NaN: T = 1, Z = 0.
   1398     brtc 0f
   1399     ldi     R24,    1
   1400     brne 1f
   1401 0:
   1402     clr     R24
   1403 1:
   1404     clr     R25
   1405     ret
   1406 _ENDF __isnan
   1407 #endif /* F7MOD_D_isnan_ */
   1408 
   1409 
   1410 #ifdef F7MOD_D_isfinite_
   1411 _DEFUN __isfinite
   1412     DALIAS isfinite
   1413     LALIAS isfinitel
   1414     F7call  class_D
   1415     ;; Number <=> T = 0.
   1416     bld     R24,    0
   1417     com     R24
   1418     andi    R24,    1
   1419     clr     R25
   1420     ret
   1421 _ENDF __isfinite
   1422 #endif /* F7MOD_D_isfinite_ */
   1423 
   1424 
   1425 #ifdef F7MOD_D_class_
   1426 ;; The encoded exponent has 11 Bits.
   1427 #define MAX_BIASED_EXPO 0b0111111111110000
   1428 
   1429 ;; Classify a double in R18[]
   1430 ;; Number: T-Flag = 0.
   1431 ;; +-Inf : T-Flag = 1, Z-Flag = 1.
   1432 ;; NaN   : T-Flag = 1, Z-Flag = 0.
   1433 DEFUN class_D
   1434     wmov    R26,    R24
   1435     andi    R26,    lo8 (MAX_BIASED_EXPO)
   1436     andi    R27,    hi8 (MAX_BIASED_EXPO)
   1437     subi    R26,    lo8 (MAX_BIASED_EXPO)
   1438     sbci    R27,    hi8 (MAX_BIASED_EXPO)
   1439     clt
   1440     brne .L.number
   1441     set
   1442     ;; Set sign and expo to 0.
   1443     clr     R25
   1444     andi    R24,    lo8 (~MAX_BIASED_EXPO)
   1445     ;; What remains is the mantissa.
   1446     ;; Mantissa == 0  =>  +/-Inf.
   1447     ;; Mantissa != 0  =>  NaN.
   1448     ;; Compare R18[] against sign_extend(R26) with R26 = 0.
   1449     .global __cmpdi2_s8
   1450     XJMP    __cmpdi2_s8
   1451 .L.number:
   1452     ret
   1453 
   1454 ENDF class_D
   1455 #endif /* F7MOD_D_class_ */
   1456 
   1457 
   1458 #ifdef F7MOD_call_dd_
   1459 
   1460 ;; Provide double wrappers for functions that operate on f7_t and get f7_t*.
   1461 ;;
   1462 ;; We set up a frame of sizeof(f7_t), convert the input double in R18[] to
   1463 ;; f7_t in that frame location, then call *Z and finally convert the result f7_t
   1464 ;; to double R18[] if that's requested.
   1465 ;;
   1466 ;; call_dd:     double func (double A)
   1467 ;;              void (*Z) (f7_t *aa, const f7_t *aa)
   1468 ;;
   1469 ;; call_dx:     double func (type_t A)  , sizeof(type_t) <= 4
   1470 ;;              void (*Z) (f7_t *aa, type_t)
   1471 ;;
   1472 ;; call_xd:     type_t func (double A)
   1473 ;;              type_t (*Z) (const f7_t *aa)
   1474 ;;
   1475 ;; call_ddx:    double func (double A, word_t)  , sizeof (word_t) <= 2
   1476 ;;              void (*Z) (f7_t *aa, const f7_t *aa, word_t)
   1477 
   1478 #define WHAT    R13
   1479 
   1480 DEFUN call_dd   ; WHAT = R13 = 3
   1481     inc     ZERO
   1482 LABEL call_xd   ; WHAT = R13 = 2
   1483     inc     ZERO
   1484 LABEL call_ddx  ; WHAT = R13 = 1
   1485     inc     ZERO
   1486 LABEL call_dx   ; WHAT = R13 = 0
   1487     push    WHAT
   1488     mov     WHAT,   ZERO
   1489     clr     ZERO
   1490     ;; R14/R15 hold Z, the address of the f7_worker function, until we need it.
   1491     push    r14
   1492     push    r15
   1493     wmov    r14,     Z
   1494 
   1495 #define n_pushed    4
   1496 #define n_frame     10
   1497 
   1498     do_prologue_saves n_pushed, n_frame
   1499     ;; Y = FramePointer + 1
   1500     adiw    Y,      1
   1501     dec     WHAT
   1502     brmi .Ldx                   ; WHAT was initially 0.
   1503     ;; FP + 1 = (f7_t) arg1
   1504     wmov    r16,    Y
   1505     ;; The double argument is in R18[].
   1506     XCALL   F7_NAME (set_double_impl)
   1507     tst     WHAT
   1508     brne .Lno.ddx               ; WHAT was initially != 1.
   1509     ;; call_ddx: Set R20/21 to the 2-byte scalar / pointer argument.
   1510     ;; Fetch it from where prologue_saves put it.
   1511     ldd     r20,    Y + n_frame + 3     ; Saved R16
   1512     ldd     r21,    Y + n_frame + 2     ; Saved R17
   1513 .Lno.ddx:
   1514     wmov    r22,    Y           ; &arg1 (input)
   1515 .Ldo.dx:
   1516     wmov    r24,    Y           ; &arg1 (output)
   1517     wmov    Z,      r14
   1518     XICALL
   1519     dec     WHAT
   1520     breq .Lepilogue             ; WHAT was initially 2: Return non-double.
   1521     wmov    r24,    Y           ; &arg1
   1522     XCALL   F7_NAME (get_double)
   1523 .Lepilogue:
   1524     ;; + 3 to account for R13...R15 pushed prior to do_prologue_saves.
   1525     do_epilogue_restores n_pushed + 3, n_frame
   1526 
   1527 .Ldx:
   1528     ;; call_dx: Copy the 4-byte input scalar from R22[4] to R20[4].
   1529     wmov    r20,    r22
   1530     wmov    r22,    r24
   1531     rjmp .Ldo.dx
   1532 
   1533 ENDF call_dd
   1534 #endif /* F7MOD_call_dd_ */
   1535 
   1536 
   1537 #ifdef F7MOD_call_ddd_
   1538 
   1539 ;; Provide double wrappers for functions that operate on f7_t and get f7_t*.
   1540 ;;
   1541 ;; We set up a frame of 2 * sizeof(f7_t), convert the input doubles in R18[]
   1542 ;; and R10[] to f7_t in these frame locations, then call *Z and finally
   1543 ;; convert the result f7_t to double R18[] if that's requested.
   1544 ;;
   1545 ;; call_ddd:    double func (double A, double B)
   1546 ;;              void (*Z) (f7_t *aa, const f7_t *aa, const f7_t *bb)
   1547 ;;
   1548 ;; call_xdd:    type_t func (double A, double B)
   1549 ;;              type_t (*Z) (const f7_t *aa, const f7_t *bb)
   1550 
   1551 DEFUN call_ddd
   1552     inc     ZERO
   1553 LABEL call_xdd
   1554     ;; R8/R9 hold Z, the address of the f7_worker function, until we need it.
   1555     push    r9
   1556     push    r8
   1557     wmov    r8,     Z
   1558     ;; This is an argument to call.2 and will be accessed by the arg pointer.
   1559     push    ZERO
   1560     clr     ZERO
   1561     rcall   call.2
   1562     pop     TMP
   1563     pop     r8
   1564     pop     r9
   1565     ret
   1566 
   1567 #define n_pushed    4
   1568 #define n_frame     20
   1569 
   1570 call.2:
   1571     do_prologue_saves n_pushed, n_frame
   1572     ;; Y = FramePointer + 1
   1573     adiw    Y,      1
   1574     ;; FP + 1 = (f7_t) arg1
   1575     wmov    r16,    Y
   1576     ;; First double argument is already in R18[].
   1577     XCALL   F7_NAME (set_double_impl)
   1578     ;; FP + 11 = (f7_t) arg2
   1579     wmov    r16,    Y
   1580     subi    r16,    lo8 (-10)
   1581     sbci    r17,    hi8 (-10)
   1582     ;; Move second double argument to R18[].
   1583     wmov    r18,    r10
   1584     wmov    r20,    r12
   1585     wmov    r22,    r14
   1586     ;; Get high word of arg2 from where prologue_saves put it.
   1587     ldd     r24,    Y + n_frame + 3     ; Saved R16
   1588     ldd     r25,    Y + n_frame + 2     ; Saved R17
   1589     XCALL   F7_NAME (set_double_impl)
   1590     ;; Z (f7_t *arg1, const f7_t *arg1, const f7_t *arg2)
   1591     wmov    Z,      r8
   1592     wmov    r24,    Y                   ; &arg1
   1593     ;; WHAT == 0  =>  call_xdd
   1594     ;; WHAT != 0  =>  call_ddd
   1595     ldd     TMP,    Y + n_frame + n_pushed + PC_SIZE
   1596     tst     TMP
   1597     breq .Lxdd
   1598     wmov    r22,    Y                   ; &arg1
   1599     wmov    r20,    r16                 ; &arg2
   1600     XICALL
   1601     wmov    r24,    Y                   ; &arg1
   1602     XCALL   F7_NAME (get_double)
   1603 .Lepilogue:
   1604     do_epilogue_restores n_pushed, n_frame
   1605 .Lxdd:
   1606     wmov    r22,    r16                 ; &arg2
   1607     XICALL
   1608     rjmp .Lepilogue
   1609 ENDF call_ddd
   1610 #endif /* F7MOD_call_ddd_ */
   1611 
   1612 #include "f7-wraps.h"
   1613 
   1614 #endif /* !AVR_TINY */
   1615