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