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