xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/config/rl78/divmodsi.S (revision 7c192b2a5e1093666e67801684f930ef49b3b363)
1/* SImode div/mod functions for the GCC support library for the Renesas RL78 processors.
2   Copyright (C) 2012-2015 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 it
8   under the terms of the GNU General Public License as published
9   by the Free Software Foundation; either version 3, or (at your
10   option) any later version.
11
12   GCC is distributed in the hope that it will be useful, but WITHOUT
13   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15   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 = r12
33	den = r16
34	bit = r20
35	.else
36	num = r8
37	quot = r12
38	den = r16
39	bit = r20
40	.endif
41
42	quotH = quot+2
43	quotL = quot
44	quotB0 = quot
45	quotB1 = quot+1
46	quotB2 = quot+2
47	quotB3 = quot+3
48
49	numH = num+2
50	numL = num
51	numB0 = num
52	numB1 = num+1
53	numB2 = num+2
54	numB3 = num+3
55
56#define	denH bc
57	denL = den
58	denB0 = den
59	denB1 = den+1
60#define	denB2 c
61#define	denB3 b
62
63	bitH = bit+2
64	bitL = bit
65	bitB0 = bit
66	bitB1 = bit+1
67	bitB2 = bit+2
68	bitB3 = bit+3
69
70START_FUNC __generic_sidivmod\which
71
72num_lt_den\which:
73	.if \need_result
74	movw	r8, #0
75	movw	r10, #0
76	.else
77	movw	ax, [sp+8]
78	movw	r8, ax
79	movw	ax, [sp+10]
80	movw	r10, ax
81	.endif
82	ret
83
84shift_den_bit16\which:
85	movw	ax, denL
86	movw	denH, ax
87	movw	denL, #0
88	.if \need_result
89	movw	ax, bitL
90	movw	bitH, ax
91	movw	bitL, #0
92	.else
93	mov	a, bit
94	add	a, #16
95	mov	bit, a
96	.endif
97	br	$shift_den_bit\which
98
99	;; These routines leave DE alone - the signed functions use DE
100	;; to store sign information that must remain intact
101
102	.if \need_result
103	.global __generic_sidiv
104__generic_sidiv:
105
106	.else
107
108	.global __generic_simod
109__generic_simod:
110
111	.endif
112
113	;; (quot,rem) = 8[sp] /% 12[sp]
114
115	movw	hl, sp
116	movw	ax, [hl+14] ; denH
117	cmpw	ax, [hl+10] ; numH
118	movw	ax, [hl+12] ; denL
119	sknz
120	cmpw	ax, [hl+8] ; numL
121	bh	$num_lt_den\which
122
123#ifdef __RL78_G10__
124	movw	ax, denL
125	push	ax
126	movw	ax, bitL
127	push	ax
128	movw	ax, bitH
129	push	ax
130#else
131	sel	rb2
132	push	ax		; denL
133;	push	bc		; denH
134	push	de		; bitL
135	push	hl		; bitH - stored in BC
136	sel	rb0
137#endif
138
139	;; (quot,rem) = 16[sp] /% 20[sp]
140
141	;; copy numerator
142	movw	ax, [hl+8]
143	movw	numL, ax
144	movw	ax, [hl+10]
145	movw	numH, ax
146
147	;; copy denomonator
148	movw	ax, [hl+12]
149	movw	denL, ax
150	movw	ax, [hl+14]
151	movw	denH, ax
152
153	movw	ax, denL
154	or	a, denB2
155	or	a, denB3	; not x
156	cmpw	ax, #0
157	bnz	$den_not_zero\which
158	movw	numL, #0
159	movw	numH, #0
160	ret
161
162den_not_zero\which:
163	.if \need_result
164	;; zero out quot
165	movw	quotL, #0
166	movw	quotH, #0
167	.endif
168
169	;; initialize bit to 1
170	movw	bitL, #1
171	movw	bitH, #0
172
173; while (den < num && !(den & (1L << BITS_MINUS_1)))
174
175	.if 1
176	;; see if we can short-circuit a bunch of shifts
177	movw	ax, denH
178	cmpw	ax, #0
179	bnz	$shift_den_bit\which
180	movw	ax, denL
181	cmpw	ax, numH
182	bnh	$shift_den_bit16\which
183	.endif
184
185shift_den_bit\which:
186	movw	ax, denH
187	mov1	cy,a.7
188	bc	$enter_main_loop\which
189	cmpw	ax, numH
190	movw	ax, denL	; we re-use this below
191	sknz
192	cmpw	ax, numL
193	bh	$enter_main_loop\which
194
195	;; den <<= 1
196;	movw	ax, denL	; already has it from the cmpw above
197	shlw	ax, 1
198	movw	denL, ax
199;	movw	ax, denH
200	rolwc	denH, 1
201;	movw	denH, ax
202
203	;; bit <<= 1
204	.if \need_result
205	movw	ax, bitL
206	shlw	ax, 1
207	movw	bitL, ax
208	movw	ax, bitH
209	rolwc	ax, 1
210	movw	bitH, ax
211	.else
212	;; if we don't need to compute the quotent, we don't need an
213	;; actual bit *mask*, we just need to keep track of which bit
214	inc	bitB0
215	.endif
216
217	br	$shift_den_bit\which
218
219	;; while (bit)
220main_loop\which:
221
222	;; if (num >= den) (cmp den > num)
223	movw	ax, numH
224	cmpw	ax, denH
225	movw	ax, numL
226	sknz
227	cmpw	ax, denL
228	skz
229	bnh	$next_loop\which
230
231	;; num -= den
232;	movw	ax, numL	; already has it from the cmpw above
233	subw	ax, denL
234	movw	numL, ax
235	movw	ax, numH
236	sknc
237	decw	ax
238	subw	ax, denH
239	movw	numH, ax
240
241	.if \need_result
242	;; res |= bit
243	mov	a, quotB0
244	or	a, bitB0
245	mov	quotB0, a
246	mov	a, quotB1
247	or	a, bitB1
248	mov	quotB1, a
249	mov	a, quotB2
250	or	a, bitB2
251	mov	quotB2, a
252	mov	a, quotB3
253	or	a, bitB3
254	mov	quotB3, a
255	.endif
256
257next_loop\which:
258
259	;; den >>= 1
260	movw	ax, denH
261	shrw	ax, 1
262	movw	denH, ax
263	mov	a, denB1
264	rorc	a, 1
265	mov	denB1, a
266	mov	a, denB0
267	rorc	a, 1
268	mov	denB0, a
269
270	;; bit >>= 1
271	.if \need_result
272	movw	ax, bitH
273	shrw	ax, 1
274	movw	bitH, ax
275	mov	a, bitB1
276	rorc	a, 1
277	mov	bitB1, a
278	mov	a, bitB0
279	rorc	a, 1
280	mov	bitB0, a
281	.else
282	dec	bitB0
283	.endif
284
285enter_main_loop\which:
286	.if \need_result
287	movw	ax, bitH
288	cmpw	ax, #0
289	bnz	$main_loop\which
290	.else
291	cmp	bitB0, #15
292	bh	$main_loop\which
293	.endif
294	;; bit is HImode now; check others
295	movw	ax, numH	; numerator
296	cmpw	ax, #0
297	bnz	$bit_high_set\which
298	movw	ax, denH	; denominator
299	cmpw	ax, #0
300	bz	$switch_to_himode\which
301bit_high_set\which:
302	.if \need_result
303	movw	ax, bitL
304	cmpw	ax, #0
305	.else
306	cmp0	bitB0
307	.endif
308	bnz	$main_loop\which
309
310switch_to_himode\which:
311	.if \need_result
312	movw	ax, bitL
313	cmpw	ax, #0
314	.else
315	cmp0	bitB0
316	.endif
317	bz	$main_loop_done_himode\which
318
319	;; From here on in, r22, r14, and r18 are all zero
320	;; while (bit)
321main_loop_himode\which:
322
323	;; if (num >= den) (cmp den > num)
324	movw	ax, denL
325	cmpw	ax, numL
326	bh	$next_loop_himode\which
327
328	;; num -= den
329	movw	ax, numL
330	subw	ax, denL
331	movw	numL, ax
332	movw	ax, numH
333	sknc
334	decw	ax
335	subw	ax, denH
336	movw	numH, ax
337
338	.if \need_result
339	;; res |= bit
340	mov	a, quotB0
341	or	a, bitB0
342	mov	quotB0, a
343	mov	a, quotB1
344	or	a, bitB1
345	mov	quotB1, a
346	.endif
347
348next_loop_himode\which:
349
350	;; den >>= 1
351	movw	ax, denL
352	shrw	ax, 1
353	movw	denL, ax
354
355	.if \need_result
356	;; bit >>= 1
357	movw	ax, bitL
358	shrw	ax, 1
359	movw	bitL, ax
360	.else
361	dec	bitB0
362	.endif
363
364	.if \need_result
365	movw	ax, bitL
366	cmpw	ax, #0
367	.else
368	cmp0	bitB0
369	.endif
370	bnz	$main_loop_himode\which
371
372main_loop_done_himode\which:
373#ifdef __RL78_G10__
374	pop	ax
375	movw	bitH, ax
376	pop	ax
377	movw	bitL, ax
378	pop	ax
379	movw	denL, ax
380#else
381	sel	rb2
382	pop	hl		; bitH - stored in BC
383	pop	de		; bitL
384;	pop	bc		; denH
385	pop	ax		; denL
386	sel	rb0
387#endif
388
389	ret
390END_FUNC __generic_sidivmod\which
391.endm
392
393;----------------------------------------------------------------------
394
395	MAKE_GENERIC _d 1
396	MAKE_GENERIC _m 0
397
398;----------------------------------------------------------------------
399
400START_FUNC ___udivsi3
401	;; r8 = 4[sp] / 8[sp]
402	call	$!__generic_sidiv
403	ret
404END_FUNC ___udivsi3
405
406
407START_FUNC ___umodsi3
408	;; r8 = 4[sp] % 8[sp]
409	call	$!__generic_simod
410	ret
411END_FUNC ___umodsi3
412
413;----------------------------------------------------------------------
414
415.macro NEG_AX
416	movw	hl, ax
417	movw	ax, #0
418	subw	ax, [hl]
419	movw	[hl], ax
420	movw	ax, #0
421	sknc
422	decw	ax
423	subw	ax, [hl+2]
424	movw	[hl+2], ax
425.endm
426
427;----------------------------------------------------------------------
428
429START_FUNC ___divsi3
430	;; r8 = 4[sp] / 8[sp]
431	movw	de, #0
432	mov	a, [sp+7]
433	mov1	cy, a.7
434	bc	$div_signed_num
435	mov	a, [sp+11]
436	mov1	cy, a.7
437	bc	$div_signed_den
438	call	$!__generic_sidiv
439	ret
440
441div_signed_num:
442	;; neg [sp+4]
443	movw	ax, sp
444	addw	ax, #4
445	NEG_AX
446	mov	d, #1
447	mov	a, [sp+11]
448	mov1	cy, a.7
449	bnc	$div_unsigned_den
450div_signed_den:
451	;; neg [sp+8]
452	movw	ax, sp
453	addw	ax, #8
454	NEG_AX
455	mov	e, #1
456div_unsigned_den:
457	call	$!__generic_sidiv
458
459	mov	a, d
460	cmp0	a
461	bz	$div_skip_restore_num
462	;;  We have to restore the numerator [sp+4]
463	movw	ax, sp
464	addw	ax, #4
465	NEG_AX
466	mov	a, d
467div_skip_restore_num:
468	xor	a, e
469	bz	$div_no_neg
470	movw	ax, #r8
471	NEG_AX
472div_no_neg:
473	mov	a, e
474	cmp0	a
475	bz	$div_skip_restore_den
476	;;  We have to restore the denominator [sp+8]
477	movw	ax, sp
478	addw	ax, #8
479	NEG_AX
480div_skip_restore_den:
481	ret
482END_FUNC ___divsi3
483
484
485START_FUNC ___modsi3
486	;; r8 = 4[sp] % 8[sp]
487	movw	de, #0
488	mov	a, [sp+7]
489	mov1	cy, a.7
490	bc	$mod_signed_num
491	mov	a, [sp+11]
492	mov1	cy, a.7
493	bc	$mod_signed_den
494	call	$!__generic_simod
495	ret
496
497mod_signed_num:
498	;; neg [sp+4]
499	movw	ax, sp
500	addw	ax, #4
501	NEG_AX
502	mov	d, #1
503	mov	a, [sp+11]
504	mov1	cy, a.7
505	bnc	$mod_unsigned_den
506mod_signed_den:
507	;; neg [sp+8]
508	movw	ax, sp
509	addw	ax, #8
510	NEG_AX
511	mov	e, #1
512mod_unsigned_den:
513	call	$!__generic_simod
514
515	mov	a, d
516	cmp0	a
517	bz	$mod_no_neg
518	movw	ax, #r8
519	NEG_AX
520	;;  We have to restore [sp+4] as well.
521	movw	ax, sp
522	addw	ax, #4
523	NEG_AX
524mod_no_neg:
525 .if 1
526	mov	a, e
527	cmp0	a
528	bz	$mod_skip_restore_den
529	movw	ax, sp
530	addw	ax, #8
531	NEG_AX
532mod_skip_restore_den:
533 .endif
534	ret
535END_FUNC ___modsi3
536