* $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