1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
4 *
5 * Floating-point emulation code
6 *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
7 */
8/*
9 * BEGIN_DESC
10 *
11 *  File:
12 *	@(#)	pa/fp/denormal.c		$ Revision: $
13 *
14 *  Purpose:
15 *	<<please update with a synopsis of the functionality provided by this file>>
16 *
17 *  External Interfaces:
18 *	<<the following list was autogenerated, please review>>
19 *	dbl_denormalize(dbl_opndp1,dbl_opndp2,inexactflag,rmode)
20 *	sgl_denormalize(sgl_opnd,inexactflag,rmode)
21 *
22 *  Internal Interfaces:
23 *	<<please update>>
24 *
25 *  Theory:
26 *	<<please update with a overview of the operation of this file>>
27 *
28 * END_DESC
29*/
30
31
32
33#include "float.h"
34#include "sgl_float.h"
35#include "dbl_float.h"
36#include "hppa.h"
37#include <linux/kernel.h>
38/* #include <machine/sys/mdep_private.h> */
39
40#undef Fpustatus_register
41#define Fpustatus_register Fpu_register[0]
42
43void
44sgl_denormalize(unsigned int *sgl_opnd, boolean *inexactflag, int rmode)
45{
46	unsigned int opnd;
47	int sign, exponent;
48	boolean guardbit = FALSE, stickybit, inexact;
49
50	opnd = *sgl_opnd;
51	stickybit = *inexactflag;
52        exponent = Sgl_exponent(opnd) - SGL_WRAP;
53        sign = Sgl_sign(opnd);
54	Sgl_denormalize(opnd,exponent,guardbit,stickybit,inexact);
55	if (inexact) {
56	    switch (rmode) {
57	      case ROUNDPLUS:
58		if (sign == 0) {
59			Sgl_increment(opnd);
60		}
61		break;
62	      case ROUNDMINUS:
63		if (sign != 0) {
64			Sgl_increment(opnd);
65		}
66		break;
67	      case ROUNDNEAREST:
68		if (guardbit && (stickybit ||
69		       Sgl_isone_lowmantissa(opnd))) {
70			   Sgl_increment(opnd);
71		}
72		break;
73	    }
74	}
75	Sgl_set_sign(opnd,sign);
76	*sgl_opnd = opnd;
77	*inexactflag = inexact;
78	return;
79}
80
81void
82dbl_denormalize(unsigned int *dbl_opndp1,
83	unsigned int * dbl_opndp2,
84	boolean *inexactflag,
85	int rmode)
86{
87	unsigned int opndp1, opndp2;
88	int sign, exponent;
89	boolean guardbit = FALSE, stickybit, inexact;
90
91	opndp1 = *dbl_opndp1;
92	opndp2 = *dbl_opndp2;
93	stickybit = *inexactflag;
94	exponent = Dbl_exponent(opndp1) - DBL_WRAP;
95	sign = Dbl_sign(opndp1);
96	Dbl_denormalize(opndp1,opndp2,exponent,guardbit,stickybit,inexact);
97	if (inexact) {
98	    switch (rmode) {
99	      case ROUNDPLUS:
100		if (sign == 0) {
101			Dbl_increment(opndp1,opndp2);
102		}
103		break;
104	      case ROUNDMINUS:
105		if (sign != 0) {
106			Dbl_increment(opndp1,opndp2);
107		}
108		break;
109	      case ROUNDNEAREST:
110		if (guardbit && (stickybit ||
111		       Dbl_isone_lowmantissap2(opndp2))) {
112			   Dbl_increment(opndp1,opndp2);
113		}
114		break;
115	    }
116	}
117	Dbl_set_sign(opndp1,sign);
118	*dbl_opndp1 = opndp1;
119	*dbl_opndp2 = opndp2;
120	*inexactflag = inexact;
121	return;
122}
123