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