1 | #include "fpsp-namespace.h" |
---|
2 | // |
---|
3 | // |
---|
4 | // x_unfl.sa 3.4 7/1/91 |
---|
5 | // |
---|
6 | // fpsp_unfl --- FPSP handler for underflow exception |
---|
7 | // |
---|
8 | // Trap disabled results |
---|
9 | // For 881/2 compatibility, sw must denormalize the intermediate |
---|
10 | // result, then store the result. Denormalization is accomplished |
---|
11 | // by taking the intermediate result (which is always normalized) and |
---|
12 | // shifting the mantissa right while incrementing the exponent until |
---|
13 | // it is equal to the denormalized exponent for the destination |
---|
14 | // format. After denormalization, the result is rounded to the |
---|
15 | // destination format. |
---|
16 | // |
---|
17 | // Trap enabled results |
---|
18 | // All trap disabled code applies. In addition the exceptional |
---|
19 | // operand needs to made available to the user with a bias of $6000 |
---|
20 | // added to the exponent. |
---|
21 | // |
---|
22 | |
---|
23 | // Copyright (C) Motorola, Inc. 1990 |
---|
24 | // All Rights Reserved |
---|
25 | // |
---|
26 | // THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA |
---|
27 | // The copyright notice above does not evidence any |
---|
28 | // actual or intended publication of such source code. |
---|
29 | |
---|
30 | X_UNFL: //idnt 2,1 | Motorola 040 Floating Point Software Package |
---|
31 | |
---|
32 | |section 8 |
---|
33 | |
---|
34 | #include "fpsp.defs" |
---|
35 | |
---|
36 | |xref denorm |
---|
37 | |xref round |
---|
38 | |xref store |
---|
39 | |xref g_rndpr |
---|
40 | |xref g_opcls |
---|
41 | |xref g_dfmtou |
---|
42 | |xref real_unfl |
---|
43 | |xref real_inex |
---|
44 | |xref fpsp_done |
---|
45 | |xref b1238_fix |
---|
46 | |
---|
47 | .global fpsp_unfl |
---|
48 | fpsp_unfl: |
---|
49 | link %a6,#-LOCAL_SIZE |
---|
50 | fsave -(%a7) |
---|
51 | moveml %d0-%d1/%a0-%a1,USER_DA(%a6) |
---|
52 | fmovemx %fp0-%fp3,USER_FP0(%a6) |
---|
53 | fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) |
---|
54 | |
---|
55 | // |
---|
56 | bsrl unf_res //denormalize, round & store interm op |
---|
57 | // |
---|
58 | // If underflow exceptions are not enabled, check for inexact |
---|
59 | // exception |
---|
60 | // |
---|
61 | btstb #unfl_bit,FPCR_ENABLE(%a6) |
---|
62 | beqs ck_inex |
---|
63 | |
---|
64 | btstb #E3,E_BYTE(%a6) |
---|
65 | beqs no_e3_1 |
---|
66 | // |
---|
67 | // Clear dirty bit on dest resister in the frame before branching |
---|
68 | // to b1238_fix. |
---|
69 | // |
---|
70 | bfextu CMDREG3B(%a6){#6:#3},%d0 //get dest reg no |
---|
71 | bclrb %d0,FPR_DIRTY_BITS(%a6) //clr dest dirty bit |
---|
72 | bsrl b1238_fix //test for bug1238 case |
---|
73 | movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |
---|
74 | orl #sx_mask,E_BYTE(%a6) |
---|
75 | no_e3_1: |
---|
76 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
---|
77 | fmovemx USER_FP0(%a6),%fp0-%fp3 |
---|
78 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
---|
79 | frestore (%a7)+ |
---|
80 | unlk %a6 |
---|
81 | bral real_unfl |
---|
82 | // |
---|
83 | // It is possible to have either inex2 or inex1 exceptions with the |
---|
84 | // unfl. If the inex enable bit is set in the FPCR, and either |
---|
85 | // inex2 or inex1 occurred, we must clean up and branch to the |
---|
86 | // real inex handler. |
---|
87 | // |
---|
88 | ck_inex: |
---|
89 | moveb FPCR_ENABLE(%a6),%d0 |
---|
90 | andb FPSR_EXCEPT(%a6),%d0 |
---|
91 | andib #0x3,%d0 |
---|
92 | beqs unfl_done |
---|
93 | |
---|
94 | // |
---|
95 | // Inexact enabled and reported, and we must take an inexact exception |
---|
96 | // |
---|
97 | take_inex: |
---|
98 | btstb #E3,E_BYTE(%a6) |
---|
99 | beqs no_e3_2 |
---|
100 | // |
---|
101 | // Clear dirty bit on dest resister in the frame before branching |
---|
102 | // to b1238_fix. |
---|
103 | // |
---|
104 | bfextu CMDREG3B(%a6){#6:#3},%d0 //get dest reg no |
---|
105 | bclrb %d0,FPR_DIRTY_BITS(%a6) //clr dest dirty bit |
---|
106 | bsrl b1238_fix //test for bug1238 case |
---|
107 | movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |
---|
108 | orl #sx_mask,E_BYTE(%a6) |
---|
109 | no_e3_2: |
---|
110 | moveb #INEX_VEC,EXC_VEC+1(%a6) |
---|
111 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
---|
112 | fmovemx USER_FP0(%a6),%fp0-%fp3 |
---|
113 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
---|
114 | frestore (%a7)+ |
---|
115 | unlk %a6 |
---|
116 | bral real_inex |
---|
117 | |
---|
118 | unfl_done: |
---|
119 | bclrb #E3,E_BYTE(%a6) |
---|
120 | beqs e1_set //if set then branch |
---|
121 | // |
---|
122 | // Clear dirty bit on dest resister in the frame before branching |
---|
123 | // to b1238_fix. |
---|
124 | // |
---|
125 | bfextu CMDREG3B(%a6){#6:#3},%d0 //get dest reg no |
---|
126 | bclrb %d0,FPR_DIRTY_BITS(%a6) //clr dest dirty bit |
---|
127 | bsrl b1238_fix //test for bug1238 case |
---|
128 | movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |
---|
129 | orl #sx_mask,E_BYTE(%a6) |
---|
130 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
---|
131 | fmovemx USER_FP0(%a6),%fp0-%fp3 |
---|
132 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
---|
133 | frestore (%a7)+ |
---|
134 | unlk %a6 |
---|
135 | bral fpsp_done |
---|
136 | e1_set: |
---|
137 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
---|
138 | fmovemx USER_FP0(%a6),%fp0-%fp3 |
---|
139 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
---|
140 | unlk %a6 |
---|
141 | bral fpsp_done |
---|
142 | // |
---|
143 | // unf_res --- underflow result calculation |
---|
144 | // |
---|
145 | unf_res: |
---|
146 | bsrl g_rndpr //returns RND_PREC in d0 0=ext, |
---|
147 | // ;1=sgl, 2=dbl |
---|
148 | // ;we need the RND_PREC in the |
---|
149 | // ;upper word for round |
---|
150 | movew #0,-(%a7) |
---|
151 | movew %d0,-(%a7) //copy RND_PREC to stack |
---|
152 | // |
---|
153 | // |
---|
154 | // If the exception bit set is E3, the exceptional operand from the |
---|
155 | // fpu is in WBTEMP; else it is in FPTEMP. |
---|
156 | // |
---|
157 | btstb #E3,E_BYTE(%a6) |
---|
158 | beqs unf_E1 |
---|
159 | unf_E3: |
---|
160 | lea WBTEMP(%a6),%a0 //a0 now points to operand |
---|
161 | // |
---|
162 | // Test for fsgldiv and fsglmul. If the inst was one of these, then |
---|
163 | // force the precision to extended for the denorm routine. Use |
---|
164 | // the user's precision for the round routine. |
---|
165 | // |
---|
166 | movew CMDREG3B(%a6),%d1 //check for fsgldiv or fsglmul |
---|
167 | andiw #0x7f,%d1 |
---|
168 | cmpiw #0x30,%d1 //check for sgldiv |
---|
169 | beqs unf_sgl |
---|
170 | cmpiw #0x33,%d1 //check for sglmul |
---|
171 | bnes unf_cont //if not, use fpcr prec in round |
---|
172 | unf_sgl: |
---|
173 | clrl %d0 |
---|
174 | movew #0x1,(%a7) //override g_rndpr precision |
---|
175 | // ;force single |
---|
176 | bras unf_cont |
---|
177 | unf_E1: |
---|
178 | lea FPTEMP(%a6),%a0 //a0 now points to operand |
---|
179 | unf_cont: |
---|
180 | bclrb #sign_bit,LOCAL_EX(%a0) //clear sign bit |
---|
181 | sne LOCAL_SGN(%a0) //store sign |
---|
182 | |
---|
183 | bsrl denorm //returns denorm, a0 points to it |
---|
184 | // |
---|
185 | // WARNING: |
---|
186 | // ;d0 has guard,round sticky bit |
---|
187 | // ;make sure that it is not corrupted |
---|
188 | // ;before it reaches the round subroutine |
---|
189 | // ;also ensure that a0 isn't corrupted |
---|
190 | |
---|
191 | // |
---|
192 | // Set up d1 for round subroutine d1 contains the PREC/MODE |
---|
193 | // information respectively on upper/lower register halves. |
---|
194 | // |
---|
195 | bfextu FPCR_MODE(%a6){#2:#2},%d1 //get mode from FPCR |
---|
196 | // ;mode in lower d1 |
---|
197 | addl (%a7)+,%d1 //merge PREC/MODE |
---|
198 | // |
---|
199 | // WARNING: a0 and d0 are assumed to be intact between the denorm and |
---|
200 | // round subroutines. All code between these two subroutines |
---|
201 | // must not corrupt a0 and d0. |
---|
202 | // |
---|
203 | // |
---|
204 | // Perform Round |
---|
205 | // Input: a0 points to input operand |
---|
206 | // d0{31:29} has guard, round, sticky |
---|
207 | // d1{01:00} has rounding mode |
---|
208 | // d1{17:16} has rounding precision |
---|
209 | // Output: a0 points to rounded operand |
---|
210 | // |
---|
211 | |
---|
212 | bsrl round //returns rounded denorm at (a0) |
---|
213 | // |
---|
214 | // Differentiate between store to memory vs. store to register |
---|
215 | // |
---|
216 | unf_store: |
---|
217 | bsrl g_opcls //returns opclass in d0{2:0} |
---|
218 | cmpib #0x3,%d0 |
---|
219 | bnes not_opc011 |
---|
220 | // |
---|
221 | // At this point, a store to memory is pending |
---|
222 | // |
---|
223 | opc011: |
---|
224 | bsrl g_dfmtou |
---|
225 | tstb %d0 |
---|
226 | beqs ext_opc011 //If extended, do not subtract |
---|
227 | // ;If destination format is sgl/dbl, |
---|
228 | tstb LOCAL_HI(%a0) //If rounded result is normal,don't |
---|
229 | // ;subtract |
---|
230 | bmis ext_opc011 |
---|
231 | subqw #1,LOCAL_EX(%a0) //account for denorm bias vs. |
---|
232 | // ;normalized bias |
---|
233 | // ; normalized denormalized |
---|
234 | // ;single $7f $7e |
---|
235 | // ;double $3ff $3fe |
---|
236 | // |
---|
237 | ext_opc011: |
---|
238 | bsrl store //stores to memory |
---|
239 | bras unf_done //finish up |
---|
240 | |
---|
241 | // |
---|
242 | // At this point, a store to a float register is pending |
---|
243 | // |
---|
244 | not_opc011: |
---|
245 | bsrl store //stores to float register |
---|
246 | // ;a0 is not corrupted on a store to a |
---|
247 | // ;float register. |
---|
248 | // |
---|
249 | // Set the condition codes according to result |
---|
250 | // |
---|
251 | tstl LOCAL_HI(%a0) //check upper mantissa |
---|
252 | bnes ck_sgn |
---|
253 | tstl LOCAL_LO(%a0) //check lower mantissa |
---|
254 | bnes ck_sgn |
---|
255 | bsetb #z_bit,FPSR_CC(%a6) //set condition codes if zero |
---|
256 | ck_sgn: |
---|
257 | btstb #sign_bit,LOCAL_EX(%a0) //check the sign bit |
---|
258 | beqs unf_done |
---|
259 | bsetb #neg_bit,FPSR_CC(%a6) |
---|
260 | |
---|
261 | // |
---|
262 | // Finish. |
---|
263 | // |
---|
264 | unf_done: |
---|
265 | btstb #inex2_bit,FPSR_EXCEPT(%a6) |
---|
266 | beqs no_aunfl |
---|
267 | bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) |
---|
268 | no_aunfl: |
---|
269 | rts |
---|
270 | |
---|
271 | |end |
---|