home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / ASM / GRDBDL17.ZIP / FP.ASM < prev    next >
Encoding:
Assembly Source File  |  1998-10-26  |  11.0 KB  |  696 lines

  1. ;
  2. ; GRDP
  3. ;
  4. ; Copyright(c) LADsoft
  5. ;
  6. ; David Lindauer, camille@bluegrass.net
  7. ;
  8. ;
  9. ; FP.ASM
  10. ;
  11. ; Function: Handle FP status commands
  12. ;
  13.     ;MASM MODE
  14.     .MODEL SMALL
  15.     .386
  16.  
  17.     public    floatcheck, fpcommand
  18.  
  19. include  eprints.inc 
  20. include  einput.inc 
  21. include  emtrap.inc 
  22. include  ebreaks.inc 
  23. include  eloader.inc
  24. include  edos.inc
  25. include eexec.inc
  26.  
  27. ;
  28. ; hack to help MASM versions that die on pop-fmath
  29. ;
  30.     .data
  31. ten        dw    10
  32. pointone    dt    0.1
  33. nan        dd    7fffffffh    ; quiet nan
  34. inf        dd    7f800000h    ; plus infinity
  35. curdig        dd    ?        ;current digit for input
  36. work        dw    ?        ;used in detecting FP hardware
  37. fpflag        db    ?        ;flag if we can use FP commands
  38. floatstat     dw    47 dup (0)    ;FNSAVE/FNSTOR buffer
  39. enames        db    "IDZOUP"    ;exception names
  40.  
  41.  
  42.     .code
  43. precmsg    dw    offset _text:prsing,offset _text:reserved
  44.     dw    offset _text:prdbl,offset _text:prxt
  45. roundmsg dw    offset _text:rdnear,offset _text:rdminus
  46.     dw    offset _text:rdplus,offset _text:rdzer
  47. prsing    db    "Single",0
  48. prdbl    db    "Double",0
  49. prxt    db    "Extended",0
  50. reserved db    "Reserved",0
  51. rdnear    db    "Nearest",0
  52. rdzer    db    "Zero",0
  53. rdplus    db    "Plus Infinity",0
  54. rdminus db    "Minus Infinity",0
  55.  
  56. ;
  57. ; check for floating point unit
  58. ;
  59. floatcheck    proc
  60.         mov    [fpflag],1
  61.         mov    [work],4567h
  62.         fninit
  63.         fstsw     [work]
  64.         cmp    [work],0
  65.         jz    hasfp
  66.         mov    [fpflag],0
  67. hasfp:
  68.         ret
  69. floatcheck    endp
  70. ;
  71. ; fp commands
  72. ;
  73. fpcommand    proc
  74.     test    [fpflag],1
  75.     jnz    hasfloat
  76.     PRINT_MESSAGE    <13,10,"No FP unit">
  77.     clc
  78.     ret
  79. hasfloat:
  80.     fnsave    [floatstat]
  81.     fninit
  82.     fwait
  83.     call    WadeSpace
  84.     jz    dumpstack
  85.     cmp    al,'s'
  86.     jnz    flread
  87. ;
  88. ; status command
  89. ;
  90.     inc    si
  91.     call    WadeSpace
  92.     jnz    flerr
  93.     frstor [floatstat]
  94.     PRINT_MESSAGE    <13,10,"Masked exceptions: ">
  95.     mov    dx,word ptr [floatstat]
  96.     call    except
  97.     PRINT_MESSAGE    <13,10,"Active exceptions: ">
  98.     mov    dx,word ptr [floatstat+2]
  99.     call    except
  100.     PRINT_MESSAGE    <13,10,"Precision:         ">
  101.     movzx    bx,byte ptr [floatstat+1]
  102.     and    bl,3
  103.     shl    bl,1
  104.     mov    bx,[bx+precmsg]
  105.     call    olMessage
  106.     PRINT_MESSAGE    <13,10,"Rounding:          ">
  107.     movzx    bx,byte ptr [floatstat+1]
  108.     and    bl,0ch
  109.     shr    bl,1
  110.     mov    bx,[bx+roundmsg]
  111.     call    olMessage
  112.     PRINT_MESSAGE    <13,10,"FPU Status flags:  ">
  113.     test    word ptr [floatstat+2],100h
  114.     jz    notc0
  115.     PRINT_MESSAGE    "C0 "
  116. notc0:
  117.     test    word ptr [floatstat+2],200h
  118.     jz    notc1
  119.     PRINT_MESSAGE    "C1 "
  120. notc1:
  121.     test    word ptr [floatstat+2],400h
  122.     jz    notc2
  123.     PRINT_MESSAGE    "C2 "
  124. notc2:
  125.     test    word ptr [floatstat+2],4000h
  126.     jz    notc3
  127.     PRINT_MESSAGE    "C3 "
  128. notc3:
  129.     clc
  130.     ret
  131. ;
  132. ; dump the FP stack
  133. ;
  134. dumpstack:
  135.     mov    ax,word ptr [floatstat+2]
  136.     shr    ax,11
  137.     and    ax,7
  138.     sub    ax,7
  139.     neg    ax
  140.     mul    [ten]
  141.     mov    bx,offset floatstat+14
  142.     add    bx,ax
  143.     mov    cx,8
  144. dsl:
  145.     push    bx
  146.     push    cx
  147.     call    dumpval
  148.     pop    cx
  149.     pop    bx
  150.     sub    bx,10
  151.     loop    dsl
  152.     frstor [floatstat]
  153.     clc
  154.     ret
  155. ;
  156. ; read an FP number into a reg
  157. ;
  158. flread:
  159.     sub    al,'0'
  160.     jc    flerr
  161.     cmp    al,8
  162.     jae    flerr
  163.     push    ax
  164.     inc    si
  165.     call    wadespace
  166.     jz    flerr2
  167.     call    ReadFpNumber
  168.     jc    flerr2
  169.     pop    ax
  170.     mov    cl,al
  171.     call    testtag
  172.     jz    flerr3
  173.     mov    bx,word ptr [floatstat+2]
  174.     shr    bx,11
  175.     and    bx,7
  176.     movzx    ax,al
  177.     sub    ax,bx
  178.     mul    [ten]
  179.     mov    bx,ax
  180.     fstp    tbyte ptr [bx + floatstat + 14]
  181.     frstor [floatstat]
  182.     clc
  183.     ret
  184.     
  185. testtag    PROC
  186.     and    cl,7
  187.     add    cl,cl
  188.     mov    bx,[floatstat+4]
  189.     shr    bx,cl
  190.     and    bl,3
  191.     cmp    bl,3
  192.     ret
  193. testtag    ENDP
  194.  
  195. flerr3:
  196.     frstor    [floatstat]
  197.     PRINT_MESSAGE    <13,10,"err - empty reg">
  198.     clc
  199.     ret
  200. flerr2:
  201.     add    sp,2
  202. flerr:
  203.     frstor [floatstat]
  204.     stc
  205.     ret
  206. fpcommand    endp
  207. except    PROC
  208.     mov    si,offset enames
  209.     mov    cx,6
  210. exlp:
  211.     shr    dx,1
  212.     lodsb
  213.     jnc    nhr
  214.     push    dx
  215.        mov    dl,al
  216.     call    putchar
  217.     mov    dl,'e'
  218.     call    putchar
  219.     call    printspace
  220.     pop    dx
  221. nhr:
  222.     loop    exlp
  223.     ret
  224. except    ENDP
  225. ;
  226. ; dump the value of a stack register
  227. ;
  228. dumpval    PROC
  229.     call    crlf
  230.     dec    cl
  231.     mov    dl,cl
  232.     add    dl,'0'
  233.     call    putchar
  234.     mov    ax,word ptr [floatstat+2]
  235.     shr    ax,11
  236.     and    al,7
  237.     cmp    al,cl
  238.     jnz    nottop
  239.            mov    dl,'*'
  240.     call    putchar
  241.     jmp    join
  242. nottop:
  243.     call    printspace
  244. join:
  245.     mov    dl,')'
  246.     call    putchar
  247.     call    printspace
  248.     call    printspace
  249.     call    printspace
  250.     mov    ax,word ptr [floatstat+4]
  251.     shr    ax,cl
  252.     shr    ax,cl
  253.     and    al,3
  254.     cmp    al,3
  255.     jnz    notempty
  256.     PRINT_MESSAGE    "<Empty>"
  257.     clc
  258.     ret
  259.  
  260. notempty:
  261.     cmp    al,2
  262.     jnz    notnan
  263.     test    byte ptr [bx + 9],80h
  264.     jz    nsinf
  265.           mov    dl,'-'
  266.     call    putchar
  267. nsinf:
  268.     fld    tbyte ptr [bx]
  269.     fxam
  270.     fnstsw    ax
  271.     fstp    st(0)
  272.     sahf
  273.     jpe    isinf
  274.     PRINT_MESSAGE    "<Nan>"
  275.     clc
  276.     ret
  277. isinf:
  278.     PRINT_MESSAGE    "<Inf>"
  279.     clc
  280.     ret
  281. notnan:
  282.     cmp    al,1
  283.     jnz    notzero
  284.     jnz    notnan
  285.     test    byte ptr [bx + 9],80h
  286.     jz    nszer
  287.           mov    dl,'-'
  288.     call    putchar
  289. nszer:
  290.     mov    dl,'0'
  291.     call    putchar
  292.     clc
  293.     ret
  294. notzero:
  295.     fld    tbyte ptr [bx]
  296.     call    PrintFloating
  297.     fcomp
  298.     clc
  299.     ret
  300. dumpval    ENDP
  301. ;
  302. ; actual FP print routines
  303. ;
  304. PrintFloating    PROC
  305.     call    fextract
  306.     or    ax,ax
  307.     jz    notdenorm
  308.     PRINT_MESSAGE    "<Denorm>"
  309.     ret
  310. notdenorm:
  311.     or    dx,dx
  312.     jns    noneg
  313.     call    putneg
  314. noneg:
  315.     cmp    bx,8        ; getter be less than 16!!!!
  316.     jg    highexp
  317.     cmp    bx,-4
  318.     jle    lowexp
  319.     or    bx,bx
  320.     jge    gte0
  321. ;
  322. ; print for less than one but not exponential
  323. ;
  324.     push    bx
  325.     call    putzer
  326.     call    putper
  327.     pop    cx
  328.     not    cx
  329.     jcxz    nozr
  330.     inc    cx
  331. zrl:
  332.     call    putzer
  333.     loop    zrl
  334. nozr:
  335.     mov    cx,16
  336. nl2:
  337.     call    fnd
  338.     call    putdig
  339.     loop    nl2
  340.     ret
  341. ;
  342. ; print for greater than or equal to one but not exponential
  343. ;
  344. gte0:
  345.     push    bx
  346.     mov    cx,bx
  347.     call    fnd
  348.     call    putdig
  349.     jcxz    gte0nl
  350. gtel1:
  351.     call    fnd
  352.     call    putdig
  353.     loop    gtel1
  354. gte0nl:
  355.     call    putper
  356.     pop    cx
  357.     sub    cx,16
  358.     neg    cx
  359. gtel2:
  360.     call    fnd
  361.     call    putdig
  362.     loop    gtel2
  363.     ret
  364. ;
  365. ; hack to justify negative exponents
  366. ;
  367. lowexp:
  368.     dec    bx
  369.     call    fnd
  370. ;
  371. ; exponential print
  372. ;
  373. highexp:
  374.     push    bx
  375.     call    fnd
  376.     call    putdig
  377.     call    putper
  378.     mov    cx,16
  379. hel1:
  380.     call    fnd
  381.     call    putdig
  382.     loop    hel1
  383.     mov    dl,'e'
  384.     call    putchar
  385.     pop    ax
  386.     or    ax,ax
  387.     jns    nonegx
  388.     push    ax
  389.     call    putneg
  390.     pop    ax
  391.     neg    ax
  392. nonegx:
  393.     sub    cx,cx
  394. elp1:
  395.     sub    dx,dx
  396.     div    [ten]
  397.     push    dx
  398.     inc    cx
  399.     or    ax,ax
  400.     jnz    elp1
  401. elp2:
  402.     pop    ax
  403.     call    putdig
  404.     loop    elp2
  405.     ret
  406. putdig:
  407.     mov    dl,al
  408.     add    dl,'0'
  409.     call    putchar
  410.            ret
  411. putper:
  412.     mov    dl,'.'
  413.     call    putchar
  414.     ret
  415. putneg:
  416.     mov    dl,'-'
  417.     call    putchar
  418.     ret
  419. putzer:
  420.     mov    dl,'0'
  421.     call    putchar
  422.     ret
  423. PrintFloating    ENDP
  424. ;
  425. ; get exponent and mantissa and sign
  426. ;
  427. ; enter:
  428. ;   st(0) = value
  429. ;
  430. ; returns:
  431. ;   ax = 0    ; ok val
  432. ;   
  433. ;     st(0) = mantissa
  434. ;     bx = exp
  435. ;     dx = sign   ( +-1)
  436. ;
  437. ;   ax = -1    ; infinity or dnormal
  438. ;
  439. fextract     PROC
  440.     enter    6,0
  441.     fstcw    [bp-2]
  442.     mov    ax,[bp-2]
  443.     or    ah,0ch        ; round toward zero
  444.     mov    [bp-4],ax
  445.     fldcw    [bp-4]
  446.  
  447.     ftst
  448.     fnstsw    ax
  449.     fnclex            ; just in case ... 
  450.     sahf
  451.     mov    eax,-1       ; first check for out of range
  452.     jp    fxx
  453.     jnz    dosign        ; now check for zero
  454.     sub    bx,bx
  455.     sub    dx,dx
  456.     jmp    fxx
  457.  
  458. dosign:
  459.     mov    dx,1        ; nonzero, finally get sign
  460.     jnc    pos
  461.     fabs               ; we will work with positive nums hereafter
  462.     mov    dx,-1
  463. pos:
  464.     fldlg2               ; log to base 10
  465.     fxch
  466.     fyl2x
  467.     
  468.     fld    st(0)        ; get int part
  469.     frndint
  470.     fist    word ptr [bp-6]
  471.     pop    bx
  472.  
  473.     fsubp    st(1),st(0)            ; fraction
  474.     fldl2t            ; convert back to base 2
  475.     fmulp    st(1),st(0)
  476.  
  477.     fld    st(0)        ; lovely exponentiation
  478.     frndint
  479.     fxch
  480.     fld    st(1)
  481.     fsubp    st(1),st(0)
  482.     f2xm1            ;
  483.     fld1
  484.     faddp    st(1),st(0)
  485.     fscale
  486.     fxch
  487.     fcomp
  488.     sub    eax,eax
  489. fxx:
  490.     fnclex
  491.     fldcw    [bp-2]
  492.     fwait
  493.     leave
  494.     ret
  495. fextract    ENDP
  496. ;
  497. ; get next digit from mantissa
  498. ;
  499. ; enter:
  500. ;   mantissa from fextract on stack
  501. ;
  502. ; exit:
  503. ;   eax = next digit (base 10)
  504. ;   stack = new mantissa
  505. ;
  506. fnd    PROC
  507.     ENTER    6,0
  508.     fstcw    [bp-2]
  509.     mov    ax,[bp-2]
  510.     or    ah,0ch        ; round toward zero
  511.     mov    [bp-4],ax
  512.     fldcw    [bp-4]
  513.  
  514.     fld    st(0)        ; next digit
  515.     frndint
  516.     fist    word ptr [bp-6]
  517.  
  518.     fsubp    st(1),st(0)            ; new mantissa
  519.     fimul    word ptr [ten]
  520.  
  521.     fnclex
  522.     fldcw    [bp-2]
  523.     fwait
  524.     pop    ax        ; cute trick to get result :)
  525.     leave
  526.     ret
  527. fnd    ENDP
  528. ;
  529. ; read floating point number
  530. readfpnumber PROC
  531.     sub    dx,dx        ; sign = +
  532.     cmp    al,'+'        ; get sign bit
  533.     jz    rfn_gotsign
  534.     cmp    al,'-'
  535.     jnz    rfn_nosign
  536.     inc    dx        ; minus sign, sign = '-'
  537. rfn_gotsign:
  538.     inc    si        ; step past sign
  539. rfn_nosign:
  540.     call    wadespace    ; skip space
  541.     jz    rfn_err
  542.     mov    eax,[si]    ; check for nan
  543.     and    eax,0ffffffh
  544.     cmp    eax,"nan"
  545.     jnz    rfn_notnan
  546.     fld    [nan]        ; nan, load it
  547.     jmp    rfn_ni
  548. rfn_notnan:
  549.     cmp    eax,"fni"    ; check for inf
  550.     jnz    rfn_notinf
  551.     fld    [inf]        ; inf load it
  552. rfn_ni:
  553.     add    si,3        ; skip past inf/nan
  554.     call    wadespace    ; err if more
  555.     jnz    rfn_err2
  556.     jmp    rfn_done        ; else tag in sign and exit
  557. ;
  558. rfn_notinf:
  559.     fldz                ; return val
  560.     call    getdig        ; see if leading digits
  561.     jc    rfn_err2        
  562.     jz    rfn_nostart     ; go check for '.' if not digit
  563. rfn_prelp:
  564.     fimul    [ten]       ; else shift digit in
  565.     fild    [curdig]
  566.     faddp    st(1),st(0)
  567.     call    getdig         ; loop till all digits got
  568.     jc    rfn_err2
  569.     jnz    rfn_prelp
  570.     cmp    al,'.'        ; now check for '.'
  571.     jz    rfn_dot        ; yes, do it
  572.     jmp    rfn_exp
  573. ;
  574. rfn_nostart:
  575.     cmp    al,'.'        ; no leading digit, must have dot
  576.     jnz    rfn_err
  577. rfn_dot:
  578.     call    getdig        ; if no digits get exponent
  579.     jc    rfn_err2
  580.     jz    rfn_exp
  581.     fld    [pointone]    ; else we have digits, load up 0.1
  582. rfn_ptlp:
  583.     fild    [curdig]    ; load digit
  584.     fmul    st(0),st(1)    ; mul by placeholder and add it in
  585.     faddp    st(2),st(0)
  586.     fld    [pointone]     ; adjust placeholder
  587.     fmulp    st(1),st(0)
  588.     call    getdig
  589.     jc    rfn_err3
  590.     jnz    rfn_ptlp
  591.     fstp    st(0)       ; get rid of placeholder
  592. rfn_exp:
  593.     cmp    al,'e'      ; check for exponent
  594.     jnz    rfn_done
  595.     sub    bx,bx
  596.     sub    cx,cx
  597. rfn_exl:
  598.     call    getdig        ; first digit of exponent or sign
  599.     jc    rfn_err2
  600.     jnz    rfn_nexs
  601.     inc    cx
  602.     call    getdig
  603.     jz    rfn_err2
  604.     jc    rfn_err2
  605. rfn_nexs:
  606.     xchg    ax,bx
  607.     push    dx
  608.     mul    [ten]
  609.     pop    dx
  610.     xchg    ax,bx
  611.     movzx    ax,al
  612.     add    bx,ax
  613.     call    getdig
  614.     jc    rfn_err2
  615.     jnz    rfn_nexs
  616.     or    cx,cx
  617.     jz    rfn_nexs2
  618.           neg    bx
  619. rfn_nexs2:
  620.     cmp    bx,1024        ; verify range
  621.     jg    rfn_err2
  622.     cmp    bx,-1024
  623.     jl    rfn_err2
  624.     enter    4,0        ; need temp space now
  625.     mov    [bp-2],bx    ; get exponent to fp stack
  626.     fild    word ptr [bp-2]
  627.     fldl2t                     ; convert exponent to logarithmic base 2
  628.     fmulp    st(1),st(0)
  629.     fnstcw    [bp-4]        ; set rounding mode to zero
  630.     mov    ax,[bp-4]
  631.     and    ah,0f3h
  632.     or    ah,0ch
  633.     mov    [bp-2],ax
  634.     fldcw    [bp-2]
  635.     fld    st(0)       ; extract int and fraction of exponent
  636.     frndint
  637.     fxch    st(1)
  638.     fsub    st(0),st(1)
  639.     f2xm1                  ; exponentiate the fraction
  640.     fld1
  641.     faddp    st(1),st(0)
  642.     fscale            ; scale in the integer part of exponent
  643.     fxch    st(1)          ; get rid of int part
  644.     fcomp    st(1)
  645.     fldcw    [bp-4]        ; restore round mode
  646.     leave            ; clear stack
  647.     fmulp    st(1),st(0)    ; multiply base * exponent (may result in 
  648.                 ; an infinity)
  649. rfn_done:
  650.     or    dx,dx        ; get the sign bit
  651.     jz    rfn_x
  652.     fchs            ; to the FPU
  653. rfn_x:
  654.     clc
  655.     ret
  656.  
  657. rfn_err3:
  658.     fstp    st(0)
  659. rfn_err2:
  660.     fstp    st(0)
  661. rfn_err:
  662.     stc
  663.     ret
  664. ;
  665. ; routine to get a digit, returns ZR for a '.' or 'e' or CR
  666. ; and Carry for an error, else NZ means a digit
  667. ;
  668. getdig    PROC
  669.     lodsb            ; get val
  670.     cmp    al,'0'        ; check low end of digits
  671.     jc    gds        ; no, check high end
  672.     cmp    al,'9'
  673.     ja    gds
  674.     sub    al,'0'
  675.     mov    byte ptr [curdig],al ; digit, store it for later
  676.     or    si,si        ; set nz
  677.     ret
  678. gds:
  679.     cmp    al,'-'
  680.     jz    gdsk
  681.     cmp    al,'e'        ; check for 'e'
  682.     jz    gdsk
  683.     cmp    al,'.'        ; '.'
  684.     jz    gdsk
  685.     cmp    al,13        ; CR
  686.     jnz    gdsk
  687.     pushf            ; if is CR bump char ptr back so
  688.     dec    si        ; we don't overrun
  689.     popf
  690. gdsk:
  691.     clc
  692.     ret
  693.  
  694. getdig    ENDP
  695. readfpnumber ENDP
  696. end