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 36GEN_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 46exc_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 58gen_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| 102unimp_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 107test_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 112unimp_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 131do_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 149check_fr: 150 cmpb #UNIMP_40_SIZE-4,1(%a7) 151 beqs frame_com 152 clrw NMNEXC(%a6) 153frame_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| 165bsun_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| 175commonE1: 176 bsetb #E1,E_BYTE(%a6) |set E1 flag 177 bra commonE |go clean and exit 178 179commonE3: 180 tstb UFLG_TMP(%a6) |test flag for unsup/unimp state 181 bnes unsE3 182uniE3: 183 bsetb #E3,E_BYTE(%a6) |set E3 flag 184 bclrb #E1,E_BYTE(%a6) |clr E1 from unimp 185 bra commonE 186 187unsE3: 188 tstb RES_FLG(%a6) 189 bnes unsE3_0 190unsE3_1: 191 bsetb #E3,E_BYTE(%a6) |set E3 flag 192unsE3_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 206commonE: 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| 214no_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. 225no_exc: 226 tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state 227 beqs uni_no_exc 228uns_no_exc: 229 tstb RES_FLG(%a6) |check if frestore is needed 230 bne do_clean |if clear, no frestore needed 231uni_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| 257ovfl_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 277ofuf_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 285try_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 290ofuf_fin: 291 clrl (%a7) 292loop1: 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. 297busy_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| 329do_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 334do_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 339do_build: 340 moveb (%a7),VER_TMP(%a6) 341 clrl (%a7) 342loop2: 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 366do_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 374cont: 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| 383finish_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| 401g_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 414g_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| 420bug1384: 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 427frame_40: 428 tstb 1(%sp) | check to see if idle 429 bne notidle 430idle40: 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 434loop40: 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 442frame_41: 443 tstb 1(%sp) | check to see if idle 444 bne notidle 445idle41: 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 449loop41: 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 457notidle: 458 bclrb #etemp15_bit,-40(%a5) 459 frestore (%sp)+ 460 unlk %a5 461 rts 462 463nofix: 464 frestore (%sp)+ 465 unlk %a5 466 rts 467 468 |end 469