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