xref: /netbsd/sys/arch/m68k/fpsp/bugfix.sa (revision bf9ec67e)
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