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