home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2MISC / WMEMU2S.ZIP / LINUX / DRIVERS / FPU-EMU / REG_U_SU.S < prev    next >
Encoding:
Text File  |  1993-12-01  |  6.2 KB  |  293 lines

  1.     .file    "reg_u_sub.S"
  2. /*---------------------------------------------------------------------------+
  3.  |  reg_u_sub.S                                                              |
  4.  |                                                                           |
  5.  | Core floating point subtraction routine.                                  |
  6.  |                                                                           |
  7.  | Copyright (C) 1992,1993                                                   |
  8.  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  9.  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  10.  |                                                                           |
  11.  | Call from C as:                                                           |
  12.  |   void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
  13.  |                                                int control_w)             |
  14.  |                                                                           |
  15.  +---------------------------------------------------------------------------*/
  16.  
  17. /*
  18.  |    Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
  19.  |    Takes two valid reg f.p. numbers (TW_Valid), which are
  20.  |    treated as unsigned numbers,
  21.  |    and returns their difference as a TW_Valid or TW_Zero f.p.
  22.  |    number.
  23.  |    The first number (arg1) must be the larger.
  24.  |    The returned number is normalized.
  25.  |    Basic checks are performed if PARANOID is defined.
  26.  */
  27.  
  28. #include "exception.h"
  29. #include "fpu_asm.h"
  30. #include "control_w.h"
  31.  
  32. .text
  33.     .align 2,144
  34. .globl _reg_u_sub
  35. _reg_u_sub:
  36.     pushl    %ebp
  37.     movl    %esp,%ebp
  38.     pushl    %esi
  39.     pushl    %edi
  40.     pushl    %ebx
  41.  
  42.     movl    PARAM1,%esi    /* source 1 */
  43.     movl    PARAM2,%edi    /* source 2 */
  44.  
  45. #ifdef DENORM_OPERAND
  46.     cmpl    EXP_UNDER,EXP(%esi)
  47.     jg    xOp1_not_denorm
  48.  
  49.     call    _denormal_operand
  50.     orl    %eax,%eax
  51.     jnz    fpu_Arith_exit
  52.  
  53. xOp1_not_denorm:
  54.     cmpl    EXP_UNDER,EXP(%edi)
  55.     jg    xOp2_not_denorm
  56.  
  57.     call    _denormal_operand
  58.     orl    %eax,%eax
  59.     jnz    fpu_Arith_exit
  60.  
  61. xOp2_not_denorm:
  62. #endif DENORM_OPERAND
  63.  
  64.     movl    EXP(%esi),%ecx
  65.     subl    EXP(%edi),%ecx    /* exp1 - exp2 */
  66.  
  67. #ifdef PARANOID
  68.     /* source 2 is always smaller than source 1 */
  69.     js    L_bugged_1
  70.  
  71.     testl    $0x80000000,SIGH(%edi)    /* The args are assumed to be be normalized */
  72.     je    L_bugged_2
  73.  
  74.     testl    $0x80000000,SIGH(%esi)
  75.     je    L_bugged_2
  76. #endif PARANOID
  77.  
  78. /*--------------------------------------+
  79.  |    Form a register holding the     |
  80.  |    smaller number                  |
  81.  +--------------------------------------*/
  82.     movl    SIGH(%edi),%eax    /* register ms word */
  83.     movl    SIGL(%edi),%ebx    /* register ls word */
  84.  
  85.     movl    PARAM3,%edi    /* destination */
  86.     movl    EXP(%esi),%edx
  87.     movl    %edx,EXP(%edi)    /* Copy exponent to destination */
  88. /*    movb    SIGN(%esi),%dl
  89.     movb    %dl,SIGN(%edi) */    /* Copy the sign from the first arg */
  90.  
  91.     xorl    %edx,%edx    /* register extension */
  92.  
  93. /*--------------------------------------+
  94.  |    Shift the temporary register    |
  95.  |      right the required number of    |
  96.  |    places.                |
  97.  +--------------------------------------*/
  98. L_shift_r:
  99.     cmpl    $32,%ecx        /* shrd only works for 0..31 bits */
  100.     jnc    L_more_than_31
  101.  
  102. /* less than 32 bits */
  103.     shrd    %cl,%ebx,%edx
  104.     shrd    %cl,%eax,%ebx
  105.     shr    %cl,%eax
  106.     jmp    L_shift_done
  107.  
  108. L_more_than_31:
  109.     cmpl    $64,%ecx
  110.     jnc    L_more_than_63
  111.  
  112.     subb    $32,%cl
  113.     jz    L_exactly_32
  114.  
  115.     shrd    %cl,%eax,%edx
  116.     shr    %cl,%eax
  117.     orl    %ebx,%ebx
  118.     jz    L_more_31_no_low    /* none of the lowest bits is set */
  119.  
  120.     orl    $1,%edx            /* record the fact in the extension */
  121.  
  122. L_more_31_no_low:
  123.     movl    %eax,%ebx
  124.     xorl    %eax,%eax
  125.     jmp    L_shift_done
  126.  
  127. L_exactly_32:
  128.     movl    %ebx,%edx
  129.     movl    %eax,%ebx
  130.     xorl    %eax,%eax
  131.     jmp    L_shift_done
  132.  
  133. L_more_than_63:
  134.     cmpw    $65,%cx
  135.     jnc    L_more_than_64
  136.  
  137.     /* Shift right by 64 bits */
  138.     movl    %eax,%edx
  139.     orl    %ebx,%ebx
  140.     jz    L_more_63_no_low
  141.  
  142.     orl    $1,%edx
  143.     jmp    L_more_63_no_low
  144.  
  145. L_more_than_64:
  146.     jne    L_more_than_65
  147.  
  148.     /* Shift right by 65 bits */
  149.     /* Carry is clear if we get here */
  150.     movl    %eax,%edx
  151.     rcrl    %edx
  152.     jnc    L_shift_65_nc
  153.  
  154.     orl    $1,%edx
  155.     jmp    L_more_63_no_low
  156.  
  157. L_shift_65_nc:
  158.     orl    %ebx,%ebx
  159.     jz    L_more_63_no_low
  160.  
  161.     orl    $1,%edx
  162.     jmp    L_more_63_no_low
  163.  
  164. L_more_than_65:
  165.     movl    $1,%edx        /* The shifted nr always at least one '1' */
  166.  
  167. L_more_63_no_low:
  168.     xorl    %ebx,%ebx
  169.     xorl    %eax,%eax
  170.  
  171. L_shift_done:
  172. L_subtr:
  173. /*------------------------------+
  174.  |    Do the subtraction    |
  175.  +------------------------------*/
  176.     xorl    %ecx,%ecx
  177.     subl    %edx,%ecx
  178.     movl    %ecx,%edx
  179.     movl    SIGL(%esi),%ecx
  180.     sbbl    %ebx,%ecx
  181.     movl    %ecx,%ebx
  182.     movl    SIGH(%esi),%ecx
  183.     sbbl    %eax,%ecx
  184.     movl    %ecx,%eax
  185.  
  186. #ifdef PARANOID
  187.     /* We can never get a borrow */
  188.     jc    L_bugged
  189. #endif PARANOID
  190.  
  191. /*--------------------------------------+
  192.  |    Normalize the result        |
  193.  +--------------------------------------*/
  194.     testl    $0x80000000,%eax
  195.     jnz    L_round        /* no shifting needed */
  196.  
  197.     orl    %eax,%eax
  198.     jnz    L_shift_1    /* shift left 1 - 31 bits */
  199.  
  200.     orl    %ebx,%ebx
  201.     jnz    L_shift_32    /* shift left 32 - 63 bits */
  202.  
  203. /*
  204.  *     A rare case, the only one which is non-zero if we got here
  205.  *         is:           1000000 .... 0000
  206.  *                      -0111111 .... 1111 1
  207.  *                       -------------------- 
  208.  *                       0000000 .... 0000 1 
  209.  */
  210.  
  211.     cmpl    $0x80000000,%edx
  212.     jnz    L_must_be_zero
  213.  
  214.     /* Shift left 64 bits */
  215.     subl    $64,EXP(%edi)
  216.     xchg    %edx,%eax
  217.     jmp    fpu_reg_round
  218.  
  219. L_must_be_zero:
  220. #ifdef PARANOID
  221.     orl    %edx,%edx
  222.     jnz    L_bugged_3
  223. #endif PARANOID
  224.  
  225.     /* The result is zero */
  226.     movb    TW_Zero,TAG(%edi)
  227.     movl    $0,EXP(%edi)        /* exponent */
  228.     movl    $0,SIGL(%edi)
  229.     movl    $0,SIGH(%edi)
  230.     jmp    L_exit        /* %eax contains zero */
  231.  
  232. L_shift_32:
  233.     movl    %ebx,%eax
  234.     movl    %edx,%ebx
  235.     movl    $0,%edx
  236.     subl    $32,EXP(%edi)    /* Can get underflow here */
  237.  
  238. /* We need to shift left by 1 - 31 bits */
  239. L_shift_1:
  240.     bsrl    %eax,%ecx    /* get the required shift in %ecx */
  241.     subl    $31,%ecx
  242.     negl    %ecx
  243.     shld    %cl,%ebx,%eax
  244.     shld    %cl,%edx,%ebx
  245.     shl    %cl,%edx
  246.     subl    %ecx,EXP(%edi)    /* Can get underflow here */
  247.  
  248. L_round:
  249.     jmp    fpu_reg_round    /* Round the result */
  250.  
  251.  
  252. #ifdef PARANOID
  253. L_bugged_1:
  254.     pushl    EX_INTERNAL|0x206
  255.     call    EXCEPTION
  256.     pop    %ebx
  257.     jmp    L_error_exit
  258.  
  259. L_bugged_2:
  260.     pushl    EX_INTERNAL|0x209
  261.     call    EXCEPTION
  262.     pop    %ebx
  263.     jmp    L_error_exit
  264.  
  265. L_bugged_3:
  266.     pushl    EX_INTERNAL|0x210
  267.     call    EXCEPTION
  268.     pop    %ebx
  269.     jmp    L_error_exit
  270.  
  271. L_bugged_4:
  272.     pushl    EX_INTERNAL|0x211
  273.     call    EXCEPTION
  274.     pop    %ebx
  275.     jmp    L_error_exit
  276.  
  277. L_bugged:
  278.     pushl    EX_INTERNAL|0x212
  279.     call    EXCEPTION
  280.     pop    %ebx
  281.     jmp    L_error_exit
  282. #endif PARANOID
  283.  
  284.  
  285. L_error_exit:
  286.     movl    $1,%eax
  287. L_exit:
  288.     popl    %ebx
  289.     popl    %edi
  290.     popl    %esi
  291.     leave
  292.     ret
  293.