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