📄 calmanfp.asm
字号:
jmp short end_pop_stack_87
no_emulation: ; if no emulation, then
fninit ; use the faster FNINIT
end_pop_stack_87:
mov color,ax
cmp orbit_ptr,0 ; any orbits to clear?
je calcmandfpasm_ret_87 ; nope.
call far ptr scrub_orbit ; clear out any old orbits
mov ax,color ; restore color
; speed not critical here in orbit land
calcmandfpasm_ret_87:
UNFRAME <si,di> ; pop stack frame
fwait ; just to make sure
ret
over_bailout_87: ; x^2 y^2 1 xy Cx Cy b
; outside
mov ax,cx
sub ax,10 ; 10 more next time before checking
jns no_fix_underflow_87
; if the number of iterations was within 10 of maxit, then subtracting
; 10 would underflow and cause periodicity checking to start right
; away. Catching a period doesn't occur as often in the pixels at
; the edge of the set anyway.
sub ax,ax ; don't check next time
no_fix_underflow_87:
mov oldcolor,ax ; check when past this - 10 next time
mov ax,maxit
sub ax,cx ; leave 'times through loop' in ax
; zero color fix
jnz zero_color_fix_87
inc ax ; if (ax == 0 ) ax = 1
zero_color_fix_87:
mov realcolor,ax ; save unadjusted realcolor
sub kbdcount,ax ; adjust the keyboard count
cmp outside,-1 ; iter ? (most common case)
je pop_stack_7_87
cmp outside,-2 ; outside <= -2 ?
jle special_outside_87 ; yes, go do special outside options
mov ax,outside ; use outside color
jmp short pop_stack_7_87
special_outside_87:
call near ptr special_outside
jmp short pop_stack_7_87
calcmandfpasm ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Since periodicity checking is used most of the time, I decided to
; separate the periodicity_check routines into a _287_387 version
; and an _87 version to achieve a slight increase in speed. The
; epsilon_cross, show_orbit_xy, and special_outside routines are less
; frequently used and therefore have been implemented as single routines
; usable by the 8087 and up. -Wes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.286
.287
periodicity_check_287_387 PROC NEAR
; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
; fpu stack is either
; y x Cx Cy b (387)
; y 1 x Cx Cy b (287/emul)
cmp fpu,387
jb pc_load_x
fld st(1) ; if 387
jmp short pc_end_load_x
pc_load_x:
fld st(2) ; if 287/emul
pc_end_load_x:
; x y ...
test cx,savedand ; save on 0, check on anything else
jnz do_check_287_387 ; time to save a new "old" value
; save last value ; fpu stack is
fstp savedx ; x y ...
fst savedy ; y ...
dec savedincr ; time to lengthen the periodicity?
jnz per_check_287_387_ret ; if not 0, then skip
shl savedand,1 ; savedand = (savedand << 1) + 1
inc savedand ; for longer periodicity
mov savedincr,4 ; and restart counter
ret ; y ...
do_check_287_387: ; fpu stack is
; x y ...
fsub savedx ; x-savedx y ...
fabs ; |x-savedx| y ...
fcomp closenuff ; y ...
fstsw ax
sahf
ja per_check_287_387_ret
fld st ; y y ...
fsub savedy ; y-savedy y ...
fabs ; |y-savedy| y ...
fcomp closenuff ; y ...
fstsw ax
sahf
ja per_check_287_387_ret
; caught a cycle!!!
mov oldcolor,0FFFFh ; check periodicity immediately next time
mov ax,maxit
mov realcolor,ax ; save unadjusted realcolor as maxit
sub ax,cx ; subtract half c
sub kbdcount,ax ; adjust the keyboard count
mov ax,periodicity_color ; set color
sub cx,cx ; flag to exit cx loop immediately
per_check_287_387_ret:
ret
periodicity_check_287_387 ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.8086
.8087
periodicity_check_87 PROC NEAR
; just like periodicity_check_287_387 except for the use of
; fstsw tmp_word
; instead of
; fstsw ax
; REMEMBER, the cx counter is counting BACKWARDS from maxit to 0
fld st(2) ; x y ...
test cx,savedand ; save on 0, check on anything else
jnz do_check_87 ; time to save a new "old" value
; save last value ; fpu stack is
; x y ...
fstp savedx ; y ...
fst savedy ; y ...
dec savedincr ; time to lengthen the periodicity?
jnz per_check_87_ret ; if not 0, then skip
shl savedand,1 ; savedand = (savedand << 1) + 1
inc savedand ; for longer periodicity
mov savedincr,4 ; and restart counter
ret ; y ...
do_check_87: ; fpu stack is
; x y ...
fsub savedx ; x-savedx y ...
fabs ; |x-savedx| y ...
fcomp closenuff ; y ...
fstsw tmp_word
fwait
mov ax,tmp_word
sahf
ja per_check_87_ret
fld st ; y y ...
fsub savedy ; y-savedy y ...
fabs ; |y-savedy| y ...
fcomp closenuff ; y ...
fstsw tmp_word
fwait
mov ax,tmp_word
sahf
ja per_check_87_ret
; caught a cycle!!!
mov oldcolor,0FFFFh ; check periodicity immediately next time
mov ax,maxit
mov realcolor,ax ; save unadjusted realcolor as maxit
sub ax,cx
sub kbdcount,ax ; adjust the keyboard count
mov ax,periodicity_color ; set color
sub cx,cx ; flag to exit cx loop immediately
per_check_87_ret:
ret
periodicity_check_87 ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.8086
.8087
epsilon_cross PROC NEAR
; fpu stack is either
; y x Cx Cy b (387)
; y 1 x Cx Cy b (287/87/emul)
cmp fpu,387
jb ec_load_x
fld st(1) ; if 387
jmp short ec_end_load_x
ec_load_x:
fld st(2) ; if 287/87/emul
ec_end_load_x: ; x y ...
fabs ; |x| y 1 x Cx Cy b
fcomp close ; y 1 x Cx Cy b
fstsw tmp_word
fwait
mov ax,tmp_word
sahf
jae no_x_epsilon_cross
mov ax,maxit ; x is close to y axis
sub ax,cx ; leave 'times through loop' in ax
; zero color fix
jnz zero_color_fix_1
inc ax ; if (ax == 0 ) ax = 1
zero_color_fix_1:
mov realcolor,ax ; save unadjusted realcolor
sub kbdcount,ax ; adjust the keyboard count
mov ax,GREEN ;
sub cx,cx ; flag to end loop
mov oldcolor,cx ; don't check next time
ret ; return
no_x_epsilon_cross: ; y 1 x Cx Cy b
fld st ; y y 1 x Cx Cy b
fabs ; |y| y 1 x Cx Cy b
fcomp close ; y 1 x Cx Cy b
fstsw tmp_word
fwait
mov ax,tmp_word
sahf
jae no_y_epsilon_cross
mov ax,maxit ; y is close to x axis
sub ax,cx ; leave 'times through loop' in ax
; zero color fix
jnz zero_color_fix_2
inc ax ; if (ax == 0 ) ax = 1
zero_color_fix_2:
mov realcolor,ax ; save unadjusted realcolor
sub kbdcount,ax ; adjust the keyboard count
mov ax,YELLOW
sub cx,cx ; flag to end loop
mov oldcolor,cx ; don't check next time
ret ; return
no_y_epsilon_cross:
ret
epsilon_cross ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.8086
.8087
show_orbit_xy PROC NEAR USES cx si di
local tmp_ten_byte_0:tbyte ; stupid klooge for MASM 5.1 LOCAL bug
local tmp_ten_byte_1:tbyte
local tmp_ten_byte_2:tbyte
local tmp_ten_byte_3:tbyte
local tmp_ten_byte_4:tbyte
local tmp_ten_byte_5:tbyte
local tmp_ten_byte_6:tbyte
; USES is needed because in all likelyhood, plot_orbit surely
; uses these registers. It's ok to have to push/pop's here in the
; orbits as speed is not crucial when showing orbits.
; fpu stack is either
; y x Cx Cy b (387)
; y 1 x Cx Cy b (287/87/emul)
cmp fpu,387
jb so_load_x
fld st(1) ; if 387
jmp short so_end_load_x
so_load_x:
fld st(2) ; if 287/87/emul
so_end_load_x:
; x y ...
; and needs to returned as
; y ...
fstp orbit_real ; y ...
fst orbit_imag ; y ...
mov ax,-1 ; color for plot orbit
push ax ; ...
; since the number fpu registers that plot_orbit() preserves is compiler
; dependant, it's best to fstp the entire stack into 10 byte memories
; and fld them back after plot_orbit() returns.
fstp tmp_ten_byte_1 ; store the stack in 80 bit form
fstp tmp_ten_byte_2
fstp tmp_ten_byte_3
fstp tmp_ten_byte_4
fstp tmp_ten_byte_5
cmp fpu,287 ; with 287/87/emul the stack is 6 high
jg no_store_6 ; with 387 it is only 5 high
fstp tmp_ten_byte_6
no_store_6:
fwait ; just to be safe
push word ptr orbit_imag+6 ; co-ordinates for plot orbit
push word ptr orbit_imag+4 ; ...
push word ptr orbit_imag+2 ; ...
push word ptr orbit_imag ; ...
push word ptr orbit_real+6 ; co-ordinates for plot orbit
push word ptr orbit_real+4 ; ...
push word ptr orbit_real+2 ; ...
push word ptr orbit_real ; ...
call far ptr plot_orbit ; display the orbit
add sp,9*2 ; clear out the parameters
cmp fpu,287
jg no_load_6
fld tmp_ten_byte_6 ; load them back in reverse order
no_load_6:
fld tmp_ten_byte_5
fld tmp_ten_byte_4
fld tmp_ten_byte_3
fld tmp_ten_byte_2
fld tmp_ten_byte_1
fwait ; just to be safe
ret
show_orbit_xy ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.8086
.8087
special_outside PROC NEAR
; When type casting floating point variables to integers in C, the decimal
; is truncated. When using FIST in asm, the value is rounded. Using
; "FSUB round_down_half" causes the values to be rounded down.
cmp outside,-2
jne not_real
fld newx
fsub round_down_half
fistp tmp_word
add ax,7
fwait
add ax,tmp_word
jmp short check_color
not_real:
cmp outside,-3
jne not_imag
fld newy
fsub round_down_half
fistp tmp_word
add ax,7
fwait
add ax,tmp_word
jmp short check_color
not_imag:
cmp outside,-4
jne not_mult
fld newy
ftst ; check to see if newy == 0
fstsw tmp_word
push ax ; save current ax value
fwait
mov ax,tmp_word
sahf
pop ax ; retrieve ax (does not affect flags)
jne non_zero_y
ret ; if y==0, return with normal ax
non_zero_y:
fdivr newx ; newx/newy
mov tmp_word,ax
fimul tmp_word ; ax*newx/newy (Use FIMUL instead of MUL
fsub round_down_half ; to make it match the C code.)
fistp tmp_word
fwait
mov ax,tmp_word
jmp short check_color
not_mult:
cmp outside,-5 ; currently always equal, but put here
jne not_sum ; for future outside types
fld newx
fadd newy ; newx+newy
fsub round_down_half
fistp tmp_word
fwait
add ax,tmp_word
not_sum:
check_color:
cmp ax,maxit ; use UNSIGNED comparison
jbe special_outside_ret ; color < 0 || color > maxit
sub ax,ax ; ax = 0
special_outside_ret:
ret
special_outside ENDP
.8086 ;just to be sure
.8087
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -