Annotation of sys/arch/m68k/fpsp/bugfix.sa, Revision 1.1
1.1 ! nbrk 1: * $OpenBSD: bugfix.sa,v 1.2 1996/05/29 21:05:26 niklas Exp $
! 2: * $NetBSD: bugfix.sa,v 1.3 1994/10/26 07:48:55 cgd Exp $
! 3:
! 4: * MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
! 5: * M68000 Hi-Performance Microprocessor Division
! 6: * M68040 Software Package
! 7: *
! 8: * M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
! 9: * All rights reserved.
! 10: *
! 11: * THE SOFTWARE is provided on an "AS IS" basis and without warranty.
! 12: * To the maximum extent permitted by applicable law,
! 13: * MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
! 14: * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
! 15: * PARTICULAR PURPOSE and any warranty against infringement with
! 16: * regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
! 17: * and any accompanying written materials.
! 18: *
! 19: * To the maximum extent permitted by applicable law,
! 20: * IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
! 21: * (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS
! 22: * PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR
! 23: * OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE
! 24: * SOFTWARE. Motorola assumes no responsibility for the maintenance
! 25: * and support of the SOFTWARE.
! 26: *
! 27: * You are hereby granted a copyright license to use, modify, and
! 28: * distribute the SOFTWARE so long as this entire notice is retained
! 29: * without alteration in any modified and/or redistributed versions,
! 30: * and that such modified versions are clearly identified as such.
! 31: * No licenses are granted by implication, estoppel or otherwise
! 32: * under any patents or trademarks of Motorola, Inc.
! 33:
! 34: *
! 35: * bugfix.sa 3.2 1/31/91
! 36: *
! 37: *
! 38: * This file contains workarounds for bugs in the 040
! 39: * relating to the Floating-Point Software Package (FPSP)
! 40: *
! 41: * Fixes for bugs: 1238
! 42: *
! 43: * Bug: 1238
! 44: *
! 45: *
! 46: * /* The following dirty_bit clear should be left in
! 47: * * the handler permanently to improve throughput.
! 48: * * The dirty_bits are located at bits [23:16] in
! 49: * * longword $08 in the busy frame $4x60. Bit 16
! 50: * * corresponds to FP0, bit 17 corresponds to FP1,
! 51: * * and so on.
! 52: * */
! 53: * if (E3_exception_just_serviced) {
! 54: * dirty_bit[cmdreg3b[9:7]] = 0;
! 55: * }
! 56: *
! 57: * if (fsave_format_version != $40) {goto NOFIX}
! 58: *
! 59: * if !(E3_exception_just_serviced) {goto NOFIX}
! 60: * if (cupc == 0000000) {goto NOFIX}
! 61: * if ((cmdreg1b[15:13] != 000) &&
! 62: * (cmdreg1b[15:10] != 010001)) {goto NOFIX}
! 63: * if (((cmdreg1b[15:13] != 000) || ((cmdreg1b[12:10] != cmdreg2b[9:7]) &&
! 64: * (cmdreg1b[12:10] != cmdreg3b[9:7])) ) &&
! 65: * ((cmdreg1b[ 9: 7] != cmdreg2b[9:7]) &&
! 66: * (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) ) {goto NOFIX}
! 67: *
! 68: * /* Note: for 6d43b or 8d43b, you may want to add the following code
! 69: * * to get better coverage. (If you do not insert this code, the part
! 70: * * won't lock up; it will simply get the wrong answer.)
! 71: * * Do NOT insert this code for 10d43b or later parts.
! 72: * *
! 73: * * if (fpiarcu == integer stack return address) {
! 74: * * cupc = 0000000;
! 75: * * goto NOFIX;
! 76: * * }
! 77: * */
! 78: *
! 79: * if (cmdreg1b[15:13] != 000) {goto FIX_OPCLASS2}
! 80: * FIX_OPCLASS0:
! 81: * if (((cmdreg1b[12:10] == cmdreg2b[9:7]) ||
! 82: * (cmdreg1b[ 9: 7] == cmdreg2b[9:7])) &&
! 83: * (cmdreg1b[12:10] != cmdreg3b[9:7]) &&
! 84: * (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) { /* xu conflict only */
! 85: * /* We execute the following code if there is an
! 86: * xu conflict and NOT an nu conflict */
! 87: *
! 88: * /* first save some values on the fsave frame */
! 89: * stag_temp = STAG[fsave_frame];
! 90: * cmdreg1b_temp = CMDREG1B[fsave_frame];
! 91: * dtag_temp = DTAG[fsave_frame];
! 92: * ete15_temp = ETE15[fsave_frame];
! 93: *
! 94: * CUPC[fsave_frame] = 0000000;
! 95: * FRESTORE
! 96: * FSAVE
! 97: *
! 98: * /* If the xu instruction is exceptional, we punt.
! 99: * * Otherwise, we would have to include OVFL/UNFL handler
! 100: * * code here to get the correct answer.
! 101: * */
! 102: * if (fsave_frame_format == $4060) {goto KILL_PROCESS}
! 103: *
! 104: * fsave_frame = /* build a long frame of all zeros */
! 105: * fsave_frame_format = $4060; /* label it as long frame */
! 106: *
! 107: * /* load it with the temps we saved */
! 108: * STAG[fsave_frame] = stag_temp;
! 109: * CMDREG1B[fsave_frame] = cmdreg1b_temp;
! 110: * DTAG[fsave_frame] = dtag_temp;
! 111: * ETE15[fsave_frame] = ete15_temp;
! 112: *
! 113: * /* Make sure that the cmdreg3b dest reg is not going to
! 114: * * be destroyed by a FMOVEM at the end of all this code.
! 115: * * If it is, you should move the current value of the reg
! 116: * * onto the stack so that the reg will loaded with that value.
! 117: * */
! 118: *
! 119: * /* All done. Proceed with the code below */
! 120: * }
! 121: *
! 122: * etemp = FP_reg_[cmdreg1b[12:10]];
! 123: * ete15 = ~ete14;
! 124: * cmdreg1b[15:10] = 010010;
! 125: * clear(bug_flag_procIDxxxx);
! 126: * FRESTORE and return;
! 127: *
! 128: *
! 129: * FIX_OPCLASS2:
! 130: * if ((cmdreg1b[9:7] == cmdreg2b[9:7]) &&
! 131: * (cmdreg1b[9:7] != cmdreg3b[9:7])) { /* xu conflict only */
! 132: * /* We execute the following code if there is an
! 133: * xu conflict and NOT an nu conflict */
! 134: *
! 135: * /* first save some values on the fsave frame */
! 136: * stag_temp = STAG[fsave_frame];
! 137: * cmdreg1b_temp = CMDREG1B[fsave_frame];
! 138: * dtag_temp = DTAG[fsave_frame];
! 139: * ete15_temp = ETE15[fsave_frame];
! 140: * etemp_temp = ETEMP[fsave_frame];
! 141: *
! 142: * CUPC[fsave_frame] = 0000000;
! 143: * FRESTORE
! 144: * FSAVE
! 145: *
! 146: *
! 147: * /* If the xu instruction is exceptional, we punt.
! 148: * * Otherwise, we would have to include OVFL/UNFL handler
! 149: * * code here to get the correct answer.
! 150: * */
! 151: * if (fsave_frame_format == $4060) {goto KILL_PROCESS}
! 152: *
! 153: * fsave_frame = /* build a long frame of all zeros */
! 154: * fsave_frame_format = $4060; /* label it as long frame */
! 155: *
! 156: * /* load it with the temps we saved */
! 157: * STAG[fsave_frame] = stag_temp;
! 158: * CMDREG1B[fsave_frame] = cmdreg1b_temp;
! 159: * DTAG[fsave_frame] = dtag_temp;
! 160: * ETE15[fsave_frame] = ete15_temp;
! 161: * ETEMP[fsave_frame] = etemp_temp;
! 162: *
! 163: * /* Make sure that the cmdreg3b dest reg is not going to
! 164: * * be destroyed by a FMOVEM at the end of all this code.
! 165: * * If it is, you should move the current value of the reg
! 166: * * onto the stack so that the reg will loaded with that value.
! 167: * */
! 168: *
! 169: * /* All done. Proceed with the code below */
! 170: * }
! 171: *
! 172: * if (etemp_exponent == min_sgl) etemp_exponent = min_dbl;
! 173: * if (etemp_exponent == max_sgl) etemp_exponent = max_dbl;
! 174: * cmdreg1b[15:10] = 010101;
! 175: * clear(bug_flag_procIDxxxx);
! 176: * FRESTORE and return;
! 177: *
! 178: *
! 179: * NOFIX:
! 180: * clear(bug_flag_procIDxxxx);
! 181: * FRESTORE and return;
! 182: *
! 183:
! 184: BUGFIX IDNT 2,1 Motorola 040 Floating Point Software Package
! 185:
! 186: section 8
! 187:
! 188: include fpsp.h
! 189:
! 190: xref fpsp_fmt_error
! 191:
! 192: xdef b1238_fix
! 193: b1238_fix:
! 194: *
! 195: * This code is entered only on completion of the handling of an
! 196: * nu-generated ovfl, unfl, or inex exception. If the version
! 197: * number of the fsave is not $40, this handler is not necessary.
! 198: * Simply branch to fix_done and exit normally.
! 199: *
! 200: cmpi.b #VER_40,4(a7)
! 201: bne.w fix_done
! 202: *
! 203: * Test for cu_savepc equal to zero. If not, this is not a bug
! 204: * #1238 case.
! 205: *
! 206: move.b CU_SAVEPC(a6),d0
! 207: andi.b #$FE,d0
! 208: beq fix_done ;if zero, this is not bug #1238
! 209:
! 210: *
! 211: * Test the register conflict aspect. If opclass0, check for
! 212: * cu src equal to xu dest or equal to nu dest. If so, go to
! 213: * op0. Else, or if opclass2, check for cu dest equal to
! 214: * xu dest or equal to nu dest. If so, go to tst_opcl. Else,
! 215: * exit, it is not the bug case.
! 216: *
! 217: * Check for opclass 0. If not, go and check for opclass 2 and sgl.
! 218: *
! 219: move.w CMDREG1B(a6),d0
! 220: andi.w #$E000,d0 ;strip all but opclass
! 221: bne op2sgl ;not opclass 0, check op2
! 222: *
! 223: * Check for cu and nu register conflict. If one exists, this takes
! 224: * priority over a cu and xu conflict.
! 225: *
! 226: bfextu CMDREG1B(a6){3:3},d0 ;get 1st src
! 227: bfextu CMDREG3B(a6){6:3},d1 ;get 3rd dest
! 228: cmp.b d0,d1
! 229: beq.b op0 ;if equal, continue bugfix
! 230: *
! 231: * Check for cu dest equal to nu dest. If so, go and fix the
! 232: * bug condition. Otherwise, exit.
! 233: *
! 234: bfextu CMDREG1B(a6){6:3},d0 ;get 1st dest
! 235: cmp.b d0,d1 ;cmp 1st dest with 3rd dest
! 236: beq.b op0 ;if equal, continue bugfix
! 237: *
! 238: * Check for cu and xu register conflict.
! 239: *
! 240: bfextu CMDREG2B(a6){6:3},d1 ;get 2nd dest
! 241: cmp.b d0,d1 ;cmp 1st dest with 2nd dest
! 242: beq.b op0_xu ;if equal, continue bugfix
! 243: bfextu CMDREG1B(a6){3:3},d0 ;get 1st src
! 244: cmp.b d0,d1 ;cmp 1st src with 2nd dest
! 245: beq op0_xu
! 246: bne fix_done ;if the reg checks fail, exit
! 247: *
! 248: * We have the opclass 0 situation.
! 249: *
! 250: op0:
! 251: bfextu CMDREG1B(a6){3:3},d0 ;get source register no
! 252: move.l #7,d1
! 253: sub.l d0,d1
! 254: clr.l d0
! 255: bset.l d1,d0
! 256: fmovem.x d0,ETEMP(a6) ;load source to ETEMP
! 257:
! 258: move.b #$12,d0
! 259: bfins d0,CMDREG1B(a6){0:6} ;opclass 2, extended
! 260: *
! 261: * Set ETEMP exponent bit 15 as the opposite of ete14
! 262: *
! 263: btst #6,ETEMP_EX(a6) ;check etemp exponent bit 14
! 264: beq setete15
! 265: bclr #etemp15_bit,STAG(a6)
! 266: bra finish
! 267: setete15:
! 268: bset #etemp15_bit,STAG(a6)
! 269: bra finish
! 270:
! 271: *
! 272: * We have the case in which a conflict exists between the cu src or
! 273: * dest and the dest of the xu. We must clear the instruction in
! 274: * the cu and restore the state, allowing the instruction in the
! 275: * xu to complete. Remember, the instruction in the nu
! 276: * was exceptional, and was completed by the appropriate handler.
! 277: * If the result of the xu instruction is not exceptional, we can
! 278: * restore the instruction from the cu to the frame and continue
! 279: * processing the original exception. If the result is also
! 280: * exceptional, we choose to kill the process.
! 281: *
! 282: * Items saved from the stack:
! 283: *
! 284: * $3c stag - L_SCR1
! 285: * $40 cmdreg1b - L_SCR2
! 286: * $44 dtag - L_SCR3
! 287: *
! 288: * The cu savepc is set to zero, and the frame is restored to the
! 289: * fpu.
! 290: *
! 291: op0_xu:
! 292: move.l STAG(a6),L_SCR1(a6)
! 293: move.l CMDREG1B(a6),L_SCR2(a6)
! 294: move.l DTAG(a6),L_SCR3(a6)
! 295: andi.l #$e0000000,L_SCR3(a6)
! 296: clr.b CU_SAVEPC(a6)
! 297: move.l (a7)+,d1 ;save return address from bsr
! 298: frestore (a7)+
! 299: fsave -(a7)
! 300: *
! 301: * Check if the instruction which just completed was exceptional.
! 302: *
! 303: cmp.w #$4060,(a7)
! 304: beq op0_xb
! 305: *
! 306: * It is necessary to isolate the result of the instruction in the
! 307: * xu if it is to fp0 - fp3 and write that value to the USER_FPn
! 308: * locations on the stack. The correct destination register is in
! 309: * cmdreg2b.
! 310: *
! 311: bfextu CMDREG2B(a6){6:3},d0 ;get dest register no
! 312: cmpi.l #3,d0
! 313: bgt.b op0_xi
! 314: beq.b op0_fp3
! 315: cmpi.l #1,d0
! 316: blt.b op0_fp0
! 317: beq.b op0_fp1
! 318: op0_fp2:
! 319: fmovem.x fp2,USER_FP2(a6)
! 320: bra.b op0_xi
! 321: op0_fp1:
! 322: fmovem.x fp1,USER_FP1(a6)
! 323: bra.b op0_xi
! 324: op0_fp0:
! 325: fmovem.x fp0,USER_FP0(a6)
! 326: bra.b op0_xi
! 327: op0_fp3:
! 328: fmovem.x fp3,USER_FP3(a6)
! 329: *
! 330: * The frame returned is idle. We must build a busy frame to hold
! 331: * the cu state information and setup etemp.
! 332: *
! 333: op0_xi:
! 334: move.l #22,d0 ;clear 23 lwords
! 335: clr.l (a7)
! 336: op0_loop:
! 337: clr.l -(a7)
! 338: dbf d0,op0_loop
! 339: move.l #$40600000,-(a7)
! 340: move.l L_SCR1(a6),STAG(a6)
! 341: move.l L_SCR2(a6),CMDREG1B(a6)
! 342: move.l L_SCR3(a6),DTAG(a6)
! 343: move.b #$6,CU_SAVEPC(a6)
! 344: move.l d1,-(a7) ;return bsr return address
! 345: bfextu CMDREG1B(a6){3:3},d0 ;get source register no
! 346: move.l #7,d1
! 347: sub.l d0,d1
! 348: clr.l d0
! 349: bset.l d1,d0
! 350: fmovem.x d0,ETEMP(a6) ;load source to ETEMP
! 351:
! 352: move.b #$12,d0
! 353: bfins d0,CMDREG1B(a6){0:6} ;opclass 2, extended
! 354: *
! 355: * Set ETEMP exponent bit 15 as the opposite of ete14
! 356: *
! 357: btst #6,ETEMP_EX(a6) ;check etemp exponent bit 14
! 358: beq op0_sete15
! 359: bclr #etemp15_bit,STAG(a6)
! 360: bra finish
! 361: op0_sete15:
! 362: bset #etemp15_bit,STAG(a6)
! 363: bra finish
! 364:
! 365: *
! 366: * The frame returned is busy. It is not possible to reconstruct
! 367: * the code sequence to allow completion. We will jump to
! 368: * fpsp_fmt_error and allow the kernel to kill the process.
! 369: *
! 370: op0_xb:
! 371: jmp fpsp_fmt_error
! 372:
! 373: *
! 374: * Check for opclass 2 and single size. If not both, exit.
! 375: *
! 376: op2sgl:
! 377: move.w CMDREG1B(a6),d0
! 378: andi.w #$FC00,d0 ;strip all but opclass and size
! 379: cmpi.w #$4400,d0 ;test for opclass 2 and size=sgl
! 380: bne fix_done ;if not, it is not bug 1238
! 381: *
! 382: * Check for cu dest equal to nu dest or equal to xu dest, with
! 383: * a cu and nu conflict taking priority an nu conflict. If either,
! 384: * go and fix the bug condition. Otherwise, exit.
! 385: *
! 386: bfextu CMDREG1B(a6){6:3},d0 ;get 1st dest
! 387: bfextu CMDREG3B(a6){6:3},d1 ;get 3rd dest
! 388: cmp.b d0,d1 ;cmp 1st dest with 3rd dest
! 389: beq op2_com ;if equal, continue bugfix
! 390: bfextu CMDREG2B(a6){6:3},d1 ;get 2nd dest
! 391: cmp.b d0,d1 ;cmp 1st dest with 2nd dest
! 392: bne fix_done ;if the reg checks fail, exit
! 393: *
! 394: * We have the case in which a conflict exists between the cu src or
! 395: * dest and the dest of the xu. We must clear the instruction in
! 396: * the cu and restore the state, allowing the instruction in the
! 397: * xu to complete. Remember, the instruction in the nu
! 398: * was exceptional, and was completed by the appropriate handler.
! 399: * If the result of the xu instruction is not exceptional, we can
! 400: * restore the instruction from the cu to the frame and continue
! 401: * processing the original exception. If the result is also
! 402: * exceptional, we choose to kill the process.
! 403: *
! 404: * Items saved from the stack:
! 405: *
! 406: * $3c stag - L_SCR1
! 407: * $40 cmdreg1b - L_SCR2
! 408: * $44 dtag - L_SCR3
! 409: * etemp - FP_SCR2
! 410: *
! 411: * The cu savepc is set to zero, and the frame is restored to the
! 412: * fpu.
! 413: *
! 414: op2_xu:
! 415: move.l STAG(a6),L_SCR1(a6)
! 416: move.l CMDREG1B(a6),L_SCR2(a6)
! 417: move.l DTAG(a6),L_SCR3(a6)
! 418: andi.l #$e0000000,L_SCR3(a6)
! 419: clr.b CU_SAVEPC(a6)
! 420: move.l ETEMP(a6),FP_SCR2(a6)
! 421: move.l ETEMP_HI(a6),FP_SCR2+4(a6)
! 422: move.l ETEMP_LO(a6),FP_SCR2+8(a6)
! 423: move.l (a7)+,d1 ;save return address from bsr
! 424: frestore (a7)+
! 425: fsave -(a7)
! 426: *
! 427: * Check if the instruction which just completed was exceptional.
! 428: *
! 429: cmp.w #$4060,(a7)
! 430: beq op2_xb
! 431: *
! 432: * It is necessary to isolate the result of the instruction in the
! 433: * xu if it is to fp0 - fp3 and write that value to the USER_FPn
! 434: * locations on the stack. The correct destination register is in
! 435: * cmdreg2b.
! 436: *
! 437: bfextu CMDREG2B(a6){6:3},d0 ;get dest register no
! 438: cmpi.l #3,d0
! 439: bgt.b op2_xi
! 440: beq.b op2_fp3
! 441: cmpi.l #1,d0
! 442: blt.b op2_fp0
! 443: beq.b op2_fp1
! 444: op2_fp2:
! 445: fmovem.x fp2,USER_FP2(a6)
! 446: bra.b op2_xi
! 447: op2_fp1:
! 448: fmovem.x fp1,USER_FP1(a6)
! 449: bra.b op2_xi
! 450: op2_fp0:
! 451: fmovem.x fp0,USER_FP0(a6)
! 452: bra.b op2_xi
! 453: op2_fp3:
! 454: fmovem.x fp3,USER_FP3(a6)
! 455: *
! 456: * The frame returned is idle. We must build a busy frame to hold
! 457: * the cu state information and fix up etemp.
! 458: *
! 459: op2_xi:
! 460: move.l #22,d0 ;clear 23 lwords
! 461: clr.l (a7)
! 462: op2_loop:
! 463: clr.l -(a7)
! 464: dbf d0,op2_loop
! 465: move.l #$40600000,-(a7)
! 466: move.l L_SCR1(a6),STAG(a6)
! 467: move.l L_SCR2(a6),CMDREG1B(a6)
! 468: move.l L_SCR3(a6),DTAG(a6)
! 469: move.b #$6,CU_SAVEPC(a6)
! 470: move.l FP_SCR2(a6),ETEMP(a6)
! 471: move.l FP_SCR2+4(a6),ETEMP_HI(a6)
! 472: move.l FP_SCR2+8(a6),ETEMP_LO(a6)
! 473: move.l d1,-(a7)
! 474: bra op2_com
! 475:
! 476: *
! 477: * We have the opclass 2 single source situation.
! 478: *
! 479: op2_com:
! 480: move.b #$15,d0
! 481: bfins d0,CMDREG1B(a6){0:6} ;opclass 2, double
! 482:
! 483: cmp.w #$407F,ETEMP_EX(a6) ;single +max
! 484: bne.b case2
! 485: move.w #$43FF,ETEMP_EX(a6) ;to double +max
! 486: bra finish
! 487: case2:
! 488: cmp.w #$C07F,ETEMP_EX(a6) ;single -max
! 489: bne.b case3
! 490: move.w #$C3FF,ETEMP_EX(a6) ;to double -max
! 491: bra finish
! 492: case3:
! 493: cmp.w #$3F80,ETEMP_EX(a6) ;single +min
! 494: bne.b case4
! 495: move.w #$3C00,ETEMP_EX(a6) ;to double +min
! 496: bra finish
! 497: case4:
! 498: cmp.w #$BF80,ETEMP_EX(a6) ;single -min
! 499: bne fix_done
! 500: move.w #$BC00,ETEMP_EX(a6) ;to double -min
! 501: bra finish
! 502: *
! 503: * The frame returned is busy. It is not possible to reconstruct
! 504: * the code sequence to allow completion. fpsp_fmt_error causes
! 505: * an fline illegal instruction to be executed.
! 506: *
! 507: * You should replace the jump to fpsp_fmt_error with a jump
! 508: * to the entry point used to kill a process.
! 509: *
! 510: op2_xb:
! 511: jmp fpsp_fmt_error
! 512:
! 513: *
! 514: * Enter here if the case is not of the situations affected by
! 515: * bug #1238, or if the fix is completed, and exit.
! 516: *
! 517: finish:
! 518: fix_done:
! 519: rts
! 520:
! 521: end
CVSweb