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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [i386/] [math-emu/] [reg_u_div.S] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
        .file   "reg_u_div.S"
2
/*---------------------------------------------------------------------------+
3
 |  reg_u_div.S                                                              |
4
 |                                                                           |
5
 | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
6
 |                                                                           |
7
 | Copyright (C) 1992,1993,1995,1997                                         |
8
 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9
 |                  E-mail   billm@suburbia.net                              |
10
 |                                                                           |
11
 |                                                                           |
12
 +---------------------------------------------------------------------------*/
13
 
14
/*---------------------------------------------------------------------------+
15
 | Call from C as:                                                           |
16
 |    int FPU_u_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,                   |
17
 |                unsigned int control_word, char *sign)                     |
18
 |                                                                           |
19
 |  Does not compute the destination exponent, but does adjust it.           |
20
 |                                                                           |
21
 |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
22
 |    one was raised, or -1 on internal error.                               |
23
 +---------------------------------------------------------------------------*/
24
 
25
#include "exception.h"
26
#include "fpu_emu.h"
27
#include "control_w.h"
28
 
29
 
30
/* #define      dSIGL(x)        (x) */
31
/* #define      dSIGH(x)        4(x) */
32
 
33
 
34
#ifndef NON_REENTRANT_FPU
35
/*
36
        Local storage on the stack:
37
        Result:         FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
38
        Overflow flag:  ovfl_flag
39
 */
40
#define FPU_accum_3     -4(%ebp)
41
#define FPU_accum_2     -8(%ebp)
42
#define FPU_accum_1     -12(%ebp)
43
#define FPU_accum_0     -16(%ebp)
44
#define FPU_result_1    -20(%ebp)
45
#define FPU_result_2    -24(%ebp)
46
#define FPU_ovfl_flag   -28(%ebp)
47
 
48
#else
49
.data
50
/*
51
        Local storage in a static area:
52
        Result:         FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
53
        Overflow flag:  ovfl_flag
54
 */
55
        .align 4,0
56
FPU_accum_3:
57
        .long   0
58
FPU_accum_2:
59
        .long   0
60
FPU_accum_1:
61
        .long   0
62
FPU_accum_0:
63
        .long   0
64
FPU_result_1:
65
        .long   0
66
FPU_result_2:
67
        .long   0
68
FPU_ovfl_flag:
69
        .byte   0
70
#endif /* NON_REENTRANT_FPU */
71
 
72
#define REGA    PARAM1
73
#define REGB    PARAM2
74
#define DEST    PARAM3
75
 
76
.text
77
ENTRY(FPU_u_div)
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    REGA,%esi
89
        movl    REGB,%ebx
90
        movl    DEST,%edi
91
 
92
        movswl  EXP(%esi),%edx
93
        movswl  EXP(%ebx),%eax
94
        subl    %eax,%edx
95
        addl    EXP_BIAS,%edx
96
 
97
        /* A denormal and a large number can cause an exponent underflow */
98
        cmpl    EXP_WAY_UNDER,%edx
99
        jg      xExp_not_underflow
100
 
101
        /* Set to a really low value allow correct handling */
102
        movl    EXP_WAY_UNDER,%edx
103
 
104
xExp_not_underflow:
105
 
106
        movw    %dx,EXP(%edi)
107
 
108
#ifdef PARANOID
109
/*      testl   $0x80000000, SIGH(%esi) // Dividend */
110
/*      je      L_bugged */
111
        testl   $0x80000000, SIGH(%ebx) /* Divisor */
112
        je      L_bugged
113
#endif /* PARANOID */
114
 
115
/* Check if the divisor can be treated as having just 32 bits */
116
        cmpl    $0,SIGL(%ebx)
117
        jnz     L_Full_Division /* Can't do a quick divide */
118
 
119
/* We should be able to zip through the division here */
120
        movl    SIGH(%ebx),%ecx /* The divisor */
121
        movl    SIGH(%esi),%edx /* Dividend */
122
        movl    SIGL(%esi),%eax /* Dividend */
123
 
124
        cmpl    %ecx,%edx
125
        setaeb  FPU_ovfl_flag   /* Keep a record */
126
        jb      L_no_adjust
127
 
128
        subl    %ecx,%edx       /* Prevent the overflow */
129
 
130
L_no_adjust:
131
        /* Divide the 64 bit number by the 32 bit denominator */
132
        divl    %ecx
133
        movl    %eax,FPU_result_2
134
 
135
        /* Work on the remainder of the first division */
136
        xorl    %eax,%eax
137
        divl    %ecx
138
        movl    %eax,FPU_result_1
139
 
140
        /* Work on the remainder of the 64 bit division */
141
        xorl    %eax,%eax
142
        divl    %ecx
143
 
144
        testb   $255,FPU_ovfl_flag      /* was the num > denom ? */
145
        je      L_no_overflow
146
 
147
        /* Do the shifting here */
148
        /* increase the exponent */
149
        incw    EXP(%edi)
150
 
151
        /* shift the mantissa right one bit */
152
        stc                     /* To set the ms bit */
153
        rcrl    FPU_result_2
154
        rcrl    FPU_result_1
155
        rcrl    %eax
156
 
157
L_no_overflow:
158
        jmp     LRound_precision        /* Do the rounding as required */
159
 
160
 
161
/*---------------------------------------------------------------------------+
162
 |  Divide:   Return  arg1/arg2 to arg3.                                     |
163
 |                                                                           |
164
 |  This routine does not use the exponents of arg1 and arg2, but does       |
165
 |  adjust the exponent of arg3.                                             |
166
 |                                                                           |
167
 |  The maximum returned value is (ignoring exponents)                       |
168
 |               .ffffffff ffffffff                                          |
169
 |               ------------------  =  1.ffffffff fffffffe                  |
170
 |               .80000000 00000000                                          |
171
 | and the minimum is                                                        |
172
 |               .80000000 00000000                                          |
173
 |               ------------------  =  .80000000 00000001   (rounded)       |
174
 |               .ffffffff ffffffff                                          |
175
 |                                                                           |
176
 +---------------------------------------------------------------------------*/
177
 
178
 
179
L_Full_Division:
180
        /* Save extended dividend in local register */
181
        movl    SIGL(%esi),%eax
182
        movl    %eax,FPU_accum_2
183
        movl    SIGH(%esi),%eax
184
        movl    %eax,FPU_accum_3
185
        xorl    %eax,%eax
186
        movl    %eax,FPU_accum_1        /* zero the extension */
187
        movl    %eax,FPU_accum_0        /* zero the extension */
188
 
189
        movl    SIGL(%esi),%eax /* Get the current num */
190
        movl    SIGH(%esi),%edx
191
 
192
/*----------------------------------------------------------------------*/
193
/* Initialization done.
194
   Do the first 32 bits. */
195
 
196
        movb    $0,FPU_ovfl_flag
197
        cmpl    SIGH(%ebx),%edx /* Test for imminent overflow */
198
        jb      LLess_than_1
199
        ja      LGreater_than_1
200
 
201
        cmpl    SIGL(%ebx),%eax
202
        jb      LLess_than_1
203
 
204
LGreater_than_1:
205
/* The dividend is greater or equal, would cause overflow */
206
        setaeb  FPU_ovfl_flag           /* Keep a record */
207
 
208
        subl    SIGL(%ebx),%eax
209
        sbbl    SIGH(%ebx),%edx /* Prevent the overflow */
210
        movl    %eax,FPU_accum_2
211
        movl    %edx,FPU_accum_3
212
 
213
LLess_than_1:
214
/* At this point, we have a dividend < divisor, with a record of
215
   adjustment in FPU_ovfl_flag */
216
 
217
        /* We will divide by a number which is too large */
218
        movl    SIGH(%ebx),%ecx
219
        addl    $1,%ecx
220
        jnc     LFirst_div_not_1
221
 
222
        /* here we need to divide by 100000000h,
223
           i.e., no division at all.. */
224
        mov     %edx,%eax
225
        jmp     LFirst_div_done
226
 
227
LFirst_div_not_1:
228
        divl    %ecx            /* Divide the numerator by the augmented
229
                                   denom ms dw */
230
 
231
LFirst_div_done:
232
        movl    %eax,FPU_result_2       /* Put the result in the answer */
233
 
234
        mull    SIGH(%ebx)      /* mul by the ms dw of the denom */
235
 
236
        subl    %eax,FPU_accum_2        /* Subtract from the num local reg */
237
        sbbl    %edx,FPU_accum_3
238
 
239
        movl    FPU_result_2,%eax       /* Get the result back */
240
        mull    SIGL(%ebx)      /* now mul the ls dw of the denom */
241
 
242
        subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
243
        sbbl    %edx,FPU_accum_2
244
        sbbl    $0,FPU_accum_3
245
        je      LDo_2nd_32_bits         /* Must check for non-zero result here */
246
 
247
#ifdef PARANOID
248
        jb      L_bugged_1
249
#endif /* PARANOID */
250
 
251
        /* need to subtract another once of the denom */
252
        incl    FPU_result_2    /* Correct the answer */
253
 
254
        movl    SIGL(%ebx),%eax
255
        movl    SIGH(%ebx),%edx
256
        subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
257
        sbbl    %edx,FPU_accum_2
258
 
259
#ifdef PARANOID
260
        sbbl    $0,FPU_accum_3
261
        jne     L_bugged_1      /* Must check for non-zero result here */
262
#endif /* PARANOID */
263
 
264
/*----------------------------------------------------------------------*/
265
/* Half of the main problem is done, there is just a reduced numerator
266
   to handle now.
267
   Work with the second 32 bits, FPU_accum_0 not used from now on */
268
LDo_2nd_32_bits:
269
        movl    FPU_accum_2,%edx        /* get the reduced num */
270
        movl    FPU_accum_1,%eax
271
 
272
        /* need to check for possible subsequent overflow */
273
        cmpl    SIGH(%ebx),%edx
274
        jb      LDo_2nd_div
275
        ja      LPrevent_2nd_overflow
276
 
277
        cmpl    SIGL(%ebx),%eax
278
        jb      LDo_2nd_div
279
 
280
LPrevent_2nd_overflow:
281
/* The numerator is greater or equal, would cause overflow */
282
        /* prevent overflow */
283
        subl    SIGL(%ebx),%eax
284
        sbbl    SIGH(%ebx),%edx
285
        movl    %edx,FPU_accum_2
286
        movl    %eax,FPU_accum_1
287
 
288
        incl    FPU_result_2    /* Reflect the subtraction in the answer */
289
 
290
#ifdef PARANOID
291
        je      L_bugged_2      /* Can't bump the result to 1.0 */
292
#endif /* PARANOID */
293
 
294
LDo_2nd_div:
295
        cmpl    $0,%ecx         /* augmented denom msw */
296
        jnz     LSecond_div_not_1
297
 
298
        /* %ecx == 0, we are dividing by 1.0 */
299
        mov     %edx,%eax
300
        jmp     LSecond_div_done
301
 
302
LSecond_div_not_1:
303
        divl    %ecx            /* Divide the numerator by the denom ms dw */
304
 
305
LSecond_div_done:
306
        movl    %eax,FPU_result_1       /* Put the result in the answer */
307
 
308
        mull    SIGH(%ebx)      /* mul by the ms dw of the denom */
309
 
310
        subl    %eax,FPU_accum_1        /* Subtract from the num local reg */
311
        sbbl    %edx,FPU_accum_2
312
 
313
#ifdef PARANOID
314
        jc      L_bugged_2
315
#endif /* PARANOID */
316
 
317
        movl    FPU_result_1,%eax       /* Get the result back */
318
        mull    SIGL(%ebx)      /* now mul the ls dw of the denom */
319
 
320
        subl    %eax,FPU_accum_0        /* Subtract from the num local reg */
321
        sbbl    %edx,FPU_accum_1        /* Subtract from the num local reg */
322
        sbbl    $0,FPU_accum_2
323
 
324
#ifdef PARANOID
325
        jc      L_bugged_2
326
#endif /* PARANOID */
327
 
328
        jz      LDo_3rd_32_bits
329
 
330
#ifdef PARANOID
331
        cmpl    $1,FPU_accum_2
332
        jne     L_bugged_2
333
#endif /* PARANOID */
334
 
335
        /* need to subtract another once of the denom */
336
        movl    SIGL(%ebx),%eax
337
        movl    SIGH(%ebx),%edx
338
        subl    %eax,FPU_accum_0        /* Subtract from the num local reg */
339
        sbbl    %edx,FPU_accum_1
340
        sbbl    $0,FPU_accum_2
341
 
342
#ifdef PARANOID
343
        jc      L_bugged_2
344
        jne     L_bugged_2
345
#endif /* PARANOID */
346
 
347
        addl    $1,FPU_result_1 /* Correct the answer */
348
        adcl    $0,FPU_result_2
349
 
350
#ifdef PARANOID
351
        jc      L_bugged_2      /* Must check for non-zero result here */
352
#endif /* PARANOID */
353
 
354
/*----------------------------------------------------------------------*/
355
/* The division is essentially finished here, we just need to perform
356
   tidying operations.
357
   Deal with the 3rd 32 bits */
358
LDo_3rd_32_bits:
359
        movl    FPU_accum_1,%edx                /* get the reduced num */
360
        movl    FPU_accum_0,%eax
361
 
362
        /* need to check for possible subsequent overflow */
363
        cmpl    SIGH(%ebx),%edx /* denom */
364
        jb      LRound_prep
365
        ja      LPrevent_3rd_overflow
366
 
367
        cmpl    SIGL(%ebx),%eax /* denom */
368
        jb      LRound_prep
369
 
370
LPrevent_3rd_overflow:
371
        /* prevent overflow */
372
        subl    SIGL(%ebx),%eax
373
        sbbl    SIGH(%ebx),%edx
374
        movl    %edx,FPU_accum_1
375
        movl    %eax,FPU_accum_0
376
 
377
        addl    $1,FPU_result_1 /* Reflect the subtraction in the answer */
378
        adcl    $0,FPU_result_2
379
        jne     LRound_prep
380
        jnc     LRound_prep
381
 
382
        /* This is a tricky spot, there is an overflow of the answer */
383
        movb    $255,FPU_ovfl_flag              /* Overflow -> 1.000 */
384
 
385
LRound_prep:
386
/*
387
 * Prepare for rounding.
388
 * To test for rounding, we just need to compare 2*accum with the
389
 * denom.
390
 */
391
        movl    FPU_accum_0,%ecx
392
        movl    FPU_accum_1,%edx
393
        movl    %ecx,%eax
394
        orl     %edx,%eax
395
        jz      LRound_ovfl             /* The accumulator contains zero. */
396
 
397
        /* Multiply by 2 */
398
        clc
399
        rcll    $1,%ecx
400
        rcll    $1,%edx
401
        jc      LRound_large            /* No need to compare, denom smaller */
402
 
403
        subl    SIGL(%ebx),%ecx
404
        sbbl    SIGH(%ebx),%edx
405
        jnc     LRound_not_small
406
 
407
        movl    $0x70000000,%eax        /* Denom was larger */
408
        jmp     LRound_ovfl
409
 
410
LRound_not_small:
411
        jnz     LRound_large
412
 
413
        movl    $0x80000000,%eax        /* Remainder was exactly 1/2 denom */
414
        jmp     LRound_ovfl
415
 
416
LRound_large:
417
        movl    $0xff000000,%eax        /* Denom was smaller */
418
 
419
LRound_ovfl:
420
/* We are now ready to deal with rounding, but first we must get
421
   the bits properly aligned */
422
        testb   $255,FPU_ovfl_flag      /* was the num > denom ? */
423
        je      LRound_precision
424
 
425
        incw    EXP(%edi)
426
 
427
        /* shift the mantissa right one bit */
428
        stc                     /* Will set the ms bit */
429
        rcrl    FPU_result_2
430
        rcrl    FPU_result_1
431
        rcrl    %eax
432
 
433
/* Round the result as required */
434
LRound_precision:
435
        decw    EXP(%edi)       /* binary point between 1st & 2nd bits */
436
 
437
        movl    %eax,%edx
438
        movl    FPU_result_1,%ebx
439
        movl    FPU_result_2,%eax
440
        jmp     fpu_reg_round
441
 
442
 
443
#ifdef PARANOID
444
/* The logic is wrong if we got here */
445
L_bugged:
446
        pushl   EX_INTERNAL|0x202
447
        call    EXCEPTION
448
        pop     %ebx
449
        jmp     L_exit
450
 
451
L_bugged_1:
452
        pushl   EX_INTERNAL|0x203
453
        call    EXCEPTION
454
        pop     %ebx
455
        jmp     L_exit
456
 
457
L_bugged_2:
458
        pushl   EX_INTERNAL|0x204
459
        call    EXCEPTION
460
        pop     %ebx
461
        jmp     L_exit
462
 
463
L_exit:
464
        movl    $-1,%eax
465
        popl    %ebx
466
        popl    %edi
467
        popl    %esi
468
 
469
        leave
470
        ret
471
#endif /* PARANOID */

powered by: WebSVN 2.1.0

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