home *** CD-ROM | disk | FTP | other *** search
/ Fractal Creations (Second Edition) / FRACTALS_2E.iso / frasrc.exe / CALMANFP.ASM < prev    next >
Assembly Source File  |  1992-02-26  |  43KB  |  1,125 lines

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ; calmanfp.asm - floating point version of the calcmand.asm file
  3. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4. ; The following code was adapted from a little program called "Mandelbrot
  5. ; Sets by Wesley Loewer" which had a very limited distribution (my
  6. ; Algebra II class).  It didn't have any of the fancy integer math, but it
  7. ; did run floating point stuff pretty fast.
  8. ;
  9. ; The code was originally optimized for a 287 ('cuz that's what I've got)
  10. ; and for a large maxit (ie: use of generous overhead outside the loop to get
  11. ; slightly faster code inside the loop), which is generally the case when
  12. ; Fractint chooses to use floating point math.  This code also has the
  13. ; advantage that once the initial parameters are loaded into the fpu
  14. ; register, no transfers of fp values to/from memory are needed except to
  15. ; check periodicity and to show orbits and the like.  Thus, values keep all
  16. ; the significant digits of the full 10 byte real number format internal to
  17. ; the fpu.  Intermediate results are not rounded to the normal IEEE 8 byte
  18. ; format (double) at any time.
  19. ;
  20. ; The non fpu specific stuff, such as periodicity checking and orbits,
  21. ; was adapted from CALCFRAC.C and CALCMAND.ASM.
  22. ;
  23. ; This file must be assembled with floating point emulation turned on.  I
  24. ; suppose there could be some compiler differences in the emulation
  25. ; libraries, but this code has been successfully tested with the MSQC 2.51
  26. ; and MSC 5.1 emulation libraries.
  27. ;
  28. ;                                               Wes Loewer
  29. ;
  30. ; and now for some REAL fractal calculations...
  31. ; (get it, real, floating point..., never mind)
  32. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  33.  
  34. ;                        required for compatibility if Turbo ASM
  35. IFDEF ??version
  36. MASM51
  37. QUIRKS
  38. ENDIF
  39.  
  40. .8086
  41. .8087
  42.  
  43. .MODEL medium,c
  44.  
  45. ; external functions
  46. EXTRN   keypressed:FAR          ; this routine is in 'general.asm'
  47. EXTRN   getakey:FAR             ; this routine is in 'general.asm'
  48. EXTRN   plot_orbit:FAR          ; this routine is in 'fracsubr.c'
  49. EXTRN   scrub_orbit:FAR         ; this routine is in 'fracsubr.c'
  50.  
  51. ; external data
  52. EXTRN init:WORD                 ; declared as type complex
  53. EXTRN parm:WORD                 ; declared as type complex
  54. EXTRN new:WORD                  ; declared as type complex
  55. EXTRN maxit:WORD
  56. EXTRN inside:WORD
  57. EXTRN outside:WORD
  58. EXTRN fpu:WORD                  ; fpu type: 87, 287, or 387
  59. EXTRN rqlim:QWORD               ; bailout (I never did figure out
  60.                 ;   what "rqlim" stands for. -Wes)
  61. EXTRN color:WORD
  62. EXTRN oldcolor:WORD
  63. EXTRN realcolor:WORD
  64. EXTRN periodicitycheck:WORD
  65. EXTRN reset_periodicity:WORD
  66. EXTRN closenuff:QWORD
  67. EXTRN fractype:WORD             ; Mandelbrot or Julia
  68. EXTRN kbdcount:WORD             ; keyboard counter
  69. EXTRN dotmode:WORD
  70. EXTRN show_orbit:WORD           ; "show-orbit" flag
  71. EXTRN orbit_ptr:WORD            ; "orbit pointer" flag
  72. EXTRN potflag:WORD              ; potential flag
  73. EXTRN magnitude:QWORD           ; when using potential
  74.  
  75. JULIAFP  EQU 6                  ; from FRACTYPE.H
  76. MANDELFP EQU 4
  77. GREEN    EQU 2                  ; near y-axis
  78. YELLOW   EQU 6                  ; near x-axis
  79.  
  80. initx    EQU <qword ptr init>   ; just to make life easier
  81. inity    EQU <qword ptr init+8>
  82. parmx    EQU <qword ptr parm>
  83. parmy    EQU <qword ptr parm+8>
  84. newx     EQU <qword ptr new>
  85. newy     EQU <qword ptr new+8>
  86.  
  87. ; Apparently, these might be needed for TC++ overlays. I don't know if
  88. ; these are really needed here since I am not familiar with TC++. -Wes
  89. FRAME   MACRO regs
  90.     push    bp
  91.     mov     bp, sp
  92.     IRP     reg, <regs>
  93.       push  reg
  94.       ENDM
  95.     ENDM
  96.  
  97. UNFRAME MACRO regs
  98.     IRP     reg, <regs>
  99.       pop reg
  100.       ENDM
  101.     pop bp
  102.     ENDM
  103.  
  104.  
  105. .DATA
  106.     align   2
  107. savedx                  DQ  ?
  108. savedy                  DQ  ?
  109. orbit_real              DQ  ?
  110. orbit_imag              DQ  ?
  111. close                   DD  0.01
  112. round_down_half         DD  0.5
  113. tmp_word                DW  ?
  114. inside_color            DW  ?
  115. periodicity_color       DW  ?
  116. ;savedand               DW  ?
  117. ;savedincr              DW  ?
  118. savedand                EQU     SI      ; this doesn't save much time or
  119. savedincr               EQU     DI      ; space, but it doesn't hurt either
  120.  
  121. .CODE
  122.  
  123. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  124. ; This routine is called once per image.
  125. ; Put things here that won't change from one pixel to the next.
  126. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  127. PUBLIC calcmandfpasmstart
  128. calcmandfpasmstart   PROC
  129.                     ; not sure if needed here
  130.     FRAME   <di,si>                 ; std frame, for TC++ overlays
  131.  
  132.     mov     ax,inside
  133.     cmp     ax,0                    ; if (inside color == maxiter)
  134.     jnl     non_neg_inside
  135.     mov     ax,maxit                ;   use maxit as inside_color
  136.  
  137. non_neg_inside:                         ; else
  138.     mov     inside_color,ax         ;   use inside as inside_color
  139.  
  140.     cmp     periodicitycheck,0      ; if periodicitycheck < 0
  141.     jnl     non_neg_periodicitycheck
  142.     mov     ax,7                    ;   use color 7 (default white)
  143. non_neg_periodicitycheck:               ; else
  144.     mov     periodicity_color,ax    ;   use inside_color still in ax
  145.     mov     oldcolor,0              ; no periodicity checking on 1st pixel
  146.     sub     ax,ax                   ; ax=0
  147.     UNFRAME <si,di>                 ; pop stack frame
  148.     ret
  149. calcmandfpasmstart       ENDP
  150.  
  151. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  152. ; floating point version of calcmandasm
  153. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  154. PUBLIC calcmandfpasm
  155. calcmandfpasm  PROC
  156.     FRAME   <di,si>                 ; std frame, for TC++ overlays
  157. ; initialization stuff
  158.     sub     ax,ax                   ; clear ax
  159.     cmp     periodicitycheck,ax     ; periodicity checking?
  160.     je      initoldcolor            ;  no, set oldcolor 0 to disable it
  161.     cmp     inside,-59              ; zmag?
  162.     je      initoldcolor            ;  set oldcolor to 0
  163.     cmp     reset_periodicity,ax    ; periodicity reset?
  164.     je      short initparms         ;  no, inherit oldcolor from prior invocation
  165.     mov     ax,maxit                ; yup.  reset oldcolor to maxit-250
  166.     sub     ax,250                  ; (avoids slowness at high maxits)
  167. initoldcolor:
  168.     mov     oldcolor,ax             ; reset oldcolor
  169.  
  170. initparms:
  171.     sub     ax,ax                   ; clear ax
  172.     mov     word ptr savedx,ax      ; savedx = 0.0
  173.     mov     word ptr savedx+2,ax    ; needed since savedx is a QWORD
  174.     mov     word ptr savedx+4,ax
  175.     mov     word ptr savedx+6,ax
  176.     mov     word ptr savedy,ax      ; savedy = 0.0
  177.     mov     word ptr savedy+2,ax    ; needed since savedy is a QWORD
  178.     mov     word ptr savedy+4,ax
  179.     mov     word ptr savedy+6,ax
  180.     inc     ax                      ; ax = 1
  181.     mov     savedand,ax             ; savedand = 1
  182.     mov     savedincr,ax            ; savedincr = 1
  183.     mov     orbit_ptr,0             ; clear orbits
  184.     dec     kbdcount                ; decrement the keyboard counter
  185.     jns     short nokey             ;  skip keyboard test if still positive
  186.     mov     kbdcount,10             ; stuff in a low kbd count
  187.     cmp     show_orbit,0            ; are we showing orbits?
  188.     jne     quickkbd                ;  yup.  leave it that way.
  189. ;this may need to be adjusted, I'm guessing at the "appropriate" values -Wes
  190.     mov     kbdcount,5000           ; else, stuff an appropriate count val
  191.     cmp     fpu,387                 ; ("appropriate" to the FPU)
  192.     je      short kbddiskadj        ;     ...
  193.     mov     kbdcount,3000           ;     ...
  194.     cmp     fpu,287                 ;     ...
  195.     je      short kbddiskadj        ;     ...
  196.     mov     kbdcount,1000           ;     ...
  197.     cmp     fpu,87                  ;     ...
  198.     je      short kbddiskadj        ;     ...
  199.     mov     kbdcount,500            ; emulation
  200. kbddiskadj:
  201.     cmp     dotmode,11              ; disk video?
  202.     jne     quickkbd                ;  no, leave as is
  203.     mov     cl,2                    ; yes, reduce count
  204.     shr     kbdcount,cl             ;  ...
  205.  
  206. quickkbd:
  207.     call    far ptr keypressed      ; has a key been pressed?
  208.     cmp     ax,0                    ;  ...
  209.     je      nokey                   ; nope.  proceed
  210.     mov     kbdcount,0              ; make sure it goes negative again
  211.     cmp     ax,'o'                  ; orbit toggle hit?
  212.     je      orbitkey                ;  yup.  show orbits
  213.     cmp     ax,'O'                  ; orbit toggle hit?
  214.     jne     keyhit                  ;  nope.  normal key.
  215. orbitkey:
  216.     call    far ptr getakey         ; read the key for real
  217.     mov     ax,1                    ; reset orbittoggle = 1 - orbittoggle
  218.     sub     ax,show_orbit           ;  ...
  219.     mov     show_orbit,ax           ;  ...
  220.     jmp     short nokey             ; pretend no key was hit
  221. keyhit:
  222.     mov     ax,-1                   ; return with -1
  223.     mov     color,ax                ; set color to -1
  224.     UNFRAME <si,di>                 ; pop stack frame
  225.     ret                             ; bail out!
  226. nokey:
  227.  
  228. ; OK, here's the heart of the floating point code.
  229. ; In my original program, the bailout value was loaded once per image and
  230. ; was left on the floating point stack after each pixel, and finally popped
  231. ; off the stack when the fractal was finished.  A lot of overhead for very
  232. ; little gain in my opinion, so I changed it so that it loads and unloads
  233. ; per pixel. -Wes
  234.  
  235.     fld     rqlim                   ; everything needs bailout first
  236.     mov     cx,maxit                ; using cx as loop counter
  237.     cmp     fpu,387                 ; jump to fpu specific code
  238.     je      start_387               ; 387, slight efficiency tweeking
  239.     cmp     fpu,287                 ;
  240.     je      to_start_287            ; 287 (original version)
  241.     jmp     start_87                ; else must be 87/emulation
  242. to_start_287:
  243.     jmp     start_287               ; needs a long jump here
  244.  
  245.  
  246. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  247. ; _387 code is just like _287 code except that it uses an FADD instead
  248. ; of an FSCALE per orbit and also saves an FLD1 per pixel.
  249. ;
  250. ; You could use .386/.387 here, but it is not necessary.  The _387 floating
  251. ; point routines in this file do not have any 387 specific op-codes,
  252. ; only 387 specific optimizations.  (And plus my MS QuickAssembler does not
  253. ; recognize the .386/.387 directives.) -Wes
  254. ;
  255. .286
  256. .287
  257.  
  258. start_387:
  259.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  260.     je      short dojulia_387       ; julia set - go there
  261.  
  262. ; Mandelbrot _387 initialization of stack
  263.     dec     cx                      ; always requires at least 1 iteration
  264.  
  265.                     ; the fpu stack is shown below
  266.                     ; st(0) ... st(7)
  267.                     ; b (already on stack)
  268.     fld     inity                   ; Cy b
  269.     fld     initx                   ; Cx Cy b
  270.     fld     st(1)                   ; Cy Cx Cy b
  271.     fadd    parmy                   ; Py+Cy Cx Cy b
  272.     fld     st                      ; Py+Cy Py+Cy Cx Cy b
  273.     fmul    st,st                   ; (Py+Cy)^2 Py+Cy Cx Cy b
  274.     fld     st(2)                   ; Cx (Py+Cy)^2 Py+Cy Cx Cy b
  275.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 Py+Cy Cx Cy b
  276.     fmul    st(2),st                ; Px+Cx (Py+Cy)^2 (Py+Cy)(Px+Cx) Cx Cy b
  277.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 (Py+Cy)(Px+Cx) Cx Cy b
  278.     ; which is the next               x^2 y^2 xy Cx Cy b
  279.     jmp     short top_of_cx_loop_387 ; branch around the julia switch
  280.  
  281. dojulia_387:
  282.                     ; Julia 387 initialization of stack
  283.                     ; note that init and parm are "reversed"
  284.                     ; b (already on stack)
  285.     fld     parmy                   ; Cy b
  286.     fld     parmx                   ; Cx Cy b
  287.     fld     inity                   ; y Cx Cy b
  288.     fld     st                      ; y y Cx Cy b
  289.     fmul    st,st                   ; y^2 y Cx Cy b
  290.     fld     initx                   ; x y^2 y Cx Cy b
  291.     fmul    st(2),st                ; x y^2 xy Cx Cy b
  292.     fmul    st,st                   ; x^2 y^2 xy Cx Cy b
  293.  
  294. top_of_cx_loop_387:                     ; x^2 y^2 xy Cx Cy b
  295.     fsubr                           ; x^2-y^2 xy Cx Cy b
  296.     fadd    st,st(2)                ; x^2-y^2+Cx xy Cx Cy b
  297.     fxch                            ; xy x^2-y^2+Cx Cx Cy b
  298. ; FADD is faster than FSCALE for 387
  299.     fadd    st,st                   ; 2xy x^2-y^2+Cx Cx Cy b
  300.     fadd    st,st(3)                ; 2xy+Cy x^2-y^2+Cx Cx Cy b
  301.                     ; now same as the new
  302.                     ; y x Cx Cy b
  303.  
  304.     cmp     outside,-2              ; real, imag, mult, or sum ?
  305.     jg      no_save_new_xy_387      ; if not, then skip this
  306.     fld     st(1)                   ; x y x Cx Cy b
  307.     fstp    newx                    ; y x Cx Cy b
  308.     fst     newy                    ; y x Cx Cy b
  309. no_save_new_xy_387:
  310.  
  311.     cmp     inside,-100                     ; epsilon cross ?
  312.     jne     end_epsilon_cross_387
  313.     call    near ptr epsilon_cross          ; y x Cx Cy b
  314.     jcxz    pop_stack_387                   ; if cx=0, pop stack
  315. end_epsilon_cross_387:
  316.  
  317.     cmp     cx,oldcolor                     ; if cx >= oldcolor
  318.     jae     end_periodicity_check_387       ; don't check periodicity
  319.     call    near ptr periodicity_check_287_387  ; y x Cx Cy b
  320.     jcxz    pop_stack_387                   ; if cx=0, pop stack
  321. end_periodicity_check_387:
  322.  
  323.     cmp     show_orbit,0            ; is show_orbit clear
  324.     je      no_show_orbit_387       ; if so then skip
  325.     call    near ptr show_orbit_xy  ; y x Cx Cy b
  326. no_show_orbit_387:
  327.  
  328.                     ; y x Cx Cy b
  329.     fld     st(1)                   ; x y x Cx Cy b
  330.     fld     st(1)                   ; y x y x Cx Cy b
  331.     fmul    st(3),st                ; y x y xy Cx Cy b
  332.     fmulp   st(2),st                ; x y^2 xy Cx Cy b
  333.     fmul    st,st                   ; x^2 y^2 xy Cx Cy b
  334.     fld     st                      ; x^2 x^2 y^2 xy Cx Cy b
  335.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 xy Cx Cy b
  336.  
  337.     cmp     potflag,0               ; check for potential
  338.     je      no_potflag_387
  339.     fst     magnitude               ; if so, save magnitude
  340. no_potflag_387:
  341.  
  342.     fcomp   st(6)                   ; x^2 y^2 xy Cx Cy b
  343.     fstsw   ax
  344.     sahf
  345.     ja      over_bailout_387
  346.  
  347. ;less than or equal to bailout
  348.     loop    top_of_cx_loop_387      ; x^2 y^2 xy Cx Cy b
  349.  
  350. ; reached maxit, inside
  351.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  352.     mov     ax,maxit
  353.     sub     kbdcount,ax             ; adjust the keyboard count
  354.     mov     realcolor,ax            ; save unadjusted realcolor
  355.     mov     ax,inside_color
  356.  
  357.     cmp     inside,-59              ; zmag ?
  358.     jne     no_zmag_387
  359.     fadd    st,st(1)                ; x^2+y^2 y^2 xy Cx Cy b
  360.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 xy Cx Cy b
  361.  
  362. ; When type casting floating point variables to integers in C, the decimal
  363. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  364. ; line cause the positive value to be truncated.
  365.     fsub    round_down_half
  366.  
  367.     fist    tmp_word                ; tmp_word = |z^2|*maxit
  368.     fwait
  369.     mov     ax,tmp_word
  370.     shr     ax,1                    ; |z^2|*maxit/2
  371.     inc     ax                      ; |z^2|*maxit/2+1
  372.  
  373. no_zmag_387:
  374.  
  375. pop_stack_387:
  376.     fninit
  377.  
  378.     mov     color,ax
  379.  
  380.     cmp     orbit_ptr,0             ; any orbits to clear?
  381.     je      calcmandfpasm_ret_387   ; nope.
  382.     call    far ptr scrub_orbit     ; clear out any old orbits
  383.     mov     ax,color                ; restore color
  384.                     ; speed not critical here in orbit land
  385.  
  386. calcmandfpasm_ret_387:
  387.     UNFRAME <si,di>                 ; pop stack frame
  388.     fwait                ; just to make sure
  389.     ret
  390.  
  391.     
  392. over_bailout_387:                       ; x^2 y^2 xy Cx Cy b
  393. ; outside
  394.     mov     ax,cx
  395.     sub     ax,10                   ; 10 more next time before checking
  396.     jns     no_fix_underflow_387
  397. ; if the number of iterations was within 10 of maxit, then subtracting
  398. ; 10 would underflow and cause periodicity checking to start right
  399. ; away.  Catching a period doesn't occur as often in the pixels at
  400. ; the edge of the set anyway.
  401.     sub     ax,ax                   ; don't check next time
  402. no_fix_underflow_387:
  403.     mov     oldcolor,ax             ; check when past this - 10 next time
  404.     mov     ax,maxit
  405.     sub     ax,cx                   ; leave 'times through loop' in ax
  406.  
  407. ; zero color fix
  408.     jnz     zero_color_fix_387
  409.     inc     ax                      ; if (ax == 0 ) ax = 1
  410. zero_color_fix_387:
  411.     mov     realcolor,ax            ; save unadjusted realcolor
  412.     sub     kbdcount,ax             ; adjust the keyboard count
  413.  
  414.     cmp     outside,-1              ; iter ? (most common case)
  415.     je      pop_stack_387
  416.     cmp     outside,-2        ; outside <= -2 ?
  417.     jle     special_outside_387     ; yes, go do special outside options
  418.     mov     ax,outside              ; use outside color
  419.     jmp     short pop_stack_387
  420. special_outside_387:
  421.     call    near ptr special_outside
  422.     jmp     short pop_stack_387
  423.  
  424. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  425. ; _287 version (closely resembles original code)
  426. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  427. .286
  428. .287
  429. start_287:      ; 287
  430.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  431.     je      short dojulia_287       ; julia set - go there
  432.  
  433. ; Mandelbrot _287 initialization of stack
  434.     dec     cx                      ; always requires at least 1 iteration
  435.  
  436.                     ; the fpu stack is shown below
  437.                     ; st(0) ... st(7)
  438.                     ; b (already on stack)
  439.     fld     inity                   ; Cy b
  440.     fld     initx                   ; Cx Cy b
  441.     fld     st(1)                   ; Cy Cx Cy b
  442.     fadd    parmy                   ; Py+Cy Cx Cy b
  443.     fld1                            ; 1 Py+Cy Cx Cy b
  444.     fld     st(1)                   ; Py+Cy 1 Py+Cy Cx Cy b
  445.     fmul    st,st                   ; (Py+Cy)^2 1 Py+Cy Cx Cy b
  446.     fld     st(3)                   ; Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  447.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  448.     fmul    st(3),st                ; Px+Cx (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  449.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  450.     ; which is the next                x^2 y^2 1 xy Cx Cy b
  451.     jmp     short top_of_cx_loop_287 ; branch around the julia switch
  452.  
  453. dojulia_287:
  454.                     ; Julia 287 initialization of stack
  455.                     ; note that init and parm are "reversed"
  456.                     ; b (already on stack)
  457.     fld     parmy                   ; Cy b
  458.     fld     parmx                   ; Cx Cy b
  459.     fld     inity                   ; y Cx Cy b
  460.     fld1                            ; 1 y Cx Cy b
  461.     fld     st(1)                   ; y 1 y Cx Cy b
  462.     fmul    st,st                   ; y^2 1 y Cx Cy b
  463.     fld     initx                   ; x y^2 1 y Cx Cy b
  464.     fmul    st(3),st                ; x y^2 1 xy Cx Cy b
  465.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  466.  
  467. top_of_cx_loop_287:                     ; x^2 y^2 1 xy Cx Cy b
  468.     fsubr                           ; x^2-y^2 1 xy Cx Cy b
  469.     fadd    st,st(3)                ; x^2-y^2+Cx 1 xy Cx Cy b
  470.     fxch    st(2)                   ; xy 1 x^2-y^2+Cx Cx Cy b
  471. ; FSCALE is faster than FADD for 287
  472.     fscale                          ; 2xy 1 x^2-y^2+Cx Cx Cy b
  473.     fadd    st,st(4)                ; 2xy+Cy 1 x^2-y^2+Cx Cx Cy b
  474.                     ; now same as the new
  475.                     ; y 1 x Cx Cy b
  476.  
  477.     cmp     outside,-2              ; real, imag, mult, or sum ?
  478.     jg      no_save_new_xy_287      ; if not, then skip this
  479.     fld     st(2)                   ; x y 1 x Cx Cy b
  480.     fstp    newx                    ; y 1 x Cx Cy b
  481.     fst     newy                    ; y 1 x Cx Cy b
  482. no_save_new_xy_287:
  483.  
  484.     cmp     inside,-100                     ; epsilon cross ?
  485.     jne     end_epsilon_cross_287
  486.     call    near ptr epsilon_cross          ; y 1 x Cx Cy b
  487.     jcxz    pop_stack_287                   ; if cx=0, pop stack
  488. end_epsilon_cross_287:
  489.  
  490.     cmp     cx,oldcolor                     ; if cx >= oldcolor
  491.     jae     end_periodicity_check_287       ; don't check periodicity
  492.     call    near ptr periodicity_check_287_387 ; y 1 x Cx Cy b
  493.     jcxz    pop_stack_287                   ; if cx=0, pop stack
  494. end_periodicity_check_287:
  495.  
  496.     cmp     show_orbit,0            ; is show_orbit clear
  497.     je      no_show_orbit_287       ; if so then skip
  498.     call    near ptr show_orbit_xy  ; y 1 x Cx Cy b
  499. no_show_orbit_287:
  500.                     ; y 1 x Cx Cy b
  501.     fld     st(2)                   ; x y 1 x Cx Cy b
  502.     fld     st(1)                   ; y x y 1 x Cx Cy b
  503.     fmul    st(4),st                ; y x y 1 xy Cx Cy b
  504.     fmulp   st(2),st                ; x y^2 1 xy Cx Cy b
  505.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  506.     fld     st                      ; x^2 x^2 y^2 1 xy Cx Cy b
  507.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 1 xy Cx Cy b
  508.  
  509.     cmp     potflag,0        ; check for potential
  510.     je      no_potflag_287
  511.     fst     magnitude        ; if so, save magnitude
  512. no_potflag_287:
  513.  
  514.     fcomp   st(7)                   ; x^2 y^2 1 xy Cx Cy b
  515.     fstsw   ax
  516.     sahf
  517.     ja      over_bailout_287
  518.  
  519. ;less than or equal to bailout
  520.     loop    top_of_cx_loop_287      ; x^2 y^2 1 xy Cx Cy b
  521.  
  522. ; reached maxit, inside
  523.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  524.     mov     ax,maxit
  525.     sub     kbdcount,ax             ; adjust the keyboard count
  526.     mov     realcolor,ax            ; save unadjusted realcolor
  527.     mov     ax,inside_color
  528.  
  529.     cmp     inside,-59              ; zmag ?
  530.     jne     no_zmag_287
  531.     fadd    st,st(1)                ; x^2+y^2 y^2 1 xy Cx Cy b
  532.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 1 xy Cx Cy b
  533.  
  534. ; When type casting floating point variables to integers in C, the decimal
  535. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  536. ; line cause the positive value to be truncated.
  537.     fsub    round_down_half
  538.  
  539.     fist    tmp_word                ; tmp_word = |z^2|*maxit
  540.     fwait
  541.     mov     ax,tmp_word
  542.     shr     ax,1                    ; |z^2|*maxit/2
  543.     inc     ax                      ; |z^2|*maxit/2+1
  544.  
  545. no_zmag_287:
  546.  
  547. pop_stack_287:
  548.     fninit
  549.  
  550.     mov     color,ax
  551.  
  552.     cmp     orbit_ptr,0             ; any orbits to clear?
  553.     je      calcmandfpasm_ret_287   ; nope.
  554.     call    far ptr scrub_orbit     ; clear out any old orbits
  555.     mov     ax,color                ; restore color
  556.                     ; speed not critical here in orbit land
  557.  
  558. calcmandfpasm_ret_287:
  559.     UNFRAME <si,di>                 ; pop stack frame
  560.     fwait                           ; just to make sure
  561.     ret
  562.  
  563. over_bailout_287:                       ; x^2 y^2 1 xy Cx Cy b
  564. ; outside
  565.     mov     ax,cx
  566.     sub     ax,10                   ; 10 more next time before checking
  567.     jns     no_fix_underflow_287
  568. ; if the number of iterations was within 10 of maxit, then subtracting
  569. ; 10 would underflow and cause periodicity checking to start right
  570. ; away.  Catching a period doesn't occur as often in the pixels at
  571. ; the edge of the set anyway.
  572.     sub     ax,ax                   ; don't check next time
  573. no_fix_underflow_287:
  574.     mov     oldcolor,ax             ; check when past this - 10 next time
  575.     mov     ax,maxit
  576.     sub     ax,cx                   ; leave 'times through loop' in ax
  577.  
  578. ; zero color fix
  579.     jnz     zero_color_fix_287
  580.     inc     ax                      ; if (ax == 0 ) ax = 1
  581. zero_color_fix_287:
  582.     mov     realcolor,ax            ; save unadjusted realcolor
  583.     sub     kbdcount,ax             ; adjust the keyboard count
  584.  
  585.     cmp     outside,-1              ; iter ? (most common case)
  586.     je      pop_stack_287
  587.     cmp     outside,-2        ; outside <= -2 ?
  588.     jle     special_outside_287     ; yes, go do special outside options
  589.     mov     ax,outside              ; use outside color
  590.     jmp     short pop_stack_287
  591. special_outside_287:
  592.     call    near ptr special_outside
  593.     jmp     short pop_stack_287
  594.  
  595.  
  596. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  597. ; _87 code is just like 287 code except that it must use
  598. ;       fstsw   tmp_word
  599. ;       fwait
  600. ;       mov     ax,tmp_word
  601. ; instead of
  602. ;       fstsw   ax
  603. ;
  604. .8086
  605. .8087
  606. start_87:
  607. ; let emulation fall through to the 87 code here
  608. ; as it seems not emulate correctly on an 8088/86 otherwise
  609.     cmp     fractype,JULIAFP        ; julia or mandelbrot set?
  610.     je      short dojulia_87        ; julia set - go there
  611.  
  612. ; Mandelbrot _87 initialization of stack
  613.     dec     cx                      ; always requires at least 1 iteration
  614.  
  615.                     ; the fpu stack is shown below
  616.                     ; st(0) ... st(7)
  617.                     ; b (already on stack)
  618.     fld     inity                   ; Cy b
  619.     fld     initx                   ; Cx Cy b
  620.     fld     st(1)                   ; Cy Cx Cy b
  621.     fadd    parmy                   ; Py+Cy Cx Cy b
  622.     fld1                            ; 1 Py+Cy Cx Cy b
  623.     fld     st(1)                   ; Py+Cy 1 Py+Cy Cx Cy b
  624.     fmul    st,st                   ; (Py+Cy)^2 1 Py+Cy Cx Cy b
  625.     fld     st(3)                   ; Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  626.     fadd    parmx                   ; Px+Cx (Py+Cy)^2 1 Py+Cy Cx Cy b
  627.     fmul    st(3),st                ; Px+Cx (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  628.     fmul    st,st                   ; (Px+Cx)^2 (Py+Cy)^2 1 (Py+Cy)(Px+Cx) Cx Cy b
  629.     ; which is the next               x^2 y^2 1 xy Cx Cy b
  630.     jmp     short top_of_cx_loop_87 ; branch around the julia switch
  631.  
  632. dojulia_87:
  633.                     ; Julia 87 initialization of stack
  634.                     ; note that init and parm are "reversed"
  635.                     ; b (already on stack)
  636.     fld     parmy                   ; Cy b
  637.     fld     parmx                   ; Cx Cy b
  638.     fld     inity                   ; y Cx Cy b
  639.     fld1                            ; 1 y Cx Cy b
  640.     fld     st(1)                   ; y 1 y Cx Cy b
  641.     fmul    st,st                   ; y^2 1 y Cx Cy b
  642.     fld     initx                   ; x y^2 1 y Cx Cy b
  643.     fmul    st(3),st                ; x y^2 1 xy Cx Cy b
  644.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  645.  
  646. top_of_cx_loop_87:                      ; x^2 y^2 1 xy Cx Cy b
  647.     fsubr                           ; x^2-y^2 1 xy Cx Cy b
  648.     fadd    st,st(3)                ; x^2-y^2+Cx 1 xy Cx Cy b
  649.     fxch    st(2)                   ; xy 1 x^2-y^2+Cx Cx Cy b
  650. ; FSCALE is faster than FADD for 87
  651.     fscale                          ; 2xy 1 x^2-y^2+Cx Cx Cy b
  652.     fadd    st,st(4)                ; 2xy+Cy 1 x^2-y^2+Cx Cx Cy b
  653.                     ; now same as the new
  654.                     ; y 1 x Cx Cy b
  655.  
  656.     cmp     outside,-2              ; real, imag, mult, or sum ?
  657.     jg      no_save_new_xy_87       ; if not, then skip this
  658.     fld     st(2)                   ; x y 1 x Cx Cy b
  659.     fstp    newx                    ; y 1 x Cx Cy b
  660.     fst     newy                    ; y 1 x Cx Cy b
  661. no_save_new_xy_87:
  662.  
  663.     cmp     inside,-100                     ; epsilon cross ?
  664.     jne     end_epsilon_cross_87
  665.     call    near ptr epsilon_cross          ; y 1 x Cx Cy b
  666.     test    cx,cx                           ; if cx=0, pop stack
  667.     jnz     end_epsilon_cross_87            ; replaces jcxz
  668.     jmp     pop_stack_6_87                  ; with a long jump
  669. end_epsilon_cross_87:
  670.  
  671.     cmp     cx,oldcolor                     ; if cx >= oldcolor
  672.     jae     no_periodicity_check_87         ; don't check periodicity
  673.     call    near ptr periodicity_check_87   ; y 1 x Cx Cy b
  674.     jcxz    pop_stack_6_87                  ; if cx=0, pop stack
  675. no_periodicity_check_87:
  676.  
  677.     cmp     show_orbit,0            ; is show_orbit clear
  678.     je      no_show_orbit_87        ; if so then skip
  679.     call    near ptr show_orbit_xy  ; y 1 x Cx Cy b
  680. no_show_orbit_87:
  681.  
  682.                     ; y 1 x Cx Cy b
  683.     fld     st(2)                   ; x y 1 x Cx Cy b
  684.     fld     st(1)                   ; y x y 1 x Cx Cy b
  685.     fmul    st(4),st                ; y x y 1 xy Cx Cy b
  686.     fmulp   st(2),st                ; x y^2 1 xy Cx Cy b
  687.     fmul    st,st                   ; x^2 y^2 1 xy Cx Cy b
  688.     fld     st                      ; x^2 x^2 y^2 1 xy Cx Cy b
  689.     fadd    st,st(2)                ; x^2+y^2 x^2 y^2 1 xy Cx Cy b
  690.  
  691.     cmp     potflag,0               ; check for potential
  692.     je      no_potflag_87
  693.     fst     magnitude               ; if so, save magnitude
  694. no_potflag_87:
  695.  
  696.     fcomp   st(7)                   ; x^2 y^2 1 xy Cx Cy b
  697.     fstsw   tmp_word
  698.     fwait
  699.     mov     ax,tmp_word
  700.     sahf
  701.     ja      over_bailout_87
  702.  
  703. ;less than or equal to bailout
  704.     loop    top_of_cx_loop_87       ; x^2 y^2 1 xy Cx Cy b
  705.  
  706. ; reached maxit
  707.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  708.     mov     ax,maxit
  709.     sub     kbdcount,ax             ; adjust the keyboard count
  710.     mov     realcolor,ax            ; save unadjusted realcolor
  711.     mov     ax,inside_color
  712.  
  713.     cmp     inside,-59              ; zmag ?
  714.     jne     no_zmag_87
  715.     fadd    st,st(1)                ; x^2+y^2 y^2 1 xy Cx Cy b
  716.     fimul   maxit                   ; maxit*|z^2| x^2 y^2 1 xy Cx Cy b
  717.  
  718. ; When type casting floating point variables to integers in C, the decimal
  719. ; is truncated.  When using FIST in asm, the value is rounded.  The following
  720. ; line cause the positive value to be truncated.
  721.     fsub    round_down_half
  722.  
  723.     fist    tmp_word                ; tmp_word = |z^2|*maxit
  724.     fwait
  725.     mov     ax,tmp_word
  726.     shr     ax,1                    ; |z^2|*maxit/2
  727.     inc     ax                      ; |z^2|*maxit/2+1
  728.  
  729. no_zmag_87:
  730.  
  731. pop_stack_7_87:
  732. ; The idea here is just to clear the floating point stack.  There was a
  733. ; problem using FNINIT with the emulation library.  It didn't seem to
  734. ; properly clear the emulated stack, resulting in "stack overflow"
  735. ; messages.  Therefore, if emulation is being used, then FSTP's are used
  736. ; instead.
  737.  
  738.     cmp     fpu,0                   ; are we using emulation?
  739.     jne     no_emulation            ; if not, then jump
  740.     fstp    st
  741. ; you could just jump over this next check, but its faster to just check again
  742. pop_stack_6_87:
  743.     cmp     fpu,0                   ; are we using emulation?
  744.     jne     no_emulation            ; if not, then jump
  745.     fstp    st
  746.     fstp    st
  747.     fstp    st
  748.     fstp    st
  749.     fstp    st
  750.     fstp    st
  751.     jmp     short end_pop_stack_87
  752. no_emulation:                           ; if no emulation, then
  753.     fninit                          ;   use the faster FNINIT
  754. end_pop_stack_87:
  755.  
  756.     mov     color,ax
  757.  
  758.     cmp     orbit_ptr,0             ; any orbits to clear?
  759.     je      calcmandfpasm_ret_87    ; nope.
  760.     call    far ptr scrub_orbit     ; clear out any old orbits
  761.     mov     ax,color                ; restore color
  762.                     ; speed not critical here in orbit land
  763.  
  764. calcmandfpasm_ret_87:
  765.     UNFRAME <si,di>                 ; pop stack frame
  766.     fwait                ; just to make sure
  767.     ret
  768.  
  769. over_bailout_87:                        ; x^2 y^2 1 xy Cx Cy b
  770. ; outside
  771.     mov     ax,cx
  772.     sub     ax,10                   ; 10 more next time before checking
  773.     jns     no_fix_underflow_87
  774. ; if the number of iterations was within 10 of maxit, then subtracting
  775. ; 10 would underflow and cause periodicity checking to start right
  776. ; away.  Catching a period doesn't occur as often in the pixels at
  777. ; the edge of the set anyway.
  778.     sub     ax,ax                   ; don't check next time
  779. no_fix_underflow_87:
  780.     mov     oldcolor,ax             ; check when past this - 10 next time
  781.     mov     ax,maxit
  782.     sub     ax,cx                   ; leave 'times through loop' in ax
  783.  
  784. ; zero color fix
  785.     jnz     zero_color_fix_87
  786.     inc     ax                      ; if (ax == 0 ) ax = 1
  787. zero_color_fix_87:
  788.     mov     realcolor,ax            ; save unadjusted realcolor
  789.     sub     kbdcount,ax             ; adjust the keyboard count
  790.  
  791.     cmp     outside,-1              ; iter ? (most common case)
  792.     je      pop_stack_7_87
  793.     cmp     outside,-2        ; outside <= -2 ?
  794.     jle     special_outside_87      ; yes, go do special outside options
  795.     mov     ax,outside              ; use outside color
  796.     jmp     short pop_stack_7_87
  797. special_outside_87:
  798.     call    near ptr special_outside
  799.     jmp     short pop_stack_7_87
  800.  
  801. calcmandfpasm  ENDP
  802.  
  803. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  804. ; Since periodicity checking is used most of the time, I decided to
  805. ; separate the periodicity_check routines into a _287_387 version
  806. ; and an _87 version to achieve a slight increase in speed.  The
  807. ; epsilon_cross, show_orbit_xy, and special_outside routines are less
  808. ; frequently used and therefore have been implemented as single routines
  809. ; usable by the 8087 and up. -Wes
  810. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  811. .286
  812. .287
  813. periodicity_check_287_387   PROC    NEAR
  814. ; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
  815.                     ; fpu stack is either
  816.                     ; y x Cx Cy b (387)
  817.                     ; y 1 x Cx Cy b (287/emul)
  818.     cmp     fpu,387
  819.     jb      pc_load_x
  820.     fld     st(1)                   ; if 387
  821.     jmp     short pc_end_load_x
  822. pc_load_x:
  823.     fld     st(2)                   ; if 287/emul
  824. pc_end_load_x:
  825.                     ; x y ...
  826.     test    cx,savedand             ; save on 0, check on anything else
  827.     jnz     do_check_287_387        ;  time to save a new "old" value
  828.  
  829. ; save last value                       ; fpu stack is
  830.     fstp    savedx                  ; x y ...
  831.     fst     savedy                  ; y ...
  832.     dec     savedincr               ; time to lengthen the periodicity?
  833.     jnz     per_check_287_387_ret   ; if not 0, then skip
  834.     shl     savedand,1              ; savedand = (savedand << 1) + 1
  835.     inc     savedand                ; for longer periodicity
  836.     mov     savedincr,4             ; and restart counter
  837.     ret                             ; y ...
  838.  
  839. do_check_287_387:                       ; fpu stack is
  840.                     ; x y ...
  841.     fsub    savedx                  ; x-savedx y ...
  842.     fabs                            ; |x-savedx| y ...
  843.     fcomp   closenuff               ; y ...
  844.     fstsw   ax
  845.     sahf
  846.     ja      per_check_287_387_ret
  847.     fld     st                      ; y y ...
  848.     fsub    savedy                  ; y-savedy y ...
  849.     fabs                            ; |y-savedy| y ...
  850.     fcomp   closenuff               ; y ...
  851.     fstsw   ax
  852.     sahf
  853.     ja      per_check_287_387_ret
  854.                     ; caught a cycle!!!
  855.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  856.  
  857.     mov     ax,maxit
  858.     mov     realcolor,ax            ; save unadjusted realcolor as maxit
  859.     sub     ax,cx                   ; subtract half c
  860.     sub     kbdcount,ax             ; adjust the keyboard count
  861.     mov     ax,periodicity_color    ; set color
  862.     sub     cx,cx                   ; flag to exit cx loop immediately
  863.  
  864. per_check_287_387_ret:
  865.     ret
  866. periodicity_check_287_387   ENDP
  867.  
  868. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  869. .8086
  870. .8087
  871. periodicity_check_87    PROC    NEAR
  872. ; just like periodicity_check_287_387 except for the use of
  873. ;       fstsw tmp_word
  874. ; instead of
  875. ;       fstsw ax
  876.  
  877. ; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
  878.     fld     st(2)                   ; x y ...
  879.     test    cx,savedand             ; save on 0, check on anything else
  880.     jnz     do_check_87             ;  time to save a new "old" value
  881.  
  882. ; save last value                       ; fpu stack is
  883.                     ; x y ...
  884.     fstp    savedx                  ; y ...
  885.     fst     savedy                  ; y ...
  886.     dec     savedincr               ; time to lengthen the periodicity?
  887.     jnz     per_check_87_ret        ; if not 0, then skip
  888.     shl     savedand,1              ; savedand = (savedand << 1) + 1
  889.     inc     savedand                ; for longer periodicity
  890.     mov     savedincr,4             ; and restart counter
  891.     ret                             ; y ...
  892.  
  893. do_check_87:                            ; fpu stack is
  894.                     ; x y ...
  895.     fsub    savedx                  ; x-savedx y ...
  896.     fabs                            ; |x-savedx| y ...
  897.     fcomp   closenuff               ; y ...
  898.     fstsw   tmp_word
  899.     fwait
  900.     mov     ax,tmp_word
  901.     sahf
  902.     ja      per_check_87_ret
  903.     fld     st                      ; y y ...
  904.     fsub    savedy                  ; y-savedy y ...
  905.     fabs                            ; |y-savedy| y ...
  906.     fcomp   closenuff               ; y ...
  907.     fstsw   tmp_word
  908.     fwait
  909.     mov     ax,tmp_word
  910.     sahf
  911.     ja      per_check_87_ret
  912.                     ; caught a cycle!!!
  913.     mov     oldcolor,0FFFFh         ; check periodicity immediately next time
  914.  
  915.     mov     ax,maxit
  916.     mov     realcolor,ax            ; save unadjusted realcolor as maxit
  917.     sub     ax,cx
  918.     sub     kbdcount,ax             ; adjust the keyboard count
  919.  
  920.     mov     ax,periodicity_color    ; set color
  921.     sub     cx,cx                   ; flag to exit cx loop immediately
  922.  
  923. per_check_87_ret:
  924.     ret
  925. periodicity_check_87       ENDP
  926.  
  927. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  928. .8086
  929. .8087
  930. epsilon_cross   PROC    NEAR
  931.                     ; fpu stack is either
  932.                     ; y x Cx Cy b (387)
  933.                     ; y 1 x Cx Cy b (287/87/emul)
  934.     cmp     fpu,387
  935.     jb      ec_load_x
  936.     fld     st(1)                   ; if 387
  937.     jmp     short ec_end_load_x
  938. ec_load_x:
  939.     fld     st(2)                   ; if 287/87/emul
  940. ec_end_load_x:                          ; x y ...
  941.  
  942.     fabs                            ; |x| y 1 x Cx Cy b
  943.     fcomp   close                   ; y 1 x Cx Cy b
  944.     fstsw   tmp_word
  945.     fwait
  946.     mov     ax,tmp_word
  947.     sahf
  948.     jae     no_x_epsilon_cross
  949.     mov     ax,maxit                ; x is close to y axis
  950.     sub     ax,cx                   ; leave 'times through loop' in ax
  951. ; zero color fix
  952.     jnz     zero_color_fix_1
  953.     inc     ax                      ; if (ax == 0 ) ax = 1
  954. zero_color_fix_1:
  955.     mov     realcolor,ax            ; save unadjusted realcolor
  956.     sub     kbdcount,ax             ; adjust the keyboard count
  957.     mov     ax,GREEN                ;
  958.     sub     cx,cx                   ; flag to end loop
  959.     mov     oldcolor,cx             ; don't check next time
  960.     ret                             ; return
  961. no_x_epsilon_cross:                     ; y 1 x Cx Cy b
  962.     fld     st                      ; y y 1 x Cx Cy b
  963.     fabs                            ; |y| y 1 x Cx Cy b
  964.     fcomp   close                   ; y 1 x Cx Cy b
  965.     fstsw   tmp_word
  966.     fwait
  967.     mov     ax,tmp_word
  968.     sahf
  969.     jae     no_y_epsilon_cross
  970.     mov     ax,maxit                ; y is close to x axis
  971.     sub     ax,cx                   ; leave 'times through loop' in ax
  972. ; zero color fix
  973.     jnz     zero_color_fix_2
  974.     inc     ax                      ; if (ax == 0 ) ax = 1
  975. zero_color_fix_2:
  976.     mov     realcolor,ax            ; save unadjusted realcolor
  977.     sub     kbdcount,ax             ; adjust the keyboard count
  978.     mov     ax,YELLOW
  979.     sub     cx,cx                   ; flag to end loop
  980.     mov     oldcolor,cx             ; don't check next time
  981.     ret                             ; return
  982. no_y_epsilon_cross:
  983.     ret
  984. epsilon_cross   ENDP
  985. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  986. .8086
  987. .8087
  988. show_orbit_xy   PROC NEAR USES cx si di
  989.     local    tmp_ten_byte_0:tbyte    ; stupid klooge for MASM 5.1 LOCAL bug
  990.     local    tmp_ten_byte_1:tbyte
  991.     local    tmp_ten_byte_2:tbyte
  992.     local    tmp_ten_byte_3:tbyte
  993.     local    tmp_ten_byte_4:tbyte
  994.     local    tmp_ten_byte_5:tbyte
  995.     local    tmp_ten_byte_6:tbyte
  996. ; USES is needed because in all likelyhood, plot_orbit surely
  997. ; uses these registers.  It's ok to have to push/pop's here in the
  998. ; orbits as speed is not crucial when showing orbits.
  999.  
  1000.                     ; fpu stack is either
  1001.                     ; y x Cx Cy b (387)
  1002.                     ; y 1 x Cx Cy b (287/87/emul)
  1003.     cmp     fpu,387
  1004.     jb      so_load_x
  1005.     fld     st(1)                   ; if 387
  1006.     jmp     short so_end_load_x
  1007. so_load_x:
  1008.     fld     st(2)                   ; if 287/87/emul
  1009. so_end_load_x:
  1010.                     ; x y ...
  1011.                     ; and needs to returned as
  1012.                     ; y ...
  1013.  
  1014.     fstp    orbit_real              ; y ...
  1015.     fst     orbit_imag              ; y ...
  1016.     mov     ax,-1                   ; color for plot orbit
  1017.     push    ax                      ;       ...
  1018. ; since the number fpu registers that plot_orbit() preserves is compiler
  1019. ; dependant, it's best to fstp the entire stack into 10 byte memories
  1020. ; and fld them back after plot_orbit() returns.
  1021.     fstp    tmp_ten_byte_1          ; store the stack in 80 bit form
  1022.     fstp    tmp_ten_byte_2
  1023.     fstp    tmp_ten_byte_3
  1024.     fstp    tmp_ten_byte_4
  1025.     fstp    tmp_ten_byte_5
  1026.     cmp     fpu,287                 ; with 287/87/emul the stack is 6 high
  1027.     jg      no_store_6              ; with 387 it is only 5 high
  1028.     fstp    tmp_ten_byte_6
  1029. no_store_6:
  1030.     fwait                           ; just to be safe
  1031.     push    word ptr orbit_imag+6   ; co-ordinates for plot orbit
  1032.     push    word ptr orbit_imag+4   ;       ...
  1033.     push    word ptr orbit_imag+2   ;       ...
  1034.     push    word ptr orbit_imag     ;       ...
  1035.     push    word ptr orbit_real+6   ; co-ordinates for plot orbit
  1036.     push    word ptr orbit_real+4   ;       ...
  1037.     push    word ptr orbit_real+2   ;       ...
  1038.     push    word ptr orbit_real     ;       ...
  1039.     call    far ptr plot_orbit      ; display the orbit
  1040.     add     sp,9*2                  ; clear out the parameters
  1041.  
  1042.         cmp     fpu,287
  1043.         jg      no_load_6
  1044.         fld     tmp_ten_byte_6          ; load them back in reverse order
  1045. no_load_6:
  1046.     fld    tmp_ten_byte_5
  1047.     fld    tmp_ten_byte_4
  1048.     fld    tmp_ten_byte_3
  1049.     fld    tmp_ten_byte_2
  1050.     fld    tmp_ten_byte_1
  1051.     fwait                           ; just to be safe
  1052.     ret
  1053. show_orbit_xy   ENDP
  1054. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1055. .8086
  1056. .8087
  1057. special_outside PROC NEAR
  1058. ; When type casting floating point variables to integers in C, the decimal
  1059. ; is truncated.  When using FIST in asm, the value is rounded.  Using
  1060. ; "FSUB round_down_half" causes the values to be rounded down.
  1061.  
  1062.     cmp     outside,-2
  1063.     jne     not_real
  1064.     fld     newx
  1065.     fsub    round_down_half
  1066.     fistp   tmp_word
  1067.     add     ax,7
  1068.     fwait
  1069.     add     ax,tmp_word
  1070.     jmp     short check_color
  1071. not_real:
  1072.     cmp     outside,-3
  1073.     jne     not_imag
  1074.     fld     newy
  1075.     fsub    round_down_half
  1076.     fistp   tmp_word
  1077.     add     ax,7
  1078.     fwait
  1079.     add     ax,tmp_word
  1080.     jmp     short check_color
  1081. not_imag:
  1082.     cmp     outside,-4
  1083.     jne     not_mult
  1084.     fld     newy
  1085.     ftst                    ; check to see if newy == 0
  1086.     fstsw   tmp_word
  1087.     push    ax              ; save current ax value
  1088.     fwait
  1089.     mov     ax,tmp_word
  1090.     sahf
  1091.     pop     ax              ; retrieve ax (does not affect flags)
  1092.     jne     non_zero_y
  1093.     ret                     ; if y==0, return with normal ax
  1094. non_zero_y:
  1095.     fdivr   newx            ; newx/newy
  1096.     mov     tmp_word,ax
  1097.     fimul   tmp_word        ; ax*newx/newy  (Use FIMUL instead of MUL
  1098.     fsub    round_down_half ; to make it match the C code.)
  1099.     fistp   tmp_word
  1100.     fwait
  1101.     mov     ax,tmp_word
  1102.     jmp     short check_color
  1103. not_mult:
  1104.     cmp     outside,-5      ; currently always equal, but put here
  1105.     jne     not_sum         ; for future outside types
  1106.     fld     newx
  1107.     fadd    newy            ; newx+newy
  1108.     fsub    round_down_half
  1109.     fistp   tmp_word
  1110.     fwait
  1111.     add     ax,tmp_word
  1112.  
  1113. not_sum:
  1114. check_color:
  1115.     cmp     ax,maxit                ; use UNSIGNED comparison
  1116.     jbe     special_outside_ret     ; color < 0 || color > maxit
  1117.     sub     ax,ax                   ; ax = 0
  1118. special_outside_ret:
  1119.     ret
  1120. special_outside ENDP
  1121.  
  1122. .8086   ;just to be sure
  1123. .8087
  1124. END
  1125.