162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* IEEE754 floating point arithmetic
362306a36Sopenharmony_ci * single precision
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * MIPS floating point support
762306a36Sopenharmony_ci * Copyright (C) 1994-2000 Algorithmics Ltd.
862306a36Sopenharmony_ci * Copyright (C) 2017 Imagination Technologies, Ltd.
962306a36Sopenharmony_ci * Author: Aleksandar Markovic <aleksandar.markovic@imgtec.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "ieee754sp.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciunion ieee754sp ieee754sp_rint(union ieee754sp x)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	union ieee754sp ret;
1762306a36Sopenharmony_ci	u32 residue;
1862306a36Sopenharmony_ci	int sticky;
1962306a36Sopenharmony_ci	int round;
2062306a36Sopenharmony_ci	int odd;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	COMPXDP;		/* <-- DP needed for 64-bit mantissa tmp */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	ieee754_clearcx();
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	EXPLODEXSP;
2762306a36Sopenharmony_ci	FLUSHXSP;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (xc == IEEE754_CLASS_SNAN)
3062306a36Sopenharmony_ci		return ieee754sp_nanxcpt(x);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	if ((xc == IEEE754_CLASS_QNAN) ||
3362306a36Sopenharmony_ci	    (xc == IEEE754_CLASS_INF) ||
3462306a36Sopenharmony_ci	    (xc == IEEE754_CLASS_ZERO))
3562306a36Sopenharmony_ci		return x;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (xe >= SP_FBITS)
3862306a36Sopenharmony_ci		return x;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (xe < -1) {
4162306a36Sopenharmony_ci		residue = xm;
4262306a36Sopenharmony_ci		round = 0;
4362306a36Sopenharmony_ci		sticky = residue != 0;
4462306a36Sopenharmony_ci		xm = 0;
4562306a36Sopenharmony_ci	} else {
4662306a36Sopenharmony_ci		residue = xm << (xe + 1);
4762306a36Sopenharmony_ci		residue <<= 31 - SP_FBITS;
4862306a36Sopenharmony_ci		round = (residue >> 31) != 0;
4962306a36Sopenharmony_ci		sticky = (residue << 1) != 0;
5062306a36Sopenharmony_ci		xm >>= SP_FBITS - xe;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	odd = (xm & 0x1) != 0x0;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	switch (ieee754_csr.rm) {
5662306a36Sopenharmony_ci	case FPU_CSR_RN:	/* toward nearest */
5762306a36Sopenharmony_ci		if (round && (sticky || odd))
5862306a36Sopenharmony_ci			xm++;
5962306a36Sopenharmony_ci		break;
6062306a36Sopenharmony_ci	case FPU_CSR_RZ:	/* toward zero */
6162306a36Sopenharmony_ci		break;
6262306a36Sopenharmony_ci	case FPU_CSR_RU:	/* toward +infinity */
6362306a36Sopenharmony_ci		if ((round || sticky) && !xs)
6462306a36Sopenharmony_ci			xm++;
6562306a36Sopenharmony_ci		break;
6662306a36Sopenharmony_ci	case FPU_CSR_RD:	/* toward -infinity */
6762306a36Sopenharmony_ci		if ((round || sticky) && xs)
6862306a36Sopenharmony_ci			xm++;
6962306a36Sopenharmony_ci		break;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (round || sticky)
7362306a36Sopenharmony_ci		ieee754_setcx(IEEE754_INEXACT);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	ret = ieee754sp_flong(xm);
7662306a36Sopenharmony_ci	SPSIGN(ret) = xs;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return ret;
7962306a36Sopenharmony_ci}
80