blob: e08345a32801e93c6517592e6bff96707f66e61d [file] [log] [blame]
/* HImode div/mod functions for the GCC support library for the Renesas RL78 processors.
Copyright (C) 2012-2014 Free Software Foundation, Inc.
Contributed by Red Hat.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef __RL78_G10__
#include "vregs.h"
.macro make_generic which,need_result
.if \need_result
quot = r8
num = r10
den = r12
bit = r14
.else
num = r8
quot = r10
den = r12
bit = r14
.endif
quotB0 = quot
quotB1 = quot+1
numB0 = num
numB1 = num+1
denB0 = den
denB1 = den+1
bitB0 = bit
bitB1 = bit+1
#if 1
#define bit bc
#define bitB0 c
#define bitB1 b
#endif
num_lt_den\which:
.if \need_result
movw r8, #0
.else
movw ax, [sp+8]
movw r8, ax
.endif
ret
;; These routines leave DE alone - the signed functions use DE
;; to store sign information that must remain intact
.if \need_result
generic_div:
.else
generic_mod:
.endif
;; (quot,rem) = 8[sp] /% 10[sp]
movw hl, sp
movw ax, [hl+10] ; denH
cmpw ax, [hl+8] ; numH
bh $num_lt_den\which
;; (quot,rem) = 16[sp] /% 20[sp]
;; copy numerator
movw ax, [hl+8]
movw num, ax
;; copy denomonator
movw ax, [hl+10]
movw den, ax
movw ax, den
cmpw ax, #0
bnz $den_not_zero\which
movw num, #0
ret
den_not_zero\which:
.if \need_result
;; zero out quot
movw quot, #0
.endif
;; initialize bit to 1
movw bit, #1
; while (den < num && !(den & (1L << BITS_MINUS_1)))
shift_den_bit\which:
movw ax, den
mov1 cy,a.7
bc $enter_main_loop\which
cmpw ax, num
bh $enter_main_loop\which
;; den <<= 1
; movw ax, den ; already has it from the cmpw above
shlw ax, 1
movw den, ax
;; bit <<= 1
.if \need_result
#ifdef bit
shlw bit, 1
#else
movw ax, bit
shlw ax, 1
movw bit, ax
#endif
.else
;; if we don't need to compute the quotent, we don't need an
;; actual bit *mask*, we just need to keep track of which bit
inc bitB0
.endif
br $shift_den_bit\which
main_loop\which:
;; if (num >= den) (cmp den > num)
movw ax, den
cmpw ax, num
bh $next_loop\which
;; num -= den
movw ax, num
subw ax, den
movw num, ax
.if \need_result
;; res |= bit
mov a, quotB0
or a, bitB0
mov quotB0, a
mov a, quotB1
or a, bitB1
mov quotB1, a
.endif
next_loop\which:
;; den >>= 1
movw ax, den
shrw ax, 1
movw den, ax
.if \need_result
;; bit >>= 1
movw ax, bit
shrw ax, 1
movw bit, ax
.else
dec bitB0
.endif
enter_main_loop\which:
.if \need_result
movw ax, bit
cmpw ax, #0
.else
cmp0 bitB0
.endif
bnz $main_loop\which
main_loop_done\which:
ret
.endm
make_generic _d 1
make_generic _m 0
;----------------------------------------------------------------------
.global ___udivhi3
.type ___udivhi3,@function
___udivhi3:
;; r8 = 4[sp] / 6[sp]
call $!generic_div
ret
.size ___udivhi3, . - ___udivhi3
.global ___umodhi3
.type ___umodhi3,@function
___umodhi3:
;; r8 = 4[sp] % 6[sp]
call $!generic_mod
ret
.size ___umodhi3, . - ___umodhi3
;----------------------------------------------------------------------
.macro neg_ax
movw hl, ax
movw ax, #0
subw ax, [hl]
movw [hl], ax
.endm
.global ___divhi3
.type ___divhi3,@function
___divhi3:
;; r8 = 4[sp] / 6[sp]
movw de, #0
mov a, [sp+5]
mov1 cy, a.7
bc $div_signed_num
mov a, [sp+7]
mov1 cy, a.7
bc $div_signed_den
call $!generic_div
ret
div_signed_num:
;; neg [sp+4]
movw ax, sp
addw ax, #4
neg_ax
mov d, #1
mov a, [sp+7]
mov1 cy, a.7
bnc $div_unsigned_den
div_signed_den:
;; neg [sp+6]
movw ax, sp
addw ax, #6
neg_ax
mov e, #1
div_unsigned_den:
call $!generic_div
mov a, d
cmp0 a
bz $div_skip_restore_num
;; We have to restore the numerator [sp+4]
movw ax, sp
addw ax, #4
neg_ax
mov a, d
div_skip_restore_num:
xor a, e
bz $div_no_neg
movw ax, #r8
neg_ax
div_no_neg:
mov a, e
cmp0 a
bz $div_skip_restore_den
movw ax, sp
addw ax, #6
neg_ax
div_skip_restore_den:
ret
.size ___divhi3, . - ___divhi3
.global ___modhi3
.type ___modhi3,@function
___modhi3:
;; r8 = 4[sp] % 6[sp]
movw de, #0
mov a, [sp+5]
mov1 cy, a.7
bc $mod_signed_num
mov a, [sp+7]
mov1 cy, a.7
bc $mod_signed_den
call $!generic_mod
ret
mod_signed_num:
;; neg [sp+4]
movw ax, sp
addw ax, #4
neg_ax
mov d, #1
mov a, [sp+7]
mov1 cy, a.7
bnc $mod_unsigned_den
mod_signed_den:
;; neg [sp+6]
movw ax, sp
addw ax, #6
neg_ax
mod_unsigned_den:
call $!generic_mod
mov a, d
cmp0 a
bz $mod_no_neg
movw ax, #r8
neg_ax
;; Also restore numerator
movw ax, sp
addw ax, #4
neg_ax
mod_no_neg:
mov a, e
cmp0 a
bz $mod_skip_restore_den
movw ax, sp
addw ax, #6
neg_ax
mod_skip_restore_den:
ret
.size ___modhi3, . - ___modhi3
#endif