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 61GEN_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 71exc_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 83gen_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* 127unimp_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 132test_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 137unimp_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 156do_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 174check_fr: 175 cmp.b #UNIMP_40_SIZE-4,1(a7) 176 beq.b frame_com 177 clr.w NMNEXC(a6) 178frame_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* 190bsun_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* 200commonE1: 201 bset.b #E1,E_BYTE(a6) ;set E1 flag 202 bra.w commonE ;go clean and exit 203 204commonE3: 205 tst.b UFLG_TMP(a6) ;test flag for unsup/unimp state 206 bne.b unsE3 207uniE3: 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 212unsE3: 213 tst.b RES_FLG(a6) 214 bne.b unsE3_0 215unsE3_1: 216 bset.b #E3,E_BYTE(a6) ;set E3 flag 217unsE3_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 231commonE: 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* 239no_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. 250no_exc: 251 tst.b UFLG_TMP(a6) ;test flag for unsupp/unimp state 252 beq.b uni_no_exc 253uns_no_exc: 254 tst.b RES_FLG(a6) ;check if frestore is needed 255 bne.w do_clean ;if clear, no frestore needed 256uni_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* 282ovfl_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 302ofuf_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 310try_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 315ofuf_fin: 316 clr.l (a7) 317loop1: 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. 322busy_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* 354do_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 359do_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 364do_build: 365 move.b (a7),VER_TMP(a6) 366 clr.l (a7) 367loop2: 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 391do_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 399cont: 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* 408finish_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* 426g_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 439g_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* 445bug1384: 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 452frame_40: 453 tst.b 1(sp) ; check to see if idle 454 bne notidle 455idle40: 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 459loop40: 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 467frame_41: 468 tst.b 1(sp) ; check to see if idle 469 bne notidle 470idle41: 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 474loop41: 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 482notidle: 483 bclr.b #etemp15_bit,-40(a5) 484 frestore (sp)+ 485 unlk a5 486 rts 487 488nofix: 489 frestore (sp)+ 490 unlk a5 491 rts 492 493 end 494