home *** CD-ROM | disk | FTP | other *** search
/ Mega A/V / mega_av.zip / mega_av / DEMOS / FRACT386.ZIP / FRASM386.ASM < prev    next >
Assembly Source File  |  1988-11-06  |  23KB  |  664 lines

  1.  
  2. ;    FRACT386 (assembler portion)    Version 3.0    By Bert Tyler
  3.  
  4. ;    NOTE: this routine REQUIRES a 386.  It does NOT require (or use)
  5. ;    a floating point co-processor.
  6.  
  7. ;    This code relies on several tricks to run as quickly as it does.
  8.  
  9. ;    One can fake floating point arithmetic by using integer
  10. ;    arithmetic and keeping track of the implied decimal point
  11. ;    if things are reasonable -- and in this case, they are.
  12. ;    I replaced code that looked like: z = x*y with code that
  13. ;    looks like:
  14. ;            ix = x * ifudge            (outside the loops)
  15. ;            iy = y * ifudge
  16. ;            ....
  17. ;            iz = (ix * iy) / ifudge        (inside the loops)
  18. ;    (and keep remembering that all the integers are "ifudged" bigger)
  19. ;    ((Examine FUDGEFACTOR to see the factor I'm currently using))
  20.  
  21. ;    The 386 has native 32-bit integer arithmetic, and (briefly) keeps
  22. ;    64-bit values around after 32-bit multiplies.   If the result is
  23. ;    divided down right away, you've got 64-bit arithmetic.   You just
  24. ;    have to ensure that the result after the divide is <= 32 bits long.
  25.  
  26. ;    Dividing is slow -- but the 386 can perform 32-bit wide shifting
  27. ;    -- and can even perform 64-bit shifts with the following logic:
  28. ;            shdr    eax,edx,cl
  29. ;            shr    edx,cl
  30. ;    so we make sure that our "fudge factor" is a power of 2 and shift
  31. ;    it down that way.
  32.  
  33.  
  34. ;                    Bert Tyler (btyler on BIX)
  35.  
  36.  
  37. .MODEL    medium,c
  38.  
  39. .386
  40.  
  41. .CODE
  42.  
  43. FUDGEFACTOR    equ    29
  44.  
  45. ; ************************ External variables *****************************
  46.  
  47.     extrn    julia:word        ; == 0 if Mandelbrot set, else Julia
  48.     extrn    creal:dword, cimag:dword ; Julia Set Constant
  49.     extrn    lx0:dword, ly0:dword    ; arrays of (dword) increment values
  50.     extrn    dotmode: word        ; video mode:   1 = use the BIOS (yuck)
  51. ;                            2 = use EGA/VGA style
  52. ;                            3 = use MCGA style
  53.     extrn    xdots:word, ydots:word    ; number of dots across and down
  54.     extrn    maxit:word, colors:word    ; maximum iterations, colors
  55.     extrn    ixmin:word, ixmax:word    ; for zoom/pan: x and y limits
  56.     extrn    iymin:word, iymax:word    ;  for the local zoom-box
  57.  
  58. dotcount    dd    0        ; dot-counter:  0 to a*b
  59. dotwrite    dw    0        ; write-a-dot routine:  mode-specific
  60. dotread        dw    0        ; read-a-dot routine:   mode-specific
  61. x        dw    0        ; x-axis: 0 to (xdots-1)
  62. y        dw    0        ; y-axis: 0 to (ydots-1)
  63.  
  64. ;                    ; Zoom-Box values (2K x 2K screens max)
  65. boxcount    dw    0        ; (previous) box pt counter: 0 if none.
  66. boxpoints    dd    1028 dup(0)    ; (previous) box data points
  67. boxvalues    db    1028 dup(0)    ; (previous) box color values
  68.  
  69. ; ***************** Function calcdots() **********************************
  70.  
  71. calcdots proc
  72.     local    fluff1:dword        ; stack fluff for safety's sake
  73.     local    lm:dword        ; bail-out value: 4 << fudgefactor
  74.     local    lx:dword        ; local value of lx0 (from above array)
  75.     local    ly:dword        ; local value of ly0 (from above array)
  76.     local    fluff2:dword        ; stack fluff for safety's sake
  77.     local    k:word            ; local counter: 1 to maxit
  78.     local    kbdcount:word        ; keyboard counter: nnnnn to 0
  79.     local    kbdflag:word        ; keyboard hit flag: 0 if no, 1 if yes
  80.     local    fluff3:dword        ; stack fluff for safety's sake
  81.  
  82.     push    es            ; save the original ES value
  83.     mov    ax,0a000h        ; EGA, VGA, MCGA starts here
  84.     mov    es,ax            ; save it here during this routine
  85.  
  86.     mov    eax,0            ; initialize dot counter
  87.     dec    eax            ;  (to -1: it gets incremented later)
  88.     mov    dotcount,eax        ;  ...
  89.  
  90.     mov    kbdcount,ax        ; initialize keyboard counter (to -1)
  91.     mov    kbdflag,0        ; initialize keyboard int flag: nope
  92.  
  93.  
  94.                     ; prepare special video-mode speedups
  95.     cmp    dotmode,3        ; MCGA mode?
  96.     je    mcgamode        ; yup.
  97.     cmp    dotmode,2        ; EGA/VGA mode?
  98.     je    vgamode            ; yup.
  99. dullnormalmode:
  100.     mov    ax,offset normalwrite    ; set up the BIOS write-a-dot routine
  101.     mov    bx,offset normalread    ; set up the BIOS read-a-dot  routine
  102.     jmp    videomode        ; return to common code
  103. mcgamode:
  104.     mov    ax,offset mcgawrite    ; set up MCGA write-a-dot routine
  105.     mov    bx,offset mcgaread    ; set up the BIOS read-a-dot  routine
  106.     jmp    videomode        ; return to common code
  107. egamode:
  108. vgamode:
  109.     mov    ax,offset vgawrite    ; set up EGA/VGA write-a-dot routine.
  110.     mov    bx,offset vgaread    ; set up the BIOS read-a-dot  routine
  111.     jmp    videomode        ; return to common code
  112. videomode:
  113.     mov    dotwrite,ax        ; save the results
  114.     mov    dotread,bx        ;  ...
  115.  
  116.     mov    eax,4            ; initialize lm
  117.     shl    eax,FUDGEFACTOR        ;  ( == 4 << fudgefactor )
  118.     mov    lm,eax            ;  ...
  119.  
  120.     mov    y,0            ; initialize outer loop
  121.  
  122. yloop:                    ; for (y = 0; y < ydots; y++)
  123.     mov    x,0            ; initialize inner loop
  124.  
  125. xloop:                    ; for (x = 0; x < xdots; x++)
  126.     mov    bx,y            ; pull ly0 value out of the array
  127.     shl    bx,2            ; convert to double-word pointer
  128.     mov    eax,ly0[bx]        ;  here it is!
  129.     mov    ly,eax            ; save it for later
  130.  
  131.     mov    bx,x            ; pull lx0 value out of the array
  132.     shl    bx,2            ; convert to double-word pointer
  133.     mov    eax,lx0[bx]        ;  here it is!
  134.     mov    lx,eax            ; save it for later
  135.  
  136.     mov    esi,0            ; (esi == lx0) lx0 = 0
  137.     mov    edi,esi            ; (edi == ly0) ly0 = 0
  138.     mov    ebx,esi            ; (ebx == ...<calculated on the fly>)
  139.                     ;      (lx0*lx0 - ly0*ly0) / fudge = 0
  140.  
  141.     cmp    julia,0            ; julia or mandelbrot set?
  142.     je    doeither        ; Mandelbrot set:  initialization done.
  143.  
  144. dojulia:                ; Julia Set initialization
  145.                     ; "fudge" Mandelbrot start-up values
  146.     mov    ebx,lx            ; get a running start on real part
  147.     sub    ebx,creal        ;  sub, later add Creal .. and get x0!
  148.  
  149.     mov    edi,ly            ; get a running start on imag'ry part
  150.     sub    edi,cimag        ;  (subtract, later add Cimag)
  151.     mov    esi,1            ;  (multiply, later div by [2/fudge])
  152.     shl    esi,FUDGEFACTOR-1    ;   ... and we'll get y0!!!
  153.  
  154.     mov    edx,creal        ; reset real, imaginary parts of const
  155.     mov    lx,edx            ;  Creal
  156.     mov    edx,cimag        ;  ...
  157.     mov    ly,edx            ;  Cimaginary
  158.  
  159. doeither:                ; common Mandelbrot, Julia set code
  160.     mov    ax,maxit            ; setup k = maxit
  161.     mov    k,ax            ;  (decrementing to 0 is faster)
  162.  
  163.     inc    dotcount        ; increment the dot-counter
  164.  
  165.     dec    kbdcount        ; decrement the keyboard counter
  166.     jns    maxittest        ;  skip keyboard test if still positive
  167.     mov    kbdcount,5000        ; else, stuff an appropriate count val
  168.     mov    ah,1            ; check the keyboard
  169.     int    16h            ; has it been hit?
  170.     jz    maxittest        ; nope.  proceed
  171.     mov    kbdflag,1        ; yup.  reset kbd-hit flag: yes.
  172.     jmp    wedone            ; so, bail out!
  173.  
  174. maxittest:                ; timing check: avoid the main
  175.     cmp    maxit,1            ;  processing loop if maxit <= 1
  176.     jg    kloop            ;  ...
  177.     mov    maxit,1            ; avoid divides by zero
  178.     mov    k,0            ; pretend we have done 1 loop
  179.     jmp    kloopend        ; and bail out
  180.  
  181. ;    This is the main processing loop.  Here, every T-state counts...
  182.  
  183. kloop:                    ; for (k = 0; k <= maxit; k++)
  184.  
  185.     mov    eax,edi            ; compute (ly * lx)
  186.     imul    esi            ;  ...
  187.     shrd    eax,edx,FUDGEFACTOR-1    ;  ( * 2 / fudge)
  188.     add    eax,ly            ;  (above) + ly0
  189.     mov    edi,eax            ;  save this as ly
  190.  
  191. ;    (from the previous iteration)    ; compute (lx*lx - ly*ly) / fudge
  192.     add    ebx,lx            ;       + lx0
  193.     mov    esi,ebx            ; save this as lx
  194.  
  195.     mov    eax,esi            ; compute (lx * lx)
  196.     imul    esi            ;  ...
  197.     shrd    eax,edx,FUDGEFACTOR    ; ( / fudge)
  198.     shr    edx,FUDGEFACTOR-1    ; (complete 64-bit shift and check
  199.     cmp    edx,0            ;  for any overflow/sign reversals)
  200.     jne    kloopend        ; bail out if too high
  201.     mov    ecx,eax            ; save this for below
  202.     mov    eax,edi            ; compute (ly * ly)
  203.     imul    edi            ;  ...
  204.     shrd    eax,edx,FUDGEFACTOR    ; ( / fudge)
  205.     shr    edx,FUDGEFACTOR-1    ; (complete 64-bit shift and check
  206.     cmp    edx,0            ;  for any overflow/sign reversals) 
  207.     jne    kloopend        ; bail out if too high
  208.     mov    ebx,ecx            ; compute (lx*lx - ly*ly) / fudge
  209.     sub    ebx,eax            ;  for the next iteration
  210.     add    eax,ecx            ; compute (lx*lx + ly*ly) / fudge
  211.     jo    kloopend        ; bail out if too high
  212.     js    kloopend        ;  ...
  213.  
  214.     dec    k            ; while (k < maxit) (dec to 0 is faster)
  215.     jz    kloopend        ; while (k < maxit) ...
  216.  
  217.     cmp    eax,lm            ; while ( lr <= lm)
  218.     jbe    kloop            ;  ...
  219.  
  220. kloopend:
  221.  
  222.     mov    ax,maxit        ; compute color
  223.     sub    ax,k            ;  (first, re-compute "k")
  224.     sub    kbdcount,ax        ; adjust the keyboard count
  225.     cmp    ax,0            ; convert any "outlier" region 
  226.     jne    coloradjust1        ;  (where abs(x) > 2 or abs(y) > 2)
  227.     mov    ax,1            ;   to look like we ran through
  228. coloradjust1:                ;    at least one loop.
  229.     cmp    ax,maxit        ; did we max out on iterations?
  230.     jne    coloradjust2        ;  nope.
  231.     mov    ax,1            ; reset max-out color to border color
  232. coloradjust2:                ;  (it just looks better, somehow)
  233.     mov    dx,0            ;  convert to a 32-bit value
  234.     div    colors            ;  ...
  235.     mov    al,dl            ; result in al
  236.  
  237.     call    dotwrite        ; invoke the appropriate write-a-dot
  238.  
  239. loopchecks:
  240.     inc    x            ; check for end of xloop
  241.     mov    ax,xdots        ;  ...
  242.     cmp    x,ax            ;  ...
  243.     jb    xloop            ; more to go
  244.  
  245.     inc    y            ; check for end of yloop
  246.     mov    ax,ydots        ;  ...
  247.     cmp    y,ax            ;  ...
  248.     jb    yloop            ; more to go
  249.  
  250. wedone:                    ; restore everything and return.
  251.     mov    ax,dotwrite        ; check: were we in EGA/VGA mode?
  252.     cmp    ax,offset vgawrite    ;  ...
  253.     jne    wereallydone        ; nope.  no adjustments
  254.     mov    ax,0ff08h        ; restore the default bit mask
  255.     out    dx,ax            ; ...
  256.     mov    ax,0003h        ; restore the function select
  257.     out    dx,ax            ;  ...
  258.     mov    ax,0001h        ; restore the enable set/reset
  259.     out    dx,ax            ;  ...
  260. wereallydone:
  261.     pop    es            ; restore the original ES value
  262.     mov    ax,kbdflag        ; return the keyboard-interrupt flag
  263.     mov    boxcount,0        ; indicate no boxes drawn yet.
  264.     ret                ; and return.
  265.  
  266. calcdots endp
  267.  
  268. ; **************** internal Read/Write-a-dot routines ***********************
  269.  
  270. normalwrite    proc    near        ; generic write-a-dot routine
  271.     push    ax            ; save the AX register for a tad
  272.     mov    eax,dotcount        ; determine the row and cloumn
  273.     mov    edx,dotcount        ; need it in a DX:AX pair
  274.     ror    edx,16            ;  now we have it
  275.     div    xdots            ; perform the divide
  276.     mov    cx,dx            ; this is the x-coord
  277.     mov    dx,ax            ; this is the y-coord
  278.     pop    ax            ; now retrieve the AX register
  279.     mov    ah,12            ; write the dot (al == color)
  280.     mov    bx,0            ; this page
  281.     push    bp            ; some BIOS's don't save this
  282.     int    10h            ; do it.
  283.     pop    bp            ; restore the saved register
  284.     ret                ; we done.
  285. normalwrite    endp
  286.  
  287. normalread    proc    near        ; generic read-a-dot routine
  288.     mov    eax,dotcount        ; determine the row and cloumn
  289.     mov    edx,dotcount        ; need it in a DX:AX pair
  290.     ror    edx,16            ;  now we have it
  291.     div    xdots            ; perform the divide
  292.     mov    cx,dx            ; this is the x-coord
  293.     mov    dx,ax            ; this is the y-coord
  294.     mov    ah,13            ; read the dot (al == color)
  295.     mov    bx,0            ; this page
  296.     push    bp            ; some BIOS's don't save this
  297.     int    10h            ; do it.
  298.     pop    bp            ; restore the saved register
  299.     ret                ; we done.
  300. normalread    endp
  301.  
  302. mcgawrite    proc    near        ; MCGA 320*200, 246 colors
  303.     mov    ebx,dotcount        ; load up an offset register
  304.     mov    es:[bx],al        ; write the dot
  305.     ret                ; we done.
  306. mcgawrite    endp
  307.  
  308. mcgaread    proc    near        ; MCGA 320*200, 246 colors
  309.     mov    ebx,dotcount        ; load up an offset register
  310.     mov    al,es:[bx]        ; retrieve the previous value
  311.     ret                ; we done.
  312. mcgaread    endp
  313.  
  314. vgawrite    proc    near        ; EGA/VGA write mode 0
  315.     mov    bh,al            ; save the color value for a bit
  316.     mov    esi,dotcount        ; compute the buffer offset
  317.     mov    cx,si            ; and bit mask
  318.     shr    esi,3            ; (buffer offset == dotcount / 8)
  319.     and    cx,7            ; bit-mask shift calculation
  320.     xor    cl,7            ;  ...
  321.     mov    dx,03ceh        ; graphics controller address
  322.     mov    ax,0108h        ; set up controller bit mask register
  323.     shl    ah,cl            ;  ...
  324.     out    dx,ax            ;  ...
  325.     mov    ah,bh            ; set set/reset registers
  326.     mov    al,0            ;  ...
  327.     out    dx,ax            ;  ...
  328.     mov    ax,0f01h        ; enable set/reset registers
  329.     out    dx,ax            ;  ...
  330.     or    es:[si],al        ; update all bit planes
  331.     ret                ; we done.
  332. vgawrite    endp
  333.  
  334. vgaread    proc    near            ; EGA/VGA read mode 0
  335.     mov    esi,dotcount        ; compute the buffer offset
  336.     mov    cx,si            ; and bit mask
  337.     shr    esi,3            ; (buffer offset == dotcount / 8)
  338.     and    cx,7            ; bit-mask shift calculation
  339.     xor    cl,7            ;  ...
  340.     mov    ch,01h            ; bit mask to shift
  341.     shl    ch,cl            ;  ...
  342.     mov    bx,0            ; initialize bits-read value (none)
  343.     mov    dx,03ceh        ; graphics controller address
  344.     mov    ax,0304h        ; set up controller address register
  345. vgareadloop:
  346.     out    dx,ax            ; do it
  347.     mov    bh,es:[si]        ; retrieve the old value
  348.     and    bh,ch            ; mask one bit
  349.     neg    bh            ; set bit 7 correctly
  350.     rol    bx,1            ; rotate the bit into bl
  351.     dec    ah            ; go for another bit?
  352.     jge    vgareadloop        ;  sure, why not.
  353.     mov    al,bl            ; returned pixel value
  354.     ret                ; we done.
  355. vgaread    endp
  356.  
  357. ; ******************** Function drawbox() *******************************
  358.  
  359. drawbox    proc
  360.     local    fluff7:dword        ; stack fluff for safety's sake
  361.     local    xmax:dword        ; double-word copies of x and y
  362.     local    xmin:dword        ;  zoom-box minimums and maximums
  363.     local    ymax:dword        ;  ...
  364.     local    ymin:dword        ;  ...
  365.     local    dxdots:dword        ; double-word versions of total
  366.     local    dydots:dword        ;  number of x, y dots on screen
  367.     local    xstep:dword        ; box drawing: x-step increments
  368.     local    ystep:dword        ; box drawing: y-step increments
  369.     local    fluff8:dword        ; stack fluff for safety's sake
  370.     local    boxcolor:byte        ; box drawing: box color
  371.     local    fluff9:dword        ; stack fluff for safety's sake
  372.  
  373.     mov    eax,0            ; move word min, max values to dwords
  374.     mov    ax,ixmin        ;  ...
  375.     mov    xmin,eax        ;  ...
  376.     mov    ax,ixmax        ;  ...
  377.     mov    xmax,eax        ;  ...
  378.     mov    ax,iymin        ;  ...
  379.     mov    ymin,eax        ;  ...
  380.     mov    ax,iymax        ;  ...
  381.     mov    ymax,eax        ;  ...
  382.     mov    ax,xdots        ; move xdots, ydots values to dwords
  383.     mov    dxdots,eax        ;  ...
  384.     mov    ax,ydots        ;  ...
  385.     mov    dydots,eax        ;  ...
  386.  
  387.     mov    eax,1            ; default x-step:  every pixel
  388.     mov    xstep,eax        ;  ...
  389.     mov    eax,dxdots        ; default y-step:  every row
  390.     mov    ystep,eax        ;  ...
  391.     mov    eax,xmax        ; just how big is this zoom-box?
  392.     sub    eax,xmin        ;  this many dots,...
  393.     shl    eax,3            ; an eighth of the screen or less?
  394.     cmp    eax,dxdots        ;  ...
  395.     jb    solidbox        ;  yup.  keep the box solid.
  396.     mov    xstep,2            ; nope.  make the box every other pixel
  397.     mov    edx,ystep        ;  ...
  398.     add    ystep,edx        ;  ...
  399. solidbox:
  400.     shr    eax,1            ; a quarter of the screen or less?
  401.     cmp    eax,dxdots        ;  ...
  402.     jb    solidbox2        ;  yup.  keep the box (semi) solid.
  403.     mov    xstep,4            ; nope.  make the box every 4th pixel
  404.     add    ystep,edx        ;  ...
  405. solidbox2:
  406.  
  407.     mov    ax,colors        ; define the zoom-box color
  408.     dec    al            ;  ...
  409.     cmp    al,15            ; do we have 16 colors?
  410.     jbe    whitebox        ;  nope.  use what we can get.
  411.     mov    al,15            ; force a white zoom box
  412. whitebox:
  413.     mov    boxcolor,al        ; save the box color
  414.  
  415.     push    es            ; save the original ES value
  416.     mov    ax,0a000h        ; EGA, VGA, MCGA starts here
  417.     mov    es,ax            ; save it here during this routine
  418.  
  419.     mov    bx,boxcount        ; load up a counter: # points to clear
  420.     dec    bx            ; switch to an offset value
  421.     js    calcnewbox        ;  oops. no old box to clear.
  422. eraseoldbox:
  423.     shl    bx,2            ; switch to double-word counter
  424.     mov    edx,boxpoints[bx]    ; get the (previous) point location
  425.     mov    dotcount,edx        ; save it for the subroutine call
  426.     shr    bx,2            ; switch back to character counter
  427.     mov    al,boxvalues[bx]    ; get the (previous) color
  428.     push    bx            ; save the counter
  429.     call    dotwrite        ; adjust the dot.
  430.     pop    bx            ; restore the counter
  431.     dec    bx            ; are we done yet?
  432.     jns    eraseoldbox        ;  nope.  try again.
  433. calcnewbox:
  434.     mov    eax,ymin        ; calculate top-left point
  435.     mul    dxdots            ;  == yoffset * dots/xline
  436.     add    eax,xmin        ;     + xoffset
  437.     mov    boxpoints,eax        ; save it.
  438.     sub    eax,xmin        ; now calculate top-right point
  439.     add    eax,xmax        ;  ...
  440.     mov    boxpoints+4,eax        ; save it.
  441.     mov    eax,ymax        ; calculate bottom-left point
  442.     mul    dxdots            ;  == yoffset * dots/xline
  443.     add    eax,xmin        ;     + xoffset
  444.     mov    boxpoints+8,eax        ; save it.
  445.     sub    eax,xmin        ; now calculate bot-right point
  446.     add    eax,xmax        ;  ...
  447.     mov    boxpoints+12,eax    ; save it.
  448.     mov    boxcount,4        ; set flag: new box drawn.
  449.     mov    bx,boxcount        ; get set to draw lines
  450.     shl    bx,2            ; switch to double-word pointers
  451. starttop:
  452.     mov    eax,boxpoints        ; now, draw the top line.
  453.     mov    edx,xstep        ; draw every 'step'th dot
  454. topline:
  455.     add    eax,edx            ; calculate the next dot address
  456.     cmp    eax,boxpoints+4        ; gone past the end-of-line?
  457.     jae    startbottom        ;  yup.  bail out.
  458.     mov    boxpoints[bx],eax    ; save this point.
  459.     add    bx,4            ; bump up the pointer offsets
  460.     inc    boxcount        ; and counters
  461.     jmp    topline            ; and try again.
  462. startbottom:
  463.     mov    eax,boxpoints+8        ; now, draw the bottom line.
  464. bottomline:
  465.     add    eax,edx            ; calculate the next dot address
  466.     cmp    eax,boxpoints+12    ; gone past the end-of-line?
  467.     jae    startleft        ;  yup.  bail out.
  468.     mov    boxpoints[bx],eax    ; save this point.
  469.     add    bx,4            ; bump up the pointer offsets
  470.     inc    boxcount        ; and counters
  471.     jmp    bottomline        ; and try again.
  472. startleft:
  473.     mov    eax,boxpoints        ; now, draw the left line.
  474.     mov    edx,ystep        ; draw every 'step'th dot
  475. leftline:
  476.     add    eax,edx            ; calculate the next dot address
  477.     cmp    eax,boxpoints+8        ; gone past the end-of-line?
  478.     jae    startright        ;  yup.  bail out.
  479.     mov    boxpoints[bx],eax    ; save this point.
  480.     add    bx,4            ; bump up the pointer offsets
  481.     inc    boxcount        ; and counters
  482.     jmp    leftline        ; and try again.
  483. startright:
  484.     mov    eax,boxpoints+4        ; now, draw the right line.
  485. rightline:
  486.     add    eax,edx            ; calculate the next dot address
  487.     cmp    eax,boxpoints+12    ; gone past the end-of-line?
  488.     jae    endlines        ;  yup.  bail out.
  489.     mov    boxpoints[bx],eax    ; save this point.
  490.     add    bx,4            ; bump up the pointer offsets
  491.     inc    boxcount        ; and counters
  492.     jmp    rightline        ; and try again.
  493. endlines:
  494.     mov    bx,boxcount        ; load up a counter: # points to draw
  495.     dec    bx            ; switch to an offset
  496. readnewbox:
  497.     shl    bx,2            ; switch to double-word counter
  498.     mov    edx,boxpoints[bx]    ; get the (new) point location
  499.     mov    dotcount,edx        ; save it for the subroutine call
  500.     shr    bx,2            ; switch back to character counter
  501.     push    bx            ; save the counter
  502.     call    dotread            ; read the (previous) dot value
  503.     pop    bx            ; restore the counter
  504.     mov    boxvalues[bx],al    ; get the (previous) color
  505.     dec    bx            ; are we done yet?
  506.     jns    readnewbox        ;  nope.  try again.
  507.     mov    bx,boxcount        ; load up a counter: # points to draw
  508.     dec    bx            ; switch to an offset
  509. drawnewbox:
  510.     shl    bx,2            ; switch to double-word counter
  511.     mov    edx,boxpoints[bx]    ; get the (new) point location
  512.     mov    dotcount,edx        ; save it for the subroutine call
  513.     shr    bx,2            ; switch back to character counter
  514.     push    bx            ; save the counter
  515.     mov    al,boxcolor        ; set the (new) box color
  516.     call    dotwrite        ; adjust the dot.
  517.     pop    bx            ; restore the counter
  518.     dec    bx            ; are we done yet?
  519.     jns    drawnewbox        ;  nope.  try again.
  520.  
  521.     mov    ax,dotwrite        ; check: were we in EGA/VGA mode?
  522.     cmp    ax,offset vgawrite    ;  ...
  523.     jne    dotsdone        ; nope.  no adjustments
  524.     mov    ax,0ff08h        ; restore the default bit mask
  525.     out    dx,ax            ; ...
  526.     mov    ax,0003h        ; restore the function select
  527.     out    dx,ax            ;  ...
  528.     mov    ax,0001h        ; restore the enable set/reset
  529.     out    dx,ax            ;  ...
  530. dotsdone:
  531.     pop    es            ; restore ES register
  532.     ret                ; we done.
  533.  
  534. drawbox    endp
  535.  
  536. ; **************** Function setvideomode(ax, bx, cx, dx) ****************
  537.  
  538. ;    This function sets the (alphanumeric or graphic) video mode
  539. ;    of the monitor.   Called with the proper values of AX thru DX.
  540. ;    No returned values, as there is no particular standard to
  541. ;    adhere to in this case.
  542.  
  543. setvideomode    proc    argax:word, argbx:word, argcx:word, argdx:word
  544.     push    ax            ; save registers
  545.     push    bx            ;  ...
  546.     push    cx            ;  ...
  547.     push    dx            ;  ...
  548.     push    bp            ;  ...
  549.     mov    ax,argax        ; load up for the interrupt call
  550.     mov    bx,argbx        ;  ...
  551.     mov    cx,argcx        ;  ...
  552.     mov    dx,argdx        ;  ...
  553.     int    10h            ; do it.
  554.     pop    bp            ; restore registers
  555.     pop    dx            ;  ...
  556.     pop    cx            ;  ...
  557.     pop    bx            ;  ...
  558.     pop    ax            ;  ...
  559.     ret
  560. setvideomode    endp
  561.  
  562.  
  563. ; ****************** Function getakey() *****************************
  564.  
  565. ;    This function gets a key from either a "normal" or an enhanced
  566. ;    keyboard.   Returns either the vanilla ASCII code for regular
  567. ;    keys, or 1000+(the scan code) for special keys (like F1, etc)
  568. ;    Use of this routine permits the Control-Up/Down arrow keys on
  569. ;    enhanced keyboards.
  570. ;
  571. ;    The concept for this routine was "borrowed" from the MSKermit
  572. ;    SCANCHEK utility
  573.  
  574. getakey    proc
  575.     push    es                ; save ES for a tad
  576.     mov    ax,40h                ; reload ES with BIOS data seg
  577.     mov    es,ax                ;  ...
  578.     mov    ah,es:96h            ; get the keyboard byte
  579.     pop    es                ; restore ES
  580.     and    ah,10h                ; isolate the Enhanced KBD bit
  581.     int    16h                ; now get a key
  582.     cmp    al,0e0h                ; check: Enhanced Keyboard key?
  583.     jne    getakey1            ; nope.  proceed
  584.     cmp    ah,0                ; part 2 of Enhanced Key check
  585.     je    getakey1            ; failed.  normal key.
  586.     mov    al,0                ; Turn enhanced key "normal"
  587.     jmp    getakey2            ; jump to common code
  588. getakey1:            
  589.     cmp    ah,0e0h                ; check again:  Enhanced Key?
  590.     jne    getakey2            ;  nope.  proceed.
  591.     mov    ah,al                ; Turn Enhanced key "normal"
  592.     mov    al,0                ;  ...
  593. getakey2:
  594.     cmp    al,0                ; Function Key?
  595.     jne    getakey3            ;  nope.  proceed.
  596.     mov    al,ah                ; klooge into ASCII Key
  597.     mov    ah,0                ; clobber the scan code
  598.     add    ax,1000                ;  + 1000
  599.     jmp    getakey4            ; go to common return
  600. getakey3:
  601.     mov    ah,0                ; clobber the scan code
  602. getakey4:
  603.     ret
  604. getakey    endp
  605.  
  606.  
  607. ; ****************** Function cputype() *****************************
  608.  
  609. ; This program was downloaded from PC Tech Journal's Hotline service
  610. ; (it was originally in their November, 1987 issue), and is used here
  611. ; with their knowledge and permission.
  612.  
  613. ; Function cputype(), for real OR protected mode.  Returns (in AX)
  614. ; the value 86, 186, 286 or 386; negative if protected mode.
  615.  
  616.  
  617.            .286P                  ;enable protected-mode instr.
  618.  
  619. .code
  620.  
  621. cputype    proc
  622.            push    bp
  623.            push    sp             ;86/186 will push SP-2,
  624.            pop     ax             ;286/386 will push SP
  625.            cmp     ax,sp
  626.            jz      not86          ;if equal, SP was pushed
  627.            mov     ax,186         ;is it 86 or 186?
  628.            mov     cl,32          ;  186 uses count mod 32 = 0;
  629.            shl     ax,cl          ;  86 shifts 32 so ax = 0
  630.            jnz     exit           ;non-zero: no shift, so 186
  631.            mov     ax,86          ;zero: shifted out all bits
  632.            jmp     exit
  633.  
  634. not86:     pushf                  ;Test 16 or 32 operand size:
  635.            mov     ax,sp          ;  pushed 2 or 4 bytes of flags?
  636.            popf                   ;  restore SP
  637.            inc     ax             ;  restore AX by 2 bytes
  638.            inc     ax
  639.            cmp     ax,sp          ;  did pushf change SP by 2?
  640.            jnz     is32bit        ;  if not, then 4 bytes of flags
  641.  
  642. is16bit:   sub     sp,6           ;Is it 286 or 386 in 16-bit mode?
  643.            mov     bp,sp          ;allocate stack space for GDT ptr
  644.            sgdt    fword ptr[bp]  ;(use PWORD PTR for MASM5)
  645.            add     sp,4           ;discard 2 words of GDT pointer
  646.            pop     ax             ;get third word
  647.            inc     ah             ;286 stores -1, 386 0 or 1
  648.            jnz     is386
  649. is286:     mov     ax,286         ;set return value
  650.            jmp     testprot
  651.  
  652. is32bit:   db      66H            ;16-bit override in 32-bit mode
  653. is386:     mov     ax,386
  654.  
  655. testprot:  smsw    cx             ;Protected?  Machine status -> CX
  656.            ror     cx,1           ;protection bit -> carry flag
  657.            jnc     exit           ;real mode if no carry
  658.            neg     ax             ;protected:  return neg value
  659. exit:      pop     bp
  660.            ret
  661. cputype    endp
  662.  
  663.            end
  664.