home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Computerworld 1996 March
/
Computerworld_1996-03_cd.bin
/
idg_cd3
/
grafika
/
fraktaly
/
frasr192
/
parsera.asm
< prev
next >
Wrap
Assembly Source File
|
1995-03-18
|
98KB
|
2,132 lines
PAGE ,132
; Name: PARSERA.ASM
; Author: Chuck Ebbert CompuServe [76306,1226]
; internet: 76306.1226@compuserve.com
; Fast floating-point routines for Fractint.
; (c) Copyright 1992-1995 Chuck Ebbert. All rights reserved.
; This program is an assembler version of the C 'execution engine' part
; of Mark Peterson's FRACTINT Formula Parser. Many of the operator
; functions were copied from Mark's code in the files FPU087.ASM
; and FPU387.ASM. The basic operator functions are assembler versions
; of the code in PARSER.C. Many 'combined' operator functions were
; added to the program as well.
; As of 31 Decmember 1993 this is also an in-memory compiler. The code
; generator is in PARSERFP.C. Define the variable COMPILER to
; build the compiler, otherwise the interpreter will be built.
; COMPILER must also be #defined in PARSERFP.C to build compiler.
; This code may be freely distributed and used in non-commercial
; programs provided the author is credited either during program
; execution or in the documentation, and this copyright notice
; is left intact. Sale of this code, or its use in any commercial
; product requires permission from the author. Nominal distribution
; and handling fees may be charged by shareware and freeware
; distributors.
; Date Init Change description
; 7 Mar 1995 TIW Added PWR (0,0) domain check
; 21 Feb 1995 TIW Shortened ATanh/ATan for MASM 6 compatibility
; 21 Feb 1995 CAE Changes ATan and ATanh
; 15 Feb 1995 CAE Added safety tests to macros.
; Changed fStkASin, etc. to work with compiler.
; Added fwait to Sto2 function for safety.
; 8 Feb 1995 CAE Removed transparent3d code.
; Added inversion support (compiler untested.)
; 8 Jan 1995 JCO Added fStkASin, fStkASinh, fStkACos, fStkACosh,
; fStkATan, fStkATanh, fStkSqrt, fStkCAbs.
; 31 Dec 1994 JCO Made changes to keep code in line with C code.
; Not necessary, since code isn't called. Will
; make it easier to make it run later. Added
; old <- z to end of fform_per_pixel to match
; C code.
; 30 Dec 1993 CAE Compiler is working
; Changed EXIT_OPER -> ret in 3 operator fns
; Added safety test for fn size in macros
; 12 Dec 1993 CAE Compiler additions
; 4 Dec 1993 CAE SinhCosh function accuracy improved
; Added LoadImagAdd/Sub/Mul
; 19 Nov 1993 CAE Revised macros for compiler mode.
; 10 Nov 1993 CAE Changed Exp function for more accuracy.
; 06 Nov 93 CAE Added 'LodRealPwr', 'One', 'ORClr2', 'Sqr3'.
; Revised Pwr function to use regs vs. memory.
; Changed many functions to 'included' type.
; 31 Oct 93 CAE Added 'Dbl' function.
; 09 Oct 1993 CAE Changed SinhCosh to use wider range of 387.
; Most FNINITs changed to FINIT.
; Loop logic revised slightly.
; Separated code from parserfp.c's codeseg.
; Added fStkStoClr2, fStkZero and fStkIdent.
; New 'pseudo calctype' fn. fFormulaX added.
; 12 Jul 1993 CAE Moved BadFormula to PARSER.C.
.386 ; this only works on a 386
.387 ; with a 387
ifdef ??version
masm51
quirks
endif
ARGSZ equ 16 ; size of complex arg
;;;ARGSZ equ 32 ; size of hypercomplex arg
CPFX equ 4 ; size of constarg prefix
CARG equ CPFX+ARGSZ ; size of constarg
LASTSQR equ CARG*4+CPFX ; offset of lastsqr from start of v
; ---------------------------------------------------------------------------
FRAME MACRO regs ; build a stack frame
push bp
mov bp, sp
IRP reg, <regs>
push reg
ENDM
ENDM
UNFRAME MACRO regs ; unframe before return
IRP reg, <regs>
pop reg
ENDM
pop bp
ENDM
; ---------------------------------------------------------------------------
; Pop a number of scalars from the FPU stack.
; Generate as many 'fcompp' instr.'s as possible.
; Then a 'fstp st(0)' if needed.
POP_STK MACRO StkPop
NumToPop = StkPop SHR 1
REPT NumToPop
fcompp
ENDM
NumToPop = StkPop - ( NumToPop SHL 1 )
REPT NumToPop
fstp st(0)
ENDM
ENDM
; Uncomment the following line to enable compiler code generation.
;COMPILER EQU 1
; ---------------------------------------------------------------------------
; Generate beginning code for operator fn.
BEGN_OPER MACRO OperName
ifndef COMPILER
;; only align when no compiler
align 4
endif
;; always generate public and begin of proc (before fixups)
public _fStk&OperName
_fStk&OperName proc near
ifdef COMPILER
;; generate the fixups for compiler
;; size of fn. | 8000h to mark it as an OPER instead of an INCL CAE 27Dec93
dw Size_&OperName OR 8000h
;; near pointer to the start of actual code CAE 19Dec93
dw offset PARSERA_TEXT:Code_&OperName
;; addr of fn to include (undefined if Incl_&OperName==255 below)
dw IAddr_&OperName
;; offset of x fixup or 255 if none
db XFixup_&OperName
;; offset of y fixup or 255 if none
db YFixup_&OperName
;; offset of included(called) fn or 255 if none
db Incl_&OperName
endif
;; added label for code begin point CAE 25Nov93
Code_&OperName:
ENDM
; ---------------------------------------------------------------------------
END_OPER MACRO OperName
; Generate end of operator fn. code.
ifndef COMPILER
;; gen a return instr.
ret
else
;; gen a jump label
End_&OperName:
;; generate zero for fixups not generated during fn.
ifndef Incl_&OperName
;; No included operator. Generate 255 offset, 0 address. CAE 19Nov93
Incl_&OperName EQU 255
IAddr_&OperName EQU 0
endif
ifndef XFixup_&OperName
XFixup_&OperName EQU 255
endif
ifndef YFixup_&OperName
YFixup_&OperName EQU 255
endif
endif
;; Always gen size of fn (subtract size of header here)
Size_&OperName EQU $ - Code_&OperName
;; Make sure fn is of legal size CAE 30DEC93
.errnz (Size_&OperName GT 127)
;; and end of procedure.
_fStk&OperName endp
ENDM
; ---------------------------------------------------------------------------
BEGN_INCL MACRO OperName
;; Generate beginning code for 'included' operator fn.
;; No fixups allowed in one of these functions.
;; Safety test: generate an equate here so the INCL_OPER CAE 15Feb95
;; macro can test to see if this really is includable.
Is_Incl_&OperName EQU 1
;; Don't bother with align in compiler mode.
ifndef COMPILER
align 4
endif
;; Generate public (incl fns. can be called directly) and begin of proc.
public _fStk&OperName
_fStk&OperName proc near
ifdef COMPILER
;; Size of included fn. changed to word CAE 27Dec93
dw Size_&OperName
endif
;; added label for code begin point CAE 25Nov93
Code_&OperName:
ENDM
; ---------------------------------------------------------------------------
; Generate end of 'included' operator fn. code.
END_INCL MACRO OperName
ifndef COMPILER
;; generate return
ret
else
;; generate label for jump to end of fn.
End_&OperName:
endif
;; always generate actual size of fn. (subtract hdr. size)
Size_&OperName EQU $ - Code_&OperName
;; Make sure fn is of legal size CAE 30DEC93
.errnz (Size_&OperName GT 127)
;; always generate end-of-proc
_fStk&OperName endp
ENDM
; ---------------------------------------------------------------------------
; 'Include' a function inside another one
INCL_OPER MACRO CallingOper,OperToIncl
;; Make sure the included fn was defined with the BEGN_INCL macro.
ifndef Is_Incl_&OperToIncl ; CAE 15Feb95
.error "Included function was not defined with BEGN_INCL macro"
endif
;; Gen equate for offset of include in outer fn.
;; Always generate this to prevent >1 include even when not CAE 15FEB95
;; building the compiler.
Incl_&CallingOper EQU $ - Code_&CallingOper
ifdef COMPILER
;; Address of included fn.
IAddr_&CallingOper EQU _fStk&OperToIncl
;; Gen 1 1-byte placeholder for the included fn to make codegen easier
db 0ffH
else
;; Generate a call to the included fn.
call _fStk&OperToIncl
endif
ENDM
; ---------------------------------------------------------------------------
; Exit early from an operator function.
EXIT_OPER MACRO FnToExit
ifdef COMPILER
;; jump to end of operator fn
jmp short End_&FnToExit
else
;; return to caller
ret
endif
ENDM
; ---------------------------------------------------------------------------
; Generate an FPU instruction and a fixup.
; AddrToFix is = X or Y
FIXUP MACRO OperName, InstrToFix, Addr
ifdef COMPILER
;; Generate a fixup as an offset from start of fn.
;; Fixup is two bytes into the instruction, thus the '+ 2'.
;; This may not be true for all instructions.
ifidni <Addr>, <X>
XFixup_&OperName EQU $ - Code_&OperName + 2
else
;; assume fixup is for y
YFixup_&OperName EQU $ - Code_&OperName + 2
endif
;; Generate a load, store or whatever of any convenient value using DS.
&InstrToFix QWORD PTR ds:_fLastOp
else
ifidni <Addr>, <X>
;; Gen load of X using SI.
&InstrToFix QWORD PTR [si]
else
;; Assume fixup is for y, use SI+8.
&InstrToFix QWORD PTR [si+8]
endif
endif
ENDM
; ---------------------------------------------------------------------------
; Align 4 if no compiler.
PARSALIGN macro AlignFn
ifndef COMPILER
align 4
endif
ENDM
; CAE added macros for common operations Feb 1995
GEN_SQR0 macro
;; square the stack top, don't save magnitude in lastsqr CAE 15FEB95
fld st(0) ; x x y
fld st(0) ; x x x y
fmul st,st(3) ; xy x x y
fadd st,st ; 2xy x x y
fxch st(3) ; y x x 2xy
fadd st(2),st ; y x x+y 2xy
fsubp st(1),st ; x-y x+y 2xy
fmulp st(1),st ; xx-yy 2xy
ENDM
GEN_SQRT macro ; CAE 15Feb95
; can use a max of 2 regs
fld st(1) ; y x y
fld st(1) ; x y x y
fpatan ; atan x y
fdiv __2_ ; theta=atan/2 x y
fsincos ; cos sin x y
fxch st(3) ; y sin x cos
fmul st,st(0) ; yy sin x cos
fxch st(2) ; x sin yy cos
fmul st,st(0) ; xx sin yy cos
faddp st(2),st ; sin xx+yy cos
fxch st(2) ; cos xx+yy sin
fxch ; xx+yy cos sin
fsqrt ; sqrt(xx+yy) cos sin
fsqrt ; mag=sqrt(sqrt(xx+yy)) cos sin
fmul st(2),st ; mag cos mag*sin
fmulp st(1),st ; mag*cos mag*sin
ENDM
; ---------------------------------------------------------------------------
; external functions
extrn _invertz2:far
; ---------------------------------------------------------------------------
_DATA segment word public use16 'DATA'
extrn _invert:WORD
extrn _maxit:DWORD
extrn _inside:WORD
extrn _outside:WORD
extrn _coloriter:DWORD
extrn _kbdcount:WORD ; keyboard counter
extrn _dotmode:WORD
extrn __1_:QWORD, _PointFive:QWORD, __2_:QWORD, _infinity:QWORD
extrn _LastOp:WORD, _LastInitOp:WORD
extrn _InitOpPtr:WORD, _InitStoPtr:WORD, _InitLodPtr:WORD
extrn _s:WORD
extrn _OpPtr:WORD, _LodPtr:WORD, _StoPtr:WORD
extrn _Load:DWORD, _Store:DWORD
extrn _FormName:byte
extrn _dy1:DWORD, _dx1:DWORD, _dy0:DWORD, _dx0:DWORD
extrn _new:WORD, _old:WORD
extrn _overflow:WORD
extrn _col:WORD, _row:WORD
extrn _Arg1:WORD, _Arg2:WORD
extrn _f:DWORD, _pfls:DWORD, _v:DWORD
extrn _debugflag:WORD
_DATA ends
; ---------------------------------------------------------------------------
_BSS segment word public use16 'BSS'
_fLastOp label DWORD ; save seg, offset of lastop here
dd ?
_PtrToZ label WORD ; offset of z
dw ?
_BSS ends
DGROUP group _DATA,_BSS
; ---------------------------------------------------------------------------
; Operator Functions follow.
; ---------------------------------------------------------------------------
; NOTE: None of these operator functions may change any registers but
; ax and si. The exceptions are those functions that update
; the current values of the 'status' regs as needed.
; On entry to these functions:
; FPU stack is used as the evaluation stack.
; The FPU stack can overflow into memory. Accuracy is not lost but
; calculations are slower.
; es -> DGROUP
; ds -> parser data
; cx -> lastop
; edx == orbit counter (in fFormulaX)
; di -> stack overflow area, used by push and pull functions and as
; a temporary storage area
; bx -> current operator, operand pair
; [bx] = operator function address, i.e. addr. of current '_fStkXXX'
; [bx+2] = operand pointer or zero if no operand
; si = operand pointer (loaded from [bx+2] before call of operator fn.)
; New rules Feb 1993:
; 1. No EXIT_OPER before an INCL_OPER
; (no jumps can be made past an included function.)
; 2. No included fn may include another, or have any fixups.
; 3. Only one included fn. allowed per 'normal' fn.
; --------------------------------------------------------------------------
; Put this code in PARSERA_TEXT, not PARSERFP_TEXT CAE 09OCT93
PARSERA_TEXT segment para public use16 'CODE'
; Non-standard segment register setup.
assume es:DGROUP, ds:nothing, cs:PARSERA_TEXT
; --------------------------------------------------------------------------
; Included functions must be before any fns that include them.
; --------------------------------------------------------------------------
BEGN_INCL Log ; Log
; From FPU387.ASM
; Log is called by Pwr and is also called directly.
ftst
fstsw ax
sahf
jnz short NotBothZero
fxch ; y x
ftst
fstsw ax
sahf
fxch ; x y
jnz short NotBothZero
POP_STK 2 ; clear two numbers
fldz
fldz
mov ax, 1 ; domain error (1 in ax)
EXIT_OPER Log ; return (0,0)
PARSALIGN
NotBothZero:
xor ax,ax ; no domain error (0 in ax)
fld st(1) ; y x y
fld st(1) ; x y x y
fpatan ; z.y x y
fxch st(2) ; y x z.y
fmul st,st(0) ; yy x z.y
fxch ; x yy z.y
fmul st,st(0) ; xx yy z.y
fadd ; mod z.y
fldln2 ; ln2, mod, z.y
fmul _PointFive ; ln2/2, mod, z.y
fxch ; mod, ln2/2, z.y
fyl2x ; z.x, z.y
END_INCL Log
; --------------------------------------------------------------------------
BEGN_INCL SinhCosh ; Included fn, Sinh, Cosh of st
; From FPU087.ASM with mods to use less registers & for 387.
; Mod for 387-only after Fractint v18. CAE 09OCT93
; NOTE: Full 80-bit accuracy is *NOT* maintained in this function!
; Only 1 additional register can be used here.
; Changed fn so that rounding errors are less. CAE 04DEC93
fstcw _Arg2 ; use arg2 to hold CW
fwait
fldln2 ; ln(2) x
fdivp st(1),st ; x/ln(2), start the fdivr instr.
mov ax,_Arg2 ; Now do some integer instr.'s
push ax ; Save control word on stack
or ax,0000110000000000b
mov _Arg2,ax
fld st ; x/ln(2), x/ln(2)
fldcw _Arg2 ; Now set control to round toward zero
; Chop toward zero rounding applies now CAE 4DEC93
frndint ; int = integer(x/ln(2)), x/ln(2)
pop ax ; restore old CW to AX
mov _Arg2,ax ; ...then move it to Arg2
fldcw _Arg2 ; Restore control word from Arg2
; Normal rounding is in effect again CAE 4DEC93
fxch ; x/ln(2), int
fsub st,st(1) ; -1 < rem < 1.0, int
f2xm1 ; 2**rem-1, int
fadd __1_ ; 2**rem, int
fscale ; e**x, int
fstp st(1) ; e**x
fld st ; e**x, e**x
fmul _PointFive ; e^x/2 e^x
fstp QWORD PTR es:[di] ; e^x use overflow stk for temp here
fdivr _PointFive ; e**-x/2
fld st ; e**-x/2, e**-x/2
fadd QWORD PTR es:[di] ; coshx, e**-x/2
fxch ; e^-x/2, coshx
fsubr QWORD PTR es:[di] ; sinhx, coshx (fsubr pending)
END_INCL SinhCosh
; --------------------------------------------------------------------------
BEGN_INCL Ident ; Ident CAE 09OCT93
END_INCL Ident
; --------------------------------------------------------------------------
BEGN_INCL Sqr3 ; Sqr3 CAE 06NOV93
fmul st,st(0) ; Magnitude/sqr of a real# on st
END_INCL Sqr3 ; x^2 0 ...
; --------------------------------------------------------------------------
BEGN_INCL Conj ; Complex conjugate
fxch ; y x ...
fchs ; -y x ...
fxch ; x -y ...
END_INCL Conj
; --------------------------------------------------------------------------
BEGN_INCL Conj2 ; Complex conjugate (uses a reg)
fldz ; 0 x y ... CAE 20Nov93
fsubrp st(2),st ; x -y ...
END_INCL Conj2
; --------------------------------------------------------------------------
BEGN_INCL Real ; Real
fstp st(1) ; x ...
fldz ; 0 x ...
fxch ; x 0 ...
END_INCL Real
; --------------------------------------------------------------------------
BEGN_INCL RealFlip ; Real, flip combined.
fstp st(1) ; y=x ...
fldz ; x=0 y ...
END_INCL RealFlip
; --------------------------------------------------------------------------
BEGN_INCL Add ; Add
faddp st(2),st ; Arg2->d.x += Arg1->d.x;
faddp st(2),st ; Arg2->d.y += Arg1->d.y;
END_INCL Add
; --------------------------------------------------------------------------
BEGN_INCL Sub ; Subtract
fsubp st(2),st ; Arg2->d.x -= Arg1->d.x;
fsubp st(2),st ; Arg2->d.y -= Arg1->d.y;
END_INCL Sub
; --------------------------------------------------------------------------
BEGN_OPER LodRealAdd ; Load, Real, Add combined
FIXUP LodRealAdd, fadd, X ; Add x-value from memory
END_OPER LodRealAdd
; --------------------------------------------------------------------------
BEGN_OPER LodRealSub ; Load, Real, Subtract combined
FIXUP LodRealSub, fsub, X ; (fsub qword ptr X)
END_OPER LodRealSub
; --------------------------------------------------------------------------
BEGN_OPER LodImagAdd ; Load, Imag, Add combined CAE 4DEC93
FIXUP LodImagAdd, fadd, Y ; Add x-value from memory
END_OPER LodImagAdd
; --------------------------------------------------------------------------
BEGN_OPER LodImagSub ; Load, Imag, Sub combined CAE 4DEC93
FIXUP LodImagSub, fsub, Y ; (fsub qword ptr X)
END_OPER LodImagSub
; --------------------------------------------------------------------------
BEGN_INCL Real2 ; Real value (fast version)
fldz ; 0 x y ... (uses a reg)
fstp st(2) ; x 0 ...
END_INCL Real2
; --------------------------------------------------------------------------
BEGN_OPER Lod ; Load
FIXUP Lod, fld, Y ; y ...
FIXUP Lod, fld, X ; x y ...
END_OPER Lod
; --------------------------------------------------------------------------
BEGN_INCL Clr1 ; Clear stack
finit ; changed from fninit CAE 09OCT93
END_INCL Clr1
; --------------------------------------------------------------------------
BEGN_INCL Imag ; Imaginary value
POP_STK 1 ; y
fldz ; 0 y
fxch ; x=y 0
END_INCL Imag
; --------------------------------------------------------------------------
BEGN_INCL ImagFlip ; Imaginary value, flip combined
POP_STK 1 ; y ...
fldz ; x=0 y ...
END_INCL ImagFlip
; --------------------------------------------------------------------------
BEGN_INCL Abs ; Absolute value
fxch
fabs
fxch
fabs
END_INCL Abs
; --------------------------------------------------------------------------
BEGN_OPER LodRealMul ; Load, Real, Multiply
FIXUP LodRealMul, fld, X ; y.x x.x x.y
fmul st(2),st ; y.x x.x z.y
fmul ; z.x z.y
END_OPER LodRealMul
; --------------------------------------------------------------------------
BEGN_OPER LodImagMul ; Load, Imag, Multiply CAE 4DEC93
FIXUP LodImagMul, fld, Y ; y.y x.x x.y
fmul st(2),st ; y.y x.x z.y
fmul ; z.x z.y
END_OPER LodImagMul
; --------------------------------------------------------------------------
BEGN_INCL Neg ; Negative
fxch
fchs ; Arg1->d.y = -Arg1->d.y;
fxch
fchs
END_INCL Neg
; --------------------------------------------------------------------------
BEGN_OPER EndInit ; End of initialization expr.
ifndef COMPILER ; this instr not needed CAE 30DEC93
mov _LastInitOp,bx ; LastInitOp=OpPtr
endif
finit ; changed from fninit CAE 09OCT93
END_OPER EndInit
; --------------------------------------------------------------------------
BEGN_OPER StoClr1 ; Store, clear FPU
FIXUP StoClr1, fstp, X ; y ...
FIXUP StoClr1, fst, Y ; y ...
finit ; use finit, not fninit
END_OPER StoClr1
; --------------------------------------------------------------------------
BEGN_OPER StoClr2 ; Store, clear FPU CAE 09OCT93
FIXUP StoClr2, fstp, X ; y
FIXUP StoClr2, fstp, Y ; <empty> (store pending)
END_OPER StoClr2
; --------------------------------------------------------------------------
BEGN_OPER Sto ; Store, leave on ST
; Revised to do store first, then exchange. CAE 10NOV93
FIXUP Sto, fst, X
fxch ; y x ...
FIXUP Sto, fst, Y
fxch ; x y ...
END_OPER Sto
; --------------------------------------------------------------------------
BEGN_OPER Sto2 ; Store, leave on ST (uses a reg)
fld st(1) ; y x y
FIXUP Sto2, fstp, Y ; x y
FIXUP Sto2, fst, X
fwait ; CAE added fwait for safety 15Feb95
END_OPER Sto2
; --------------------------------------------------------------------------
BEGN_OPER LodReal ; Load a real
fldz ; 0 ...
FIXUP LodReal, fld, X ; x 0 ...
END_OPER LodReal
; --------------------------------------------------------------------------
BEGN_OPER LodRealC ; Load real const
fldz ; y=0 ...
FIXUP LodRealC, fld, X ; x 0 ...
END_OPER LodRealC
; --------------------------------------------------------------------------
BEGN_OPER LodRealFlip ; Load real, flip
FIXUP LodRealFlip, fld, X ; y=x ...
fldz ; x=0 y ...
END_OPER LodRealFlip
; --------------------------------------------------------------------------
BEGN_OPER LodRealAbs ; Load real, abs
fldz ; 0 ...
FIXUP LodRealAbs, fld, X ; x 0 ...
fabs ; x=abs(x) 0 ...
END_OPER LodRealAbs
; --------------------------------------------------------------------------
BEGN_INCL Flip ; Exchange real, imag
fxch ; x=y y=x ...
END_INCL Flip
; --------------------------------------------------------------------------
BEGN_OPER LodImag ; Load, imaginary
fldz ; 0 ...
FIXUP LodImag, fld, Y ; x=y 0
END_OPER LodImag
; --------------------------------------------------------------------------
BEGN_OPER LodImagFlip ; Load, imaginary, flip
FIXUP LodImagFlip, fld, Y ; y ...
fldz ; 0 y ...
END_OPER LodImagFlip
; --------------------------------------------------------------------------
BEGN_OPER LodImagAbs ; Load, imaginary, absolute value
fldz ; 0 ...
FIXUP LodImagAbs, fld, Y ; x=y 0 ...
fabs ; x=abs(y) 0 ...
END_OPER LodImagAbs
; --------------------------------------------------------------------------
BEGN_OPER LodConj ; Load, conjugate
FIXUP LodConj, fld, Y ; y ...
fchs ; y=-y ...
FIXUP LodConj, fld, X ; x y ...
END_OPER LodConj
; --------------------------------------------------------------------------
BEGN_OPER LodAdd ; Load, Add (uses a reg)
FIXUP LodAdd, fadd, X
FIXUP LodAdd, fld, Y
faddp st(2),st
END_OPER LodAdd
; --------------------------------------------------------------------------
BEGN_OPER LodSub ; Load, Subtract (uses a reg)
FIXUP LodSub, fsub, X
FIXUP LodSub, fld, Y
fsubp st(2),st
END_OPER LodSub
; --------------------------------------------------------------------------
BEGN_OPER StoDup ; Store, duplicate top operand
FIXUP StoDup, fst, X ; x y
fld st(1) ; y x y
FIXUP StoDup, fst, Y ; y x y
fld st(1) ; x y x y
END_OPER StoDup
; --------------------------------------------------------------------------
BEGN_OPER StoDbl ; Store, double (uses a reg)
FIXUP StoDbl, fst, X ; x y (store x)
fadd st,st ; 2x y
fld st(1) ; y 2x y
FIXUP StoDbl, fst, Y ; y 2x y (store y)
faddp st(2),st ; 2x 2y
END_OPER StoDbl
; --------------------------------------------------------------------------
BEGN_INCL Zero ; Zero CAE 09OCT93
POP_STK 2 ; ...
fldz ; 0 ...
fldz ; 0 0 ...
END_INCL Zero
; --------------------------------------------------------------------------
BEGN_INCL One ; One CAE 06NOV93
POP_STK 2 ; ...
fldz ; 0 ...
fld1 ; 1 0 ...
END_INCL One
; --------------------------------------------------------------------------
BEGN_OPER LodSubMod ; Load, Subtract, Mod
FIXUP LodSubMod, fsub, X ; x.x-y.x x.y ...
fmul st,st ; sqr(x.x-y.x) x.y ...
fldz ; 0 sqrx x.y ...
fxch st(2) ; x.y sqrx 0 ...
FIXUP LodSubMod, fsub, Y ; x.y-y.y sqrx 0 ...
fmul st,st ; sqry sqrx 0 ...
fadd ; mod 0
END_OPER LodSubMod
; --------------------------------------------------------------------------
BEGN_INCL Sqr ; Square, save magnitude in LastSqr
fld st(0) ; x x y
fmul st(1),st ; x x*x y
fmul st,st(2) ; xy xx y
mov si, WORD PTR _v ; si -> variables
fadd st,st(0) ; 2xy xx y
fxch st(2) ; y xx 2xy
fmul st,st(0) ; yy xx 2xy
fld st(1) ; xx yy xx 2xy
fadd st,st(1) ; xx+yy yy xx 2xy
fstp QWORD PTR [si+LASTSQR] ; yy xx 2xy
fsubp st(1),st ; xx-yy 2xy
END_INCL Sqr
; --------------------------------------------------------------------------
BEGN_INCL Sqr0 ; Square, don't save magnitude
GEN_SQR0
END_INCL Sqr0
; --------------------------------------------------------------------------
BEGN_INCL Mul ; Multiply
; From FPU087.ASM
fld st(1) ; y.y, y.x, y.y, x.x, x.y
fmul st,st(4) ; y.y*x.y, y.x. y.y, x.x, x.y
fld st(1) ; y.x, y.y*x.y, y.x, y.y, x.x, x.y
fmul st,st(4) ; y.x*x.x,y.y*x.y,y.x y.y,x.x,x.y
fsubr ; newx=y.x*x.x-y.y*x.y,y.x,y.y,x.x,x.y
fxch st(3) ; x.x, y.x, y.y, newx, x.y
fmulp st(2),st ; y.x, y.y*x.x, newx, x.y
fmulp st(3),st ; y.y*x.x, newx, y.x*x.y
faddp st(2),st ; newx newy = y.x*x.y + x.x*y.y
END_INCL Mul
; --------------------------------------------------------------------------
BEGN_OPER LodMul ; Load, Multiply
; This is just load followed by multiply but it saves a fn. call
; and also allows optimizer enhancements.
FIXUP LodMul, fld, Y ; y.y x.x x.y
FIXUP LodMul, fld, X ; y.x y.y x.x x.y
fld st(1) ; y.y, y.x, y.y, x.x, x.y
fmul st,st(4) ; y.y*x.y, y.x. y.y, x.x, x.y
fld st(1) ; y.x, y.y*x.y, y.x, y.y, x.x, x.y
fmul st, st(4) ; y.x*x.x, y.y*x.y, y.x, y.y, x.x, x.y
fsubr ; newx=y.x*x.x-y.y*x.y,y.x,y.y,x.x,x.y
fxch st(3) ; x.x, y.x, y.y, newx, x.y
fmulp st(2), st ; y.x, y.y*x.x, newx, x.y
fmulp st(3), st ; y.y*x.x, newx, y.x*x.y
faddp st(2), st ; newx newy = y.x*x.y + x.x*y.y
END_OPER LodMul
; --------------------------------------------------------------------------
BEGN_INCL Div ; Divide
; From FPU087.ASM with speedups
fld st(1) ; y.y,y.x,y.y,x.x,x.y
fmul st,st ; y.y*y.y,y.x,y.y,x.x,x.y
fld st(1) ; y.x,y.y*y.y,y.x,y.y,x.x,x.y
fmul st,st ; y.x*y.x,y.y*y.y,y.x,y.y,x.x,x.y
fadd ; mod,y.x,y.y,x.x,x.y
ftst
fstsw ax
sahf
jz short DivNotOk
; can't do this divide until now
fdiv st(1),st ; mod,y.x=y.x/mod,y.y,x.x,x.y
fdivp st(2),st ; y.x,y.y=y.y/mod,x.x,x.y
fld st(1) ; y.y,y.x,y.y,x.x,x.y
fmul st,st(4) ; y.y*x.y,y.x,y.y,x.x,x.y
fld st(1) ; y.x,y.y*x.y,y.x,y.y,x.x,x.y
fmul st,st(4) ; y.x*x.x,y.y*x.y,y.x,y.y,x.x,x.y
fadd ; y.x*x.x+y.y*x.y,y.x,y.y,x.x,x.y
fxch st(3) ; x.x,y.x,y.y,newx,x.y
fmulp st(2),st ; y.x,y.y*x.x,newx,x.y
fmulp st(3),st ; x.x*y.y,newx,y.x*x.y
fsubp st(2),st ; newx,newy
EXIT_OPER Div
DivNotOk:
POP_STK 5 ; clear 5 from stack (!)
fld _infinity ; return a very large number
fld st(0)
END_INCL Div
; --------------------------------------------------------------------------
BEGN_INCL Recip ; Reciprocal
; From FPU087.ASM
fld st(1) ; y, x, y
fmul st,st ; y*y, x, y
fld st(1) ; x, y*y, x, y
fmul st,st ; x*x, y*y, x, y
fadd ; mod, x, y
ftst
fstsw ax
sahf
jz short RecipNotOk
fdiv st(1),st ; mod, newx=x/mod, y
fchs ; -mod newx y
fdivp st(2),st ; newx, newy=y/-mod
EXIT_OPER Recip
RecipNotOk:
POP_STK 3 ; clear three from stack
fld _infinity ; return a very large number
fld st(0)
END_INCL Recip
; --------------------------------------------------------------------------
BEGN_OPER StoSqr ; Sto, Square, save magnitude
fld st(0) ; x x y
FIXUP StoSqr, fst, X ; " (store x)
fmul st(1),st ; x x*x y
fmul st,st(2) ; xy xx y
fadd st,st(0) ; 2xy xx y
fxch st(2) ; y xx 2xy
FIXUP StoSqr, fst, Y ; " (store y)
fmul st,st(0) ; yy xx 2xy
; It is now safe to overlay si here
mov si, WORD PTR _v ; si -> variables
fld st(1) ; xx yy xx 2xy
fadd st,st(1) ; xx+yy yy xx 2xy
fstp QWORD PTR [si+LASTSQR] ; yy xx 2xy
fsubp st(1),st ; xx-yy 2xy
END_OPER StoSqr
; --------------------------------------------------------------------------
BEGN_OPER StoSqr0 ; Sto, Square, don't save magnitude
fld st(0) ; x x y
FIXUP StoSqr0, fst, X ; store x
fld st(0) ; x x x y
fmul st,st(3) ; xy x x y
fadd st,st ; 2xy x x y
fxch st(3) ; y x x 2xy
FIXUP StoSqr0, fst, Y ; store y
fadd st(2),st ; y x x+y 2xy
fsubp st(1),st ; x-y x+y 2xy
fmulp st(1),st ; xx-yy 2xy
END_OPER StoSqr0
; --------------------------------------------------------------------------
BEGN_INCL Mod2 ; Modulus (uses a reg)
fmul st,st ; xx y
fldz ; 0 xx y
fxch st(2) ; y xx 0
fmul st,st ; yy xx 0
fadd ; mod 0
END_INCL Mod2
; --------------------------------------------------------------------------
BEGN_OPER LodMod2 ; Load, Modulus (uses a reg)
fldz ; 0 ...
FIXUP LodMod2, fld, X ; x 0 ...
fmul st,st ; xx 0
FIXUP LodMod2, fld, Y ; y xx 0
fmul st,st ; yy xx 0
fadd ; mod 0
END_OPER LodMod2
; --------------------------------------------------------------------------
BEGN_OPER StoMod2 ; Store, Modulus (uses a reg)
FIXUP StoMod2, fst, X ; x y
fmul st,st ; xx y
fldz ; 0 xx y
fxch st(2) ; y xx 0
FIXUP StoMod2, fst, Y ; y xx 0
fmul st,st ; yy xx 0
fadd ; mod 0
END_OPER StoMod2
; --------------------------------------------------------------------------
BEGN_OPER Clr2 ; Test ST, clear FPU
ftst
fstsw ax
fninit ; fstsw will complete first
and ah,01000000b ; return 1 if zf=1
shr ax,14 ; AX will be returned by fFormula()
END_OPER Clr2
; --------------------------------------------------------------------------
BEGN_OPER PLodAdd ; Load, Add (uses no regs)
fxch ; y x
FIXUP PLodAdd, fadd, Y ; add y from memory
fxch ; x y
FIXUP PLodAdd, fadd, X ; add x, overlap execution
END_OPER PLodAdd
; --------------------------------------------------------------------------
BEGN_OPER PLodSub ; Load, Subtract (uses no regs)
fxch
FIXUP PLodSub, fsub, Y ; sub y from memory
fxch ; x y
FIXUP PLodSub, fsub, X ; sub x, overlap execution
END_OPER PLodSub
; --------------------------------------------------------------------------
BEGN_OPER LodDup ; Load, duplicate
FIXUP LodDup, fld, Y ; y ...
FIXUP LodDup, fld, X ; x y ...
fld st(1) ; y x y ...
fld st(1) ; x y x y ...
END_OPER LodDup
; --------------------------------------------------------------------------
BEGN_OPER LodSqr ; Load, square (no save lastsqr)
FIXUP LodSqr, fld, Y ; y ...
fld st(0) ; y y ...
fadd st(1),st ; y 2y ...
fld st(0) ; y y 2y
FIXUP LodSqr, fld, X ; x y y 2y ...
fmul st(3),st ; x y y 2xy ...
fadd st(2),st ; x y X+y 2xy ...
fsubrp st(1),st ; x-y x+y 2xy ...
fmul ; xx-yy 2xy ...
END_OPER LodSqr
; --------------------------------------------------------------------------
BEGN_OPER LodSqr2 ; Load, square (save lastsqr)
FIXUP LodSqr2, fld, Y ; y ...
fld st(0) ; y y ...
fadd st(1),st ; y 2y ...
fmul st,st(0) ; yy 2y ...
FIXUP LodSqr2, fld, X ; x yy 2y ...
fmul st(2),st ; x yy 2xy ...
mov si,WORD PTR _v ; put address of v in si
fmul st,st(0) ; xx yy 2xy ...
fld st(0) ; xx xx yy 2xy
fadd st,st(2) ; mod xx yy 2xy
fstp QWORD PTR [si+LASTSQR] ; xx yy 2xy ... (save lastsqr)
fsubrp st(1),st ; xx-yy 2xy ...
END_OPER LodSqr2
; --------------------------------------------------------------------------
BEGN_OPER LodDbl ; Load, double
FIXUP LodDbl, fld, Y ; load y
fadd st,st(0) ; double it
FIXUP LodDbl, fld, X ; same for x
fadd st,st(0)
END_OPER LodDbl
; --------------------------------------------------------------------------
BEGN_INCL Dbl ; Double CAE 31OCT93
fxch ; y x ...
fadd st,st(0) ; 2y x ...
fxch ; x 2y ...
fadd st,st(0) ; 2x 2y ...
END_INCL Dbl
; --------------------------------------------------------------------------
BEGN_INCL Mod ; Modulus (uses no regs)
fmul st,st ; x*x y
fxch ; y x*x
fmul st,st ; y*y x*x
fadd ; mod
fldz ; 0 mod
fxch ; mod 0
END_INCL Mod
; --------------------------------------------------------------------------
; The following code was 'discovered' by experimentation. The Intel manuals
; really don't help much in writing this kind of code.
; --------------------------------------------------------------------------
BEGN_INCL Push2 ; Push stack down from 8 to 6
fdecstp ; roll the stack
fdecstp ; ...
fstp tbyte PTR es:[di] ; store x on overflow stack
fstp tbyte PTR es:[di+10] ; and y (ten bytes each)
add di,20 ; adjust di
END_INCL Push2
; --------------------------------------------------------------------------
BEGN_INCL Pull2 ; Pull stack up from 2 to 4
fld tbyte PTR es:[di-10] ; oldy x y
sub di,20 ; adjust di now
fxch st(2) ; y x oldy
fld tbyte PTR es:[di] ; oldx y x oldy
fxch st(2) ; x y oldx oldy
END_INCL Pull2
; --------------------------------------------------------------------------
BEGN_INCL Push4 ; Push stack down from 8 to 4
fdecstp ; roll the stack four times
fdecstp
fdecstp
fdecstp
fstp tbyte PTR es:[di+20] ; save the bottom four numbers
fstp tbyte PTR es:[di+30] ; save full precision on overflow
fstp tbyte PTR es:[di]
fstp tbyte PTR es:[di+10]
add di,40 ; adjust di
END_INCL Push4
; --------------------------------------------------------------------------
BEGN_INCL Push2a ; Push stack down from 6 to 4
fdecstp ; roll the stack 4 times
fdecstp
fdecstp
fdecstp
fstp tbyte PTR es:[di] ; save only two numbers
fstp tbyte PTR es:[di+10]
add di, 20
fincstp ; roll back 2 times
fincstp
END_INCL Push2a
; --------------------------------------------------------------------------
; End of stack overflow/underflow code.
; --------------------------------------------------------------------------
BEGN_INCL Exp ; Exponent
; From FPU387.ASM with mods to use less registers.
; Modified to preserve 80-bit accuracy. CAE 10NOV93
fldln2 ; ln2 x y
fdivp st(1),st ; x/ln2 y
fstp TBYTE PTR es:[di] ; y
fsincos ; cosy, siny
fld1 ; 1 cos sin
fld TBYTE PTR es:[di] ; x/ln2 1 cos sin
fprem ; prem, 1, cos, sin
f2xm1 ; e**prem-1, 1, cos, sin
fadd ; e**prem, cos, sin
fld TBYTE PTR es:[di] ; x.x/ln2, e**prem, cos, sin
fxch ; e**prem, x.x/ln2, cos, sin
fscale ; e**x.x, x.x/ln2, cos, sin
fstp st(1) ; e**x.x, cos, sin
fmul st(2),st ; e**x.x, cos, z.y
fmul ; z.x, z.y
END_INCL Exp
; --------------------------------------------------------------------------
BEGN_OPER Pwr ; Power
; First exchange the top two complex numbers.
fxch st(2) ; x.x y.y y.x x.y
fxch ; y.y x.x y.x x.y
fxch st(3) ; x.y x.x y.x y.y
fxch ; x.x x.y y.x y.y
; Now take the log of the # on st.
INCL_OPER Pwr, Log ; l.x l.y y.x y.y
cmp ax,1 ; log domain error?
jne domainok ; nope
cmp _debugflag, 94 ; user wants old pwr?
je domainok ; yup
POP_STK 4 ; clear stack completely
fldz ; 0
fldz ; 0 0
EXIT_OPER Pwr ; return (0,0)
PARSALIGN
domainok:
; Inline multiply function from FPU087.ASM instead of include.
fld st(1) ; y.y y.x y.y x.x x.y
fmul st,st(4) ; y.y*x.y y.x y.y x.x x.y
fld st(1) ; y.x y.y*x.y y.x y.y x.x x.y
fmul st,st(4) ; y.x*x.x y.y*x.y y.x y.y x.x x.y
fsubr ; newx=y.x*x.x-y.y*x.y y.x y.y x.x x.y
fxch st(3) ; x.x y.x y.y newx x.y
fmulp st(2),st ; y.x y.y*x.x newx x.y
fmulp st(3),st ; y.y*x.x newx y.x*x.y
faddp st(2),st ; newx newy=y.x*x.y+x.x*y.y
; Exp function from FPU387.ASM. 4 regs are free here.
; Modified to use the regs instead of memory. CAE 06NOV93
fldln2 ; ln2 x y
fdiv ; x/ln2 y
fxch ; y x/ln2
fsincos ; cosy, siny, x/ln2
fxch ; sin, cos, x/ln2
fxch st(2) ; x/ln2, cos, sin
fld1 ; 1, x/ln2, cos, sin
fld st(1) ; x/ln2, 1, x/ln2, cos, sin
fprem ; prem, 1, x/ln2, cos, sin
f2xm1 ; e**prem-1, 1, x/ln2, cos, sin
fadd ; e**prem, x/ln2, cos, sin
fscale ; e**x.x, x.x/ln2, cos, sin
fstp st(1) ; e**x.x, cos, sin
fmul st(2),st ; e**x.x, cos, z.y
fmul ; z.x, z.y
END_OPER Pwr
; --------------------------------------------------------------------------
BEGN_OPER LodRealPwr ; lod, real, power CAE 6NOV93
; First take the log of the # on st.
INCL_OPER LodRealPwr, Log ; l.x l.y
; Inline multiply by a real.
FIXUP LodRealPwr, fld, X ; y.x, x.x, x.y
fmul st(2),st ; y.x, x.x, z.y
fmulp st(1),st ; z.x z.y
; Exp function from FPU387.ASM. 4 regs are free here, so use them.
fldln2 ; ln2 x y
fdiv ; x/ln2 y
fxch ; y x/ln2
fsincos ; cosy, siny, x/ln2
fxch ; sin, cos, x/ln2
fxch st(2) ; x/ln2, cos, sin
fld1 ; 1, x/ln2, cos, sin
fld st(1) ; x/ln2, 1, x/ln2, cos, sin
fprem ; prem, 1, x/ln2, cos, sin
f2xm1 ; e**prem-1, 1, x/ln2, cos, sin
fadd ; e**prem, x/ln2, cos, sin
fscale ; e**x.x, x.x/ln2, cos, sin
fstp st(1) ; e**x.x, cos, sin
fmul st(2),st ; e**x.x, cos, z.y
fmul ; z.x, z.y
END_OPER LodRealPwr
; --------------------------------------------------------------------------
BEGN_OPER Cosh ; Cosh
INCL_OPER Cosh, SinhCosh ; sinhx coshx y
fxch st(2) ; y coshx sinhx
fsincos ; cosy siny coshx sinhx
fmulp st(2),st ; siny x=cosy*coshx sinhx
fmulp st(2),st ; x y=sinhx*siny
END_OPER Cosh
; --------------------------------------------------------------------------
BEGN_OPER Sinh ; Sinh
INCL_OPER Sinh, SinhCosh ; sinhx coshx y
fxch st(2) ; y coshx sinhx
fsincos ; cosy siny coshx sinhx
fmulp st(3),st ; siny coshx x=sinhx*cosy
fmulp st(1),st ; y=coshx*siny x
fxch ; x y
END_OPER Sinh
; --------------------------------------------------------------------------
BEGN_OPER Sin ; Sin
fsincos ; cosx sinx y
fxch st(2) ; y sinx cosx
INCL_OPER Sin, SinhCosh ; sinhy coshy sinx cosx
fmulp st(3),st ; coshy sinx y=cosx*sinhy
fmulp st(1),st ; x=sinx*coshy y
END_OPER Sin
; --------------------------------------------------------------------------
BEGN_OPER Cos ; Cos
fsincos ; cosx sinx y
fxch st(2) ; y sinx cosx
INCL_OPER Cos, SinhCosh ; sinhy coshy sinx cosx
fchs ; -sinhy coshy sinx cosx
fmulp st(2),st ; coshy y=-sinhy*sinx cosx
fmulp st(2),st ; y x=cosx*coshy
fxch ; x y
END_OPER Cos
; --------------------------------------------------------------------------
BEGN_OPER CosXX ; CosXX
fsincos ; cosx sinx y
fxch st(2) ; y sinx cosx
INCL_OPER CosXX, SinhCosh ; sinhy coshy sinx cosx
; note missing fchs here
fmulp st(2),st ; coshy y=sinhy*sinx cosx
fmulp st(2),st ; y x=cosx*coshy
fxch ; x y
END_OPER CosXX
; --------------------------------------------------------------------------
BEGN_OPER Tan ; Tan
fadd st,st ; 2x y
fsincos ; cos2x sin2x y
fxch st(2) ; y sin2x cos2x
fadd st,st ; 2y sin2x cos2x
INCL_OPER Tan, SinhCosh ; sinh2y cosh2y sin2x cos2x
fxch ; cosh2y sinh2y sin2x cos2x
faddp st(3),st ; sinhy sinx denom=cos2x+cosh2y
fld st(2) ; denom sinh2y sin2x denom
fdivp st(2),st ; sinh2y x=sin2x/denom denom
fdivrp st(2),st ; x y=sinh2y/denom
END_OPER Tan
; --------------------------------------------------------------------------
BEGN_OPER CoTan ; CoTan
fadd st,st ; 2x y
fsincos ; cos2x sin2x y
fxch st(2) ; y sin2x cos2x
fadd st,st ; 2y sin2x cos2x
INCL_OPER CoTan, SinhCosh ; sinh2y cosh2y sin2x cos2x
fxch ; cosh2y sinh2y sin2x cos2x
fsubrp st(3),st ; sinh2y sin2x denom=cosh2y-cos2x
fld st(2) ; denom sinh2y sin2x denom
fdivp st(2),st ; sinh2y x=sin2x/denom denom
fchs ; -sinh2y x denom
fdivrp st(2),st ; x y=-sinh2y/denom
END_OPER CoTan
; --------------------------------------------------------------------------
BEGN_OPER Tanh ; Tanh
fadd st,st ; 2x y
INCL_OPER Tanh, SinhCosh ; sinh2x cosh2x y
fxch st(2) ; y cosh2x sinh2x
fadd st,st ; 2y cosh2x sinh2x
fsincos ; cos2y sin2y cosh2x sinh2x
faddp st(2),st ; sin2y denom=cos2y+cosh2x sinh2x
fxch ; denom sin2y sinh2x
fdiv st(1),st ; denom y=sin2y/denom sinh2x
fdivp st(2),st ; y x=sinh2x/denom
fxch ; x y
END_OPER Tanh
; --------------------------------------------------------------------------
BEGN_OPER CoTanh ; CoTanh
fadd st,st ; 2x y
INCL_OPER CoTanh, SinhCosh ; sinh2x cosh2x y
fxch st(2) ; y cosh2x sinh2x
fadd st,st ; 2y cosh2x sinh2x
fsincos ; cos2y sin2y cosh2x sinh2x
fsubp st(2),st ; sin2y denom=cosh2x-cos2y sinh2x
fchs ; -sin2y denom sinh2x
fxch ; denom -sin2y sinh2x
fdiv st(1),st ; denom y=-sin2y/denom sinh2x
fdivp st(2),st ; y x=sinh2x/denom
fxch ; x y
END_OPER CoTanh
; --------------------------------------------------------------------------
; JCO added Sqrt .. CAbs for version 19.
; CAE updated them 15Feb94 to work with compiler mode.
; --------------------------------------------------------------------------
BEGN_OPER Sqrt ; Sqrt
GEN_SQRT
END_OPER Sqrt
; --------------------------------------------------------------------------
BEGN_OPER ASin ; ArcSin
fld st(1) ; y x y
fld st(1) ; x y x y
GEN_SQR0 ; tz1.x tz1.y x y
fxch st(1) ; tz1.y tz1.x x y
fchs ; -tz1.y tz1.x x y
fxch st(1) ; tz1.x -tz1.y x y
fsubr __1_ ; 1-tz1.x -tz1.y x y
GEN_SQRT ; tz1.x tz1.y x y
fsubrp st(3),st ; tz1.y x tz1.x-y
fadd ; tz1.y+x tz1.x-y
fxch st(1) ; tz1.x-y tz1.y+x
INCL_OPER ASin, Log ; l.x l.y
fchs ; -l.x l.y
fxch st(1) ; l.y -l.x ;; rz = (-i)*l
END_OPER ASin
; --------------------------------------------------------------------------
BEGN_OPER ACos ; ArcCos
fld st(1) ; y x y
fld st(1) ; x y x y
GEN_SQR0 ; tz1.x tz1.y x y
fsub __1_ ; tz1.x-1 tz1.y x y
GEN_SQRT ; tz.x tz.y x y
faddp st(2),st ; tz.y tz.x+x y
faddp st(2),st ; tz.x+x tz.y+y
INCL_OPER ACos, Log ; l.x l.y
fchs ; -l.x l.y
fxch st(1) ; l.y -l.x ;; rz = (-i)*l
END_OPER ACos
; --------------------------------------------------------------------------
BEGN_OPER ASinh ; ArcSinh
fld st(1) ; y x y
fld st(1) ; x y x y
GEN_SQR0 ; tz1.x tz1.y x y
fadd __1_ ; tz1.x+1 tz1.y x y
GEN_SQRT ; tz.x tz.y x y
faddp st(2),st ; tz.y tz.x+x y
faddp st(2),st ; tz.x+x tz.y+y
INCL_OPER ASinh, Log ; l.x l.y
END_OPER ASinh
; --------------------------------------------------------------------------
BEGN_OPER ACosh ; ArcCosh
fld st(1) ; y x y
fld st(1) ; x y x y
GEN_SQR0 ; tz1.x tz1.y x y
fsub __1_ ; tz1.x+1 tz1.y x y
GEN_SQRT ; tz.x tz.y x y
faddp st(2),st ; tz.y tz.x+x y
faddp st(2),st ; tz.x+x tz.y+y
INCL_OPER ACosh, Log ; l.x l.y
END_OPER ACosh
; --------------------------------------------------------------------------
BEGN_OPER ATanh ; ArcTanh
fld st(1) ; y x y
fchs ; -y x y
fld st(1) ; x -y x y
fld1 ; 1 x -y x y
fadd st(3),st ; 1 x -y 1+x y
fsubr ; 1-x -y 1+x y
INCL_OPER ATanh, Div ; d.x d.y
; From FPU387.ASM
; Log is called by Pwr and is also called directly.
ftst
fstsw ax
sahf
jnz short ATanh_NotBothZero
fxch ; y x
ftst
fstsw ax
sahf
fxch ; x y
jnz short ATanh_NotBothZero
POP_STK 2 ; clear two numbers
fldz
fldz
jmp SHORT End_Log_ATanh ; return (0,0)
PARSALIGN
ATanh_NotBothZero:
fld st(1) ; y x y
fld st(1) ; x y x y
fpatan ; z.y x y
fxch st(2) ; y x z.y
fmul st,st(0) ; yy x z.y
fxch ; x yy z.y
fmul st,st(0) ; xx yy z.y
fadd ; mod z.y
fldln2 ; ln2, mod, z.y
fmul _PointFive ; ln2/2, mod, z.y
fxch ; mod, ln2/2, z.y
fyl2x ; z.x, z.y
End_Log_ATanh:
fld _PointFive ; .5 l.x l.y
fmul st(1),st ; .5 l.x/2 l.y
fmulp st(2),st ; l.x/2 l.y/2
END_OPER ATanh
; --------------------------------------------------------------------------
BEGN_OPER ATan ; ArcTan
fxch ; y x
fld st(1) ; x y x
fchs ; -x y x
fxch st(2) ; x y -x
fld st(1) ; y x y -x
fld1 ; 1 y x y -x
fadd st(3),st ; 1 y x 1+y -x
fsubr ; 1-y x 1+y -x
INCL_OPER ATan, Div ; d.x d.y
; CAE put log fn inline 15Feb95
ftst
fstsw ax
sahf
jnz short ATan_NotBothZero
fxch ; y x
ftst
fstsw ax
sahf
fxch ; x y
jnz short ATan_NotBothZero
POP_STK 2 ; clear two numbers
fldz
fldz
jmp short End_Log_ATan ; return (0,0)
PARSALIGN
ATan_NotBothZero:
fld st(1) ; y x y
fld st(1) ; x y x y
fpatan ; z.y x y
fxch st(2) ; y x z.y
fmul st,st(0) ; yy x z.y
fxch ; x yy z.y
fmul st,st(0) ; xx yy z.y
fadd ; mod z.y
fldln2 ; ln2, mod, z.y
fmul _PointFive ; ln2/2, mod, z.y
fxch ; mod, ln2/2, z.y
fyl2x ; z.x, z.y
End_Log_ATan:
fld _PointFive ; .5 l.x l.y
fmul st(1),st ; .5 z.y=l.x/2 l.y
fmulp st(2),st ; z.y l.y/2
fxch ; l.y/2 z.y
fchs ; z.x=-l.y/2 z.y
END_OPER ATan
; --------------------------------------------------------------------------
BEGN_OPER CAbs ; Complex Absolute Value
fmul st,st ; x*x y
fxch ; y x*x
fmul st,st ; y*y x*x
fadd ; y*y+x*x
fsqrt ; mag=sqrt(yy+xx)
fldz ; 0 mag
fxch ; mag 0
END_OPER CAbs
; --------------------------------------------------------------------------
; End of new functions. CAE 15Feb95
; --------------------------------------------------------------------------
BEGN_OPER LT ; <
; Arg2->d.x = (double)(Arg2->d.x < Arg1->d.x);
fcomp st(2) ; y.y, x.x, x.y, comp arg1 to arg2
fstsw ax
POP_STK 3
sahf
fldz ; 0 (Arg2->d.y = 0.0;)
jbe short LTfalse ; jump if arg1 <= arg2
fld1 ; 1 0 (return arg2 < arg1)
EXIT_OPER LT
LTfalse:
fldz ; 0 0
END_OPER LT
; --------------------------------------------------------------------------
BEGN_INCL LT2 ; LT, set AX, clear FPU
; returns !(Arg2->d.x < Arg1->d.x) in ax
fcom st(2) ; compare arg1, arg2
fstsw ax
fninit
sahf
setbe al ; return (Arg1 <= Arg2) in AX
xor ah,ah
END_INCL LT2
; --------------------------------------------------------------------------
BEGN_OPER LodLT ; load, LT
; return (1,0) on stack if arg2 < arg1
FIXUP LodLT, fcomp, X ; compare arg2 to arg1, pop st
fstsw ax ; y ...
POP_STK 1 ; ...
sahf
fldz ; 0 ...
jae short LodLTfalse ; jump when arg2 >= arg1
fld1 ; 1 0 ...
EXIT_OPER LodLT
LodLTfalse:
fldz ; 0 0 ...
END_OPER LodLT
; --------------------------------------------------------------------------
BEGN_OPER LodLT2 ; Lod, LT, set AX, clear FPU
; returns !(Arg2->d.x < Arg1->d.x) in ax
FIXUP LodLT2, fcom, X ; compare arg2, arg1
fstsw ax
fninit ; clear fpu
sahf
setae al ; set al when arg2 >= arg1
xor ah,ah ; clear ah
END_OPER LodLT2 ; ret 0 in ax for true, 1 for false
; --------------------------------------------------------------------------
BEGN_OPER LodLTMul ; Lod, LT, Multiply (needs 4 on stack)
; for '<expr> * ( <expr> < <var> )'
; return number on stack if arg2 < arg1
FIXUP LodLTMul, fcomp, X ; comp Arg2 to Arg1, pop st
fstsw ax ; save status
POP_STK 1 ; clear 1 from stack
sahf
jae short LodLTMulfalse ; jump if arg2 >= arg1
EXIT_OPER LodLTMul ; return value on st
PARSALIGN
LodLTMulfalse:
POP_STK 2 ; return (0,0)
fldz
fldz
END_OPER LodLTMul
; --------------------------------------------------------------------------
BEGN_INCL GT ; >
; Arg2->d.x = (double)(Arg2->d.x > Arg1->d.x);
fcomp st(2) ; compare arg1, arg2
fstsw ax
POP_STK 3
sahf
fldz ; 0 (Arg2->d.y = 0.0;)
jae short GTfalse ; jump if Arg1 >= Arg2
fld1 ; 1 0, return arg2 > arg1
EXIT_OPER GT
GTfalse:
fldz ; 0 0
END_INCL GT
; --------------------------------------------------------------------------
BEGN_INCL GT2 ; GT, set AX, clear FPU
; returns !(Arg2->d.x > Arg1->d.x) in ax
fcom st(2) ; compare arg1, arg2
fstsw ax
fninit
sahf
setae al ; return (Arg1 >= Arg2) in AX
xor ah,ah
END_INCL GT2
; --------------------------------------------------------------------------
BEGN_OPER LodGT ; load, GT
; return (1,0) on stack if arg2 > arg1
FIXUP LodGT, fcomp, X ; compare arg2 to arg1, pop st
fstsw ax ; y ...
POP_STK 1 ; ...
sahf
fldz ; 0 ...
jbe short LodGTfalse ; jump when arg2 <= arg1
fld1 ; 1 0 ...
EXIT_OPER LodGT
LodGTfalse:
fldz ; 0 0 ...
END_OPER LodGT
; --------------------------------------------------------------------------
BEGN_OPER LodGT2 ; Lod, GT, set AX, clear FPU
; returns !(Arg2->d.x > Arg1->d.x) in AX
FIXUP LodGT2, fcom, X ; compare arg2, arg1
fstsw ax
fninit ; clear fpu
sahf
setbe al ; set al when arg2 <= arg1
xor ah,ah ; clear ah
END_OPER LodGT2 ; ret 0 in ax for true, 1 for false
; --------------------------------------------------------------------------
BEGN_INCL LTE ; <=
; Arg2->d.x = (double)(Arg2->d.x <= Arg1->d.x);
fcomp st(2) ; y x y, comp Arg1 to Arg2
fstsw ax ; save status now
POP_STK 3
fldz ; 0 (Arg2->d.y = 0.0;)
sahf
jb short LTEfalse ; jump if arg1 > arg2
fld1 ; 1 0, ret arg2 <= arg1
EXIT_OPER LTE
LTEfalse:
fldz ; 0 0
END_INCL LTE
; --------------------------------------------------------------------------
BEGN_INCL LTE2 ; LTE, test ST, clear
; return !(Arg2->d.x <= Arg1->d.x) in AX
fcom st(2) ; comp Arg1 to Arg2
fstsw ax
fninit ; clear stack
and ah,1 ; mask cf
shr ax,8 ; ax=1 when arg1 < arg1
END_INCL LTE2 ; return (Arg1 < Arg2),
; --------------------------------------------------------------------------
BEGN_OPER LodLTE ; load, LTE
; return (1,0) on stack if arg2 <= arg1
FIXUP LodLTE, fcomp, X ; compare arg2 to arg1, pop st
fstsw ax ; y ...
POP_STK 1 ; ...
sahf
fldz ; 0 ...
ja short LodLTEfalse ; jump when arg2 > arg1
fld1 ; 1 0 ...
EXIT_OPER LodLTE
LodLTEfalse:
fldz ; 0 0 ...
END_OPER LodLTE
; --------------------------------------------------------------------------
BEGN_OPER LodLTE2 ; Load, LTE, test ST, clear
; return !(Arg2->d.x <= Arg1->d.x) in AX
FIXUP LodLTE2, fcom, X ; comp Arg2 to Arg1
fstsw ax
fninit
sahf
seta al
xor ah,ah ; ax=1 for expr. false
END_OPER LodLTE2 ; return (Arg2 > Arg1)
; --------------------------------------------------------------------------
BEGN_OPER LodLTEMul ; Lod, LTE, Multiply (needs 4 on stk)
; for '<expr> * ( <expr> <= <var> )'
; return number on stack if arg2 <= arg1
FIXUP LodLTEMul, fcomp, X ; comp Arg2 to Arg1, pop st
fstsw ax ; save status
POP_STK 1 ; clear 1 from stack
sahf
ja short LodLTEMulfalse ; jump if arg2 > arg1
EXIT_OPER LodLTEMul ; return value on st
PARSALIGN
LodLTEMulfalse:
POP_STK 2 ; return (0,0)
fldz
fldz
END_OPER LodLTEMul
; --------------------------------------------------------------------------
BEGN_OPER LodLTEAnd2 ; Load, LTE, AND, test ST, clear
; this is for 'expression && (expression <= value)'
; stack has {arg2.x arg2.y logical.x junk} on entry (arg1 in memory)
; Arg2->d.x = (double)(Arg2->d.x <= Arg1->d.x);
FIXUP LodLTEAnd2, fcom, X ; comp Arg2 to Arg1
fstsw ax
sahf
fxch st(2) ; logical.x arg2.y arg2.x junk ...
ja LTEA2RFalse ; right side is false, Arg2 > Arg1
ftst ; now see if left side of expr is true
fstsw ax
sahf
fninit ; clear fpu
jz LTEA2LFalse ; jump if left side of && is false
xor ax,ax ; return zero in ax for expr true
ret ; changed EXIT_OPER->ret CAE 30DEC93
LTEA2RFalse:
fninit
LTEA2LFalse:
mov ax,1 ; return ax=1 for condition false
END_OPER LodLTEAnd2
; --------------------------------------------------------------------------
BEGN_INCL GTE ; >=
; Arg2->d.x = (double)(Arg2->d.x >= Arg1->d.x);
fcomp st(2) ; y x y (compare arg1,arg2)
fstsw ax
POP_STK 3 ; clear 3 from stk
sahf
fldz ; 0 (Arg2->d.y = 0.0;)
ja short GTEfalse ; jmp if arg1 > arg2
fld1 ; 1 0 (return arg2 >= arg1 on stack)
EXIT_OPER GTE
GTEfalse:
fldz ; 0 0
END_INCL GTE
; --------------------------------------------------------------------------
BEGN_OPER LodGTE ; load, GTE
; return (1,0) on stack if arg2 >= arg1
FIXUP LodGTE, fcomp, X ; compare arg2 to arg1, pop st
fstsw ax ; y ...
POP_STK 1 ; ...
fldz ; 0 ...
sahf
jb short LodGTEfalse ; jump when arg2 < arg1
fld1 ; 1 0 ...
EXIT_OPER LodGTE
LodGTEfalse:
fldz ; 0 0 ...
END_OPER LodGTE
; --------------------------------------------------------------------------
BEGN_OPER LodGTE2 ; Lod, GTE, set AX, clear FPU
; return !(Arg2->d.x >= Arg1->d.x) in AX
FIXUP LodGTE2, fcom, X ; compare arg2, arg1
fstsw ax
fninit ; clear fpu
and ah,1 ; mask cf
shr ax,8 ; shift it (AX = 1 when arg2 < arg1)
END_OPER LodGTE2 ; ret 0 in ax for true, 1 for false
; --------------------------------------------------------------------------
BEGN_INCL EQ ; ==
; Arg2->d.x = (double)(Arg2->d.x == Arg1->d.x);
fcomp st(2) ; compare arg1, arg2
fstsw ax
POP_STK 3
sahf
fldz ; 0 (Arg2->d.y = 0.0;)
jne short EQfalse ; jmp if arg1 != arg2
fld1 ; 1 0 (ret arg2 == arg1)
EXIT_OPER EQ
EQfalse:
fldz
END_INCL EQ
; --------------------------------------------------------------------------
BEGN_OPER LodEQ ; load, EQ
; return (1,0) on stack if arg2 == arg1
FIXUP LodEQ, fcomp, X ; compare arg2 to arg1, pop st
fstsw ax ; y ...
POP_STK 1 ; ...
fldz ; 0 ...
sahf
jne short LodEQfalse ; jump when arg2 != arg1
fld1 ; 1 0 ... (return arg2 == arg1)
EXIT_OPER LodEQ
LodEQfalse:
fldz ; 0 0 ...
END_OPER LodEQ
; --------------------------------------------------------------------------
BEGN_INCL NE ; !=
; Arg2->d.x = (double)(Arg2->d.x != Arg1->d.x);
fcomp st(2) ; compare arg1,arg2
fstsw ax
POP_STK 3
sahf
fldz
je short NEfalse ; jmp if arg1 == arg2
fld1 ; ret arg2 != arg1
EXIT_OPER NE
NEfalse:
fldz
END_INCL NE
; --------------------------------------------------------------------------
BEGN_OPER LodNE ; load, NE
; return (1,0) on stack if arg2 != arg1
FIXUP LodNE, fcomp, X ; compare arg2 to arg1, pop st
fstsw ax ; y ...
POP_STK 1 ; ...
fldz ; 0 ...
sahf
je short LodNEfalse ; jump when arg2 == arg1
; CAE changed above 'jne' to 'je' 9 MAR 1993
fld1 ; 1 0 ...
EXIT_OPER LodNE
LodNEfalse:
fldz ; 0 0 ...
END_OPER LodNE
; --------------------------------------------------------------------------
BEGN_INCL OR ; Or
; Arg2->d.x = (double)(Arg2->d.x || Arg1->d.x);
ftst ; a1.x a1.y a2.x a2.y ...
fstsw ax
sahf
POP_STK 2 ; a2.x a2.y ...
jnz short Arg1True
ftst
fstsw ax
sahf
POP_STK 2 ; ...
fldz ; 0 ...
jz short NoneTrue
fld1 ; 1 0 ...
EXIT_OPER OR
PARSALIGN
Arg1True:
POP_STK 2 ; ...
fldz ; 0 ...
fld1 ; 1 0 ...
EXIT_OPER OR
NoneTrue: ; 0 ...
fldz ; 0 0 ...
END_INCL OR
; --------------------------------------------------------------------------
BEGN_INCL AND ; And
; Arg2->d.x = (double)(Arg2->d.x && Arg1->d.x);
ftst ; a1.x a1.y a2.x a2.y ...
fstsw ax
sahf
POP_STK 2 ; a2.x a2.y ...
jz short Arg1False
ftst
fstsw ax
sahf
POP_STK 2 ; ...
fldz ; 0 ...
jz short Arg2False
fld1 ; 1 0 ...
EXIT_OPER AND
PARSALIGN
Arg1False:
POP_STK 2 ; ...
fldz ; 0 ...
Arg2False:
fldz ; 0 0 ...
END_INCL AND
; --------------------------------------------------------------------------
BEGN_INCL ANDClr2 ; And, test ST, clear FPU
; for bailouts using <condition> && <condition>
; Arg2->d.x = (double)(Arg2->d.x && Arg1->d.x);
; Returns !(Arg1 && Arg2) in ax
ftst ; y.x y.y x.x x.y
fstsw ax
sahf
jz short Arg1False2
fxch st(2) ; x.x y.y y.x x.y
ftst
fstsw ax
sahf
fninit
jz short Arg2False2
BothTrue2:
xor ax,ax
ret ; changed EXIT_OPER->ret CAE 30DEC93
Arg1False2:
fninit
Arg2False2:
mov ax,1
END_INCL ANDClr2
; --------------------------------------------------------------------------
BEGN_INCL ORClr2 ; Or, test ST, clear FPU CAE 6NOV93
; for bailouts using <condition> || <condition>
; Arg2->d.x = (double)(Arg2->d.x || Arg1->d.x);
; Returns !(Arg1 || Arg2) in ax
ftst ; y.x y.y x.x x.y
fstsw ax
sahf
jnz short ORArg1True
fxch st(2) ; x.x y.y y.x x.y
ftst
fstsw ax
sahf
fninit
jnz short ORArg2True
ORNeitherTrue:
mov ax,1
ret ; changed EXIT_OPER->ret CAE 30DEC93
ORArg1True:
fninit
ORArg2True:
xor ax,ax
END_INCL ORClr2
; --------------------------------------------------------------------------
assume ds:DGROUP, es:nothing
; --------------------------------------------------------------------------
ifndef COMPILER
; --------------------------------------------------------------------------
; called once per image
; --------------------------------------------------------------------------
public _Img_Setup
align 2
; Changed to FAR, FRAME/UNFRAME added by CAE 09OCT93
_Img_Setup proc far
FRAME <si,di>
les si,_pfls ; es:si = &pfls[0]
mov di,_LastOp ; load index of lastop
dec di ; flastop now points at last operator
; above added by CAE 09OCT93 because of loop logic changes
shl di,2 ; convert to offset
mov bx,offset DGROUP:_fLastOp ; set bx for store
add di,si ; di = offset lastop
mov WORD PTR [bx],di ; save value of flastop
mov ax,es ; es has segment value
mov WORD PTR [bx+2],ax ; save seg for easy reload
mov ax,word ptr _v ; build a ptr to Z
add ax,3*CARG+CPFX
mov _PtrToZ,ax ; and save it
UNFRAME <di,si>
ret
_Img_Setup endp
; --------------------------------------------------------------------------
; Hybrid orbitcalc/per-pixel routine (tested, but not implemented.)
;
; To implement, stick the following code in calcfrac.c around line 788,
; just before the line that says "while (++coloriter < maxit)".
; --------------------------------------------------------------------------
; if (curfractalspecific->orbitcalc == fFormula /* 387 parser */
; && periodicitycheck == 0
; && !show_orbit
; && inside >= -5
; && attractors == 0
; && !distest ){
; fFormulaX(); /* orbit till done */
; } else
; --------------------------------------------------------------------------
public _fFormulaX ; CAE 09OCT93
align 16
_fFormulaX proc far
push si
push di
mov edx,_maxit ; edx holds coloriter during loop
mov _coloriter,edx ; set coloriter to maxit
mov ax,ds ; save ds in ax
lds cx,_fLastOp ; ds:cx -> one past last token
mov es,ax ; es -> DGROUP
assume es:DGROUP, ds:nothing ; swap es, ds before any fn. calls
jmp short skipfirst ; skip bailout test first time
align 16
outer_loop:
or ax,ax ; did bailout occur?
jnz short doneloop ; yes, exit
skipfirst:
dec edx ; ++coloriter
jle short doneloop ; yes, exit because of maxiter
mov bx,_InitOpPtr ; bx -> one before first token
mov di,offset DGROUP:_s ; reset stk overflow ptr
align 16
inner_loop2:
cmp bx,cx ; time to quit yet?
jae short outer_loop ; yes, bx points to last function
add bx,4 ; point to next pointer pair
push offset PARSERA_TEXT:inner_loop2 ; do this first
mov si,WORD PTR [bx+2] ; set si to operand pointer
jmp WORD PTR [bx] ; jmp to operator fn
align 16
doneloop:
; NOTE: edx must be preserved here.
mov si,_PtrToZ ; ds:si -> z
mov di,offset DGROUP:_new ; es:di -> new
mov cx,4
rep movsd ; new = z
mov ax,es
pop di
pop si
mov ds,ax ; restore ds before return
assume ds:DGROUP, es:nothing
sub _coloriter,edx ; now put new coloriter back from edx
ret
_fFormulaX endp
; --------------------------------------------------------------------------
; orbitcalc function follows
; --------------------------------------------------------------------------
public _fFormula
align 16
_fFormula proc far
push di ; don't build a frame here
mov di,offset DGROUP:_s ; reset this for stk overflow area
mov bx,_InitOpPtr ; bx -> one before first token
mov ax,ds ; save ds in ax
lds cx,_fLastOp ; ds:cx -> last token
mov es,ax ; es -> DGROUP
assume es:DGROUP, ds:nothing
align 16 ; already aligned 16
push si ; 1-byte instruction
inner_loop: ; loop revised CAE 09OCT93
cmp bx,cx ; time to quit yet?
jae short past_loop ; yes, bx points to last token
add bx,4 ; point to next token
push offset PARSERA_TEXT:inner_loop ; push return addr first
mov si,WORD PTR [bx+2] ; now set si to operand pointer
jmp WORD PTR [bx] ; ...and jump to operator fn
past_loop: ; 15-byte loop
; NOTE: AX was set by the last operator fn called.
mov si,_PtrToZ ; ds:si -> z
mov di,offset DGROUP:_new ; es:di -> new
mov cx,4 ; get ready to move 4 dwords
rep movsd ; new = z
mov bx,es ; put seg dgroup in bx
pop si
pop di ; restore si, di
mov ds,bx ; restore ds from bx before return
assume ds:DGROUP, es:nothing
ret ; return AX unmodified
_fFormula endp
; --------------------------------------------------------------------------
public _fform_per_pixel ; called once per pixel
align 4
_fform_per_pixel proc far
FRAME <si, di>
cmp _invert,0 ; inversion support added
je skip_invert ; CAE 08FEB95
mov si,offset DGROUP:_old
push si
call far ptr _invertz2
add sp,2
; now copy old to v[0].a.d
les di,_v ; ds:si already points to old
add di,CPFX ; make es:di point to v[0].a.d
mov cx,4
rep movsd
jmp after_load
skip_invert:
; /* v[5].a.d.x = */ (v[0].a.d.x = dx0[col]+dShiftx);
mov ax,_col
shl ax,3
les bx,_dx0
add bx,ax
fld QWORD PTR es:[bx]
mov ax,_row
shl ax,3
les bx,_dx1
add bx,ax
fadd QWORD PTR es:[bx]
les bx,_v
fstp QWORD PTR es:[bx+CPFX]
; /* v[5].a.d.x = */ (v[0].a.d.y = dy0[row]+dShifty);
mov ax,_row
shl ax,3
les bx,_dy0
add bx,ax
fld QWORD PTR es:[bx]
mov ax,_col
shl ax,3
les bx,_dy1
add bx,ax
fadd QWORD PTR es:[bx]
les bx,_v
fstp QWORD PTR es:[bx+CPFX+8] ; make this an fstp
after_load:
mov di,offset DGROUP:_s ; di points to stack overflow area
mov ax,ds
mov bx,WORD PTR _pfls ; bx -> pfls
lds cx,_fLastOp ; cx = offset &f[LastOp],load ds
mov es,ax
assume es:DGROUP, ds:nothing
cmp _LastInitOp,0
je short skip_initloop ; no operators to do here
mov _LastInitOp,cx ; lastinitop=lastop
jmp short pixel_loop
align 16
pixel_loop:
mov si,WORD PTR [bx+2] ; get address of load or store
call WORD PTR [bx] ; (*opptr)()
add bx,4 ; ++opptr
cmp bx,_LastInitOp
jb short pixel_loop
skip_initloop:
mov si,_PtrToZ ; ds:si -> z
mov di,offset DGROUP:_old ; es:di -> old
mov cx,4 ; get ready to move 4 dwords
rep movsd ; old = z
mov ax,es
mov ds,ax
assume ds:DGROUP, es:nothing ; for the rest of the program
sub bx,4 ; make initopptr point 1 token b4 1st
mov _InitOpPtr, bx ; InitOptPtr = OpPtr;
UNFRAME <di, si>
xor ax,ax
ret
_fform_per_pixel endp
; --------------------------------------------------------------------------
else ; Compiler
; --------------------------------------------------------------------------
; . . . and now for the real fun!
; --------------------------------------------------------------------------
public _Img_Setup
align 2
_Img_Setup proc far
mov ax,word ptr _v ; build a ptr to Z
add ax,3*CARG+CPFX
mov _PtrToZ,ax ; and save it
ret
_Img_Setup endp
; --------------------------------------------------------------------------
; Hybrid orbitcalc/per-pixel routine.
; --------------------------------------------------------------------------
public _fFormulaX
align 16
_fFormulaX proc far
push si
push di
mov edx,_maxit ; edx holds coloriter during loop
mov _coloriter,edx ; set coloriter to maxit
mov ax,ds ; save ds in ax
mov cx,word ptr _pfls+2 ; just get the seg part
mov es,ax ; es -> DGROUP
mov ds,cx ; ds -> parser data
assume es:DGROUP, ds:nothing
jmp short skipfirst ; skip bailout test first time
align 16
outer_loop:
or ax,ax ; did bailout occur?
jnz short doneloop ; yes, exit
skipfirst:
dec edx ; ++coloriter, was maxiter reached?
jle short doneloop ; yes, exit because of maxiter
push offset PARSERA_TEXT:outer_loop
mov di,offset DGROUP:_s ; reset this for stk overflow area
jmp _compiled_fn_2 ; call the compiled code
doneloop:
; NOTE: edx must be preserved here.
mov si,_PtrToZ ; ds:si -> z
mov di,offset DGROUP:_new ; es:di -> new
mov cx,4
rep movsd ; new = z
mov ax,es
pop di
pop si
mov ds,ax ; restore ds before return
assume ds:DGROUP, es:nothing
sub _coloriter,edx ; now put new coloriter back from edx
ret
_fFormulaX endp
; --------------------------------------------------------------------------
; orbitcalc function follows
; --------------------------------------------------------------------------
public _fFormula
align 16
_fFormula proc far
push di ; don't build a frame here
mov di,offset DGROUP:_s ; reset this for stk overflow area
mov ax,ds ; save ds in ax
mov cx,WORD PTR _pfls+2 ; just load seg value
mov es,ax ; es -> DGROUP
mov ds,cx ; ds -> parser data
assume es:DGROUP, ds:nothing
push si ; compiled_fn modifies si
call _compiled_fn_2 ; call the compiled code
; NOTE: AX was set by the compiled code and must be preserved here.
mov si,_PtrToZ ; ds:si -> z
mov di,offset DGROUP:_new ; es:di -> new
mov cx,4 ; get ready to move 4 dwords
rep movsd ; new = z
mov bx,es ; put seg dgroup in bx
pop si
pop di ; restore si, di
mov ds,bx ; restore ds from bx before return
assume ds:DGROUP, es:nothing
ret ; return AX unmodified
_fFormula endp
; --------------------------------------------------------------------------
public _fform_per_pixel ; called once per pixel
align 4
_fform_per_pixel proc far
FRAME <si, di>
cmp _invert,0 ; inversion support added
je skip_invert ; CAE 08FEB95
mov si,offset DGROUP:_old
push si
call far ptr _invertz2
add sp,2
; now copy old to v[0].a.d
les di,_v ; ds:si already points to old
add di,CPFX ; make es:di point to v[0].a.d
mov cx,4
rep movsd
jmp after_load
skip_invert:
; /* v[5].a.d.x = */ (v[0].a.d.x = dx0[col]+dShiftx);
mov ax,_col
shl ax,3
les bx,_dx0
add bx,ax
fld QWORD PTR es:[bx]
mov ax,_row
shl ax,3
les bx,_dx1
add bx,ax
fadd QWORD PTR es:[bx]
les bx,_v
fstp QWORD PTR es:[bx+CPFX]
; /* v[5].a.d.x = */ (v[0].a.d.y = dy0[row]+dShifty);
mov ax,_row
shl ax,3
les bx,_dy0
add bx,ax
fld QWORD PTR es:[bx]
mov ax,_col
shl ax,3
les bx,_dy1
add bx,ax
fadd QWORD PTR es:[bx]
les bx,_v
fstp QWORD PTR es:[bx+CPFX+8] ; make this an fstp
after_load:
mov di,offset DGROUP:_s ; di points to stack overflow area
mov ax,ds
mov cx,word ptr _pfls+2 ; just to load ds
mov es,ax ; es -> DGROUP
mov ds,cx ; ds -> parser data
assume es:DGROUP, ds:nothing
call _compiled_fn_1 ; call compiled code
mov ax,es
mov ds,ax
assume ds:DGROUP, es:nothing ; for the rest of the program
UNFRAME <di, si>
xor ax,ax
ret
_fform_per_pixel endp
align 16
public _compiled_fn_1
_compiled_fn_1 proc near
retn ; compiled code will be put here
db 1023 DUP (?)
_compiled_fn_1 endp
align 16
public _compiled_fn_2
_compiled_fn_2 proc near
retn ; ...and here
db 1023 DUP (?)
_compiled_fn_2 endp
; --------------------------------------------------------------------------
endif ; COMPILER
; --------------------------------------------------------------------------
PARSERA_TEXT ends
end