|
|
1.1 root 1: /*---------------------------------------------------------------------------+
2: | reg_add_sub.c |
3: | |
4: | Functions to add or subtract two registers and put the result in a third. |
5: | |
6: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
7: | Australia. E-mail [email protected] |
8: | |
9: | |
10: +---------------------------------------------------------------------------*/
11:
12: /*---------------------------------------------------------------------------+
13: | For each function, the destination may be any FPU_REG, including one of |
14: | the source FPU_REGs. |
15: +---------------------------------------------------------------------------*/
16:
17: #include "fpu_system.h"
18: #include "exception.h"
19: #include "reg_constant.h"
20: #include "fpu_emu.h"
21:
22:
23:
24: void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
25: {
26: int diff;
27:
28: if ( !(a->tag | b->tag) )
29: {
30: /* Both registers are valid */
31: if (!(a->sign ^ b->sign))
32: {
33: /* signs are the same */
34: reg_u_add(a, b, dest);
35: dest->sign = a->sign;
36: return;
37: }
38:
39: /* The signs are different, so do a subtraction */
40: diff = a->exp - b->exp;
41: if (!diff)
42: {
43: diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
44: if (!diff)
45: diff = a->sigl > b->sigl;
46: }
47:
48: if (diff > 0)
49: {
50: reg_u_sub(a, b, dest);
51: dest->sign = a->sign;
52: return;
53: }
54: else
55: {
56: reg_u_sub(b, a, dest);
57: dest->sign = b->sign;
58: return;
59: }
60: }
61: else
62: {
63: if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
64: { real_2op_NaN(a, b, dest); return; }
65: else if (a->tag == TW_Zero)
66: { reg_move(b, dest); return; }
67: else if (b->tag == TW_Zero)
68: { reg_move(a, dest); return; }
69: else if (a->tag == TW_Infinity)
70: {
71: if (b->tag != TW_Infinity)
72: { reg_move(a, dest); return; }
73: /* They are both + or - infinity */
74: if (a->sign == b->sign)
75: { reg_move(a, dest); return; }
76: reg_move(&CONST_QNaN, dest); /* inf - inf is undefined. */
77: return;
78: }
79: else if (b->tag == TW_Infinity)
80: { reg_move(b, dest); return; }
81: }
82: #ifdef PARANOID
83: EXCEPTION(EX_INTERNAL|0x101);
84: #endif
85: }
86:
87:
88: /* Subtract b from a. (a-b) -> dest */
89: void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
90: {
91: int diff;
92:
93: if ( !(a->tag | b->tag) )
94: {
95: /* Both registers are valid */
96: diff = a->exp - b->exp;
97: if (!diff)
98: {
99: diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
100: if (!diff)
101: diff = a->sigl > b->sigl;
102: }
103:
104: switch (a->sign*2 + b->sign)
105: {
106: case 0: /* P - P */
107: case 3: /* N - N */
108: if (diff > 0)
109: {
110: reg_u_sub(a, b, dest);
111: dest->sign = a->sign;
112: }
113: else
114: {
115: reg_u_sub(b, a, dest);
116: dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
117: }
118: return;
119: case 1: /* P - N */
120: reg_u_add(a, b, dest);
121: dest->sign = SIGN_POS;
122: return;
123: case 2: /* N - P */
124: reg_u_add(a, b, dest);
125: dest->sign = SIGN_NEG;
126: return;
127: }
128: }
129: else
130: {
131: if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
132: { real_2op_NaN(a, b, dest); return; }
133: else if (b->tag == TW_Zero)
134: { reg_move(a, dest); return; }
135: else if (a->tag == TW_Zero)
136: {
137: reg_move(b, dest);
138: dest->sign ^= SIGN_POS^SIGN_NEG;
139: return;
140: }
141: else if (a->tag == TW_Infinity)
142: {
143: if (b->tag != TW_Infinity)
144: { reg_move(a, dest); return; }
145: if (a->sign == b->sign)
146: { reg_move(&CONST_QNaN, dest); return; }
147: reg_move(a, dest);
148: return;
149: }
150: else if (b->tag == TW_Infinity)
151: {
152: reg_move(b, dest);
153: dest->sign ^= SIGN_POS^SIGN_NEG;
154: return;
155: }
156: }
157: #ifdef PARANOID
158: EXCEPTION(EX_INTERNAL|0x110);
159: #endif
160: }
161:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.