aboutsummaryrefslogtreecommitdiff
path: root/arch/parisc/lib/milli/divU.S
blob: 9287fe2546faed63951c43bb25b8dd58cb91d9c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/* 32 and 64-bit millicode, original author Hewlett-Packard
   adapted for gcc by Paul Bame <bame@debian.org>
   and Alan Modra <alan@linuxcare.com.au>.

   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.

   This file is part of GCC and is released under the terms of
   of the GNU General Public License as published by the Free Software
   Foundation; either version 2, or (at your option) any later version.
   See the file COPYING in the top-level GCC source directory for a copy
   of the license.  */

#include "milli.h"

#ifdef L_divU
/* ROUTINE:	$$divU
   .
   .	Single precision divide for unsigned integers.
   .
   .	Quotient is truncated towards zero.
   .	Traps on divide by zero.

   INPUT REGISTERS:
   .	arg0 ==	dividend
   .	arg1 ==	divisor
   .	mrp  == return pc
   .	sr0  == return space when called externally

   OUTPUT REGISTERS:
   .	arg0 =	undefined
   .	arg1 =	undefined
   .	ret1 =	quotient

   OTHER REGISTERS AFFECTED:
   .	r1   =	undefined

   SIDE EFFECTS:
   .	Causes a trap under the following conditions:
   .		divisor is zero
   .	Changes memory at the following places:
   .		NONE

   PERMISSIBLE CONTEXT:
   .	Unwindable.
   .	Does not create a stack frame.
   .	Suitable for internal or external millicode.
   .	Assumes the special millicode register conventions.

   DISCUSSION:
   .	Branchs to other millicode routines using BE:
   .		$$divU_# for 3,5,6,7,9,10,12,14,15
   .
   .	For selected small divisors calls the special divide by constant
   .	routines written by Karl Pettis.  These are: 3,5,6,7,9,10,12,14,15.  */

RDEFINE(temp,r1)
RDEFINE(retreg,ret1)	/* r29 */
RDEFINE(temp1,arg0)
	SUBSPA_MILLI_DIV
	ATTR_MILLI
	.export $$divU,millicode
	.import $$divU_3,millicode
	.import $$divU_5,millicode
	.import $$divU_6,millicode
	.import $$divU_7,millicode
	.import $$divU_9,millicode
	.import $$divU_10,millicode
	.import $$divU_12,millicode
	.import $$divU_14,millicode
	.import $$divU_15,millicode
	.proc
	.callinfo	millicode
	.entry
GSYM($$divU)
/* The subtract is not nullified since it does no harm and can be used
   by the two cases that branch back to "normal".  */
	ldo	-1(arg1),temp		/* is there at most one bit set ? */
	and,=	arg1,temp,r0		/* if so, denominator is power of 2 */
	b	LREF(regular_seq)
	addit,=	0,arg1,0		/* trap for zero dvr */
	copy	arg0,retreg
	extru,= arg1,15,16,temp		/* test denominator with 0xffff0000 */
	extru	retreg,15,16,retreg	/* retreg = retreg >> 16 */
	or	arg1,temp,arg1		/* arg1 = arg1 | (arg1 >> 16) */
	ldi	0xcc,temp1		/* setup 0xcc in temp1 */
	extru,= arg1,23,8,temp		/* test denominator with 0xff00 */
	extru	retreg,23,24,retreg	/* retreg = retreg >> 8 */
	or	arg1,temp,arg1		/* arg1 = arg1 | (arg1 >> 8) */
	ldi	0xaa,temp		/* setup 0xaa in temp */
	extru,= arg1,27,4,r0		/* test denominator with 0xf0 */
	extru	retreg,27,28,retreg	/* retreg = retreg >> 4 */
	and,=	arg1,temp1,r0		/* test denominator with 0xcc */
	extru	retreg,29,30,retreg	/* retreg = retreg >> 2 */
	and,=	arg1,temp,r0		/* test denominator with 0xaa */
	extru	retreg,30,31,retreg	/* retreg = retreg >> 1 */
	MILLIRETN
	nop	
LSYM(regular_seq)
	comib,>=  15,arg1,LREF(special_divisor)
	subi	0,arg1,temp		/* clear carry, negate the divisor */
	ds	r0,temp,r0		/* set V-bit to 1 */
LSYM(normal)
	add	arg0,arg0,retreg	/* shift msb bit into carry */
	ds	r0,arg1,temp		/* 1st divide step, if no carry */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 2nd divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 3rd divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 4th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 5th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 6th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 7th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 8th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 9th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 10th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 11th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 12th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 13th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 14th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 15th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 16th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 17th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 18th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 19th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 20th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 21st divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 22nd divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 23rd divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 24th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 25th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 26th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 27th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 28th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 29th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 30th divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 31st divide step */
	addc	retreg,retreg,retreg	/* shift retreg with/into carry */
	ds	temp,arg1,temp		/* 32nd divide step, */
	MILLIRET
	addc	retreg,retreg,retreg	/* shift last retreg bit into retreg */

/* Handle the cases where divisor is a small constant or has high bit on.  */
LSYM(special_divisor)
/*	blr	arg1,r0 */
/*	comib,>,n  0,arg1,LREF(big_divisor) ; nullify previous instruction */

/* Pratap 8/13/90. The 815 Stirling chip set has a bug that prevents us from
   generating such a blr, comib sequence. A problem in nullification. So I
   rewrote this code.  */

#if defined(CONFIG_64BIT)
/* Clear the upper 32 bits of the arg1 register.  We are working with
   small divisors (and 32-bit unsigned integers)   We must not be mislead
   by "1" bits left in the upper 32 bits.  */
	depd %r0,31,32,%r25
#endif
	comib,>	0,arg1,LREF(big_divisor)
	nop
	blr	arg1,r0
	nop

LSYM(zero_divisor)	/* this label is here to provide external visibility */
	addit,=	0,arg1,0		/* trap for zero dvr */
	nop
	MILLIRET			/* divisor == 1 */
	copy	arg0,retreg
	MILLIRET			/* divisor == 2 */
	extru	arg0,30,31,retreg
	MILLI_BEN($$divU_3)		/* divisor == 3 */
	nop
	MILLIRET			/* divisor == 4 */
	extru	arg0,29,30,retreg
	MILLI_BEN($$divU_5)		/* divisor == 5 */
	nop
	MILLI_BEN($$divU_6)		/* divisor == 6 */
	nop
	MILLI_BEN($$divU_7)		/* divisor == 7 */
	nop
	MILLIRET			/* divisor == 8 */
	extru	arg0,28,29,retreg
	MILLI_BEN($$divU_9)		/* divisor == 9 */
	nop
	MILLI_BEN($$divU_10)		/* divisor == 10 */
	nop
	b	LREF(normal)		/* divisor == 11 */
	ds	r0,temp,r0		/* set V-bit to 1 */
	MILLI_BEN($$divU_12)		/* divisor == 12 */
	nop
	b	LREF(normal)		/* divisor == 13 */
	ds	r0,temp,r0		/* set V-bit to 1 */
	MILLI_BEN($$divU_14)		/* divisor == 14 */
	nop
	MILLI_BEN($$divU_15)		/* divisor == 15 */
	nop

/* Handle the case where the high bit is on in the divisor.
   Compute:	if( dividend>=divisor) quotient=1; else quotient=0;
   Note:	dividend>==divisor iff dividend-divisor does not borrow
   and		not borrow iff carry.  */
LSYM(big_divisor)
	sub	arg0,arg1,r0
	MILLIRET
	addc	r0,r0,retreg
	.exit
	.procend
	.end
#endif