OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [div_Xsig.S] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1623 jcastillo
        .file   "div_Xsig.S"
2
/*---------------------------------------------------------------------------+
3
 |  div_Xsig.S                                                               |
4
 |                                                                           |
5
 | Division subroutine for 96 bit quantities                                 |
6
 |                                                                           |
7
 | Copyright (C) 1994,1995                                                   |
8
 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
9
 |                       Australia.  E-mail billm@jacobi.maths.monash.edu.au |
10
 |                                                                           |
11
 |                                                                           |
12
 +---------------------------------------------------------------------------*/
13
 
14
/*---------------------------------------------------------------------------+
15
 | Divide the 96 bit quantity pointed to by a, by that pointed to by b, and  |
16
 | put the 96 bit result at the location d.                                  |
17
 |                                                                           |
18
 | The result may not be accurate to 96 bits. It is intended for use where   |
19
 | a result better than 64 bits is required. The result should usually be    |
20
 | good to at least 94 bits.                                                 |
21
 | The returned result is actually divided by one half. This is done to      |
22
 | prevent overflow.                                                         |
23
 |                                                                           |
24
 |  .aaaaaaaaaaaaaa / .bbbbbbbbbbbbb  ->  .dddddddddddd                      |
25
 |                                                                           |
26
 |  void div_Xsig(Xsig *a, Xsig *b, Xsig *dest)                              |
27
 |                                                                           |
28
 +---------------------------------------------------------------------------*/
29
 
30
#include "exception.h"
31
#include "fpu_emu.h"
32
 
33
 
34
#define XsigLL(x)       (x)
35
#define XsigL(x)        4(x)
36
#define XsigH(x)        8(x)
37
 
38
 
39
#ifndef NON_REENTRANT_FPU
40
/*
41
        Local storage on the stack:
42
        Accumulator:    FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
43
 */
44
#define FPU_accum_3     -4(%ebp)
45
#define FPU_accum_2     -8(%ebp)
46
#define FPU_accum_1     -12(%ebp)
47
#define FPU_accum_0     -16(%ebp)
48
#define FPU_result_3    -20(%ebp)
49
#define FPU_result_2    -24(%ebp)
50
#define FPU_result_1    -28(%ebp)
51
 
52
#else
53
.data
54
/*
55
        Local storage in a static area:
56
        Accumulator:    FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
57
 */
58
        .align 2,0
59
FPU_accum_3:
60
        .long   0
61
FPU_accum_2:
62
        .long   0
63
FPU_accum_1:
64
        .long   0
65
FPU_accum_0:
66
        .long   0
67
FPU_result_3:
68
        .long   0
69
FPU_result_2:
70
        .long   0
71
FPU_result_1:
72
        .long   0
73
#endif NON_REENTRANT_FPU
74
 
75
 
76
.text
77
ENTRY(div_Xsig)
78
        pushl   %ebp
79
        movl    %esp,%ebp
80
#ifndef NON_REENTRANT_FPU
81
        subl    $28,%esp
82
#endif NON_REENTRANT_FPU
83
 
84
        pushl   %esi
85
        pushl   %edi
86
        pushl   %ebx
87
 
88
        movl    PARAM1,%esi     /* pointer to num */
89
        movl    PARAM2,%ebx     /* pointer to denom */
90
 
91
#ifdef PARANOID
92
        testl   $0x80000000, XsigH(%ebx)        /* Divisor */
93
        je      L_bugged
94
#endif PARANOID
95
 
96
 
97
/*---------------------------------------------------------------------------+
98
 |  Divide:   Return  arg1/arg2 to arg3.                                     |
99
 |                                                                           |
100
 |  The maximum returned value is (ignoring exponents)                       |
101
 |               .ffffffff ffffffff                                          |
102
 |               ------------------  =  1.ffffffff fffffffe                  |
103
 |               .80000000 00000000                                          |
104
 | and the minimum is                                                        |
105
 |               .80000000 00000000                                          |
106
 |               ------------------  =  .80000000 00000001   (rounded)       |
107
 |               .ffffffff ffffffff                                          |
108
 |                                                                           |
109
 +---------------------------------------------------------------------------*/
110
 
111
        /* Save extended dividend in local register */
112
 
113
        /* Divide by 2 to prevent overflow */
114
        clc
115
        movl    XsigH(%esi),%eax
116
        rcrl    %eax
117
        movl    %eax,FPU_accum_3
118
        movl    XsigL(%esi),%eax
119
        rcrl    %eax
120
        movl    %eax,FPU_accum_2
121
        movl    XsigLL(%esi),%eax
122
        rcrl    %eax
123
        movl    %eax,FPU_accum_1
124
        movl    $0,%eax
125
        rcrl    %eax
126
        movl    %eax,FPU_accum_0
127
 
128
        movl    FPU_accum_2,%eax        /* Get the current num */
129
        movl    FPU_accum_3,%edx
130
 
131
/*----------------------------------------------------------------------*/
132
/* Initialization done.
133
   Do the first 32 bits. */
134
 
135
        /* We will divide by a number which is too large */
136
        movl    XsigH(%ebx),%ecx
137
        addl    $1,%ecx
138
        jnc     LFirst_div_not_1
139
 
140
        /* here we need to divide by 100000000h,
141
           i.e., no division at all.. */
142
        mov     %edx,%eax
143
        jmp     LFirst_div_done
144
 
145
LFirst_div_not_1:
146
        divl    %ecx            /* Divide the numerator by the augmented
147
                                   denom ms dw */
148
 
149
LFirst_div_done:
150
        movl    %eax,FPU_result_3       /* Put the result in the answer */
151
 
152
        mull    XsigH(%ebx)     /* mul by the ms dw of the denom */
153
 
154
        subl    %eax,FPU_accum_2        /* Subtract from the num local reg */
155
        sbbl    %edx,FPU_accum_3
156
 
157
        movl    FPU_result_3,%eax       /* Get the result back */
158
        mull    XsigL(%ebx)     /* now mul the ls dw of the denom */
159
 
160
        subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
161
        sbbl    %edx,FPU_accum_2
162
        sbbl    $0,FPU_accum_3
163
        je      LDo_2nd_32_bits         /* Must check for non-zero result here */
164
 
165
#ifdef PARANOID
166
        jb      L_bugged_1
167
#endif PARANOID
168
 
169
        /* need to subtract another once of the denom */
170
        incl    FPU_result_3    /* Correct the answer */
171
 
172
        movl    XsigL(%ebx),%eax
173
        movl    XsigH(%ebx),%edx
174
        subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
175
        sbbl    %edx,FPU_accum_2
176
 
177
#ifdef PARANOID
178
        sbbl    $0,FPU_accum_3
179
        jne     L_bugged_1      /* Must check for non-zero result here */
180
#endif PARANOID
181
 
182
/*----------------------------------------------------------------------*/
183
/* Half of the main problem is done, there is just a reduced numerator
184
   to handle now.
185
   Work with the second 32 bits, FPU_accum_0 not used from now on */
186
LDo_2nd_32_bits:
187
        movl    FPU_accum_2,%edx        /* get the reduced num */
188
        movl    FPU_accum_1,%eax
189
 
190
        /* need to check for possible subsequent overflow */
191
        cmpl    XsigH(%ebx),%edx
192
        jb      LDo_2nd_div
193
        ja      LPrevent_2nd_overflow
194
 
195
        cmpl    XsigL(%ebx),%eax
196
        jb      LDo_2nd_div
197
 
198
LPrevent_2nd_overflow:
199
/* The numerator is greater or equal, would cause overflow */
200
        /* prevent overflow */
201
        subl    XsigL(%ebx),%eax
202
        sbbl    XsigH(%ebx),%edx
203
        movl    %edx,FPU_accum_2
204
        movl    %eax,FPU_accum_1
205
 
206
        incl    FPU_result_3    /* Reflect the subtraction in the answer */
207
 
208
#ifdef PARANOID
209
        je      L_bugged_2      /* Can't bump the result to 1.0 */
210
#endif PARANOID
211
 
212
LDo_2nd_div:
213
        cmpl    $0,%ecx         /* augmented denom msw */
214
        jnz     LSecond_div_not_1
215
 
216
        /* %ecx == 0, we are dividing by 1.0 */
217
        mov     %edx,%eax
218
        jmp     LSecond_div_done
219
 
220
LSecond_div_not_1:
221
        divl    %ecx            /* Divide the numerator by the denom ms dw */
222
 
223
LSecond_div_done:
224
        movl    %eax,FPU_result_2       /* Put the result in the answer */
225
 
226
        mull    XsigH(%ebx)     /* mul by the ms dw of the denom */
227
 
228
        subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
229
        sbbl    %edx,FPU_accum_2
230
 
231
#ifdef PARANOID
232
        jc      L_bugged_2
233
#endif PARANOID
234
 
235
        movl    FPU_result_2,%eax       /* Get the result back */
236
        mull    XsigL(%ebx)     /* now mul the ls dw of the denom */
237
 
238
        subl    %eax,FPU_accum_0        /* Subtract from the num local reg */
239
        sbbl    %edx,FPU_accum_1        /* Subtract from the num local reg */
240
        sbbl    $0,FPU_accum_2
241
 
242
#ifdef PARANOID
243
        jc      L_bugged_2
244
#endif PARANOID
245
 
246
        jz      LDo_3rd_32_bits
247
 
248
#ifdef PARANOID
249
        cmpl    $1,FPU_accum_2
250
        jne     L_bugged_2
251
#endif PARANOID
252
 
253
        /* need to subtract another once of the denom */
254
        movl    XsigL(%ebx),%eax
255
        movl    XsigH(%ebx),%edx
256
        subl    %eax,FPU_accum_0        /* Subtract from the num local reg */
257
        sbbl    %edx,FPU_accum_1
258
        sbbl    $0,FPU_accum_2
259
 
260
#ifdef PARANOID
261
        jc      L_bugged_2
262
        jne     L_bugged_2
263
#endif PARANOID
264
 
265
        addl    $1,FPU_result_2 /* Correct the answer */
266
        adcl    $0,FPU_result_3
267
 
268
#ifdef PARANOID
269
        jc      L_bugged_2      /* Must check for non-zero result here */
270
#endif PARANOID
271
 
272
/*----------------------------------------------------------------------*/
273
/* The division is essentially finished here, we just need to perform
274
   tidying operations.
275
   Deal with the 3rd 32 bits */
276
LDo_3rd_32_bits:
277
        /* We use an approximation for the third 32 bits.
278
        To take account of the 3rd 32 bits of the divisor
279
        (call them del), we subtract  del * (a/b) */
280
 
281
        movl    FPU_result_3,%eax       /* a/b */
282
        mull    XsigLL(%ebx)            /* del */
283
 
284
        subl    %edx,FPU_accum_1
285
 
286
        /* A borrow indicates that the result is negative */
287
        jnb     LTest_over
288
 
289
        movl    XsigH(%ebx),%edx
290
        addl    %edx,FPU_accum_1
291
 
292
        subl    $1,FPU_result_2         /* Adjust the answer */
293
        sbbl    $0,FPU_result_3
294
 
295
        /* The above addition might not have been enough, check again. */
296
        movl    FPU_accum_1,%edx        /* get the reduced num */
297
        cmpl    XsigH(%ebx),%edx        /* denom */
298
        jb      LDo_3rd_div
299
 
300
        movl    XsigH(%ebx),%edx
301
        addl    %edx,FPU_accum_1
302
 
303
        subl    $1,FPU_result_2         /* Adjust the answer */
304
        sbbl    $0,FPU_result_3
305
        jmp     LDo_3rd_div
306
 
307
LTest_over:
308
        movl    FPU_accum_1,%edx        /* get the reduced num */
309
 
310
        /* need to check for possible subsequent overflow */
311
        cmpl    XsigH(%ebx),%edx        /* denom */
312
        jb      LDo_3rd_div
313
 
314
        /* prevent overflow */
315
        subl    XsigH(%ebx),%edx
316
        movl    %edx,FPU_accum_1
317
 
318
        addl    $1,FPU_result_2 /* Reflect the subtraction in the answer */
319
        adcl    $0,FPU_result_3
320
 
321
LDo_3rd_div:
322
        movl    FPU_accum_0,%eax
323
        movl    FPU_accum_1,%edx
324
        divl    XsigH(%ebx)
325
 
326
        movl    %eax,FPU_result_1       /* Rough estimate of third word */
327
 
328
        movl    PARAM3,%esi             /* pointer to answer */
329
 
330
        movl    FPU_result_1,%eax
331
        movl    %eax,XsigLL(%esi)
332
        movl    FPU_result_2,%eax
333
        movl    %eax,XsigL(%esi)
334
        movl    FPU_result_3,%eax
335
        movl    %eax,XsigH(%esi)
336
 
337
L_exit:
338
        popl    %ebx
339
        popl    %edi
340
        popl    %esi
341
 
342
        leave
343
        ret
344
 
345
 
346
#ifdef PARANOID
347
/* The logic is wrong if we got here */
348
L_bugged:
349
        pushl   EX_INTERNAL|0x240
350
        call    EXCEPTION
351
        pop     %ebx
352
        jmp     L_exit
353
 
354
L_bugged_1:
355
        pushl   EX_INTERNAL|0x241
356
        call    EXCEPTION
357
        pop     %ebx
358
        jmp     L_exit
359
 
360
L_bugged_2:
361
        pushl   EX_INTERNAL|0x242
362
        call    EXCEPTION
363
        pop     %ebx
364
        jmp     L_exit
365
#endif PARANOID

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.