306 lines
5.1 KiB
ArmAsm
306 lines
5.1 KiB
ArmAsm
/* QImode div/mod functions for the GCC support library for the Renesas RL78 processors.
|
|
Copyright (C) 2012-2022 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/>. */
|
|
|
|
#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
|
|
|
|
#define bit b
|
|
#define den c
|
|
#define bitden bc
|
|
|
|
START_FUNC __generic_qidivmod\which
|
|
|
|
num_lt_den\which:
|
|
.if \need_result
|
|
mov r8, #0
|
|
.else
|
|
mov a, [hl+4]
|
|
mov r8, a
|
|
.endif
|
|
ret
|
|
|
|
num_eq_den\which:
|
|
.if \need_result
|
|
mov r8, #1
|
|
.else
|
|
mov r8, #0
|
|
.endif
|
|
ret
|
|
|
|
den_is_zero\which:
|
|
mov r8, #0x00
|
|
ret
|
|
|
|
;; These routines leave DE alone - the signed functions use DE
|
|
;; to store sign information that must remain intact
|
|
|
|
.if \need_result
|
|
.global __generic_qidiv
|
|
__generic_qidiv:
|
|
|
|
.else
|
|
|
|
.global __generic_qimod
|
|
__generic_qimod:
|
|
|
|
.endif
|
|
|
|
;; (quot,rem) = 4[hl] /% 6[hl]
|
|
|
|
mov a, [hl+4] ; num
|
|
cmp a, [hl+6] ; den
|
|
bz $num_eq_den\which
|
|
bnh $num_lt_den\which
|
|
|
|
;; copy numerator
|
|
; mov a, [hl+4] ; already there from above
|
|
mov num, a
|
|
|
|
;; copy denomonator
|
|
mov a, [hl+6]
|
|
mov den, a
|
|
|
|
cmp0 den
|
|
bz $den_is_zero\which
|
|
|
|
den_not_zero\which:
|
|
.if \need_result
|
|
;; zero out quot
|
|
mov quot, #0
|
|
.endif
|
|
|
|
;; initialize bit to 1
|
|
mov bit, #1
|
|
|
|
; while (den < num && !(den & (1L << BITS_MINUS_1)))
|
|
|
|
shift_den_bit\which:
|
|
|
|
.macro SDB_ONE\which
|
|
mov a, den
|
|
mov1 cy,a.7
|
|
bc $enter_main_loop\which
|
|
cmp a, num
|
|
bh $enter_main_loop\which
|
|
|
|
;; den <<= 1
|
|
; mov a, den ; already has it from the cmpw above
|
|
shl a, 1
|
|
mov den, a
|
|
|
|
;; bit <<= 1
|
|
shl bit, 1
|
|
.endm
|
|
|
|
SDB_ONE\which
|
|
SDB_ONE\which
|
|
|
|
br $shift_den_bit\which
|
|
|
|
main_loop\which:
|
|
|
|
;; if (num >= den) (cmp den > num)
|
|
mov a, den
|
|
cmp a, num
|
|
bh $next_loop\which
|
|
|
|
;; num -= den
|
|
mov a, num
|
|
sub a, den
|
|
mov num, a
|
|
|
|
.if \need_result
|
|
;; res |= bit
|
|
mov a, quot
|
|
or a, bit
|
|
mov quot, a
|
|
.endif
|
|
|
|
next_loop\which:
|
|
|
|
;; den, bit >>= 1
|
|
movw ax, bitden
|
|
shrw ax, 1
|
|
movw bitden, ax
|
|
|
|
enter_main_loop\which:
|
|
cmp0 bit
|
|
bnz $main_loop\which
|
|
|
|
main_loop_done\which:
|
|
ret
|
|
END_FUNC __generic_qidivmod\which
|
|
.endm
|
|
|
|
;----------------------------------------------------------------------
|
|
|
|
MAKE_GENERIC _d 1
|
|
MAKE_GENERIC _m 0
|
|
|
|
;----------------------------------------------------------------------
|
|
|
|
START_FUNC ___udivqi3
|
|
;; r8 = 4[sp] / 6[sp]
|
|
movw hl, sp
|
|
br $!__generic_qidiv
|
|
END_FUNC ___udivqi3
|
|
|
|
|
|
START_FUNC ___umodqi3
|
|
;; r8 = 4[sp] % 6[sp]
|
|
movw hl, sp
|
|
br $!__generic_qimod
|
|
END_FUNC ___umodqi3
|
|
|
|
;----------------------------------------------------------------------
|
|
|
|
.macro NEG_AX
|
|
movw hl, ax
|
|
mov a, #0
|
|
sub a, [hl]
|
|
mov [hl], a
|
|
.endm
|
|
|
|
;----------------------------------------------------------------------
|
|
|
|
START_FUNC ___divqi3
|
|
;; r8 = 4[sp] / 6[sp]
|
|
movw hl, sp
|
|
movw de, #0
|
|
mov a, [sp+4]
|
|
mov1 cy, a.7
|
|
bc $div_signed_num
|
|
mov a, [sp+6]
|
|
mov1 cy, a.7
|
|
bc $div_signed_den
|
|
br $!__generic_qidiv
|
|
|
|
div_signed_num:
|
|
;; neg [sp+4]
|
|
mov a, #0
|
|
sub a, [hl+4]
|
|
mov [hl+4], a
|
|
mov d, #1
|
|
mov a, [sp+6]
|
|
mov1 cy, a.6
|
|
bnc $div_unsigned_den
|
|
div_signed_den:
|
|
;; neg [sp+6]
|
|
mov a, #0
|
|
sub a, [hl+6]
|
|
mov [hl+6], a
|
|
mov e, #1
|
|
div_unsigned_den:
|
|
call $!__generic_qidiv
|
|
|
|
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
|
|
END_FUNC ___divqi3
|
|
|
|
|
|
START_FUNC ___modqi3
|
|
;; r8 = 4[sp] % 6[sp]
|
|
movw hl, sp
|
|
movw de, #0
|
|
mov a, [hl+4]
|
|
mov1 cy, a.7
|
|
bc $mod_signed_num
|
|
mov a, [hl+6]
|
|
mov1 cy, a.7
|
|
bc $mod_signed_den
|
|
br $!__generic_qimod
|
|
|
|
mod_signed_num:
|
|
;; neg [sp+4]
|
|
mov a, #0
|
|
sub a, [hl+4]
|
|
mov [hl+4], a
|
|
mov d, #1
|
|
mov a, [hl+6]
|
|
mov1 cy, a.7
|
|
bnc $mod_unsigned_den
|
|
mod_signed_den:
|
|
;; neg [sp+6]
|
|
mov a, #0
|
|
sub a, [hl+6]
|
|
mov [hl+6], a
|
|
mov e, #1
|
|
mod_unsigned_den:
|
|
call $!__generic_qimod
|
|
|
|
mov a, d
|
|
cmp0 a
|
|
bz $mod_no_neg
|
|
mov a, #0
|
|
sub a, r8
|
|
mov r8, a
|
|
;; 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
|
|
END_FUNC ___modqi3
|