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