1 | #include "fpsp-namespace.h" |
---|
2 | // |
---|
3 | // |
---|
4 | // x_operr.sa 3.5 7/1/91 |
---|
5 | // |
---|
6 | // fpsp_operr --- FPSP handler for operand error exception |
---|
7 | // |
---|
8 | // See 68040 User's Manual pp. 9-44f |
---|
9 | // |
---|
10 | // Note 1: For trap disabled 040 does the following: |
---|
11 | // If the dest is a fp reg, then an extended precision non_signaling |
---|
12 | // NAN is stored in the dest reg. If the dest format is b, w, or l and |
---|
13 | // the source op is a NAN, then garbage is stored as the result (actually |
---|
14 | // the upper 32 bits of the mantissa are sent to the integer unit). If |
---|
15 | // the dest format is integer (b, w, l) and the operr is caused by |
---|
16 | // integer overflow, or the source op is inf, then the result stored is |
---|
17 | // garbage. |
---|
18 | // There are three cases in which operr is incorrectly signaled on the |
---|
19 | // 040. This occurs for move_out of format b, w, or l for the largest |
---|
20 | // negative integer (-2^7 for b, -2^15 for w, -2^31 for l). |
---|
21 | // |
---|
22 | // On opclass = 011 fmove.(b,w,l) that causes a conversion |
---|
23 | // overflow -> OPERR, the exponent in wbte (and fpte) is: |
---|
24 | // byte 56 - (62 - exp) |
---|
25 | // word 48 - (62 - exp) |
---|
26 | // long 32 - (62 - exp) |
---|
27 | // |
---|
28 | // where exp = (true exp) - 1 |
---|
29 | // |
---|
30 | // So, wbtemp and fptemp will contain the following on erroneously |
---|
31 | // signalled operr: |
---|
32 | // fpts = 1 |
---|
33 | // fpte = $4000 (15 bit externally) |
---|
34 | // byte fptm = $ffffffff ffffff80 |
---|
35 | // word fptm = $ffffffff ffff8000 |
---|
36 | // long fptm = $ffffffff 80000000 |
---|
37 | // |
---|
38 | // Note 2: For trap enabled 040 does the following: |
---|
39 | // If the inst is move_out, then same as Note 1. |
---|
40 | // If the inst is not move_out, the dest is not modified. |
---|
41 | // The exceptional operand is not defined for integer overflow |
---|
42 | // during a move_out. |
---|
43 | // |
---|
44 | |
---|
45 | // Copyright (C) Motorola, Inc. 1990 |
---|
46 | // All Rights Reserved |
---|
47 | // |
---|
48 | // THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA |
---|
49 | // The copyright notice above does not evidence any |
---|
50 | // actual or intended publication of such source code. |
---|
51 | |
---|
52 | X_OPERR: //idnt 2,1 | Motorola 040 Floating Point Software Package |
---|
53 | |
---|
54 | |section 8 |
---|
55 | |
---|
56 | #include "fpsp.defs" |
---|
57 | |
---|
58 | |xref mem_write |
---|
59 | |xref real_operr |
---|
60 | |xref real_inex |
---|
61 | |xref get_fline |
---|
62 | |xref fpsp_done |
---|
63 | |xref reg_dest |
---|
64 | |
---|
65 | .global fpsp_operr |
---|
66 | fpsp_operr: |
---|
67 | // |
---|
68 | link %a6,#-LOCAL_SIZE |
---|
69 | fsave -(%a7) |
---|
70 | moveml %d0-%d1/%a0-%a1,USER_DA(%a6) |
---|
71 | fmovemx %fp0-%fp3,USER_FP0(%a6) |
---|
72 | fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) |
---|
73 | |
---|
74 | // |
---|
75 | // Check if this is an opclass 3 instruction. |
---|
76 | // If so, fall through, else branch to operr_end |
---|
77 | // |
---|
78 | btstb #TFLAG,T_BYTE(%a6) |
---|
79 | beqs operr_end |
---|
80 | |
---|
81 | // |
---|
82 | // If the destination size is B,W,or L, the operr must be |
---|
83 | // handled here. |
---|
84 | // |
---|
85 | movel CMDREG1B(%a6),%d0 |
---|
86 | bfextu %d0{#3:#3},%d0 //0=long, 4=word, 6=byte |
---|
87 | cmpib #0,%d0 //determine size; check long |
---|
88 | beq operr_long |
---|
89 | cmpib #4,%d0 //check word |
---|
90 | beq operr_word |
---|
91 | cmpib #6,%d0 //check byte |
---|
92 | beq operr_byte |
---|
93 | |
---|
94 | // |
---|
95 | // The size is not B,W,or L, so the operr is handled by the |
---|
96 | // kernel handler. Set the operr bits and clean up, leaving |
---|
97 | // only the integer exception frame on the stack, and the |
---|
98 | // fpu in the original exceptional state. |
---|
99 | // |
---|
100 | operr_end: |
---|
101 | bsetb #operr_bit,FPSR_EXCEPT(%a6) |
---|
102 | bsetb #aiop_bit,FPSR_AEXCEPT(%a6) |
---|
103 | |
---|
104 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
---|
105 | fmovemx USER_FP0(%a6),%fp0-%fp3 |
---|
106 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
---|
107 | frestore (%a7)+ |
---|
108 | unlk %a6 |
---|
109 | bral real_operr |
---|
110 | |
---|
111 | operr_long: |
---|
112 | moveql #4,%d1 //write size to d1 |
---|
113 | moveb STAG(%a6),%d0 //test stag for nan |
---|
114 | andib #0xe0,%d0 //clr all but tag |
---|
115 | cmpib #0x60,%d0 //check for nan |
---|
116 | beq operr_nan |
---|
117 | cmpil #0x80000000,FPTEMP_LO(%a6) //test if ls lword is special |
---|
118 | bnes chklerr //if not equal, check for incorrect operr |
---|
119 | bsr check_upper //check if exp and ms mant are special |
---|
120 | tstl %d0 |
---|
121 | bnes chklerr //if d0 is true, check for incorrect operr |
---|
122 | movel #0x80000000,%d0 //store special case result |
---|
123 | bsr operr_store |
---|
124 | bra not_enabled //clean and exit |
---|
125 | // |
---|
126 | // CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE |
---|
127 | // |
---|
128 | chklerr: |
---|
129 | movew FPTEMP_EX(%a6),%d0 |
---|
130 | andw #0x7FFF,%d0 //ignore sign bit |
---|
131 | cmpw #0x3FFE,%d0 //this is the only possible exponent value |
---|
132 | bnes chklerr2 |
---|
133 | fixlong: |
---|
134 | movel FPTEMP_LO(%a6),%d0 |
---|
135 | bsr operr_store |
---|
136 | bra not_enabled |
---|
137 | chklerr2: |
---|
138 | movew FPTEMP_EX(%a6),%d0 |
---|
139 | andw #0x7FFF,%d0 //ignore sign bit |
---|
140 | cmpw #0x4000,%d0 |
---|
141 | bcc store_max //exponent out of range |
---|
142 | |
---|
143 | movel FPTEMP_LO(%a6),%d0 |
---|
144 | andl #0x7FFF0000,%d0 //look for all 1's on bits 30-16 |
---|
145 | cmpl #0x7FFF0000,%d0 |
---|
146 | beqs fixlong |
---|
147 | |
---|
148 | tstl FPTEMP_LO(%a6) |
---|
149 | bpls chklepos |
---|
150 | cmpl #0xFFFFFFFF,FPTEMP_HI(%a6) |
---|
151 | beqs fixlong |
---|
152 | bra store_max |
---|
153 | chklepos: |
---|
154 | tstl FPTEMP_HI(%a6) |
---|
155 | beqs fixlong |
---|
156 | bra store_max |
---|
157 | |
---|
158 | operr_word: |
---|
159 | moveql #2,%d1 //write size to d1 |
---|
160 | moveb STAG(%a6),%d0 //test stag for nan |
---|
161 | andib #0xe0,%d0 //clr all but tag |
---|
162 | cmpib #0x60,%d0 //check for nan |
---|
163 | beq operr_nan |
---|
164 | cmpil #0xffff8000,FPTEMP_LO(%a6) //test if ls lword is special |
---|
165 | bnes chkwerr //if not equal, check for incorrect operr |
---|
166 | bsr check_upper //check if exp and ms mant are special |
---|
167 | tstl %d0 |
---|
168 | bnes chkwerr //if d0 is true, check for incorrect operr |
---|
169 | movel #0x80000000,%d0 //store special case result |
---|
170 | bsr operr_store |
---|
171 | bra not_enabled //clean and exit |
---|
172 | // |
---|
173 | // CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE |
---|
174 | // |
---|
175 | chkwerr: |
---|
176 | movew FPTEMP_EX(%a6),%d0 |
---|
177 | andw #0x7FFF,%d0 //ignore sign bit |
---|
178 | cmpw #0x3FFE,%d0 //this is the only possible exponent value |
---|
179 | bnes store_max |
---|
180 | movel FPTEMP_LO(%a6),%d0 |
---|
181 | swap %d0 |
---|
182 | bsr operr_store |
---|
183 | bra not_enabled |
---|
184 | |
---|
185 | operr_byte: |
---|
186 | moveql #1,%d1 //write size to d1 |
---|
187 | moveb STAG(%a6),%d0 //test stag for nan |
---|
188 | andib #0xe0,%d0 //clr all but tag |
---|
189 | cmpib #0x60,%d0 //check for nan |
---|
190 | beqs operr_nan |
---|
191 | cmpil #0xffffff80,FPTEMP_LO(%a6) //test if ls lword is special |
---|
192 | bnes chkberr //if not equal, check for incorrect operr |
---|
193 | bsr check_upper //check if exp and ms mant are special |
---|
194 | tstl %d0 |
---|
195 | bnes chkberr //if d0 is true, check for incorrect operr |
---|
196 | movel #0x80000000,%d0 //store special case result |
---|
197 | bsr operr_store |
---|
198 | bra not_enabled //clean and exit |
---|
199 | // |
---|
200 | // CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE |
---|
201 | // |
---|
202 | chkberr: |
---|
203 | movew FPTEMP_EX(%a6),%d0 |
---|
204 | andw #0x7FFF,%d0 //ignore sign bit |
---|
205 | cmpw #0x3FFE,%d0 //this is the only possible exponent value |
---|
206 | bnes store_max |
---|
207 | movel FPTEMP_LO(%a6),%d0 |
---|
208 | asll #8,%d0 |
---|
209 | swap %d0 |
---|
210 | bsr operr_store |
---|
211 | bra not_enabled |
---|
212 | |
---|
213 | // |
---|
214 | // This operr condition is not of the special case. Set operr |
---|
215 | // and aiop and write the portion of the nan to memory for the |
---|
216 | // given size. |
---|
217 | // |
---|
218 | operr_nan: |
---|
219 | orl #opaop_mask,USER_FPSR(%a6) //set operr & aiop |
---|
220 | |
---|
221 | movel ETEMP_HI(%a6),%d0 //output will be from upper 32 bits |
---|
222 | bsr operr_store |
---|
223 | bra end_operr |
---|
224 | // |
---|
225 | // Store_max loads the max pos or negative for the size, sets |
---|
226 | // the operr and aiop bits, and clears inex and ainex, incorrectly |
---|
227 | // set by the 040. |
---|
228 | // |
---|
229 | store_max: |
---|
230 | orl #opaop_mask,USER_FPSR(%a6) //set operr & aiop |
---|
231 | bclrb #inex2_bit,FPSR_EXCEPT(%a6) |
---|
232 | bclrb #ainex_bit,FPSR_AEXCEPT(%a6) |
---|
233 | fmovel #0,%FPSR |
---|
234 | |
---|
235 | tstw FPTEMP_EX(%a6) //check sign |
---|
236 | blts load_neg |
---|
237 | movel #0x7fffffff,%d0 |
---|
238 | bsr operr_store |
---|
239 | bra end_operr |
---|
240 | load_neg: |
---|
241 | movel #0x80000000,%d0 |
---|
242 | bsr operr_store |
---|
243 | bra end_operr |
---|
244 | |
---|
245 | // |
---|
246 | // This routine stores the data in d0, for the given size in d1, |
---|
247 | // to memory or data register as required. A read of the fline |
---|
248 | // is required to determine the destination. |
---|
249 | // |
---|
250 | operr_store: |
---|
251 | movel %d0,L_SCR1(%a6) //move write data to L_SCR1 |
---|
252 | movel %d1,-(%a7) //save register size |
---|
253 | bsrl get_fline //fline returned in d0 |
---|
254 | movel (%a7)+,%d1 |
---|
255 | bftst %d0{#26:#3} //if mode is zero, dest is Dn |
---|
256 | bnes dest_mem |
---|
257 | // |
---|
258 | // Destination is Dn. Get register number from d0. Data is on |
---|
259 | // the stack at (a7). D1 has size: 1=byte,2=word,4=long/single |
---|
260 | // |
---|
261 | andil #7,%d0 //isolate register number |
---|
262 | cmpil #4,%d1 |
---|
263 | beqs op_long //the most frequent case |
---|
264 | cmpil #2,%d1 |
---|
265 | bnes op_con |
---|
266 | orl #8,%d0 |
---|
267 | bras op_con |
---|
268 | op_long: |
---|
269 | orl #0x10,%d0 |
---|
270 | op_con: |
---|
271 | movel %d0,%d1 //format size:reg for reg_dest |
---|
272 | bral reg_dest //call to reg_dest returns to caller |
---|
273 | // ;of operr_store |
---|
274 | // |
---|
275 | // Destination is memory. Get <ea> from integer exception frame |
---|
276 | // and call mem_write. |
---|
277 | // |
---|
278 | dest_mem: |
---|
279 | leal L_SCR1(%a6),%a0 //put ptr to write data in a0 |
---|
280 | movel EXC_EA(%a6),%a1 //put user destination address in a1 |
---|
281 | movel %d1,%d0 //put size in d0 |
---|
282 | bsrl mem_write |
---|
283 | rts |
---|
284 | // |
---|
285 | // Check the exponent for $c000 and the upper 32 bits of the |
---|
286 | // mantissa for $ffffffff. If both are true, return d0 clr |
---|
287 | // and store the lower n bits of the least lword of FPTEMP |
---|
288 | // to d0 for write out. If not, it is a real operr, and set d0. |
---|
289 | // |
---|
290 | check_upper: |
---|
291 | cmpil #0xffffffff,FPTEMP_HI(%a6) //check if first byte is all 1's |
---|
292 | bnes true_operr //if not all 1's then was true operr |
---|
293 | cmpiw #0xc000,FPTEMP_EX(%a6) //check if incorrectly signalled |
---|
294 | beqs not_true_operr //branch if not true operr |
---|
295 | cmpiw #0xbfff,FPTEMP_EX(%a6) //check if incorrectly signalled |
---|
296 | beqs not_true_operr //branch if not true operr |
---|
297 | true_operr: |
---|
298 | movel #1,%d0 //signal real operr |
---|
299 | rts |
---|
300 | not_true_operr: |
---|
301 | clrl %d0 //signal no real operr |
---|
302 | rts |
---|
303 | |
---|
304 | // |
---|
305 | // End_operr tests for operr enabled. If not, it cleans up the stack |
---|
306 | // and does an rte. If enabled, it cleans up the stack and branches |
---|
307 | // to the kernel operr handler with only the integer exception |
---|
308 | // frame on the stack and the fpu in the original exceptional state |
---|
309 | // with correct data written to the destination. |
---|
310 | // |
---|
311 | end_operr: |
---|
312 | btstb #operr_bit,FPCR_ENABLE(%a6) |
---|
313 | beqs not_enabled |
---|
314 | enabled: |
---|
315 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
---|
316 | fmovemx USER_FP0(%a6),%fp0-%fp3 |
---|
317 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
---|
318 | frestore (%a7)+ |
---|
319 | unlk %a6 |
---|
320 | bral real_operr |
---|
321 | |
---|
322 | not_enabled: |
---|
323 | // |
---|
324 | // It is possible to have either inex2 or inex1 exceptions with the |
---|
325 | // operr. If the inex enable bit is set in the FPCR, and either |
---|
326 | // inex2 or inex1 occurred, we must clean up and branch to the |
---|
327 | // real inex handler. |
---|
328 | // |
---|
329 | ck_inex: |
---|
330 | moveb FPCR_ENABLE(%a6),%d0 |
---|
331 | andb FPSR_EXCEPT(%a6),%d0 |
---|
332 | andib #0x3,%d0 |
---|
333 | beq operr_exit |
---|
334 | // |
---|
335 | // Inexact enabled and reported, and we must take an inexact exception. |
---|
336 | // |
---|
337 | take_inex: |
---|
338 | moveb #INEX_VEC,EXC_VEC+1(%a6) |
---|
339 | movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |
---|
340 | orl #sx_mask,E_BYTE(%a6) |
---|
341 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
---|
342 | fmovemx USER_FP0(%a6),%fp0-%fp3 |
---|
343 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
---|
344 | frestore (%a7)+ |
---|
345 | unlk %a6 |
---|
346 | bral real_inex |
---|
347 | // |
---|
348 | // Since operr is only an E1 exception, there is no need to frestore |
---|
349 | // any state back to the fpu. |
---|
350 | // |
---|
351 | operr_exit: |
---|
352 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 |
---|
353 | fmovemx USER_FP0(%a6),%fp0-%fp3 |
---|
354 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar |
---|
355 | unlk %a6 |
---|
356 | bral fpsp_done |
---|
357 | |
---|
358 | |end |
---|