summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16/win87em/emftran.asm
blob: 6f21e53811546f24cc32de9668967687a01e95f1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
	page	,132
	subttl	emftran.asm - Transcendentals
;***
;emftran.asm - Transcendentals
;
;	Copyright (c) 1986-89, Microsoft Corporation
;
;Purpose:
;	Transcendentals
;
;	This Module contains Proprietary Information of Microsoft
;	Corporation and should be treated as Confidential.
;
;Revision History:
;	See emulator.hst
;
;*******************************************************************************


;-----------------------------------------;
;					  ;
;	     Transcendentals		  ;
;					  ;
;-----------------------------------------;

ProfBegin FTRAN


pub	MoveCodeSItoDataSI
	PUSH	edi
	MOV	edi,offset COEFFICIENT
ifdef	i386
    rept	Reg87Len/4
	MOVS	dword ptr es:[edi],dword ptr cs:[esi]
    endm
else
    rept	Reg87Len/2
	MOVS	word ptr es:[edi],word ptr cs:[esi]
    endm
endif
	MOV	esi,offset COEFFICIENT
	POP	edi
	RET

;---------------------------------------------------
;						   !
;	8087 emulator transcendental utilities	   !
;						   !
;---------------------------------------------------

;  COMPcsSIDI is  analogous  to the 8086 CMP instruction with operands
;  cs:[SI],[DI].  All registers except CX and DX are  left  unaltered.
;  Zero and  negative  zero  are  determined to be unequal.  NAN's and
;  infinities may not be compared with this routine.
;
;  FRAT2X performs   {TOS=[DI]}   <--	{TOS=[SI]}*PNUM({TOS=[SI]}^2),
;  and program created {temp=[SI]} <-- PDEN({TOS=[SI]}^2).  On	input,
;  [BX] must  contain  the  degree  of	PNUM, the coefficients of PNUM
;  in descending order, the degree-1  of  PDEN	and  the  coefficients
;  of PDEN in descending order.  PDEN is evaluated assuming an implied
;  highest coefficient of one.	[BX] is left unaltered, ARG2 is loaded
;  with   {TOS}^2,  DENORX is  used, all  registers are destroyed with
;  DI returning the value input in SI.

pub	BOTHZERO
	CMP	CH,CH			;set flags to equal
	JMP	short COMPDONE		;compare finished

pub	COMPcsSIDI
	MOV	CX,CS
	MOV	DS,CX
	MOV	CX,[esi+Flag]		;get sign byte of [SI]
	AND	CL,Sign 		;mask for sign
	MOV	DX,ES:[edi+Flag]	;get sign byte of [DI]
	AND	DL,Sign 		;mask for sign
	CMP	DL,CL			;compare signs
	JNE	short SIGNDIFF
	PUSH	ES
	PUSH	esi
	PUSH	edi			;save pointers
	OR	CL,CL			;if signs are +
	JNS	short BOTHPOS		;   don't exchange pointers
	PUSH	DS
	PUSH	ES
	POP	DS
	POP	ES
	XCHG	esi,edi 		;exchange pointers
	XCHG	CX,DX			;exchange flags

pub	BOTHPOS
	AND	CH,ZROorINF		;mask for zero
	AND	DH,ZROorINF		;mask for zero
	CMP	DH,CH			;if exactly one zero
	JNE	short COMPDONE		;   then finished
	OR	CH,CH			;if both zero
	JA	BOTHZERO		;   then done after flags set
	MOV	CX,[esi+Expon]		;get exponent of [SI]
	ADD	CX,IexpBias		;make it unbiased
	MOV	DX,ES:[edi+Expon]	;get exponent of [DI]
	ADD	DX,IexpBias		;make it unbiased
	CMP	CX,DX
	JNE	short COMPDONE		;compare exponents
	ADD	esi,MB6
	ADD	edi,MB6
	STD
	CMPS	word ptr [edi],word ptr [esi]
	JNE	short COMPDONE
	CMPS	word ptr [edi],word ptr [esi]
	JNE	short COMPDONE
	CMPS	word ptr [edi],word ptr [esi]
	JNE	short COMPDONE
	CMPS	word ptr [edi],word ptr [esi]	;compare mantissas

pub	COMPDONE
	CLD
	POP	edi
	POP	esi
	POP	ES

pub	SIGNDIFF
	MOV	CX,ES
	MOV	DS,CX
	RET

pub	FRAT2X
	MOV	edi,offset DENORX	;[DI]=temp
	CALL	MOVRQQ			;[DI]=x=temp
	PUSH	edi			;save ptr to x=temp
	PUSH	esi			;save ptr to TOS
	PUSH	ebx			;save ptr to polynomials
	MOV	edi,offset ARG2 	;get ptr to space for x^2
	CALL	MOVRQQ			;copy x to space for x^2
	MOV	[RESULT],edi		;result=[DI]
	CALL	MUDRQQ			;ARG2 gets x^2
	POP	esi			;get ptr to numerator poly
ifdef	i386
	xor	ecx,ecx
endif
	LODS	word ptr CS:[esi]
	XCHG	CX,AX			;CX=denominator degree-1
	POP	edi			;[DI]=TOS
	CALL	csMOVRQQ		;[DI]=first coeff=TOS
	MOV	[RESULT],edi		;result=[DI]

pub	POLYLOOPA
	PUSH	ecx			;save no. of terms left
	PUSH	esi			;save ptr to next coeff
	MOV	esi,offset ARG2 	;get ptr to x^2
	CALL	MUDRQQ			;multiply TOS by x^2
	POP	esi			;get pointer to coeff
	ADD	esi,Reg87Len		;point to next coeff
	PUSH	esi			;save pointer to coeff
	CALL	MoveCodeSItoDataSI
	CALL	ADDRQQ			;add coeff to TOS
	POP	esi			;get ptr to coeff
	POP	ecx			;get no. of terms remaining
	LOOP	POLYLOOPA		;loop until no terms left

	MOV	ebx,esi 		;move poly ptr
	POP	esi			;[SI]=x=temp
	PUSH	esi			;save ptr to x
	PUSH	ebx			;save poly ptr
	CALL	MUDRQQ			;multiply poly by x
	POP	esi			;get ptr to poly
	ADD	esi,12			;[SI]=denominator degree-1
ifdef	i386
	xor	ecx,ecx
endif
	LODS	word ptr CS:[esi]
	XCHG	CX,AX			;CX=denominator degree-1
	POP	ebx			;[BX]=temp
	PUSH	edi			;save denominator ptr
	MOV	edi,ebx 		;[DI]=temp
	CALL	csMOVRQQ		;move second coeff to temp
	PUSH	ecx			;save poly degree-1
	PUSH	esi			;save ptr to denominator poly
	MOV	esi,offset ARG2 	;get ptr to x^2
	MOV	[RESULT],edi		;result=[DI]
	CALL	ADDRQQ			;add x^2 to temp
	POP	esi			;get ptr to second coeff
	POP	ecx			;get poly degree-1

pub	POLYLOOPB
	PUSH	ecx			;save no. of terms left
	ADD	esi,Reg87Len		;point to next coeff
	PUSH	esi			;save ptr to next coeff
	MOV	esi,offset ARG2 	;get ptr to x^2
	CALL	MUDRQQ			;multiply temp by x^2
	POP	esi			;get pointer to coeff
	PUSH	esi			;save pointer to coeff
	CALL	MoveCodeSItoDataSI
	CALL	ADDRQQ			;add coeff to temp
	POP	esi			;get ptr to coeff
	POP	ecx			;get no. of terms remaining
	LOOP	POLYLOOPB		;loop until no terms left

	MOV	esi,edi 		;[SI]=denominator=temp
	POP	edi			;[DI]=numerator=TOS
	RET
;-------------------------------------------------------------------------------

pub	eFPTAN
	MOV	esi,[CURstk]
	CALL	$FPTAN
	PUSH	esi
	PUSHST
	MOV	edi,[CURstk]
	POP	esi
	CALL	MOVRQQ
	RET

;---------------------------------------------------
;						   !
;	8087 emulator partial tangent		   !
;						   !
;---------------------------------------------------

;  When 0<=x={TOS=[SI]}<=pi/4  then  $FPTAN  performs  {TOS=[DI]}  <--
;  numerator tangent  ({TOS=[SI]}),  system  created  {temp=[SI]}  <--
;  denominator tangent	({TOS=[SI]).   Every  register	except	DI  is
;  destroyed.

pub	$FPTAN
	MOV	ebx,offset TANRAT	;[BX]=rational function
	CALL	FRAT2X			;[DI]=numerator=TOS,
	RET				;   [SI]=denominator=temp
;-------------------------------------------------------------------------------

pub	eFPATAN
	MOV	edi,[CURstk]
	MOV	esi,edi
	MOV	AX,Flag[esi]
	SUB	edi,Reg87Len

pub	CALLFPATAN
	CALL	$FPATAN
	MOV	esi,[CURstk]
	POPST
	RET

;---------------------------------------------------
;						   !
;	8087 emulator arctangent		   !
;						   !
;---------------------------------------------------

;  When 0<y={[DI]=NOS}<=x={[SI]=TOS}<infinity  then  $FPATAN  performs
;  {NOS=[DI]} <--   arctangent({NOS=[DI]}/{TOS=[SI]}),	 TOS  is  left
;  unaltered.  All registers except DI are destroyed.

pub	$FPATAN
	MOV	[RESULT],edi		;result=[DI]
	CALL	DIDRQQ			;NOS=[DI] <-- [DI]/[SI]=x
	MOV	AL,0			;flag reset
	MOV	esi,offset TWOMRT3	;[SI]=2-3^.5
	CALL	COMPcsSIDI		;if 2-3^.5 >= x
	JNB	short ATNREDUCED	;   then bypass arg reduction
	MOV	esi,edi 		;[SI]=x=NOS
	MOV	edi,offset TEMP1	;[DI]=temp
	CALL	MOVRQQ			;[DI]=x=temp
	PUSH	esi			;save NOS
	MOV	esi,offset RT3		;[SI]=3^.5
	CALL	MoveCodeSItoDataSI
	MOV	[RESULT],edi		;result=[DI]
	CALL	MUDRQQ			;[DI]=3^.5*x=temp
	MOV	esi,offset cFLD1	;[SI]=1
	CALL	MoveCodeSItoDataSI
	CALL	SUDRQQ			;[DI]=3^.5*x-1
	POP	esi			;get NOS
	PUSH	edi			;save ptr to 3^.5*x-1
	MOV	edi,esi 		;DI gets NOS
	MOV	esi,offset RT3		;[SI]=3^.5
	CALL	MoveCodeSItoDataSI
	MOV	[RESULT],edi		;result=[DI]
	CALL	ADDRQQ			;[DI]=x+3^.5=NOS
	POP	esi			;[SI]=3^.5*x-1
	CALL	DRDRQQ			;[DI]=(3^.5*x-1)/(x+3^.5)=NOS
	MOV	AL,1			;flag set

pub	ATNREDUCED
	PUSH	eax			;save flag
	MOV	esi,edi 		;[SI]=reduced x=NOS
	MOV	ebx,offset ATNRAT	;[BX]=rational function
	CALL	FRAT2X			;[DI]=numerator=NOS,
					;   [SI]=denominator=temp
	MOV	[RESULT],edi		;result=[DI]
	CALL	DIDRQQ			;[DI]=arctan(reduced x)=NOS
	POP	eax			;get flag
	OR	AL,AL			;if flag=0
	JZ	short ATNCOMPLETE	;   bypass adjust
	MOV	esi,offset PIBY6	;[SI]=pi/6
	CALL	MoveCodeSItoDataSI
	CALL	ADDRQQ			;[DI]=arctan(x)=NOS

pub	ATNCOMPLETE
	RET
;-------------------------------------------------------------------------------

pub	eF2XM1
	MOV	esi,[CURstk]
	CALL	$F2XM1
	RET

;---------------------------------------------------
;						   !
;	8087 emulator exponential		   !
;						   !
;---------------------------------------------------

;  When  0<=x={TOS=[SI]}<=.5  then  $F2XM1  performs  {TOS=[SI]}   <--
;  2^{TOS=[SI]}-1.  All registers except SI are destroyed.

pub	$F2XM1
	MOV	ebx,offset EXPRAT	;[BX]=rational function
	CALL	FRAT2X			;[DI]=numerator=TOS
	PUSH	edi			;save numerator=TOS
	XCHG	esi,edi 		;[SI]=numerator, [DI]=denominator
	MOV	[RESULT],edi		;result=[DI]
	CALL	SUDRQQ			;[DI]=denominator-numerator
	MOV	esi,edi 		;[SI]=denominator-numerator
	POP	edi			;[DI]=numerator=TOS
	MOV	[RESULT],edi		;result=[DI]
	CALL	DIDRQQ			;[DI]=(2^x-1)/2
	INC	word ptr [edi+Expon]	;[DI]=2^x-1
	MOV	esi,edi 		;[SI]=2^x-1
	RET
;-------------------------------------------------------------------------------

pub	eFYL2X
	MOV	edi,[CURstk]
	MOV	esi,edi
	MOV	AX,Flag[esi]
	SUB	edi,Reg87Len

pub	CALLFYL2X
	CALL	$FYL2X
	MOV	esi,[CURstk]
	POPST
	RET


;---------------------------------------------------
;						   !
;	8087 emulator multiple of logarithm	   !
;						   !
;---------------------------------------------------

;  When -infinity<y={NOS=[DI]}<infinity   and  0<x={TOS=[SI]}<infinity
;  then $FYL2X performs  {NOS=[DI]}  <--  {NOS=[DI]}*log2({TOS=[SI]}).
;  TOS is  left  unaltered,  all  registers  except  DI are destroyed.

pub	$FYL2X
	PUSH	esi			;save ptr to x=TOS
	MOV	esi,edi 		;[SI]=y=NOS
	MOV	edi,offset TEMP2	;[DI]=temp2
	CALL	MOVRQQ			;[DI]=y=temp2
	MOV	edi,esi 		;[DI]=y=NOS
	POP	esi			;[SI]=x=TOS
	PUSH	edi			;save ptr to y=NOS
	MOV	edi,offset TEMP3	;[DI]=temp3
	CALL	MOVRQQ			;[DI]=x=temp3
	MOV	BX,[edi+Expon]		;BX=exponent of x
	MOV	word ptr [edi+Expon],0	;set exponent of x to 0
	MOV	esi,offset RT2		;[SI]=2^.5
	CALL	COMPcsSIDI		;if reduced x < 2^.5
	JA	short LOGREDUCED	;   then bypass normalization
	DEC	word ptr [edi+Expon]	;otherwise make x < 2^.5
	INC	BX			;adjust exponent

pub	LOGREDUCED
	PUSH	ebx			;save exponent of x
	MOV	esi,offset cFLD1	;[SI]=1
	CALL	MoveCodeSItoDataSI
	MOV	[RESULT],edi		;result=[DI]
	CALL	SUDRQQ			;[DI]=(reduced x)-1=temp3
	MOV	esi,edi 		;[SI]=(reduced x)-1=temp3
	POP	ebx			;get exponent of x
	POP	edi			;[DI]=y=NOS
	PUSH	ebx			;save exponent of x
	CALL	$FYL2XP1		;[DI]=y*log2(reduced x)=NOS
	POP	ebx			;get exponent of x
	XOR	AX,AX			;zero AX
	OR	BX,BX			;if exponent is zero
	JZ	short LOGRETURN 	;   then done
	MOV	DX,AX			;make sign +
	JNS	short EXPPOSITIVE	;if + then bypass adjust
	MOV	DL,Sign 		;make sign -
	NEG	BX			;negate exponent

pub	EXPPOSITIVE
	MOV	CX,16			;initialize bit count

pub	LOGLOOP
	DEC	CX			;decrement shift count
	SHL	BX,1			;and shift exponent of x left
	JNC	LOGLOOP 		;until carry detected
	PUSH	edi			;save ptr to y*log2(reduced x)=NOS
	RCR	BX,1			;normalize exponent of x
	MOV	edi,offset TEMP3	;[DI]=temp3
	STOS	word ptr es:[edi]
	STOS	word ptr es:[edi]
	STOS	word ptr es:[edi]
	MOV	AX,BX
	STOS	word ptr es:[edi]
	MOV	AX,CX
	STOS	word ptr es:[edi]
	MOV	AX,DX
	STOS	word ptr es:[edi]	;store exponent of x in temp3
	MOV	edi,offset TEMP2	;[DI]=y=temp2
	MOV	esi,offset TEMP3	;[SI]=exponent of x=temp3
	MOV	[RESULT],edi		;result=[DI]
	CALL	MUDRQQ			;[DI]=y*exponent of x=temp2
	MOV	esi,edi 		;[SI]=y*exponent of x=temp2
	POP	edi			;[DI]=y*log2(reduced x)=NOS
	MOV	[RESULT],edi		;result=[DI]
	CALL	ADDRQQ			;[DI]=y*log2(x)=NOS

pub	LOGRETURN
	RET
;-------------------------------------------------------------------------------

pub	eFYL2XP1
	MOV	edi,[CURstk]
	MOV	esi,edi
	MOV	AX,Flag[esi]
	SUB	edi,Reg87Len

pub	CALLFYL2XP1
	CALL	$FYL2XP1
	MOV	esi,[CURstk]
	POPST
	RET

;---------------------------------------------------
;						   !
;	8087 emulator add 1 multiple of logarithm  !
;						   !
;---------------------------------------------------

;  When 	      -infinity<y={[DI]=NOS}<infinity		   and
;  2^-.5-1<=x={[SI]=TOS}<2^.5-1 then  $FYL2XP1	 performs   {NOS=[DI]}
;  <-- {NOS=[DI]}*log2({TOS=[SI]}+1).	TOS  is  left  unaltered,  all
;  registers except DI are destroyed.

pub	$FYL2XP1
	PUSH	edi			;save ptr to y
	MOV	edi,offset TEMP1	;[DI]=temp
	CALL	MOVRQQ			;[DI]=x=temp
	PUSH	esi			;save ptr to x
	MOV	esi,offset TWO		;[SI]=2
	CALL	MoveCodeSItoDataSI
	MOV	[RESULT],edi		;result=[DI]
	CALL	ADDRQQ			;[DI]=x+2=temp
	POP	esi			;[SI]=x=TOS
	CALL	DRDRQQ			;[DI]=x/(x+2)=temp
	INC	word ptr [edi+Expon]	;[DI]=2x/(x+2)=temp
	MOV	esi,edi 		;[SI]=2x/(x+2)=temp
	MOV	ebx,offset LOGRAT	;[BX]=rational function
	CALL	FRAT2X			;[DI]=numerator=temp,
					;   [SI]=denominator=temp
	MOV	[RESULT],edi		;result=[DI]
	CALL	DIDRQQ			;[DI]=log2(x+1)=temp
	MOV	esi,edi 		;[SI]=log2(x+1)=temp
	POP	edi			;get ptr to y=NOS
	MOV	[RESULT],edi		;result=[DI]
	CALL	MUDRQQ			;[DI]=y*log2(x+1)=NOS
	RET

ProfEnd  FTRAN