Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |