No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / m68k / fpsp / bugfix.sa
blob31d86aecc936f96f403ff77dc5449d364df621dc
1 *       $NetBSD$
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.
8 *       All rights reserved.
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
42 *       Bug: 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,
50 *     * and so on.
51 *     */
52 *    if  (E3_exception_just_serviced)   {
53 *         dirty_bit[cmdreg3b[9:7]] = 0;
54 *         }
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.
71 *     *
72 *     *  if (fpiarcu == integer stack return address) {
73 *     *       cupc = 0000000;
74 *     *       goto NOFIX;
75 *     *       }
76 *     */
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 */
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;
94 *       FRESTORE
95 *       FSAVE
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}
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.
116 *        */
118 *       /* All done.  Proceed with the code below */
119 *    }
121 *    etemp  = FP_reg_[cmdreg1b[12:10]];
122 *    ete15  = ~ete14;
123 *    cmdreg1b[15:10] = 010010;
124 *    clear(bug_flag_procIDxxxx);
125 *    FRESTORE and return;
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 */
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;
142 *       FRESTORE
143 *       FSAVE
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}
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.
166 *        */
168 *       /* All done.  Proceed with the code below */
169 *    }
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;
178 *    NOFIX:
179 *    clear(bug_flag_procIDxxxx);
180 *    FRESTORE and return;
183 BUGFIX    IDNT    2,1 Motorola 040 Floating Point Software Package
185         section 8
187         include fpsp.h
189         xref    fpsp_fmt_error
191         xdef    b1238_fix
192 b1238_fix:
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.
199         cmpi.b  #VER_40,4(a7)
200         bne.w   fix_done
202 * Test for cu_savepc equal to zero.  If not, this is not a bug
203 * #1238 case.
205         move.b  CU_SAVEPC(a6),d0
206         andi.b  #$FE,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
227         cmp.b   d0,d1
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
244         beq     op0_xu
245         bne     fix_done                ;if the reg checks fail, exit
247 * We have the opclass 0 situation.
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
257         move.b  #$12,d0
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
263         beq     setete15
264         bclr    #etemp15_bit,STAG(a6)
265         bra     finish
266 setete15:
267         bset    #etemp15_bit,STAG(a6)
268         bra     finish
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:
282 *       
283 *               $3c stag     - L_SCR1
284 *               $40 cmdreg1b - L_SCR2
285 *               $44 dtag     - L_SCR3
287 * The cu savepc is set to zero, and the frame is restored to the
288 * fpu.
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)
300 * Check if the instruction which just completed was exceptional.
302         cmp.w   #$4060,(a7)
303         beq     op0_xb
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.
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)
329 * The frame returned is idle.  We must build a busy frame to hold
330 * the cu state information and setup etemp.
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
351         move.b  #$12,d0
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
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
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.
369 op0_xb:
370         jmp     fpsp_fmt_error
373 * Check for opclass 2 and single size.  If not both, exit.
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
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:
404 *       
405 *               $3c stag     - L_SCR1
406 *               $40 cmdreg1b - L_SCR2
407 *               $44 dtag     - L_SCR3
408 *               etemp        - FP_SCR2
410 * The cu savepc is set to zero, and the frame is restored to the
411 * fpu.
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)
426 * Check if the instruction which just completed was exceptional.
428         cmp.w   #$4060,(a7)
429         beq     op2_xb
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.
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)
455 * The frame returned is idle.  We must build a busy frame to hold
456 * the cu state information and fix up etemp.
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
476 * We have the opclass 2 single source situation.
478 op2_com:
479         move.b  #$15,d0
480         bfins   d0,CMDREG1B(a6){0:6}    ;opclass 2, double
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
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. 
509 op2_xb:
510         jmp     fpsp_fmt_error
513 * Enter here if the case is not of the situations affected by
514 * bug #1238, or if the fix is completed, and exit.
516 finish:
517 fix_done:
518         rts
520         end