Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | | |
2 | | gen_except.sa 3.7 1/16/92 | |
3 | | | |
4 | | gen_except --- FPSP routine to detect reportable exceptions | |
5 | | | |
6 | | This routine compares the exception enable byte of the | |
7 | | user_fpcr on the stack with the exception status byte | |
8 | | of the user_fpsr. | |
9 | | | |
10 | | Any routine which may report an exceptions must load | |
11 | | the stack frame in memory with the exceptional operand(s). | |
12 | | | |
13 | | Priority for exceptions is: | |
14 | | | |
15 | | Highest: bsun | |
16 | | snan | |
17 | | operr | |
18 | | ovfl | |
19 | | unfl | |
20 | | dz | |
21 | | inex2 | |
22 | | Lowest: inex1 | |
23 | | | |
24 | | Note: The IEEE standard specifies that inex2 is to be | |
25 | | reported if ovfl occurs and the ovfl enable bit is not | |
26 | | set but the inex2 enable bit is. | |
27 | | | |
28 | | | |
29 | | Copyright (C) Motorola, Inc. 1990 | |
30 | | All Rights Reserved | |
31 | | | |
e00d82d0 MW |
32 | | For details on the license for this file, please see the |
33 | | file, README, in this same directory. | |
1da177e4 LT |
34 | |
35 | GEN_EXCEPT: |idnt 2,1 | Motorola 040 Floating Point Software Package | |
36 | ||
37 | |section 8 | |
38 | ||
39 | #include "fpsp.h" | |
40 | ||
41 | |xref real_trace | |
42 | |xref fpsp_done | |
43 | |xref fpsp_fmt_error | |
44 | ||
45 | exc_tbl: | |
46 | .long bsun_exc | |
47 | .long commonE1 | |
48 | .long commonE1 | |
49 | .long ovfl_unfl | |
50 | .long ovfl_unfl | |
51 | .long commonE1 | |
52 | .long commonE3 | |
53 | .long commonE3 | |
54 | .long no_match | |
55 | ||
56 | .global gen_except | |
57 | gen_except: | |
58 | cmpib #IDLE_SIZE-4,1(%a7) |test for idle frame | |
59 | beq do_check |go handle idle frame | |
60 | cmpib #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame | |
61 | beqs unimp_x |go handle unimp frame | |
62 | cmpib #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame | |
63 | beqs unimp_x |go handle unimp frame | |
64 | cmpib #BUSY_SIZE-4,1(%a7) |if size <> $60, fmt error | |
65 | bnel fpsp_fmt_error | |
66 | leal BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 so fpsp.h | |
67 | | ;equates will work | |
68 | | Fix up the new busy frame with entries from the unimp frame | |
69 | | | |
70 | movel ETEMP_EX(%a6),ETEMP_EX(%a1) |copy etemp from unimp | |
71 | movel ETEMP_HI(%a6),ETEMP_HI(%a1) |frame to busy frame | |
72 | movel ETEMP_LO(%a6),ETEMP_LO(%a1) | |
73 | movel CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp | |
74 | movel CMDREG1B(%a6),%d0 |fix cmd1b to make it | |
75 | andl #0x03c30000,%d0 |work for cmd3b | |
76 | bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2 | |
77 | lsll #5,%d1 | |
78 | swap %d1 | |
79 | orl %d1,%d0 |put it in the right place | |
80 | bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5 | |
81 | lsll #2,%d1 | |
82 | swap %d1 | |
83 | orl %d1,%d0 |put them in the right place | |
84 | movel %d0,CMDREG3B(%a1) |in the busy frame | |
85 | | | |
86 | | Or in the FPSR from the emulation with the USER_FPSR on the stack. | |
87 | | | |
88 | fmovel %FPSR,%d0 | |
89 | orl %d0,USER_FPSR(%a6) | |
90 | movel USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits | |
91 | orl #sx_mask,E_BYTE(%a1) | |
92 | bra do_clean | |
93 | ||
94 | | | |
95 | | Frame is an unimp frame possible resulting from an fmove <ea>,fp0 | |
96 | | that caused an exception | |
97 | | | |
98 | | a1 is modified to point into the new frame allowing fpsp equates | |
99 | | to be valid. | |
100 | | | |
101 | unimp_x: | |
102 | cmpib #UNIMP_40_SIZE-4,1(%a7) |test for orig unimp frame | |
103 | bnes test_rev | |
104 | leal UNIMP_40_SIZE+LOCAL_SIZE(%a7),%a1 | |
105 | bras unimp_con | |
106 | test_rev: | |
107 | cmpib #UNIMP_41_SIZE-4,1(%a7) |test for rev unimp frame | |
108 | bnel fpsp_fmt_error |if not $28 or $30 | |
109 | leal UNIMP_41_SIZE+LOCAL_SIZE(%a7),%a1 | |
110 | ||
111 | unimp_con: | |
112 | | | |
113 | | Fix up the new unimp frame with entries from the old unimp frame | |
114 | | | |
115 | movel CMDREG1B(%a6),CMDREG1B(%a1) |set inst in frame to unimp | |
116 | | | |
117 | | Or in the FPSR from the emulation with the USER_FPSR on the stack. | |
118 | | | |
119 | fmovel %FPSR,%d0 | |
120 | orl %d0,USER_FPSR(%a6) | |
121 | bra do_clean | |
122 | ||
123 | | | |
124 | | Frame is idle, so check for exceptions reported through | |
125 | | USER_FPSR and set the unimp frame accordingly. | |
126 | | A7 must be incremented to the point before the | |
127 | | idle fsave vector to the unimp vector. | |
128 | | | |
129 | ||
130 | do_check: | |
131 | addl #4,%a7 |point A7 back to unimp frame | |
132 | | | |
133 | | Or in the FPSR from the emulation with the USER_FPSR on the stack. | |
134 | | | |
135 | fmovel %FPSR,%d0 | |
136 | orl %d0,USER_FPSR(%a6) | |
137 | | | |
138 | | On a busy frame, we must clear the nmnexc bits. | |
139 | | | |
140 | cmpib #BUSY_SIZE-4,1(%a7) |check frame type | |
141 | bnes check_fr |if busy, clr nmnexc | |
142 | clrw NMNEXC(%a6) |clr nmnexc & nmcexc | |
143 | btstb #5,CMDREG1B(%a6) |test for fmove out | |
144 | bnes frame_com | |
145 | movel USER_FPSR(%a6),FPSR_SHADOW(%a6) |set exc bits | |
146 | orl #sx_mask,E_BYTE(%a6) | |
147 | bras frame_com | |
148 | check_fr: | |
149 | cmpb #UNIMP_40_SIZE-4,1(%a7) | |
150 | beqs frame_com | |
151 | clrw NMNEXC(%a6) | |
152 | frame_com: | |
153 | moveb FPCR_ENABLE(%a6),%d0 |get fpcr enable byte | |
154 | andb FPSR_EXCEPT(%a6),%d0 |and in the fpsr exc byte | |
155 | bfffo %d0{#24:#8},%d1 |test for first set bit | |
156 | leal exc_tbl,%a0 |load jmp table address | |
157 | subib #24,%d1 |normalize bit offset to 0-8 | |
158 | movel (%a0,%d1.w*4),%a0 |load routine address based | |
159 | | ;based on first enabled exc | |
160 | jmp (%a0) |jump to routine | |
161 | | | |
162 | | Bsun is not possible in unimp or unsupp | |
163 | | | |
164 | bsun_exc: | |
165 | bra do_clean | |
166 | | | |
167 | | The typical work to be done to the unimp frame to report an | |
168 | | exception is to set the E1/E3 byte and clr the U flag. | |
169 | | commonE1 does this for E1 exceptions, which are snan, | |
170 | | operr, and dz. commonE3 does this for E3 exceptions, which | |
171 | | are inex2 and inex1, and also clears the E1 exception bit | |
172 | | left over from the unimp exception. | |
173 | | | |
174 | commonE1: | |
175 | bsetb #E1,E_BYTE(%a6) |set E1 flag | |
176 | bra commonE |go clean and exit | |
177 | ||
178 | commonE3: | |
179 | tstb UFLG_TMP(%a6) |test flag for unsup/unimp state | |
180 | bnes unsE3 | |
181 | uniE3: | |
182 | bsetb #E3,E_BYTE(%a6) |set E3 flag | |
183 | bclrb #E1,E_BYTE(%a6) |clr E1 from unimp | |
184 | bra commonE | |
185 | ||
186 | unsE3: | |
187 | tstb RES_FLG(%a6) | |
188 | bnes unsE3_0 | |
189 | unsE3_1: | |
190 | bsetb #E3,E_BYTE(%a6) |set E3 flag | |
191 | unsE3_0: | |
192 | bclrb #E1,E_BYTE(%a6) |clr E1 flag | |
193 | movel CMDREG1B(%a6),%d0 | |
194 | andl #0x03c30000,%d0 |work for cmd3b | |
195 | bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2 | |
196 | lsll #5,%d1 | |
197 | swap %d1 | |
198 | orl %d1,%d0 |put it in the right place | |
199 | bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5 | |
200 | lsll #2,%d1 | |
201 | swap %d1 | |
202 | orl %d1,%d0 |put them in the right place | |
203 | movel %d0,CMDREG3B(%a6) |in the busy frame | |
204 | ||
205 | commonE: | |
206 | bclrb #UFLAG,T_BYTE(%a6) |clr U flag from unimp | |
207 | bra do_clean |go clean and exit | |
208 | | | |
209 | | No bits in the enable byte match existing exceptions. Check for | |
210 | | the case of the ovfl exc without the ovfl enabled, but with | |
211 | | inex2 enabled. | |
212 | | | |
213 | no_match: | |
214 | btstb #inex2_bit,FPCR_ENABLE(%a6) |check for ovfl/inex2 case | |
215 | beqs no_exc |if clear, exit | |
216 | btstb #ovfl_bit,FPSR_EXCEPT(%a6) |now check ovfl | |
217 | beqs no_exc |if clear, exit | |
218 | bras ovfl_unfl |go to unfl_ovfl to determine if | |
219 | | ;it is an unsupp or unimp exc | |
220 | ||
221 | | No exceptions are to be reported. If the instruction was | |
222 | | unimplemented, no FPU restore is necessary. If it was | |
223 | | unsupported, we must perform the restore. | |
224 | no_exc: | |
225 | tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state | |
226 | beqs uni_no_exc | |
227 | uns_no_exc: | |
228 | tstb RES_FLG(%a6) |check if frestore is needed | |
229 | bne do_clean |if clear, no frestore needed | |
230 | uni_no_exc: | |
231 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 | |
232 | fmovemx USER_FP0(%a6),%fp0-%fp3 | |
233 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar | |
234 | unlk %a6 | |
235 | bra finish_up | |
236 | | | |
237 | | Unsupported Data Type Handler: | |
238 | | Ovfl: | |
239 | | An fmoveout that results in an overflow is reported this way. | |
240 | | Unfl: | |
241 | | An fmoveout that results in an underflow is reported this way. | |
242 | | | |
243 | | Unimplemented Instruction Handler: | |
244 | | Ovfl: | |
245 | | Only scosh, setox, ssinh, stwotox, and scale can set overflow in | |
246 | | this manner. | |
247 | | Unfl: | |
248 | | Stwotox, setox, and scale can set underflow in this manner. | |
249 | | Any of the other Library Routines such that f(x)=x in which | |
250 | | x is an extended denorm can report an underflow exception. | |
251 | | It is the responsibility of the exception-causing exception | |
252 | | to make sure that WBTEMP is correct. | |
253 | | | |
254 | | The exceptional operand is in FP_SCR1. | |
255 | | | |
256 | ovfl_unfl: | |
257 | tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state | |
258 | beqs ofuf_con | |
259 | | | |
260 | | The caller was from an unsupported data type trap. Test if the | |
261 | | caller set CU_ONLY. If so, the exceptional operand is expected in | |
262 | | FPTEMP, rather than WBTEMP. | |
263 | | | |
264 | tstb CU_ONLY(%a6) |test if inst is cu-only | |
265 | beq unsE3 | |
266 | | move.w #$fe,CU_SAVEPC(%a6) | |
267 | clrb CU_SAVEPC(%a6) | |
268 | bsetb #E1,E_BYTE(%a6) |set E1 exception flag | |
269 | movew ETEMP_EX(%a6),FPTEMP_EX(%a6) | |
270 | movel ETEMP_HI(%a6),FPTEMP_HI(%a6) | |
271 | movel ETEMP_LO(%a6),FPTEMP_LO(%a6) | |
272 | bsetb #fptemp15_bit,DTAG(%a6) |set fpte15 | |
273 | bclrb #UFLAG,T_BYTE(%a6) |clr U flag from unimp | |
274 | bra do_clean |go clean and exit | |
275 | ||
276 | ofuf_con: | |
277 | moveb (%a7),VER_TMP(%a6) |save version number | |
278 | cmpib #BUSY_SIZE-4,1(%a7) |check for busy frame | |
279 | beqs busy_fr |if unimp, grow to busy | |
280 | cmpib #VER_40,(%a7) |test for orig unimp frame | |
281 | bnes try_41 |if not, test for rev frame | |
282 | moveql #13,%d0 |need to zero 14 lwords | |
283 | bras ofuf_fin | |
284 | try_41: | |
285 | cmpib #VER_41,(%a7) |test for rev unimp frame | |
286 | bnel fpsp_fmt_error |if neither, exit with error | |
287 | moveql #11,%d0 |need to zero 12 lwords | |
288 | ||
289 | ofuf_fin: | |
290 | clrl (%a7) | |
291 | loop1: | |
292 | clrl -(%a7) |clear and dec a7 | |
293 | dbra %d0,loop1 | |
294 | moveb VER_TMP(%a6),(%a7) | |
295 | moveb #BUSY_SIZE-4,1(%a7) |write busy fmt word. | |
296 | busy_fr: | |
297 | movel FP_SCR1(%a6),WBTEMP_EX(%a6) |write | |
298 | movel FP_SCR1+4(%a6),WBTEMP_HI(%a6) |exceptional op to | |
299 | movel FP_SCR1+8(%a6),WBTEMP_LO(%a6) |wbtemp | |
300 | bsetb #E3,E_BYTE(%a6) |set E3 flag | |
301 | bclrb #E1,E_BYTE(%a6) |make sure E1 is clear | |
302 | bclrb #UFLAG,T_BYTE(%a6) |clr U flag | |
303 | movel USER_FPSR(%a6),FPSR_SHADOW(%a6) | |
304 | orl #sx_mask,E_BYTE(%a6) | |
305 | movel CMDREG1B(%a6),%d0 |fix cmd1b to make it | |
306 | andl #0x03c30000,%d0 |work for cmd3b | |
307 | bfextu CMDREG1B(%a6){#13:#1},%d1 |extract bit 2 | |
308 | lsll #5,%d1 | |
309 | swap %d1 | |
310 | orl %d1,%d0 |put it in the right place | |
311 | bfextu CMDREG1B(%a6){#10:#3},%d1 |extract bit 3,4,5 | |
312 | lsll #2,%d1 | |
313 | swap %d1 | |
314 | orl %d1,%d0 |put them in the right place | |
315 | movel %d0,CMDREG3B(%a6) |in the busy frame | |
316 | ||
317 | | | |
318 | | Check if the frame to be restored is busy or unimp. | |
319 | |** NOTE *** Bug fix for errata (0d43b #3) | |
320 | | If the frame is unimp, we must create a busy frame to | |
321 | | fix the bug with the nmnexc bits in cases in which they | |
322 | | are set by a previous instruction and not cleared by | |
323 | | the save. The frame will be unimp only if the final | |
324 | | instruction in an emulation routine caused the exception | |
325 | | by doing an fmove <ea>,fp0. The exception operand, in | |
326 | | internal format, is in fptemp. | |
327 | | | |
328 | do_clean: | |
329 | cmpib #UNIMP_40_SIZE-4,1(%a7) | |
330 | bnes do_con | |
331 | moveql #13,%d0 |in orig, need to zero 14 lwords | |
332 | bras do_build | |
333 | do_con: | |
334 | cmpib #UNIMP_41_SIZE-4,1(%a7) | |
335 | bnes do_restore |frame must be busy | |
336 | moveql #11,%d0 |in rev, need to zero 12 lwords | |
337 | ||
338 | do_build: | |
339 | moveb (%a7),VER_TMP(%a6) | |
340 | clrl (%a7) | |
341 | loop2: | |
342 | clrl -(%a7) |clear and dec a7 | |
343 | dbra %d0,loop2 | |
344 | | | |
345 | | Use a1 as pointer into new frame. a6 is not correct if an unimp or | |
346 | | busy frame was created as the result of an exception on the final | |
347 | | instruction of an emulation routine. | |
348 | | | |
349 | | We need to set the nmcexc bits if the exception is E1. Otherwise, | |
350 | | the exc taken will be inex2. | |
351 | | | |
352 | leal BUSY_SIZE+LOCAL_SIZE(%a7),%a1 |init a1 for new frame | |
353 | moveb VER_TMP(%a6),(%a7) |write busy fmt word | |
354 | moveb #BUSY_SIZE-4,1(%a7) | |
355 | movel FP_SCR1(%a6),WBTEMP_EX(%a1) |write | |
356 | movel FP_SCR1+4(%a6),WBTEMP_HI(%a1) |exceptional op to | |
357 | movel FP_SCR1+8(%a6),WBTEMP_LO(%a1) |wbtemp | |
358 | | btst.b #E1,E_BYTE(%a1) | |
359 | | beq.b do_restore | |
360 | bfextu USER_FPSR(%a6){#17:#4},%d0 |get snan/operr/ovfl/unfl bits | |
361 | bfins %d0,NMCEXC(%a1){#4:#4} |and insert them in nmcexc | |
362 | movel USER_FPSR(%a6),FPSR_SHADOW(%a1) |set exc bits | |
363 | orl #sx_mask,E_BYTE(%a1) | |
364 | ||
365 | do_restore: | |
366 | moveml USER_DA(%a6),%d0-%d1/%a0-%a1 | |
367 | fmovemx USER_FP0(%a6),%fp0-%fp3 | |
368 | fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar | |
369 | frestore (%a7)+ | |
370 | tstb RES_FLG(%a6) |RES_FLG indicates a "continuation" frame | |
371 | beq cont | |
372 | bsr bug1384 | |
373 | cont: | |
374 | unlk %a6 | |
375 | | | |
376 | | If trace mode enabled, then go to trace handler. This handler | |
377 | | cannot have any fp instructions. If there are fp inst's and an | |
378 | | exception has been restored into the machine then the exception | |
379 | | will occur upon execution of the fp inst. This is not desirable | |
380 | | in the kernel (supervisor mode). See MC68040 manual Section 9.3.8. | |
381 | | | |
382 | finish_up: | |
383 | btstb #7,(%a7) |test T1 in SR | |
384 | bnes g_trace | |
385 | btstb #6,(%a7) |test T0 in SR | |
386 | bnes g_trace | |
387 | bral fpsp_done | |
388 | | | |
389 | | Change integer stack to look like trace stack | |
390 | | The address of the instruction that caused the | |
391 | | exception is already in the integer stack (is | |
392 | | the same as the saved friar) | |
393 | | | |
394 | | If the current frame is already a 6-word stack then all | |
395 | | that needs to be done is to change the vector# to TRACE. | |
396 | | If the frame is only a 4-word stack (meaning we got here | |
397 | | on an Unsupported data type exception), then we need to grow | |
398 | | the stack an extra 2 words and get the FPIAR from the FPU. | |
399 | | | |
400 | g_trace: | |
401 | bftst EXC_VEC-4(%sp){#0:#4} | |
402 | bne g_easy | |
403 | ||
404 | subw #4,%sp | make room | |
405 | movel 4(%sp),(%sp) | |
406 | movel 8(%sp),4(%sp) | |
407 | subw #BUSY_SIZE,%sp | |
408 | fsave (%sp) | |
409 | fmovel %fpiar,BUSY_SIZE+EXC_EA-4(%sp) | |
410 | frestore (%sp) | |
411 | addw #BUSY_SIZE,%sp | |
412 | ||
413 | g_easy: | |
414 | movew #TRACE_VEC,EXC_VEC-4(%a7) | |
415 | bral real_trace | |
416 | | | |
417 | | This is a work-around for hardware bug 1384. | |
418 | | | |
419 | bug1384: | |
420 | link %a5,#0 | |
421 | fsave -(%sp) | |
422 | cmpib #0x41,(%sp) | check for correct frame | |
423 | beq frame_41 | |
424 | bgt nofix | if more advanced mask, do nada | |
425 | ||
426 | frame_40: | |
427 | tstb 1(%sp) | check to see if idle | |
428 | bne notidle | |
429 | idle40: | |
430 | clrl (%sp) | get rid of old fsave frame | |
431 | movel %d1,USER_D1(%a6) | save d1 | |
432 | movew #8,%d1 | place unimp frame instead | |
433 | loop40: clrl -(%sp) | |
434 | dbra %d1,loop40 | |
435 | movel USER_D1(%a6),%d1 | restore d1 | |
436 | movel #0x40280000,-(%sp) | |
437 | frestore (%sp)+ | |
438 | unlk %a5 | |
439 | rts | |
440 | ||
441 | frame_41: | |
442 | tstb 1(%sp) | check to see if idle | |
443 | bne notidle | |
444 | idle41: | |
445 | clrl (%sp) | get rid of old fsave frame | |
446 | movel %d1,USER_D1(%a6) | save d1 | |
447 | movew #10,%d1 | place unimp frame instead | |
448 | loop41: clrl -(%sp) | |
449 | dbra %d1,loop41 | |
450 | movel USER_D1(%a6),%d1 | restore d1 | |
451 | movel #0x41300000,-(%sp) | |
452 | frestore (%sp)+ | |
453 | unlk %a5 | |
454 | rts | |
455 | ||
456 | notidle: | |
457 | bclrb #etemp15_bit,-40(%a5) | |
458 | frestore (%sp)+ | |
459 | unlk %a5 | |
460 | rts | |
461 | ||
462 | nofix: | |
463 | frestore (%sp)+ | |
464 | unlk %a5 | |
465 | rts | |
466 | ||
467 | |end |