home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / graf / fract5.zip / GENERAL.ASM < prev    next >
Assembly Source File  |  1989-12-18  |  41KB  |  1,394 lines

  1. ;    Generic assembler routines that have very little at all
  2. ;    to do with fractals.
  3. ;
  4. ;    (NOTE:  The video routines have been moved over to VIDEO.ASM)
  5. ;
  6. ; ---- Overall Support
  7. ;
  8. ;    initasmvars()
  9. ;
  10. ; ---- Quick-copy to/from Extraseg support
  11. ;
  12. ;    toextra()
  13. ;    fromextra()
  14. ;    cmpextra()
  15. ;
  16. ; ---- far memory allocation support
  17. ;
  18. ;    farmemalloc()
  19. ;    farmemfree()
  20. ;    erasesegment()
  21. ;
  22. ; ---- General Turbo-C (artificial) support
  23. ;
  24. ;    disable()
  25. ;    enable()
  26. ;
  27. ; ---- 32-bit Multiply/Divide Routines (includes 16-bit emulation)
  28. ;
  29. ;    multiply()
  30. ;    divide()
  31. ;
  32. ; ---- Keyboard, audio (and, hidden inside them, Mouse) support
  33. ;
  34. ;    keypressed()
  35. ;    getakey()
  36. ;    buzzer()
  37. ;    delay()
  38. ;    tone()
  39. ;
  40. ; ---- Expanded Memory Support
  41. ;
  42. ;    emmquery()
  43. ;    emmgetfree()
  44. ;    emmallocate()
  45. ;    emmdeallocate()
  46. ;    emmgetpage()
  47. ;    emmclearpage()
  48. ;
  49. ; ---- CPU, FPU Detectors
  50. ;
  51. ;    cputype()
  52. ;    fputype()
  53.  
  54.  
  55.  
  56. ;             required for compatibility if Turbo ASM
  57. IFDEF ??version
  58.     MASM51
  59.     QUIRKS
  60. ENDIF
  61.  
  62.     .MODEL  medium,c
  63.  
  64.     .8086
  65.  
  66.         ; these must NOT be in any segment!!
  67.         ; this get's rid of TURBO-C fixup errors
  68.  
  69.         extrn   help:far        ; help code (in help.c)
  70.  
  71. .DATA
  72.  
  73. ; ************************ External variables *****************************
  74.  
  75.     extrn    sound:word        ; if 0, supress sounds
  76.     extrn    debugflag:word        ; for debugging purposes only
  77.     extrn    helpmode:word        ; help mode (AUTHORS is special)
  78.  
  79.  
  80. ; ************************ Public variables *****************************
  81.  
  82. public        cpu            ; used by 'calcmand'
  83. public        fpu            ; will be used by somebody someday
  84. public        lookatmouse        ; used by 'calcfrac'
  85. public        _dataseg        ; used by TARGA, other Turbo Code
  86.  
  87. public        extraseg        ; extra 64K segment, if any
  88.  
  89. public        overflow        ; Mul, Div overflow flag: 0 means none
  90.  
  91. ;        arrays declared here, used elsewhere
  92. ;        arrays not used simultaneously are deliberately overlapped
  93.  
  94. public        lx0,ly0                ; used by FRACTINT, CALCFRAC
  95. public        prefix, suffix, dstack, decoderline    ; Used by the Decoder
  96. public        strlocn, teststring        ; used by the Encoder
  97. public        boxx, boxy, boxvalues        ; zoom-box arrays
  98. public        olddacbox            ; temporary DAC saves
  99. public        diskline            ; Used by the Diskvid rtns
  100. public        rlebuf                ; Used ty the TARGA En/Decoder
  101. public        paldata, stbuff            ; 8514A arrays, (FR8514A.ASM)
  102.  
  103. ; ************************* "Shared" array areas **************************
  104.  
  105. lx0        dd    0        ; 8K X-pixel value array
  106. prefix        dw    4096 dup(0)    ; 8K Decoder array
  107.  
  108. ly0        dd    0        ; 8K y-pixel value array
  109. suffix        dw    2048 dup(0)    ; 4K Decoder array
  110. dstack        dw    2048 dup(0)    ; 4K Decoder array
  111.  
  112. strlocn        dw    0        ; 10K Encoder array
  113. olddacbox    db    0        ; (256*3) temporary dacbox values
  114. boxx        dw    2048 dup(0)    ; (previous) box data points - x axis
  115. decoderline    db    0        ; 2K Decoder array
  116. boxy        dw    2048 dup(0)    ; (previous) box data points - y axis
  117. boxvalues    db    2048 dup(0)    ; 2K of (previous) box color values
  118.  
  119. diskline    db    0        ; 2K Diskvideo array
  120. rlebuf        db    0        ; 256 char TARGA encoder array
  121. paldata        db    1024 dup (0)    ; 8514A palette (used in FR8514A.ASM)
  122. stbuff        db    415 dup (0)    ; 8514A state   (used in FR8514A.ASM)
  123.         db    609 dup(0)    ; (fluff this area out to 2K)
  124.  
  125. teststring    db    100  dup(0)    ; 100 byte Encoder array
  126.  
  127. ; ************************ Internal variables *****************************
  128.  
  129. cpu        dw    0        ; cpu type: 86, 186, 286, or 386
  130. fpu        dw    0        ; fpu type: 0, 87, 287, 387
  131. _dataseg    dw    0        ; our "near" data segment
  132.  
  133. overflow    dw    0        ; overflow flag
  134.  
  135. kbd_type    db    0        ; type of keyboard
  136. keybuffer    dw    0        ; real small keyboard buffer
  137.  
  138. delayloop    dw    32        ; delay loop value
  139. delaycount    dw    0        ; number of delay "loops" per ms.
  140.  
  141. ;    "buzzer()" codes:  strings of two-word pairs 
  142. ;        (frequency in cycles/sec, delay in milliseconds)
  143. ;        frequency == 0 means no sound
  144. ;        delay     == 0 means end-of-tune
  145.  
  146. buzzer0        dw    1047,100    ; "normal" completion
  147.         dw    1109,100
  148.         dw    1175,100
  149.         dw    0,0
  150. buzzer1        dw    2093,100    ; "interrupted" completion
  151.         dw    1976,100
  152.         dw    1857,100
  153.         dw    0,0
  154. buzzer2        dw    40,500        ; "error" condition (razzberry)
  155.         dw    0,0
  156.  
  157. extraseg    dw    0        ; extra 64K segment (allocated by init)
  158.  
  159. ; ********************** Mouse Support Variables **************************
  160.  
  161. mouse        db    0        ; == -1 if/when a mouse is found.
  162. mousekey    db    0        ; status of mouse keys (up, down)
  163. mousemickeys    dw    0        ; running mickey counter
  164. lookatmouse    dw    0        ; if 0, ignore non-button mouse mvment
  165.  
  166.  
  167. .CODE
  168.  
  169. ; *************** Function toextra(tooffset,fromaddr, fromcount) *********
  170.  
  171. toextra    proc    uses es di si, tooffset:word, fromaddr:word, fromcount:word
  172.     cmp    extraseg,0        ; IS there extra memory?
  173.     je    tobad            ;  nope.  too bad.
  174.     cld                ; move forward
  175.     mov    ax,extraseg        ; load ES == extra segment
  176.     mov    es,ax            ;  ..
  177.     mov    di,tooffset        ; load to here
  178.     mov    si,fromaddr        ; load from here
  179.     mov    cx,fromcount        ; this many bytes
  180.     rep    movsb            ; do it.
  181. tobad:
  182.     ret                ; we done.
  183. toextra    endp
  184.  
  185.  
  186. ; *************** Function fromextra(fromoffset, toaddr, tocount) *********
  187.  
  188. fromextra proc    uses es di si, fromoffset:word, toaddr:word, tocount:word
  189.     push    ds            ; save DS for a tad
  190.     pop    es            ; restore it to ES
  191.     cmp    extraseg,0        ; IS there extra memory?
  192.     je    frombad            ;  nope.  too bad.
  193.     cld                ; move forward
  194.     mov    si,fromoffset        ; load from here
  195.     mov    di,toaddr        ; load to here
  196.     mov    cx,tocount        ; this many bytes
  197.     mov    ax,extraseg        ; load DS == extra segment
  198.     mov    ds,ax            ;  ..
  199.     rep    movsb            ; do it.
  200. frombad:
  201.     push    es            ; save ES again.
  202.     pop    ds            ; restore DS 
  203.     ret                ; we done.
  204. fromextra endp
  205.  
  206.  
  207. ; *************** Function cmpextra(cmpoffset,cmpaddr, cmpcount) *********
  208.  
  209. cmpextra proc    uses es di si, cmpoffset:word, cmpaddr:word, cmpcount:word
  210.     cmp    extraseg,0        ; IS there extra memory?
  211.     je    cmpbad            ;  nope.  too bad.
  212.     cld                ; move forward
  213.     mov    ax,extraseg        ; load ES == extra segment
  214.     mov    es,ax            ;  ..
  215.     mov    di,cmpoffset        ; load to here
  216.     mov    si,cmpaddr        ; load from here
  217.     mov    cx,cmpcount        ; this many bytes
  218.     rep    cmpsb            ; do it.
  219.     jnz    cmpbad            ; failed.
  220.     mov    ax,0            ; 0 == true
  221.     jmp    cmpend
  222. cmpbad:
  223.     mov    ax,1            ; 1 == false
  224. cmpend:
  225.     ret                ; we done.
  226. cmpextra    endp
  227.  
  228.  
  229. ; =======================================================
  230. ;
  231. ;    32-bit integer multiply routine with an 'n'-bit shift.
  232. ;    Overflow condition returns 0x7fffh with overflow = 1;
  233. ;
  234. ;    long x, y, z, multiply();
  235. ;    int n;
  236. ;
  237. ;    z = multiply(x,y,n)
  238. ;
  239. ;    requires the presence of an external variable, 'cpu'.
  240. ;        'cpu' == 386 if a 386 is present.
  241.  
  242. .MODEL    medium,c
  243.  
  244. .8086
  245.  
  246. .DATA
  247.  
  248. temp    dw    5 dup(0)        ; temporary 64-bit result goes here
  249. sign    db    0            ; sign flag goes here
  250.  
  251. .CODE
  252.  
  253. multiply    proc    uses di si es, x:dword, y:dword, n:word
  254.  
  255.     cmp    cpu,386            ; go-fast time?
  256.     jne    slowmultiply        ; no.  yawn...
  257.  
  258. .386                    ; 386-specific code starts here
  259.  
  260.     mov    eax,x            ; load X into EAX
  261.     imul    y            ; do the multiply
  262.     mov    cx,n            ; set up the shift
  263.     cmp    cx,32            ; ugly klooge:  check for 32-bit shift
  264.     jb    short fastm1        ;  < 32 bits:  no problem
  265.     mov    eax,edx            ;  >= 32 bits:  manual shift
  266.     mov    edx,0            ;  ...
  267.     sub    cx,32            ;  ...
  268. fastm1:    push    cx            ; save to counter
  269.     shrd    eax,edx,cl        ; shift down 'n' bits
  270.     pop    cx            ; restore the counter
  271.     sar    edx,cl            ; shift down the top bits
  272.     cmp    eax,0            ; verify the resulting sign
  273.     jge    fastm3            ;  positive
  274.     inc    edx            ; negative - increment edx
  275. fastm3:    cmp    edx,0            ; if EDX isn't zero
  276.     jne    overm1            ;  we overflowed
  277.     push    eax            ; save the 64-bit result
  278.     pop    ax            ; low-order  16 bits
  279.     pop    dx            ; high-order 16 bits
  280.     jmp    multiplyreturn        ; back to common code
  281.  
  282. .8086                    ; 386-specific code ends here
  283.  
  284. slowmultiply:                ; (sigh)  time to do it the hard way...
  285.  
  286.     mov    ax,0
  287.     mov    temp+4,ax        ; first, zero out the (temporary)
  288.     mov    temp+6,ax        ;  result
  289.     mov    temp+8,ax
  290.  
  291.     les    bx,x            ; move X to SI:BX
  292.     mov    si,es            ;  ...
  293.     les    cx,y            ; move Y to DI:CX
  294.     mov    di,es            ;  ...
  295.  
  296.     mov    sign,0            ; clear out the sign flag
  297.     cmp    si,0            ; is X negative?
  298.     jge    mults1            ;  nope
  299.     not    sign            ;  yup.  flip signs
  300.     not    bx            ;   ...
  301.     not    si            ;   ...
  302.     stc                ;   ...
  303.     adc    bx,ax            ;   ...
  304.     adc    si,ax            ;   ...
  305. mults1:    cmp    di,0            ; is DI:CX negative?
  306.     jge    mults2            ;  nope
  307.     not    sign            ;  yup.  flip signs
  308.     not    cx            ;   ...
  309.     not    di            ;   ...
  310.     stc                ;   ...
  311.     adc    cx,ax            ;   ...
  312.     adc    di,ax            ;   ...
  313. mults2:
  314.  
  315.     mov    ax,bx            ; perform BX x CX
  316.     mul    cx            ;  ...
  317.     mov    temp,ax            ;  results in lowest 32 bits
  318.     mov    temp+2,dx        ;  ...
  319.  
  320.     mov    ax,bx            ; perform BX x DI
  321.     mul    di            ;  ...
  322.     add    temp+2,ax        ;  results in middle 32 bits
  323.     adc    temp+4,dx        ;  ...
  324.     jnc    mults3            ;  carry bit set?
  325.     inc    word ptr temp+6        ;  yup.  overflow
  326. mults3:
  327.  
  328.     mov    ax,si            ; perform SI * CX
  329.     mul    cx            ;  ...
  330.     add    temp+2,ax        ;  results in middle 32 bits
  331.     adc    temp+4,dx        ;  ...
  332.     jnc    mults4            ;  carry bit set?
  333.     inc    word ptr temp+6        ;  yup.  overflow
  334. mults4:
  335.  
  336.     mov    ax,si            ; perform SI * DI
  337.     mul    di            ;  ...
  338.     add    temp+4,ax        ; results in highest 32 bits
  339.     adc    temp+6,dx        ;  ...
  340.  
  341.     mov    cx,n            ; set up for the shift loop
  342.     cmp    cx,24            ; shifting by three bytes or more?
  343.     jl    multc1            ;  nope.  check for something else
  344.     sub    cx,24            ; quick-shift 24 bits
  345.     mov    ax,temp+3        ; load up the registers
  346.     mov    dx,temp+5        ;  ...
  347.     mov    si,temp+7        ;  ...
  348.     mov    bx,0            ;  ...
  349.     jmp    short multc4        ; branch to common code
  350. multc1:    cmp    cx,16            ; shifting by two bytes or more?
  351.     jl    multc2            ;  nope.  check for something else
  352.     sub    cx,16            ; quick-shift 16 bits
  353.     mov    ax,temp+2        ; load up the registers
  354.     mov    dx,temp+4        ;  ...
  355.     mov    si,temp+6        ;  ...
  356.     mov    bx,0            ;  ...
  357.     jmp    short multc4        ; branch to common code
  358. multc2:    cmp    cx,8            ; shifting by one byte or more?
  359.     jl    multc3            ;  nope.  check for something else
  360.     sub    cx,8            ; quick-shift 8 bits
  361.     mov    ax,temp+1        ; load up the registers
  362.     mov    dx,temp+3        ;  ...
  363.     mov    si,temp+5        ;  ...
  364.     mov    bx,temp+7        ;  ...
  365.     jmp    short multc4        ; branch to common code
  366. multc3:    mov    ax,temp            ; load up the regs
  367.     mov    dx,temp+2        ;  ...
  368.     mov    si,temp+4        ;  ...
  369.     mov    bx,temp+6        ;  ...
  370. multc4:    cmp    cx,0            ; done shifting?
  371.     je    multc5            ;  yup.  bail out
  372.  
  373. multloop:
  374.     shr    bx,1            ; shift down 1 bit, cascading
  375.     rcr    si,1            ;  ...
  376.     rcr    dx,1            ;  ...
  377.     rcr    ax,1            ;  ...
  378.     loop    multloop        ; try the next bit, if any
  379. multc5:
  380.     cmp    si,0            ; overflow time?
  381.     jne    overm1            ; yup.  Bail out.
  382.     cmp    bx,0            ; overflow time?
  383.     jne    overm1            ; yup.  Bail out.
  384.     cmp    dx,0            ; overflow time?
  385.     jl    overm1            ; yup.  Bail out.
  386.  
  387.     cmp    sign,0            ; should we negate the result?
  388.     je    mults5            ;  nope.
  389.     not    ax            ;  yup.  flip signs.
  390.     not    dx            ;   ...
  391.     mov    bx,0            ;   ...
  392.     stc                ;   ...
  393.     adc    ax,bx            ;   ...
  394.     adc    dx,bx            ;   ...
  395. mults5:
  396.     jmp    multiplyreturn
  397.  
  398. overm1:
  399.     mov    ax,0ffffh        ; overflow value
  400.     mov    dx,07fffh        ; overflow value
  401.     mov    overflow,1        ; flag overflow
  402.  
  403. multiplyreturn:                ; that's all, folks!
  404.     ret
  405. multiply    endp
  406.  
  407.  
  408. ; =======================================================
  409. ;
  410. ;    32-bit integer divide routine with an 'n'-bit shift.
  411. ;    Overflow condition returns 0x7fffh with overflow = 1;
  412. ;
  413. ;    long x, y, z, divide();
  414. ;    int n;
  415. ;
  416. ;    z = divide(x,y,n);    /* z = x / y; */
  417. ;
  418. ;    requires the presence of an external variable, 'cpu'.
  419. ;        'cpu' == 386 if a 386 is present.
  420.  
  421.  
  422. .8086
  423.  
  424. divide        proc    uses di si es, x:dword, y:dword, n:word
  425.  
  426.     cmp    cpu,386            ; go-fast time?
  427.     jne    slowdivide        ; no.  yawn...
  428.  
  429. .386                    ; 386-specific code starts here
  430.  
  431.     mov    edx,x            ; load X into EDX (shifts to EDX:EAX)
  432.     mov    ebx,y            ; load Y into EBX
  433.  
  434.     mov    sign,0            ; clear out the sign flag
  435.     cmp    edx,0            ; is X negative?
  436.     jge    short divides1        ;  nope
  437.     not    sign            ;  yup.  flip signs
  438.     neg    edx            ;   ...
  439. divides1:
  440.     cmp    ebx,0            ; is Y negative?
  441.     jge    short divides2        ;  nope
  442.     not    sign            ;  yup.  flip signs
  443.     neg    ebx            ;   ...
  444. divides2:
  445.  
  446.     mov    eax,0            ; clear out the low-order bits
  447.     mov    cx,32            ; set up the shift
  448.     sub    cx,n            ; (for large shift counts - faster)
  449. fastd1:    cmp    cx,0            ; done shifting?
  450.     je    fastd2            ; yup.
  451.     shr    edx,1            ; shift one bit
  452.     rcr    eax,1            ;  ...
  453.     loop    fastd1            ; and try again
  454. fastd2:
  455.     cmp    edx,ebx            ; umm, will the divide blow out?
  456.     jae    overd1            ;  yup.  better skip it.
  457.     div    ebx            ; do the divide
  458.     cmp    eax,0            ; did the sign flip?
  459.     jl    overd1            ;  then we overflowed
  460.     cmp    sign,0            ; is the sign reversed?
  461.     je    short divides3        ;  nope
  462.     neg    eax            ; flip the sign
  463. divides3:
  464.     push    eax            ; save the 64-bit result
  465.     pop    ax            ; low-order  16 bits
  466.     pop    dx            ; high-order 16 bits
  467.     jmp    dividereturn        ; back to common code
  468.  
  469. .8086                    ; 386-specific code ends here
  470.  
  471. slowdivide:                ; (sigh)  time to do it the hard way...
  472.  
  473.     les    ax,x            ; move X to DX:AX
  474.     mov    dx,es            ;  ...
  475.  
  476.     mov    sign,0            ; clear out the sign flag
  477.     cmp    dx,0            ; is X negative?
  478.     jge    divides4        ;  nope
  479.     not    sign            ;  yup.  flip signs
  480.     not    ax            ;   ...
  481.     not    dx            ;   ...
  482.     stc                ;   ...
  483.     adc    ax,0            ;   ...
  484.     adc    dx,0            ;   ...
  485. divides4:
  486.  
  487.     mov    cx,32            ; get ready to shift the bits
  488.     sub    cx,n            ; (shift down rather than up)
  489.     mov    byte ptr temp+4,cl    ;  ...
  490.  
  491.     mov    cx,0            ;  clear out low bits of DX:AX:CX:BX
  492.     mov    bx,0            ;  ...
  493.  
  494.     cmp    byte ptr temp+4,16    ; >= 16 bits to shift?
  495.     jl    dividex0        ;  nope
  496.     mov    bx,cx            ;  yup.  Take a short-cut
  497.     mov    cx,ax            ;   ...
  498.     mov    ax,dx            ;   ...
  499.     mov    dx,0            ;   ...
  500.     sub    byte ptr temp+4,16    ;   ...
  501. dividex0:
  502.     cmp    byte ptr temp+4,8    ; >= 8 bits to shift?
  503.     jl    dividex1        ;  nope
  504.     mov    bl,bh            ;  yup.  Take a short-cut
  505.     mov    bh,cl            ;   ...
  506.     mov    cl,ch            ;   ...
  507.     mov    ch,al            ;   ...
  508.     mov    al,ah            ;   ...
  509.     mov    ah,dl            ;   ...
  510.     mov    dl,dh            ;   ...
  511.     mov    dh,0            ;   ...
  512.     sub    byte ptr temp+4,8    ;   ...
  513. dividex1:
  514.     cmp    byte ptr temp+4,0    ; are we done yet?
  515.     je    dividex2        ;  yup
  516.     shr    dx,1            ; shift all 64 bits
  517.     rcr    ax,1            ;  ...
  518.     rcr    cx,1            ;  ...
  519.     rcr    bx,1            ;  ...
  520.     dec    byte ptr temp+4        ; decrement the shift counter
  521.     jmp    short dividex1        ;  and try again
  522. dividex2:
  523.  
  524.     les    di,y            ; move Y to SI:DI
  525.     mov    si,es            ;  ...
  526.  
  527.     cmp    si,0            ; is Y negative?
  528.     jge    divides5        ;  nope
  529.     not    sign            ;  yup.  flip signs
  530.     not    di            ;   ...
  531.     not    si            ;   ...
  532.     stc                ;   ...
  533.     adc    di,0            ;   ...
  534.     adc    si,0            ;   ...
  535. divides5:
  536.  
  537.     mov    byte ptr temp+4,33    ; main loop counter 
  538.     mov    temp,0            ; results in temp
  539.     mov    word ptr temp+2,0    ;  ...
  540.  
  541. dividel1:
  542.     shl    temp,1            ; shift the result up 1
  543.     rcl    word ptr temp+2,1    ;  ...
  544.     cmp    dx,si            ; is DX:AX >= Y?
  545.     jb    dividel3        ;  nope
  546.     ja    dividel2        ;  yup
  547.     cmp    ax,di            ;  maybe
  548.     jb    dividel3        ;  nope
  549. dividel2:
  550.     cmp    byte ptr temp+4,32    ; overflow city?
  551.     jge    overd1            ;  yup.
  552.     sub    ax,di            ; subtract Y
  553.     sbb    dx,si            ;  ...
  554.     inc    temp            ; add 1 to the result
  555.     adc    word ptr temp+2,0    ;  ...
  556. dividel3:
  557.     shl    bx,1            ; shift all 64 bits
  558.     rcl    cx,1            ;  ...
  559.     rcl    ax,1            ;  ...
  560.     rcl    dx,1            ;  ...
  561.     dec    byte ptr temp+4        ; time to quit?
  562.     jnz    dividel1        ;  nope.  try again.
  563.  
  564.     mov    ax,temp            ; copy the result to DX:AX
  565.     mov    dx,word ptr temp+2    ;  ...
  566.     cmp    sign,0            ; should we negate the result?
  567.     je    divides6        ;  nope.
  568.     not    ax            ;  yup.  flip signs.
  569.     not    dx            ;   ...
  570.     mov    bx,0            ;   ...
  571.     stc                ;   ...
  572.     adc    ax,0            ;   ...
  573.     adc    dx,0            ;   ...
  574. divides6:
  575.     jmp    short dividereturn
  576.  
  577. overd1:
  578.     mov    ax,0ffffh        ; overflow value
  579.     mov    dx,07fffh        ; overflow value
  580.     mov    overflow,1        ; flag overflow
  581.  
  582. dividereturn:                ; that's all, folks!
  583.     ret
  584. divide        endp
  585.  
  586.  
  587. ; ****************** Function getakey() *****************************
  588. ; **************** Function keypressed() ****************************
  589.  
  590. ;    'getakey()' gets a key from either a "normal" or an enhanced
  591. ;    keyboard.   Returns either the vanilla ASCII code for regular
  592. ;    keys, or 1000+(the scan code) for special keys (like F1, etc)
  593. ;    Use of this routine permits the Control-Up/Down arrow keys on
  594. ;    enhanced keyboards.
  595. ;
  596. ;    The concept for this routine was "borrowed" from the MSKermit
  597. ;    SCANCHEK utility
  598. ;
  599. ;    'keypressed()' returns a zero if no keypress is outstanding,
  600. ;    and the value that 'getakey()' will return if one is.  Note
  601. ;    that you must still call 'getakey()' to flush the character.
  602. ;    As a sidebar function, calls 'help()' if appropriate.
  603. ;    Think of 'keypressed()' as a super-'kbhit()'.
  604.  
  605. keypressed    proc
  606. keypressed1:
  607.     cmp    keybuffer,0            ; is a keypress stacked up?
  608.     jne    keypressed3            ;  yup. use it.
  609.     mov    ah,kbd_type            ; get the keyboard type
  610.     or    ah,1                ; check if a key is ready
  611.     int    16h                ; has a key been hit?
  612.      jnz    keypressed2            ; yes.  handle it
  613.      call    msemvd                ; key pressed on the mouse?
  614.      jc    keypressed2            ; yes.  handle it.
  615.     cmp    lookatmouse,0            ; look for mouse movement?
  616.     je    keypressed5            ; nope.  return: no action.
  617.      call    chkmse                ; was the mouse moved
  618.      jnc    keypressed5            ; nope.  return: no action.
  619. keypressed2:
  620.     call    far ptr getakey            ; get the keypress code
  621.     mov    keybuffer,ax            ; and save the result.
  622. keypressed3:
  623.     mov    ax,keybuffer            ; return the keypress code.
  624.     cmp    helpmode,1            ; is this HELPAUTHORS mode?
  625.     je    keypressed5            ;  yup.  forget help.
  626.     cmp    ax,'h'                ; help called?
  627.     je    keypressed4            ;  ...
  628.     cmp    ax,'H'                ; help called?
  629.     je    keypressed4            ;  ...
  630.     cmp    ax,'?'                ; help called?
  631.     je    keypressed4            ;  ...
  632.     cmp    ax,'/'                ; help called?
  633.     je    keypressed4            ;  ...
  634.     jmp    keypressed5            ; no help asked for.
  635. keypressed4:
  636.     mov    keybuffer,0            ; say no key hit
  637.     push    es                ; save a few registers
  638.     mov    ax,2                ; ask for general help
  639.     push    ax                ;  ...
  640.     call    far ptr help            ; help!
  641.     mov    keybuffer,ax            ; save the result
  642.     pop    ax                ; returned value
  643.     pop    es                ; restore some registers
  644. keypressed5:
  645.     mov    ax,keybuffer            ; return keypress, if any
  646.     ret
  647. keypressed    endp
  648.  
  649. getakey    proc
  650. ; TARGA 31 May 89 j mclain
  651. ; when using '.model size,c' with TASM,
  652. ;   TASM 'gifts' us with automatic insertions of:
  653. ;  proc xxxx
  654. ;   -> push bp
  655. ;   -> mov bp,sp
  656. ;    ...
  657. ;   ->pop bp
  658. ;  ret
  659. ;
  660. ; we corrected a situation here where we had a constant 'jz getakey'
  661. ; can we say 'stack overflow'
  662. ;
  663. getakey0:
  664.     mov    ax,keybuffer            ; keypress may be here
  665.     mov    keybuffer,0            ; if it was, clear it
  666.     cmp    ax,0                ; is a keypress outstanding?
  667.     jne    getakey4            ;  if so, we're done!
  668.      call    msemvd                ; key pressed on the mouse?
  669.      jc    getakey5            ; yes.  handle it.
  670.     cmp    lookatmouse,0            ; look for mouse movement?
  671.     je    getakey6            ; nope.  return: no action.
  672. getakey5:
  673.      call    chkmse                ; see if the mouse was used
  674.      jc    short getakey4            ; ax holds the phoney key
  675. getakey6:
  676.     mov    ah,kbd_type            ; get the keyboard type
  677.     or    ah,1                ; check if a key is ready
  678.     int    16h                ; now check a key
  679.     jz    getakey0            ; so check the mouse again
  680.     mov    ah,kbd_type            ; get the keyboard type
  681.     int    16h                ; now get a key
  682.     cmp    al,0e0h                ; check: Enhanced Keyboard key?
  683.     jne    short getakey1            ; nope.  proceed
  684.     cmp    ah,0                ; part 2 of Enhanced Key check
  685.     je    short getakey1            ; failed.  normal key.
  686.     mov    al,0                ; Turn enhanced key "normal"
  687.     jmp    short getakey2            ; jump to common code
  688. getakey1:            
  689.     cmp    ah,0e0h                ; check again:  Enhanced Key?
  690.     jne    short getakey2            ;  nope.  proceed.
  691.     mov    ah,al                ; Turn Enhanced key "normal"
  692.     mov    al,0                ;  ...
  693. getakey2:
  694.     cmp    al,0                ; Function Key?
  695.     jne    short getakey3            ;  nope.  proceed.
  696.     mov    al,ah                ; klooge into ASCII Key
  697.     mov    ah,0                ; clobber the scan code
  698.     add    ax,1000                ;  + 1000
  699.     jmp    short getakey4            ; go to common return
  700. getakey3:
  701.     mov    ah,0                ; clobber the scan code
  702. getakey4:
  703.     ret
  704. getakey    endp
  705.  
  706. ; ****************** Function buzzer(int buzzertype) *******************
  707. ;
  708. ;    Sound a tone based on the value of the parameter
  709. ;
  710. ;    0 = normal completion of task
  711. ;    1 = interrupted task
  712. ;    2 = error contition
  713.  
  714. ; ***********************************************************************
  715.  
  716. buzzer    proc    uses si, buzzertype:word
  717.     cmp    sound,0            ; is the sound supressed?
  718.     je    buzzerreturn        ;  yup.  bail out.
  719.     mov    si, offset buzzer0    ; normal completion frequency
  720.     cmp    buzzertype,0        ; normal completion?
  721.     je    buzzerdoit        ; do it
  722.     mov    si,offset buzzer1    ; interrupted task frequency
  723.     cmp    buzzertype,1        ; interrupted task?
  724.     je    buzzerdoit        ; do it
  725.     mov    si,offset buzzer2    ; error condition frequency
  726. buzzerdoit:
  727.     mov    ax,0[si]        ; get the (next) frequency
  728.     mov    bx,2[si]        ; get the (next) delay
  729.     add    si,4            ; get ready for the next tone
  730.     cmp    bx,0            ; are we done?
  731.     je    buzzerreturn        ;  yup.
  732.     push    bx            ; put delay time on the stack
  733.     push    ax            ; put tone value on the stack
  734.     call    far ptr tone        ; do it
  735.     pop    ax            ; restore stack
  736.     pop    bx            ; restore stack
  737.     jmp    short buzzerdoit    ; get the next tone
  738. buzzerreturn:
  739.     ret                ; we done
  740. buzzer    endp
  741.  
  742. ; ***************** Function delay(int delaytime) ************************
  743. ;
  744. ;    performs a delay loop for 'delaytime' milliseconds
  745. ;
  746. ; ************************************************************************
  747.  
  748. delayamillisecond    proc    near    ; internal delay-a-millisecond code
  749.     mov    bx,delaycount        ; set up to burn another millisecond
  750. delayamill1:
  751.     mov    cx,delayloop        ; start up the counter
  752. delayamill2:                ;
  753.     loop    delayamill2        ; burn up some time
  754.     dec    bx            ; have we burned up a millisecond?
  755.     jnz    delayamill1        ;  nope.  try again.
  756.     ret                ; we done
  757. delayamillisecond    endp
  758.  
  759. delay    proc    uses es, delaytime:word    ; delay loop (arg in milliseconds)
  760.     mov    ax,delaytime        ; get the number of milliseconds
  761.     cmp    ax,0            ; any delay time at all?
  762.     je    delayreturn        ;  nope.
  763. delayloop1:
  764.     call    delayamillisecond    ; burn up a millisecond of time
  765.     dec    ax            ; have we burned up enough m-seconds?
  766.     jnz    delayloop1        ;  nope.  try again.
  767. delayreturn:
  768.     ret                ; we done.
  769. delay    endp
  770.  
  771. ; ************** Function tone(int frequency,int delaytime) **************
  772. ;
  773. ;    buzzes the speaker with this frequency for this amount of time
  774. ;
  775. ; ************************************************************************
  776.  
  777. tone    proc    uses es, tonefrequency:word, tonedelay:word
  778.     mov    al,0b6h            ; latch to channel 2
  779.     out    43h,al            ;  ...
  780.     cmp    tonefrequency,12h    ; was there a frequency?
  781.     jbe    tonebypass        ;  nope.  delay only
  782.     mov    bx,tonefrequency    ; get the frequency value
  783.     mov    ax,0            ; ugly klooge: convert this to the
  784.     mov    dx,12h            ; divisor the 8253 wants to see
  785.     div    bx            ;  ...
  786.     out    42h,al            ; send the low value
  787.     mov    al,ah            ; then the high value
  788.     out    42h,al            ;  ...
  789.     in    al,61h            ; get the current 8255 bits
  790.     or    al,3            ; turn bits 0 and 1 on
  791.     out    61h,al            ;  ...
  792. tonebypass:
  793.     mov    ax,tonedelay        ; get the delay value
  794.     push    ax            ; set the parameter
  795.     call    far ptr delay        ; and force a delay
  796.     pop    ax            ; restore the parameter
  797.  
  798.     in    al,61h            ; get the current 8255 bits
  799.     and    al,11111100b        ; turn bits 0 and 1 off
  800.     out    61h,al
  801.  
  802.     ret                ; we done
  803. tone    endp
  804.  
  805.  
  806. ; ********************* Mouse Support Code ******************************
  807. ;
  808. ;         Contributed by Mike Kaufman
  809. ;    (and then hacked up beyond all recall by me (sorry) - Bert)
  810. ;
  811. ; ***********************************************************************
  812.  
  813. ; ****************** Function initasmvars() *****************************
  814.  
  815. initasmvars    proc    uses es si di
  816.  
  817.      cmp    cpu,0            ; have we been called yet:
  818.      je    initasmvarsgo        ;  nope.  proceed.
  819.      jmp    initreturn        ;  yup.  no need to be here.
  820.  
  821. initasmvarsgo:
  822.     mov    ax,ds            ; save the data segment
  823.     mov    _dataseg,ax        ;  for the C code
  824.  
  825.     mov    overflow,0        ; indicate no overflows so far
  826.  
  827.     mov    dx,1            ; ask for 96K of far space
  828.     mov    ax,8000h        ;  ...
  829.     push    dx            ;  ...
  830.     push    ax            ;  ...
  831.     call    far ptr farmemalloc    ; use the assembler routine to do it
  832.     pop    ax            ; restore the stack
  833.     pop    ax            ;  ...
  834.     mov    extraseg,dx        ; save the results here.
  835.  
  836.     push    es            ; save ES for a tad
  837.     mov    ax,0            ; reset ES to BIOS data area
  838.     mov    es,ax            ;  ...
  839.     mov    dx,es:46ch        ; obtain the current timer value
  840. delaystartuploop:
  841.     cmp    dx,es:46ch        ; has the timer value changed?
  842.     je    delaystartuploop    ;  nope.  check again.
  843.     mov    dx,es:46ch        ; obtain the current timer value again
  844.     mov    ax,0            ; clear the delay counter
  845.     mov    delaycount,55        ; 55 millisecs = 1/18.2 secs
  846. delaytestloop:
  847.     call    delayamillisecond    ; burn up a (fake) millisecond
  848.     inc    ax            ; indicate another loop has passed
  849.     cmp    dx,es:46ch        ; has the timer value changed?
  850.     je    delaytestloop        ; nope.  burn up some more time.
  851.     mov    delaycount,ax        ; save the results here
  852.     pop    es            ; restore ES again
  853.  
  854.                        ; first see if a mouse is installed 
  855.  
  856.     push    es            ; (no, first check to ensure that
  857.     mov    ax,0            ; int 33h doesn't point to 0:0)
  858.     mov    es,ax            ; ...
  859.     mov    ax,es:0cch        ; ...
  860.     pop    es            ; ...
  861.     cmp    ax,0            ; does int 33h have a non-zero value?
  862.     je    noint33            ;  nope.  then there's no mouse.
  863.  
  864.          xor    ax,ax                  ; function for mouse check
  865.          int    33h                    ; call mouse driver
  866. noint33:
  867.      mov    mouse,al           ; al holds info about mouse
  868.     
  869.                         ; now get the information about the kbd
  870.      push    es               ; save ES for a tad
  871.      mov    ax,40h               ; reload ES with BIOS data seg
  872.      mov    es,ax               ;  ...
  873.      mov    ah,es:96h           ; get the keyboard byte
  874.      pop    es               ; restore ES
  875.      and    ah,10h               ; isolate the Enhanced KBD bit
  876.      mov    kbd_type,ah           ; and save it
  877.  
  878.     call    far ptr cputype        ; what kind of CPU do we have here?
  879.     cmp    ax,0            ; protected mode of some sort?
  880.     jge    positive        ;  nope.  proceed.
  881.     neg    ax            ;  yup.  flip the sign.
  882. positive:
  883.     mov    cpu,ax            ; save the cpu type.
  884. itsa386:
  885.     cmp    debugflag,8088        ; say, should we pretend it's an 8088?
  886.     jne    nodebug            ;  nope.
  887.     mov    cpu,86            ; yup.  use 16-bit emulation.
  888. nodebug:
  889.     call far ptr fputype        ; what kind of an FPU do we have?
  890.     mov    fpu,ax            ;  save the results
  891.  
  892. initreturn:
  893.      ret                           ; return to caller
  894. initasmvars endp
  895.  
  896.  
  897. ; This function checks if a mouse button has been pushed or if the mouse moved
  898. chkmse    proc    near
  899.     cmp    mouse,-1           ; is mouse installed
  900.     jz    short chkit           ; yes, so do stuff
  901.     clc                   ; clear the carry flag
  902.     ret                   ; and return
  903.      
  904. chkit:  push    bx                     ; save registers
  905.     push    dx
  906.     push    cx
  907.     push    bp
  908. mousecheck:
  909.     mov    ax,3                    ; function for mouse status
  910.     int    33h                     ; call mouse driver
  911.     and    bx,7                    ; we only care about these bits
  912.     mov    mousekey,bl        ; save the results
  913.     cmp    bx,0                ; any buttons pressed?
  914.     jz    short notpressed        ; no so check for mouse movement
  915.     cmp    bx,1            ; left-hand button (only) down?
  916.     je    short mouseleft        ;  yup.  deal with it.
  917.     cmp    bx,2            ; right-hand button (only) down?
  918.     je    short mouseright    ;  yup.  deal with it.
  919.  
  920. mousemiddle:                ; multiple or middle button down
  921.     mov    mousekey,4        ; force it to be middle-button down
  922.     mov    ax,13            ; pretend the ENTER key was hit
  923.     jmp    short pressed        ; and return.
  924.     
  925. mouseleft:
  926.     mov    ax,0bh                ; distance moved function
  927.     int    33h                ; see how far the mouse has moved
  928.     mov    ax, 1073        ; indicate page up
  929.     add    mousemickeys,dx        ; compute a running movement sum
  930.     cmp    mousemickeys,-10    ; which way'd we go?
  931.     jle    short pressed        ;  Up.  Proceed.
  932.     mov    ax, 1081        ; indicate page down
  933.     cmp    mousemickeys,10        ; which way'd we go?
  934.     jge    short pressed        ;  Up.  Proceed.
  935.     jmp    mousecheck        ; else check again.
  936.     
  937. pressed:
  938.     mov    mousemickeys,0        ; clear out the mickey counter
  939.     stc                ; indicate something happened
  940.     jmp    short exitpress     ; and exit
  941.      
  942. ; The purpose of this bit of code is to eliminate the effect of small mouse
  943. ; movements.  What I mean is that, the direction to move is the direction that
  944. ; the mouse has moved the most
  945.  
  946. mouseright:
  947.  
  948. notpressed:                   ; no button pressed, but maybe the 
  949.                        ; mouse was moved so check that out
  950.     mov    ax,0bh               ; distance moved function
  951.     int    33h               ; see how far the mouse has moved
  952.     mov    ax,dx               ; now see who moved farther
  953.     mov    bx,cx               ; move to ax,bx so we can play
  954.     cmp    ax,0               ; find the abs(ax)
  955.     jge    short chk_bx           ; already postive
  956.     not    ax               ; ax is negative, so negate
  957. chk_bx: cmp    bx,0               ; find  the abs(bx)
  958.     jge    short chk_grt           ; already postive
  959.     not    bx               ; bx is negative, so negate
  960. chk_grt:
  961.     cmp    ax,bx               ; see which one is greater
  962.     jl    short nocol           ; bx is greater so check the rows
  963.     
  964.     cmp    dx,0               ; did the col change
  965.     jz    short nthng           ; no then nothing changed (ie cx=dx=0)
  966.     jg    short ardown           ; mouse moved down
  967.     mov    ax,1072               ; indicate an up arrow
  968.     cmp    mousekey,0           ; were any mouse keys hit?
  969.     jne    pressed               ;  yup.  proceed.
  970.     mov    ax,1141               ; indicate a control-arrow
  971.     jmp    short pressed
  972. ardown:
  973.     mov    ax,1080               ; indicate a down arrow
  974.     cmp    mousekey,0           ; were any mouse keys hit?
  975.     jne    pressed               ;  yup.  proceed.
  976.     mov    ax,1145               ; indicate a control-arrow
  977.     jmp    short pressed
  978. nocol:    cmp    cx,0               ; did the row change up or down
  979.     jg    short arright           ; mouse moved to the right
  980.     mov    ax,1075               ; indicate a left arrow
  981.     cmp    mousekey,0           ; were any mouse keys hit?
  982.     jne    pressed               ;  yup.  proceed.
  983.     mov    ax,1115               ; indicate a control-arrow
  984.     jmp    short pressed
  985. arright:
  986.     mov    ax,1077               ;indeicate a right arrow
  987.     cmp    mousekey,0           ; were any mouse keys hit?
  988.     jne    pressed               ;  yup.  proceed.
  989.     mov    ax,1116               ; indicate a control-arrow
  990.     jmp    short pressed
  991. nthng:  clc                            ; indicate that nothing changed
  992. exitpress:
  993.     pop    bp               ; restore registers
  994.     pop    cx
  995.     pop    dx
  996.     pop    bx               ; restore value 
  997.     ret                   ; return to caller
  998. chkmse    endp
  999.  
  1000.  
  1001. ; Check if a button was hit on the mouse
  1002. msemvd    proc  near
  1003.     cmp    mouse,-1           ; is mouse installed
  1004.     jz    short mchkit           ; yes, so do stuff
  1005.     clc                   ; clear the carry flag
  1006.     ret                   ; and return
  1007.  
  1008. mchkit:    push    bx                     ; save registers
  1009.     push    dx
  1010.     push    cx
  1011.     push    ax
  1012. mousecheck2:
  1013.     mov    ax,3                   ; function to check mouse status
  1014.     int    33h                    ; call mouse driver
  1015.     and    bx,7                   ; we only care about these bits
  1016.     cmp    mousekey,4           ; ugly klooge for dual-key presses:
  1017.     jne    short mouseklooge       ; wait until they ALL clear out
  1018.     cmp    bx,0               ; any keys still down?
  1019.     jne    mousecheck2           ;  yup.  try again.
  1020.     mov    mousekey,0           ; else clear out the klooge flag
  1021. mouseklooge:
  1022.     cmp    bx,0               ; any buttons pressed?
  1023.     jnz    short mpress           ; yes so exit with a yes
  1024.     clc                   ; indicate that nothing changed
  1025.     jmp    short mexit           ; and exit
  1026. mpress:    stc                   ; indicate a change
  1027. mexit:    pop    ax
  1028.     pop    cx
  1029.     pop    dx
  1030.     pop    bx               ; restore value 
  1031.     ret                   ; return to caller
  1032. msemvd    endp
  1033.  
  1034. ;===============================================================
  1035. ;
  1036. ; CPUTYPE.ASM : C-callable functions cputype() and ndptype() adapted
  1037. ; by Lee Daniel Crocker from code appearing in the late PC Tech Journal,
  1038. ; August 1987 and November 1987.  PC Tech Journal was a Ziff-Davis
  1039. ; Publication.    Code herein is copyrighted and used with permission.
  1040. ;
  1041. ; The function cputype() returns an integer value based on what kind
  1042. ; of CPU it found, as follows:
  1043. ;
  1044. ;    Value    CPU Type
  1045. ;    =====    ========
  1046. ;    86    8086, 8088, V20, or V30
  1047. ;    186    80186 or 80188
  1048. ;    286    80286
  1049. ;    386    80386 or 80386sx
  1050. ;    -286    80286 in protected mode
  1051. ;    -386    80386 or 80386sx in protected or 32-bit address mode
  1052. ;
  1053. ; The function ndptype() returns an integer based on the type of NDP
  1054. ; it found, as follows:
  1055. ;
  1056. ;    Value    NDP Type
  1057. ;    =====    ========
  1058. ;    0    No NDP found
  1059. ;    87    8087
  1060. ;    287    80287
  1061. ;    387    80387
  1062. ;
  1063. ; No provisions are made for the 80486 CPU/FPU or Weitek FPA chips.
  1064. ;
  1065. ; Neither function takes any arguments or affects any external storage,
  1066. ; so there should be no memory-model dependencies.
  1067.  
  1068. .model medium, c
  1069. .286P
  1070. .code
  1071.  
  1072. cputype proc
  1073.     push    bp
  1074.  
  1075.     push    sp            ; 86/186 will push SP-2;
  1076.     pop    ax            ; 286/386 will push SP.
  1077.     cmp    ax, sp
  1078.     jz    not86            ; If equal, SP was pushed
  1079.     mov    ax, 186
  1080.     mov    cl, 32            ;   186 uses count mod 32 = 0;
  1081.     shl    ax, cl            ;   86 shifts 32 so ax = 0
  1082.     jnz    exit            ; Non-zero: no shift, so 186
  1083.     mov    ax, 86            ; Zero: shifted out all bits
  1084.     jmp    short exit
  1085. not86:
  1086.     pushf                ; Test 16 or 32 operand size:
  1087.     mov    ax, sp            ;   Pushed 2 or 4 bytes of flags?
  1088.     popf
  1089.     inc    ax
  1090.     inc    ax
  1091.     cmp    ax, sp            ;   Did pushf change SP by 2?
  1092.     jnz    is32bit         ;   If not, then 4 bytes of flags
  1093. is16bit:
  1094.     sub    sp, 6            ; Is it 286 or 386 in 16-bit mode?
  1095.     mov    bp, sp            ; Allocate stack space for GDT pointer
  1096.     sgdt    fword ptr [bp]
  1097.     add    sp, 4            ; Discard 2 words of GDT pointer
  1098.     pop    ax            ; Get third word
  1099.     inc    ah            ; 286 stores -1, 386 stores 0 or 1
  1100.     jnz    is386
  1101. is286:
  1102.     mov    ax, 286
  1103.     jmp    short testprot        ; Check for protected mode
  1104. is32bit:
  1105.     db    66h            ; 16-bit override in 32-bit mode
  1106. is386:
  1107.     mov    ax, 386
  1108. testprot:
  1109.     smsw    cx            ; Protected?  Machine status -> CX
  1110.     ror    cx,1            ; Protection bit -> carry flag
  1111.     jnc    exit            ; Real mode if no carry
  1112.     neg    ax            ; Protected:  return neg value
  1113. exit:
  1114.     pop    bp
  1115.     ret
  1116. cputype endp
  1117.  
  1118. .data
  1119.  
  1120. control dw    0            ; Temp storage for 8087 control
  1121.                     ;   and status registers
  1122. .code
  1123.  
  1124. fputype proc
  1125.     push    bp
  1126.  
  1127.     fninit                ; Defaults to 64-bit mantissa
  1128.     mov    byte ptr control+1, 0
  1129.     fnstcw    control         ; Store control word over 0
  1130. ;    dw    3ed9h            ; (klooge to avoid the MASM \e switch)
  1131. ;    dw    offset control        ; ((equates to the above 'fnstcw' cmd))
  1132.     mov    ah, byte ptr control+1    ; Test contents of byte written
  1133.     cmp    ah, 03h         ; Test for 64-bit precision flags
  1134.     je    gotone            ; Got one!  Now let's find which
  1135.     xor    ax, ax
  1136.     jmp    short fexit        ; No NDP found
  1137. gotone:
  1138.     and    control, not 0080h    ; IEM = 0 (interrupts on)
  1139.     fldcw    control
  1140.     fdisi                ; Disable ints; 287/387 will ignore
  1141.     fstcw    control
  1142.     test    control, 0080h
  1143.     jz    not87            ; Got 287/387; keep testing
  1144.     mov    ax, 87
  1145.     jmp    short fexit
  1146. not87:
  1147.     finit
  1148.     fld1
  1149.     fldz
  1150.     fdiv                ; Divide 1/0 to create infinity
  1151.     fld    st
  1152.     fchs                ; Push -infinity on stack
  1153.     fcompp                ; Compare +-infinity
  1154.     fstsw    control
  1155.     mov    ax, control
  1156.     sahf
  1157.     jnz    got387            ; 387 will compare correctly
  1158.     mov    ax, 287
  1159.     jmp    short fexit
  1160. got387:                 ; Only one left (until 487/Weitek
  1161.     mov    ax, 387         ;   test is added)
  1162. fexit:
  1163.     pop    bp
  1164.     ret
  1165. fputype endp
  1166.  
  1167. ; ************************* Far Segment RAM Support **************************
  1168. ;
  1169. ;
  1170. ;    farptr = (char far *)farmemalloc(long bytestoalloc);
  1171. ;    (void)farmemfree(farptr);
  1172. ;
  1173. ;    alternatives to Microsoft/TurboC routines
  1174. ;
  1175. ;
  1176. .8086
  1177.  
  1178. farmemalloc    proc    uses es, bytestoallocate:dword
  1179.     les    bx,bytestoallocate    ; get the # of bytes into DX:BX
  1180.     mov    dx,es            ;  ...
  1181.     add    bx,15            ; round up to next paragraph boundary
  1182.     adc    dx,0            ;  ...
  1183.     shr    dx,1            ; convert to paragraphs
  1184.     rcr    bx,1            ;  ...
  1185.     shr    dx,1            ;  ...
  1186.     rcr    bx,1            ;  ...
  1187.     shr    dx,1            ;  ...
  1188.     rcr    bx,1            ;  ...
  1189.     shr    dx,1            ;  ...
  1190.     rcr    bx,1            ;  ...
  1191.     cmp    dx,0            ; ensure that we don't want > 1MB
  1192.     jne    farmemallocfailed    ;  bail out if we do
  1193.     mov    ah,48h            ; invoke DOS to allocate memory
  1194.     int    21h            ;  ... 
  1195.     jc    farmemallocfailed    ; bail out on failure
  1196.     mov    dx,ax            ; set up DX:AX as far address
  1197.     mov    ax,0            ;  ...
  1198.     jmp    short farmemallocreturn    ; and return
  1199. farmemallocfailed:
  1200.     mov    ax,0            ; (load up with a failed response)
  1201.     mov    dx,0            ;  ...
  1202. farmemallocreturn:
  1203.     ret                ; we done.
  1204. farmemalloc    endp
  1205.  
  1206. farmemfree    proc    uses es, farptr:dword
  1207.     les    ax,farptr        ; get the segment into ES
  1208.     mov    ah,49h            ; invoke DOS to free the segment
  1209.     int    21h            ;  ...
  1210.     ret
  1211. farmemfree    endp
  1212.  
  1213. erasesegment    proc    uses es di si, segaddress:word, segvalue:word
  1214.     mov    ax,segaddress        ; load up the segment address
  1215.     mov    es,ax            ;  ...
  1216.     mov    di,0            ; start at the beginning
  1217.     mov    ax,segvalue        ; use this value
  1218.     mov    cx,8000h        ; over the entire segment
  1219.     repnz    stosw            ; do it
  1220.     ret                ; we done
  1221. erasesegment    endp
  1222.  
  1223. disable    proc                ; disable interrupts
  1224.     cli
  1225.     ret
  1226. disable    endp
  1227.  
  1228. enable    proc                ; re-enable interrupts
  1229.     sti
  1230.     ret
  1231. enable    endp
  1232.  
  1233. ; *************** Expanded Memory Manager Support Routines ******************
  1234. ;        for use with LIM 3.2 or 4.0 Expanded Memory
  1235. ;
  1236. ;    farptr = emmquery()    ; Query presence of EMM and initialize EMM code
  1237. ;                ; returns EMM FAR Address, or 0 if no EMM
  1238. ;    freepages = emmgetfree(); Returns the number of pages (1 page = 16K)
  1239. ;                ; not already allocated for something else
  1240. ;    handle = emmallocate(pages)    ; allocate EMM pages (1 page = 16K)
  1241. ;                ; returns handle # if OK, or else 0
  1242. ;    emmdeallocate(handle)    ; return EMM pages to system - MUST BE CALLED
  1243. ;                ; or allocated EMM memory fills up
  1244. ;    emmgetpage(page, handle); get an EMM page (actually, links the EMM
  1245. ;                ; page to the EMM Segment ADDR, saving any
  1246. ;                ; prior page in the process)
  1247. ;    emmclearpage(page, handle) ; performs an 'emmgetpage()' and then clears
  1248. ;                ; it out (quickly) to zeroes with a 'REP STOSW'
  1249.  
  1250. .MODEL    medium,c
  1251.  
  1252. .8086
  1253.  
  1254. .DATA
  1255.  
  1256. emm_name    db    'EMMXXXX0',0    ; device driver for EMM
  1257. emm_segment    dw    0        ; EMM page frame segment
  1258. emm_zeroflag    db    0        ; klooge flag for handle==0
  1259.  
  1260. .CODE
  1261.  
  1262. emmquery    proc
  1263.     mov    ah,3dh            ; function 3dh = open file
  1264.     mov    al,0            ;  read only
  1265.     mov    dx,offset emm_name    ; DS:DX = address of name of EMM
  1266.     int    21h            ; open it
  1267.     jc    emmqueryfailed        ;  oops.  no EMM.
  1268.  
  1269.     mov    bx,ax            ; BX = handle for EMM
  1270.     mov    ah,44h            ; function 44h = IOCTL
  1271.     mov    al,7            ; get outo. status
  1272.     mov    cx,0            ; CX = # of bytes to read
  1273.     int    21h            ; do it.
  1274.     push    ax            ; save the IOCTL handle.
  1275.  
  1276.     mov    ah,3eh            ; function 3H = close
  1277.     int    21h            ; BX still cintains handle
  1278.     pop    ax            ; restore AX for the status query
  1279.     jc    emmqueryfailed        ; huh?  close FAILED?
  1280.  
  1281.     or    al,al            ; was the status 0?
  1282.     jz    emmqueryfailed        ; well then, it wasn't EMM!
  1283.  
  1284.     mov    ah,40h            ; query EMM: hardware ok?
  1285.     int    67h            ; EMM call
  1286.     cmp    ah,0            ; is it ok?
  1287.     jne    emmqueryfailed        ; if not, fail
  1288.  
  1289.     mov    ah,41h            ; query EMM: Get Page Frame Segment
  1290.     int    67h            ; EMM call
  1291.     cmp    ah,0            ; is it ok?
  1292.     jne    emmqueryfailed        ; if not, fail
  1293.     mov    emm_segment,bx        ; save page frame segment
  1294.     mov    dx,bx            ; return page frame address
  1295.     mov    ax,0            ;  ...
  1296.     jmp    short    emmqueryreturn    ; we done.
  1297.  
  1298. emmqueryfailed:
  1299.     mov    ax,0            ; return 0 (no EMM found)
  1300.     mov    dx,0            ;  ...
  1301. emmqueryreturn:
  1302.     ret                ; we done.
  1303. emmquery    endp
  1304.  
  1305. emmgetfree    proc            ; get # of free EMM pages
  1306.     mov    ah,42h            ; EMM call: get total and free pages
  1307.     int    67h            ; EMM call
  1308.     cmp    ah,0            ; did we suceed?
  1309.     jne    emmgetfreefailed    ;  nope.  return 0 free pages
  1310.     mov    ax,bx            ; else return # of free pages
  1311.     jmp    emmgetfreereturn    ; we done.
  1312. emmgetfreefailed:
  1313.     mov    ax,0            ; failure mode
  1314. emmgetfreereturn:
  1315.     ret                ; we done
  1316. emmgetfree    endp
  1317.  
  1318. emmallocate    proc    pages:word    ; allocate EMM pages
  1319.     mov    bx,pages        ; BX = # of 16K pages
  1320.     mov    ah,43h            ; ask for the memory
  1321.     int    67h            ; EMM call
  1322.     mov    emm_zeroflag,0        ; clear the klooge flag
  1323.     cmp    ah,0            ; did the call work?
  1324.     jne    emmallocatebad        ;  nope.
  1325.     mov    ax,dx            ; yup.  save the handle here
  1326.     cmp    ax,0            ; was the handle a zero?
  1327.     jne    emmallocatereturn    ;  yup.  no kloogy fixes
  1328.     mov    emm_zeroflag,1        ; oops.  set an internal flag
  1329.     mov    ax,1234            ; and make up a dummy handle.
  1330.     jmp    short    emmallocatereturn ; and return
  1331. emmallocatebad:
  1332.     mov    ax,0            ; indicate no handle
  1333. emmallocatereturn:
  1334.     ret                ; we done.
  1335. emmallocate    endp
  1336.  
  1337. emmdeallocate    proc    emm_handle:word    ; De-allocate EMM memory
  1338. emmdeallocatestart:
  1339.     mov    dx,emm_handle        ; get the EMM handle
  1340.     cmp    dx,1234            ; was it our special klooge value?
  1341.     jne    emmdeallocatecontinue    ;  nope.  proceed.
  1342.     cmp    emm_zeroflag,1        ; was it really a zero handle?
  1343.     jne    emmdeallocatecontinue    ;  nope.  proceed.
  1344.     mov    dx,0            ; yup.  use zero instead.
  1345. emmdeallocatecontinue:
  1346.     mov    ah,45h            ; EMM function: deallocate
  1347.     int    67h            ; EMM call
  1348.     cmp    ah,0            ; did it work?
  1349.     jne    emmdeallocatestart    ; well then, try it again!
  1350. emmdeallocatereturn:
  1351.     ret                ; we done
  1352. emmdeallocate    endp
  1353.  
  1354. emmgetpage    proc    pagenum:word, emm_handle:word    ; get EMM page
  1355.     mov    bx,pagenum        ; BX = page numper
  1356.     mov    dx,emm_handle        ; DX = EMM handle
  1357.     cmp    dx,1234            ; was it our special klooge value?
  1358.     jne    emmgetpagecontinue    ;  nope.  proceed.
  1359.     cmp    emm_zeroflag,1        ; was it really a zero handle?
  1360.     jne    emmgetpagecontinue    ;  nope.  proceed.
  1361.     mov    dx,0            ; yup.  use zero instead.
  1362. emmgetpagecontinue:
  1363.     mov    ah,44h            ; EMM call: get page
  1364.     mov    al,0            ; get it into page 0
  1365.     int    67h            ; EMM call
  1366.     ret                ; we done
  1367. emmgetpage    endp
  1368.  
  1369. emmclearpage    proc    pagenum:word, emm_handle:word    ; clear EMM page
  1370.     mov    bx,pagenum        ; BX = page numper
  1371.     mov    dx,emm_handle        ; DX = EMM handle
  1372.     cmp    dx,1234            ; was it our special klooge value?
  1373.     jne    emmclearpagecontinue    ;  nope.  proceed.
  1374.     cmp    emm_zeroflag,1        ; was it really a zero handle?
  1375.     jne    emmclearpagecontinue    ;  nope.  proceed.
  1376.     mov    dx,0            ; yup.  use zero instead.
  1377. emmclearpagecontinue:
  1378.     mov    ah,44h            ; EMM call: get page
  1379.     mov    al,0            ; get it into page 0
  1380.     int    67h            ; EMM call
  1381.     mov    ax,emm_segment        ; get EMM segment into ES
  1382.     push    es            ;  ...
  1383.     mov    es,ax            ;  ...
  1384.     mov    di,0            ; start at offset 0
  1385.     mov    cx,8192            ; for 16K (in words)
  1386.     mov    ax,0            ; clear out EMM segment to zeroes
  1387.     rep    stosw            ; clear the page
  1388.     pop    es            ; restore ES
  1389.     ret                ; we done
  1390. emmclearpage    endp
  1391.  
  1392.     end
  1393.  
  1394.