xref: /OK3568_Linux_fs/kernel/arch/h8300/lib/udivsi3.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun#include "libgcc.h"
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun	;; This function also computes the remainder and stores it in er3.
5*4882a593Smuzhiyun	.global	__udivsi3
6*4882a593Smuzhiyun__udivsi3:
7*4882a593Smuzhiyun	mov.w	A1E,A1E		; denominator top word 0?
8*4882a593Smuzhiyun	bne	DenHighNonZero
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun	; do it the easy way, see page 107 in manual
11*4882a593Smuzhiyun	mov.w	A0E,A2
12*4882a593Smuzhiyun	extu.l	A2P
13*4882a593Smuzhiyun	divxu.w	A1,A2P
14*4882a593Smuzhiyun	mov.w	A2E,A0E
15*4882a593Smuzhiyun	divxu.w	A1,A0P
16*4882a593Smuzhiyun	mov.w	A0E,A3
17*4882a593Smuzhiyun	mov.w	A2,A0E
18*4882a593Smuzhiyun	extu.l	A3P
19*4882a593Smuzhiyun	rts
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun	; er0 = er0 / er1
22*4882a593Smuzhiyun	; er3 = er0 % er1
23*4882a593Smuzhiyun	; trashes er1 er2
24*4882a593Smuzhiyun	; expects er1 >= 2^16
25*4882a593SmuzhiyunDenHighNonZero:
26*4882a593Smuzhiyun	mov.l	er0,er3
27*4882a593Smuzhiyun	mov.l	er1,er2
28*4882a593Smuzhiyun#ifdef CONFIG_CPU_H8300H
29*4882a593Smuzhiyundivmod_L21:
30*4882a593Smuzhiyun	shlr.l	er0
31*4882a593Smuzhiyun	shlr.l	er2		; make divisor < 2^16
32*4882a593Smuzhiyun	mov.w	e2,e2
33*4882a593Smuzhiyun	bne	divmod_L21
34*4882a593Smuzhiyun#else
35*4882a593Smuzhiyun	shlr.l	#2,er2		; make divisor < 2^16
36*4882a593Smuzhiyun	mov.w	e2,e2
37*4882a593Smuzhiyun	beq	divmod_L22A
38*4882a593Smuzhiyundivmod_L21:
39*4882a593Smuzhiyun	shlr.l	#2,er0
40*4882a593Smuzhiyundivmod_L22:
41*4882a593Smuzhiyun	shlr.l	#2,er2		; make divisor < 2^16
42*4882a593Smuzhiyun	mov.w	e2,e2
43*4882a593Smuzhiyun	bne	divmod_L21
44*4882a593Smuzhiyundivmod_L22A:
45*4882a593Smuzhiyun	rotxl.w	r2
46*4882a593Smuzhiyun	bcs	divmod_L23
47*4882a593Smuzhiyun	shlr.l	er0
48*4882a593Smuzhiyun	bra	divmod_L24
49*4882a593Smuzhiyundivmod_L23:
50*4882a593Smuzhiyun	rotxr.w	r2
51*4882a593Smuzhiyun	shlr.l	#2,er0
52*4882a593Smuzhiyundivmod_L24:
53*4882a593Smuzhiyun#endif
54*4882a593Smuzhiyun	;; At this point,
55*4882a593Smuzhiyun	;;  er0 contains shifted dividend
56*4882a593Smuzhiyun	;;  er1 contains divisor
57*4882a593Smuzhiyun	;;  er2 contains shifted divisor
58*4882a593Smuzhiyun	;;  er3 contains dividend, later remainder
59*4882a593Smuzhiyun	divxu.w	r2,er0		; r0 now contains the approximate quotient (AQ)
60*4882a593Smuzhiyun	extu.l	er0
61*4882a593Smuzhiyun	beq	divmod_L25
62*4882a593Smuzhiyun	subs	#1,er0		; er0 = AQ - 1
63*4882a593Smuzhiyun	mov.w	e1,r2
64*4882a593Smuzhiyun	mulxu.w	r0,er2		; er2 = upper (AQ - 1) * divisor
65*4882a593Smuzhiyun	sub.w	r2,e3		; dividend - 65536 * er2
66*4882a593Smuzhiyun	mov.w	r1,r2
67*4882a593Smuzhiyun	mulxu.w	r0,er2		; compute er3 = remainder (tentative)
68*4882a593Smuzhiyun	sub.l	er2,er3		; er3 = dividend - (AQ - 1) * divisor
69*4882a593Smuzhiyundivmod_L25:
70*4882a593Smuzhiyun	cmp.l	er1,er3		; is divisor < remainder?
71*4882a593Smuzhiyun	blo	divmod_L26
72*4882a593Smuzhiyun	adds	#1,er0
73*4882a593Smuzhiyun	sub.l	er1,er3		; correct the remainder
74*4882a593Smuzhiyundivmod_L26:
75*4882a593Smuzhiyun	rts
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun	.end
78