Home | History | Annotate | Line # | Download | only in fpsp
      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