1 * $NetBSD: bugfix.sa,v 1.3 1994/10/26 07:48:55 cgd Exp $
3 * MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
4 * M68000 Hi-Performance Microprocessor Division
5 * M68040 Software Package
7 * M68040 Software Package Copyright (c) 1993, 1994 Motorola Inc.
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.
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.
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.
34 * bugfix.sa 3.2 1/31/91
37 * This file contains workarounds for bugs in the 040
38 * relating to the Floating-Point Software Package (FPSP)
40 * Fixes for bugs: 1238
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,
52 * if (E3_exception_just_serviced) {
53 * dirty_bit[cmdreg3b[9:7]] = 0;
56 * if (fsave_format_version != $40) {goto NOFIX}
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}
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.
72 * * if (fpiarcu == integer stack return address) {
78 * if (cmdreg1b[15:13] != 000) {goto FIX_OPCLASS2}
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 */
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];
93 * CUPC[fsave_frame] = 0000000;
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.
101 * if (fsave_frame_format == $4060) {goto KILL_PROCESS}
103 * fsave_frame = /* build a long frame of all zeros */
104 * fsave_frame_format = $4060; /* label it as long frame */
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;
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.
118 * /* All done. Proceed with the code below */
121 * etemp = FP_reg_[cmdreg1b[12:10]];
123 * cmdreg1b[15:10] = 010010;
124 * clear(bug_flag_procIDxxxx);
125 * FRESTORE and return;
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 */
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];
141 * CUPC[fsave_frame] = 0000000;
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.
150 * if (fsave_frame_format == $4060) {goto KILL_PROCESS}
152 * fsave_frame = /* build a long frame of all zeros */
153 * fsave_frame_format = $4060; /* label it as long frame */
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;
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.
168 * /* All done. Proceed with the code below */
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;
179 * clear(bug_flag_procIDxxxx);
180 * FRESTORE and return;
183 BUGFIX IDNT 2,1 Motorola 040 Floating Point Software Package
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.
202 * Test for cu_savepc equal to zero. If not, this is not a bug
205 move.b CU_SAVEPC(a6),d0
207 beq fix_done ;if zero, this is not bug #1238
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.
216 * Check for opclass 0. If not, go and check for opclass 2 and sgl.
218 move.w CMDREG1B(a6),d0
219 andi.w #$E000,d0 ;strip all but opclass
220 bne op2sgl ;not opclass 0, check op2
222 * Check for cu and nu register conflict. If one exists, this takes
223 * priority over a cu and xu conflict.
225 bfextu CMDREG1B(a6){3:3},d0 ;get 1st src
226 bfextu CMDREG3B(a6){6:3},d1 ;get 3rd dest
228 beq.b op0 ;if equal, continue bugfix
230 * Check for cu dest equal to nu dest. If so, go and fix the
231 * bug condition. Otherwise, exit.
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
237 * Check for cu and xu register conflict.
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
245 bne fix_done ;if the reg checks fail, exit
247 * We have the opclass 0 situation.
250 bfextu CMDREG1B(a6){3:3},d0 ;get source register no
255 fmovem.x d0,ETEMP(a6) ;load source to ETEMP
258 bfins d0,CMDREG1B(a6){0:6} ;opclass 2, extended
260 * Set ETEMP exponent bit 15 as the opposite of ete14
262 btst #6,ETEMP_EX(a6) ;check etemp exponent bit 14
264 bclr #etemp15_bit,STAG(a6)
267 bset #etemp15_bit,STAG(a6)
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.
281 * Items saved from the stack:
284 * $40 cmdreg1b - L_SCR2
287 * The cu savepc is set to zero, and the frame is restored to the
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)
296 move.l (a7)+,d1 ;save return address from bsr
300 * Check if the instruction which just completed was exceptional.
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
310 bfextu CMDREG2B(a6){6:3},d0 ;get dest register no
318 fmovem.x fp2,USER_FP2(a6)
321 fmovem.x fp1,USER_FP1(a6)
324 fmovem.x fp0,USER_FP0(a6)
327 fmovem.x fp3,USER_FP3(a6)
329 * The frame returned is idle. We must build a busy frame to hold
330 * the cu state information and setup etemp.
333 move.l #22,d0 ;clear 23 lwords
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
349 fmovem.x d0,ETEMP(a6) ;load source to ETEMP
352 bfins d0,CMDREG1B(a6){0:6} ;opclass 2, extended
354 * Set ETEMP exponent bit 15 as the opposite of ete14
356 btst #6,ETEMP_EX(a6) ;check etemp exponent bit 14
358 bclr #etemp15_bit,STAG(a6)
361 bset #etemp15_bit,STAG(a6)
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.
373 * Check for opclass 2 and single size. If not both, exit.
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
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.
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
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.
403 * Items saved from the stack:
406 * $40 cmdreg1b - L_SCR2
410 * The cu savepc is set to zero, and the frame is restored to the
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)
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
426 * Check if the instruction which just completed was exceptional.
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
436 bfextu CMDREG2B(a6){6:3},d0 ;get dest register no
444 fmovem.x fp2,USER_FP2(a6)
447 fmovem.x fp1,USER_FP1(a6)
450 fmovem.x fp0,USER_FP0(a6)
453 fmovem.x fp3,USER_FP3(a6)
455 * The frame returned is idle. We must build a busy frame to hold
456 * the cu state information and fix up etemp.
459 move.l #22,d0 ;clear 23 lwords
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)
476 * We have the opclass 2 single source situation.
480 bfins d0,CMDREG1B(a6){0:6} ;opclass 2, double
482 cmp.w #$407F,ETEMP_EX(a6) ;single +max
484 move.w #$43FF,ETEMP_EX(a6) ;to double +max
487 cmp.w #$C07F,ETEMP_EX(a6) ;single -max
489 move.w #$C3FF,ETEMP_EX(a6) ;to double -max
492 cmp.w #$3F80,ETEMP_EX(a6) ;single +min
494 move.w #$3C00,ETEMP_EX(a6) ;to double +min
497 cmp.w #$BF80,ETEMP_EX(a6) ;single -min
499 move.w #$BC00,ETEMP_EX(a6) ;to double -min
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.
506 * You should replace the jump to fpsp_fmt_error with a jump
507 * to the entry point used to kill a process.
513 * Enter here if the case is not of the situations affected by
514 * bug #1238, or if the fix is completed, and exit.