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