1/* QImode div/mod functions for the GCC support library for the Renesas RL78 processors.
2   Copyright (C) 2012-2022 Free Software Foundation, Inc.
3   Contributed by Red Hat.
4
5   This file is part of GCC.
6
7   GCC is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3, or (at your option)
10   any later version.
11
12   GCC is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   Under Section 7 of GPL version 3, you are granted additional
18   permissions described in the GCC Runtime Library Exception, version
19   3.1, as published by the Free Software Foundation.
20
21   You should have received a copy of the GNU General Public License and
22   a copy of the GCC Runtime Library Exception along with this program;
23   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24   <http://www.gnu.org/licenses/>.  */
25
26#include "vregs.h"
27
28.macro MAKE_GENERIC  which,need_result
29
30	.if \need_result
31	quot = r8
32	num = r10
33	den = r12
34	bit = r14
35	.else
36	num = r8
37	quot = r10
38	den = r12
39	bit = r14
40	.endif
41
42#define bit	b
43#define den	c
44#define bitden	bc
45
46	START_FUNC __generic_qidivmod\which
47
48num_lt_den\which:
49	.if \need_result
50	mov	r8, #0
51	.else
52	mov	a, [hl+4]
53	mov	r8, a
54	.endif
55	ret
56
57num_eq_den\which:
58	.if \need_result
59	mov	r8, #1
60	.else
61	mov	r8, #0
62	.endif
63	ret
64
65den_is_zero\which:
66	mov	r8, #0x00
67	ret
68
69	;; These routines leave DE alone - the signed functions use DE
70	;; to store sign information that must remain intact
71
72	.if \need_result
73	.global __generic_qidiv
74__generic_qidiv:
75
76	.else
77
78	.global __generic_qimod
79__generic_qimod:
80
81	.endif
82
83	;; (quot,rem) = 4[hl] /% 6[hl]
84
85	mov	a, [hl+4] ; num
86	cmp	a, [hl+6] ; den
87	bz	$num_eq_den\which
88	bnh	$num_lt_den\which
89
90	;; copy numerator
91;	mov	a, [hl+4]	; already there from above
92	mov	num, a
93
94	;; copy denomonator
95	mov	a, [hl+6]
96	mov	den, a
97
98	cmp0	den
99	bz	$den_is_zero\which
100
101den_not_zero\which:
102	.if \need_result
103	;; zero out quot
104	mov	quot, #0
105	.endif
106
107	;; initialize bit to 1
108	mov	bit, #1
109
110; while (den < num && !(den & (1L << BITS_MINUS_1)))
111
112shift_den_bit\which:
113
114.macro	SDB_ONE\which
115	mov	a, den
116	mov1	cy,a.7
117	bc	$enter_main_loop\which
118	cmp	a, num
119	bh	$enter_main_loop\which
120
121	;; den <<= 1
122;	mov	a, den		; already has it from the cmpw above
123	shl	a, 1
124	mov	den, a
125
126	;; bit <<= 1
127	shl	bit, 1
128.endm
129
130	SDB_ONE\which
131	SDB_ONE\which
132
133	br	$shift_den_bit\which
134
135main_loop\which:
136
137	;; if (num >= den) (cmp den > num)
138	mov	a, den
139	cmp	a, num
140	bh	$next_loop\which
141
142	;; num -= den
143	mov	a, num
144	sub	a, den
145	mov	num, a
146
147	.if \need_result
148	;; res |= bit
149	mov	a, quot
150	or	a, bit
151	mov	quot, a
152	.endif
153
154next_loop\which:
155
156	;; den, bit >>= 1
157	movw	ax, bitden
158	shrw	ax, 1
159	movw	bitden, ax
160
161enter_main_loop\which:
162	cmp0	bit
163	bnz	$main_loop\which
164
165main_loop_done\which:
166	ret
167	END_FUNC __generic_qidivmod\which
168.endm
169
170;----------------------------------------------------------------------
171
172	MAKE_GENERIC _d 1
173	MAKE_GENERIC _m 0
174
175;----------------------------------------------------------------------
176
177START_FUNC ___udivqi3
178	;; r8 = 4[sp] / 6[sp]
179	movw	hl, sp
180	br	$!__generic_qidiv
181END_FUNC ___udivqi3
182
183
184START_FUNC ___umodqi3
185	;; r8 = 4[sp] % 6[sp]
186	movw	hl, sp
187	br	$!__generic_qimod
188END_FUNC ___umodqi3
189
190;----------------------------------------------------------------------
191
192.macro NEG_AX
193	movw	hl, ax
194	mov	a, #0
195	sub	a, [hl]
196	mov	[hl], a
197.endm
198
199;----------------------------------------------------------------------
200
201START_FUNC	___divqi3
202	;; r8 = 4[sp] / 6[sp]
203	movw	hl, sp
204	movw	de, #0
205	mov	a, [sp+4]
206	mov1	cy, a.7
207	bc	$div_signed_num
208	mov	a, [sp+6]
209	mov1	cy, a.7
210	bc	$div_signed_den
211	br	$!__generic_qidiv
212
213div_signed_num:
214	;; neg [sp+4]
215	mov	a, #0
216	sub	a, [hl+4]
217	mov	[hl+4], a
218	mov	d, #1
219	mov	a, [sp+6]
220	mov1	cy, a.6
221	bnc	$div_unsigned_den
222div_signed_den:
223	;; neg [sp+6]
224	mov	a, #0
225	sub	a, [hl+6]
226	mov	[hl+6], a
227	mov	e, #1
228div_unsigned_den:
229	call	$!__generic_qidiv
230
231	mov	a, d
232	cmp0	a
233	bz	$div_skip_restore_num
234	;;  We have to restore the numerator [sp+4]
235	movw	ax, sp
236	addw	ax, #4
237	NEG_AX
238	mov	a, d
239div_skip_restore_num:
240	xor	a, e
241	bz	$div_no_neg
242	movw	ax, #r8
243	NEG_AX
244div_no_neg:
245	mov	a, e
246	cmp0	a
247	bz	$div_skip_restore_den
248	movw	ax, sp
249	addw	ax, #6
250	NEG_AX
251div_skip_restore_den:
252	ret
253END_FUNC ___divqi3
254
255
256START_FUNC ___modqi3
257	;; r8 = 4[sp] % 6[sp]
258	movw	hl, sp
259	movw	de, #0
260	mov	a, [hl+4]
261	mov1	cy, a.7
262	bc	$mod_signed_num
263	mov	a, [hl+6]
264	mov1	cy, a.7
265	bc	$mod_signed_den
266	br	$!__generic_qimod
267
268mod_signed_num:
269	;; neg [sp+4]
270	mov	a, #0
271	sub	a, [hl+4]
272	mov	[hl+4], a
273	mov	d, #1
274	mov	a, [hl+6]
275	mov1	cy, a.7
276	bnc	$mod_unsigned_den
277mod_signed_den:
278	;; neg [sp+6]
279	mov	a, #0
280	sub	a, [hl+6]
281	mov	[hl+6], a
282	mov	e, #1
283mod_unsigned_den:
284	call	$!__generic_qimod
285
286	mov	a, d
287	cmp0	a
288	bz	$mod_no_neg
289	mov	a, #0
290	sub	a, r8
291	mov	r8, a
292	;;  Also restore numerator
293	movw 	ax, sp
294	addw	ax, #4
295	NEG_AX
296mod_no_neg:
297	mov	a, e
298	cmp0	a
299	bz	$mod_skip_restore_den
300	movw	ax, sp
301	addw	ax, #6
302	NEG_AX
303mod_skip_restore_den:
304	ret
305END_FUNC ___modqi3
306