home *** CD-ROM | disk | FTP | other *** search
/ Fractal Creations (Second Edition) / FRACTALS_2E.iso / frasrc.exe / GENERAL.ASM < prev    next >
Assembly Source File  |  1992-12-05  |  64KB  |  2,277 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. ;    snd()
  40. ;    nosnd()
  41. ;
  42. ; ---- Expanded Memory Support
  43. ;
  44. ;    emmquery()
  45. ;    emmgetfree()
  46. ;    emmallocate()
  47. ;    emmdeallocate()
  48. ;    emmgetpage()
  49. ;    emmclearpage()
  50. ;
  51. ; ---- Extended Memory Support
  52. ;
  53. ;    xmmquery()
  54. ;    xmmlongest()
  55. ;    xmmallocate()
  56. ;    xmmreallocate()
  57. ;    xmmdeallocate()
  58. ;    xmmmoveextended()
  59. ;
  60. ; ---- CPU, FPU Detectors
  61. ;
  62. ;    cputype()
  63. ;    fputype()
  64. ;
  65. ; ---- IIT FPU Support
  66. ;
  67. ;    load_mat()
  68. ;    mult_vec_iit()
  69. ;    IITCoPro()
  70. ;
  71.  
  72.  
  73. ;             required for compatibility if Turbo ASM
  74. IFDEF ??version
  75.     MASM51
  76.     QUIRKS
  77. ENDIF
  78.  
  79.     .MODEL    medium,c
  80.  
  81.     .8086
  82.  
  83.     ; these must NOT be in any segment!!
  84.     ; this get's rid of TURBO-C fixup errors
  85.  
  86.     extrn    help:far        ; help code (in help.c)
  87.     extrn    tab_display:far     ; TAB display (in fractint.c)
  88.     extrn    restore_active_ovly:far
  89.     extrn    edit_text_colors:far
  90.     extrn    adapter_init:far    ; video adapter init (in video.asm)
  91.     extrn    slideshw:far
  92.     extrn    recordshw:far
  93.     extrn    stopslideshow:far
  94.  
  95. .DATA
  96.  
  97. ; ************************ External variables *****************************
  98.  
  99.     extrn    soundflag:word        ; if 0, supress sounds
  100.     extrn    debugflag:word        ; for debugging purposes only
  101.     extrn    helpmode:word        ; help mode (AUTHORS is special)
  102.     extrn    tabmode:word        ; tab key enabled?
  103.     extrn    sxdots:word        ; horizontal pixels
  104.     extrn    timedsave:word        ; triggers autosave
  105.     extrn    calc_status:word    ; in calcfrac.c
  106.     extrn    got_status:word     ; in calcfrac.c
  107.     extrn    currow:word        ; in calcfrac.c
  108.     extrn    slides:word        ; in cmdfiles.c
  109.  
  110.  
  111. ; ************************ Public variables *****************************
  112.  
  113. public        cpu            ; used by 'calcmand'
  114. public        fpu            ; will be used by somebody someday
  115. public        iit            ; IIT fpu?
  116. public        lookatmouse        ; used by 'calcfrac'
  117. public        saveticks        ; set by fractint
  118. public        savebase        ; set by fractint
  119. public        finishrow        ; set by fractint
  120. public        _dataseg_xx        ; used by TARGA, other Turbo Code
  121.  
  122. public        extraseg        ; extra 64K segment
  123.  
  124. public        overflow        ; Mul, Div overflow flag: 0 means none
  125.  
  126. ;        arrays declared here, used elsewhere
  127. ;        arrays not used simultaneously are deliberately overlapped
  128.  
  129. public        keybuffer            ; needed for ungetakey
  130. public        prefix, suffix, dstack, decoderline ; for the Decoder
  131. public        tstack                ; for the prompting routines
  132. public        strlocn, teststring, block    ; used by the Encoder
  133. public        boxx, boxy, boxvalues        ; zoom-box arrays
  134. public        olddacbox            ; temporary DAC saves
  135. public        rlebuf                ; Used ty the TARGA En/Decoder
  136. public        paldata, stbuff         ; 8514A arrays, (FR8514A.ASM)
  137.  
  138. ; ************************* "Shared" array areas **************************
  139.  
  140. ; Shared near arrays are discussed below. First some comments about "extraseg".
  141. ; It is a 96k far area permanently allocated during fractint runup.
  142. ; The first part is used for:
  143. ;   64k coordinate arrays during image calculation (initialized in fracsubr.c)
  144. ;   64k create gif save file, encoder.c
  145. ;   64k 3d transforms, line3d.c
  146. ;   64k credits screen, intro.c
  147. ;   22k video mode selection (for fractint.cfg, loadfdos, miscovl)
  148. ;    2k .frm .ifs .l .par entry selection (prompts.c)
  149. ;   ??k printing, printer.c
  150. ;   ??k fractint.doc creation, help.c, not important cause it saves/restores
  151. ; The high 32k is used for graphics image save during text mode; video.asm
  152. ; and realdos.c.
  153.  
  154. ; Short forms used in subsequent comments:
  155. ;   name........duration of use......................modules....................
  156. ;   encoder    "s"aving an image                    encoder.c
  157. ;   decoder    "r"estoring an image                 decoder.c, gifview.c
  158. ;   zoom    zoom box is visible             zoom.c, video.asm
  159. ;   vidswitch    temp during video mode setting         video.asm
  160. ;   8514a    8514a is in use (graphics only?)     fr8514a.asm
  161. ;   tgaview    restore of tga image             tgaview.c
  162. ;   solidguess    image gen with "g", not to disk      calcfrac.c
  163. ;   btm     image gen with "b", not to disk      calcfrac.c
  164. ;   editpal    palette editor "heap"                editpal.c
  165. ; Note that decoder using an 8514a is worst case, uses all arrays at once.
  166. ; Keep db lengths even so that word alignment is preserved for speed.
  167.  
  168. block        label    byte        ; encoder(266)
  169. suffix        dw    2048 dup(0)    ; decoder(4k), vidswitch(256),
  170.                     ; savegraphics/restoregraphics(4k)
  171.  
  172. tstack        label    byte        ; prompts(4k), ifsload(4k),
  173.                     ; make_batch(4k)
  174. teststring    label    byte        ; encoder(100)
  175. olddacbox    label    byte        ; fractint(768), prompts(768)
  176. dstack        dw    2048 dup(0)    ; decoder(4k), solidguess(4k), btm(2k)
  177.                     ;   zoom(2k), printer(2400)
  178.                     ;   loadfdos(2000)
  179.  
  180. strlocn     label    word        ; encoder(10k), editpal(10k)
  181. prefix        label    word        ; decoder(8k), solidguess(6k)
  182. boxx        dw    2048 dup(0)    ; zoom(4k), tgaview(4k), prompts(9k)
  183.                     ;   make_batch(8k), parser(8k)
  184. boxy        dw    2048 dup(0)    ; zoom(4k)
  185. boxvalues    label    byte        ; zoom(2k)
  186. decoderline    db    2050 dup(0)    ; decoder(2049), btm(2k)
  187.  
  188. rlebuf        label    byte        ; f16.c(258) .tga save/restore?
  189. paldata     db    1024 dup(0)    ; 8514a(1k)
  190. stbuff        db    415 dup(0)    ; 8514a(415)
  191.  
  192. ; ************************ Internal variables *****************************
  193.  
  194.         align    2
  195. cpu        dw    0        ; cpu type: 86, 186, 286, or 386
  196. fpu        dw    0        ; fpu type: 0, 87, 287, 387
  197. iit        dw    0        ; iit fpu:  0=no, 1=yes
  198. _dataseg_xx    dw    0        ; our "near" data segment
  199.  
  200. overflow    dw    0        ; overflow flag
  201.  
  202. kbd_type    db    0        ; type of keyboard
  203.         align    2
  204. keybuffer    dw    0        ; real small keyboard buffer
  205.  
  206. delayloop    dw    32        ; delay loop value
  207. delaycount    dw    0        ; number of delay "loops" per ms.
  208.  
  209. extraseg    dw    0        ; extra 64K segment (allocated by init)
  210.  
  211. ; ********************** Mouse Support Variables **************************
  212.  
  213. lookatmouse    dw    0        ; see notes at mouseread routine
  214. prevlamouse    dw    0        ; previous lookatmouse value
  215. mousetime    dw    0        ; time of last mouseread call
  216. mlbtimer    dw    0        ; time of left button 1st click
  217. mrbtimer    dw    0        ; time of right button 1st click
  218. mhtimer     dw    0        ; time of last horiz move
  219. mvtimer     dw    0        ; time of last vert  move
  220. mhmickeys    dw    0        ; pending horiz movement
  221. mvmickeys    dw    0        ; pending vert    movement
  222. mbstatus    db    0        ; status of mouse buttons
  223. mouse        db    0        ; == -1 if/when a mouse is found.
  224. mbclicks    db    0        ; had 1 click so far? &1 mlb, &2 mrb
  225.  
  226.         align    2
  227. ; timed save variables, handled by readmouse:
  228. savechktime    dw    0        ; time of last autosave check
  229. savebase    dw    2 dup(0)    ; base clock ticks
  230. saveticks    dw    2 dup(0)    ; save after this many ticks
  231. finishrow    dw    0        ; save when this row is finished
  232.  
  233.  
  234. .CODE
  235.  
  236. ; *************** Function toextra(tooffset,fromaddr, fromcount) *********
  237.  
  238. toextra proc    uses es di si, tooffset:word, fromaddr:word, fromcount:word
  239.     cld                ; move forward
  240.     mov    ax,extraseg        ; load ES == extra segment
  241.     mov    es,ax            ;  ..
  242.     mov    di,tooffset        ; load to here
  243.     mov    si,fromaddr        ; load from here
  244.     mov    cx,fromcount        ; this many bytes
  245.     rep    movsb            ; do it.
  246.     ret                ; we done.
  247. toextra endp
  248.  
  249.  
  250. ; *************** Function fromextra(fromoffset, toaddr, tocount) *********
  251.  
  252. fromextra proc    uses es di si, fromoffset:word, toaddr:word, tocount:word
  253.     push    ds            ; save DS for a tad
  254.     pop    es            ; restore it to ES
  255.     cld                ; move forward
  256.     mov    si,fromoffset        ; load from here
  257.     mov    di,toaddr        ; load to here
  258.     mov    cx,tocount        ; this many bytes
  259.     mov    ax,extraseg        ; load DS == extra segment
  260.     mov    ds,ax            ;  ..
  261.     rep    movsb            ; do it.
  262.     push    es            ; save ES again.
  263.     pop    ds            ; restore DS
  264.     ret                ; we done.
  265. fromextra endp
  266.  
  267.  
  268. ; *************** Function cmpextra(cmpoffset,cmpaddr, cmpcount) *********
  269.  
  270. cmpextra proc    uses es di si, cmpoffset:word, cmpaddr:word, cmpcount:word
  271.     cld                ; move forward
  272.     mov    ax,extraseg        ; load ES == extra segment
  273.     mov    es,ax            ;  ..
  274.     mov    di,cmpoffset        ; load to here
  275.     mov    si,cmpaddr        ; load from here
  276.     mov    cx,cmpcount        ; this many bytes
  277.     rep    cmpsb            ; do it.
  278.     jnz    cmpbad            ; failed.
  279.     sub    ax,ax            ; 0 == true
  280.     jmp    short cmpend
  281. cmpbad:
  282.     mov    ax,1            ; 1 == false
  283. cmpend:
  284.     ret                ; we done.
  285. cmpextra    endp
  286.  
  287.  
  288. ; =======================================================
  289. ;
  290. ;    32-bit integer multiply routine with an 'n'-bit shift.
  291. ;    Overflow condition returns 0x7fffh with overflow = 1;
  292. ;
  293. ;    long x, y, z, multiply();
  294. ;    int n;
  295. ;
  296. ;    z = multiply(x,y,n)
  297. ;
  298. ;    requires the presence of an external variable, 'cpu'.
  299. ;        'cpu' == 386 if a 386 is present.
  300.  
  301. .8086
  302.  
  303. .DATA
  304.  
  305. temp    dw    5 dup(0)        ; temporary 64-bit result goes here
  306. sign    db    0            ; sign flag goes here
  307.  
  308. .CODE
  309.  
  310. FRAME    MACRO regs
  311.     push    bp
  312.     mov    bp, sp
  313.     IRP    reg, <regs>
  314.       push    reg
  315.       ENDM
  316.     ENDM
  317.  
  318. UNFRAME MACRO regs
  319.     IRP    reg, <regs>
  320.       pop reg
  321.       ENDM
  322.     pop bp
  323.     ENDM
  324.  
  325.  
  326. multiply    proc    x:dword, y:dword, n:word
  327.  
  328.     cmp    cpu,386         ; go-fast time?
  329.     jne    slowmultiply        ; no.  yawn...
  330.  
  331. .386                    ; 386-specific code starts here
  332.  
  333.     mov    eax,x            ; load X into EAX
  334.     imul    y            ; do the multiply
  335.     mov    cx,n            ; set up the shift
  336.     cmp    cx,32            ; ugly klooge:    check for 32-bit shift
  337.     jb    short fastm1        ;  < 32 bits:  no problem
  338.     mov    eax,edx         ;  >= 32 bits:    manual shift
  339.     mov    edx,0            ;  ...
  340.     sub    cx,32            ;  ...
  341. fastm1: shrd    eax,edx,cl        ; shift down 'n' bits
  342.     js    fastm3
  343.     sar    edx,cl
  344.     jne    overmf
  345.     shld    edx,eax,16
  346.     ret
  347. fastm3: sar    edx,cl
  348.     inc    edx
  349.     jne    overmf
  350.     shld    edx,eax,16
  351.     ret
  352. overmf:
  353.     mov    ax,0ffffh        ; overflow value
  354.     mov    dx,07fffh        ; overflow value
  355.     mov    overflow,1        ; flag overflow
  356.     ret
  357.  
  358. .8086                    ; 386-specific code ends here
  359.  
  360. slowmultiply:                ; (sigh)  time to do it the hard way...
  361.     push    di
  362.     push    si
  363.     push    es
  364.  
  365.     mov    ax,0
  366.     mov    temp+4,ax        ; first, zero out the (temporary)
  367.     mov    temp+6,ax        ;  result
  368.     mov    temp+8,ax
  369.  
  370.     les    bx,x            ; move X to SI:BX
  371.     mov    si,es            ;  ...
  372.     les    cx,y            ; move Y to DI:CX
  373.     mov    di,es            ;  ...
  374.  
  375.     mov    sign,0            ; clear out the sign flag
  376.     cmp    si,0            ; is X negative?
  377.     jge    mults1            ;  nope
  378.     not    sign            ;  yup.  flip signs
  379.     not    bx            ;   ...
  380.     not    si            ;   ...
  381.     stc                ;   ...
  382.     adc    bx,ax            ;   ...
  383.     adc    si,ax            ;   ...
  384. mults1: cmp    di,0            ; is DI:CX negative?
  385.     jge    mults2            ;  nope
  386.     not    sign            ;  yup.  flip signs
  387.     not    cx            ;   ...
  388.     not    di            ;   ...
  389.     stc                ;   ...
  390.     adc    cx,ax            ;   ...
  391.     adc    di,ax            ;   ...
  392. mults2:
  393.  
  394.     mov    ax,bx            ; perform BX x CX
  395.     mul    cx            ;  ...
  396.     mov    temp,ax         ;  results in lowest 32 bits
  397.     mov    temp+2,dx        ;  ...
  398.  
  399.     mov    ax,bx            ; perform BX x DI
  400.     mul    di            ;  ...
  401.     add    temp+2,ax        ;  results in middle 32 bits
  402.     adc    temp+4,dx        ;  ...
  403.     jnc    mults3            ;  carry bit set?
  404.     inc    word ptr temp+6     ;  yup.  overflow
  405. mults3:
  406.  
  407.     mov    ax,si            ; perform SI * CX
  408.     mul    cx            ;  ...
  409.     add    temp+2,ax        ;  results in middle 32 bits
  410.     adc    temp+4,dx        ;  ...
  411.     jnc    mults4            ;  carry bit set?
  412.     inc    word ptr temp+6     ;  yup.  overflow
  413. mults4:
  414.  
  415.     mov    ax,si            ; perform SI * DI
  416.     mul    di            ;  ...
  417.     add    temp+4,ax        ; results in highest 32 bits
  418.     adc    temp+6,dx        ;  ...
  419.  
  420.     mov    cx,n            ; set up for the shift loop
  421.     cmp    cx,24            ; shifting by three bytes or more?
  422.     jl    multc1            ;  nope.  check for something else
  423.     sub    cx,24            ; quick-shift 24 bits
  424.     mov    ax,temp+3        ; load up the registers
  425.     mov    dx,temp+5        ;  ...
  426.     mov    si,temp+7        ;  ...
  427.     mov    bx,0            ;  ...
  428.     jmp    short multc4        ; branch to common code
  429. multc1: cmp    cx,16            ; shifting by two bytes or more?
  430.     jl    multc2            ;  nope.  check for something else
  431.     sub    cx,16            ; quick-shift 16 bits
  432.     mov    ax,temp+2        ; load up the registers
  433.     mov    dx,temp+4        ;  ...
  434.     mov    si,temp+6        ;  ...
  435.     mov    bx,0            ;  ...
  436.     jmp    short multc4        ; branch to common code
  437. multc2: cmp    cx,8            ; shifting by one byte or more?
  438.     jl    multc3            ;  nope.  check for something else
  439.     sub    cx,8            ; quick-shift 8 bits
  440.     mov    ax,temp+1        ; load up the registers
  441.     mov    dx,temp+3        ;  ...
  442.     mov    si,temp+5        ;  ...
  443.     mov    bx,temp+7        ;  ...
  444.     jmp    short multc4        ; branch to common code
  445. multc3: mov    ax,temp         ; load up the regs
  446.     mov    dx,temp+2        ;  ...
  447.     mov    si,temp+4        ;  ...
  448.     mov    bx,temp+6        ;  ...
  449. multc4: cmp    cx,0            ; done shifting?
  450.     je    multc5            ;  yup.  bail out
  451.  
  452. multloop:
  453.     shr    bx,1            ; shift down 1 bit, cascading
  454.     rcr    si,1            ;  ...
  455.     rcr    dx,1            ;  ...
  456.     rcr    ax,1            ;  ...
  457.     loop    multloop        ; try the next bit, if any
  458. multc5:
  459.     cmp    si,0            ; overflow time?
  460.     jne    overm1            ; yup.    Bail out.
  461.     cmp    bx,0            ; overflow time?
  462.     jne    overm1            ; yup.    Bail out.
  463.     cmp    dx,0            ; overflow time?
  464.     jl    overm1            ; yup.    Bail out.
  465.  
  466.     cmp    sign,0            ; should we negate the result?
  467.     je    mults5            ;  nope.
  468.     not    ax            ;  yup.  flip signs.
  469.     not    dx            ;   ...
  470.     mov    bx,0            ;   ...
  471.     stc                ;   ...
  472.     adc    ax,bx            ;   ...
  473.     adc    dx,bx            ;   ...
  474. mults5:
  475.     jmp    multiplyreturn
  476.  
  477. overm1:
  478.     mov    ax,0ffffh        ; overflow value
  479.     mov    dx,07fffh        ; overflow value
  480.     mov    overflow,1        ; flag overflow
  481.  
  482. multiplyreturn:             ; that's all, folks!
  483.     pop    es
  484.     pop    si
  485.     pop    di
  486.     ret
  487. multiply    endp
  488.  
  489.  
  490. ; =======================================================
  491. ;
  492. ;    32-bit integer divide routine with an 'n'-bit shift.
  493. ;    Overflow condition returns 0x7fffh with overflow = 1;
  494. ;
  495. ;    long x, y, z, divide();
  496. ;    int n;
  497. ;
  498. ;    z = divide(x,y,n);    /* z = x / y; */
  499. ;
  500. ;    requires the presence of an external variable, 'cpu'.
  501. ;        'cpu' == 386 if a 386 is present.
  502.  
  503.  
  504. .8086
  505.  
  506. divide        proc    uses di si es, x:dword, y:dword, n:word
  507.  
  508.     cmp    cpu,386         ; go-fast time?
  509.     jne    slowdivide        ; no.  yawn...
  510.  
  511. .386                    ; 386-specific code starts here
  512.  
  513.     mov    edx,x            ; load X into EDX (shifts to EDX:EAX)
  514.     mov    ebx,y            ; load Y into EBX
  515.  
  516.     mov    sign,0            ; clear out the sign flag
  517.     cmp    edx,0            ; is X negative?
  518.     jge    short divides1        ;  nope
  519.     not    sign            ;  yup.  flip signs
  520.     neg    edx            ;   ...
  521. divides1:
  522.     cmp    ebx,0            ; is Y negative?
  523.     jge    short divides2        ;  nope
  524.     not    sign            ;  yup.  flip signs
  525.     neg    ebx            ;   ...
  526. divides2:
  527.  
  528.     mov    eax,0            ; clear out the low-order bits
  529.     mov    cx,32            ; set up the shift
  530.     sub    cx,n            ; (for large shift counts - faster)
  531. fastd1: cmp    cx,0            ; done shifting?
  532.     je    fastd2            ; yup.
  533.     shr    edx,1            ; shift one bit
  534.     rcr    eax,1            ;  ...
  535.     loop    fastd1            ; and try again
  536. fastd2:
  537.     cmp    edx,ebx         ; umm, will the divide blow out?
  538.     jae    overd1            ;  yup.  better skip it.
  539.     div    ebx            ; do the divide
  540.     cmp    eax,0            ; did the sign flip?
  541.     jl    overd1            ;  then we overflowed
  542.     cmp    sign,0            ; is the sign reversed?
  543.     je    short divides3        ;  nope
  544.     neg    eax            ; flip the sign
  545. divides3:
  546.     push    eax            ; save the 64-bit result
  547.     pop    ax            ; low-order  16 bits
  548.     pop    dx            ; high-order 16 bits
  549.     jmp    dividereturn        ; back to common code
  550.  
  551. .8086                    ; 386-specific code ends here
  552.  
  553. slowdivide:                ; (sigh)  time to do it the hard way...
  554.  
  555.     les    ax,x            ; move X to DX:AX
  556.     mov    dx,es            ;  ...
  557.  
  558.     mov    sign,0            ; clear out the sign flag
  559.     cmp    dx,0            ; is X negative?
  560.     jge    divides4        ;  nope
  561.     not    sign            ;  yup.  flip signs
  562.     not    ax            ;   ...
  563.     not    dx            ;   ...
  564.     stc                ;   ...
  565.     adc    ax,0            ;   ...
  566.     adc    dx,0            ;   ...
  567. divides4:
  568.  
  569.     mov    cx,32            ; get ready to shift the bits
  570.     sub    cx,n            ; (shift down rather than up)
  571.     mov    byte ptr temp+4,cl    ;  ...
  572.  
  573.     mov    cx,0            ;  clear out low bits of DX:AX:CX:BX
  574.     mov    bx,0            ;  ...
  575.  
  576.     cmp    byte ptr temp+4,16    ; >= 16 bits to shift?
  577.     jl    dividex0        ;  nope
  578.     mov    bx,cx            ;  yup.  Take a short-cut
  579.     mov    cx,ax            ;   ...
  580.     mov    ax,dx            ;   ...
  581.     mov    dx,0            ;   ...
  582.     sub    byte ptr temp+4,16    ;   ...
  583. dividex0:
  584.     cmp    byte ptr temp+4,8    ; >= 8 bits to shift?
  585.     jl    dividex1        ;  nope
  586.     mov    bl,bh            ;  yup.  Take a short-cut
  587.     mov    bh,cl            ;   ...
  588.     mov    cl,ch            ;   ...
  589.     mov    ch,al            ;   ...
  590.     mov    al,ah            ;   ...
  591.     mov    ah,dl            ;   ...
  592.     mov    dl,dh            ;   ...
  593.     mov    dh,0            ;   ...
  594.     sub    byte ptr temp+4,8    ;   ...
  595. dividex1:
  596.     cmp    byte ptr temp+4,0    ; are we done yet?
  597.     je    dividex2        ;  yup
  598.     shr    dx,1            ; shift all 64 bits
  599.     rcr    ax,1            ;  ...
  600.     rcr    cx,1            ;  ...
  601.     rcr    bx,1            ;  ...
  602.     dec    byte ptr temp+4     ; decrement the shift counter
  603.     jmp    short dividex1        ;  and try again
  604. dividex2:
  605.  
  606.     les    di,y            ; move Y to SI:DI
  607.     mov    si,es            ;  ...
  608.  
  609.     cmp    si,0            ; is Y negative?
  610.     jge    divides5        ;  nope
  611.     not    sign            ;  yup.  flip signs
  612.     not    di            ;   ...
  613.     not    si            ;   ...
  614.     stc                ;   ...
  615.     adc    di,0            ;   ...
  616.     adc    si,0            ;   ...
  617. divides5:
  618.  
  619.     mov    byte ptr temp+4,33    ; main loop counter
  620.     mov    temp,0            ; results in temp
  621.     mov    word ptr temp+2,0    ;  ...
  622.  
  623. dividel1:
  624.     shl    temp,1            ; shift the result up 1
  625.     rcl    word ptr temp+2,1    ;  ...
  626.     cmp    dx,si            ; is DX:AX >= Y?
  627.     jb    dividel3        ;  nope
  628.     ja    dividel2        ;  yup
  629.     cmp    ax,di            ;  maybe
  630.     jb    dividel3        ;  nope
  631. dividel2:
  632.     cmp    byte ptr temp+4,32    ; overflow city?
  633.     jge    overd1            ;  yup.
  634.     sub    ax,di            ; subtract Y
  635.     sbb    dx,si            ;  ...
  636.     inc    temp            ; add 1 to the result
  637.     adc    word ptr temp+2,0    ;  ...
  638. dividel3:
  639.     shl    bx,1            ; shift all 64 bits
  640.     rcl    cx,1            ;  ...
  641.     rcl    ax,1            ;  ...
  642.     rcl    dx,1            ;  ...
  643.     dec    byte ptr temp+4     ; time to quit?
  644.     jnz    dividel1        ;  nope.  try again.
  645.  
  646.     mov    ax,temp         ; copy the result to DX:AX
  647.     mov    dx,word ptr temp+2    ;  ...
  648.     cmp    sign,0            ; should we negate the result?
  649.     je    divides6        ;  nope.
  650.     not    ax            ;  yup.  flip signs.
  651.     not    dx            ;   ...
  652.     mov    bx,0            ;   ...
  653.     stc                ;   ...
  654.     adc    ax,0            ;   ...
  655.     adc    dx,0            ;   ...
  656. divides6:
  657.     jmp    short dividereturn
  658.  
  659. overd1:
  660.     mov    ax,0ffffh        ; overflow value
  661.     mov    dx,07fffh        ; overflow value
  662.     mov    overflow,1        ; flag overflow
  663.  
  664. dividereturn:                ; that's all, folks!
  665.     ret
  666. divide        endp
  667.  
  668.  
  669. ; ****************** Function getakey() *****************************
  670. ; **************** Function keypressed() ****************************
  671.  
  672. ;    'getakey()' gets a key from either a "normal" or an enhanced
  673. ;    keyboard.   Returns either the vanilla ASCII code for regular
  674. ;    keys, or 1000+(the scan code) for special keys (like F1, etc)
  675. ;    Use of this routine permits the Control-Up/Down arrow keys on
  676. ;    enhanced keyboards.
  677. ;
  678. ;    The concept for this routine was "borrowed" from the MSKermit
  679. ;    SCANCHEK utility
  680. ;
  681. ;    'keypressed()' returns a zero if no keypress is outstanding,
  682. ;    and the value that 'getakey()' will return if one is.  Note
  683. ;    that you must still call 'getakey()' to flush the character.
  684. ;    As a sidebar function, calls 'help()' if appropriate, or
  685. ;    'tab_display()' if appropriate.
  686. ;    Think of 'keypressed()' as a super-'kbhit()'.
  687.  
  688. keypressed  proc
  689.     call    far ptr getkeynowait        ; check for key
  690.     jc    keypressed1            ;  got a key
  691.     sub    ax,ax                ; fast no-key return
  692.     ret
  693. keypressed1:
  694.     FRAME    <di,si,es>            ; std frame, for TC++ overlays
  695.     mov    keybuffer,ax            ; remember it for next time
  696.     cmp    ax,1059             ; help called?
  697.     jne    keypressed2            ; no help asked for.
  698.     cmp    helpmode,0            ; help enabled?
  699.     jl    keypressedx            ;  nope.
  700.     mov    keybuffer,0            ; say no key hit
  701.     xor    ax,ax
  702.     push    ax
  703.     call    far ptr help            ; help!
  704.     pop    ax
  705.     call    far ptr restore_active_ovly    ; help might've clobbered ovly
  706.     sub    ax,ax
  707.     jmp    short keypressedx
  708. keypressed2:
  709.     cmp    ax,9                ; TAB key hit?
  710.     jne    keypressedx            ;  nope.  no TAB display.
  711.     cmp    tabmode,0            ; tab enabled?
  712.     je    keypressedx            ;  nope
  713.     mov    keybuffer,0            ; say no key hit
  714.     call    far ptr tab_display        ; show the TAB status
  715.     call    far ptr restore_active_ovly    ; tab might've clobbered ovly
  716.     sub    ax,ax
  717. keypressedx:
  718.     UNFRAME <es,si,di>            ; pop frame
  719.     ret
  720. keypressed    endp
  721.  
  722. getakeynohelp proc
  723. gknhloop:
  724.     call    far ptr getakey         ; get keystroke
  725.     cmp    ax,1059             ; help key?
  726.     je    gknhloop            ;  ignore help, none available
  727.     ret
  728. getakeynohelp endp
  729.  
  730. getakey proc
  731.         cmp     soundflag,1                     ; is the sound on?
  732.         jl      getakeyloop                     ; ok, sound is off
  733.         call    far ptr nosnd                   ; turn off sound
  734. getakeyloop:
  735.     call    far ptr getkeynowait        ; check for keystroke
  736.     jnc    getakeyloop            ;  no key, loop till we get one
  737.     ret
  738. getakey endp
  739.  
  740. getkeynowait proc
  741.     FRAME    <di,si,es>            ; std frame, for TC++ overlays
  742. getkeyn0:
  743.     cmp    keybuffer,0            ; got a key buffered?
  744.     je    getkeynobuf            ;  nope
  745.     mov    ax,keybuffer            ; key was buffered here
  746.     mov    keybuffer,0            ; clear buffer
  747.     jmp    getkeyyup            ; exit with the key
  748. getkeynobuf:
  749.     call    mouseread            ; mouse activity or savetime?
  750.     jc    getkeyn4            ;  yup, ax holds the phoney key
  751.     mov    ah,kbd_type            ; get the keyboard type
  752.     or    ah,1                ; check if a key is ready
  753.     int    16h                ; now check a key
  754.     jnz    gotkeyn             ;  got one
  755.     cmp    slides,1            ; slideshow playback active?
  756.     jne    getkeynope            ;  nope, return no key
  757.     call    far ptr slideshw        ; check next playback keystroke
  758.     cmp    ax,0                ; got one?
  759.     jne    getkeyn5            ;  yup, use it
  760. getkeynope:
  761.     clc                    ; return no key
  762.     UNFRAME <es,si,di>            ; pop frame
  763.     ret
  764. gotkeyn:                    ; got a real keyboard keystroke
  765.     mov    ah,kbd_type            ; get the keyboard type
  766.     int    16h                ; now get a key
  767.     cmp    al,0e0h             ; check: Enhanced Keyboard key?
  768.     jne    short getkeyn1            ; nope.  proceed
  769.     cmp    ah,0                ; part 2 of Enhanced Key check
  770.     je    short getkeyn1            ; failed.  normal key.
  771.     mov    al,0                ; Turn enhanced key "normal"
  772.     jmp    short getkeyn2            ; jump to common code
  773. getkeyn1:
  774.     cmp    ah,0e0h             ; check again:    Enhanced Key?
  775.     jne    short getkeyn2            ;  nope.  proceed.
  776.     mov    ah,al                ; Turn Enhanced key "normal"
  777.     mov    al,0                ;  ...
  778. getkeyn2:
  779.     cmp    al,0                ; Function Key?
  780.     jne    short getkeyn3            ;  nope.  proceed.
  781.     mov    al,ah                ; klooge into ASCII Key
  782.     mov    ah,0                ; clobber the scan code
  783.     add    ax,1000             ;  + 1000
  784.     jmp    short getkeyn4            ; go to common return
  785. getkeyn3:
  786.     mov    ah,0                ; clobber the scan code
  787. getkeyn4:                    ; got real key (not playback)
  788.     cmp    ax,9999             ; savetime from mousread?
  789.     je    getkeyn6            ;  yup, do it and don't record
  790.     cmp    slides,1            ; slideshow playback active?
  791.     jne    getkeyn5            ;  nope
  792.     cmp    ax,1bh                ; escape?
  793.     jne    getkeyn0            ;  nope, ignore the key
  794.     call    far ptr stopslideshow        ; terminate playback
  795.     jmp    short getkeyn0            ; go check for another key
  796. getkeyn5:
  797.     cmp    slides,2            ; slideshow record mode?
  798.     jne    getkeyn6            ;  nope
  799.     push    ax
  800.     call    far ptr recordshw        ; record the key
  801.     pop    ax
  802. getkeyn6:
  803.     cmp    debugflag,3000            ; color play enabled?
  804.     jne    getkeyyup            ;  nope
  805.     cmp    ax,'~'                          ; color play requested?
  806.     jne    getkeyyup            ;  nope
  807.     call    far ptr edit_text_colors    ; play
  808.     call    far ptr restore_active_ovly    ; might've clobbered ovly
  809.     jmp    getkeyn0            ; done playing, back around
  810. getkeyyup:
  811.     stc                    ; indicate we have a key
  812.     UNFRAME <es,si,di>            ; pop frame
  813.     ret
  814. getkeynowait endp
  815.  
  816. ; ****************** Function buzzer(int buzzertype) *******************
  817. ;
  818. ;    Sound a tone based on the value of the parameter
  819. ;
  820. ;    0 = normal completion of task
  821. ;    1 = interrupted task
  822. ;    2 = error contition
  823.  
  824. ;    "buzzer()" codes:  strings of two-word pairs
  825. ;        (frequency in cycles/sec, delay in milliseconds)
  826. ;        frequency == 0 means no sound
  827. ;        delay      == 0 means end-of-tune
  828. buzzer0     dw    1047,100    ; "normal" completion
  829.         dw    1109,100
  830.         dw    1175,100
  831.         dw    0,0
  832. buzzer1     dw    2093,100    ; "interrupted" completion
  833.         dw    1976,100
  834.         dw    1857,100
  835.         dw    0,0
  836. buzzer2     dw    40,500        ; "error" condition (razzberry)
  837.         dw    0,0
  838.  
  839. ; ***********************************************************************
  840.  
  841. buzzer    proc    uses si, buzzertype:word
  842.     cmp    soundflag,0        ; is the sound supressed?
  843.     je    buzzerreturn        ;  yup.  bail out.
  844.     mov    si, offset buzzer0    ; normal completion frequency
  845.     cmp    buzzertype,0        ; normal completion?
  846.     je    buzzerdoit        ; do it
  847.     mov    si,offset buzzer1    ; interrupted task frequency
  848.     cmp    buzzertype,1        ; interrupted task?
  849.     je    buzzerdoit        ; do it
  850.     mov    si,offset buzzer2    ; error condition frequency
  851. buzzerdoit:
  852.     mov    ax,cs:0[si]        ; get the (next) frequency
  853.     mov    bx,cs:2[si]        ; get the (next) delay
  854.     add    si,4            ; get ready for the next tone
  855.     cmp    bx,0            ; are we done?
  856.     je    buzzerreturn        ;  yup.
  857.     push    bx            ; put delay time on the stack
  858.     push    ax            ; put tone value on the stack
  859.     call    far ptr tone        ; do it
  860.     pop    ax            ; restore stack
  861.     pop    bx            ; restore stack
  862.     jmp    short buzzerdoit    ; get the next tone
  863. buzzerreturn:
  864.     ret                ; we done
  865. buzzer    endp
  866.  
  867. ; ***************** Function delay(int delaytime) ************************
  868. ;
  869. ;    performs a delay loop for 'delaytime' milliseconds
  870. ;
  871. ; ************************************************************************
  872.  
  873. delayamillisecond    proc    near    ; internal delay-a-millisecond code
  874.     mov    bx,delaycount        ; set up to burn another millisecond
  875. delayamill1:
  876.     mov    cx,delayloop        ; start up the counter
  877. delayamill2:                ;
  878.     loop    delayamill2        ; burn up some time
  879.     dec    bx            ; have we burned up a millisecond?
  880.     jnz    delayamill1        ;  nope.  try again.
  881.     ret                ; we done
  882. delayamillisecond    endp
  883.  
  884. delay    proc    uses es, delaytime:word ; delay loop (arg in milliseconds)
  885.     mov    ax,delaytime        ; get the number of milliseconds
  886.     cmp    ax,0            ; any delay time at all?
  887.     je    delayreturn        ;  nope.
  888. delayloop1:
  889.     call    delayamillisecond    ; burn up a millisecond of time
  890.     dec    ax            ; have we burned up enough m-seconds?
  891.     jnz    delayloop1        ;  nope.  try again.
  892. delayreturn:
  893.     ret                ; we done.
  894. delay    endp
  895.  
  896. ; ************** Function tone(int frequency,int delaytime) **************
  897. ;
  898. ;    buzzes the speaker with this frequency for this amount of time
  899. ;
  900. ; ************************************************************************
  901.  
  902. tone    proc    uses es, tonefrequency:word, tonedelay:word
  903.     mov    al,0b6h         ; latch to channel 2
  904.     out    43h,al            ;  ...
  905.     cmp    tonefrequency,12h    ; was there a frequency?
  906.     jbe    tonebypass        ;  nope.  delay only
  907.     mov    bx,tonefrequency    ; get the frequency value
  908.     mov    ax,0            ; ugly klooge: convert this to the
  909.     mov    dx,12h            ; divisor the 8253 wants to see
  910.     div    bx            ;  ...
  911.     out    42h,al            ; send the low value
  912.     mov    al,ah            ; then the high value
  913.     out    42h,al            ;  ...
  914.     in    al,61h            ; get the current 8255 bits
  915.     or    al,3            ; turn bits 0 and 1 on
  916.     out    61h,al            ;  ...
  917. tonebypass:
  918.     mov    ax,tonedelay        ; get the delay value
  919.     push    ax            ; set the parameter
  920.     call    far ptr delay        ; and force a delay
  921.     pop    ax            ; restore the parameter
  922.  
  923.     in    al,61h            ; get the current 8255 bits
  924.     and    al,11111100b        ; turn bits 0 and 1 off
  925.     out    61h,al
  926.  
  927.     ret                ; we done
  928. tone    endp
  929.  
  930. ; ************** Function snd(int hertz) and nosnd() **************
  931. ;
  932. ;    turn the speaker on with this frequency (snd) or off (nosnd)
  933. ;
  934. ; *****************************************************************
  935.  
  936. snd    proc    hertz:word        ;Sound the speaker
  937.     cmp    hertz, 20
  938.     jle    hertzbad
  939.     cmp    hertz, 5000
  940.     jge    hertzbad
  941.     mov    ax,0            ;Convert hertz
  942.     mov    dx, 12h         ;for use by routine
  943.     div    hertz
  944.     mov    bx, ax
  945.     mov    al,10110110b        ;Put magic number
  946.     out    43h, al         ;into timer2
  947.     mov    ax, bx            ;Pitch into AX
  948.     out    42h, al         ;LSB into timer2
  949.     mov    al, ah            ;MSB to AL then
  950.     out    42h, al         ;to timer2
  951.     in    al, 61h         ;read I/O port B into AL
  952.     or    al,3            ;turn on bits 0 and 1
  953.     out    61h,al            ;to turn on speaker
  954. hertzbad:
  955.     ret
  956. snd        endp
  957.  
  958. nosnd        proc                ;Turn off speaker
  959.     in    al, 61h         ;Read I/O port B into AL
  960.     and    al, 11111100b        ;mask lower two bits
  961.     out    61h, al         ;to turn off speaker
  962.     ret
  963. nosnd    endp
  964.  
  965.  
  966. ; ****************** Function initasmvars() *****************************
  967.  
  968. initasmvars    proc    uses es si di
  969.  
  970.      cmp    cpu,0            ; have we been called yet:
  971.      je    initasmvarsgo        ;  nope.  proceed.
  972.      jmp    initreturn        ;  yup.  no need to be here.
  973.  
  974. initasmvarsgo:
  975.     mov    ax,ds            ; save the data segment
  976.     mov    _dataseg_xx,ax        ;  for the C code
  977.  
  978.     mov    overflow,0        ; indicate no overflows so far
  979.  
  980.     mov    dx,1            ; ask for 96K of far space
  981.     mov    ax,8000h        ;  ...
  982.     push    dx            ;  ...
  983.     push    ax            ;  ...
  984.     call    far ptr farmemalloc    ; use the assembler routine to do it
  985.     pop    ax            ; restore the stack
  986.     pop    ax            ;  ...
  987.     mov    extraseg,dx        ; save the results here.
  988.  
  989.     call    adapter_init        ; call the video adapter init
  990.  
  991.                        ; first see if a mouse is installed
  992.  
  993.     push    es            ; (no, first check to ensure that
  994.     mov    ax,0            ; int 33h doesn't point to 0:0)
  995.     mov    es,ax            ; ...
  996.     mov    ax,es:0cch        ; ...
  997.     pop    es            ; ...
  998.     cmp    ax,0            ; does int 33h have a non-zero value?
  999.     je    noint33         ;  nope.  then there's no mouse.
  1000.  
  1001.      xor    ax,ax               ; function for mouse check
  1002.      int    33h               ; call mouse driver
  1003. noint33:
  1004.      mov    mouse,al           ; al holds info about mouse
  1005.  
  1006.                        ; now get the information about the kbd
  1007.      push    es               ; save ES for a tad
  1008.      mov    ax,40h               ; reload ES with BIOS data seg
  1009.      mov    es,ax               ;  ...
  1010.      mov    ah,es:96h           ; get the keyboard byte
  1011.      pop    es               ; restore ES
  1012.      and    ah,10h               ; isolate the Enhanced KBD bit
  1013.      mov    kbd_type,ah           ; and save it
  1014.  
  1015.     call    far ptr cputype     ; what kind of CPU do we have here?
  1016.     cmp    ax,0            ; protected mode of some sort?
  1017.     jge    positive        ;  nope.  proceed.
  1018.     neg    ax            ;  yup.  flip the sign.
  1019. positive:
  1020.     mov    cpu,ax            ; save the cpu type.
  1021. itsa386:
  1022.     cmp    debugflag,8088        ; say, should we pretend it's an 8088?
  1023.     jne    nodebug         ;  nope.
  1024.     mov    cpu,86            ; yup.    use 16-bit emulation.
  1025. nodebug:
  1026.     call far ptr fputype        ; what kind of an FPU do we have?
  1027.     mov    fpu,ax            ;  save the results
  1028.  
  1029.     push    es            ; save ES for a tad
  1030.     mov    ax,0            ; reset ES to BIOS data area
  1031.     mov    es,ax            ;  ...
  1032.     mov    dx,es:46ch        ; obtain the current timer value
  1033.     cmp    cpu,386            ; are we on a 386 or above?
  1034.     jb    delaystartuploop    ;  nope.  don't adjust anything
  1035.     mov    delayloop, 256        ;  yup.  slow down the timer loop
  1036. delaystartuploop:
  1037.     cmp    dx,es:46ch        ; has the timer value changed?
  1038.     je    delaystartuploop    ;  nope.  check again.
  1039.     mov    dx,es:46ch        ; obtain the current timer value again
  1040.     mov    ax,0            ; clear the delay counter
  1041.     mov    delaycount,55        ; 55 millisecs = 1/18.2 secs
  1042. delaytestloop:
  1043.     call    delayamillisecond    ; burn up a (fake) millisecond
  1044.     inc    ax            ; indicate another loop has passed
  1045.     cmp    dx,es:46ch        ; has the timer value changed?
  1046.     je    delaytestloop        ; nope.  burn up some more time.
  1047.     mov    delaycount,ax        ; save the results here
  1048.     pop    es            ; restore ES again
  1049.  
  1050. initreturn:
  1051.      ret                   ; return to caller
  1052. initasmvars endp
  1053.  
  1054.  
  1055. ; New (Apr '90) mouse code by Pieter Branderhorst follows.
  1056. ; The variable lookatmouse controls it all.  Callers of keypressed and
  1057. ; getakey should set lookatmouse to:
  1058. ;      0  ignore the mouse entirely
  1059. ;     <0  only test for left button click; if it occurs return fake key
  1060. ;        number 0-lookatmouse
  1061. ;      1  return enter key for left button, arrow keys for mouse movement,
  1062. ;        mouse sensitivity is suitable for graphics cursor
  1063. ;      2  same as 1 but sensitivity is suitable for text cursor
  1064. ;      3  specials for zoombox, left/right double-clicks generate fake
  1065. ;        keys, mouse movement generates a variety of fake keys
  1066. ;        depending on state of buttons
  1067. ; Mouse movement is accumulated & saved across calls.  Eg if mouse has been
  1068. ; moved up-right quickly, the next few calls to getakey might return:
  1069. ;      right,right,up,right,up
  1070. ; Minor jiggling of the mouse generates no keystroke, and is forgotten (not
  1071. ; accumulated with additional movement) if no additional movement in the
  1072. ; same direction occurs within a short interval.
  1073. ; Movements on angles near horiz/vert are treated as horiz/vert; the nearness
  1074. ; tolerated varies depending on mode.
  1075. ; Any movement not picked up by calling routine within a short time of mouse
  1076. ; stopping is forgotten.  (This does not apply to button pushes in modes<3.)
  1077. ; Mouseread would be more accurate if interrupt-driven, but with the usage
  1078. ; in fractint (tight getakey loops while mouse active) there's no need.
  1079.  
  1080. ; translate table for mouse movement -> fake keys
  1081. mousefkey dw   1077,1075,1080,1072  ; right,left,down,up     just movement
  1082.     dw      0,   0,1081,1073  ;         ,pgdn,pgup  + left button
  1083.     dw    1144,1142,1147,1146  ; kpad+,kpad-,cdel,cins  + rt   button
  1084.     dw    1117,1119,1118,1132  ; ctl-end,home,pgdn,pgup + mid/multi
  1085.  
  1086. DclickTime    equ 9   ; ticks within which 2nd click must occur
  1087. JitterTime    equ 6   ; idle ticks before turfing unreported mickeys
  1088. TextHSens     equ 22  ; horizontal sensitivity in text mode
  1089. TextVSens     equ 44  ; vertical sensitivity in text mode
  1090. GraphSens     equ 5   ; sensitivity in graphics mode; gets lower @ higher res
  1091. ZoomSens      equ 20  ; sensitivity for zoom box sizing/rotation
  1092. TextVHLimit   equ 6   ; treat angles < 1:6  as straight
  1093. GraphVHLimit  equ 14  ; treat angles < 1:14 as straight
  1094. ZoomVHLimit   equ 1   ; treat angles < 1:1  as straight
  1095. JitterMickeys equ 3   ; mickeys to ignore before noticing motion
  1096.  
  1097. mouseread proc near
  1098.     local    moveaxis:word
  1099.  
  1100.     ; check if it is time to do an autosave
  1101.     cmp    saveticks,0    ; autosave timer running?
  1102.     je    mouse0        ;  nope
  1103.     sub    ax,ax        ; reset ES to BIOS data area
  1104.     mov    es,ax        ;  see notes at mouse1 in similar code
  1105. tickread:
  1106.     mov    ax,es:046ch    ; obtain the current timer value
  1107.     cmp    ax,savechktime    ; a new clock tick since last check?
  1108.     je    mouse0        ;  nope, save a dozen opcodes or so
  1109.     mov    dx,es:046eh    ; high word of ticker
  1110.     cmp    ax,es:046ch    ; did a tick get counted just as we looked?
  1111.     jne    tickread    ; yep, reread both words to be safe
  1112.     mov    savechktime,ax
  1113.     sub    ax,savebase    ; calculate ticks since timer started
  1114.     sbb    dx,savebase+2
  1115.     jns    tickcompare
  1116.     add    ax,0b0h     ; wrapped past midnight, add a day
  1117.     adc    dx,018h
  1118. tickcompare:
  1119.     cmp    dx,saveticks+2    ; check if past autosave time
  1120.     jb    mouse0
  1121.     ja    ticksavetime
  1122.     cmp    ax,saveticks
  1123.     jb    mouse0
  1124. ticksavetime:            ; it is time to do a save
  1125.     mov    ax,finishrow
  1126.     cmp    ax,-1        ; waiting for the end of a row before save?
  1127.     jne    tickcheckrow    ;  yup, go check row
  1128.     cmp    calc_status,1    ; safety check, calc active?
  1129.     jne    tickdosave    ;  nope, don't check type of calc
  1130.     cmp    got_status,0    ; 1pass or 2pass?
  1131.     je    ticknoterow    ;  yup
  1132.     cmp    got_status,1    ; solid guessing?
  1133.     jne    tickdosave    ;  not 1pass, 2pass, ssg, so save immediately
  1134. ticknoterow:
  1135.     mov    ax,currow    ; note the current row
  1136.     mov    finishrow,ax    ;  ...
  1137.     jmp    short mouse0    ; and keep working for now
  1138. tickcheckrow:
  1139.     cmp    ax,currow    ; started a new row since timer went off?
  1140.     je    mouse0        ;  nope, don't do the save yet
  1141. tickdosave:
  1142.     mov    timedsave,1    ; tell mainline what's up
  1143.     mov    ax,9999     ; a dummy key value, never gets used
  1144.     jmp    mouseret
  1145.  
  1146. mouse0: ; now the mouse stuff
  1147.     cmp    mouse,-1
  1148.     jne    mouseidle    ; no mouse, that was easy
  1149.     mov    ax,lookatmouse
  1150.     cmp    ax,prevlamouse
  1151.     je    mouse1
  1152.  
  1153.     ; lookatmouse changed, reset everything
  1154.     mov    prevlamouse,ax
  1155.     mov    mbclicks,0
  1156.     mov    mbstatus,0
  1157.     mov    mhmickeys,0
  1158.     mov    mvmickeys,0
  1159.     ; note: don't use int 33 func 0 nor 21 to reset, they're SLOW
  1160.     mov    ax,06h        ; reset button counts by reading them
  1161.     mov    bx,0
  1162.     int    33h
  1163.     mov    ax,06h
  1164.     mov    bx,1
  1165.     int    33h
  1166.     mov    ax,05h
  1167.     mov    bx,0
  1168.     int    33h
  1169.     mov    ax,0Bh        ; reset motion counters by reading
  1170.     int    33h
  1171.     mov    ax,lookatmouse
  1172.  
  1173. mouse1: or    ax,ax
  1174.     jz    mouseidle    ; check nothing when lookatmouse=0
  1175.     ; following code directly accesses bios tick counter; it would be
  1176.     ; better not to rely on addr (use int 1A instead) but old PCs don't
  1177.     ; have the required int, the addr is constant in bios to date, and
  1178.     ; fractint startup already counts on it, so:
  1179.     mov    ax,0        ; reset ES to BIOS data area
  1180.     mov    es,ax        ;  ...
  1181.     mov    dx,es:46ch    ; obtain the current timer value
  1182.     cmp    dx,mousetime
  1183.     ; if timer same as last call, skip int 33s:  reduces expense and gives
  1184.     ; caller a chance to read all pending stuff and paint something
  1185.     jne    mnewtick
  1186.     cmp    lookatmouse,0    ; interested in anything other than left button?
  1187.     jl    mouseidle    ; nope, done
  1188.     jmp    mouse5
  1189.  
  1190. mouseidle:
  1191.     clc            ; tell caller no mouse activity this time
  1192.     ret
  1193.  
  1194. mnewtick: ; new tick, read buttons and motion
  1195.     mov    mousetime,dx    ; note current timer
  1196.     cmp    lookatmouse,3
  1197.     je    mouse2        ; skip button press if mode 3
  1198.  
  1199.     ; check press of left button
  1200.     mov    ax,05h        ; get button press info
  1201.     mov    bx,0        ; for left button
  1202.     int    33h
  1203.     or    bx,bx
  1204.     jnz    mleftb
  1205.     cmp    lookatmouse,0
  1206.     jl    mouseidle    ; exit if nothing but left button matters
  1207.     jmp    mouse3        ; not mode 3 so skip past button release stuff
  1208. mleftb: mov    ax,13
  1209.     cmp    lookatmouse,0
  1210.     jg    mouser        ; return fake key enter
  1211.     mov    ax,lookatmouse    ; return fake key 0-lookatmouse
  1212.     neg    ax
  1213. mouser: jmp    mouseret
  1214.  
  1215. mouse2: ; mode 3, check for double clicks
  1216.     mov    ax,06h        ; get button release info
  1217.     mov    bx,0        ; left button
  1218.     int    33h
  1219.     mov    dx,mousetime
  1220.     cmp    bx,1        ; left button released?
  1221.     jl    msnolb        ; go check timer if not
  1222.     jg    mslbgo        ; double click
  1223.     test    mbclicks,1    ; had a 1st click already?
  1224.     jnz    mslbgo        ; yup, double click
  1225.     mov    mlbtimer,dx    ; note time of 1st click
  1226.     or    mbclicks,1
  1227.     jmp    short mousrb
  1228. mslbgo: and    mbclicks,0ffh-1
  1229.     mov    ax,13        ; fake key enter
  1230.     jmp    mouseret
  1231. msnolb: sub    dx,mlbtimer    ; clear 1st click if its been too long
  1232.     cmp    dx,DclickTime
  1233.     jb    mousrb
  1234.     and    mbclicks,0ffh-1 ; forget 1st click if any
  1235.     ; next all the same code for right button
  1236. mousrb: mov    ax,06h        ; get button release info
  1237.     mov    bx,1        ; right button
  1238.     int    33h
  1239.     ; now much the same as for left
  1240.     mov    dx,mousetime
  1241.     cmp    bx,1
  1242.     jl    msnorb
  1243.     jg    msrbgo
  1244.     test    mbclicks,2
  1245.     jnz    msrbgo
  1246.     mov    mrbtimer,dx
  1247.     or    mbclicks,2
  1248.     jmp    short mouse3
  1249. msrbgo: and    mbclicks,0ffh-2
  1250.     mov    ax,1010     ; fake key ctl-enter
  1251.     jmp    mouseret
  1252. msnorb: sub    dx,mrbtimer
  1253.     cmp    dx,DclickTime
  1254.     jb    mouse3
  1255.     and    mbclicks,0ffh-2
  1256.  
  1257.     ; get buttons state, if any changed reset mickey counters
  1258. mouse3: mov    ax,03h        ; get button status
  1259.     int    33h
  1260.     and    bl,7        ; just the button bits
  1261.     cmp    bl,mbstatus    ; any changed?
  1262.     je    mouse4
  1263.     mov    mbstatus,bl    ; yup, reset stuff
  1264.     mov    mhmickeys,0
  1265.     mov    mvmickeys,0
  1266.     mov    ax,0Bh
  1267.     int    33h        ; reset driver's mickeys by reading them
  1268.  
  1269.     ; get motion counters, forget any jiggle
  1270. mouse4: mov    ax,0Bh        ; get motion counters
  1271.     int    33h
  1272.     mov    bx,mousetime    ; just to have it in a register
  1273.     cmp    cx,0        ; horiz motion?
  1274.     jne    moushm        ; yup, go accum it
  1275.     mov    ax,bx
  1276.     sub    ax,mhtimer
  1277.     cmp    ax,JitterTime    ; timeout since last horiz motion?
  1278.     jb    mousev
  1279.     mov    mhmickeys,0
  1280.     jmp    short mousev
  1281. moushm: mov    mhtimer,bx    ; note time of latest motion
  1282.     add    mhmickeys,cx
  1283.     ; same as above for vertical movement:
  1284. mousev: cmp    dx,0        ; vert motion?
  1285.     jne    mousvm
  1286.     mov    ax,bx
  1287.     sub    ax,mvtimer
  1288.     cmp    ax,JitterTime
  1289.     jb    mouse5
  1290.     mov    mvmickeys,0
  1291.     jmp    short mouse5
  1292. mousvm: mov    mvtimer,bx
  1293.     add    mvmickeys,dx
  1294.  
  1295.     ; pick the axis with largest pending movement
  1296. mouse5: mov    bx,mhmickeys
  1297.     or    bx,bx
  1298.     jns    mchkv
  1299.     neg    bx        ; make it +ve
  1300. mchkv:    mov    cx,mvmickeys
  1301.     or    cx,cx
  1302.     jns    mchkmx
  1303.     neg    cx
  1304. mchkmx: mov    moveaxis,0    ; flag that we're going horiz
  1305.     cmp    bx,cx        ; horiz>=vert?
  1306.     jge    mangle
  1307.     xchg    bx,cx        ; nope, use vert
  1308.     mov    moveaxis,1    ; flag that we're going vert
  1309.  
  1310.     ; if moving nearly horiz/vert, make it exactly horiz/vert
  1311. mangle: mov    ax,TextVHLimit
  1312.     cmp    lookatmouse,2    ; slow (text) mode?
  1313.     je    mangl2
  1314.     mov    ax,GraphVHLimit
  1315.     cmp    lookatmouse,3    ; special mode?
  1316.     jne    mangl2
  1317.     cmp    mbstatus,0    ; yup, any buttons down?
  1318.     je    mangl2
  1319.     mov    ax,ZoomVHLimit    ; yup, special zoom functions
  1320. mangl2: mul    cx        ; smaller axis * limit
  1321.     cmp    ax,bx
  1322.     ja    mchkmv        ; min*ratio <= max?
  1323.     cmp    moveaxis,0    ; yup, clear the smaller movement axis
  1324.     jne    mzeroh
  1325.     mov    mvmickeys,0
  1326.     jmp    short mchkmv
  1327. mzeroh: mov    mhmickeys,0
  1328.  
  1329.     ; pick sensitivity to use
  1330. mchkmv: cmp    lookatmouse,2    ; slow (text) mode?
  1331.     je    mchkmt
  1332.     mov    dx,ZoomSens+JitterMickeys
  1333.     cmp    lookatmouse,3    ; special mode?
  1334.     jne    mchkmg
  1335.     cmp    mbstatus,0    ; yup, any buttons down?
  1336.     jne    mchkm2        ; yup, use zoomsens
  1337. mchkmg: mov    dx,GraphSens
  1338.     mov    cx,sxdots    ; reduce sensitivity for higher res
  1339. mchkg2: cmp    cx,400        ; horiz dots >= 400?
  1340.     jl    mchkg3
  1341.     shr    cx,1        ; horiz/2
  1342.     shr    dx,1
  1343.     inc    dx        ; sensitivity/2+1
  1344.     jmp    short mchkg2
  1345. mchkg3: add    dx,JitterMickeys
  1346.     jmp    short mchkm2
  1347. mchkmt: mov    dx,TextVSens+JitterMickeys
  1348.     cmp    moveaxis,0
  1349.     jne    mchkm2
  1350.     mov    dx,TextHSens+JitterMickeys ; slower on X axis than Y
  1351.  
  1352.     ; is largest movement past threshold?
  1353. mchkm2: cmp    bx,dx
  1354.     jge    mmove
  1355.     jmp    mouseidle    ; no movement past threshold, return nothing
  1356.  
  1357.     ; set bx for right/left/down/up, and reduce the pending mickeys
  1358. mmove:    sub    dx,JitterMickeys
  1359.     cmp    moveaxis,0
  1360.     jne    mmovev
  1361.     cmp    mhmickeys,0
  1362.     jl    mmovh2
  1363.     sub    mhmickeys,dx    ; horiz, right
  1364.     mov    bx,0
  1365.     jmp    short mmoveb
  1366. mmovh2: add    mhmickeys,dx    ; horiz, left
  1367.     mov    bx,2
  1368.     jmp    short mmoveb
  1369. mmovev: cmp    mvmickeys,0
  1370.     jl    mmovv2
  1371.     sub    mvmickeys,dx    ; vert, down
  1372.     mov    bx,4
  1373.     jmp    short mmoveb
  1374. mmovv2: add    mvmickeys,dx    ; vert, up
  1375.     mov    bx,6
  1376.  
  1377.     ; modify bx if a button is being held down
  1378. mmoveb: cmp    lookatmouse,3
  1379.     jne    mmovek        ; only modify in mode 3
  1380.     cmp    mbstatus,1
  1381.     jne    mmovb2
  1382.     add    bx,8        ; modify by left button
  1383.     jmp    short mmovek
  1384. mmovb2: cmp    mbstatus,2
  1385.     jne    mmovb3
  1386.     add    bx,16        ; modify by rb
  1387.     jmp    short mmovek
  1388. mmovb3: cmp    mbstatus,0
  1389.     je    mmovek
  1390.     add    bx,24        ; modify by middle or multiple
  1391.  
  1392.     ; finally, get the fake key number
  1393. mmovek: mov    ax,mousefkey[bx]
  1394.  
  1395. mouseret:
  1396.     stc
  1397.     ret
  1398. mouseread endp
  1399.  
  1400.  
  1401. ; long readticker() returns current bios ticker value
  1402.  
  1403. readticker proc uses es
  1404.     sub    ax,ax        ; reset ES to BIOS data area
  1405.     mov    es,ax        ;  see notes at mouse1 in similar code
  1406. tickread:
  1407.     mov    ax,es:046ch    ; obtain the current timer value
  1408.     mov    dx,es:046eh    ; high word of ticker
  1409.     cmp    ax,es:046ch    ; did a tick get counted just as we looked?
  1410.     jne    tickread    ; yep, reread both words to be safe
  1411.     ret
  1412. readticker endp
  1413.  
  1414.  
  1415. ;===============================================================
  1416. ;
  1417. ; CPUTYPE.ASM : C-callable functions cputype() and ndptype() adapted
  1418. ; by Lee Daniel Crocker from code appearing in the late PC Tech Journal,
  1419. ; August 1987 and November 1987.  PC Tech Journal was a Ziff-Davis
  1420. ; Publication.    Code herein is copyrighted and used with permission.
  1421. ;
  1422. ; The function cputype() returns an integer value based on what kind
  1423. ; of CPU it found, as follows:
  1424. ;
  1425. ;    Value    CPU Type
  1426. ;    =====    ========
  1427. ;    86    8086, 8088, V20, or V30
  1428. ;    186    80186 or 80188
  1429. ;    286    80286
  1430. ;    386    80386 or 80386sx
  1431. ;    -286    80286 in protected mode
  1432. ;    -386    80386 or 80386sx in protected or 32-bit address mode
  1433. ;
  1434. ; The function ndptype() returns an integer based on the type of NDP
  1435. ; it found, as follows:
  1436. ;
  1437. ;    Value    NDP Type
  1438. ;    =====    ========
  1439. ;    0    No NDP found
  1440. ;    87    8087
  1441. ;    287    80287
  1442. ;    387    80387
  1443. ;
  1444. ; No provisions are made for the 80486 CPU/FPU or Weitek FPA chips.
  1445. ;
  1446. ; Neither function takes any arguments or affects any external storage,
  1447. ; so there should be no memory-model dependencies.
  1448.  
  1449. .286P
  1450. .code
  1451.  
  1452. cputype proc
  1453.     push    bp
  1454.  
  1455.     push    sp            ; 86/186 will push SP-2;
  1456.     pop    ax            ; 286/386 will push SP.
  1457.     cmp    ax, sp
  1458.     jz    not86            ; If equal, SP was pushed
  1459.     mov    ax, 186
  1460.     mov    cl, 32            ;   186 uses count mod 32 = 0;
  1461.     shl    ax, cl            ;   86 shifts 32 so ax = 0
  1462.     jnz    exit            ; Non-zero: no shift, so 186
  1463.     mov    ax, 86            ; Zero: shifted out all bits
  1464.     jmp    short exit
  1465. not86:
  1466.     pushf                ; Test 16 or 32 operand size:
  1467.     mov    ax, sp            ;   Pushed 2 or 4 bytes of flags?
  1468.     popf
  1469.     inc    ax
  1470.     inc    ax
  1471.     cmp    ax, sp            ;   Did pushf change SP by 2?
  1472.     jnz    is32bit         ;   If not, then 4 bytes of flags
  1473. is16bit:
  1474.     sub    sp, 6            ; Is it 286 or 386 in 16-bit mode?
  1475.     mov    bp, sp            ; Allocate stack space for GDT pointer
  1476.     sgdt    fword ptr [bp]
  1477.     add    sp, 4            ; Discard 2 words of GDT pointer
  1478.     pop    ax            ; Get third word
  1479.     inc    ah            ; 286 stores -1, 386 stores 0 or 1
  1480.     jnz    is386
  1481. is286:
  1482.     mov    ax, 286
  1483.     jmp    short testprot        ; Check for protected mode
  1484. is32bit:
  1485.     db    66h            ; 16-bit override in 32-bit mode
  1486. is386:
  1487.     mov    ax, 386
  1488. testprot:
  1489.     smsw    cx            ; Protected?  Machine status -> CX
  1490.     ror    cx,1            ; Protection bit -> carry flag
  1491.     jnc    exit            ; Real mode if no carry
  1492.     neg    ax            ; Protected:  return neg value
  1493. exit:
  1494.     pop    bp
  1495.     ret
  1496. cputype endp
  1497.  
  1498. .data
  1499.  
  1500. control dw    0            ; Temp storage for 8087 control
  1501.                     ;   and status registers
  1502. .code
  1503.  
  1504. fputype proc
  1505.     push    bp
  1506.  
  1507.     fninit                ; Defaults to 64-bit mantissa
  1508.     mov    byte ptr control+1, 0
  1509.     fnstcw    control         ; Store control word over 0
  1510. ;    dw    3ed9h            ; (klooge to avoid the MASM \e switch)
  1511. ;    dw    offset control        ; ((equates to the above 'fnstcw' cmd))
  1512.     mov    ah, byte ptr control+1    ; Test contents of byte written
  1513.     cmp    ah, 03h         ; Test for 64-bit precision flags
  1514.     je    gotone            ; Got one!  Now let's find which
  1515.     xor    ax, ax
  1516.     jmp    short fexit        ; No NDP found
  1517. gotone:
  1518.     and    control, not 0080h    ; IEM = 0 (interrupts on)
  1519.     fldcw    control
  1520.     fdisi                ; Disable ints; 287/387 will ignore
  1521.     fstcw    control
  1522.     test    control, 0080h
  1523.     jz    not87            ; Got 287/387; keep testing
  1524.     mov    ax, 87
  1525.     jmp    short freset
  1526. not87:
  1527.     finit
  1528.     fld1
  1529.     fldz
  1530.     fdiv                ; Divide 1/0 to create infinity
  1531.     fld    st
  1532.     fchs                ; Push -infinity on stack
  1533.     fcompp                ; Compare +-infinity
  1534.     fstsw    control
  1535.     mov    ax, control
  1536.     sahf
  1537.     jnz    got387            ; 387 will compare correctly
  1538.     mov    ax, 287
  1539.     jmp    short freset
  1540. got387:                 ; Only one left (until 487/Weitek
  1541.     mov    ax, 387         ;   test is added)
  1542. freset:
  1543.     fninit                ; in case tests have had strange
  1544.     finit                ; side-effects, reset
  1545. fexit:
  1546.     pop    bp
  1547.     ret
  1548. fputype endp
  1549.  
  1550. ; ************************* Far Segment RAM Support **************************
  1551. ;
  1552. ;
  1553. ;    farptr = (char far *)farmemalloc(long bytestoalloc);
  1554. ;    (void)farmemfree(farptr);
  1555. ;
  1556. ;    alternatives to Microsoft/TurboC routines
  1557. ;
  1558. ;
  1559. .8086
  1560.  
  1561. farmemalloc    proc    uses es, bytestoallocate:dword
  1562.     les    bx,bytestoallocate    ; get the # of bytes into DX:BX
  1563.     mov    dx,es            ;  ...
  1564.     add    bx,15            ; round up to next paragraph boundary
  1565.     adc    dx,0            ;  ...
  1566.     shr    dx,1            ; convert to paragraphs
  1567.     rcr    bx,1            ;  ...
  1568.     shr    dx,1            ;  ...
  1569.     rcr    bx,1            ;  ...
  1570.     shr    dx,1            ;  ...
  1571.     rcr    bx,1            ;  ...
  1572.     shr    dx,1            ;  ...
  1573.     rcr    bx,1            ;  ...
  1574.     cmp    dx,0            ; ensure that we don't want > 1MB
  1575.     jne    farmemallocfailed    ;  bail out if we do
  1576.     mov    ah,48h            ; invoke DOS to allocate memory
  1577.     int    21h            ;  ...
  1578.     jc    farmemallocfailed    ; bail out on failure
  1579.     mov    dx,ax            ; set up DX:AX as far address
  1580.     mov    ax,0            ;  ...
  1581.     jmp    short farmemallocreturn ; and return
  1582. farmemallocfailed:
  1583.     mov    ax,0            ; (load up with a failed response)
  1584.     mov    dx,0            ;  ...
  1585. farmemallocreturn:
  1586.     ret                ; we done.
  1587. farmemalloc    endp
  1588.  
  1589. farmemfree    proc    uses es, farptr:dword
  1590.     les    ax,farptr        ; get the segment into ES
  1591.     mov    ah,49h            ; invoke DOS to free the segment
  1592.     int    21h            ;  ...
  1593.     ret
  1594. farmemfree    endp
  1595.  
  1596. erasesegment    proc    uses es di si, segaddress:word, segvalue:word
  1597.     mov    ax,segaddress        ; load up the segment address
  1598.     mov    es,ax            ;  ...
  1599.     mov    di,0            ; start at the beginning
  1600.     mov    ax,segvalue        ; use this value
  1601.     mov    cx,8000h        ; over the entire segment
  1602.     rep    stosw            ; do it
  1603.     ret                ; we done
  1604. erasesegment    endp
  1605.  
  1606.  
  1607. farread proc uses ds, handle:word, buf:dword, len:word
  1608.     mov    ah, 03Fh
  1609.     mov    bx, [handle]
  1610.     mov    cx, [len]
  1611.     lds    dx, [buf]
  1612.     int    21h
  1613.     jnc    farreaddone
  1614.     mov    ax, -1
  1615. farreaddone:
  1616.     ret
  1617. farread endp
  1618.  
  1619.  
  1620. farwrite proc uses ds, handle:word, buf:dword, len:word
  1621.     mov    ah, 040h
  1622.     mov    bx, [handle]
  1623.     mov    cx, [len]
  1624.     lds    dx, [buf]
  1625.     int    21h
  1626.     jnc    farwritedone
  1627.     mov    ax, -1
  1628. farwritedone:
  1629.     ret
  1630. farwrite endp
  1631.  
  1632.  
  1633. ; Convert segment:offset to equiv pointer with minimum possible offset
  1634. normalize proc p: dword
  1635. ;    mov    ax, [word ptr p]
  1636. ;    mov    dx, [word ptr p+2]
  1637.     les    ax, p
  1638.     mov    dx, es
  1639.     mov    bx, ax
  1640.     shr    bx, 1
  1641.     shr    bx, 1
  1642.     shr    bx, 1
  1643.     shr    bx, 1
  1644.     and    ax, 0Fh
  1645.     add    dx, bx
  1646.     ret
  1647. normalize endp
  1648.  
  1649.  
  1650. ; *************** Far string/memory functions *********
  1651. ;    far_strlen ( char far *);
  1652. ;    far_strcpy ( char far *, char far *);
  1653. ;    far_strcmp ( char far *, char far *);
  1654. ;    far_stricmp( char far *, char far *);
  1655. ;    far_strnicmp(char far *, char far *, int);
  1656. ;    far_strcat ( char far *, char far *);
  1657. ;    far_memset ( char far *, char far,   int);
  1658. ;    far_memcpy ( char far *, char far *, int);
  1659. ;    far_memcmp ( char far *, char far *, int);
  1660. ;    far_memicmp( char far *, char far *, int);
  1661.  
  1662. ;    xxxfar_routines are called internally with:
  1663. ;        ds:si pointing to the source
  1664. ;        es:di pointing to the destination
  1665. ;        cx    containing a byte count
  1666. ;        al    contining  a character (set) value
  1667. ;        (and they destroy registers willy-nilly)
  1668.  
  1669. xxxfar_memlen    proc    near    ; return string length - INCLUDING the 0
  1670.     mov    ax,0
  1671.     mov    cx,1024
  1672.     repne    scasb
  1673.     sub    cx,1024
  1674.     neg    cx
  1675.     ret
  1676. xxxfar_memlen    endp
  1677.  
  1678. xxxfar_memcmp    proc    near    ; compare two strings - length in CX
  1679.     mov    ax,0
  1680.     rep    cmpsb
  1681.     jz    wedone
  1682.     mov    ax,1
  1683. wedone: ret
  1684. xxxfar_memcmp    endp
  1685.  
  1686. xxxfar_memicmp    proc    near    ; compare two caseless strings - length in CX
  1687.     mov    ax,0
  1688.     cmp    cx,0
  1689.     je    wedone
  1690.     dec    si
  1691.     dec    di
  1692. loop1:    inc    si
  1693.     inc    di
  1694.     mov    al,es:[di]
  1695.     mov    ah,ds:[si]
  1696.     cmp    al,ah
  1697.     je    loop2
  1698.     cmp    al,'A'
  1699.     jb    lower1
  1700.     cmp    al,'Z'
  1701.     ja    lower1
  1702.     add    al,20h
  1703. lower1: cmp    ah,'A'
  1704.     jb    lower2
  1705.     cmp    ah,'Z'
  1706.     ja    lower2
  1707.     add    ah,20h
  1708. lower2: cmp    al,ah
  1709.     jne    uneql
  1710. loop2:    loop    loop1
  1711.     mov    ax,0
  1712.     jmp    short wedone
  1713. uneql:    mov    ax,1
  1714. wedone: ret
  1715. xxxfar_memicmp    endp
  1716.  
  1717.  
  1718. far_strlen proc uses ds es di si, fromaddr:dword
  1719.     les    di,fromaddr        ; point to start-of-string
  1720.     call    xxxfar_memlen        ; find the string length
  1721.     mov    ax,cx            ; return len
  1722.     dec    ax            ; don't count null
  1723.     ret                ; we done.
  1724. far_strlen endp
  1725.  
  1726. far_strnicmp proc    uses ds es di si, toaddr:dword, fromaddr:dword, len:word
  1727.     les    di,fromaddr        ; point to start-of-string
  1728.     call    xxxfar_memlen        ; find the string length
  1729.     cmp    cx,len            ; source less than or equal to len?
  1730.     jle    cxbigger        ; yup - use cx
  1731.     mov    cx,len            ; nope - use len
  1732. cxbigger:
  1733.     les    di,toaddr        ; get the dest string
  1734.     lds    si,fromaddr        ; get the source string
  1735.     call    xxxfar_memicmp        ; compare them
  1736.     ret                ; we done.
  1737. far_strnicmp endp
  1738.  
  1739. far_strcpy proc uses ds es di si, toaddr:dword, fromaddr:dword
  1740.     les    di,fromaddr        ; point to start-of-string
  1741.     call    xxxfar_memlen        ; find the string length
  1742.     les    di,toaddr        ; now move to here
  1743.     lds    si,fromaddr        ; from here
  1744.     rep    movsb            ; move them
  1745.     ret                ; we done.
  1746. far_strcpy endp
  1747.  
  1748. far_strcmp proc uses ds es di si, toaddr:dword, fromaddr:dword
  1749.     les    di,fromaddr        ; point to start-of-string
  1750.     call    xxxfar_memlen        ; find the string length
  1751.     les    di,toaddr        ; now compare to here
  1752.     lds    si,fromaddr        ; compare here
  1753.     call    xxxfar_memcmp        ; compare them
  1754.     ret                ; we done.
  1755. far_strcmp endp
  1756.  
  1757. far_stricmp proc    uses ds es di si, toaddr:dword, fromaddr:dword
  1758.     les    di,fromaddr        ; point to start-of-string
  1759.     call    xxxfar_memlen        ; find the string length
  1760.     les    di,toaddr        ; get the dest string
  1761.     lds    si,fromaddr        ; get the source string
  1762.     call    xxxfar_memicmp        ; compare them
  1763.     ret                ; we done.
  1764. far_stricmp endp
  1765.  
  1766. far_strcat proc uses ds es di si, toaddr:dword, fromaddr:dword
  1767.     les    di,fromaddr        ; point to start-of-string
  1768.     call    xxxfar_memlen        ; find the string length
  1769.     push    cx            ; save it
  1770.     les    di,toaddr        ; point to start-of-string
  1771.     call    xxxfar_memlen        ; find the string length
  1772.     les    di,toaddr        ; now move to here
  1773.     add    di,cx            ; but start at the end of string
  1774.     dec    di            ; (less the EOS zero)
  1775.     lds    si,fromaddr        ; from here
  1776.     pop    cx            ; get the string length
  1777.     rep    movsb            ; move them
  1778.     ret                ; we done.
  1779. far_strcat endp
  1780.  
  1781. far_memset proc uses es di, toaddr:dword, fromvalue:word, slength:word
  1782.     mov    ax,fromvalue        ; get the value to store
  1783.     mov    cx,slength        ; get the store length
  1784.     les    di,toaddr        ; now move to here
  1785.     rep    stosb            ; store them
  1786.     ret                ; we done.
  1787. far_memset endp
  1788.  
  1789. far_memcpy proc uses ds es di si, toaddr:dword, fromaddr:dword, slength:word
  1790.     mov    cx,slength        ; get the move length
  1791.     les    di,toaddr        ; now move to here
  1792.     lds    si,fromaddr        ; from here
  1793.     rep    movsb            ; move them
  1794.     ret                ; we done.
  1795. far_memcpy endp
  1796.  
  1797. far_memcmp proc uses ds es di si, toaddr:dword, fromaddr:dword, slength:word
  1798.     mov    cx,slength        ; get the compare length
  1799.     les    di,toaddr        ; now compare to here
  1800.     lds    si,fromaddr        ; compare here
  1801.     call    xxxfar_memcmp        ; compare them
  1802.     ret                ; we done.
  1803. far_memcmp endp
  1804.  
  1805. far_memicmp proc uses ds es di si, toaddr:dword, fromaddr:dword, slength:word
  1806.     mov    cx,slength        ; get the compare length
  1807.     les    di,toaddr        ; get the dest string
  1808.     lds    si,fromaddr        ; get the source string
  1809.     call    xxxfar_memicmp        ; compare them
  1810.     ret                ; we done.
  1811. far_memicmp endp
  1812.  
  1813. disable proc                ; disable interrupts
  1814.     cli
  1815.     ret
  1816. disable endp
  1817.  
  1818. enable    proc                ; re-enable interrupts
  1819.     sti
  1820.     ret
  1821. enable    endp
  1822.  
  1823. ; *************** Expanded Memory Manager Support Routines ******************
  1824. ;        for use with LIM 3.2 or 4.0 Expanded Memory
  1825. ;
  1826. ;    farptr = emmquery()    ; Query presence of EMM and initialize EMM code
  1827. ;                ; returns EMM FAR Address, or 0 if no EMM
  1828. ;    freepages = emmgetfree(); Returns the number of pages (1 page = 16K)
  1829. ;                ; not already allocated for something else
  1830. ;    handle = emmallocate(pages)    ; allocate EMM pages (1 page = 16K)
  1831. ;                ; returns handle # if OK, or else 0
  1832. ;    emmdeallocate(handle)    ; return EMM pages to system - MUST BE CALLED
  1833. ;                ; or allocated EMM memory fills up
  1834. ;    emmgetpage(page, handle); get an EMM page (actually, links the EMM
  1835. ;                ; page to the EMM Segment ADDR, saving any
  1836. ;                ; prior page in the process)
  1837. ;    emmclearpage(page, handle) ; performs an 'emmgetpage()' and then clears
  1838. ;                ; it out (quickly) to zeroes with a 'REP STOSW'
  1839.  
  1840. .8086
  1841.  
  1842. .DATA
  1843.  
  1844. emm_name    db    'EMMXXXX0',0    ; device driver for EMM
  1845. emm_segment    dw    0        ; EMM page frame segment
  1846. emm_zeroflag    db    0        ; klooge flag for handle==0
  1847.  
  1848. .CODE
  1849.  
  1850. emmquery    proc
  1851.     mov    ah,3dh            ; function 3dh = open file
  1852.     mov    al,0            ;  read only
  1853.     mov    dx,offset emm_name    ; DS:DX = address of name of EMM
  1854.     int    21h            ; open it
  1855.     jc    emmqueryfailed        ;  oops.  no EMM.
  1856.  
  1857.     mov    bx,ax            ; BX = handle for EMM
  1858.     mov    ah,44h            ; function 44h = IOCTL
  1859.     mov    al,7            ; get outo. status
  1860.     mov    cx,0            ; CX = # of bytes to read
  1861.     int    21h            ; do it.
  1862.     push    ax            ; save the IOCTL handle.
  1863.  
  1864.     mov    ah,3eh            ; function 3H = close
  1865.     int    21h            ; BX still cintains handle
  1866.     pop    ax            ; restore AX for the status query
  1867.     jc    emmqueryfailed        ; huh?    close FAILED?
  1868.  
  1869.     or    al,al            ; was the status 0?
  1870.     jz    emmqueryfailed        ; well then, it wasn't EMM!
  1871.  
  1872.     mov    ah,40h            ; query EMM: hardware ok?
  1873.     int    67h            ; EMM call
  1874.     cmp    ah,0            ; is it ok?
  1875.     jne    emmqueryfailed        ; if not, fail
  1876.  
  1877.     mov    ah,41h            ; query EMM: Get Page Frame Segment
  1878.     int    67h            ; EMM call
  1879.     cmp    ah,0            ; is it ok?
  1880.     jne    emmqueryfailed        ; if not, fail
  1881.     mov    emm_segment,bx        ; save page frame segment
  1882.     mov    dx,bx            ; return page frame address
  1883.     mov    ax,0            ;  ...
  1884.     jmp    short    emmqueryreturn    ; we done.
  1885.  
  1886. emmqueryfailed:
  1887.     mov    ax,0            ; return 0 (no EMM found)
  1888.     mov    dx,0            ;  ...
  1889. emmqueryreturn:
  1890.     ret                ; we done.
  1891. emmquery    endp
  1892.  
  1893. emmgetfree    proc            ; get # of free EMM pages
  1894.     mov    ah,42h            ; EMM call: get total and free pages
  1895.     int    67h            ; EMM call
  1896.     cmp    ah,0            ; did we suceed?
  1897.     jne    emmgetfreefailed    ;  nope.  return 0 free pages
  1898.     mov    ax,bx            ; else return # of free pages
  1899.     jmp    emmgetfreereturn    ; we done.
  1900. emmgetfreefailed:
  1901.     mov    ax,0            ; failure mode
  1902. emmgetfreereturn:
  1903.     ret                ; we done
  1904. emmgetfree    endp
  1905.  
  1906. emmallocate    proc    pages:word    ; allocate EMM pages
  1907.     mov    bx,pages        ; BX = # of 16K pages
  1908.     mov    ah,43h            ; ask for the memory
  1909.     int    67h            ; EMM call
  1910.     mov    emm_zeroflag,0        ; clear the klooge flag
  1911.     cmp    ah,0            ; did the call work?
  1912.     jne    emmallocatebad        ;  nope.
  1913.     mov    ax,dx            ; yup.    save the handle here
  1914.     cmp    ax,0            ; was the handle a zero?
  1915.     jne    emmallocatereturn    ;  yup.  no kloogy fixes
  1916.     mov    emm_zeroflag,1        ; oops.  set an internal flag
  1917.     mov    ax,1234         ; and make up a dummy handle.
  1918.     jmp    short    emmallocatereturn ; and return
  1919. emmallocatebad:
  1920.     mov    ax,0            ; indicate no handle
  1921. emmallocatereturn:
  1922.     ret                ; we done.
  1923. emmallocate    endp
  1924.  
  1925. emmdeallocate    proc    emm_handle:word ; De-allocate EMM memory
  1926. emmdeallocatestart:
  1927.     mov    dx,emm_handle        ; get the EMM handle
  1928.     cmp    dx,1234         ; was it our special klooge value?
  1929.     jne    emmdeallocatecontinue    ;  nope.  proceed.
  1930.     cmp    emm_zeroflag,1        ; was it really a zero handle?
  1931.     jne    emmdeallocatecontinue    ;  nope.  proceed.
  1932.     mov    dx,0            ; yup.    use zero instead.
  1933. emmdeallocatecontinue:
  1934.     mov    ah,45h            ; EMM function: deallocate
  1935.     int    67h            ; EMM call
  1936.     cmp    ah,0            ; did it work?
  1937.     jne    emmdeallocatestart    ; well then, try it again!
  1938. emmdeallocatereturn:
  1939.     ret                ; we done
  1940. emmdeallocate    endp
  1941.  
  1942. emmgetpage    proc    pagenum:word, emm_handle:word    ; get EMM page
  1943.     mov    bx,pagenum        ; BX = page numper
  1944.     mov    dx,emm_handle        ; DX = EMM handle
  1945.     cmp    dx,1234         ; was it our special klooge value?
  1946.     jne    emmgetpagecontinue    ;  nope.  proceed.
  1947.     cmp    emm_zeroflag,1        ; was it really a zero handle?
  1948.     jne    emmgetpagecontinue    ;  nope.  proceed.
  1949.     mov    dx,0            ; yup.    use zero instead.
  1950. emmgetpagecontinue:
  1951.     mov    ah,44h            ; EMM call: get page
  1952.     mov    al,0            ; get it into page 0
  1953.     int    67h            ; EMM call
  1954.     ret                ; we done
  1955. emmgetpage    endp
  1956.  
  1957. emmclearpage    proc    pagenum:word, emm_handle:word    ; clear EMM page
  1958.     mov    bx,pagenum        ; BX = page numper
  1959.     mov    dx,emm_handle        ; DX = EMM handle
  1960.     cmp    dx,1234         ; was it our special klooge value?
  1961.     jne    emmclearpagecontinue    ;  nope.  proceed.
  1962.     cmp    emm_zeroflag,1        ; was it really a zero handle?
  1963.     jne    emmclearpagecontinue    ;  nope.  proceed.
  1964.     mov    dx,0            ; yup.    use zero instead.
  1965. emmclearpagecontinue:
  1966.     mov    ah,44h            ; EMM call: get page
  1967.     mov    al,0            ; get it into page 0
  1968.     int    67h            ; EMM call
  1969.     mov    ax,emm_segment        ; get EMM segment into ES
  1970.     push    es            ;  ...
  1971.     mov    es,ax            ;  ...
  1972.     mov    di,0            ; start at offset 0
  1973.     mov    cx,8192         ; for 16K (in words)
  1974.     mov    ax,0            ; clear out EMM segment to zeroes
  1975.     rep    stosw            ; clear the page
  1976.     pop    es            ; restore ES
  1977.     ret                ; we done
  1978. emmclearpage    endp
  1979.  
  1980. ; *************** Extended Memory Manager Support Routines ******************
  1981. ;          for use XMS 2.0 and later Extended Memory
  1982. ;
  1983. ;    xmmquery()        ; Query presence of XMM and initialize XMM code
  1984. ;                ; returns 0 if no XMM
  1985. ;    xmmlongest()        ; return size of largest available
  1986. ;                ; XMM block in Kbytes (or zero if none)
  1987. ;    handle = xmmallocate(Kbytes)    ; allocate XMM block in Kbytes
  1988. ;                    ; returns handle # if OK, or else 0
  1989. ;    xmmreallocate(handle, Kbytes)    ; change size of handle's block
  1990. ;                ; to size of Kbytes.  Returns 0 if failed
  1991. ;    xmmdeallocate(handle)    ; return XMM block to system - MUST BE CALLED
  1992. ;                ; or allocated XMM memory is not released.
  1993. ;    xmmmoveextended(&MoveStruct)    ; Moves a block of memory to or
  1994. ;                ; from extended memory.  Returns 1 if OK
  1995. ;                ; else returns 0.
  1996. ; The structure format for use with xmmoveextended is:
  1997. ;
  1998. ;    ASM             |        C
  1999. ;--------------------------------+----------------------------------------
  2000. ; XMM_Move    struc         |    struct XMM_Move
  2001. ;                 |    {
  2002. ;   Length      dd ?         |        unsigned long   Length;
  2003. ;   SourceHandle  dw ?         |        unsigned int    SourceHandle;
  2004. ;   SourceOffset  dd ?         |        unsigned long   SourceOffset;
  2005. ;   DestHandle      dw ?         |        unsigned int    DestHandle;
  2006. ;   DestOffset      dd ?         |        unsigned long   DestOffset;
  2007. ; XMM_Move    ends         |    };
  2008. ;                 |
  2009. ;
  2010. ; Please refer to XMS spec version 2.0 for further information.
  2011.  
  2012. .data
  2013. xmscontrol    dd dword ptr (?) ; Address of driver's control function
  2014.  
  2015. .code
  2016. xmmquery    proc
  2017.     mov    ax,4300h        ; Is an XMS driver installed?
  2018.     int    2fh
  2019.     cmp    al, 80h         ; Did it succeed?
  2020.     jne    xmmqueryfailed        ; No
  2021.     mov    ax,4310h        ; Get control function address
  2022.     int    2fh
  2023.     mov    word ptr [xmscontrol], bx   ; Put address in xmscontrol
  2024.     mov    word ptr [xmscontrol+2], es ; ...
  2025.     mov    ah,00h            ; Get version number
  2026.     call [xmscontrol]
  2027.     cmp    ax,0200h        ; Is 2.00 or higher?
  2028.     jge  xmmquerydone        ; Yes
  2029. xmmqueryfailed:
  2030.     mov    ax,0            ; return failure
  2031.     mov    dx,0
  2032. xmmquerydone:
  2033.     ret
  2034. xmmquery    endp
  2035.  
  2036.  
  2037. xmmlongest    proc            ; query length of largest avail block
  2038.     mov    ah, 08h            ;
  2039.     call    [xmscontrol]
  2040.     mov    dx, 0
  2041.     ret
  2042. xmmlongest    endp
  2043.  
  2044.  
  2045. xmmallocate    proc    ksize:word
  2046.     mov    ah,09h            ; Allocate extended memory block
  2047.     mov    dx,ksize        ; size of block in Kbytes
  2048.     call    [xmscontrol]
  2049.     cmp    ax,0001h        ; did it succeed?
  2050.     jne    xmmallocatefail     ; nope
  2051.     mov    ax,dx            ; Put handle here
  2052.     jmp    short xmmallocatedone
  2053. xmmallocatefail:
  2054.     mov    ax, 0            ; Indicate failure;
  2055. xmmallocatedone:
  2056.     ret
  2057. xmmallocate    endp
  2058.  
  2059.  
  2060. xmmreallocate    proc    handle:word, newsize:word
  2061.     mov    ah, 0Fh            ; Change size of extended mem block
  2062.     mov    dx, handle        ; handle of block to reallocate
  2063.     mov    bx, newsize             ; new size for block
  2064.     call    [xmscontrol]
  2065.     cmp    ax, 0001h        ; one indicates success
  2066.     je    xmmreallocdone
  2067.     mov    ax, 0            ; we return zero for failure
  2068. xmmreallocdone:
  2069.     ret
  2070. xmmreallocate    endp
  2071.  
  2072.  
  2073. xmmdeallocate    proc    xmm_handle:word
  2074.     mov    ah,0ah            ; Deallocate extended memory block
  2075.     mov    dx, xmm_handle        ; Give it handle
  2076.     call    [xmscontrol]
  2077.     ret
  2078. xmmdeallocate    endp
  2079.  
  2080. xmmmoveextended proc uses si, MoveStruct:word
  2081.  
  2082.     ; Call the XMS MoveExtended function.
  2083.     mov    ah,0Bh
  2084.     mov    si,MoveStruct            ; the move structure.
  2085.     call    [xmscontrol]            ;
  2086.  
  2087. ; The call to xmscontrol returns a 1 in AX if successful, 0 otherwise.
  2088.  
  2089.     ret
  2090.  
  2091. xmmmoveextended endp
  2092.  
  2093.  
  2094. ; ********************* IIT FPU Chip Support Routines ******************
  2095. ;             for use with 2C87 and 3C87 FPU chips
  2096. ;
  2097. ; load_mat(double matrix[16])     ; Load a 4x4 matrix of doubles into IIT
  2098. ;                 ; IIT registers
  2099. ;
  2100. ; mult_vec_iit(double vector[3]) ; Multiply matrix times vector. Routine
  2101. ;                 ; is not completely general - makes use of
  2102. ;                 ; the fact that Fractint 3D vectors always
  2103. ;                 ; have a fourth component of 1. Only three
  2104. ;                 ; array elements are actually accessed.
  2105. ;                 ; Source and target vectors are the same.
  2106. ;
  2107. ; IITCoPro()             ; Detect IIT chip - return 1. Do not call
  2108. ;                 ; unless at least a 287 already detected.
  2109. ;
  2110. ; Code adapted by Tim Wegner from IIT documentation and detect routine
  2111. ; sent by Jonathan Osuch and modified by Charles Marslett -- 01/29/91
  2112. ;
  2113. ; The following routines were provided by IIT to implement a semaphore
  2114. ; system to protect the IIT extra registers from multi-tasking:
  2115. ;
  2116. ; F4x4Check()              ; returns 1 if semaphore TSR loaded           
  2117. ; F4x4Lock()             ; returns 1 if semaphore free and locks
  2118. ; F4x4Free()             ; frees locked semaphore
  2119.  
  2120. .286
  2121. .287
  2122. .data
  2123. one dq 1.0
  2124. .code
  2125. ;
  2126. ;load_mat(double *array)
  2127. ;
  2128. load_mat proc    array:WORD
  2129.     finit
  2130.     db    0DBh,0EBh    ; select register set 0
  2131.     fwait
  2132.     mov    bx, array
  2133.     fld    QWORD PTR [bx+64 ] ; load row 3
  2134.     fld    QWORD PTR [bx+72 ]
  2135.     fld    QWORD PTR [bx+80 ]
  2136.     fld    QWORD PTR [bx+88 ]
  2137.     fld    QWORD PTR [bx+96 ] ; load row 4
  2138.     fld    QWORD PTR [bx+104]
  2139.     fld    QWORD PTR [bx+112]
  2140.     fld    QWORD PTR [bx+120]
  2141.  
  2142.     finit
  2143.     db    0DBh,0EAh    ; select register set 1
  2144.     fld    QWORD PTR [bx+0 ] ; load row 1
  2145.     fld    QWORD PTR [bx+8 ]
  2146.     fld    QWORD PTR [bx+16]
  2147.     fld    QWORD PTR [bx+24]
  2148.     fld    QWORD PTR [bx+32] ; load row 2
  2149.     fld    QWORD PTR [bx+40]
  2150.     fld    QWORD PTR [bx+48]
  2151.     fld    QWORD PTR [bx+56]
  2152.  
  2153.     finit
  2154.     db    0DBh,0E8h    ; select register set 0
  2155.     fwait
  2156.     ret
  2157. load_mat endp
  2158.  
  2159. .code
  2160. ;
  2161. ;mult_vec_iit(vector)
  2162. ;
  2163. mult_vec_iit proc uses bx, vector:WORD
  2164.     mov    bx,vector
  2165.     fld    one ; last component always 1 in fractint
  2166. ;    fld    QWORD PTR [bx+24 ] ; 4
  2167.     fld    QWORD PTR [bx+16 ] ; 3
  2168.     fld    QWORD PTR [bx+8  ] ; 2
  2169.     fld    QWORD PTR [bx+0  ] ; 1
  2170.  
  2171.     db    0DBh,0F1h    ; multiply the column vector
  2172.     fwait
  2173.     fstp    QWORD PTR [bx+0  ] ; 1
  2174.     fstp    QWORD PTR [bx+8  ] ; 2
  2175.     fstp    QWORD PTR [bx+16 ] ; 3
  2176. ;    fstp    QWORD PTR [bx+24 ] ; 4 vectors length 3 in Fractint
  2177.  
  2178.     fwait
  2179.     ret
  2180. mult_vec_iit endp
  2181.  
  2182. ;
  2183. ; IITCoPro()
  2184. ;
  2185.  
  2186. .data
  2187. testdata db 0FFh,0FFh,00h,00h,00h,00h,00h,00h,00h,00h
  2188. .code
  2189.  
  2190. IITCoPro proc
  2191.      finit
  2192.      fld   tbyte ptr testdata
  2193.      fstp  tbyte ptr temp
  2194.      fwait
  2195.      mov   ax,word ptr temp
  2196.      or    ax,ax             ; test for 1st word of result zero
  2197.      mov   ax,1             ; return 1 if next branch taken
  2198.      jz    must_be_IIT         ;  result was zero, is IIT
  2199.      xor   ax,ax             ; return 0
  2200. must_be_IIT:
  2201.      ret
  2202. IITCoPro endp
  2203.  
  2204. .8086
  2205. .8087
  2206.  
  2207. eIIT2fService        equ    0C0h        ; user services: 0C0h - 0FFh
  2208.  
  2209. ; services provided by int 2F
  2210. eInstallationCheck    equ    0        ; <== must be zero
  2211. eSetSemaphore        equ    1
  2212. eClearSemaphore        equ    2
  2213.  
  2214. .code
  2215. F4x4Check    PROC    FAR
  2216. ; IIT F4x4 semaphore installation check
  2217.     
  2218.     inc    bp
  2219.     push    bp
  2220.     mov    bp, sp
  2221.     mov    ax, (eIIT2fService SHL 8) + eInstallationCheck
  2222.     mov    bx, 'II'
  2223.     mov    cx, 'Ts'
  2224.     mov    dx, 'em'
  2225.     int    2Fh
  2226.     cmp    ax, (eIIT2fService SHL 8) + 0FFh
  2227.     jne    not_installed
  2228.     cmp    bx, 'OK'
  2229.     jne    not_installed
  2230.     cmp    cx, ' I'
  2231.     jne    not_installed
  2232.     cmp    dx, 'IT'
  2233.     jne    not_installed
  2234. installed:
  2235.     mov    ax, 1
  2236.     pop    bp
  2237.     dec    bp
  2238.     ret
  2239. not_installed:
  2240.     xor    ax, ax
  2241.     pop    bp
  2242.     dec    bp
  2243.     ret
  2244. F4x4Check    ENDP
  2245.  
  2246.  
  2247. F4x4Lock    PROC    FAR
  2248.     inc    bp
  2249.     push    bp
  2250.     mov    bp, sp
  2251.     mov    ax, (eIIT2fService SHL 8) + eSetSemaphore 
  2252.     mov    bx, 'II'
  2253.     mov    cx, 'Ts'
  2254.     mov    dx, 'em'
  2255.     int    2Fh
  2256.     pop    bp
  2257.     dec    bp
  2258.     ret
  2259. F4x4Lock    ENDP
  2260.  
  2261.  
  2262. F4x4Free    PROC    FAR
  2263.     inc    bp
  2264.     push    bp
  2265.     mov    bp, sp
  2266.     mov    ax, (eIIT2fService SHL 8) + eClearSemaphore
  2267.     mov    bx, 'II'
  2268.     mov    cx, 'Ts'
  2269.     mov    dx, 'em'
  2270.     int    2Fh
  2271.     pop    bp
  2272.     dec    bp
  2273.     ret
  2274. F4x4Free    ENDP
  2275.     END
  2276.  
  2277.