* $NetBSD: bugfix.sa,v 1.3 1994/10/26 07:48:55 cgd Exp $ * MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP * M68000 Hi-Performance Microprocessor Division * M68040 Software Package * * M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc. * All rights reserved. * * THE SOFTWARE is provided on an "AS IS" basis and without warranty. * To the maximum extent permitted by applicable law, * MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A * PARTICULAR PURPOSE and any warranty against infringement with * regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) * and any accompanying written materials. * * To the maximum extent permitted by applicable law, * IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER * (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS * PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR * OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE * SOFTWARE. Motorola assumes no responsibility for the maintenance * and support of the SOFTWARE. * * You are hereby granted a copyright license to use, modify, and * distribute the SOFTWARE so long as this entire notice is retained * without alteration in any modified and/or redistributed versions, * and that such modified versions are clearly identified as such. * No licenses are granted by implication, estoppel or otherwise * under any patents or trademarks of Motorola, Inc. * * bugfix.sa 3.2 1/31/91 * * * This file contains workarounds for bugs in the 040 * relating to the Floating-Point Software Package (FPSP) * * Fixes for bugs: 1238 * * Bug: 1238 * * * /* The following dirty_bit clear should be left in * * the handler permanently to improve throughput. * * The dirty_bits are located at bits [23:16] in * * longword $08 in the busy frame $4x60. Bit 16 * * corresponds to FP0, bit 17 corresponds to FP1, * * and so on. * */ * if (E3_exception_just_serviced) { * dirty_bit[cmdreg3b[9:7]] = 0; * } * * if (fsave_format_version != $40) {goto NOFIX} * * if !(E3_exception_just_serviced) {goto NOFIX} * if (cupc == 0000000) {goto NOFIX} * if ((cmdreg1b[15:13] != 000) && * (cmdreg1b[15:10] != 010001)) {goto NOFIX} * if (((cmdreg1b[15:13] != 000) || ((cmdreg1b[12:10] != cmdreg2b[9:7]) && * (cmdreg1b[12:10] != cmdreg3b[9:7])) ) && * ((cmdreg1b[ 9: 7] != cmdreg2b[9:7]) && * (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) ) {goto NOFIX} * * /* Note: for 6d43b or 8d43b, you may want to add the following code * * to get better coverage. (If you do not insert this code, the part * * won't lock up; it will simply get the wrong answer.) * * Do NOT insert this code for 10d43b or later parts. * * * * if (fpiarcu == integer stack return address) { * * cupc = 0000000; * * goto NOFIX; * * } * */ * * if (cmdreg1b[15:13] != 000) {goto FIX_OPCLASS2} * FIX_OPCLASS0: * if (((cmdreg1b[12:10] == cmdreg2b[9:7]) || * (cmdreg1b[ 9: 7] == cmdreg2b[9:7])) && * (cmdreg1b[12:10] != cmdreg3b[9:7]) && * (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) { /* xu conflict only */ * /* We execute the following code if there is an * xu conflict and NOT an nu conflict */ * * /* first save some values on the fsave frame */ * stag_temp = STAG[fsave_frame]; * cmdreg1b_temp = CMDREG1B[fsave_frame]; * dtag_temp = DTAG[fsave_frame]; * ete15_temp = ETE15[fsave_frame]; * * CUPC[fsave_frame] = 0000000; * FRESTORE * FSAVE * * /* If the xu instruction is exceptional, we punt. * * Otherwise, we would have to include OVFL/UNFL handler * * code here to get the correct answer. * */ * if (fsave_frame_format == $4060) {goto KILL_PROCESS} * * fsave_frame = /* build a long frame of all zeros */ * fsave_frame_format = $4060; /* label it as long frame */ * * /* load it with the temps we saved */ * STAG[fsave_frame] = stag_temp; * CMDREG1B[fsave_frame] = cmdreg1b_temp; * DTAG[fsave_frame] = dtag_temp; * ETE15[fsave_frame] = ete15_temp; * * /* Make sure that the cmdreg3b dest reg is not going to * * be destroyed by a FMOVEM at the end of all this code. * * If it is, you should move the current value of the reg * * onto the stack so that the reg will loaded with that value. * */ * * /* All done. Proceed with the code below */ * } * * etemp = FP_reg_[cmdreg1b[12:10]]; * ete15 = ~ete14; * cmdreg1b[15:10] = 010010; * clear(bug_flag_procIDxxxx); * FRESTORE and return; * * * FIX_OPCLASS2: * if ((cmdreg1b[9:7] == cmdreg2b[9:7]) && * (cmdreg1b[9:7] != cmdreg3b[9:7])) { /* xu conflict only */ * /* We execute the following code if there is an * xu conflict and NOT an nu conflict */ * * /* first save some values on the fsave frame */ * stag_temp = STAG[fsave_frame]; * cmdreg1b_temp = CMDREG1B[fsave_frame]; * dtag_temp = DTAG[fsave_frame]; * ete15_temp = ETE15[fsave_frame]; * etemp_temp = ETEMP[fsave_frame]; * * CUPC[fsave_frame] = 0000000; * FRESTORE * FSAVE * * * /* If the xu instruction is exceptional, we punt. * * Otherwise, we would have to include OVFL/UNFL handler * * code here to get the correct answer. * */ * if (fsave_frame_format == $4060) {goto KILL_PROCESS} * * fsave_frame = /* build a long frame of all zeros */ * fsave_frame_format = $4060; /* label it as long frame */ * * /* load it with the temps we saved */ * STAG[fsave_frame] = stag_temp; * CMDREG1B[fsave_frame] = cmdreg1b_temp; * DTAG[fsave_frame] = dtag_temp; * ETE15[fsave_frame] = ete15_temp; * ETEMP[fsave_frame] = etemp_temp; * * /* Make sure that the cmdreg3b dest reg is not going to * * be destroyed by a FMOVEM at the end of all this code. * * If it is, you should move the current value of the reg * * onto the stack so that the reg will loaded with that value. * */ * * /* All done. Proceed with the code below */ * } * * if (etemp_exponent == min_sgl) etemp_exponent = min_dbl; * if (etemp_exponent == max_sgl) etemp_exponent = max_dbl; * cmdreg1b[15:10] = 010101; * clear(bug_flag_procIDxxxx); * FRESTORE and return; * * * NOFIX: * clear(bug_flag_procIDxxxx); * FRESTORE and return; * BUGFIX IDNT 2,1 Motorola 040 Floating Point Software Package section 8 include fpsp.h xref fpsp_fmt_error xdef b1238_fix b1238_fix: * * This code is entered only on completion of the handling of an * nu-generated ovfl, unfl, or inex exception. If the version * number of the fsave is not $40, this handler is not necessary. * Simply branch to fix_done and exit normally. * cmpi.b #VER_40,4(a7) bne.w fix_done * * Test for cu_savepc equal to zero. If not, this is not a bug * #1238 case. * move.b CU_SAVEPC(a6),d0 andi.b #$FE,d0 beq fix_done ;if zero, this is not bug #1238 * * Test the register conflict aspect. If opclass0, check for * cu src equal to xu dest or equal to nu dest. If so, go to * op0. Else, or if opclass2, check for cu dest equal to * xu dest or equal to nu dest. If so, go to tst_opcl. Else, * exit, it is not the bug case. * * Check for opclass 0. If not, go and check for opclass 2 and sgl. * move.w CMDREG1B(a6),d0 andi.w #$E000,d0 ;strip all but opclass bne op2sgl ;not opclass 0, check op2 * * Check for cu and nu register conflict. If one exists, this takes * priority over a cu and xu conflict. * bfextu CMDREG1B(a6){3:3},d0 ;get 1st src bfextu CMDREG3B(a6){6:3},d1 ;get 3rd dest cmp.b d0,d1 beq.b op0 ;if equal, continue bugfix * * Check for cu dest equal to nu dest. If so, go and fix the * bug condition. Otherwise, exit. * bfextu CMDREG1B(a6){6:3},d0 ;get 1st dest cmp.b d0,d1 ;cmp 1st dest with 3rd dest beq.b op0 ;if equal, continue bugfix * * Check for cu and xu register conflict. * bfextu CMDREG2B(a6){6:3},d1 ;get 2nd dest cmp.b d0,d1 ;cmp 1st dest with 2nd dest beq.b op0_xu ;if equal, continue bugfix bfextu CMDREG1B(a6){3:3},d0 ;get 1st src cmp.b d0,d1 ;cmp 1st src with 2nd dest beq op0_xu bne fix_done ;if the reg checks fail, exit * * We have the opclass 0 situation. * op0: bfextu CMDREG1B(a6){3:3},d0 ;get source register no move.l #7,d1 sub.l d0,d1 clr.l d0 bset.l d1,d0 fmovem.x d0,ETEMP(a6) ;load source to ETEMP move.b #$12,d0 bfins d0,CMDREG1B(a6){0:6} ;opclass 2, extended * * Set ETEMP exponent bit 15 as the opposite of ete14 * btst #6,ETEMP_EX(a6) ;check etemp exponent bit 14 beq setete15 bclr #etemp15_bit,STAG(a6) bra finish setete15: bset #etemp15_bit,STAG(a6) bra finish * * We have the case in which a conflict exists between the cu src or * dest and the dest of the xu. We must clear the instruction in * the cu and restore the state, allowing the instruction in the * xu to complete. Remember, the instruction in the nu * was exceptional, and was completed by the appropriate handler. * If the result of the xu instruction is not exceptional, we can * restore the instruction from the cu to the frame and continue * processing the original exception. If the result is also * exceptional, we choose to kill the process. * * Items saved from the stack: * * $3c stag - L_SCR1 * $40 cmdreg1b - L_SCR2 * $44 dtag - L_SCR3 * * The cu savepc is set to zero, and the frame is restored to the * fpu. * op0_xu: move.l STAG(a6),L_SCR1(a6) move.l CMDREG1B(a6),L_SCR2(a6) move.l DTAG(a6),L_SCR3(a6) andi.l #$e0000000,L_SCR3(a6) clr.b CU_SAVEPC(a6) move.l (a7)+,d1 ;save return address from bsr frestore (a7)+ fsave -(a7) * * Check if the instruction which just completed was exceptional. * cmp.w #$4060,(a7) beq op0_xb * * It is necessary to isolate the result of the instruction in the * xu if it is to fp0 - fp3 and write that value to the USER_FPn * locations on the stack. The correct destination register is in * cmdreg2b. * bfextu CMDREG2B(a6){6:3},d0 ;get dest register no cmpi.l #3,d0 bgt.b op0_xi beq.b op0_fp3 cmpi.l #1,d0 blt.b op0_fp0 beq.b op0_fp1 op0_fp2: fmovem.x fp2,USER_FP2(a6) bra.b op0_xi op0_fp1: fmovem.x fp1,USER_FP1(a6) bra.b op0_xi op0_fp0: fmovem.x fp0,USER_FP0(a6) bra.b op0_xi op0_fp3: fmovem.x fp3,USER_FP3(a6) * * The frame returned is idle. We must build a busy frame to hold * the cu state information and setup etemp. * op0_xi: move.l #22,d0 ;clear 23 lwords clr.l (a7) op0_loop: clr.l -(a7) dbf d0,op0_loop move.l #$40600000,-(a7) move.l L_SCR1(a6),STAG(a6) move.l L_SCR2(a6),CMDREG1B(a6) move.l L_SCR3(a6),DTAG(a6) move.b #$6,CU_SAVEPC(a6) move.l d1,-(a7) ;return bsr return address bfextu CMDREG1B(a6){3:3},d0 ;get source register no move.l #7,d1 sub.l d0,d1 clr.l d0 bset.l d1,d0 fmovem.x d0,ETEMP(a6) ;load source to ETEMP move.b #$12,d0 bfins d0,CMDREG1B(a6){0:6} ;opclass 2, extended * * Set ETEMP exponent bit 15 as the opposite of ete14 * btst #6,ETEMP_EX(a6) ;check etemp exponent bit 14 beq op0_sete15 bclr #etemp15_bit,STAG(a6) bra finish op0_sete15: bset #etemp15_bit,STAG(a6) bra finish * * The frame returned is busy. It is not possible to reconstruct * the code sequence to allow completion. We will jump to * fpsp_fmt_error and allow the kernel to kill the process. * op0_xb: jmp fpsp_fmt_error * * Check for opclass 2 and single size. If not both, exit. * op2sgl: move.w CMDREG1B(a6),d0 andi.w #$FC00,d0 ;strip all but opclass and size cmpi.w #$4400,d0 ;test for opclass 2 and size=sgl bne fix_done ;if not, it is not bug 1238 * * Check for cu dest equal to nu dest or equal to xu dest, with * a cu and nu conflict taking priority an nu conflict. If either, * go and fix the bug condition. Otherwise, exit. * bfextu CMDREG1B(a6){6:3},d0 ;get 1st dest bfextu CMDREG3B(a6){6:3},d1 ;get 3rd dest cmp.b d0,d1 ;cmp 1st dest with 3rd dest beq op2_com ;if equal, continue bugfix bfextu CMDREG2B(a6){6:3},d1 ;get 2nd dest cmp.b d0,d1 ;cmp 1st dest with 2nd dest bne fix_done ;if the reg checks fail, exit * * We have the case in which a conflict exists between the cu src or * dest and the dest of the xu. We must clear the instruction in * the cu and restore the state, allowing the instruction in the * xu to complete. Remember, the instruction in the nu * was exceptional, and was completed by the appropriate handler. * If the result of the xu instruction is not exceptional, we can * restore the instruction from the cu to the frame and continue * processing the original exception. If the result is also * exceptional, we choose to kill the process. * * Items saved from the stack: * * $3c stag - L_SCR1 * $40 cmdreg1b - L_SCR2 * $44 dtag - L_SCR3 * etemp - FP_SCR2 * * The cu savepc is set to zero, and the frame is restored to the * fpu. * op2_xu: move.l STAG(a6),L_SCR1(a6) move.l CMDREG1B(a6),L_SCR2(a6) move.l DTAG(a6),L_SCR3(a6) andi.l #$e0000000,L_SCR3(a6) clr.b CU_SAVEPC(a6) move.l ETEMP(a6),FP_SCR2(a6) move.l ETEMP_HI(a6),FP_SCR2+4(a6) move.l ETEMP_LO(a6),FP_SCR2+8(a6) move.l (a7)+,d1 ;save return address from bsr frestore (a7)+ fsave -(a7) * * Check if the instruction which just completed was exceptional. * cmp.w #$4060,(a7) beq op2_xb * * It is necessary to isolate the result of the instruction in the * xu if it is to fp0 - fp3 and write that value to the USER_FPn * locations on the stack. The correct destination register is in * cmdreg2b. * bfextu CMDREG2B(a6){6:3},d0 ;get dest register no cmpi.l #3,d0 bgt.b op2_xi beq.b op2_fp3 cmpi.l #1,d0 blt.b op2_fp0 beq.b op2_fp1 op2_fp2: fmovem.x fp2,USER_FP2(a6) bra.b op2_xi op2_fp1: fmovem.x fp1,USER_FP1(a6) bra.b op2_xi op2_fp0: fmovem.x fp0,USER_FP0(a6) bra.b op2_xi op2_fp3: fmovem.x fp3,USER_FP3(a6) * * The frame returned is idle. We must build a busy frame to hold * the cu state information and fix up etemp. * op2_xi: move.l #22,d0 ;clear 23 lwords clr.l (a7) op2_loop: clr.l -(a7) dbf d0,op2_loop move.l #$40600000,-(a7) move.l L_SCR1(a6),STAG(a6) move.l L_SCR2(a6),CMDREG1B(a6) move.l L_SCR3(a6),DTAG(a6) move.b #$6,CU_SAVEPC(a6) move.l FP_SCR2(a6),ETEMP(a6) move.l FP_SCR2+4(a6),ETEMP_HI(a6) move.l FP_SCR2+8(a6),ETEMP_LO(a6) move.l d1,-(a7) bra op2_com * * We have the opclass 2 single source situation. * op2_com: move.b #$15,d0 bfins d0,CMDREG1B(a6){0:6} ;opclass 2, double cmp.w #$407F,ETEMP_EX(a6) ;single +max bne.b case2 move.w #$43FF,ETEMP_EX(a6) ;to double +max bra finish case2: cmp.w #$C07F,ETEMP_EX(a6) ;single -max bne.b case3 move.w #$C3FF,ETEMP_EX(a6) ;to double -max bra finish case3: cmp.w #$3F80,ETEMP_EX(a6) ;single +min bne.b case4 move.w #$3C00,ETEMP_EX(a6) ;to double +min bra finish case4: cmp.w #$BF80,ETEMP_EX(a6) ;single -min bne fix_done move.w #$BC00,ETEMP_EX(a6) ;to double -min bra finish * * The frame returned is busy. It is not possible to reconstruct * the code sequence to allow completion. fpsp_fmt_error causes * an fline illegal instruction to be executed. * * You should replace the jump to fpsp_fmt_error with a jump * to the entry point used to kill a process. * op2_xb: jmp fpsp_fmt_error * * Enter here if the case is not of the situations affected by * bug #1238, or if the fix is completed, and exit. * finish: fix_done: rts end