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