1;	$NetBSD: milli_tiny.S,v 1.1 2008/06/12 14:08:29 skrll Exp $
2
3; Copyright (c) 2003 ITOH Yasufumi.
4; All rights reserved.
5;
6; Redistribution and use in source and binary forms, with or without
7; modification, are permitted provided that the following conditions
8; are met:
9; 1. Redistributions of source code must retain the above copyright
10;    notice, this list of conditions and the following disclaimer.
11; 2. Redistributions in binary forms are unlimited.
12;
13; THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS''
14; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16; PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
17; BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23; THE POSSIBILITY OF SUCH DAMAGE.
24
25; millicode library, optimized for size
26
27	.level	1.0
28	.code
29	.align	4
30
31; $$divU	unsigned division, return quotient
32;
33; inputs:
34;	%r26	dividend
35;	%r25	divisor
36;	%r31	return address
37; outputs:
38;	%r29	quotient
39;	%r1, %r25, %r26	undefined
40	.export		$$divU,millicode
41$$divU:
42	.proc
43	.callinfo	millicode,no_unwind
44	.entry
45	comb,<,n	%r25,0,bigdivisor_divU	; special case (>=0x80000000)
46	bl		sub_divU,%r29
47	subt,=		%r0,%r25,%r1		; trap divide by 0, negate
48
49	bv		%r0(%r31)		; return millicode
50	.exit
51	addc		%r26,%r26,%r29		; fix quotient
52bigdivisor_divU:
53	comclr,<<	%r26,%r25,%r29		; if dividend >= divisor
54	ldi		1,%r29			;   quotient is 1
55	bv,n		%r0(%r31)		; return millicode
56	.procend
57
58; Note this is not a normal subroutine
59; r29: return address
60sub_divU:
61	stwm		%r19,64(%sp)
62	ldi		31,%r19
63
64	ds		%r0,%r1,%r0
65	addc		%r26,%r26,%r26
66	ds		%r0,%r25,%r1
67loop_sub_divU:					; addc/ds 31 times
68	addc		%r26,%r26,%r26
69	addib,<>	-1,%r19,loop_sub_divU
70	ds		%r1,%r25,%r1
71
72	bv		%r0(%r29)
73	ldwm		-64(%sp),%r19
74
75; $$remU	unsigned division, return remainder
76;
77; inputs:
78;	%r26	dividend
79;	%r25	divisor
80;	%r31	return address
81; outputs:
82;	%r29	remainder
83;	%r1, %r25, %r26	undefined
84	.export		$$remU,millicode
85$$remU:
86	.proc
87	.callinfo	millicode,no_unwind
88	.entry
89	comb,<,n	%r25,0,bigdivisor_remU	; special case (>=0x80000000)
90	bl		sub_divU,%r29
91	subt,=		%r0,%r25,%r1		; trap divide by 0, negate
92
93	comclr,>=	%r1,%r0,%r0
94	addl		%r1,%r25,%r1		; fix remainder
95	bv		%r0(%r31)		; return millicode
96	.exit
97	copy		%r1,%r29		; the return value is remainder
98bigdivisor_remU:
99	sub,>>=		%r26,%r25,%r29		; if dividend < divisor
100	copy		%r26,%r29		;   the remainder is dividend
101	bv,n		%r0(%r31)		; return millicode
102	.procend
103
104; $$mulU	unsigned multiplication
105;
106; inputs:
107;	%r26	multiplicand
108;	%r25	multiplier
109;	%r31	return address
110; outputs:
111;	%r29	product
112;	%r1, %r25, %r26	undefined
113	.export		$$mulU,millicode
114	.export		$$mulI,millicode
115$$mulU:
116$$mulI:	; XXX actually wrong (not signed) but works for small positive numbers
117	.proc
118	.callinfo	frame=0,no_calls,millicode
119	.entry
120	copy		%r0,%r29
121	ldi		32,%r1			; loop counter
122
123	add,nuv		%r25,%r25,%r25		; shift left, skip next if not C
124loop_mul:
125	sh1add,tr	%r29,%r26,%r29		; shift left and add, skip next
126	sh1add		%r29,%r0,%r29		; shift left only
127	addib,<>,n	-1,%r1,loop_mul		; check loop condition
128	add,nuv		%r25,%r25,%r25		; shift left, skip next if not C
129	.exit
130	bv,n		%r0(%r31)		; return millicode
131	.procend
132