home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / graf / fract4.zip / CALCMAND.ASM < prev    next >
Assembly Source File  |  1989-12-18  |  30KB  |  954 lines

  1. ;    CALCMAND.ASM - Mandelbrot/Julia Set calculation Routines
  2.  
  3. ;    The routines in this code perform Mandelbrot and Julia set
  4. ;    calculations using 32-bit integer math as opposed to the 
  5. ;    "traditional" floating-point approach.
  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.  
  20. ;    The 386 has native 32-bit integer arithmetic, and (briefly) keeps
  21. ;    64-bit values around after 32-bit multiplies.   If the result is
  22. ;    divided down right away, you've got 64-bit arithmetic.   You just
  23. ;    have to ensure that the result after the divide is <= 32 bits long.
  24. ;    CPUs predating the 386 have to emulate 32-bit arithmetic using
  25. ;    16-bit arithmetic, which is significantly slower.
  26.  
  27. ;    Dividing is slow -- but shifting is fast, and we can select our
  28. ;    "fudge factor" to be a power of two, permitting us to use that
  29. ;    method instead.   In addition, the 386 can perform 32-bit wide
  30. ;    shifting -- and even 64-bit shifts with the following logic:
  31. ;            shdr    eax,edx,cl
  32. ;            shr    edx,cl
  33. ;    so we make sure that our "fudge factor" is a power of 2 and shift
  34. ;    it down that way.
  35.  
  36.  
  37. ;                    Bert Tyler
  38.  
  39.  
  40. ;             required for compatibility if Turbo ASM
  41. IFDEF ??version
  42. MASM51
  43. QUIRKS
  44. ENDIF
  45.  
  46. .MODEL    medium,c
  47.  
  48. .8086
  49.  
  50.         ; these must NOT be in any segment!!
  51.         ; this get's rid of TURBO-C fixup errors
  52.  
  53.     extrn    asmdotwrite:far        ; this routine is in 'general.asm'
  54.     extrn    asmvideocleanup:far    ; this routine is in 'general.asm'
  55.     extrn    keypressed:far        ; this routine is in 'general.asm'
  56.     extrn    getakey:far        ; this routine is in 'general.asm'
  57.     extrn    iplot_orbit:far        ; this routine is in 'calcfrac.c'
  58.     extrn    scrub_orbit:far        ; this routine is in 'calcfrac.c'
  59.     extrn    intpotential:far    ; this routine is in 'calcfrac.c'
  60.  
  61. .DATA
  62.  
  63. FUDGEFACTOR    equ    29        ; default (non-potential) fudgefactor
  64. FUDGEFACTOR2    equ    24        ; potential algoithm variant
  65.  
  66. ; ************************ External variables *****************************
  67.  
  68.     extrn    fractype:word        ; == 0 if Mandelbrot set, else Julia
  69.     extrn    numpasses:word        ; == 0 if single-pass, 1 if 2-pass
  70.     extrn    inside:word        ; "inside" color, normally 1 (blue)
  71.     extrn    creal:dword, cimag:dword ; Julia Set Constant
  72.     extrn    lx0:dword, ly0:dword    ; arrays of (dword) increment values
  73.     extrn    delx:dword, dely:dword    ; actual increment values
  74.     extrn    xdots:word, ydots:word    ; number of dots across and down
  75.     extrn    maxit:word, colors:word    ; maximum iterations, colors
  76.     extrn    bitshift:word        ; number of bits to shift
  77.     extrn    lm:dword        ; magnitude bailout limit
  78.     extrn    potflag:word        ; "continuous potential" flag
  79.     extrn    LogFlag:word        ; non-zero of logarithmic palettes
  80.     extrn    LogTable:dword        ; far pointer to log palette table
  81.  
  82.     extrn    ixstart:word, ixstop:word ; start, stop here
  83.     extrn    iystart:word, iystop:word ; start, stop here
  84.     extrn    guessing:word          ; == 1 if solid-guessing
  85.  
  86.     extrn    cpu:word        ; cpu type: 86, 186, 286, or 386
  87.  
  88.     extrn    andcolor:word        ; "and" value used for color selection
  89.  
  90.     extrn    show_orbit:word        ; "show-orbit" flag
  91.     extrn    orbit_ptr:word        ; "orbit pointer" flag
  92.  
  93.     extrn    symmetry:word        ; "Symmetry" flag
  94.  
  95.     extrn    debugflag:word        ; for debugging purposes only
  96.  
  97. ; ************************ Internal variables *****************************
  98.  
  99. passnum        db    0        ; pass number: 1 (blitz) or 0
  100.  
  101. ix        dw    0        ; x-axis: 0 to (xdots-1)
  102. iy        dw    0        ; y-axis: 0 to (ydots-1)
  103. x        dd    0        ; temp value: x
  104. y        dd    0        ; temp value: y
  105. a        dd    0        ; temp value: a
  106. b        dd    0        ; temp value: b
  107. xx        dd    0        ; temp value: x-squared
  108. yy        dd    0        ; temp value: y-squared
  109. xy        dd    0        ; temp value: x-times-y
  110. xxmyy        dd    0        ; temp value: x-squared minus y-squared
  111. sign        db    0        ; sign calue: used by 16-bit multiplies
  112. temp        dw    4 dup (0)    ; temp value: used by 16-bit multiplies
  113. k        dw    0        ; local counter
  114. kbdcount    dw    0        ; keyboard counter
  115. kbdflag        dw    0        ; keyboard hit flag: 0 if no, 1 if yes
  116. color        db    0        ; the color to set a pixel
  117. oldcolor    dw    0        ; == "old" color
  118. period        db    0        ; periodicity, if in the lake
  119. savedand    dw    0        ; AND value for periodicity checks
  120. savedincr    dw    0        ; flag for incrementing AND value
  121. savedmask    dd    0        ; saved values mask
  122. savedmax    dd    0        ; saved max(delx, dely)
  123. savedx        dd    0        ; saved values of X and Y iterations
  124. savedy        dd    0        ;  (for periodicity checks)
  125.  
  126. .CODE
  127.  
  128. ; ***************** Function calcmand() **********************************
  129.  
  130. calcmand proc    uses di si es
  131.  
  132.     push    es            ; save the original ES value
  133.     mov    ax,0a000h        ; EGA, VGA, MCGA starts here
  134.     mov    es,ax            ; save it here during this routine
  135.  
  136.     mov    ax,word ptr delx    ; compute the periodicity check value
  137.     mov    dx,word ptr delx+2    ; first find largest of delx, dely
  138.     or    ax,word ptr dely    ; (only care about the first bit,
  139.     or    dx,word ptr dely+2    ;  so this klooge works)
  140.     mov    word ptr savedmax,ax    ; save this for later
  141.     mov    word ptr savedmax+2,dx    ;  ...
  142.     mov    word ptr savedmask,0    ; starting value for savedmask
  143.     mov    word ptr savedmask+2,0c000h    ;  ...
  144. maskloop:
  145.     sar    word ptr savedmask+2,1    ; shift savedmask right one bit
  146.     rcr    word ptr savedmask,1    ;  ...
  147.     shl    ax,1            ; now shift delx.y left one bit
  148.     rcl    dx,1            ;  ...
  149.     jnc    maskloop        ; loop if no one bits hit yet
  150.  
  151.     mov    kbdcount,-1        ; initialize keyboard counter (to -1)
  152.     mov    kbdflag,0        ; initialize keyboard int flag: nope
  153.  
  154.     mov    ax,numpasses        ; detect 1 or 2-pass mode
  155.     mov    passnum,al        ; initialize pass counter
  156.     cmp    guessing,2        ; are we guessing and on pass 2?
  157.     jne    passloop        ; nope.  proceed.
  158.     dec    passnum            ;  else, assume pass #2.
  159.  
  160. passloop:
  161.     mov    ax,iystart        ; initialize outer loop
  162.     mov    iy,ax            ;  ...
  163.  
  164. yloop:                    ; for (y = iystart; y <= iystop; y++)
  165.     mov    ax,ixstart        ; initialize inner loop
  166.     mov    ix,ax            ;  ...
  167.     mov    oldcolor,0        ; set (dummy) flag: old color was high
  168.     cmp    maxit,250        ; over 250 iterations max?
  169.     jbe    xloop            ;  nope.
  170.     mov    bx,maxit        ; yup.  reset oldcolor
  171.     sub    bx,250            ;  to maxit-250.
  172.     mov    oldcolor,bx        ;  (avoids slowness at 32000 iters)
  173.  
  174. xloop:                    ; for (x = ixstart; x <= ixstop; x++)
  175.     mov    bx,ix            ; pull lx0 value out of the array
  176.     shl    bx,1            ; convert to double-word pointer
  177.     shl    bx,1            ;  ...
  178.     mov    ax,word ptr lx0[bx]    ;  here it is!
  179.     mov    dx,word ptr lx0+2[bx]    ;  ...
  180.     mov    word ptr a,ax        ; save it for later
  181.     mov    word ptr a+2,dx        ;  ...
  182.  
  183.     mov    bx,iy            ; pull ly0 value out of the array
  184.     shl    bx,1            ; convert to double-word pointer
  185.     shl    bx,1            ;  ...
  186.     mov    ax,word ptr ly0[bx]    ;  here it is!
  187.     mov    dx,word ptr ly0+2[bx]    ;  ...
  188.     mov    word ptr b,ax        ; save it for later
  189.     mov    word ptr b+2,dx        ;  ...
  190.  
  191.     mov    ax,word ptr creal    ; initialize x == creal
  192.     mov    dx,word ptr creal+2    ;  ...
  193.     mov    word ptr x,ax        ;  ...
  194.     mov    word ptr x+2,dx        ;  ...
  195.  
  196.     mov    ax,word ptr cimag    ; initialize y == cimag
  197.     mov    dx,word ptr cimag+2    ;  ...
  198.     mov    word ptr y,ax        ;  ...
  199.     mov    word ptr y+2,dx        ;  ...
  200.  
  201.     mov    ax,maxit        ; setup k = maxit
  202.     inc    ax            ; (+ 1)
  203.     mov    k,ax            ;  (decrementing to 0 is faster)
  204.  
  205.     cmp    fractype,1        ; julia or mandelbrot set?
  206.     je    short dojulia        ; julia set - go there
  207.  
  208. ;    (Tim wants this code changed so that, for the Mandelbrot,
  209. ;    Z(1) = (x + iy) + (a + ib).  Affects only "fudged" Mandelbrots.
  210. ;    (for the "normal" case, a = b = 0, and this works, too) 
  211. ;    cmp    word ptr x,0        ; Mandelbrot shortcut:
  212. ;    jne    short doeither        ;  if creal = cimag = 0,
  213. ;    cmp    word ptr x+2,0        ; the first iteration can be emulated.
  214. ;    jne    short doeither        ;  ...
  215. ;    cmp    word ptr y,0        ;  ...
  216. ;    jne    short doeither        ;  ...
  217. ;    cmp    word ptr y+2,0        ;  ...
  218. ;    jne    short doeither        ;  ...
  219. ;    dec    k            ; we know the first iteration passed
  220. ;    mov    dx,word ptr a+2        ; copy x = a
  221. ;    mov    ax,word ptr a        ;  ...
  222. ;    mov    word ptr x+2,dx        ;  ...
  223. ;    mov    word ptr x,ax        ;  ...
  224. ;    mov    dx,word ptr b+2        ; copy y = b
  225. ;    mov    ax,word ptr b        ;  ...
  226. ;    mov    word ptr y+2,dx        ;  ...
  227. ;    mov    word ptr y,ax        ;  ...
  228.  
  229.     dec    k            ; we know the first iteration passed
  230.     mov    dx,word ptr a+2        ; add x += a
  231.     mov    ax,word ptr a        ;  ...
  232.     add    word ptr x,ax        ;  ...
  233.     adc    word ptr x+2,dx        ;  ...
  234.     mov    dx,word ptr b+2        ; add y += b
  235.     mov    ax,word ptr b        ;  ...
  236.     add    word ptr y,ax        ;  ...
  237.     adc    word ptr y+2,dx        ;  ...
  238.     jmp    short doeither        ; branch around the julia switch
  239.  
  240. dojulia:                ; Julia Set initialization
  241.                     ; "fudge" Mandelbrot start-up values
  242.     mov    ax,word ptr x        ; switch x with a
  243.     mov    dx,word ptr x+2        ;  ...
  244.     mov    bx,word ptr a        ;  ...
  245.     mov    cx,word ptr a+2        ;  ...
  246.     mov    word ptr x,bx        ;  ...
  247.     mov    word ptr x+2,cx        ;  ...
  248.     mov    word ptr a,ax        ;  ...
  249.     mov    word ptr a+2,dx        ;  ...
  250.  
  251.     mov    ax,word ptr y        ; switch y with b
  252.     mov    dx,word ptr y+2        ;  ...
  253.     mov    bx,word ptr b        ;  ...
  254.     mov    cx,word ptr b+2        ;  ...
  255.     mov    word ptr y,bx        ;  ...
  256.     mov    word ptr y+2,cx        ;  ...
  257.     mov    word ptr b,ax        ;  ...
  258.     mov    word ptr b+2,dx        ;  ...
  259.  
  260. doeither:                ; common Mandelbrot, Julia set code
  261.  
  262.     cmp    numpasses,0        ; multiple-pass mode?
  263.     jz    short singlepass    ;  nope.  proceed.
  264.     cmp    passnum,0        ; second pass?
  265.     jne    short singlepass    ;  nope.  proceed
  266.     test    iy,1            ; odd dot?
  267.     jnz    short singlepass    ;  yup.  proceed.
  268.     test    ix,1            ; odd dot?
  269.     jnz    short singlepass    ;  yup.  proceed.
  270.     jmp    loopchecks        ;  nope. skip it.
  271. singlepass:
  272.  
  273.     mov    period,0        ; claim periodicity of 1
  274.     mov    savedand,1        ; initial periodicity check
  275.     mov    savedincr,1        ;  flag for incrementing periodicity
  276.     mov    word ptr savedx+2,0ffffh; impossible value of "old" x
  277.     mov    word ptr savedy+2,0ffffh; impossible value of "old" y
  278.     mov    orbit_ptr,0        ; clear orbits
  279.  
  280.     dec    kbdcount        ; decrement the keyboard counter
  281.     jns    short nokey        ;  skip keyboard test if still positive
  282.     mov    kbdcount,10        ; stuff in a low kbd count
  283.     cmp    show_orbit,0        ; are we showing orbits?
  284.     jne    quickkbd        ;  yup.  leave it that way.
  285.     mov    kbdcount,5000        ; else, stuff an appropriate count val
  286.     cmp    cpu,386            ; ("appropriate" to the CPU)
  287.     je    short quickkbd        ;  ...
  288.     cmp    word ptr savedmax+2,1    ; is 16-bit math good enough?
  289.     ja    quickkbd        ;  yes. test less often
  290.     mov    kbdcount,500        ;  no.  test more often
  291. quickkbd:
  292.     call    far ptr keypressed    ; has a key been pressed?
  293.     cmp    ax,0            ;  ...
  294.      je    nokey            ; nope.  proceed
  295.         cmp    ax,'o'            ; orbit toggle hit?
  296.     je    orbitkey        ;  yup.  show orbits
  297.     cmp    ax,'O'            ; orbit toggle hit?
  298.     jne    keyhit            ;  nope.  normal key.
  299. orbitkey:
  300.     call    far ptr getakey        ; read the key for real
  301.     mov    ax,1            ; reset orbittoggle = 1 - orbittoggle
  302.     sub    ax,show_orbit        ;  ...
  303.     mov    show_orbit,ax        ;  ...
  304.     mov    kbdcount,10        ; adjust the keyboard
  305.     jmp    short nokey        ; pretend no key was hit
  306. keyhit:    mov    kbdflag,1        ; yup.  reset kbd-hit flag: yes.
  307.     jmp    wedone            ; so, bail out!
  308.  
  309. nokey:
  310.     cmp    show_orbit,0        ; is orbiting on?
  311.     jne    no16bitcode        ;  yup.  slow down.
  312.     cmp    word ptr savedmax+2,3    ; is 16-bit math good enough?
  313.     ja    yes16bitcode        ;  YAY!!  16-bit speed!
  314.     cmp    cpu,386            ; are we on a 386?
  315.     je    short code386bit    ;  YAY!! 386-class speed!
  316.     cmp    word ptr savedmax+2,1    ; OK, we're desperate.  16 bits OK?
  317.     ja    yes16bitcode        ;  YAY!  16-bit speed!
  318. no16bitcode:
  319.     call    near ptr code32bit    ; BOO!! nap time.  Full 32 bit math
  320.     jmp    kloopend        ;  bypass the 386-specific code.
  321. yes16bitcode:
  322.     call    near ptr code16bit    ; invoke the 16-bit version
  323.     jmp    kloopend        ;  bypass the 386-specific code.
  324.  
  325. .386                    ; 386-specific code starts here
  326.  
  327. code386bit:
  328.     mov    esi,x            ; use ESI for X
  329.     mov    edi,y            ; use EDI for Y
  330.  
  331. ;    This is the main processing loop.  Here, every T-state counts...
  332.  
  333.     cmp    bitshift,29        ; only pathalogical concern for speed
  334.     jne    kloop24            ; causes us to use two algorithms here
  335.  
  336. kloop:                    ; for (k = 0; k <= maxit; k++)
  337.  
  338.     mov    eax,esi            ; compute (x * x)
  339.     imul    esi            ;  ...
  340.     shrd    eax,edx,FUDGEFACTOR    ; ( / fudge)
  341.     shr    edx,FUDGEFACTOR-1    ; (complete 64-bit shift and check
  342.     cmp    edx,0            ;  for any overflow/sign reversals)
  343.     jne    short kloopend1        ; bail out if too high
  344.     mov    ebx,eax            ; save this for below
  345.  
  346.     mov    eax,edi            ; compute (y * y)
  347.     imul    edi            ;  ...
  348.     shrd    eax,edx,FUDGEFACTOR    ; ( / fudge)
  349.     shr    edx,FUDGEFACTOR-1    ; (complete 64-bit shift and check
  350.     cmp    edx,0            ;  for any overflow/sign reversals) 
  351.     jne    short kloopend1        ; bail out if too high
  352.  
  353.     mov    ecx,ebx            ; compute (x*x - y*y) / fudge
  354.     sub    ebx,eax            ;  for the next iteration
  355.  
  356.     add    ecx,eax            ; compute (x*x + y*y) / fudge
  357.     jo    short kloopend1        ; bail out if too high
  358.     js    short kloopend1        ;  ...
  359.     cmp    ecx,lm            ; while (lr < lm)
  360.     jae    short kloopend1        ;  ...
  361.  
  362.     mov    eax,edi            ; compute (y * x)
  363.     imul    esi            ;  ...
  364.     shrd    eax,edx,FUDGEFACTOR-1    ;  ( * 2 / fudge)
  365.     add    eax,b            ;  (above) + b
  366.     mov    edi,eax            ;  save this as y
  367.  
  368. ;    (from the earlier code)        ; compute (x*x - y*y) / fudge
  369.     add    ebx,a            ;       + a
  370.     mov    esi,ebx            ; save this as x
  371.  
  372.     mov    ax,oldcolor        ; recall the old color
  373.     cmp    ax,k            ; check it against this iter
  374.     jb    short nonmax1        ;  nope.  bypass periodicity check.
  375.     mov    x,esi            ; save x and y
  376.     mov    y,edi            ; for the periodicity check
  377.     call    checkperiod        ; check for periodicity
  378. nonmax1:
  379.  
  380.     dec    k            ; while (k < maxit) (dec to 0 is faster)
  381.     jnz    short kloop        ; while (k < maxit) ...
  382. kloopend1:
  383.     jmp    kloopend32        ; we done.
  384.  
  385. kloop24:                ; for (k = 0; k <= maxit; k++)
  386.  
  387.     mov    eax,esi            ; compute (x * x)
  388.     imul    esi            ;  ...
  389.     shrd    eax,edx,FUDGEFACTOR2    ; ( / fudge)
  390.     shr    edx,FUDGEFACTOR2-1    ; (complete 64-bit shift and check
  391.     cmp    edx,0            ;  for any overflow/sign reversals)
  392.     jne    short kloopend32    ; bail out if too high
  393.     mov    ebx,eax            ; save this for below
  394.  
  395.     mov    eax,edi            ; compute (y * y)
  396.     imul    edi            ;  ...
  397.     shrd    eax,edx,FUDGEFACTOR2    ; ( / fudge)
  398.     shr    edx,FUDGEFACTOR2-1    ; (complete 64-bit shift and check
  399.     cmp    edx,0            ;  for any overflow/sign reversals) 
  400.     jne    short kloopend32    ; bail out if too high
  401.  
  402.     mov    ecx,ebx            ; compute (x*x - y*y) / fudge
  403.     sub    ebx,eax            ;  for the next iteration
  404.  
  405.     add    ecx,eax            ; compute (x*x + y*y) / fudge
  406.     mov    dword ptr temp+4,ecx    ; save the last iteration value here
  407.     jo    short kloopend32    ; bail out if too high
  408.     js    short kloopend32    ;  ...
  409.     cmp    ecx,lm            ; while (lr < lm)
  410.     jae    short kloopend32    ;  ...
  411.  
  412.     mov    eax,edi            ; compute (y * x)
  413.     imul    esi            ;  ...
  414.     shrd    eax,edx,FUDGEFACTOR2-1    ;  ( * 2 / fudge)
  415.     add    eax,b            ;  (above) + b
  416.     mov    edi,eax            ;  save this as y
  417.  
  418. ;    (from the earlier code)        ; compute (x*x - y*y) / fudge
  419.     add    ebx,a            ;       + a
  420.     mov    esi,ebx            ; save this as x
  421.  
  422.     mov    ax,oldcolor        ; recall the old color
  423.     cmp    ax,k            ; check it against this iter
  424.     jb    short nonmax241        ;  nope.  bypass periodicity check.
  425.     mov    x,esi            ; save x and y
  426.     mov    y,edi            ; for the periodicity check
  427.     call    checkperiod        ; check for periodicity
  428. nonmax241:
  429.  
  430.     dec    k            ; while (k < maxit) (dec to 0 is faster)
  431.     jnz    short kloop24        ; while (k < maxit) ...
  432.     jmp    kloopend32        ; we done.
  433.  
  434.  
  435. kloopend32:
  436.  
  437. .8086                    ; 386-specific code ends here
  438.  
  439. kloopend:
  440.     cmp    orbit_ptr,0        ; any orbits to clear?
  441.     je    noorbit2        ;  nope.
  442.     push    es            ; save es
  443.     call    far ptr scrub_orbit    ; clear out any old orbits
  444.     pop    es            ; restore es
  445. noorbit2:
  446.  
  447.     mov    ax,k            ; set old color
  448.     sub    ax,10            ; minus 10, for safety
  449.     mov    oldcolor,ax        ; and save it as the "old" color
  450.     mov    ax,maxit        ; compute color
  451.     sub    ax,k            ;  (first, re-compute "k")
  452.     sub    kbdcount,ax        ; adjust the keyboard count
  453.     cmp    ax,1            ; convert any "outlier" region 
  454.     jge    short coloradjust1    ;  (where abs(x) > 2 or abs(y) > 2)
  455.     mov    ax,1            ;   to look like we ran through
  456. coloradjust1:                ;    at least one loop.
  457.     cmp    ax,maxit        ; did we max out on iterations?
  458.     jne    short coloradjust2    ;  nope.
  459.     mov    oldcolor,ax        ; set "oldcolor" to maximum
  460.     add    oldcolor,10        ;  plus a few
  461.     cmp    inside,0        ; is "inside" >= 0?
  462.     jl    coloradjust2        ;  nope.  leave it at "maxit"
  463.     mov    ax,inside        ; reset max-out color to default
  464.     cmp    debugflag,98        ; show periodicity matches?
  465.     jne    coloradjust2        ;  nope.
  466.     mov    al,period        ;  reset color to periodicity flag
  467. coloradjust2:                ;  
  468.     cmp    potflag,0        ; continuous potential algorithm?
  469.     je    coloradjust3        ;  nope.  proceed.
  470.     push    es            ; prepare to call intpotential
  471.     push    ax            ; parameter #2 == the color
  472.     mov    ax,word ptr temp+6    ; parameter #1 == the overflow value
  473.     push    ax            ;  ...
  474.     mov    ax,word ptr temp+4    ;  ...
  475.     push    ax            ;  ...
  476.     call    far ptr intpotential    ; convert the color to potential
  477.     pop    es            ; restore the stack and registers
  478.     pop    es            ;  ...
  479.     pop    es            ;  ...
  480.     pop    es            ;  ...
  481. coloradjust3:                ;  
  482.     cmp    LogFlag,0        ; are log palettes set?
  483.     je    coloradjust4        ;  nope.  don't use log palettes.
  484.     push    es            ; save some registers
  485.     push    si            ;  ...
  486.     les    si,LogTable        ; get the address of the Log Table
  487.     add    si,ax            ; find the offset of the color
  488.     mov    al,es:0[si]        ; replace the color value
  489.     mov    ah,0            ;  ...
  490.     pop    si            ; restore the registers
  491.     pop    es            ;  ...
  492. coloradjust4:                ;  
  493.     and    ax,andcolor        ; select the color
  494.     mov    color,al        ; color result
  495.  
  496.     mov    cx,ix            ; set up the registers
  497.     mov    dx,iy            ; for the write routine
  498.     mov    al,color        ; color to use
  499.     call    asmdotwrite        ; invoke the appropriate write-a-dot
  500.  
  501.     cmp    symmetry,0        ; does symmetry apply?
  502.     jne    short passcheck        ; nope.  proceed.
  503.  
  504.     mov    cx,ix            ; set up the registers
  505.     mov    dx,ydots        ; for the write routine
  506.     sub    dx,iy            ;  (symmetrical version)
  507.     dec    dx            ;  ...
  508.     cmp    fractype,0        ; Mandelbrot set?
  509.     je    sym01            ;  yup.  Skip Julia symmetry
  510.     neg    cx            ; convert ix 
  511.     add    cx,xdots        ;  to (xdots-1-ix)
  512.     dec    cx            ;  ...
  513. sym01:    mov    al,color        ; color to use
  514.     call    asmdotwrite        ; invoke the appropriate write-a-dot
  515.  
  516. passcheck:
  517.     cmp    passnum,0        ; final pass?
  518.     jne    passcheck1        ;  nope. write more dots.
  519.     jmp    loopchecks        ; yup.  proceed.
  520. passcheck1:
  521.     mov    cx,ix            ; set up the registers
  522.     mov    dx,iy            ; for the write routine
  523.     inc    cx            ; (but for the next x-dot)
  524.     mov    al,color        ; color to use
  525.     call    asmdotwrite        ; write the dot again
  526.     mov    cx,ix            ; set up the registers
  527.     mov    dx,iy            ; for the write routine
  528.     inc    dx            ; (but for the next y-dot)
  529.     mov    al,color        ; color to use
  530.     call    asmdotwrite        ; write the dot again
  531.     mov    cx,ix            ; set up the registers
  532.     mov    dx,iy            ; for the write routine
  533.     inc    cx            ; (but for the next x-dot)
  534.     inc    dx            ; (and the next y-dot)
  535.     mov    al,color        ; color to use
  536.     call    asmdotwrite        ; write the dot again
  537.     inc    ix            ; note extra dots have been written
  538.  
  539.     cmp    symmetry,0        ; does symmetry apply?
  540.     jne    short loopchecks    ; nope.  proceed.
  541.  
  542.     mov    cx,ix            ; set up the registers
  543.     mov    dx,ydots        ; for the write routine
  544.     sub    dx,iy            ;  (symmetrical version)
  545.     dec    dx            ;  ...
  546.     cmp    fractype,0        ; Mandelbrot set?
  547.     je    sym02            ;  yup.  Skip Julia symmetry
  548.     neg    cx            ; convert ix 
  549.     add    cx,xdots        ;  to (xdots-1-ix)
  550.     dec    cx            ;  ...
  551. sym02:    mov    al,color        ; color to use
  552.     call    asmdotwrite        ; write the dot again
  553.     mov    cx,ix            ; set up the registers
  554.     mov    dx,ydots        ; for the write routine
  555.     sub    dx,iy            ;  (symmetrical version)
  556.     dec    dx            ;  ...
  557.     dec    cx            ; (but for the previous x-dot)
  558.     dec    dx            ; (but for the previous y-dot)
  559.     cmp    fractype,0        ; Mandelbrot set?
  560.     je    sym03            ;  yup.  Skip Julia symmetry
  561.     neg    cx            ; convert ix 
  562.     add    cx,xdots        ;  to (xdots-1-ix)
  563.     dec    cx            ;  ...
  564. sym03:    mov    al,color        ; color to use
  565.     call    asmdotwrite        ; write the dot again
  566.     mov    cx,ix            ; set up the registers
  567.     mov    dx,ydots        ; for the write routine
  568.     sub    dx,iy            ;  (symmetrical version)
  569.     dec    dx            ;  ...
  570.     dec    dx            ; (and the previous y-dot)
  571.     cmp    fractype,0        ; Mandelbrot set?
  572.     je    sym04            ;  yup.  Skip Julia symmetry
  573.     neg    cx            ; convert ix 
  574.     add    cx,xdots        ;  to (xdots-1-ix)
  575.     dec    cx            ;  ...
  576. sym04:    mov    al,color        ; color to use
  577.     call    asmdotwrite        ; write the dot again
  578.  
  579. loopchecks:
  580.     inc    ix            ; check for end of xloop
  581.     mov    ax,ix            ;  ...
  582.     cmp    ax,ixstop        ;  ...
  583.     ja    loopcheck1        ; we done.
  584.     jmp    xloop            ; more to go
  585. loopcheck1:
  586.  
  587.     cmp    passnum,0        ; last pass?
  588.     je    short    lastpass    ;  yup.  proceed.
  589.     inc    iy            ; adjust y-value
  590. lastpass:
  591.  
  592.     inc    iy            ; check for end of yloop
  593.     mov    ax,iy            ;  ...
  594.     cmp    ax,iystop        ;  ...
  595.     ja    loopcheck2        ; we done.
  596.     cmp    symmetry,0        ; does symmetry apply?
  597.     je    symcheck2        ;  yup.  go check.
  598.     jmp    yloop            ;  nope.  more to go
  599.  
  600. symcheck2:                ; symmetry applies
  601.     mov    ax,ydots        ; gather the total dot count
  602.     shr    ax,1            ; are we done with the top half?
  603.     cmp    iy,ax            ;  ...
  604.     jae    loopcheck2        ; yup.  we done.
  605.     jmp    yloop            ; nope.  more to go
  606.  
  607. loopcheck2:
  608.  
  609.     dec    passnum            ; decrement the pass counter
  610.     js    loopcheck3        ; we done.
  611.     cmp    guessing,1        ; are we guessing?
  612.     je    loopcheck3        ;  yes.  we're done.
  613.     jmp    passloop        ; more to go
  614. loopcheck3:
  615.  
  616. wedone:                    ; restore everything and return.
  617.     call    asmvideocleanup        ; perform any video cleanup required
  618.     pop    es            ; restore the original ES value
  619.     mov    ax,kbdflag        ; return the keyboard-interrupt flag
  620.     ret                ; and return.
  621.  
  622. calcmand endp
  623.  
  624. ; ******************** Function code16bit() *****************************
  625. ;
  626. ;    Performs "short-cut" 16-bit math where we can get away with it.
  627. ;
  628.  
  629. code16bit    proc    near
  630.  
  631.     mov    si,word ptr x+2        ; use SI for X
  632.     mov    di,word ptr y+2        ; use DI for Y
  633.  
  634. start16bit:
  635.     mov    ax,si            ; compute (x * x)
  636.     imul    si            ;  ...
  637.     cmp    dx,0            ; say, did we overflow? <V20-compat>
  638.     jl    end16bit        ;  (oops.  We done.)
  639.     mov    cx,32            ; ( / fudge)
  640.     sub    cx,bitshift        ;  ...
  641. loop16bit1:
  642.     shl    ax,1            ;  ...
  643.     rcl    dx,1            ;  ...
  644.     jo    end16bit        ;  (oops.  overflow)
  645.     loop    loop16bit1        ;  ...
  646.     mov    bx,dx            ; save this for a tad
  647.  
  648.     mov    ax,di            ; compute (y * y)
  649.     imul    di            ;  ...
  650.     cmp    dx,0            ; say, did we overflow? <V20-compat>
  651.     jl    end16bit        ;  (oops.  We done.)
  652.     mov    cx,32            ; ( / fudge)
  653.     sub    cx,bitshift        ;  ...
  654. loop16bit2:
  655.     shl    ax,1            ;  ...
  656.     rcl    dx,1            ;  ...
  657.     jo    end16bit        ;  (oops.  overflow)
  658.     loop    loop16bit2        ;  ...
  659.  
  660.     mov    cx,bx            ; compute (x*x - y*y) / fudge
  661.     sub    bx,dx            ;  for the next iteration
  662.  
  663.     add    cx,dx            ; compute (x*x + y*y) / fudge
  664.     mov    word ptr temp+6,cx    ; save last iteration value here
  665.     jo    end16bit        ; bail out if too high
  666.     js    end16bit        ;  ...
  667.  
  668.     cmp    cx,word ptr lm+2    ; while (xx+yy < lm)
  669.     jae    end16bit        ;  ...    
  670.  
  671.     mov    ax,di            ; compute (y * x)
  672.     imul    si            ;  ...
  673.     mov    cx,33            ; ( * 2 / fudge)
  674.     sub    cx,bitshift        ;  ...
  675. loop16bit3:
  676.     shl    ax,1            ;  ...
  677.     rcl    dx,1            ;  ...
  678.     loop    loop16bit3        ;  ...
  679.     add    dx,word ptr b+2        ; (2*y*x) / fudge + b
  680.     mov    di,dx            ; save as y
  681.  
  682.     add    bx,word ptr a+2        ; (from above) (x*x - y*y)/fudge + a
  683.     mov    si,bx            ; save as x
  684.  
  685.     mov    ax,oldcolor        ; recall the old color
  686.     cmp    ax,k            ; check it against this iter
  687.     jb    short nonmax3        ;  nope.  bypass periodicity check.
  688.     mov    word ptr x+2,si        ; save x for periodicity check
  689.     mov    word ptr y+2,di        ; save y for periodicity check
  690.     call    checkperiod        ; check for periodicity
  691. nonmax3:
  692.  
  693.     dec    k            ; while (k < maxit)
  694.     jz    end16bit        ;  we done.
  695.  
  696.     jmp    start16bit        ; try, try again.
  697.  
  698. end16bit:                ; we done.
  699.     ret
  700. code16bit    endp
  701.  
  702. ; ******************** Function code32bit() *****************************
  703. ;
  704. ;    Perform the 32-bit logic required using 16-bit logic
  705.  
  706. ;    mult32bit performs 32bit x 32bit signed multiplies, with
  707. ;    (temporary) 64-bit results, and the appropriate right-shift
  708. ;    ( >> FUDGEFACTOR) before returning.   That's why it is so long.
  709. ;        arguments in SI:BX and DI:CX, results in DX:AX
  710.  
  711. mult32bit    proc near
  712.  
  713.     mov    ax,0
  714.     mov    temp+4,ax        ; first, clear out the (temporary)
  715.     mov    temp+6,ax        ;  result
  716.  
  717.     mov    sign,0            ; clear out the sign flag
  718.     cmp    si,0            ; is SI:BX negative?
  719.     jge    mults1            ;  nope
  720.     not    sign            ;  yup.  flip signs
  721.     not    bx            ;   ...
  722.     not    si            ;   ...
  723.     stc                ;   ...
  724.     adc    bx,ax            ;   ...
  725.     adc    si,ax            ;   ...
  726. mults1:    cmp    di,0            ; is DI:CX negative?
  727.     jge    mults2            ;  nope
  728.     not    sign            ;  yup.  flip signs
  729.     not    cx            ;   ...
  730.     not    di            ;   ...
  731.     stc                ;   ...
  732.     adc    cx,ax            ;   ...
  733.     adc    di,ax            ;   ...
  734. mults2:
  735.  
  736.     mov    ax,bx            ; perform BX x CX
  737.     mul    cx            ;  ...
  738. ;    mov    temp,ax            ;  results in lowest 32 bits
  739.     mov    temp+2,dx        ;  ...
  740.  
  741.     mov    ax,bx            ; perform BX x DI
  742.     mul    di            ;  ...
  743.     add    temp+2,ax        ;  results in middle 32 bits
  744.     adc    temp+4,dx        ;  ...
  745.     jnc    mults3            ;  carry bit set?
  746.     inc    word ptr temp+6        ;  yup.  overflow
  747. mults3:
  748.  
  749.     mov    ax,si            ; perform SI * CX
  750.     mul    cx            ;  ...
  751.     add    temp+2,ax        ;  results in middle 32 bits
  752.     adc    temp+4,dx        ;  ...
  753.     jnc    mults4            ;  carry bit set?
  754.     inc    word ptr temp+6        ;  yup.  overflow
  755. mults4:
  756.  
  757.     mov    ax,si            ; perform SI * DI
  758.     mul    di            ;  ...
  759.     add    temp+4,ax        ; results in highest 32 bits
  760.     adc    temp+6,dx        ;  ...
  761.  
  762.     mov    ax,temp+4        ; set up to fake SHR FUDGEFACTOR
  763.     mov    dx,temp+6        ;  by SHL 3 and using high-order dword
  764.     mov    si,temp+2        ;  ...
  765.     mov    cx,32            ; ( / fudge)
  766.     sub    cx,bitshift        ;  ...
  767. multl1:
  768.     shl    si,1            ; shift one bit
  769.     rcl    ax,1            ;  ...
  770.     rcl    dx,1            ;  ...
  771.     jc    multovfl        ;  (oops.  overflow)
  772.     loop    multl1            ; shift another bit, if need be
  773.  
  774.     cmp    dx,0            ; overflow on "negative" result
  775.     jl    multovfl        ;  ...
  776.  
  777.     cmp    sign,0            ; should we negate the result?
  778.     je    mults5            ;  nope.
  779.     not    ax            ;  yup.  flip signs.
  780.     not    dx            ;   ...
  781.     mov    bx,0            ;   ...
  782.     stc                ;   ...
  783.     adc    ax,bx            ;   ...
  784.     adc    dx,bx            ;   ...
  785. mults5:
  786.  
  787. multnoovfl:                ; normal exit
  788.     clc                ;  no carry
  789.     ret                ; we done.
  790.  
  791. multovfl:                ; overflow exit
  792.     stc                ;  set carry
  793.     ret                ; we done.
  794.  
  795. mult32bit    endp
  796.  
  797. code32bit    proc near
  798.  
  799. start32bit:            
  800.     mov    bx,word ptr x        ; set up to multiply x * x
  801.     mov    si,word ptr x+2        ;  ...
  802.     mov    cx,bx            ;  ...
  803.     mov    di,si            ;  ...
  804.     call    mult32bit        ; do it.
  805.     jnc    ok32bit1        ; no overflow.  continue.
  806.     jmp    end32bit        ; overflow.  we done.
  807. ok32bit1:
  808.     mov    word ptr xx,ax        ; save this for a tad.
  809.     mov    word ptr xx+2,dx    ;  ...
  810.  
  811.     mov    bx,word ptr y        ; set up to multiply y * y
  812.     mov    si,word ptr y+2        ;  ...
  813.     mov    cx,bx            ;  ...
  814.     mov    di,si            ;  ...
  815.     call    mult32bit        ; do it.
  816.     jnc    ok32bit2        ; no overflow.  continue.
  817.     jmp    end32bit        ; overflow.  we done.
  818. ok32bit2:
  819.     mov    word ptr yy,ax        ; save this for a tad.
  820.     mov    word ptr yy+2,dx    ;  ...
  821.  
  822.     mov    ax,word ptr xx        ; calculate (x*x + y*y)
  823.     mov    dx,word ptr xx+2    ;  ...
  824.     add    ax,word ptr yy        ;  ...
  825.     adc    dx,word ptr yy+2    ;  ...
  826.     jo    short end32bit        ; bail out if too high
  827.     js    short end32bit        ;  ...
  828.  
  829.     cmp    dx,word ptr lm+2    ; while (lr < lm)
  830.     jae    end32bit        ;  ...
  831.  
  832.     mov    ax,word ptr xx        ; calculate (x*x - y*y)
  833.     mov    dx,word ptr xx+2    ;  ...
  834.     sub    ax,word ptr yy        ;  ...
  835.     sbb    dx,word ptr yy+2    ;  ...
  836.     mov    word ptr xxmyy,ax    ;  ...
  837.     mov    word ptr xxmyy+2,dx    ;  ...
  838.  
  839.     mov    bx,word ptr x        ; set up to multiply x * y
  840.     mov    si,word ptr x+2        ;  ...
  841.     mov    cx,word ptr y        ;  ...
  842.     mov    di,word ptr y+2        ;  ...
  843.     call    mult32bit        ; do it.
  844.     shl    ax,1            ; multiply by 2
  845.     rcl    dx,1            ;  ...
  846.     add    ax,word ptr b        ; add b
  847.     adc    dx,word ptr b+2        ;  ...
  848.     mov    word ptr y,ax        ; save the result as y
  849.     mov    word ptr y+2,dx        ;  ...
  850.  
  851.     mov    ax,word ptr xxmyy    ; remember (x*x - y*y)
  852.     mov    dx,word ptr xxmyy+2    ;  ...
  853.     add    ax,word ptr a        ; add a
  854.     adc    dx,word ptr a+2        ;  ..
  855.     mov    word ptr x,ax        ; save the result as x
  856.     mov    word ptr x+2,dx        ;  ...
  857.  
  858.     mov    ax,oldcolor        ; recall the old color
  859.     cmp    ax,k            ; check it against this iter
  860.     jb    short nonmax2        ;  nope.  bypass periodicity check.
  861.     call    checkperiod        ; check for periodicity
  862. nonmax2:
  863.     call    checkorbit        ; check for orbiting
  864.  
  865.     dec    k            ; while (k < maxit)
  866.     jz    end32bit        ;  we done.
  867.  
  868.     jmp    start32bit        ; try, try again.
  869.  
  870. end32bit:                ; we done.
  871.     mov    word ptr temp+6,dx    ; save last iteration value here
  872.     ret                ;  return.
  873. code32bit    endp
  874.  
  875. ;    The following routine checks for periodic loops (a known
  876. ;    method of decay inside "Mandelbrot Lake", and an easy way to
  877. ;    bail out of "lake" points quickly).  For speed, only the
  878. ;    high-order sixteen bits of X and Y are checked for periodicity.
  879. ;    For accuracy, this routine is only fired up if the previous pixel
  880. ;    was in the lake (which means that the FIRST "wet" pixel was
  881. ;    detected by the dull-normal maximum iteration process).
  882.  
  883. checkperiod    proc near        ; periodicity check
  884.     mov    ax,k            ; set up to test for save-time
  885.     test    ax,savedand        ; save on 0, check on anything else
  886.     jz    checksave        ;  time to save a new "old" value
  887.     mov    dx,word ptr x+2        ; load up x 
  888.     and    dx,word ptr savedmask+2    ;  truncate to appropriate precision
  889.     cmp    dx,word ptr savedx+2    ; does X match?
  890.     jne    checkdone        ;  nope.  forget it.
  891.     mov    ax,word ptr x        ; load up x 
  892.     and    ax,word ptr savedmask    ;  truncate to appropriate precision
  893.     cmp    ax,word ptr savedx    ; does X match?
  894.     jne    checkdone        ;  nope.  forget it.
  895.     mov    dx,word ptr y+2        ; now test y
  896.     and    dx,word ptr savedmask+2    ;  truncate to appropriate precision
  897.     cmp    dx,word ptr savedy+2    ; does Y match?
  898.     jne    checkdone        ;  nope.  forget it.
  899.     mov    ax,word ptr y        ; load up y 
  900.     and    ax,word ptr savedmask    ;  truncate to appropriate precision
  901.     cmp    ax,word ptr savedy    ; does Y match?
  902.     jne    checkdone        ;  nope.  forget it.
  903.     mov    period,1        ; note that we have found periodicity
  904.     mov    k,1            ; pretend maxit reached
  905. checksave:
  906.     mov    dx,word ptr x+2        ; load up x 
  907.     and    dx,word ptr savedmask+2    ;  truncate to appropriate precision
  908.     mov    word ptr savedx+2,dx    ;  and save it
  909.     mov    ax,word ptr x        ; load up x 
  910.     and    ax,word ptr savedmask    ;  truncate to appropriate precision
  911.     mov    word ptr savedx,ax    ;  and save it
  912.     mov    dx,word ptr y+2        ; load up y 
  913.     and    dx,word ptr savedmask+2    ;  truncate to appropriate precision
  914.     mov    word ptr savedy+2,dx    ;  and save it
  915.     mov    ax,word ptr y        ; load up y 
  916.     and    ax,word ptr savedmask    ;  truncate to appropriate precision
  917.     mov    word ptr savedy,ax    ;  and save it
  918.     dec    savedincr        ; time to change the periodicity?
  919.     jnz    checkdone        ;  nope.
  920.     shl    savedand,1        ; well then, let's try this one!
  921.     inc    savedand        ;  (2**n -1)
  922.     mov    savedincr,4        ; and reset the increment flag
  923. checkdone:
  924.     ret                ; we done.
  925. checkperiod    endp
  926.  
  927. checkorbit    proc near
  928.     cmp    show_orbit,0        ; was orbiting on?
  929.     je    nonorbit1        ;  nope.
  930.     push    es            ; save ES
  931.     mov    ax,-1            ; push -1 onto the stack
  932.     push    ax            ;  ...
  933.     mov    ax,word ptr y        ; save y
  934.     mov    dx,word ptr y+2        ;  ...
  935.     push    dx            ;  ...
  936.     push    ax            ;  ...
  937.     mov    ax,word ptr x        ; save x
  938.     mov    dx,word ptr x+2        ;  ...
  939.     push    dx            ;  ...
  940.     push    ax            ;  ...
  941.     call    far ptr iplot_orbit    ; display the orbit
  942.     pop    ax            ; clear out the parameters
  943.     pop    ax            ;  ...
  944.     pop    ax            ; clear out the parameters
  945.     pop    ax            ;  ...
  946.     pop    ax            ; clear out the parameters
  947.     pop    es            ; restore ES
  948. nonorbit1:
  949.     ret
  950. checkorbit    endp
  951.  
  952.            end
  953.  
  954.