diff options
Diffstat (limited to 'arch/m68k/fpsp040/res_func.S')
-rw-r--r-- | arch/m68k/fpsp040/res_func.S | 2040 |
1 files changed, 2040 insertions, 0 deletions
diff --git a/arch/m68k/fpsp040/res_func.S b/arch/m68k/fpsp040/res_func.S new file mode 100644 index 000000000000..8f6b95217865 --- /dev/null +++ b/arch/m68k/fpsp040/res_func.S | |||
@@ -0,0 +1,2040 @@ | |||
1 | | | ||
2 | | res_func.sa 3.9 7/29/91 | ||
3 | | | ||
4 | | Normalizes denormalized numbers if necessary and updates the | ||
5 | | stack frame. The function is then restored back into the | ||
6 | | machine and the 040 completes the operation. This routine | ||
7 | | is only used by the unsupported data type/format handler. | ||
8 | | (Exception vector 55). | ||
9 | | | ||
10 | | For packed move out (fmove.p fpm,<ea>) the operation is | ||
11 | | completed here; data is packed and moved to user memory. | ||
12 | | The stack is restored to the 040 only in the case of a | ||
13 | | reportable exception in the conversion. | ||
14 | | | ||
15 | | | ||
16 | | Copyright (C) Motorola, Inc. 1990 | ||
17 | | All Rights Reserved | ||
18 | | | ||
19 | | THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA | ||
20 | | The copyright notice above does not evidence any | ||
21 | | actual or intended publication of such source code. | ||
22 | |||
23 | RES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package | ||
24 | |||
25 | |section 8 | ||
26 | |||
27 | #include "fpsp.h" | ||
28 | |||
29 | sp_bnds: .short 0x3f81,0x407e | ||
30 | .short 0x3f6a,0x0000 | ||
31 | dp_bnds: .short 0x3c01,0x43fe | ||
32 | .short 0x3bcd,0x0000 | ||
33 | |||
34 | |xref mem_write | ||
35 | |xref bindec | ||
36 | |xref get_fline | ||
37 | |xref round | ||
38 | |xref denorm | ||
39 | |xref dest_ext | ||
40 | |xref dest_dbl | ||
41 | |xref dest_sgl | ||
42 | |xref unf_sub | ||
43 | |xref nrm_set | ||
44 | |xref dnrm_lp | ||
45 | |xref ovf_res | ||
46 | |xref reg_dest | ||
47 | |xref t_ovfl | ||
48 | |xref t_unfl | ||
49 | |||
50 | .global res_func | ||
51 | .global p_move | ||
52 | |||
53 | res_func: | ||
54 | clrb DNRM_FLG(%a6) | ||
55 | clrb RES_FLG(%a6) | ||
56 | clrb CU_ONLY(%a6) | ||
57 | tstb DY_MO_FLG(%a6) | ||
58 | beqs monadic | ||
59 | dyadic: | ||
60 | btstb #7,DTAG(%a6) |if dop = norm=000, zero=001, | ||
61 | | ;inf=010 or nan=011 | ||
62 | beqs monadic |then branch | ||
63 | | ;else denorm | ||
64 | | HANDLE DESTINATION DENORM HERE | ||
65 | | ;set dtag to norm | ||
66 | | ;write the tag & fpte15 to the fstack | ||
67 | leal FPTEMP(%a6),%a0 | ||
68 | |||
69 | bclrb #sign_bit,LOCAL_EX(%a0) | ||
70 | sne LOCAL_SGN(%a0) | ||
71 | |||
72 | bsr nrm_set |normalize number (exp will go negative) | ||
73 | bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign | ||
74 | bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format | ||
75 | beqs dpos | ||
76 | bsetb #sign_bit,LOCAL_EX(%a0) | ||
77 | dpos: | ||
78 | bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0 | ||
79 | bsetb #4,DTAG(%a6) |set FPTE15 | ||
80 | orb #0x0f,DNRM_FLG(%a6) | ||
81 | monadic: | ||
82 | leal ETEMP(%a6),%a0 | ||
83 | btstb #direction_bit,CMDREG1B(%a6) |check direction | ||
84 | bne opclass3 |it is a mv out | ||
85 | | | ||
86 | | At this point, only opclass 0 and 2 possible | ||
87 | | | ||
88 | btstb #7,STAG(%a6) |if sop = norm=000, zero=001, | ||
89 | | ;inf=010 or nan=011 | ||
90 | bne mon_dnrm |else denorm | ||
91 | tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would | ||
92 | bne normal |require normalization of denorm | ||
93 | |||
94 | | At this point: | ||
95 | | monadic instructions: fabs = $18 fneg = $1a ftst = $3a | ||
96 | | fmove = $00 fsmove = $40 fdmove = $44 | ||
97 | | fsqrt = $05* fssqrt = $41 fdsqrt = $45 | ||
98 | | (*fsqrt reencoded to $05) | ||
99 | | | ||
100 | movew CMDREG1B(%a6),%d0 |get command register | ||
101 | andil #0x7f,%d0 |strip to only command word | ||
102 | | | ||
103 | | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and | ||
104 | | fdsqrt are possible. | ||
105 | | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) | ||
106 | | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) | ||
107 | | | ||
108 | btstl #0,%d0 | ||
109 | bne normal |weed out fsqrt instructions | ||
110 | | | ||
111 | | cu_norm handles fmove in instructions with normalized inputs. | ||
112 | | The routine round is used to correctly round the input for the | ||
113 | | destination precision and mode. | ||
114 | | | ||
115 | cu_norm: | ||
116 | st CU_ONLY(%a6) |set cu-only inst flag | ||
117 | movew CMDREG1B(%a6),%d0 | ||
118 | andib #0x3b,%d0 |isolate bits to select inst | ||
119 | tstb %d0 | ||
120 | beql cu_nmove |if zero, it is an fmove | ||
121 | cmpib #0x18,%d0 | ||
122 | beql cu_nabs |if $18, it is fabs | ||
123 | cmpib #0x1a,%d0 | ||
124 | beql cu_nneg |if $1a, it is fneg | ||
125 | | | ||
126 | | Inst is ftst. Check the source operand and set the cc's accordingly. | ||
127 | | No write is done, so simply rts. | ||
128 | | | ||
129 | cu_ntst: | ||
130 | movew LOCAL_EX(%a0),%d0 | ||
131 | bclrl #15,%d0 | ||
132 | sne LOCAL_SGN(%a0) | ||
133 | beqs cu_ntpo | ||
134 | orl #neg_mask,USER_FPSR(%a6) |set N | ||
135 | cu_ntpo: | ||
136 | cmpiw #0x7fff,%d0 |test for inf/nan | ||
137 | bnes cu_ntcz | ||
138 | tstl LOCAL_HI(%a0) | ||
139 | bnes cu_ntn | ||
140 | tstl LOCAL_LO(%a0) | ||
141 | bnes cu_ntn | ||
142 | orl #inf_mask,USER_FPSR(%a6) | ||
143 | rts | ||
144 | cu_ntn: | ||
145 | orl #nan_mask,USER_FPSR(%a6) | ||
146 | movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for | ||
147 | | ;snan handler | ||
148 | |||
149 | rts | ||
150 | cu_ntcz: | ||
151 | tstl LOCAL_HI(%a0) | ||
152 | bnel cu_ntsx | ||
153 | tstl LOCAL_LO(%a0) | ||
154 | bnel cu_ntsx | ||
155 | orl #z_mask,USER_FPSR(%a6) | ||
156 | cu_ntsx: | ||
157 | rts | ||
158 | | | ||
159 | | Inst is fabs. Execute the absolute value function on the input. | ||
160 | | Branch to the fmove code. If the operand is NaN, do nothing. | ||
161 | | | ||
162 | cu_nabs: | ||
163 | moveb STAG(%a6),%d0 | ||
164 | btstl #5,%d0 |test for NaN or zero | ||
165 | bne wr_etemp |if either, simply write it | ||
166 | bclrb #7,LOCAL_EX(%a0) |do abs | ||
167 | bras cu_nmove |fmove code will finish | ||
168 | | | ||
169 | | Inst is fneg. Execute the negate value function on the input. | ||
170 | | Fall though to the fmove code. If the operand is NaN, do nothing. | ||
171 | | | ||
172 | cu_nneg: | ||
173 | moveb STAG(%a6),%d0 | ||
174 | btstl #5,%d0 |test for NaN or zero | ||
175 | bne wr_etemp |if either, simply write it | ||
176 | bchgb #7,LOCAL_EX(%a0) |do neg | ||
177 | | | ||
178 | | Inst is fmove. This code also handles all result writes. | ||
179 | | If bit 2 is set, round is forced to double. If it is clear, | ||
180 | | and bit 6 is set, round is forced to single. If both are clear, | ||
181 | | the round precision is found in the fpcr. If the rounding precision | ||
182 | | is double or single, round the result before the write. | ||
183 | | | ||
184 | cu_nmove: | ||
185 | moveb STAG(%a6),%d0 | ||
186 | andib #0xe0,%d0 |isolate stag bits | ||
187 | bne wr_etemp |if not norm, simply write it | ||
188 | btstb #2,CMDREG1B+1(%a6) |check for rd | ||
189 | bne cu_nmrd | ||
190 | btstb #6,CMDREG1B+1(%a6) |check for rs | ||
191 | bne cu_nmrs | ||
192 | | | ||
193 | | The move or operation is not with forced precision. Test for | ||
194 | | nan or inf as the input; if so, simply write it to FPn. Use the | ||
195 | | FPCR_MODE byte to get rounding on norms and zeros. | ||
196 | | | ||
197 | cu_nmnr: | ||
198 | bfextu FPCR_MODE(%a6){#0:#2},%d0 | ||
199 | tstb %d0 |check for extended | ||
200 | beq cu_wrexn |if so, just write result | ||
201 | cmpib #1,%d0 |check for single | ||
202 | beq cu_nmrs |fall through to double | ||
203 | | | ||
204 | | The move is fdmove or round precision is double. | ||
205 | | | ||
206 | cu_nmrd: | ||
207 | movel #2,%d0 |set up the size for denorm | ||
208 | movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold | ||
209 | andw #0x7fff,%d1 | ||
210 | cmpw #0x3c01,%d1 | ||
211 | bls cu_nunfl | ||
212 | bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode | ||
213 | orl #0x00020000,%d1 |or in rprec (double) | ||
214 | clrl %d0 |clear g,r,s for round | ||
215 | bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format | ||
216 | sne LOCAL_SGN(%a0) | ||
217 | bsrl round | ||
218 | bfclr LOCAL_SGN(%a0){#0:#8} | ||
219 | beqs cu_nmrdc | ||
220 | bsetb #sign_bit,LOCAL_EX(%a0) | ||
221 | cu_nmrdc: | ||
222 | movew LOCAL_EX(%a0),%d1 |check for overflow | ||
223 | andw #0x7fff,%d1 | ||
224 | cmpw #0x43ff,%d1 | ||
225 | bge cu_novfl |take care of overflow case | ||
226 | bra cu_wrexn | ||
227 | | | ||
228 | | The move is fsmove or round precision is single. | ||
229 | | | ||
230 | cu_nmrs: | ||
231 | movel #1,%d0 | ||
232 | movew LOCAL_EX(%a0),%d1 | ||
233 | andw #0x7fff,%d1 | ||
234 | cmpw #0x3f81,%d1 | ||
235 | bls cu_nunfl | ||
236 | bfextu FPCR_MODE(%a6){#2:#2},%d1 | ||
237 | orl #0x00010000,%d1 | ||
238 | clrl %d0 | ||
239 | bclrb #sign_bit,LOCAL_EX(%a0) | ||
240 | sne LOCAL_SGN(%a0) | ||
241 | bsrl round | ||
242 | bfclr LOCAL_SGN(%a0){#0:#8} | ||
243 | beqs cu_nmrsc | ||
244 | bsetb #sign_bit,LOCAL_EX(%a0) | ||
245 | cu_nmrsc: | ||
246 | movew LOCAL_EX(%a0),%d1 | ||
247 | andw #0x7FFF,%d1 | ||
248 | cmpw #0x407f,%d1 | ||
249 | blt cu_wrexn | ||
250 | | | ||
251 | | The operand is above precision boundaries. Use t_ovfl to | ||
252 | | generate the correct value. | ||
253 | | | ||
254 | cu_novfl: | ||
255 | bsr t_ovfl | ||
256 | bra cu_wrexn | ||
257 | | | ||
258 | | The operand is below precision boundaries. Use denorm to | ||
259 | | generate the correct value. | ||
260 | | | ||
261 | cu_nunfl: | ||
262 | bclrb #sign_bit,LOCAL_EX(%a0) | ||
263 | sne LOCAL_SGN(%a0) | ||
264 | bsr denorm | ||
265 | bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format | ||
266 | beqs cu_nucont | ||
267 | bsetb #sign_bit,LOCAL_EX(%a0) | ||
268 | cu_nucont: | ||
269 | bfextu FPCR_MODE(%a6){#2:#2},%d1 | ||
270 | btstb #2,CMDREG1B+1(%a6) |check for rd | ||
271 | bne inst_d | ||
272 | btstb #6,CMDREG1B+1(%a6) |check for rs | ||
273 | bne inst_s | ||
274 | swap %d1 | ||
275 | moveb FPCR_MODE(%a6),%d1 | ||
276 | lsrb #6,%d1 | ||
277 | swap %d1 | ||
278 | bra inst_sd | ||
279 | inst_d: | ||
280 | orl #0x00020000,%d1 | ||
281 | bra inst_sd | ||
282 | inst_s: | ||
283 | orl #0x00010000,%d1 | ||
284 | inst_sd: | ||
285 | bclrb #sign_bit,LOCAL_EX(%a0) | ||
286 | sne LOCAL_SGN(%a0) | ||
287 | bsrl round | ||
288 | bfclr LOCAL_SGN(%a0){#0:#8} | ||
289 | beqs cu_nuflp | ||
290 | bsetb #sign_bit,LOCAL_EX(%a0) | ||
291 | cu_nuflp: | ||
292 | btstb #inex2_bit,FPSR_EXCEPT(%a6) | ||
293 | beqs cu_nuninx | ||
294 | orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL | ||
295 | cu_nuninx: | ||
296 | tstl LOCAL_HI(%a0) |test for zero | ||
297 | bnes cu_nunzro | ||
298 | tstl LOCAL_LO(%a0) | ||
299 | bnes cu_nunzro | ||
300 | | | ||
301 | | The mantissa is zero from the denorm loop. Check sign and rmode | ||
302 | | to see if rounding should have occurred which would leave the lsb. | ||
303 | | | ||
304 | movel USER_FPCR(%a6),%d0 | ||
305 | andil #0x30,%d0 |isolate rmode | ||
306 | cmpil #0x20,%d0 | ||
307 | blts cu_nzro | ||
308 | bnes cu_nrp | ||
309 | cu_nrm: | ||
310 | tstw LOCAL_EX(%a0) |if positive, set lsb | ||
311 | bges cu_nzro | ||
312 | btstb #7,FPCR_MODE(%a6) |check for double | ||
313 | beqs cu_nincs | ||
314 | bras cu_nincd | ||
315 | cu_nrp: | ||
316 | tstw LOCAL_EX(%a0) |if positive, set lsb | ||
317 | blts cu_nzro | ||
318 | btstb #7,FPCR_MODE(%a6) |check for double | ||
319 | beqs cu_nincs | ||
320 | cu_nincd: | ||
321 | orl #0x800,LOCAL_LO(%a0) |inc for double | ||
322 | bra cu_nunzro | ||
323 | cu_nincs: | ||
324 | orl #0x100,LOCAL_HI(%a0) |inc for single | ||
325 | bra cu_nunzro | ||
326 | cu_nzro: | ||
327 | orl #z_mask,USER_FPSR(%a6) | ||
328 | moveb STAG(%a6),%d0 | ||
329 | andib #0xe0,%d0 | ||
330 | cmpib #0x40,%d0 |check if input was tagged zero | ||
331 | beqs cu_numv | ||
332 | cu_nunzro: | ||
333 | orl #unfl_mask,USER_FPSR(%a6) |set unfl | ||
334 | cu_numv: | ||
335 | movel (%a0),ETEMP(%a6) | ||
336 | movel 4(%a0),ETEMP_HI(%a6) | ||
337 | movel 8(%a0),ETEMP_LO(%a6) | ||
338 | | | ||
339 | | Write the result to memory, setting the fpsr cc bits. NaN and Inf | ||
340 | | bypass cu_wrexn. | ||
341 | | | ||
342 | cu_wrexn: | ||
343 | tstw LOCAL_EX(%a0) |test for zero | ||
344 | beqs cu_wrzero | ||
345 | cmpw #0x8000,LOCAL_EX(%a0) |test for zero | ||
346 | bnes cu_wreon | ||
347 | cu_wrzero: | ||
348 | orl #z_mask,USER_FPSR(%a6) |set Z bit | ||
349 | cu_wreon: | ||
350 | tstw LOCAL_EX(%a0) | ||
351 | bpl wr_etemp | ||
352 | orl #neg_mask,USER_FPSR(%a6) | ||
353 | bra wr_etemp | ||
354 | |||
355 | | | ||
356 | | HANDLE SOURCE DENORM HERE | ||
357 | | | ||
358 | | ;clear denorm stag to norm | ||
359 | | ;write the new tag & ete15 to the fstack | ||
360 | mon_dnrm: | ||
361 | | | ||
362 | | At this point, check for the cases in which normalizing the | ||
363 | | denorm produces incorrect results. | ||
364 | | | ||
365 | tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would | ||
366 | bnes nrm_src |require normalization of denorm | ||
367 | |||
368 | | At this point: | ||
369 | | monadic instructions: fabs = $18 fneg = $1a ftst = $3a | ||
370 | | fmove = $00 fsmove = $40 fdmove = $44 | ||
371 | | fsqrt = $05* fssqrt = $41 fdsqrt = $45 | ||
372 | | (*fsqrt reencoded to $05) | ||
373 | | | ||
374 | movew CMDREG1B(%a6),%d0 |get command register | ||
375 | andil #0x7f,%d0 |strip to only command word | ||
376 | | | ||
377 | | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and | ||
378 | | fdsqrt are possible. | ||
379 | | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize) | ||
380 | | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize) | ||
381 | | | ||
382 | btstl #0,%d0 | ||
383 | bnes nrm_src |weed out fsqrt instructions | ||
384 | st CU_ONLY(%a6) |set cu-only inst flag | ||
385 | bra cu_dnrm |fmove, fabs, fneg, ftst | ||
386 | | ;cases go to cu_dnrm | ||
387 | nrm_src: | ||
388 | bclrb #sign_bit,LOCAL_EX(%a0) | ||
389 | sne LOCAL_SGN(%a0) | ||
390 | bsr nrm_set |normalize number (exponent will go | ||
391 | | ; negative) | ||
392 | bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign | ||
393 | |||
394 | bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format | ||
395 | beqs spos | ||
396 | bsetb #sign_bit,LOCAL_EX(%a0) | ||
397 | spos: | ||
398 | bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0 | ||
399 | bsetb #4,STAG(%a6) |set ETE15 | ||
400 | orb #0xf0,DNRM_FLG(%a6) | ||
401 | normal: | ||
402 | tstb DNRM_FLG(%a6) |check if any of the ops were denorms | ||
403 | bne ck_wrap |if so, check if it is a potential | ||
404 | | ;wrap-around case | ||
405 | fix_stk: | ||
406 | moveb #0xfe,CU_SAVEPC(%a6) | ||
407 | bclrb #E1,E_BYTE(%a6) | ||
408 | |||
409 | clrw NMNEXC(%a6) | ||
410 | |||
411 | st RES_FLG(%a6) |indicate that a restore is needed | ||
412 | rts | ||
413 | |||
414 | | | ||
415 | | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and | ||
416 | | ftst) completely in software without an frestore to the 040. | ||
417 | | | ||
418 | cu_dnrm: | ||
419 | st CU_ONLY(%a6) | ||
420 | movew CMDREG1B(%a6),%d0 | ||
421 | andib #0x3b,%d0 |isolate bits to select inst | ||
422 | tstb %d0 | ||
423 | beql cu_dmove |if zero, it is an fmove | ||
424 | cmpib #0x18,%d0 | ||
425 | beql cu_dabs |if $18, it is fabs | ||
426 | cmpib #0x1a,%d0 | ||
427 | beql cu_dneg |if $1a, it is fneg | ||
428 | | | ||
429 | | Inst is ftst. Check the source operand and set the cc's accordingly. | ||
430 | | No write is done, so simply rts. | ||
431 | | | ||
432 | cu_dtst: | ||
433 | movew LOCAL_EX(%a0),%d0 | ||
434 | bclrl #15,%d0 | ||
435 | sne LOCAL_SGN(%a0) | ||
436 | beqs cu_dtpo | ||
437 | orl #neg_mask,USER_FPSR(%a6) |set N | ||
438 | cu_dtpo: | ||
439 | cmpiw #0x7fff,%d0 |test for inf/nan | ||
440 | bnes cu_dtcz | ||
441 | tstl LOCAL_HI(%a0) | ||
442 | bnes cu_dtn | ||
443 | tstl LOCAL_LO(%a0) | ||
444 | bnes cu_dtn | ||
445 | orl #inf_mask,USER_FPSR(%a6) | ||
446 | rts | ||
447 | cu_dtn: | ||
448 | orl #nan_mask,USER_FPSR(%a6) | ||
449 | movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for | ||
450 | | ;snan handler | ||
451 | rts | ||
452 | cu_dtcz: | ||
453 | tstl LOCAL_HI(%a0) | ||
454 | bnel cu_dtsx | ||
455 | tstl LOCAL_LO(%a0) | ||
456 | bnel cu_dtsx | ||
457 | orl #z_mask,USER_FPSR(%a6) | ||
458 | cu_dtsx: | ||
459 | rts | ||
460 | | | ||
461 | | Inst is fabs. Execute the absolute value function on the input. | ||
462 | | Branch to the fmove code. | ||
463 | | | ||
464 | cu_dabs: | ||
465 | bclrb #7,LOCAL_EX(%a0) |do abs | ||
466 | bras cu_dmove |fmove code will finish | ||
467 | | | ||
468 | | Inst is fneg. Execute the negate value function on the input. | ||
469 | | Fall though to the fmove code. | ||
470 | | | ||
471 | cu_dneg: | ||
472 | bchgb #7,LOCAL_EX(%a0) |do neg | ||
473 | | | ||
474 | | Inst is fmove. This code also handles all result writes. | ||
475 | | If bit 2 is set, round is forced to double. If it is clear, | ||
476 | | and bit 6 is set, round is forced to single. If both are clear, | ||
477 | | the round precision is found in the fpcr. If the rounding precision | ||
478 | | is double or single, the result is zero, and the mode is checked | ||
479 | | to determine if the lsb of the result should be set. | ||
480 | | | ||
481 | cu_dmove: | ||
482 | btstb #2,CMDREG1B+1(%a6) |check for rd | ||
483 | bne cu_dmrd | ||
484 | btstb #6,CMDREG1B+1(%a6) |check for rs | ||
485 | bne cu_dmrs | ||
486 | | | ||
487 | | The move or operation is not with forced precision. Use the | ||
488 | | FPCR_MODE byte to get rounding. | ||
489 | | | ||
490 | cu_dmnr: | ||
491 | bfextu FPCR_MODE(%a6){#0:#2},%d0 | ||
492 | tstb %d0 |check for extended | ||
493 | beq cu_wrexd |if so, just write result | ||
494 | cmpib #1,%d0 |check for single | ||
495 | beq cu_dmrs |fall through to double | ||
496 | | | ||
497 | | The move is fdmove or round precision is double. Result is zero. | ||
498 | | Check rmode for rp or rm and set lsb accordingly. | ||
499 | | | ||
500 | cu_dmrd: | ||
501 | bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode | ||
502 | tstw LOCAL_EX(%a0) |check sign | ||
503 | blts cu_dmdn | ||
504 | cmpib #3,%d1 |check for rp | ||
505 | bne cu_dpd |load double pos zero | ||
506 | bra cu_dpdr |load double pos zero w/lsb | ||
507 | cu_dmdn: | ||
508 | cmpib #2,%d1 |check for rm | ||
509 | bne cu_dnd |load double neg zero | ||
510 | bra cu_dndr |load double neg zero w/lsb | ||
511 | | | ||
512 | | The move is fsmove or round precision is single. Result is zero. | ||
513 | | Check for rp or rm and set lsb accordingly. | ||
514 | | | ||
515 | cu_dmrs: | ||
516 | bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode | ||
517 | tstw LOCAL_EX(%a0) |check sign | ||
518 | blts cu_dmsn | ||
519 | cmpib #3,%d1 |check for rp | ||
520 | bne cu_spd |load single pos zero | ||
521 | bra cu_spdr |load single pos zero w/lsb | ||
522 | cu_dmsn: | ||
523 | cmpib #2,%d1 |check for rm | ||
524 | bne cu_snd |load single neg zero | ||
525 | bra cu_sndr |load single neg zero w/lsb | ||
526 | | | ||
527 | | The precision is extended, so the result in etemp is correct. | ||
528 | | Simply set unfl (not inex2 or aunfl) and write the result to | ||
529 | | the correct fp register. | ||
530 | cu_wrexd: | ||
531 | orl #unfl_mask,USER_FPSR(%a6) | ||
532 | tstw LOCAL_EX(%a0) | ||
533 | beq wr_etemp | ||
534 | orl #neg_mask,USER_FPSR(%a6) | ||
535 | bra wr_etemp | ||
536 | | | ||
537 | | These routines write +/- zero in double format. The routines | ||
538 | | cu_dpdr and cu_dndr set the double lsb. | ||
539 | | | ||
540 | cu_dpd: | ||
541 | movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero | ||
542 | clrl LOCAL_HI(%a0) | ||
543 | clrl LOCAL_LO(%a0) | ||
544 | orl #z_mask,USER_FPSR(%a6) | ||
545 | orl #unfinx_mask,USER_FPSR(%a6) | ||
546 | bra wr_etemp | ||
547 | cu_dpdr: | ||
548 | movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero | ||
549 | clrl LOCAL_HI(%a0) | ||
550 | movel #0x800,LOCAL_LO(%a0) |with lsb set | ||
551 | orl #unfinx_mask,USER_FPSR(%a6) | ||
552 | bra wr_etemp | ||
553 | cu_dnd: | ||
554 | movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero | ||
555 | clrl LOCAL_HI(%a0) | ||
556 | clrl LOCAL_LO(%a0) | ||
557 | orl #z_mask,USER_FPSR(%a6) | ||
558 | orl #neg_mask,USER_FPSR(%a6) | ||
559 | orl #unfinx_mask,USER_FPSR(%a6) | ||
560 | bra wr_etemp | ||
561 | cu_dndr: | ||
562 | movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero | ||
563 | clrl LOCAL_HI(%a0) | ||
564 | movel #0x800,LOCAL_LO(%a0) |with lsb set | ||
565 | orl #neg_mask,USER_FPSR(%a6) | ||
566 | orl #unfinx_mask,USER_FPSR(%a6) | ||
567 | bra wr_etemp | ||
568 | | | ||
569 | | These routines write +/- zero in single format. The routines | ||
570 | | cu_dpdr and cu_dndr set the single lsb. | ||
571 | | | ||
572 | cu_spd: | ||
573 | movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero | ||
574 | clrl LOCAL_HI(%a0) | ||
575 | clrl LOCAL_LO(%a0) | ||
576 | orl #z_mask,USER_FPSR(%a6) | ||
577 | orl #unfinx_mask,USER_FPSR(%a6) | ||
578 | bra wr_etemp | ||
579 | cu_spdr: | ||
580 | movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero | ||
581 | movel #0x100,LOCAL_HI(%a0) |with lsb set | ||
582 | clrl LOCAL_LO(%a0) | ||
583 | orl #unfinx_mask,USER_FPSR(%a6) | ||
584 | bra wr_etemp | ||
585 | cu_snd: | ||
586 | movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero | ||
587 | clrl LOCAL_HI(%a0) | ||
588 | clrl LOCAL_LO(%a0) | ||
589 | orl #z_mask,USER_FPSR(%a6) | ||
590 | orl #neg_mask,USER_FPSR(%a6) | ||
591 | orl #unfinx_mask,USER_FPSR(%a6) | ||
592 | bra wr_etemp | ||
593 | cu_sndr: | ||
594 | movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero | ||
595 | movel #0x100,LOCAL_HI(%a0) |with lsb set | ||
596 | clrl LOCAL_LO(%a0) | ||
597 | orl #neg_mask,USER_FPSR(%a6) | ||
598 | orl #unfinx_mask,USER_FPSR(%a6) | ||
599 | bra wr_etemp | ||
600 | |||
601 | | | ||
602 | | This code checks for 16-bit overflow conditions on dyadic | ||
603 | | operations which are not restorable into the floating-point | ||
604 | | unit and must be completed in software. Basically, this | ||
605 | | condition exists with a very large norm and a denorm. One | ||
606 | | of the operands must be denormalized to enter this code. | ||
607 | | | ||
608 | | Flags used: | ||
609 | | DY_MO_FLG contains 0 for monadic op, $ff for dyadic | ||
610 | | DNRM_FLG contains $00 for neither op denormalized | ||
611 | | $0f for the destination op denormalized | ||
612 | | $f0 for the source op denormalized | ||
613 | | $ff for both ops denormalized | ||
614 | | | ||
615 | | The wrap-around condition occurs for add, sub, div, and cmp | ||
616 | | when | ||
617 | | | ||
618 | | abs(dest_exp - src_exp) >= $8000 | ||
619 | | | ||
620 | | and for mul when | ||
621 | | | ||
622 | | (dest_exp + src_exp) < $0 | ||
623 | | | ||
624 | | we must process the operation here if this case is true. | ||
625 | | | ||
626 | | The rts following the frcfpn routine is the exit from res_func | ||
627 | | for this condition. The restore flag (RES_FLG) is left clear. | ||
628 | | No frestore is done unless an exception is to be reported. | ||
629 | | | ||
630 | | For fadd: | ||
631 | | if(sign_of(dest) != sign_of(src)) | ||
632 | | replace exponent of src with $3fff (keep sign) | ||
633 | | use fpu to perform dest+new_src (user's rmode and X) | ||
634 | | clr sticky | ||
635 | | else | ||
636 | | set sticky | ||
637 | | call round with user's precision and mode | ||
638 | | move result to fpn and wbtemp | ||
639 | | | ||
640 | | For fsub: | ||
641 | | if(sign_of(dest) == sign_of(src)) | ||
642 | | replace exponent of src with $3fff (keep sign) | ||
643 | | use fpu to perform dest+new_src (user's rmode and X) | ||
644 | | clr sticky | ||
645 | | else | ||
646 | | set sticky | ||
647 | | call round with user's precision and mode | ||
648 | | move result to fpn and wbtemp | ||
649 | | | ||
650 | | For fdiv/fsgldiv: | ||
651 | | if(both operands are denorm) | ||
652 | | restore_to_fpu; | ||
653 | | if(dest is norm) | ||
654 | | force_ovf; | ||
655 | | else(dest is denorm) | ||
656 | | force_unf: | ||
657 | | | ||
658 | | For fcmp: | ||
659 | | if(dest is norm) | ||
660 | | N = sign_of(dest); | ||
661 | | else(dest is denorm) | ||
662 | | N = sign_of(src); | ||
663 | | | ||
664 | | For fmul: | ||
665 | | if(both operands are denorm) | ||
666 | | force_unf; | ||
667 | | if((dest_exp + src_exp) < 0) | ||
668 | | force_unf: | ||
669 | | else | ||
670 | | restore_to_fpu; | ||
671 | | | ||
672 | | local equates: | ||
673 | .set addcode,0x22 | ||
674 | .set subcode,0x28 | ||
675 | .set mulcode,0x23 | ||
676 | .set divcode,0x20 | ||
677 | .set cmpcode,0x38 | ||
678 | ck_wrap: | ||
679 | | tstb DY_MO_FLG(%a6) ;check for fsqrt | ||
680 | beq fix_stk |if zero, it is fsqrt | ||
681 | movew CMDREG1B(%a6),%d0 | ||
682 | andiw #0x3b,%d0 |strip to command bits | ||
683 | cmpiw #addcode,%d0 | ||
684 | beq wrap_add | ||
685 | cmpiw #subcode,%d0 | ||
686 | beq wrap_sub | ||
687 | cmpiw #mulcode,%d0 | ||
688 | beq wrap_mul | ||
689 | cmpiw #cmpcode,%d0 | ||
690 | beq wrap_cmp | ||
691 | | | ||
692 | | Inst is fdiv. | ||
693 | | | ||
694 | wrap_div: | ||
695 | cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, | ||
696 | beq fix_stk |restore to fpu | ||
697 | | | ||
698 | | One of the ops is denormalized. Test for wrap condition | ||
699 | | and force the result. | ||
700 | | | ||
701 | cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm | ||
702 | bnes div_srcd | ||
703 | div_destd: | ||
704 | bsrl ckinf_ns | ||
705 | bne fix_stk | ||
706 | bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) | ||
707 | bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) | ||
708 | subl %d1,%d0 |subtract dest from src | ||
709 | cmpl #0x7fff,%d0 | ||
710 | blt fix_stk |if less, not wrap case | ||
711 | clrb WBTEMP_SGN(%a6) | ||
712 | movew ETEMP_EX(%a6),%d0 |find the sign of the result | ||
713 | movew FPTEMP_EX(%a6),%d1 | ||
714 | eorw %d1,%d0 | ||
715 | andiw #0x8000,%d0 | ||
716 | beq force_unf | ||
717 | st WBTEMP_SGN(%a6) | ||
718 | bra force_unf | ||
719 | |||
720 | ckinf_ns: | ||
721 | moveb STAG(%a6),%d0 |check source tag for inf or nan | ||
722 | bra ck_in_com | ||
723 | ckinf_nd: | ||
724 | moveb DTAG(%a6),%d0 |check destination tag for inf or nan | ||
725 | ck_in_com: | ||
726 | andib #0x60,%d0 |isolate tag bits | ||
727 | cmpb #0x40,%d0 |is it inf? | ||
728 | beq nan_or_inf |not wrap case | ||
729 | cmpb #0x60,%d0 |is it nan? | ||
730 | beq nan_or_inf |yes, not wrap case? | ||
731 | cmpb #0x20,%d0 |is it a zero? | ||
732 | beq nan_or_inf |yes | ||
733 | clrl %d0 | ||
734 | rts |then ; it is either a zero of norm, | ||
735 | | ;check wrap case | ||
736 | nan_or_inf: | ||
737 | moveql #-1,%d0 | ||
738 | rts | ||
739 | |||
740 | |||
741 | |||
742 | div_srcd: | ||
743 | bsrl ckinf_nd | ||
744 | bne fix_stk | ||
745 | bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) | ||
746 | bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) | ||
747 | subl %d1,%d0 |subtract src from dest | ||
748 | cmpl #0x8000,%d0 | ||
749 | blt fix_stk |if less, not wrap case | ||
750 | clrb WBTEMP_SGN(%a6) | ||
751 | movew ETEMP_EX(%a6),%d0 |find the sign of the result | ||
752 | movew FPTEMP_EX(%a6),%d1 | ||
753 | eorw %d1,%d0 | ||
754 | andiw #0x8000,%d0 | ||
755 | beqs force_ovf | ||
756 | st WBTEMP_SGN(%a6) | ||
757 | | | ||
758 | | This code handles the case of the instruction resulting in | ||
759 | | an overflow condition. | ||
760 | | | ||
761 | force_ovf: | ||
762 | bclrb #E1,E_BYTE(%a6) | ||
763 | orl #ovfl_inx_mask,USER_FPSR(%a6) | ||
764 | clrw NMNEXC(%a6) | ||
765 | leal WBTEMP(%a6),%a0 |point a0 to memory location | ||
766 | movew CMDREG1B(%a6),%d0 | ||
767 | btstl #6,%d0 |test for forced precision | ||
768 | beqs frcovf_fpcr | ||
769 | btstl #2,%d0 |check for double | ||
770 | bnes frcovf_dbl | ||
771 | movel #0x1,%d0 |inst is forced single | ||
772 | bras frcovf_rnd | ||
773 | frcovf_dbl: | ||
774 | movel #0x2,%d0 |inst is forced double | ||
775 | bras frcovf_rnd | ||
776 | frcovf_fpcr: | ||
777 | bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec | ||
778 | frcovf_rnd: | ||
779 | |||
780 | | The 881/882 does not set inex2 for the following case, so the | ||
781 | | line is commented out to be compatible with 881/882 | ||
782 | | tst.b %d0 | ||
783 | | beq.b frcovf_x | ||
784 | | or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2 | ||
785 | |||
786 | |frcovf_x: | ||
787 | bsrl ovf_res |get correct result based on | ||
788 | | ;round precision/mode. This | ||
789 | | ;sets FPSR_CC correctly | ||
790 | | ;returns in external format | ||
791 | bfclr WBTEMP_SGN(%a6){#0:#8} | ||
792 | beq frcfpn | ||
793 | bsetb #sign_bit,WBTEMP_EX(%a6) | ||
794 | bra frcfpn | ||
795 | | | ||
796 | | Inst is fadd. | ||
797 | | | ||
798 | wrap_add: | ||
799 | cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, | ||
800 | beq fix_stk |restore to fpu | ||
801 | | | ||
802 | | One of the ops is denormalized. Test for wrap condition | ||
803 | | and complete the instruction. | ||
804 | | | ||
805 | cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm | ||
806 | bnes add_srcd | ||
807 | add_destd: | ||
808 | bsrl ckinf_ns | ||
809 | bne fix_stk | ||
810 | bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) | ||
811 | bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) | ||
812 | subl %d1,%d0 |subtract dest from src | ||
813 | cmpl #0x8000,%d0 | ||
814 | blt fix_stk |if less, not wrap case | ||
815 | bra add_wrap | ||
816 | add_srcd: | ||
817 | bsrl ckinf_nd | ||
818 | bne fix_stk | ||
819 | bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) | ||
820 | bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) | ||
821 | subl %d1,%d0 |subtract src from dest | ||
822 | cmpl #0x8000,%d0 | ||
823 | blt fix_stk |if less, not wrap case | ||
824 | | | ||
825 | | Check the signs of the operands. If they are unlike, the fpu | ||
826 | | can be used to add the norm and 1.0 with the sign of the | ||
827 | | denorm and it will correctly generate the result in extended | ||
828 | | precision. We can then call round with no sticky and the result | ||
829 | | will be correct for the user's rounding mode and precision. If | ||
830 | | the signs are the same, we call round with the sticky bit set | ||
831 | | and the result will be correct for the user's rounding mode and | ||
832 | | precision. | ||
833 | | | ||
834 | add_wrap: | ||
835 | movew ETEMP_EX(%a6),%d0 | ||
836 | movew FPTEMP_EX(%a6),%d1 | ||
837 | eorw %d1,%d0 | ||
838 | andiw #0x8000,%d0 | ||
839 | beq add_same | ||
840 | | | ||
841 | | The signs are unlike. | ||
842 | | | ||
843 | cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? | ||
844 | bnes add_u_srcd | ||
845 | movew FPTEMP_EX(%a6),%d0 | ||
846 | andiw #0x8000,%d0 | ||
847 | orw #0x3fff,%d0 |force the exponent to +/- 1 | ||
848 | movew %d0,FPTEMP_EX(%a6) |in the denorm | ||
849 | movel USER_FPCR(%a6),%d0 | ||
850 | andil #0x30,%d0 | ||
851 | fmovel %d0,%fpcr |set up users rmode and X | ||
852 | fmovex ETEMP(%a6),%fp0 | ||
853 | faddx FPTEMP(%a6),%fp0 | ||
854 | leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame | ||
855 | fmovel %fpsr,%d1 | ||
856 | orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd | ||
857 | fmovex %fp0,WBTEMP(%a6) |write result to memory | ||
858 | lsrl #4,%d0 |put rmode in lower 2 bits | ||
859 | movel USER_FPCR(%a6),%d1 | ||
860 | andil #0xc0,%d1 | ||
861 | lsrl #6,%d1 |put precision in upper word | ||
862 | swap %d1 | ||
863 | orl %d0,%d1 |set up for round call | ||
864 | clrl %d0 |force sticky to zero | ||
865 | bclrb #sign_bit,WBTEMP_EX(%a6) | ||
866 | sne WBTEMP_SGN(%a6) | ||
867 | bsrl round |round result to users rmode & prec | ||
868 | bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
869 | beq frcfpnr | ||
870 | bsetb #sign_bit,WBTEMP_EX(%a6) | ||
871 | bra frcfpnr | ||
872 | add_u_srcd: | ||
873 | movew ETEMP_EX(%a6),%d0 | ||
874 | andiw #0x8000,%d0 | ||
875 | orw #0x3fff,%d0 |force the exponent to +/- 1 | ||
876 | movew %d0,ETEMP_EX(%a6) |in the denorm | ||
877 | movel USER_FPCR(%a6),%d0 | ||
878 | andil #0x30,%d0 | ||
879 | fmovel %d0,%fpcr |set up users rmode and X | ||
880 | fmovex ETEMP(%a6),%fp0 | ||
881 | faddx FPTEMP(%a6),%fp0 | ||
882 | fmovel %fpsr,%d1 | ||
883 | orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd | ||
884 | leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame | ||
885 | fmovex %fp0,WBTEMP(%a6) |write result to memory | ||
886 | lsrl #4,%d0 |put rmode in lower 2 bits | ||
887 | movel USER_FPCR(%a6),%d1 | ||
888 | andil #0xc0,%d1 | ||
889 | lsrl #6,%d1 |put precision in upper word | ||
890 | swap %d1 | ||
891 | orl %d0,%d1 |set up for round call | ||
892 | clrl %d0 |force sticky to zero | ||
893 | bclrb #sign_bit,WBTEMP_EX(%a6) | ||
894 | sne WBTEMP_SGN(%a6) |use internal format for round | ||
895 | bsrl round |round result to users rmode & prec | ||
896 | bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
897 | beq frcfpnr | ||
898 | bsetb #sign_bit,WBTEMP_EX(%a6) | ||
899 | bra frcfpnr | ||
900 | | | ||
901 | | Signs are alike: | ||
902 | | | ||
903 | add_same: | ||
904 | cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? | ||
905 | bnes add_s_srcd | ||
906 | add_s_destd: | ||
907 | leal ETEMP(%a6),%a0 | ||
908 | movel USER_FPCR(%a6),%d0 | ||
909 | andil #0x30,%d0 | ||
910 | lsrl #4,%d0 |put rmode in lower 2 bits | ||
911 | movel USER_FPCR(%a6),%d1 | ||
912 | andil #0xc0,%d1 | ||
913 | lsrl #6,%d1 |put precision in upper word | ||
914 | swap %d1 | ||
915 | orl %d0,%d1 |set up for round call | ||
916 | movel #0x20000000,%d0 |set sticky for round | ||
917 | bclrb #sign_bit,ETEMP_EX(%a6) | ||
918 | sne ETEMP_SGN(%a6) | ||
919 | bsrl round |round result to users rmode & prec | ||
920 | bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
921 | beqs add_s_dclr | ||
922 | bsetb #sign_bit,ETEMP_EX(%a6) | ||
923 | add_s_dclr: | ||
924 | leal WBTEMP(%a6),%a0 | ||
925 | movel ETEMP(%a6),(%a0) |write result to wbtemp | ||
926 | movel ETEMP_HI(%a6),4(%a0) | ||
927 | movel ETEMP_LO(%a6),8(%a0) | ||
928 | tstw ETEMP_EX(%a6) | ||
929 | bgt add_ckovf | ||
930 | orl #neg_mask,USER_FPSR(%a6) | ||
931 | bra add_ckovf | ||
932 | add_s_srcd: | ||
933 | leal FPTEMP(%a6),%a0 | ||
934 | movel USER_FPCR(%a6),%d0 | ||
935 | andil #0x30,%d0 | ||
936 | lsrl #4,%d0 |put rmode in lower 2 bits | ||
937 | movel USER_FPCR(%a6),%d1 | ||
938 | andil #0xc0,%d1 | ||
939 | lsrl #6,%d1 |put precision in upper word | ||
940 | swap %d1 | ||
941 | orl %d0,%d1 |set up for round call | ||
942 | movel #0x20000000,%d0 |set sticky for round | ||
943 | bclrb #sign_bit,FPTEMP_EX(%a6) | ||
944 | sne FPTEMP_SGN(%a6) | ||
945 | bsrl round |round result to users rmode & prec | ||
946 | bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
947 | beqs add_s_sclr | ||
948 | bsetb #sign_bit,FPTEMP_EX(%a6) | ||
949 | add_s_sclr: | ||
950 | leal WBTEMP(%a6),%a0 | ||
951 | movel FPTEMP(%a6),(%a0) |write result to wbtemp | ||
952 | movel FPTEMP_HI(%a6),4(%a0) | ||
953 | movel FPTEMP_LO(%a6),8(%a0) | ||
954 | tstw FPTEMP_EX(%a6) | ||
955 | bgt add_ckovf | ||
956 | orl #neg_mask,USER_FPSR(%a6) | ||
957 | add_ckovf: | ||
958 | movew WBTEMP_EX(%a6),%d0 | ||
959 | andiw #0x7fff,%d0 | ||
960 | cmpiw #0x7fff,%d0 | ||
961 | bne frcfpnr | ||
962 | | | ||
963 | | The result has overflowed to $7fff exponent. Set I, ovfl, | ||
964 | | and aovfl, and clr the mantissa (incorrectly set by the | ||
965 | | round routine.) | ||
966 | | | ||
967 | orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) | ||
968 | clrl 4(%a0) | ||
969 | bra frcfpnr | ||
970 | | | ||
971 | | Inst is fsub. | ||
972 | | | ||
973 | wrap_sub: | ||
974 | cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, | ||
975 | beq fix_stk |restore to fpu | ||
976 | | | ||
977 | | One of the ops is denormalized. Test for wrap condition | ||
978 | | and complete the instruction. | ||
979 | | | ||
980 | cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm | ||
981 | bnes sub_srcd | ||
982 | sub_destd: | ||
983 | bsrl ckinf_ns | ||
984 | bne fix_stk | ||
985 | bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) | ||
986 | bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) | ||
987 | subl %d1,%d0 |subtract src from dest | ||
988 | cmpl #0x8000,%d0 | ||
989 | blt fix_stk |if less, not wrap case | ||
990 | bra sub_wrap | ||
991 | sub_srcd: | ||
992 | bsrl ckinf_nd | ||
993 | bne fix_stk | ||
994 | bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) | ||
995 | bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) | ||
996 | subl %d1,%d0 |subtract dest from src | ||
997 | cmpl #0x8000,%d0 | ||
998 | blt fix_stk |if less, not wrap case | ||
999 | | | ||
1000 | | Check the signs of the operands. If they are alike, the fpu | ||
1001 | | can be used to subtract from the norm 1.0 with the sign of the | ||
1002 | | denorm and it will correctly generate the result in extended | ||
1003 | | precision. We can then call round with no sticky and the result | ||
1004 | | will be correct for the user's rounding mode and precision. If | ||
1005 | | the signs are unlike, we call round with the sticky bit set | ||
1006 | | and the result will be correct for the user's rounding mode and | ||
1007 | | precision. | ||
1008 | | | ||
1009 | sub_wrap: | ||
1010 | movew ETEMP_EX(%a6),%d0 | ||
1011 | movew FPTEMP_EX(%a6),%d1 | ||
1012 | eorw %d1,%d0 | ||
1013 | andiw #0x8000,%d0 | ||
1014 | bne sub_diff | ||
1015 | | | ||
1016 | | The signs are alike. | ||
1017 | | | ||
1018 | cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? | ||
1019 | bnes sub_u_srcd | ||
1020 | movew FPTEMP_EX(%a6),%d0 | ||
1021 | andiw #0x8000,%d0 | ||
1022 | orw #0x3fff,%d0 |force the exponent to +/- 1 | ||
1023 | movew %d0,FPTEMP_EX(%a6) |in the denorm | ||
1024 | movel USER_FPCR(%a6),%d0 | ||
1025 | andil #0x30,%d0 | ||
1026 | fmovel %d0,%fpcr |set up users rmode and X | ||
1027 | fmovex FPTEMP(%a6),%fp0 | ||
1028 | fsubx ETEMP(%a6),%fp0 | ||
1029 | fmovel %fpsr,%d1 | ||
1030 | orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd | ||
1031 | leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame | ||
1032 | fmovex %fp0,WBTEMP(%a6) |write result to memory | ||
1033 | lsrl #4,%d0 |put rmode in lower 2 bits | ||
1034 | movel USER_FPCR(%a6),%d1 | ||
1035 | andil #0xc0,%d1 | ||
1036 | lsrl #6,%d1 |put precision in upper word | ||
1037 | swap %d1 | ||
1038 | orl %d0,%d1 |set up for round call | ||
1039 | clrl %d0 |force sticky to zero | ||
1040 | bclrb #sign_bit,WBTEMP_EX(%a6) | ||
1041 | sne WBTEMP_SGN(%a6) | ||
1042 | bsrl round |round result to users rmode & prec | ||
1043 | bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
1044 | beq frcfpnr | ||
1045 | bsetb #sign_bit,WBTEMP_EX(%a6) | ||
1046 | bra frcfpnr | ||
1047 | sub_u_srcd: | ||
1048 | movew ETEMP_EX(%a6),%d0 | ||
1049 | andiw #0x8000,%d0 | ||
1050 | orw #0x3fff,%d0 |force the exponent to +/- 1 | ||
1051 | movew %d0,ETEMP_EX(%a6) |in the denorm | ||
1052 | movel USER_FPCR(%a6),%d0 | ||
1053 | andil #0x30,%d0 | ||
1054 | fmovel %d0,%fpcr |set up users rmode and X | ||
1055 | fmovex FPTEMP(%a6),%fp0 | ||
1056 | fsubx ETEMP(%a6),%fp0 | ||
1057 | fmovel %fpsr,%d1 | ||
1058 | orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd | ||
1059 | leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame | ||
1060 | fmovex %fp0,WBTEMP(%a6) |write result to memory | ||
1061 | lsrl #4,%d0 |put rmode in lower 2 bits | ||
1062 | movel USER_FPCR(%a6),%d1 | ||
1063 | andil #0xc0,%d1 | ||
1064 | lsrl #6,%d1 |put precision in upper word | ||
1065 | swap %d1 | ||
1066 | orl %d0,%d1 |set up for round call | ||
1067 | clrl %d0 |force sticky to zero | ||
1068 | bclrb #sign_bit,WBTEMP_EX(%a6) | ||
1069 | sne WBTEMP_SGN(%a6) | ||
1070 | bsrl round |round result to users rmode & prec | ||
1071 | bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
1072 | beq frcfpnr | ||
1073 | bsetb #sign_bit,WBTEMP_EX(%a6) | ||
1074 | bra frcfpnr | ||
1075 | | | ||
1076 | | Signs are unlike: | ||
1077 | | | ||
1078 | sub_diff: | ||
1079 | cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm? | ||
1080 | bnes sub_s_srcd | ||
1081 | sub_s_destd: | ||
1082 | leal ETEMP(%a6),%a0 | ||
1083 | movel USER_FPCR(%a6),%d0 | ||
1084 | andil #0x30,%d0 | ||
1085 | lsrl #4,%d0 |put rmode in lower 2 bits | ||
1086 | movel USER_FPCR(%a6),%d1 | ||
1087 | andil #0xc0,%d1 | ||
1088 | lsrl #6,%d1 |put precision in upper word | ||
1089 | swap %d1 | ||
1090 | orl %d0,%d1 |set up for round call | ||
1091 | movel #0x20000000,%d0 |set sticky for round | ||
1092 | | | ||
1093 | | Since the dest is the denorm, the sign is the opposite of the | ||
1094 | | norm sign. | ||
1095 | | | ||
1096 | eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result | ||
1097 | tstw ETEMP_EX(%a6) | ||
1098 | bgts sub_s_dwr | ||
1099 | orl #neg_mask,USER_FPSR(%a6) | ||
1100 | sub_s_dwr: | ||
1101 | bclrb #sign_bit,ETEMP_EX(%a6) | ||
1102 | sne ETEMP_SGN(%a6) | ||
1103 | bsrl round |round result to users rmode & prec | ||
1104 | bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
1105 | beqs sub_s_dclr | ||
1106 | bsetb #sign_bit,ETEMP_EX(%a6) | ||
1107 | sub_s_dclr: | ||
1108 | leal WBTEMP(%a6),%a0 | ||
1109 | movel ETEMP(%a6),(%a0) |write result to wbtemp | ||
1110 | movel ETEMP_HI(%a6),4(%a0) | ||
1111 | movel ETEMP_LO(%a6),8(%a0) | ||
1112 | bra sub_ckovf | ||
1113 | sub_s_srcd: | ||
1114 | leal FPTEMP(%a6),%a0 | ||
1115 | movel USER_FPCR(%a6),%d0 | ||
1116 | andil #0x30,%d0 | ||
1117 | lsrl #4,%d0 |put rmode in lower 2 bits | ||
1118 | movel USER_FPCR(%a6),%d1 | ||
1119 | andil #0xc0,%d1 | ||
1120 | lsrl #6,%d1 |put precision in upper word | ||
1121 | swap %d1 | ||
1122 | orl %d0,%d1 |set up for round call | ||
1123 | movel #0x20000000,%d0 |set sticky for round | ||
1124 | bclrb #sign_bit,FPTEMP_EX(%a6) | ||
1125 | sne FPTEMP_SGN(%a6) | ||
1126 | bsrl round |round result to users rmode & prec | ||
1127 | bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
1128 | beqs sub_s_sclr | ||
1129 | bsetb #sign_bit,FPTEMP_EX(%a6) | ||
1130 | sub_s_sclr: | ||
1131 | leal WBTEMP(%a6),%a0 | ||
1132 | movel FPTEMP(%a6),(%a0) |write result to wbtemp | ||
1133 | movel FPTEMP_HI(%a6),4(%a0) | ||
1134 | movel FPTEMP_LO(%a6),8(%a0) | ||
1135 | tstw FPTEMP_EX(%a6) | ||
1136 | bgt sub_ckovf | ||
1137 | orl #neg_mask,USER_FPSR(%a6) | ||
1138 | sub_ckovf: | ||
1139 | movew WBTEMP_EX(%a6),%d0 | ||
1140 | andiw #0x7fff,%d0 | ||
1141 | cmpiw #0x7fff,%d0 | ||
1142 | bne frcfpnr | ||
1143 | | | ||
1144 | | The result has overflowed to $7fff exponent. Set I, ovfl, | ||
1145 | | and aovfl, and clr the mantissa (incorrectly set by the | ||
1146 | | round routine.) | ||
1147 | | | ||
1148 | orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6) | ||
1149 | clrl 4(%a0) | ||
1150 | bra frcfpnr | ||
1151 | | | ||
1152 | | Inst is fcmp. | ||
1153 | | | ||
1154 | wrap_cmp: | ||
1155 | cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, | ||
1156 | beq fix_stk |restore to fpu | ||
1157 | | | ||
1158 | | One of the ops is denormalized. Test for wrap condition | ||
1159 | | and complete the instruction. | ||
1160 | | | ||
1161 | cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm | ||
1162 | bnes cmp_srcd | ||
1163 | cmp_destd: | ||
1164 | bsrl ckinf_ns | ||
1165 | bne fix_stk | ||
1166 | bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) | ||
1167 | bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) | ||
1168 | subl %d1,%d0 |subtract dest from src | ||
1169 | cmpl #0x8000,%d0 | ||
1170 | blt fix_stk |if less, not wrap case | ||
1171 | tstw ETEMP_EX(%a6) |set N to ~sign_of(src) | ||
1172 | bge cmp_setn | ||
1173 | rts | ||
1174 | cmp_srcd: | ||
1175 | bsrl ckinf_nd | ||
1176 | bne fix_stk | ||
1177 | bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) | ||
1178 | bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) | ||
1179 | subl %d1,%d0 |subtract src from dest | ||
1180 | cmpl #0x8000,%d0 | ||
1181 | blt fix_stk |if less, not wrap case | ||
1182 | tstw FPTEMP_EX(%a6) |set N to sign_of(dest) | ||
1183 | blt cmp_setn | ||
1184 | rts | ||
1185 | cmp_setn: | ||
1186 | orl #neg_mask,USER_FPSR(%a6) | ||
1187 | rts | ||
1188 | |||
1189 | | | ||
1190 | | Inst is fmul. | ||
1191 | | | ||
1192 | wrap_mul: | ||
1193 | cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm, | ||
1194 | beq force_unf |force an underflow (really!) | ||
1195 | | | ||
1196 | | One of the ops is denormalized. Test for wrap condition | ||
1197 | | and complete the instruction. | ||
1198 | | | ||
1199 | cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm | ||
1200 | bnes mul_srcd | ||
1201 | mul_destd: | ||
1202 | bsrl ckinf_ns | ||
1203 | bne fix_stk | ||
1204 | bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos) | ||
1205 | bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg) | ||
1206 | addl %d1,%d0 |subtract dest from src | ||
1207 | bgt fix_stk | ||
1208 | bra force_unf | ||
1209 | mul_srcd: | ||
1210 | bsrl ckinf_nd | ||
1211 | bne fix_stk | ||
1212 | bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos) | ||
1213 | bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg) | ||
1214 | addl %d1,%d0 |subtract src from dest | ||
1215 | bgt fix_stk | ||
1216 | |||
1217 | | | ||
1218 | | This code handles the case of the instruction resulting in | ||
1219 | | an underflow condition. | ||
1220 | | | ||
1221 | force_unf: | ||
1222 | bclrb #E1,E_BYTE(%a6) | ||
1223 | orl #unfinx_mask,USER_FPSR(%a6) | ||
1224 | clrw NMNEXC(%a6) | ||
1225 | clrb WBTEMP_SGN(%a6) | ||
1226 | movew ETEMP_EX(%a6),%d0 |find the sign of the result | ||
1227 | movew FPTEMP_EX(%a6),%d1 | ||
1228 | eorw %d1,%d0 | ||
1229 | andiw #0x8000,%d0 | ||
1230 | beqs frcunfcont | ||
1231 | st WBTEMP_SGN(%a6) | ||
1232 | frcunfcont: | ||
1233 | lea WBTEMP(%a6),%a0 |point a0 to memory location | ||
1234 | movew CMDREG1B(%a6),%d0 | ||
1235 | btstl #6,%d0 |test for forced precision | ||
1236 | beqs frcunf_fpcr | ||
1237 | btstl #2,%d0 |check for double | ||
1238 | bnes frcunf_dbl | ||
1239 | movel #0x1,%d0 |inst is forced single | ||
1240 | bras frcunf_rnd | ||
1241 | frcunf_dbl: | ||
1242 | movel #0x2,%d0 |inst is forced double | ||
1243 | bras frcunf_rnd | ||
1244 | frcunf_fpcr: | ||
1245 | bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec | ||
1246 | frcunf_rnd: | ||
1247 | bsrl unf_sub |get correct result based on | ||
1248 | | ;round precision/mode. This | ||
1249 | | ;sets FPSR_CC correctly | ||
1250 | bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
1251 | beqs frcfpn | ||
1252 | bsetb #sign_bit,WBTEMP_EX(%a6) | ||
1253 | bra frcfpn | ||
1254 | |||
1255 | | | ||
1256 | | Write the result to the user's fpn. All results must be HUGE to be | ||
1257 | | written; otherwise the results would have overflowed or underflowed. | ||
1258 | | If the rounding precision is single or double, the ovf_res routine | ||
1259 | | is needed to correctly supply the max value. | ||
1260 | | | ||
1261 | frcfpnr: | ||
1262 | movew CMDREG1B(%a6),%d0 | ||
1263 | btstl #6,%d0 |test for forced precision | ||
1264 | beqs frcfpn_fpcr | ||
1265 | btstl #2,%d0 |check for double | ||
1266 | bnes frcfpn_dbl | ||
1267 | movel #0x1,%d0 |inst is forced single | ||
1268 | bras frcfpn_rnd | ||
1269 | frcfpn_dbl: | ||
1270 | movel #0x2,%d0 |inst is forced double | ||
1271 | bras frcfpn_rnd | ||
1272 | frcfpn_fpcr: | ||
1273 | bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec | ||
1274 | tstb %d0 | ||
1275 | beqs frcfpn |if extended, write what you got | ||
1276 | frcfpn_rnd: | ||
1277 | bclrb #sign_bit,WBTEMP_EX(%a6) | ||
1278 | sne WBTEMP_SGN(%a6) | ||
1279 | bsrl ovf_res |get correct result based on | ||
1280 | | ;round precision/mode. This | ||
1281 | | ;sets FPSR_CC correctly | ||
1282 | bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format | ||
1283 | beqs frcfpn_clr | ||
1284 | bsetb #sign_bit,WBTEMP_EX(%a6) | ||
1285 | frcfpn_clr: | ||
1286 | orl #ovfinx_mask,USER_FPSR(%a6) | ||
1287 | | | ||
1288 | | Perform the write. | ||
1289 | | | ||
1290 | frcfpn: | ||
1291 | bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register | ||
1292 | cmpib #3,%d0 | ||
1293 | bles frc0123 |check if dest is fp0-fp3 | ||
1294 | movel #7,%d1 | ||
1295 | subl %d0,%d1 | ||
1296 | clrl %d0 | ||
1297 | bsetl %d1,%d0 | ||
1298 | fmovemx WBTEMP(%a6),%d0 | ||
1299 | rts | ||
1300 | frc0123: | ||
1301 | cmpib #0,%d0 | ||
1302 | beqs frc0_dst | ||
1303 | cmpib #1,%d0 | ||
1304 | beqs frc1_dst | ||
1305 | cmpib #2,%d0 | ||
1306 | beqs frc2_dst | ||
1307 | frc3_dst: | ||
1308 | movel WBTEMP_EX(%a6),USER_FP3(%a6) | ||
1309 | movel WBTEMP_HI(%a6),USER_FP3+4(%a6) | ||
1310 | movel WBTEMP_LO(%a6),USER_FP3+8(%a6) | ||
1311 | rts | ||
1312 | frc2_dst: | ||
1313 | movel WBTEMP_EX(%a6),USER_FP2(%a6) | ||
1314 | movel WBTEMP_HI(%a6),USER_FP2+4(%a6) | ||
1315 | movel WBTEMP_LO(%a6),USER_FP2+8(%a6) | ||
1316 | rts | ||
1317 | frc1_dst: | ||
1318 | movel WBTEMP_EX(%a6),USER_FP1(%a6) | ||
1319 | movel WBTEMP_HI(%a6),USER_FP1+4(%a6) | ||
1320 | movel WBTEMP_LO(%a6),USER_FP1+8(%a6) | ||
1321 | rts | ||
1322 | frc0_dst: | ||
1323 | movel WBTEMP_EX(%a6),USER_FP0(%a6) | ||
1324 | movel WBTEMP_HI(%a6),USER_FP0+4(%a6) | ||
1325 | movel WBTEMP_LO(%a6),USER_FP0+8(%a6) | ||
1326 | rts | ||
1327 | |||
1328 | | | ||
1329 | | Write etemp to fpn. | ||
1330 | | A check is made on enabled and signalled snan exceptions, | ||
1331 | | and the destination is not overwritten if this condition exists. | ||
1332 | | This code is designed to make fmoveins of unsupported data types | ||
1333 | | faster. | ||
1334 | | | ||
1335 | wr_etemp: | ||
1336 | btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, and | ||
1337 | beqs fmoveinc |enabled, force restore | ||
1338 | btstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite | ||
1339 | beqs fmoveinc |the dest | ||
1340 | movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for | ||
1341 | | ;snan handler | ||
1342 | tstb ETEMP(%a6) |check for negative | ||
1343 | blts snan_neg | ||
1344 | rts | ||
1345 | snan_neg: | ||
1346 | orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N | ||
1347 | rts | ||
1348 | fmoveinc: | ||
1349 | clrw NMNEXC(%a6) | ||
1350 | bclrb #E1,E_BYTE(%a6) | ||
1351 | moveb STAG(%a6),%d0 |check if stag is inf | ||
1352 | andib #0xe0,%d0 | ||
1353 | cmpib #0x40,%d0 | ||
1354 | bnes fminc_cnan | ||
1355 | orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I | ||
1356 | tstw LOCAL_EX(%a0) |check sign | ||
1357 | bges fminc_con | ||
1358 | orl #neg_mask,USER_FPSR(%a6) | ||
1359 | bra fminc_con | ||
1360 | fminc_cnan: | ||
1361 | cmpib #0x60,%d0 |check if stag is NaN | ||
1362 | bnes fminc_czero | ||
1363 | orl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN | ||
1364 | movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for | ||
1365 | | ;snan handler | ||
1366 | tstw LOCAL_EX(%a0) |check sign | ||
1367 | bges fminc_con | ||
1368 | orl #neg_mask,USER_FPSR(%a6) | ||
1369 | bra fminc_con | ||
1370 | fminc_czero: | ||
1371 | cmpib #0x20,%d0 |check if zero | ||
1372 | bnes fminc_con | ||
1373 | orl #z_mask,USER_FPSR(%a6) |if zero, set Z | ||
1374 | tstw LOCAL_EX(%a0) |check sign | ||
1375 | bges fminc_con | ||
1376 | orl #neg_mask,USER_FPSR(%a6) | ||
1377 | fminc_con: | ||
1378 | bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register | ||
1379 | cmpib #3,%d0 | ||
1380 | bles fp0123 |check if dest is fp0-fp3 | ||
1381 | movel #7,%d1 | ||
1382 | subl %d0,%d1 | ||
1383 | clrl %d0 | ||
1384 | bsetl %d1,%d0 | ||
1385 | fmovemx ETEMP(%a6),%d0 | ||
1386 | rts | ||
1387 | |||
1388 | fp0123: | ||
1389 | cmpib #0,%d0 | ||
1390 | beqs fp0_dst | ||
1391 | cmpib #1,%d0 | ||
1392 | beqs fp1_dst | ||
1393 | cmpib #2,%d0 | ||
1394 | beqs fp2_dst | ||
1395 | fp3_dst: | ||
1396 | movel ETEMP_EX(%a6),USER_FP3(%a6) | ||
1397 | movel ETEMP_HI(%a6),USER_FP3+4(%a6) | ||
1398 | movel ETEMP_LO(%a6),USER_FP3+8(%a6) | ||
1399 | rts | ||
1400 | fp2_dst: | ||
1401 | movel ETEMP_EX(%a6),USER_FP2(%a6) | ||
1402 | movel ETEMP_HI(%a6),USER_FP2+4(%a6) | ||
1403 | movel ETEMP_LO(%a6),USER_FP2+8(%a6) | ||
1404 | rts | ||
1405 | fp1_dst: | ||
1406 | movel ETEMP_EX(%a6),USER_FP1(%a6) | ||
1407 | movel ETEMP_HI(%a6),USER_FP1+4(%a6) | ||
1408 | movel ETEMP_LO(%a6),USER_FP1+8(%a6) | ||
1409 | rts | ||
1410 | fp0_dst: | ||
1411 | movel ETEMP_EX(%a6),USER_FP0(%a6) | ||
1412 | movel ETEMP_HI(%a6),USER_FP0+4(%a6) | ||
1413 | movel ETEMP_LO(%a6),USER_FP0+8(%a6) | ||
1414 | rts | ||
1415 | |||
1416 | opclass3: | ||
1417 | st CU_ONLY(%a6) | ||
1418 | movew CMDREG1B(%a6),%d0 |check if packed moveout | ||
1419 | andiw #0x0c00,%d0 |isolate last 2 bits of size field | ||
1420 | cmpiw #0x0c00,%d0 |if size is 011 or 111, it is packed | ||
1421 | beq pack_out |else it is norm or denorm | ||
1422 | bra mv_out | ||
1423 | |||
1424 | |||
1425 | | | ||
1426 | | MOVE OUT | ||
1427 | | | ||
1428 | |||
1429 | mv_tbl: | ||
1430 | .long li | ||
1431 | .long sgp | ||
1432 | .long xp | ||
1433 | .long mvout_end |should never be taken | ||
1434 | .long wi | ||
1435 | .long dp | ||
1436 | .long bi | ||
1437 | .long mvout_end |should never be taken | ||
1438 | mv_out: | ||
1439 | bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1 | ||
1440 | leal mv_tbl,%a0 | ||
1441 | movel %a0@(%d1:l:4),%a0 | ||
1442 | jmp (%a0) | ||
1443 | |||
1444 | | | ||
1445 | | This exit is for move-out to memory. The aunfl bit is | ||
1446 | | set if the result is inex and unfl is signalled. | ||
1447 | | | ||
1448 | mvout_end: | ||
1449 | btstb #inex2_bit,FPSR_EXCEPT(%a6) | ||
1450 | beqs no_aufl | ||
1451 | btstb #unfl_bit,FPSR_EXCEPT(%a6) | ||
1452 | beqs no_aufl | ||
1453 | bsetb #aunfl_bit,FPSR_AEXCEPT(%a6) | ||
1454 | no_aufl: | ||
1455 | clrw NMNEXC(%a6) | ||
1456 | bclrb #E1,E_BYTE(%a6) | ||
1457 | fmovel #0,%FPSR |clear any cc bits from res_func | ||
1458 | | | ||
1459 | | Return ETEMP to extended format from internal extended format so | ||
1460 | | that gen_except will have a correctly signed value for ovfl/unfl | ||
1461 | | handlers. | ||
1462 | | | ||
1463 | bfclr ETEMP_SGN(%a6){#0:#8} | ||
1464 | beqs mvout_con | ||
1465 | bsetb #sign_bit,ETEMP_EX(%a6) | ||
1466 | mvout_con: | ||
1467 | rts | ||
1468 | | | ||
1469 | | This exit is for move-out to int register. The aunfl bit is | ||
1470 | | not set in any case for this move. | ||
1471 | | | ||
1472 | mvouti_end: | ||
1473 | clrw NMNEXC(%a6) | ||
1474 | bclrb #E1,E_BYTE(%a6) | ||
1475 | fmovel #0,%FPSR |clear any cc bits from res_func | ||
1476 | | | ||
1477 | | Return ETEMP to extended format from internal extended format so | ||
1478 | | that gen_except will have a correctly signed value for ovfl/unfl | ||
1479 | | handlers. | ||
1480 | | | ||
1481 | bfclr ETEMP_SGN(%a6){#0:#8} | ||
1482 | beqs mvouti_con | ||
1483 | bsetb #sign_bit,ETEMP_EX(%a6) | ||
1484 | mvouti_con: | ||
1485 | rts | ||
1486 | | | ||
1487 | | li is used to handle a long integer source specifier | ||
1488 | | | ||
1489 | |||
1490 | li: | ||
1491 | moveql #4,%d0 |set byte count | ||
1492 | |||
1493 | btstb #7,STAG(%a6) |check for extended denorm | ||
1494 | bne int_dnrm |if so, branch | ||
1495 | |||
1496 | fmovemx ETEMP(%a6),%fp0-%fp0 | ||
1497 | fcmpd #0x41dfffffffc00000,%fp0 | ||
1498 | | 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec | ||
1499 | fbge lo_plrg | ||
1500 | fcmpd #0xc1e0000000000000,%fp0 | ||
1501 | | c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec | ||
1502 | fble lo_nlrg | ||
1503 | | | ||
1504 | | at this point, the answer is between the largest pos and neg values | ||
1505 | | | ||
1506 | movel USER_FPCR(%a6),%d1 |use user's rounding mode | ||
1507 | andil #0x30,%d1 | ||
1508 | fmovel %d1,%fpcr | ||
1509 | fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion | ||
1510 | fmovel %fpsr,%d1 | ||
1511 | orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set | ||
1512 | bra int_wrt | ||
1513 | |||
1514 | |||
1515 | lo_plrg: | ||
1516 | movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive int | ||
1517 | fbeq int_wrt |exact answer | ||
1518 | fcmpd #0x41dfffffffe00000,%fp0 | ||
1519 | | 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec | ||
1520 | fbge int_operr |set operr | ||
1521 | bra int_inx |set inexact | ||
1522 | |||
1523 | lo_nlrg: | ||
1524 | movel #0x80000000,L_SCR1(%a6) | ||
1525 | fbeq int_wrt |exact answer | ||
1526 | fcmpd #0xc1e0000000100000,%fp0 | ||
1527 | | c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec | ||
1528 | fblt int_operr |set operr | ||
1529 | bra int_inx |set inexact | ||
1530 | |||
1531 | | | ||
1532 | | wi is used to handle a word integer source specifier | ||
1533 | | | ||
1534 | |||
1535 | wi: | ||
1536 | moveql #2,%d0 |set byte count | ||
1537 | |||
1538 | btstb #7,STAG(%a6) |check for extended denorm | ||
1539 | bne int_dnrm |branch if so | ||
1540 | |||
1541 | fmovemx ETEMP(%a6),%fp0-%fp0 | ||
1542 | fcmps #0x46fffe00,%fp0 | ||
1543 | | 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec | ||
1544 | fbge wo_plrg | ||
1545 | fcmps #0xc7000000,%fp0 | ||
1546 | | c7000000 in sgl prec = c00e00008000000000000000 in ext prec | ||
1547 | fble wo_nlrg | ||
1548 | |||
1549 | | | ||
1550 | | at this point, the answer is between the largest pos and neg values | ||
1551 | | | ||
1552 | movel USER_FPCR(%a6),%d1 |use user's rounding mode | ||
1553 | andil #0x30,%d1 | ||
1554 | fmovel %d1,%fpcr | ||
1555 | fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion | ||
1556 | fmovel %fpsr,%d1 | ||
1557 | orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set | ||
1558 | bra int_wrt | ||
1559 | |||
1560 | wo_plrg: | ||
1561 | movew #0x7fff,L_SCR1(%a6) |answer is largest positive int | ||
1562 | fbeq int_wrt |exact answer | ||
1563 | fcmps #0x46ffff00,%fp0 | ||
1564 | | 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec | ||
1565 | fbge int_operr |set operr | ||
1566 | bra int_inx |set inexact | ||
1567 | |||
1568 | wo_nlrg: | ||
1569 | movew #0x8000,L_SCR1(%a6) | ||
1570 | fbeq int_wrt |exact answer | ||
1571 | fcmps #0xc7000080,%fp0 | ||
1572 | | c7000080 in sgl prec = c00e00008000800000000000 in ext prec | ||
1573 | fblt int_operr |set operr | ||
1574 | bra int_inx |set inexact | ||
1575 | |||
1576 | | | ||
1577 | | bi is used to handle a byte integer source specifier | ||
1578 | | | ||
1579 | |||
1580 | bi: | ||
1581 | moveql #1,%d0 |set byte count | ||
1582 | |||
1583 | btstb #7,STAG(%a6) |check for extended denorm | ||
1584 | bne int_dnrm |branch if so | ||
1585 | |||
1586 | fmovemx ETEMP(%a6),%fp0-%fp0 | ||
1587 | fcmps #0x42fe0000,%fp0 | ||
1588 | | 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec | ||
1589 | fbge by_plrg | ||
1590 | fcmps #0xc3000000,%fp0 | ||
1591 | | c3000000 in sgl prec = c00600008000000000000000 in ext prec | ||
1592 | fble by_nlrg | ||
1593 | |||
1594 | | | ||
1595 | | at this point, the answer is between the largest pos and neg values | ||
1596 | | | ||
1597 | movel USER_FPCR(%a6),%d1 |use user's rounding mode | ||
1598 | andil #0x30,%d1 | ||
1599 | fmovel %d1,%fpcr | ||
1600 | fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion | ||
1601 | fmovel %fpsr,%d1 | ||
1602 | orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set | ||
1603 | bra int_wrt | ||
1604 | |||
1605 | by_plrg: | ||
1606 | moveb #0x7f,L_SCR1(%a6) |answer is largest positive int | ||
1607 | fbeq int_wrt |exact answer | ||
1608 | fcmps #0x42ff0000,%fp0 | ||
1609 | | 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec | ||
1610 | fbge int_operr |set operr | ||
1611 | bra int_inx |set inexact | ||
1612 | |||
1613 | by_nlrg: | ||
1614 | moveb #0x80,L_SCR1(%a6) | ||
1615 | fbeq int_wrt |exact answer | ||
1616 | fcmps #0xc3008000,%fp0 | ||
1617 | | c3008000 in sgl prec = c00600008080000000000000 in ext prec | ||
1618 | fblt int_operr |set operr | ||
1619 | bra int_inx |set inexact | ||
1620 | |||
1621 | | | ||
1622 | | Common integer routines | ||
1623 | | | ||
1624 | | int_drnrm---account for possible nonzero result for round up with positive | ||
1625 | | operand and round down for negative answer. In the first case (result = 1) | ||
1626 | | byte-width (store in d0) of result must be honored. In the second case, | ||
1627 | | -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out). | ||
1628 | |||
1629 | int_dnrm: | ||
1630 | movel #0,L_SCR1(%a6) | initialize result to 0 | ||
1631 | bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode | ||
1632 | cmpb #2,%d1 | ||
1633 | bmis int_inx | if RN or RZ, done | ||
1634 | bnes int_rp | if RP, continue below | ||
1635 | tstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negative | ||
1636 | bpls int_inx | otherwise result is 0 | ||
1637 | movel #-1,L_SCR1(%a6) | ||
1638 | bras int_inx | ||
1639 | int_rp: | ||
1640 | tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if | ||
1641 | | ; source is greater than 0 | ||
1642 | bmis int_inx | otherwise, result is 0 | ||
1643 | lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1 | ||
1644 | addal %d0,%a1 | offset by destination width -1 | ||
1645 | subal #1,%a1 | ||
1646 | bsetb #0,(%a1) | set low bit at a1 address | ||
1647 | int_inx: | ||
1648 | oril #inx2a_mask,USER_FPSR(%a6) | ||
1649 | bras int_wrt | ||
1650 | int_operr: | ||
1651 | fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended | ||
1652 | | ;precision source that needs to be | ||
1653 | | ;converted to integer this is required | ||
1654 | | ;if the operr exception is enabled. | ||
1655 | | ;set operr/aiop (no inex2 on int ovfl) | ||
1656 | |||
1657 | oril #opaop_mask,USER_FPSR(%a6) | ||
1658 | | ;fall through to perform int_wrt | ||
1659 | int_wrt: | ||
1660 | movel EXC_EA(%a6),%a1 |load destination address | ||
1661 | tstl %a1 |check to see if it is a dest register | ||
1662 | beqs wrt_dn |write data register | ||
1663 | lea L_SCR1(%a6),%a0 |point to supervisor source address | ||
1664 | bsrl mem_write | ||
1665 | bra mvouti_end | ||
1666 | |||
1667 | wrt_dn: | ||
1668 | movel %d0,-(%sp) |d0 currently contains the size to write | ||
1669 | bsrl get_fline |get_fline returns Dn in d0 | ||
1670 | andiw #0x7,%d0 |isolate register | ||
1671 | movel (%sp)+,%d1 |get size | ||
1672 | cmpil #4,%d1 |most frequent case | ||
1673 | beqs sz_long | ||
1674 | cmpil #2,%d1 | ||
1675 | bnes sz_con | ||
1676 | orl #8,%d0 |add 'word' size to register# | ||
1677 | bras sz_con | ||
1678 | sz_long: | ||
1679 | orl #0x10,%d0 |add 'long' size to register# | ||
1680 | sz_con: | ||
1681 | movel %d0,%d1 |reg_dest expects size:reg in d1 | ||
1682 | bsrl reg_dest |load proper data register | ||
1683 | bra mvouti_end | ||
1684 | xp: | ||
1685 | lea ETEMP(%a6),%a0 | ||
1686 | bclrb #sign_bit,LOCAL_EX(%a0) | ||
1687 | sne LOCAL_SGN(%a0) | ||
1688 | btstb #7,STAG(%a6) |check for extended denorm | ||
1689 | bne xdnrm | ||
1690 | clrl %d0 | ||
1691 | bras do_fp |do normal case | ||
1692 | sgp: | ||
1693 | lea ETEMP(%a6),%a0 | ||
1694 | bclrb #sign_bit,LOCAL_EX(%a0) | ||
1695 | sne LOCAL_SGN(%a0) | ||
1696 | btstb #7,STAG(%a6) |check for extended denorm | ||
1697 | bne sp_catas |branch if so | ||
1698 | movew LOCAL_EX(%a0),%d0 | ||
1699 | lea sp_bnds,%a1 | ||
1700 | cmpw (%a1),%d0 | ||
1701 | blt sp_under | ||
1702 | cmpw 2(%a1),%d0 | ||
1703 | bgt sp_over | ||
1704 | movel #1,%d0 |set destination format to single | ||
1705 | bras do_fp |do normal case | ||
1706 | dp: | ||
1707 | lea ETEMP(%a6),%a0 | ||
1708 | bclrb #sign_bit,LOCAL_EX(%a0) | ||
1709 | sne LOCAL_SGN(%a0) | ||
1710 | |||
1711 | btstb #7,STAG(%a6) |check for extended denorm | ||
1712 | bne dp_catas |branch if so | ||
1713 | |||
1714 | movew LOCAL_EX(%a0),%d0 | ||
1715 | lea dp_bnds,%a1 | ||
1716 | |||
1717 | cmpw (%a1),%d0 | ||
1718 | blt dp_under | ||
1719 | cmpw 2(%a1),%d0 | ||
1720 | bgt dp_over | ||
1721 | |||
1722 | movel #2,%d0 |set destination format to double | ||
1723 | | ;fall through to do_fp | ||
1724 | | | ||
1725 | do_fp: | ||
1726 | bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1 | ||
1727 | swap %d0 |rnd prec in upper word | ||
1728 | addl %d0,%d1 |d1 has PREC/MODE info | ||
1729 | |||
1730 | clrl %d0 |clear g,r,s | ||
1731 | |||
1732 | bsrl round |round | ||
1733 | |||
1734 | movel %a0,%a1 | ||
1735 | movel EXC_EA(%a6),%a0 | ||
1736 | |||
1737 | bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format | ||
1738 | | ;at this point only the dest | ||
1739 | | ;formats sgl, dbl, ext are | ||
1740 | | ;possible | ||
1741 | cmpb #2,%d1 | ||
1742 | bgts ddbl |double=5, extended=2, single=1 | ||
1743 | bnes dsgl | ||
1744 | | ;fall through to dext | ||
1745 | dext: | ||
1746 | bsrl dest_ext | ||
1747 | bra mvout_end | ||
1748 | dsgl: | ||
1749 | bsrl dest_sgl | ||
1750 | bra mvout_end | ||
1751 | ddbl: | ||
1752 | bsrl dest_dbl | ||
1753 | bra mvout_end | ||
1754 | |||
1755 | | | ||
1756 | | Handle possible denorm or catastrophic underflow cases here | ||
1757 | | | ||
1758 | xdnrm: | ||
1759 | bsr set_xop |initialize WBTEMP | ||
1760 | bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15 | ||
1761 | |||
1762 | movel %a0,%a1 | ||
1763 | movel EXC_EA(%a6),%a0 |a0 has the destination pointer | ||
1764 | bsrl dest_ext |store to memory | ||
1765 | bsetb #unfl_bit,FPSR_EXCEPT(%a6) | ||
1766 | bra mvout_end | ||
1767 | |||
1768 | sp_under: | ||
1769 | bsetb #etemp15_bit,STAG(%a6) | ||
1770 | |||
1771 | cmpw 4(%a1),%d0 | ||
1772 | blts sp_catas |catastrophic underflow case | ||
1773 | |||
1774 | movel #1,%d0 |load in round precision | ||
1775 | movel #sgl_thresh,%d1 |load in single denorm threshold | ||
1776 | bsrl dpspdnrm |expects d1 to have the proper | ||
1777 | | ;denorm threshold | ||
1778 | bsrl dest_sgl |stores value to destination | ||
1779 | bsetb #unfl_bit,FPSR_EXCEPT(%a6) | ||
1780 | bra mvout_end |exit | ||
1781 | |||
1782 | dp_under: | ||
1783 | bsetb #etemp15_bit,STAG(%a6) | ||
1784 | |||
1785 | cmpw 4(%a1),%d0 | ||
1786 | blts dp_catas |catastrophic underflow case | ||
1787 | |||
1788 | movel #dbl_thresh,%d1 |load in double precision threshold | ||
1789 | movel #2,%d0 | ||
1790 | bsrl dpspdnrm |expects d1 to have proper | ||
1791 | | ;denorm threshold | ||
1792 | | ;expects d0 to have round precision | ||
1793 | bsrl dest_dbl |store value to destination | ||
1794 | bsetb #unfl_bit,FPSR_EXCEPT(%a6) | ||
1795 | bra mvout_end |exit | ||
1796 | |||
1797 | | | ||
1798 | | Handle catastrophic underflow cases here | ||
1799 | | | ||
1800 | sp_catas: | ||
1801 | | Temp fix for z bit set in unf_sub | ||
1802 | movel USER_FPSR(%a6),-(%a7) | ||
1803 | |||
1804 | movel #1,%d0 |set round precision to sgl | ||
1805 | |||
1806 | bsrl unf_sub |a0 points to result | ||
1807 | |||
1808 | movel (%a7)+,USER_FPSR(%a6) | ||
1809 | |||
1810 | movel #1,%d0 | ||
1811 | subw %d0,LOCAL_EX(%a0) |account for difference between | ||
1812 | | ;denorm/norm bias | ||
1813 | |||
1814 | movel %a0,%a1 |a1 has the operand input | ||
1815 | movel EXC_EA(%a6),%a0 |a0 has the destination pointer | ||
1816 | |||
1817 | bsrl dest_sgl |store the result | ||
1818 | oril #unfinx_mask,USER_FPSR(%a6) | ||
1819 | bra mvout_end | ||
1820 | |||
1821 | dp_catas: | ||
1822 | | Temp fix for z bit set in unf_sub | ||
1823 | movel USER_FPSR(%a6),-(%a7) | ||
1824 | |||
1825 | movel #2,%d0 |set round precision to dbl | ||
1826 | bsrl unf_sub |a0 points to result | ||
1827 | |||
1828 | movel (%a7)+,USER_FPSR(%a6) | ||
1829 | |||
1830 | movel #1,%d0 | ||
1831 | subw %d0,LOCAL_EX(%a0) |account for difference between | ||
1832 | | ;denorm/norm bias | ||
1833 | |||
1834 | movel %a0,%a1 |a1 has the operand input | ||
1835 | movel EXC_EA(%a6),%a0 |a0 has the destination pointer | ||
1836 | |||
1837 | bsrl dest_dbl |store the result | ||
1838 | oril #unfinx_mask,USER_FPSR(%a6) | ||
1839 | bra mvout_end | ||
1840 | |||
1841 | | | ||
1842 | | Handle catastrophic overflow cases here | ||
1843 | | | ||
1844 | sp_over: | ||
1845 | | Temp fix for z bit set in unf_sub | ||
1846 | movel USER_FPSR(%a6),-(%a7) | ||
1847 | |||
1848 | movel #1,%d0 | ||
1849 | leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result | ||
1850 | movel ETEMP_EX(%a6),(%a0) | ||
1851 | movel ETEMP_HI(%a6),4(%a0) | ||
1852 | movel ETEMP_LO(%a6),8(%a0) | ||
1853 | bsrl ovf_res | ||
1854 | |||
1855 | movel (%a7)+,USER_FPSR(%a6) | ||
1856 | |||
1857 | movel %a0,%a1 | ||
1858 | movel EXC_EA(%a6),%a0 | ||
1859 | bsrl dest_sgl | ||
1860 | orl #ovfinx_mask,USER_FPSR(%a6) | ||
1861 | bra mvout_end | ||
1862 | |||
1863 | dp_over: | ||
1864 | | Temp fix for z bit set in ovf_res | ||
1865 | movel USER_FPSR(%a6),-(%a7) | ||
1866 | |||
1867 | movel #2,%d0 | ||
1868 | leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result | ||
1869 | movel ETEMP_EX(%a6),(%a0) | ||
1870 | movel ETEMP_HI(%a6),4(%a0) | ||
1871 | movel ETEMP_LO(%a6),8(%a0) | ||
1872 | bsrl ovf_res | ||
1873 | |||
1874 | movel (%a7)+,USER_FPSR(%a6) | ||
1875 | |||
1876 | movel %a0,%a1 | ||
1877 | movel EXC_EA(%a6),%a0 | ||
1878 | bsrl dest_dbl | ||
1879 | orl #ovfinx_mask,USER_FPSR(%a6) | ||
1880 | bra mvout_end | ||
1881 | |||
1882 | | | ||
1883 | | DPSPDNRM | ||
1884 | | | ||
1885 | | This subroutine takes an extended normalized number and denormalizes | ||
1886 | | it to the given round precision. This subroutine also decrements | ||
1887 | | the input operand's exponent by 1 to account for the fact that | ||
1888 | | dest_sgl or dest_dbl expects a normalized number's bias. | ||
1889 | | | ||
1890 | | Input: a0 points to a normalized number in internal extended format | ||
1891 | | d0 is the round precision (=1 for sgl; =2 for dbl) | ||
1892 | | d1 is the single precision or double precision | ||
1893 | | denorm threshold | ||
1894 | | | ||
1895 | | Output: (In the format for dest_sgl or dest_dbl) | ||
1896 | | a0 points to the destination | ||
1897 | | a1 points to the operand | ||
1898 | | | ||
1899 | | Exceptions: Reports inexact 2 exception by setting USER_FPSR bits | ||
1900 | | | ||
1901 | dpspdnrm: | ||
1902 | movel %d0,-(%a7) |save round precision | ||
1903 | clrl %d0 |clear initial g,r,s | ||
1904 | bsrl dnrm_lp |careful with d0, it's needed by round | ||
1905 | |||
1906 | bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode | ||
1907 | swap %d1 | ||
1908 | movew 2(%a7),%d1 |set rounding precision | ||
1909 | swap %d1 |at this point d1 has PREC/MODE info | ||
1910 | bsrl round |round result, sets the inex bit in | ||
1911 | | ;USER_FPSR if needed | ||
1912 | |||
1913 | movew #1,%d0 | ||
1914 | subw %d0,LOCAL_EX(%a0) |account for difference in denorm | ||
1915 | | ;vs norm bias | ||
1916 | |||
1917 | movel %a0,%a1 |a1 has the operand input | ||
1918 | movel EXC_EA(%a6),%a0 |a0 has the destination pointer | ||
1919 | addw #4,%a7 |pop stack | ||
1920 | rts | ||
1921 | | | ||
1922 | | SET_XOP initialized WBTEMP with the value pointed to by a0 | ||
1923 | | input: a0 points to input operand in the internal extended format | ||
1924 | | | ||
1925 | set_xop: | ||
1926 | movel LOCAL_EX(%a0),WBTEMP_EX(%a6) | ||
1927 | movel LOCAL_HI(%a0),WBTEMP_HI(%a6) | ||
1928 | movel LOCAL_LO(%a0),WBTEMP_LO(%a6) | ||
1929 | bfclr WBTEMP_SGN(%a6){#0:#8} | ||
1930 | beqs sxop | ||
1931 | bsetb #sign_bit,WBTEMP_EX(%a6) | ||
1932 | sxop: | ||
1933 | bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit | ||
1934 | rts | ||
1935 | | | ||
1936 | | P_MOVE | ||
1937 | | | ||
1938 | p_movet: | ||
1939 | .long p_move | ||
1940 | .long p_movez | ||
1941 | .long p_movei | ||
1942 | .long p_moven | ||
1943 | .long p_move | ||
1944 | p_regd: | ||
1945 | .long p_dyd0 | ||
1946 | .long p_dyd1 | ||
1947 | .long p_dyd2 | ||
1948 | .long p_dyd3 | ||
1949 | .long p_dyd4 | ||
1950 | .long p_dyd5 | ||
1951 | .long p_dyd6 | ||
1952 | .long p_dyd7 | ||
1953 | |||
1954 | pack_out: | ||
1955 | leal p_movet,%a0 |load jmp table address | ||
1956 | movew STAG(%a6),%d0 |get source tag | ||
1957 | bfextu %d0{#16:#3},%d0 |isolate source bits | ||
1958 | movel (%a0,%d0.w*4),%a0 |load a0 with routine label for tag | ||
1959 | jmp (%a0) |go to the routine | ||
1960 | |||
1961 | p_write: | ||
1962 | movel #0x0c,%d0 |get byte count | ||
1963 | movel EXC_EA(%a6),%a1 |get the destination address | ||
1964 | bsr mem_write |write the user's destination | ||
1965 | moveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's | ||
1966 | |||
1967 | | | ||
1968 | | Also note that the dtag must be set to norm here - this is because | ||
1969 | | the 040 uses the dtag to execute the correct microcode. | ||
1970 | | | ||
1971 | bfclr DTAG(%a6){#0:#3} |set dtag to norm | ||
1972 | |||
1973 | rts | ||
1974 | |||
1975 | | Notes on handling of special case (zero, inf, and nan) inputs: | ||
1976 | | 1. Operr is not signalled if the k-factor is greater than 18. | ||
1977 | | 2. Per the manual, status bits are not set. | ||
1978 | | | ||
1979 | |||
1980 | p_move: | ||
1981 | movew CMDREG1B(%a6),%d0 | ||
1982 | btstl #kfact_bit,%d0 |test for dynamic k-factor | ||
1983 | beqs statick |if clear, k-factor is static | ||
1984 | dynamick: | ||
1985 | bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor | ||
1986 | lea p_regd,%a0 | ||
1987 | movel %a0@(%d0:l:4),%a0 | ||
1988 | jmp (%a0) | ||
1989 | statick: | ||
1990 | andiw #0x007f,%d0 |get k-factor | ||
1991 | bfexts %d0{#25:#7},%d0 |sign extend d0 for bindec | ||
1992 | leal ETEMP(%a6),%a0 |a0 will point to the packed decimal | ||
1993 | bsrl bindec |perform the convert; data at a6 | ||
1994 | leal FP_SCR1(%a6),%a0 |load a0 with result address | ||
1995 | bral p_write | ||
1996 | p_movez: | ||
1997 | leal ETEMP(%a6),%a0 |a0 will point to the packed decimal | ||
1998 | clrw 2(%a0) |clear lower word of exp | ||
1999 | clrl 4(%a0) |load second lword of ZERO | ||
2000 | clrl 8(%a0) |load third lword of ZERO | ||
2001 | bra p_write |go write results | ||
2002 | p_movei: | ||
2003 | fmovel #0,%FPSR |clear aiop | ||
2004 | leal ETEMP(%a6),%a0 |a0 will point to the packed decimal | ||
2005 | clrw 2(%a0) |clear lower word of exp | ||
2006 | bra p_write |go write the result | ||
2007 | p_moven: | ||
2008 | leal ETEMP(%a6),%a0 |a0 will point to the packed decimal | ||
2009 | clrw 2(%a0) |clear lower word of exp | ||
2010 | bra p_write |go write the result | ||
2011 | |||
2012 | | | ||
2013 | | Routines to read the dynamic k-factor from Dn. | ||
2014 | | | ||
2015 | p_dyd0: | ||
2016 | movel USER_D0(%a6),%d0 | ||
2017 | bras statick | ||
2018 | p_dyd1: | ||
2019 | movel USER_D1(%a6),%d0 | ||
2020 | bras statick | ||
2021 | p_dyd2: | ||
2022 | movel %d2,%d0 | ||
2023 | bras statick | ||
2024 | p_dyd3: | ||
2025 | movel %d3,%d0 | ||
2026 | bras statick | ||
2027 | p_dyd4: | ||
2028 | movel %d4,%d0 | ||
2029 | bras statick | ||
2030 | p_dyd5: | ||
2031 | movel %d5,%d0 | ||
2032 | bras statick | ||
2033 | p_dyd6: | ||
2034 | movel %d6,%d0 | ||
2035 | bra statick | ||
2036 | p_dyd7: | ||
2037 | movel %d7,%d0 | ||
2038 | bra statick | ||
2039 | |||
2040 | |end | ||