Initial revision
authorDoug Evans <dje@gnu.org>
Mon, 11 Jul 1994 22:45:37 +0000 (22:45 +0000)
committerDoug Evans <dje@gnu.org>
Mon, 11 Jul 1994 22:45:37 +0000 (22:45 +0000)
From-SVN: r7726

gcc/config/h8300/lib1funcs.asm [new file with mode: 0644]

diff --git a/gcc/config/h8300/lib1funcs.asm b/gcc/config/h8300/lib1funcs.asm
new file mode 100644 (file)
index 0000000..370ba75
--- /dev/null
@@ -0,0 +1,672 @@
+;; libgcc1 routines for the Hitachi h8/300 cpu.
+;; Contributed by Steve Chamberlain.
+;; sac@cygnus.com
+;; This file is in the public domain.
+
+/* Assembler register definitions.  */
+
+#define A0 r0
+#define A0L r0l
+#define A0H r0h
+
+#define A1 r1
+#define A1L r1l
+#define A1H r1h
+
+#define A2 r2
+#define A2L r2l
+#define A2H r2h
+
+#define A3 r3
+#define A3L r3l
+#define A3H r3h
+
+#define S0 r4
+#define S0L r4l
+#define S0H r4h
+
+#define S1 r5
+#define S1L r5l
+#define S1H r5h
+
+#define S2 r6
+#define S2L r6l
+#define S2H r6h
+
+#ifdef __H8300__
+#define MOVP   mov.w   /* pointers are 16 bits */
+#define ADDP   add.w
+#define CMPP   cmp.w
+#define PUSHP  push
+#define POPP   pop
+
+#define A0P    r0
+#define A1P    r1
+#define A2P    r2
+#define A3P    r3
+#define S0P    r4
+#define S1P    r5
+#define S2P    r6
+#endif
+
+#ifdef __H8300H__
+#define MOVP   mov.l   /* pointers are 32 bits */
+#define ADDP   add.l
+#define CMPP   cmp.l
+#define PUSHP  push.l
+#define POPP   pop.l
+
+#define A0P    er0
+#define A1P    er1
+#define A2P    er2
+#define A3P    er3
+#define S0P    er4
+#define S1P    er5
+#define S2P    er6
+
+#define A0E    e0
+#define A1E    e1
+#define A2E    e2
+#define A3E    e3
+#endif
+
+#ifdef L_cmpsi2
+#ifdef __H8300__
+       .section .text
+       .align 2
+       .global ___cmpsi2
+___cmpsi2:
+       cmp.w   A2,A0
+       bne     .L2
+       cmp.w   A3,A1
+       bne     .L2
+       mov.w   #1,A0
+       rts
+.L2:
+       cmp.w   A0,A2
+       bgt     .L4
+       bne     .L3
+       cmp.w   A1,A3
+       bls     .L3
+.L4:
+       sub.w   A0,A0
+       rts
+.L3:
+       mov.w   #2,A0
+.L5:
+       rts
+       .end
+#endif
+#endif /* L_cmpsi2 */
+
+#ifdef L_ucmpsi2
+#ifdef __H8300__
+       .section .text
+       .align 2
+       .global ___ucmpsi2
+___ucmpsi2:
+       cmp.w   A2,A0
+       bne     .L2
+       cmp.w   A3,A1
+       bne     .L2
+       mov.w   #1,A0
+       rts
+.L2:
+       cmp.w   A0,A2
+       bhi     .L4
+       bne     .L3
+       cmp.w   A1,A3
+       bls     .L3
+.L4:
+       sub.w   A0,A0
+       rts
+.L3:
+       mov.w   #2,A0
+.L5:
+       rts
+       .end
+#endif
+#endif /* L_ucmpsi2 */
+
+#ifdef L_divhi3
+
+;; HImode divides for the H8/300.
+;; We bunch all of this into one object file since there are several
+;; "supporting routines".
+
+; general purpose normalize routine
+; 
+; divisor in A0
+; dividend in A1
+; turns both into +ve numbers, and leaves what the answer sign
+; should be in A2L
+
+#ifdef __H8300__
+       .section .text
+       .align 2
+divnorm:
+       mov.b   #0x0,A2L
+       or      A0H,A0H         ; is divisor > 0
+       bge     _lab1                   
+       not     A0H             ; no - then make it +ve
+       not     A0L
+       adds    #1,A0                   
+       xor     #0x1,A2L        ; and remember that in A2L
+_lab1: or      A1H,A1H ; look at dividend
+       bge     _lab2           
+       not     A1H             ; it is -ve, make it positive
+       not     A1L
+       adds    #1,A1
+       xor     #0x1,A2L; and toggle sign of result
+_lab2: rts
+
+; A0=A0/A1 signed
+
+       .global ___divhi3
+___divhi3:
+       bsr     divnorm
+       bsr     ___udivhi3
+negans:        or      A2L,A2L ; should answer be negative ?
+       beq     _lab4
+       not     A0H     ; yes, so make it so
+       not     A0L
+       adds    #1,A0
+_lab4: rts     
+
+; A0=A0%A1 signed
+
+       .global ___modhi3
+___modhi3:
+       bsr     divnorm
+       bsr     ___udivhi3
+       mov     A3,A0
+       bra     negans
+
+; A0=A0%A1 unsigned
+
+       .global ___umodhi3
+___umodhi3:
+       bsr     ___udivhi3
+       mov     A3,A0
+       rts
+
+; A0=A0/A1 unsigned
+; A3=A0%A1 unsigned
+; A2H trashed
+; D high 8 bits of denom
+; d low 8 bits of denom
+; N high 8 bits of num
+; n low 8 bits of num
+; M high 8 bits of mod
+; m low 8 bits of mod
+; Q high 8 bits of quot
+; q low 8 bits of quot
+; P preserve
+
+; The h8 only has a 16/8 bit divide, so we look at the incoming and
+; see how to partition up the expression.
+
+       .global ___udivhi3
+___udivhi3:
+                               ; A0 A1 A2 A3 
+                               ; Nn Dd       P
+       sub.w   A3,A3           ; Nn Dd xP 00 
+       or      A1H,A1H          
+       bne     divlongway
+       or      A0H,A0H         
+       beq     _lab6           
+
+; we know that D == 0 and N is != 0
+       mov.b   A0H,A3L         ; Nn Dd xP 0N
+       divxu   A1L,A3          ;          MQ
+       mov.b   A3L,A0H         ; Q
+; dealt with N, do n
+_lab6: mov.b   A0L,A3L         ;           n
+       divxu   A1L,A3          ;          mq
+       mov.b   A3L,A0L         ; Qq
+       mov.b   A3H,A3L         ;           m
+       mov.b   #0x0,A3H        ; Qq       0m
+       rts     
+
+; D != 0 - which means the denominator is
+;          loop around to get the result.
+
+divlongway:
+       mov.b   A0H,A3L         ; Nn Dd xP 0N
+       mov.b   #0x0,A0H        ; high byte of answer has to be zero
+       mov.b   #0x8,A2H        ;       8
+div8:  add.b   A0L,A0L         ; n*=2
+       rotxl   A3L             ; Make remainder bigger
+       rotxl   A3H             
+       sub.w   A1,A3           ; Q-=N
+       bhs     setbit          ; set a bit ?
+       add.w   A1,A3           ;  no : too far , Q+=N
+
+       dec     A2H             
+       bne     div8            ; next bit      
+       rts     
+
+setbit:        inc     A0L             ; do insert bit
+       dec     A2H             
+       bne     div8            ; next bit      
+       rts     
+
+#endif /* __H8300__ */
+#endif /* L_divhi3 */
+
+#ifdef L_divsi3
+
+;; 4 byte integer divides for the H8/300.
+;;
+;; We have one routine which does all the work and lots of 
+;; little ones which prepare the args and massage the sign.
+;; We bunch all of this into one object file since there are several
+;; "supporting routines".
+
+#ifdef __H8300H__
+       .h8300h
+#endif
+
+       .section .text
+       .align 2
+
+; Put abs SIs into r0/r1 and r2/r3, and leave a 1 in r6l with sign of rest.
+; This function is here to keep branch displacements small.
+
+#ifdef __H8300__
+
+divnorm:
+       mov.b   #0,S2L          ; keep the sign in S2
+       mov.b   A0H,A0H         ; is the numerator -ve
+       bge     postive
+
+       ; negate arg
+       not     A0H
+       not     A1H
+       not     A0L
+       not     A1L
+
+       add     #1,A1L
+       addx    #0,A1H
+       addx    #0,A0H
+       addx    #0,A0L
+
+       mov.b   #1,S2L          ; the sign will be -ve
+postive:
+       mov.b   A2H,A2H         ; is the denominator -ve
+       bge     postive2
+       not     A2L             
+       not     A2H
+       not     A3L
+       not     A3H
+       add.b   #1,A3L  
+       addx    #0,A3H
+       addx    #0,A2L
+       addx    #0,A2H
+       xor     #1,S2L          ; toggle result sign
+postive2:
+       rts
+
+#else /* __H8300H__ */
+
+divnorm:
+       mov.b   #0,S2L          ; keep the sign in S2
+       mov.l   A0P,A0P         ; is the numerator -ve
+       bge     postive
+
+       neg.l   A0P             ; negate arg
+       mov.b   #1,S2L          ; the sign will be -ve
+
+postive:
+       mov.l   A1P,A1P         ; is the denominator -ve
+       bge     postive2
+
+       neg.l   A1P             ; negate arg
+       xor.b   #1,S2L          ; toggle result sign
+
+postive2:
+       rts
+
+#endif
+
+; numerator in A0/A1
+; denominator in A2/A3
+       .global ___modsi3
+___modsi3:
+       PUSHP   S2P             
+       PUSHP   S0P
+       PUSHP   S1P
+
+       bsr     divnorm
+       bsr     divmodsi4
+#ifdef __H8300__
+       mov     S0,A0
+       mov     S1,A1
+#else
+       mov.l   S0P,A0P
+#endif
+       bra     exitdiv
+
+       .global ___udivsi3
+___udivsi3:
+       PUSHP   S2P
+       PUSHP   S0P
+       PUSHP   S1P
+       mov.b   #0,S2L  ; keep sign low
+       bsr     divmodsi4
+       bra     exitdiv
+
+       .global ___umodsi3
+___umodsi3:
+       PUSHP   S2P
+       PUSHP   S0P
+       PUSHP   S1P
+       mov.b   #0,S2L  ; keep sign low
+       bsr     divmodsi4
+#ifdef __H8300__
+       mov     S0,A0
+       mov     S1,A1
+#else
+       mov.l   S0P,A0P
+#endif
+       bra     exitdiv
+       
+       .global ___divsi3
+___divsi3:
+       PUSHP   S2P
+       PUSHP   S0P
+       PUSHP   S1P
+       jsr     divnorm
+       jsr     divmodsi4
+
+       ; examine what the sign should be
+exitdiv:
+       POPP    S1P
+       POPP    S0P
+
+       or      S2L,S2L
+       beq     reti
+       
+       ; should be -ve
+#ifdef __H8300__
+       not     A0H
+       not     A1H
+       not     A0L
+       not     A1L
+
+       add     #1,A1L
+       addx    #0,A1H
+       addx    #0,A0H
+       addx    #0,A0L
+#else /* __H8300H__ */
+       neg.l   A0P
+#endif
+
+reti:
+       POPP    S2P
+       rts     
+
+       ; takes A0/A1 numerator (A0P for 300h)
+       ; A2/A3 denominator (A1P for 300h)
+       ; returns A0/A1 quotient (A0P for 300h)
+       ; S0/S1 remainder (S0P for 300h)
+       ; trashes S2
+
+#ifdef __H8300__
+
+divmodsi4:
+        sub.w  S0,S0           ; zero play area
+        mov.w  S0,S1
+        mov.b  A2H,S2H
+        or     A2L,S2H
+        or     A3H,S2H
+        bne    DenHighZero
+        mov.b  A0H,A0H
+        bne    NumByte0Zero
+        mov.b  A0L,A0L
+        bne    NumByte1Zero
+        mov.b  A1H,A1H
+        bne    NumByte2Zero
+        bra    NumByte3Zero
+NumByte0Zero:
+       mov.b   A0H,S1L
+        divxu  A3L,S1
+        mov.b  S1L,A0H
+NumByte1Zero:
+       mov.b   A0L,S1L
+        divxu  A3L,S1
+        mov.b  S1L,A0L
+NumByte2Zero:
+       mov.b   A1H,S1L
+        divxu  A3L,S1
+        mov.b  S1L,A1H
+NumByte3Zero:
+       mov.b   A1L,S1L
+        divxu  A3L,S1
+        mov.b  S1L,A1L
+
+        mov.b  S1H,S1L
+        mov.b  #0x0,S1H
+        rts    
+
+; have to do the divide by shift and test
+DenHighZero:
+       mov.b   A0H,S1L
+        mov.b  A0L,A0H
+        mov.b  A1H,A0L
+        mov.b  A1L,A1H
+
+        mov.b  #0,A1L
+        mov.b  #24,S2H ; only do 24 iterations
+
+nextbit:
+       add.w   A1,A1   ; double the answer guess
+        rotxl  A0L
+        rotxl  A0H
+
+        rotxl  S1L     ; double remainder
+        rotxl  S1H
+        rotxl  S0L
+        rotxl  S0H
+        sub.w  A3,S1   ; does it all fit
+        subx   A2L,S0L
+        subx   A2H,S0H
+        bhs    setone   
+
+        add.w  A3,S1   ; no, restore mistake
+        addx   A2L,S0L
+        addx   A2H,S0H
+
+        dec    S2H
+        bne    nextbit
+        rts    
+       
+setone:
+       inc     A1L
+        dec    S2H
+        bne    nextbit
+        rts    
+
+#else /* __H8300H__ */
+
+divmodsi4:
+       sub.l   S0P,S0P         ; zero play area
+       mov.w   A1E,A1E         ; denominator top word 0?
+       bne     DenHighZero
+
+       ; do it the easy way, see page 107 in manual
+       mov.w   A0E,A2
+       extu.l  A2P
+       divxu.w A1,A2P
+       mov.w   A2E,A0E
+       divxu.w A1,A0P
+       mov.w   A0E,S0
+       mov.w   A2,A0E
+       extu.l  S0P
+       rts
+
+DenHighZero:
+       mov.w   A0E,A2
+       mov.b   A2H,S0L
+       mov.b   A2L,A2H
+       mov.b   A0H,A2L
+       mov.w   A2,A0E
+       mov.b   A0L,A0H
+       mov.b   #0,A0L
+       mov.b   #24,S2H         ; only do 24 iterations
+
+nextbit:
+       shll.l  A0P             ; double the answer guess
+       rotxl.l S0P             ; double remainder
+       sub.l   A1P,S0P         ; does it all fit?
+       bhs     setone
+
+       add.l   A1P,S0P         ; no, restore mistake
+       dec     S2H
+       bne     nextbit
+       rts
+
+setone:
+       inc     A0L
+       dec     S2H
+       bne     nextbit
+       rts
+
+#endif
+#endif /* L_divsi3 */
+
+#ifdef L_mulhi3
+
+;; HImode multiply.
+; The h8 only has an 8*8->16 multiply.
+; The answer is the same as:
+; 
+; product = (srca.l * srcb.l) + ((srca.h * srcb.l) + (srcb.h * srca.l)) * 256
+; (we can ignore A1.h * A0.h cause that will all off the top)
+; A0 in
+; A1 in 
+; A0 answer
+
+#ifdef __H8300__
+       .section .text
+       .align 2
+       .global ___mulhi3
+___mulhi3:
+       mov.b   A1L,A2L         ; A2l gets srcb.l
+       mulxu   A0L,A2          ; A2 gets first sub product 
+
+       mov.b   A0H,A3L         ; prepare for
+       mulxu   A1L,A3          ; second sub product
+
+       add.b   A3L,A2H         ; sum first two terms
+
+       mov.b   A1H,A3L         ; third sub product
+       mulxu   A0L,A3          
+
+       add.b   A3L,A2H         ; almost there
+       mov.w   A2,A0           ; that is
+       rts
+
+#endif
+#endif /* L_mulhi3 */
+
+#ifdef L_mulsi3
+
+;; SImode multiply.
+;; 
+;; I think that shift and add may be sufficient for this.  Using the
+;; supplied 8x8->16 would need 10 ops of 14 cycles each + overhead.  This way
+;; the inner loop uses maybe 20 cycles + overhead, but terminates
+;; quickly on small args.
+;;
+;; A0/A1 src_a
+;; A2/A3 src_b
+;;
+;;  while (a) 
+;;    {
+;;      if (a & 1)
+;;        r += b;
+;;      a >>= 1;
+;;      b <<= 1;
+;;    }
+
+       .section .text
+       .align 2
+
+#ifdef __H8300__
+
+       .global ___mulsi3
+___mulsi3:
+       PUSHP   S0P
+       PUSHP   S1P
+       PUSHP   S2P
+       
+       sub.w   S0,S0
+       sub.w   S1,S1
+       
+       ; while (a)
+_top:  mov.w   A0,A0
+       bne     _more
+       mov.w   A1,A1
+       beq     _done
+_more: ; if (a & 1)
+       bld     #0,A1L
+       bcc     _nobit
+       ; r += b
+       add.w   A3,S1
+       addx    A2L,S0L
+       addx    A2H,S0H
+_nobit:
+       ; a >>= 1
+       shlr    A0H
+       rotxr   A0L
+       rotxr   A1H
+       rotxr   A1L
+       
+       ; b <<= 1
+       add.w   A3,A3
+       addx    A2L,A2L
+       addx    A2H,A2H
+       bra     _top
+
+_done:
+       mov.w   S0,A0   
+       mov.w   S1,A1
+       POPP    S2P
+       POPP    S1P
+       POPP    S0P
+       rts
+
+#else /* __H8300H__ */
+
+       .h8300h
+
+       .global ___mulsi3
+___mulsi3:
+       sub.l   A2P,A2P
+
+       ; while (a)
+_top:  mov.l   A0P,A0P
+       beq     _done
+
+       ; if (a & 1)
+       bld     #0,A0L
+       bcc     _nobit
+
+       ; r += b
+       add.l   A1P,A2P
+
+_nobit:
+       ; a >>= 1
+       shlr.l  A0P
+
+       ; b <<= 1
+       shll.l  A1P
+       bra     _top
+
+_done:
+       mov.l   A2P,A0P
+       rts
+
+#endif
+#endif /* L_mulsi3 */
\ No newline at end of file