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