18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci	.file	"reg_u_mul.S"
38c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------+
48c2ecf20Sopenharmony_ci |  reg_u_mul.S                                                              |
58c2ecf20Sopenharmony_ci |                                                                           |
68c2ecf20Sopenharmony_ci | Core multiplication routine                                               |
78c2ecf20Sopenharmony_ci |                                                                           |
88c2ecf20Sopenharmony_ci | Copyright (C) 1992,1993,1995,1997                                         |
98c2ecf20Sopenharmony_ci |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
108c2ecf20Sopenharmony_ci |                  E-mail   billm@suburbia.net                              |
118c2ecf20Sopenharmony_ci |                                                                           |
128c2ecf20Sopenharmony_ci |                                                                           |
138c2ecf20Sopenharmony_ci +---------------------------------------------------------------------------*/
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------+
168c2ecf20Sopenharmony_ci |   Basic multiplication routine.                                           |
178c2ecf20Sopenharmony_ci |   Does not check the resulting exponent for overflow/underflow            |
188c2ecf20Sopenharmony_ci |                                                                           |
198c2ecf20Sopenharmony_ci |   FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw);         |
208c2ecf20Sopenharmony_ci |                                                                           |
218c2ecf20Sopenharmony_ci |   Internal working is at approx 128 bits.                                 |
228c2ecf20Sopenharmony_ci |   Result is rounded to nearest 53 or 64 bits, using "nearest or even".    |
238c2ecf20Sopenharmony_ci +---------------------------------------------------------------------------*/
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "exception.h"
268c2ecf20Sopenharmony_ci#include "fpu_emu.h"
278c2ecf20Sopenharmony_ci#include "control_w.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#ifndef NON_REENTRANT_FPU
328c2ecf20Sopenharmony_ci/*  Local storage on the stack: */
338c2ecf20Sopenharmony_ci#define FPU_accum_0	-4(%ebp)	/* ms word */
348c2ecf20Sopenharmony_ci#define FPU_accum_1	-8(%ebp)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#else
378c2ecf20Sopenharmony_ci/*  Local storage in a static area: */
388c2ecf20Sopenharmony_ci.data
398c2ecf20Sopenharmony_ci	.align 4,0
408c2ecf20Sopenharmony_ciFPU_accum_0:
418c2ecf20Sopenharmony_ci	.long	0
428c2ecf20Sopenharmony_ciFPU_accum_1:
438c2ecf20Sopenharmony_ci	.long	0
448c2ecf20Sopenharmony_ci#endif /* NON_REENTRANT_FPU */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci.text
488c2ecf20Sopenharmony_ciSYM_FUNC_START(FPU_u_mul)
498c2ecf20Sopenharmony_ci	pushl	%ebp
508c2ecf20Sopenharmony_ci	movl	%esp,%ebp
518c2ecf20Sopenharmony_ci#ifndef NON_REENTRANT_FPU
528c2ecf20Sopenharmony_ci	subl	$8,%esp
538c2ecf20Sopenharmony_ci#endif /* NON_REENTRANT_FPU */
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	pushl	%esi
568c2ecf20Sopenharmony_ci	pushl	%edi
578c2ecf20Sopenharmony_ci	pushl	%ebx
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	movl	PARAM1,%esi
608c2ecf20Sopenharmony_ci	movl	PARAM2,%edi
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#ifdef PARANOID
638c2ecf20Sopenharmony_ci	testl	$0x80000000,SIGH(%esi)
648c2ecf20Sopenharmony_ci	jz	L_bugged
658c2ecf20Sopenharmony_ci	testl	$0x80000000,SIGH(%edi)
668c2ecf20Sopenharmony_ci	jz	L_bugged
678c2ecf20Sopenharmony_ci#endif /* PARANOID */
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	xorl	%ecx,%ecx
708c2ecf20Sopenharmony_ci	xorl	%ebx,%ebx
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	movl	SIGL(%esi),%eax
738c2ecf20Sopenharmony_ci	mull	SIGL(%edi)
748c2ecf20Sopenharmony_ci	movl	%eax,FPU_accum_0
758c2ecf20Sopenharmony_ci	movl	%edx,FPU_accum_1
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	movl	SIGL(%esi),%eax
788c2ecf20Sopenharmony_ci	mull	SIGH(%edi)
798c2ecf20Sopenharmony_ci	addl	%eax,FPU_accum_1
808c2ecf20Sopenharmony_ci	adcl	%edx,%ebx
818c2ecf20Sopenharmony_ci/*	adcl	$0,%ecx		// overflow here is not possible */
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	movl	SIGH(%esi),%eax
848c2ecf20Sopenharmony_ci	mull	SIGL(%edi)
858c2ecf20Sopenharmony_ci	addl	%eax,FPU_accum_1
868c2ecf20Sopenharmony_ci	adcl	%edx,%ebx
878c2ecf20Sopenharmony_ci	adcl	$0,%ecx
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	movl	SIGH(%esi),%eax
908c2ecf20Sopenharmony_ci	mull	SIGH(%edi)
918c2ecf20Sopenharmony_ci	addl	%eax,%ebx
928c2ecf20Sopenharmony_ci	adcl	%edx,%ecx
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* Get the sum of the exponents. */
958c2ecf20Sopenharmony_ci	movl	PARAM6,%eax
968c2ecf20Sopenharmony_ci	subl	EXP_BIAS-1,%eax
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/* Two denormals can cause an exponent underflow */
998c2ecf20Sopenharmony_ci	cmpl	EXP_WAY_UNDER,%eax
1008c2ecf20Sopenharmony_ci	jg	Exp_not_underflow
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/* Set to a really low value allow correct handling */
1038c2ecf20Sopenharmony_ci	movl	EXP_WAY_UNDER,%eax
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ciExp_not_underflow:
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/*  Have now finished with the sources */
1088c2ecf20Sopenharmony_ci	movl	PARAM3,%edi	/* Point to the destination */
1098c2ecf20Sopenharmony_ci	movw	%ax,EXP(%edi)
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/*  Now make sure that the result is normalized */
1128c2ecf20Sopenharmony_ci	testl	$0x80000000,%ecx
1138c2ecf20Sopenharmony_ci	jnz	LResult_Normalised
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* Normalize by shifting left one bit */
1168c2ecf20Sopenharmony_ci	shll	$1,FPU_accum_0
1178c2ecf20Sopenharmony_ci	rcll	$1,FPU_accum_1
1188c2ecf20Sopenharmony_ci	rcll	$1,%ebx
1198c2ecf20Sopenharmony_ci	rcll	$1,%ecx
1208c2ecf20Sopenharmony_ci	decw	EXP(%edi)
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciLResult_Normalised:
1238c2ecf20Sopenharmony_ci	movl	FPU_accum_0,%eax
1248c2ecf20Sopenharmony_ci	movl	FPU_accum_1,%edx
1258c2ecf20Sopenharmony_ci	orl	%eax,%eax
1268c2ecf20Sopenharmony_ci	jz	L_extent_zero
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	orl	$1,%edx
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciL_extent_zero:
1318c2ecf20Sopenharmony_ci	movl	%ecx,%eax
1328c2ecf20Sopenharmony_ci	jmp	fpu_reg_round
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci#ifdef PARANOID
1368c2ecf20Sopenharmony_ciL_bugged:
1378c2ecf20Sopenharmony_ci	pushl	EX_INTERNAL|0x205
1388c2ecf20Sopenharmony_ci	call	EXCEPTION
1398c2ecf20Sopenharmony_ci	pop	%ebx
1408c2ecf20Sopenharmony_ci	jmp	L_exit
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ciL_exit:
1438c2ecf20Sopenharmony_ci	popl	%ebx
1448c2ecf20Sopenharmony_ci	popl	%edi
1458c2ecf20Sopenharmony_ci	popl	%esi
1468c2ecf20Sopenharmony_ci	leave
1478c2ecf20Sopenharmony_ci	RET
1488c2ecf20Sopenharmony_ci#endif /* PARANOID */
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ciSYM_FUNC_END(FPU_u_mul)
151