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 183BUGFIX 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 192b1238_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* 249op0: 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 266setete15: 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* 290op0_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 317op0_fp2: 318 fmovem.x fp2,USER_FP2(a6) 319 bra.b op0_xi 320op0_fp1: 321 fmovem.x fp1,USER_FP1(a6) 322 bra.b op0_xi 323op0_fp0: 324 fmovem.x fp0,USER_FP0(a6) 325 bra.b op0_xi 326op0_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* 332op0_xi: 333 move.l #22,d0 ;clear 23 lwords 334 clr.l (a7) 335op0_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 360op0_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* 369op0_xb: 370 jmp fpsp_fmt_error 371 372* 373* Check for opclass 2 and single size. If not both, exit. 374* 375op2sgl: 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* 413op2_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 443op2_fp2: 444 fmovem.x fp2,USER_FP2(a6) 445 bra.b op2_xi 446op2_fp1: 447 fmovem.x fp1,USER_FP1(a6) 448 bra.b op2_xi 449op2_fp0: 450 fmovem.x fp0,USER_FP0(a6) 451 bra.b op2_xi 452op2_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* 458op2_xi: 459 move.l #22,d0 ;clear 23 lwords 460 clr.l (a7) 461op2_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* 478op2_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 486case2: 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 491case3: 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 496case4: 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* 509op2_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* 516finish: 517fix_done: 518 rts 519 520 end 521