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