1/* SImode 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 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#if defined __RL78_MUL_G14__
29
30START_FUNC ___divsi3
31	;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
32
33	;; Load and test for a negative denumerator.
34	movw	ax, [sp+8]
35	movw	de, ax
36	movw	ax, [sp+10]
37	mov1	cy, a.7
38	movw	hl, ax
39	bc	$__div_neg_den
40
41	;; Load and test for a negative numerator.
42	movw	ax, [sp+6]
43	mov1	cy, a.7
44	movw	bc, ax
45	movw	ax, [sp+4]
46	bc	$__div_neg_num
47
48	;; Neither are negative - we can use the unsigned divide instruction.
49__div_no_convert:
50	push	psw
51	di
52	divwu
53	pop	psw
54
55	movw	r8, ax
56	movw	ax, bc
57	movw	r10, ax
58	ret
59
60__div_neg_den:
61	;; Negate the denumerator (which is in HLDE)
62	clrw	ax
63	subw	ax, de
64	movw	de, ax
65	clrw	ax
66	sknc
67	decw	ax
68	subw	ax, hl
69	movw	hl, ax
70
71	;; Load and test for a negative numerator.
72	movw	ax, [sp+6]
73	mov1	cy, a.7
74	movw	bc, ax
75	movw	ax, [sp+4]
76	;; If it is not negative then we perform the division and then negate the result.
77	bnc	$__div_then_convert
78
79	;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
80	;; The negation is complicated because AX, BC, DE and HL are already in use.
81	;;              ax: numL  bc: numH  r8:       r10:
82	xchw	ax, bc
83	;;              ax: numH  bc: numL  r8:       r10:
84	movw	r8, ax
85	;;              ax:       bc: numL  r8: numH  r10:
86	clrw	ax
87	;;              ax:    0  bc: numL  r8: numH  r10:
88	subw	ax, bc
89	;;              ax: -numL bc:       r8: numH  r10:
90	movw	r10, ax
91	;;              ax:       bc:       r8: numH  r10: -numL
92	movw	ax, r8
93	;;              ax: numH  bc:       r8:       r10: -numL
94	movw	bc, ax
95	;;              ax:       bc: numH  r8:       r10: -numL
96	clrw	ax
97	;;              ax:    0  bc: numH  r8:       r10: -numL
98	sknc
99	decw	ax
100	;;              ax:    -1 bc: numH  r8:       r10: -numL
101	subw	ax, bc
102	;;              ax: -numH bc:       r8:       r10: -numL
103	movw	bc, ax
104	;;              ax:       bc: -numH r8:       r10: -numL
105	movw	ax, r10
106	;;              ax: -numL bc: -numH r8:       r10:
107	br	$!__div_no_convert
108
109__div_neg_num:
110	;; Negate the numerator (which is in BCAX)
111	;; We know that the denumerator is positive.
112	;; Note - we temporarily overwrite DE.  We know that we can safely load it again off the stack again.
113	movw	de, ax
114	clrw	ax
115	subw	ax, de
116	movw	de, ax
117	clrw	ax
118	sknc
119	decw	ax
120	subw	ax, bc
121	movw	bc, ax
122
123	movw	ax, [sp+8]
124	xchw	ax, de
125
126__div_then_convert:
127	push	psw
128	di
129	divwu
130	pop	psw
131
132	;; Negate result (in BCAX) and transfer into r8,r10
133	movw	de, ax
134	clrw	ax
135	subw	ax, de
136	movw	r8, ax
137	clrw	ax
138	sknc
139	decw	ax
140	subw	ax, bc
141	movw	r10, ax
142	ret
143
144END_FUNC ___divsi3
145
146;----------------------------------------------------------------------
147
148START_FUNC ___udivsi3
149	;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
150	;; Used when compiling with -Os specified.
151
152	movw	ax, [sp+10]
153	movw	hl, ax
154	movw	ax, [sp+8]
155	movw	de, ax
156	movw	ax, [sp+6]
157	movw	bc, ax
158	movw    ax, [sp+4]
159	push	psw	; Save the current interrupt status
160	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E
161	divwu   	; bcax = bcax / hlde
162	pop	psw	; Restore saved interrupt status
163	movw    r8, ax
164	movw	ax, bc
165	movw    r10, ax
166	ret
167
168END_FUNC ___udivsi3
169
170;----------------------------------------------------------------------
171
172START_FUNC ___modsi3
173	;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
174
175	;; Load and test for a negative denumerator.
176	movw	ax, [sp+8]
177	movw	de, ax
178	movw	ax, [sp+10]
179	mov1	cy, a.7
180	movw	hl, ax
181	bc	$__mod_neg_den
182
183	;; Load and test for a negative numerator.
184	movw	ax, [sp+6]
185	mov1	cy, a.7
186	movw	bc, ax
187	movw	ax, [sp+4]
188	bc	$__mod_neg_num
189
190	;; Neither are negative - we can use the unsigned divide instruction.
191__mod_no_convert:
192	push	psw
193	di
194	divwu
195	pop	psw
196
197	movw	ax, de
198	movw	r8, ax
199	movw	ax, hl
200	movw	r10, ax
201	ret
202
203__mod_neg_den:
204	;; Negate the denumerator (which is in HLDE)
205	clrw	ax
206	subw	ax, de
207	movw	de, ax
208	clrw	ax
209	sknc
210	decw	ax
211	subw	ax, hl
212	movw	hl, ax
213
214	;; Load and test for a negative numerator.
215	movw	ax, [sp+6]
216	mov1	cy, a.7
217	movw	bc, ax
218	movw	ax, [sp+4]
219	;; If it is not negative then we perform the modulo operation without conversion
220	bnc	$__mod_no_convert
221
222	;; Otherwise we negate the numerator and then go with a modulo followed by negation.
223	;; The negation is complicated because AX, BC, DE and HL are already in use.
224	xchw	ax, bc
225	movw	r8, ax
226	clrw	ax
227	subw	ax, bc
228	movw	r10, ax
229	movw	ax, r8
230	movw	bc, ax
231	clrw	ax
232	sknc
233	decw	ax
234	subw	ax, bc
235	movw	bc, ax
236	movw	ax, r10
237	br	$!__mod_then_convert
238
239__mod_neg_num:
240	;; Negate the numerator (which is in BCAX)
241	;; We know that the denumerator is positive.
242	;; Note - we temporarily overwrite DE.  We know that we can safely load it again off the stack again.
243	movw	de, ax
244	clrw	ax
245	subw	ax, de
246	movw	de, ax
247	clrw	ax
248	sknc
249	decw	ax
250	subw	ax, bc
251	movw	bc, ax
252
253	movw	ax, [sp+8]
254	xchw	ax, de
255
256__mod_then_convert:
257	push	psw
258	di
259	divwu
260	pop	psw
261
262	;; Negate result (in HLDE) and transfer into r8,r10
263	clrw	ax
264	subw	ax, de
265	movw	r8, ax
266	clrw	ax
267	sknc
268	decw	ax
269	subw	ax, hl
270	movw	r10, ax
271	ret
272
273END_FUNC ___modsi3
274
275;----------------------------------------------------------------------
276
277START_FUNC ___umodsi3
278	;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
279	;; Used when compiling with -Os specified.
280
281	movw	ax, [sp+10]
282	movw	hl, ax
283	movw	ax, [sp+8]
284	movw	de, ax
285	movw	ax, [sp+6]
286	movw	bc, ax
287	movw    ax, [sp+4]
288	push	psw	; Save the current interrupt status
289	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E
290	divwu   	; hlde = bcax %% hlde
291	pop	psw	; Restore saved interrupt status
292	movw	ax, de
293	movw    r8, ax
294	movw	ax, hl
295	movw    r10, ax
296	ret
297
298END_FUNC   ___umodsi3
299
300;----------------------------------------------------------------------
301
302#elif defined __RL78_MUL_G13__
303
304;----------------------------------------------------------------------
305
306	;; Hardware registers.  Note - these values match the silicon, not the documentation.
307	MDAL = 0xffff0
308	MDAH = 0xffff2
309	MDBL = 0xffff6
310	MDBH = 0xffff4
311	MDCL = 0xf00e0
312	MDCH = 0xf00e2
313	MDUC = 0xf00e8
314
315.macro _Negate low, high
316	movw	ax, \low
317	movw	bc, ax
318	clrw	ax
319	subw	ax, bc
320	movw	\low, ax
321	movw	ax, \high
322	movw	bc, ax
323	clrw	ax
324	sknc
325	decw	ax
326	subw	ax, bc
327	movw	\high, ax
328.endm
329
330;----------------------------------------------------------------------
331
332START_FUNC ___divsi3
333	;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
334
335	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
336	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
337
338	;; Load and test for a negative denumerator.
339	movw	ax, [sp+8]
340	movw	MDBL, ax
341	movw	ax, [sp+10]
342	mov1	cy, a.7
343	movw	MDBH, ax
344	bc	$__div_neg_den
345
346	;; Load and test for a negative numerator.
347	movw	ax, [sp+6]
348	mov1	cy, a.7
349	movw	MDAH, ax
350	movw	ax, [sp+4]
351	movw	MDAL, ax
352	bc	$__div_neg_num
353
354	;; Neither are negative - we can use the unsigned divide hardware.
355__div_no_convert:
356	mov	a, #0xC1	; Set the DIVST bit in MDUC
357	mov	!MDUC, a	; This starts the division op
358
3591:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
360	bt	a.0, $1b
361
362  	movw	ax, MDAL	; Read the result
363	movw	r8, ax
364	movw	ax, MDAH
365	movw	r10, ax
366	ret
367
368__div_neg_den:
369	;; Negate the denumerator (which is in MDBL/MDBH)
370	_Negate MDBL MDBH
371
372	;; Load and test for a negative numerator.
373	movw	ax, [sp+6]
374	mov1	cy, a.7
375	movw	MDAH, ax
376	movw	ax, [sp+4]
377	movw	MDAL, ax
378	;; If it is not negative then we perform the division and then negate the result.
379	bnc	$__div_then_convert
380
381	;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
382	_Negate MDAL MDAH
383	br	$!__div_no_convert
384
385__div_neg_num:
386	;; Negate the numerator (which is in MDAL/MDAH)
387	;; We know that the denumerator is positive.
388	_Negate MDAL MDAH
389
390__div_then_convert:
391	mov	a, #0xC1	; Set the DIVST bit in MDUC
392	mov	!MDUC, a	; This starts the division op
393
3941:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
395	bt	a.0, $1b
396
397	;; Negate result and transfer into r8,r10
398	_Negate MDAL MDAH    	; FIXME: This could be coded more efficiently.
399	movw	r10, ax
400	movw	ax, MDAL
401	movw	r8, ax
402
403	ret
404
405END_FUNC ___divsi3
406
407;----------------------------------------------------------------------
408
409START_FUNC ___modsi3
410	;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
411
412	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
413	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
414
415	;; Load and test for a negative denumerator.
416	movw	ax, [sp+8]
417	movw	MDBL, ax
418	movw	ax, [sp+10]
419	mov1	cy, a.7
420	movw	MDBH, ax
421	bc	$__mod_neg_den
422
423	;; Load and test for a negative numerator.
424	movw	ax, [sp+6]
425	mov1	cy, a.7
426	movw	MDAH, ax
427	movw	ax, [sp+4]
428	movw	MDAL, ax
429	bc	$__mod_neg_num
430
431	;; Neither are negative - we can use the unsigned divide hardware
432__mod_no_convert:
433	mov	a, #0xC1	; Set the DIVST bit in MDUC
434	mov	!MDUC, a	; This starts the division op
435
4361:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
437	bt	a.0, $1b
438
439  	movw	ax, !MDCL	; Read the remainder
440	movw	r8, ax
441	movw	ax, !MDCH
442	movw	r10, ax
443	ret
444
445__mod_neg_den:
446	;; Negate the denumerator (which is in MDBL/MDBH)
447	_Negate MDBL MDBH
448
449	;; Load and test for a negative numerator.
450	movw	ax, [sp+6]
451	mov1	cy, a.7
452	movw	MDAH, ax
453	movw	ax, [sp+4]
454	movw	MDAL, ax
455	;; If it is not negative then we perform the modulo operation without conversion
456	bnc	$__mod_no_convert
457
458	;; Otherwise we negate the numerator and then go with a modulo followed by negation.
459	_Negate MDAL MDAH
460	br	$!__mod_then_convert
461
462__mod_neg_num:
463	;; Negate the numerator (which is in MDAL/MDAH)
464	;; We know that the denumerator is positive.
465	_Negate MDAL MDAH
466
467__mod_then_convert:
468	mov	a, #0xC1	; Set the DIVST bit in MDUC
469	mov	!MDUC, a	; This starts the division op
470
4711:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
472	bt	a.0, $1b
473
474	movw	ax, !MDCL
475	movw	bc, ax
476	clrw	ax
477	subw	ax, bc
478	movw	r8, ax
479	movw	ax, !MDCH
480	movw	bc, ax
481	clrw	ax
482	sknc
483	decw	ax
484	subw	ax, bc
485	movw	r10, ax
486	ret
487
488END_FUNC ___modsi3
489
490;----------------------------------------------------------------------
491
492START_FUNC ___udivsi3
493	;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
494	;; Used when compilng with -Os specified.
495
496	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
497	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
498
499	movw	ax, [sp+4]	; Load the divisor
500	movw	MDAL, ax
501	movw	ax, [sp+6]
502	movw	MDAH, ax
503	movw	ax, [sp+8]	; Load the dividend
504	movw	MDBL, ax
505	movw    ax, [sp+10]
506	movw	MDBH, ax
507
508	mov	a, #0xC1	; Set the DIVST bit in MDUC
509	mov	!MDUC, a	; This starts the division op
510
5111:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
512	bt	a.0, $1b
513
514  	movw	ax, !MDAL	; Read the result
515	movw	r8, ax
516	movw	ax, !MDAH
517	movw	r10, ax
518	ret
519
520END_FUNC   ___udivsi3
521
522;----------------------------------------------------------------------
523
524START_FUNC ___umodsi3
525	;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
526	;; Used when compilng with -Os specified.
527	;; Note - hardware address match the silicon, not the documentation
528
529	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
530	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
531
532	movw	ax, [sp+4]	; Load the divisor
533	movw	MDAL, ax
534	movw	ax, [sp+6]
535	movw	MDAH, ax
536	movw	ax, [sp+8]	; Load the dividend
537	movw	MDBL, ax
538	movw    ax, [sp+10]
539	movw	MDBH, ax
540
541	mov	a, #0xC1	; Set the DIVST bit in MDUC
542	mov	!MDUC, a	; This starts the division op
543
5441:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
545	bt	a.0, $1b
546
547  	movw	ax, !MDCL	; Read the remainder
548	movw	r8, ax
549	movw	ax, !MDCH
550	movw	r10, ax
551	ret
552
553END_FUNC   ___umodsi3
554
555;----------------------------------------------------------------------
556
557#elif defined __RL78_MUL_NONE__
558
559.macro MAKE_GENERIC  which,need_result
560
561	.if \need_result
562	quot = r8
563	num = r12
564	den = r16
565	bit = r20
566	.else
567	num = r8
568	quot = r12
569	den = r16
570	bit = r20
571	.endif
572
573	quotH = quot+2
574	quotL = quot
575	quotB0 = quot
576	quotB1 = quot+1
577	quotB2 = quot+2
578	quotB3 = quot+3
579
580	numH = num+2
581	numL = num
582	numB0 = num
583	numB1 = num+1
584	numB2 = num+2
585	numB3 = num+3
586
587#define	denH bc
588	denL = den
589	denB0 = den
590	denB1 = den+1
591#define	denB2 c
592#define	denB3 b
593
594	bitH = bit+2
595	bitL = bit
596	bitB0 = bit
597	bitB1 = bit+1
598	bitB2 = bit+2
599	bitB3 = bit+3
600
601;----------------------------------------------------------------------
602
603START_FUNC __generic_sidivmod\which
604
605num_lt_den\which:
606	.if \need_result
607	movw	r8, #0
608	movw	r10, #0
609	.else
610	movw	ax, [sp+8]
611	movw	r8, ax
612	movw	ax, [sp+10]
613	movw	r10, ax
614	.endif
615	ret
616
617shift_den_bit16\which:
618	movw	ax, denL
619	movw	denH, ax
620	movw	denL, #0
621	.if \need_result
622	movw	ax, bitL
623	movw	bitH, ax
624	movw	bitL, #0
625	.else
626	mov	a, bit
627	add	a, #16
628	mov	bit, a
629	.endif
630	br	$shift_den_bit\which
631
632	;; These routines leave DE alone - the signed functions use DE
633	;; to store sign information that must remain intact
634
635	.if \need_result
636	.global __generic_sidiv
637__generic_sidiv:
638
639	.else
640
641	.global __generic_simod
642__generic_simod:
643
644	.endif
645
646	;; (quot,rem) = 8[sp] /% 12[sp]
647
648	movw	hl, sp
649	movw	ax, [hl+14] ; denH
650	cmpw	ax, [hl+10] ; numH
651	movw	ax, [hl+12] ; denL
652	sknz
653	cmpw	ax, [hl+8] ; numL
654	bh	$num_lt_den\which
655
656#ifdef __RL78_G10__
657	movw	ax, denL
658	push	ax
659	movw	ax, bitL
660	push	ax
661	movw	ax, bitH
662	push	ax
663#else
664	sel	rb2
665	push	ax		; denL
666;	push	bc		; denH
667	push	de		; bitL
668	push	hl		; bitH - stored in BC
669	sel	rb0
670#endif
671
672	;; (quot,rem) = 16[sp] /% 20[sp]
673
674	;; copy numerator
675	movw	ax, [hl+8]
676	movw	numL, ax
677	movw	ax, [hl+10]
678	movw	numH, ax
679
680	;; copy denomonator
681	movw	ax, [hl+12]
682	movw	denL, ax
683	movw	ax, [hl+14]
684	movw	denH, ax
685
686	movw	ax, denL
687	or	a, denB2
688	or	a, denB3	; not x
689	cmpw	ax, #0
690	bnz	$den_not_zero\which
691	.if \need_result
692	movw	quotL, #0
693	movw	quotH, #0
694	.else
695	movw	numL, #0
696	movw	numH, #0
697	.endif
698	br	$!main_loop_done_himode\which
699
700den_not_zero\which:
701	.if \need_result
702	;; zero out quot
703	movw	quotL, #0
704	movw	quotH, #0
705	.endif
706
707	;; initialize bit to 1
708	movw	bitL, #1
709	movw	bitH, #0
710
711; while (den < num && !(den & (1L << BITS_MINUS_1)))
712
713	.if 1
714	;; see if we can short-circuit a bunch of shifts
715	movw	ax, denH
716	cmpw	ax, #0
717	bnz	$shift_den_bit\which
718	movw	ax, denL
719	cmpw	ax, numH
720	bnh	$shift_den_bit16\which
721	.endif
722
723shift_den_bit\which:
724	movw	ax, denH
725	mov1	cy,a.7
726	bc	$enter_main_loop\which
727	cmpw	ax, numH
728	movw	ax, denL	; we re-use this below
729	sknz
730	cmpw	ax, numL
731	bh	$enter_main_loop\which
732
733	;; den <<= 1
734;	movw	ax, denL	; already has it from the cmpw above
735	shlw	ax, 1
736	movw	denL, ax
737;	movw	ax, denH
738	rolwc	denH, 1
739;	movw	denH, ax
740
741	;; bit <<= 1
742	.if \need_result
743	movw	ax, bitL
744	shlw	ax, 1
745	movw	bitL, ax
746	movw	ax, bitH
747	rolwc	ax, 1
748	movw	bitH, ax
749	.else
750	;; if we don't need to compute the quotent, we don't need an
751	;; actual bit *mask*, we just need to keep track of which bit
752	inc	bitB0
753	.endif
754
755	br	$shift_den_bit\which
756
757	;; while (bit)
758main_loop\which:
759
760	;; if (num >= den) (cmp den > num)
761	movw	ax, numH
762	cmpw	ax, denH
763	movw	ax, numL
764	sknz
765	cmpw	ax, denL
766	skz
767	bnh	$next_loop\which
768
769	;; num -= den
770;	movw	ax, numL	; already has it from the cmpw above
771	subw	ax, denL
772	movw	numL, ax
773	movw	ax, numH
774	sknc
775	decw	ax
776	subw	ax, denH
777	movw	numH, ax
778
779	.if \need_result
780	;; res |= bit
781	mov	a, quotB0
782	or	a, bitB0
783	mov	quotB0, a
784	mov	a, quotB1
785	or	a, bitB1
786	mov	quotB1, a
787	mov	a, quotB2
788	or	a, bitB2
789	mov	quotB2, a
790	mov	a, quotB3
791	or	a, bitB3
792	mov	quotB3, a
793	.endif
794
795next_loop\which:
796
797	;; den >>= 1
798	movw	ax, denH
799	shrw	ax, 1
800	movw	denH, ax
801	mov	a, denB1
802	rorc	a, 1
803	mov	denB1, a
804	mov	a, denB0
805	rorc	a, 1
806	mov	denB0, a
807
808	;; bit >>= 1
809	.if \need_result
810	movw	ax, bitH
811	shrw	ax, 1
812	movw	bitH, ax
813	mov	a, bitB1
814	rorc	a, 1
815	mov	bitB1, a
816	mov	a, bitB0
817	rorc	a, 1
818	mov	bitB0, a
819	.else
820	dec	bitB0
821	.endif
822
823enter_main_loop\which:
824	.if \need_result
825	movw	ax, bitH
826	cmpw	ax, #0
827	bnz	$main_loop\which
828	.else
829	cmp	bitB0, #15
830	bh	$main_loop\which
831	.endif
832	;; bit is HImode now; check others
833	movw	ax, numH	; numerator
834	cmpw	ax, #0
835	bnz	$bit_high_set\which
836	movw	ax, denH	; denominator
837	cmpw	ax, #0
838	bz	$switch_to_himode\which
839bit_high_set\which:
840	.if \need_result
841	movw	ax, bitL
842	cmpw	ax, #0
843	.else
844	cmp0	bitB0
845	.endif
846	bnz	$main_loop\which
847
848switch_to_himode\which:
849	.if \need_result
850	movw	ax, bitL
851	cmpw	ax, #0
852	.else
853	cmp0	bitB0
854	.endif
855	bz	$main_loop_done_himode\which
856
857	;; From here on in, r22, r14, and r18 are all zero
858	;; while (bit)
859main_loop_himode\which:
860
861	;; if (num >= den) (cmp den > num)
862	movw	ax, denL
863	cmpw	ax, numL
864	bh	$next_loop_himode\which
865
866	;; num -= den
867	movw	ax, numL
868	subw	ax, denL
869	movw	numL, ax
870	movw	ax, numH
871	sknc
872	decw	ax
873	subw	ax, denH
874	movw	numH, ax
875
876	.if \need_result
877	;; res |= bit
878	mov	a, quotB0
879	or	a, bitB0
880	mov	quotB0, a
881	mov	a, quotB1
882	or	a, bitB1
883	mov	quotB1, a
884	.endif
885
886next_loop_himode\which:
887
888	;; den >>= 1
889	movw	ax, denL
890	shrw	ax, 1
891	movw	denL, ax
892
893	.if \need_result
894	;; bit >>= 1
895	movw	ax, bitL
896	shrw	ax, 1
897	movw	bitL, ax
898	.else
899	dec	bitB0
900	.endif
901
902	.if \need_result
903	movw	ax, bitL
904	cmpw	ax, #0
905	.else
906	cmp0	bitB0
907	.endif
908	bnz	$main_loop_himode\which
909
910main_loop_done_himode\which:
911#ifdef __RL78_G10__
912	pop	ax
913	movw	bitH, ax
914	pop	ax
915	movw	bitL, ax
916	pop	ax
917	movw	denL, ax
918#else
919	sel	rb2
920	pop	hl		; bitH - stored in BC
921	pop	de		; bitL
922;	pop	bc		; denH
923	pop	ax		; denL
924	sel	rb0
925#endif
926
927	ret
928END_FUNC __generic_sidivmod\which
929.endm
930
931;----------------------------------------------------------------------
932
933	MAKE_GENERIC _d 1
934	MAKE_GENERIC _m 0
935
936;----------------------------------------------------------------------
937
938START_FUNC ___udivsi3
939	;; r8 = 4[sp] / 8[sp]
940	call	$!__generic_sidiv
941	ret
942END_FUNC ___udivsi3
943
944
945START_FUNC ___umodsi3
946	;; r8 = 4[sp] % 8[sp]
947	call	$!__generic_simod
948	ret
949END_FUNC ___umodsi3
950
951;----------------------------------------------------------------------
952
953.macro NEG_AX
954	movw	hl, ax
955	movw	ax, #0
956	subw	ax, [hl]
957	movw	[hl], ax
958	movw	ax, #0
959	sknc
960	decw	ax
961	subw	ax, [hl+2]
962	movw	[hl+2], ax
963.endm
964
965;----------------------------------------------------------------------
966
967START_FUNC ___divsi3
968	;; r8 = 4[sp] / 8[sp]
969	movw	de, #0
970	mov	a, [sp+7]
971	mov1	cy, a.7
972	bc	$div_signed_num
973	mov	a, [sp+11]
974	mov1	cy, a.7
975	bc	$div_signed_den
976	call	$!__generic_sidiv
977	ret
978
979div_signed_num:
980	;; neg [sp+4]
981	movw	ax, sp
982	addw	ax, #4
983	NEG_AX
984	mov	d, #1
985	mov	a, [sp+11]
986	mov1	cy, a.7
987	bnc	$div_unsigned_den
988div_signed_den:
989	;; neg [sp+8]
990	movw	ax, sp
991	addw	ax, #8
992	NEG_AX
993	mov	e, #1
994div_unsigned_den:
995	call	$!__generic_sidiv
996
997	mov	a, d
998	cmp0	a
999	bz	$div_skip_restore_num
1000	;;  We have to restore the numerator [sp+4]
1001	movw	ax, sp
1002	addw	ax, #4
1003	NEG_AX
1004	mov	a, d
1005div_skip_restore_num:
1006	xor	a, e
1007	bz	$div_no_neg
1008	movw	ax, #r8
1009	NEG_AX
1010div_no_neg:
1011	mov	a, e
1012	cmp0	a
1013	bz	$div_skip_restore_den
1014	;;  We have to restore the denominator [sp+8]
1015	movw	ax, sp
1016	addw	ax, #8
1017	NEG_AX
1018div_skip_restore_den:
1019	ret
1020END_FUNC ___divsi3
1021
1022
1023START_FUNC ___modsi3
1024	;; r8 = 4[sp] % 8[sp]
1025	movw	de, #0
1026	mov	a, [sp+7]
1027	mov1	cy, a.7
1028	bc	$mod_signed_num
1029	mov	a, [sp+11]
1030	mov1	cy, a.7
1031	bc	$mod_signed_den
1032	call	$!__generic_simod
1033	ret
1034
1035mod_signed_num:
1036	;; neg [sp+4]
1037	movw	ax, sp
1038	addw	ax, #4
1039	NEG_AX
1040	mov	d, #1
1041	mov	a, [sp+11]
1042	mov1	cy, a.7
1043	bnc	$mod_unsigned_den
1044mod_signed_den:
1045	;; neg [sp+8]
1046	movw	ax, sp
1047	addw	ax, #8
1048	NEG_AX
1049	mov	e, #1
1050mod_unsigned_den:
1051	call	$!__generic_simod
1052
1053	mov	a, d
1054	cmp0	a
1055	bz	$mod_no_neg
1056	movw	ax, #r8
1057	NEG_AX
1058	;;  We have to restore [sp+4] as well.
1059	movw	ax, sp
1060	addw	ax, #4
1061	NEG_AX
1062mod_no_neg:
1063 .if 1
1064	mov	a, e
1065	cmp0	a
1066	bz	$mod_skip_restore_den
1067	movw	ax, sp
1068	addw	ax, #8
1069	NEG_AX
1070mod_skip_restore_den:
1071 .endif
1072	ret
1073END_FUNC ___modsi3
1074
1075;----------------------------------------------------------------------
1076
1077#else
1078
1079#error "Unknown RL78 hardware multiply/divide support"
1080
1081#endif
1082