Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | | |
2 | | bugfix.sa 3.2 1/31/91 | |
3 | | | |
4 | | | |
5 | | This file contains workarounds for bugs in the 040 | |
6 | | relating to the Floating-Point Software Package (FPSP) | |
7 | | | |
8 | | Fixes for bugs: 1238 | |
9 | | | |
10 | | Bug: 1238 | |
11 | | | |
12 | | | |
13 | | /* The following dirty_bit clear should be left in | |
14 | | * the handler permanently to improve throughput. | |
15 | | * The dirty_bits are located at bits [23:16] in | |
16 | | * longword $08 in the busy frame $4x60. Bit 16 | |
17 | | * corresponds to FP0, bit 17 corresponds to FP1, | |
18 | | * and so on. | |
19 | | */ | |
20 | | if (E3_exception_just_serviced) { | |
21 | | dirty_bit[cmdreg3b[9:7]] = 0; | |
22 | | } | |
23 | | | |
24 | | if (fsave_format_version != $40) {goto NOFIX} | |
25 | | | |
26 | | if !(E3_exception_just_serviced) {goto NOFIX} | |
27 | | if (cupc == 0000000) {goto NOFIX} | |
28 | | if ((cmdreg1b[15:13] != 000) && | |
29 | | (cmdreg1b[15:10] != 010001)) {goto NOFIX} | |
30 | | if (((cmdreg1b[15:13] != 000) || ((cmdreg1b[12:10] != cmdreg2b[9:7]) && | |
31 | | (cmdreg1b[12:10] != cmdreg3b[9:7])) ) && | |
32 | | ((cmdreg1b[ 9: 7] != cmdreg2b[9:7]) && | |
33 | | (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) ) {goto NOFIX} | |
34 | | | |
35 | | /* Note: for 6d43b or 8d43b, you may want to add the following code | |
36 | | * to get better coverage. (If you do not insert this code, the part | |
37 | | * won't lock up; it will simply get the wrong answer.) | |
38 | | * Do NOT insert this code for 10d43b or later parts. | |
39 | | * | |
40 | | * if (fpiarcu == integer stack return address) { | |
41 | | * cupc = 0000000; | |
42 | | * goto NOFIX; | |
43 | | * } | |
44 | | */ | |
45 | | | |
46 | | if (cmdreg1b[15:13] != 000) {goto FIX_OPCLASS2} | |
47 | | FIX_OPCLASS0: | |
48 | | if (((cmdreg1b[12:10] == cmdreg2b[9:7]) || | |
49 | | (cmdreg1b[ 9: 7] == cmdreg2b[9:7])) && | |
50 | | (cmdreg1b[12:10] != cmdreg3b[9:7]) && | |
51 | | (cmdreg1b[ 9: 7] != cmdreg3b[9:7])) { /* xu conflict only */ | |
52 | | /* We execute the following code if there is an | |
53 | | xu conflict and NOT an nu conflict */ | |
54 | | | |
55 | | /* first save some values on the fsave frame */ | |
56 | | stag_temp = STAG[fsave_frame]; | |
57 | | cmdreg1b_temp = CMDREG1B[fsave_frame]; | |
58 | | dtag_temp = DTAG[fsave_frame]; | |
59 | | ete15_temp = ETE15[fsave_frame]; | |
60 | | | |
61 | | CUPC[fsave_frame] = 0000000; | |
62 | | FRESTORE | |
63 | | FSAVE | |
64 | | | |
65 | | /* If the xu instruction is exceptional, we punt. | |
66 | | * Otherwise, we would have to include OVFL/UNFL handler | |
67 | | * code here to get the correct answer. | |
68 | | */ | |
69 | | if (fsave_frame_format == $4060) {goto KILL_PROCESS} | |
70 | | | |
71 | | fsave_frame = /* build a long frame of all zeros */ | |
72 | | fsave_frame_format = $4060; /* label it as long frame */ | |
73 | | | |
74 | | /* load it with the temps we saved */ | |
75 | | STAG[fsave_frame] = stag_temp; | |
76 | | CMDREG1B[fsave_frame] = cmdreg1b_temp; | |
77 | | DTAG[fsave_frame] = dtag_temp; | |
78 | | ETE15[fsave_frame] = ete15_temp; | |
79 | | | |
80 | | /* Make sure that the cmdreg3b dest reg is not going to | |
81 | | * be destroyed by a FMOVEM at the end of all this code. | |
82 | | * If it is, you should move the current value of the reg | |
83 | | * onto the stack so that the reg will loaded with that value. | |
84 | | */ | |
85 | | | |
86 | | /* All done. Proceed with the code below */ | |
87 | | } | |
88 | | | |
89 | | etemp = FP_reg_[cmdreg1b[12:10]]; | |
90 | | ete15 = ~ete14; | |
91 | | cmdreg1b[15:10] = 010010; | |
92 | | clear(bug_flag_procIDxxxx); | |
93 | | FRESTORE and return; | |
94 | | | |
95 | | | |
96 | | FIX_OPCLASS2: | |
97 | | if ((cmdreg1b[9:7] == cmdreg2b[9:7]) && | |
98 | | (cmdreg1b[9:7] != cmdreg3b[9:7])) { /* xu conflict only */ | |
99 | | /* We execute the following code if there is an | |
100 | | xu conflict and NOT an nu conflict */ | |
101 | | | |
102 | | /* first save some values on the fsave frame */ | |
103 | | stag_temp = STAG[fsave_frame]; | |
104 | | cmdreg1b_temp = CMDREG1B[fsave_frame]; | |
105 | | dtag_temp = DTAG[fsave_frame]; | |
106 | | ete15_temp = ETE15[fsave_frame]; | |
107 | | etemp_temp = ETEMP[fsave_frame]; | |
108 | | | |
109 | | CUPC[fsave_frame] = 0000000; | |
110 | | FRESTORE | |
111 | | FSAVE | |
112 | | | |
113 | | | |
114 | | /* If the xu instruction is exceptional, we punt. | |
115 | | * Otherwise, we would have to include OVFL/UNFL handler | |
116 | | * code here to get the correct answer. | |
117 | | */ | |
118 | | if (fsave_frame_format == $4060) {goto KILL_PROCESS} | |
119 | | | |
120 | | fsave_frame = /* build a long frame of all zeros */ | |
121 | | fsave_frame_format = $4060; /* label it as long frame */ | |
122 | | | |
123 | | /* load it with the temps we saved */ | |
124 | | STAG[fsave_frame] = stag_temp; | |
125 | | CMDREG1B[fsave_frame] = cmdreg1b_temp; | |
126 | | DTAG[fsave_frame] = dtag_temp; | |
127 | | ETE15[fsave_frame] = ete15_temp; | |
128 | | ETEMP[fsave_frame] = etemp_temp; | |
129 | | | |
130 | | /* Make sure that the cmdreg3b dest reg is not going to | |
131 | | * be destroyed by a FMOVEM at the end of all this code. | |
132 | | * If it is, you should move the current value of the reg | |
133 | | * onto the stack so that the reg will loaded with that value. | |
134 | | */ | |
135 | | | |
136 | | /* All done. Proceed with the code below */ | |
137 | | } | |
138 | | | |
139 | | if (etemp_exponent == min_sgl) etemp_exponent = min_dbl; | |
140 | | if (etemp_exponent == max_sgl) etemp_exponent = max_dbl; | |
141 | | cmdreg1b[15:10] = 010101; | |
142 | | clear(bug_flag_procIDxxxx); | |
143 | | FRESTORE and return; | |
144 | | | |
145 | | | |
146 | | NOFIX: | |
147 | | clear(bug_flag_procIDxxxx); | |
148 | | FRESTORE and return; | |
149 | | | |
150 | ||
151 | ||
152 | | Copyright (C) Motorola, Inc. 1990 | |
153 | | All Rights Reserved | |
154 | | | |
e00d82d0 MW |
155 | | For details on the license for this file, please see the |
156 | | file, README, in this same directory. | |
1da177e4 LT |
157 | |
158 | |BUGFIX idnt 2,1 | Motorola 040 Floating Point Software Package | |
159 | ||
160 | |section 8 | |
161 | ||
162 | #include "fpsp.h" | |
163 | ||
164 | |xref fpsp_fmt_error | |
165 | ||
166 | .global b1238_fix | |
167 | b1238_fix: | |
168 | | | |
169 | | This code is entered only on completion of the handling of an | |
170 | | nu-generated ovfl, unfl, or inex exception. If the version | |
171 | | number of the fsave is not $40, this handler is not necessary. | |
172 | | Simply branch to fix_done and exit normally. | |
173 | | | |
174 | cmpib #VER_40,4(%a7) | |
175 | bne fix_done | |
176 | | | |
177 | | Test for cu_savepc equal to zero. If not, this is not a bug | |
178 | | #1238 case. | |
179 | | | |
180 | moveb CU_SAVEPC(%a6),%d0 | |
181 | andib #0xFE,%d0 | |
182 | beq fix_done |if zero, this is not bug #1238 | |
183 | ||
184 | | | |
185 | | Test the register conflict aspect. If opclass0, check for | |
186 | | cu src equal to xu dest or equal to nu dest. If so, go to | |
187 | | op0. Else, or if opclass2, check for cu dest equal to | |
188 | | xu dest or equal to nu dest. If so, go to tst_opcl. Else, | |
189 | | exit, it is not the bug case. | |
190 | | | |
191 | | Check for opclass 0. If not, go and check for opclass 2 and sgl. | |
192 | | | |
193 | movew CMDREG1B(%a6),%d0 | |
194 | andiw #0xE000,%d0 |strip all but opclass | |
195 | bne op2sgl |not opclass 0, check op2 | |
196 | | | |
197 | | Check for cu and nu register conflict. If one exists, this takes | |
198 | | priority over a cu and xu conflict. | |
199 | | | |
200 | bfextu CMDREG1B(%a6){#3:#3},%d0 |get 1st src | |
201 | bfextu CMDREG3B(%a6){#6:#3},%d1 |get 3rd dest | |
202 | cmpb %d0,%d1 | |
203 | beqs op0 |if equal, continue bugfix | |
204 | | | |
205 | | Check for cu dest equal to nu dest. If so, go and fix the | |
206 | | bug condition. Otherwise, exit. | |
207 | | | |
208 | bfextu CMDREG1B(%a6){#6:#3},%d0 |get 1st dest | |
209 | cmpb %d0,%d1 |cmp 1st dest with 3rd dest | |
210 | beqs op0 |if equal, continue bugfix | |
211 | | | |
212 | | Check for cu and xu register conflict. | |
213 | | | |
214 | bfextu CMDREG2B(%a6){#6:#3},%d1 |get 2nd dest | |
215 | cmpb %d0,%d1 |cmp 1st dest with 2nd dest | |
216 | beqs op0_xu |if equal, continue bugfix | |
217 | bfextu CMDREG1B(%a6){#3:#3},%d0 |get 1st src | |
218 | cmpb %d0,%d1 |cmp 1st src with 2nd dest | |
219 | beq op0_xu | |
220 | bne fix_done |if the reg checks fail, exit | |
221 | | | |
222 | | We have the opclass 0 situation. | |
223 | | | |
224 | op0: | |
225 | bfextu CMDREG1B(%a6){#3:#3},%d0 |get source register no | |
226 | movel #7,%d1 | |
227 | subl %d0,%d1 | |
228 | clrl %d0 | |
229 | bsetl %d1,%d0 | |
230 | fmovemx %d0,ETEMP(%a6) |load source to ETEMP | |
231 | ||
232 | moveb #0x12,%d0 | |
233 | bfins %d0,CMDREG1B(%a6){#0:#6} |opclass 2, extended | |
234 | | | |
235 | | Set ETEMP exponent bit 15 as the opposite of ete14 | |
236 | | | |
237 | btst #6,ETEMP_EX(%a6) |check etemp exponent bit 14 | |
238 | beq setete15 | |
239 | bclr #etemp15_bit,STAG(%a6) | |
240 | bra finish | |
241 | setete15: | |
242 | bset #etemp15_bit,STAG(%a6) | |
243 | bra finish | |
244 | ||
245 | | | |
246 | | We have the case in which a conflict exists between the cu src or | |
247 | | dest and the dest of the xu. We must clear the instruction in | |
248 | | the cu and restore the state, allowing the instruction in the | |
249 | | xu to complete. Remember, the instruction in the nu | |
250 | | was exceptional, and was completed by the appropriate handler. | |
251 | | If the result of the xu instruction is not exceptional, we can | |
252 | | restore the instruction from the cu to the frame and continue | |
253 | | processing the original exception. If the result is also | |
254 | | exceptional, we choose to kill the process. | |
255 | | | |
256 | | Items saved from the stack: | |
257 | | | |
258 | | $3c stag - L_SCR1 | |
259 | | $40 cmdreg1b - L_SCR2 | |
260 | | $44 dtag - L_SCR3 | |
261 | | | |
262 | | The cu savepc is set to zero, and the frame is restored to the | |
263 | | fpu. | |
264 | | | |
265 | op0_xu: | |
266 | movel STAG(%a6),L_SCR1(%a6) | |
267 | movel CMDREG1B(%a6),L_SCR2(%a6) | |
268 | movel DTAG(%a6),L_SCR3(%a6) | |
269 | andil #0xe0000000,L_SCR3(%a6) | |
270 | moveb #0,CU_SAVEPC(%a6) | |
271 | movel (%a7)+,%d1 |save return address from bsr | |
272 | frestore (%a7)+ | |
273 | fsave -(%a7) | |
274 | | | |
275 | | Check if the instruction which just completed was exceptional. | |
276 | | | |
277 | cmpw #0x4060,(%a7) | |
278 | beq op0_xb | |
279 | | | |
280 | | It is necessary to isolate the result of the instruction in the | |
281 | | xu if it is to fp0 - fp3 and write that value to the USER_FPn | |
282 | | locations on the stack. The correct destination register is in | |
283 | | cmdreg2b. | |
284 | | | |
285 | bfextu CMDREG2B(%a6){#6:#3},%d0 |get dest register no | |
286 | cmpil #3,%d0 | |
287 | bgts op0_xi | |
288 | beqs op0_fp3 | |
289 | cmpil #1,%d0 | |
290 | blts op0_fp0 | |
291 | beqs op0_fp1 | |
292 | op0_fp2: | |
293 | fmovemx %fp2-%fp2,USER_FP2(%a6) | |
294 | bras op0_xi | |
295 | op0_fp1: | |
296 | fmovemx %fp1-%fp1,USER_FP1(%a6) | |
297 | bras op0_xi | |
298 | op0_fp0: | |
299 | fmovemx %fp0-%fp0,USER_FP0(%a6) | |
300 | bras op0_xi | |
301 | op0_fp3: | |
302 | fmovemx %fp3-%fp3,USER_FP3(%a6) | |
303 | | | |
304 | | The frame returned is idle. We must build a busy frame to hold | |
305 | | the cu state information and setup etemp. | |
306 | | | |
307 | op0_xi: | |
308 | movel #22,%d0 |clear 23 lwords | |
309 | clrl (%a7) | |
310 | op0_loop: | |
311 | clrl -(%a7) | |
312 | dbf %d0,op0_loop | |
313 | movel #0x40600000,-(%a7) | |
314 | movel L_SCR1(%a6),STAG(%a6) | |
315 | movel L_SCR2(%a6),CMDREG1B(%a6) | |
316 | movel L_SCR3(%a6),DTAG(%a6) | |
317 | moveb #0x6,CU_SAVEPC(%a6) | |
318 | movel %d1,-(%a7) |return bsr return address | |
319 | bfextu CMDREG1B(%a6){#3:#3},%d0 |get source register no | |
320 | movel #7,%d1 | |
321 | subl %d0,%d1 | |
322 | clrl %d0 | |
323 | bsetl %d1,%d0 | |
324 | fmovemx %d0,ETEMP(%a6) |load source to ETEMP | |
325 | ||
326 | moveb #0x12,%d0 | |
327 | bfins %d0,CMDREG1B(%a6){#0:#6} |opclass 2, extended | |
328 | | | |
329 | | Set ETEMP exponent bit 15 as the opposite of ete14 | |
330 | | | |
331 | btst #6,ETEMP_EX(%a6) |check etemp exponent bit 14 | |
332 | beq op0_sete15 | |
333 | bclr #etemp15_bit,STAG(%a6) | |
334 | bra finish | |
335 | op0_sete15: | |
336 | bset #etemp15_bit,STAG(%a6) | |
337 | bra finish | |
338 | ||
339 | | | |
340 | | The frame returned is busy. It is not possible to reconstruct | |
341 | | the code sequence to allow completion. We will jump to | |
342 | | fpsp_fmt_error and allow the kernel to kill the process. | |
343 | | | |
344 | op0_xb: | |
345 | jmp fpsp_fmt_error | |
346 | ||
347 | | | |
348 | | Check for opclass 2 and single size. If not both, exit. | |
349 | | | |
350 | op2sgl: | |
351 | movew CMDREG1B(%a6),%d0 | |
352 | andiw #0xFC00,%d0 |strip all but opclass and size | |
353 | cmpiw #0x4400,%d0 |test for opclass 2 and size=sgl | |
354 | bne fix_done |if not, it is not bug 1238 | |
355 | | | |
356 | | Check for cu dest equal to nu dest or equal to xu dest, with | |
357 | | a cu and nu conflict taking priority an nu conflict. If either, | |
358 | | go and fix the bug condition. Otherwise, exit. | |
359 | | | |
360 | bfextu CMDREG1B(%a6){#6:#3},%d0 |get 1st dest | |
361 | bfextu CMDREG3B(%a6){#6:#3},%d1 |get 3rd dest | |
362 | cmpb %d0,%d1 |cmp 1st dest with 3rd dest | |
363 | beq op2_com |if equal, continue bugfix | |
364 | bfextu CMDREG2B(%a6){#6:#3},%d1 |get 2nd dest | |
365 | cmpb %d0,%d1 |cmp 1st dest with 2nd dest | |
366 | bne fix_done |if the reg checks fail, exit | |
367 | | | |
368 | | We have the case in which a conflict exists between the cu src or | |
369 | | dest and the dest of the xu. We must clear the instruction in | |
370 | | the cu and restore the state, allowing the instruction in the | |
371 | | xu to complete. Remember, the instruction in the nu | |
372 | | was exceptional, and was completed by the appropriate handler. | |
373 | | If the result of the xu instruction is not exceptional, we can | |
374 | | restore the instruction from the cu to the frame and continue | |
375 | | processing the original exception. If the result is also | |
376 | | exceptional, we choose to kill the process. | |
377 | | | |
378 | | Items saved from the stack: | |
379 | | | |
380 | | $3c stag - L_SCR1 | |
381 | | $40 cmdreg1b - L_SCR2 | |
382 | | $44 dtag - L_SCR3 | |
383 | | etemp - FP_SCR2 | |
384 | | | |
385 | | The cu savepc is set to zero, and the frame is restored to the | |
386 | | fpu. | |
387 | | | |
388 | op2_xu: | |
389 | movel STAG(%a6),L_SCR1(%a6) | |
390 | movel CMDREG1B(%a6),L_SCR2(%a6) | |
391 | movel DTAG(%a6),L_SCR3(%a6) | |
392 | andil #0xe0000000,L_SCR3(%a6) | |
393 | moveb #0,CU_SAVEPC(%a6) | |
394 | movel ETEMP(%a6),FP_SCR2(%a6) | |
395 | movel ETEMP_HI(%a6),FP_SCR2+4(%a6) | |
396 | movel ETEMP_LO(%a6),FP_SCR2+8(%a6) | |
397 | movel (%a7)+,%d1 |save return address from bsr | |
398 | frestore (%a7)+ | |
399 | fsave -(%a7) | |
400 | | | |
401 | | Check if the instruction which just completed was exceptional. | |
402 | | | |
403 | cmpw #0x4060,(%a7) | |
404 | beq op2_xb | |
405 | | | |
406 | | It is necessary to isolate the result of the instruction in the | |
407 | | xu if it is to fp0 - fp3 and write that value to the USER_FPn | |
408 | | locations on the stack. The correct destination register is in | |
409 | | cmdreg2b. | |
410 | | | |
411 | bfextu CMDREG2B(%a6){#6:#3},%d0 |get dest register no | |
412 | cmpil #3,%d0 | |
413 | bgts op2_xi | |
414 | beqs op2_fp3 | |
415 | cmpil #1,%d0 | |
416 | blts op2_fp0 | |
417 | beqs op2_fp1 | |
418 | op2_fp2: | |
419 | fmovemx %fp2-%fp2,USER_FP2(%a6) | |
420 | bras op2_xi | |
421 | op2_fp1: | |
422 | fmovemx %fp1-%fp1,USER_FP1(%a6) | |
423 | bras op2_xi | |
424 | op2_fp0: | |
425 | fmovemx %fp0-%fp0,USER_FP0(%a6) | |
426 | bras op2_xi | |
427 | op2_fp3: | |
428 | fmovemx %fp3-%fp3,USER_FP3(%a6) | |
429 | | | |
430 | | The frame returned is idle. We must build a busy frame to hold | |
431 | | the cu state information and fix up etemp. | |
432 | | | |
433 | op2_xi: | |
434 | movel #22,%d0 |clear 23 lwords | |
435 | clrl (%a7) | |
436 | op2_loop: | |
437 | clrl -(%a7) | |
438 | dbf %d0,op2_loop | |
439 | movel #0x40600000,-(%a7) | |
440 | movel L_SCR1(%a6),STAG(%a6) | |
441 | movel L_SCR2(%a6),CMDREG1B(%a6) | |
442 | movel L_SCR3(%a6),DTAG(%a6) | |
443 | moveb #0x6,CU_SAVEPC(%a6) | |
444 | movel FP_SCR2(%a6),ETEMP(%a6) | |
445 | movel FP_SCR2+4(%a6),ETEMP_HI(%a6) | |
446 | movel FP_SCR2+8(%a6),ETEMP_LO(%a6) | |
447 | movel %d1,-(%a7) | |
448 | bra op2_com | |
449 | ||
450 | | | |
451 | | We have the opclass 2 single source situation. | |
452 | | | |
453 | op2_com: | |
454 | moveb #0x15,%d0 | |
455 | bfins %d0,CMDREG1B(%a6){#0:#6} |opclass 2, double | |
456 | ||
457 | cmpw #0x407F,ETEMP_EX(%a6) |single +max | |
458 | bnes case2 | |
459 | movew #0x43FF,ETEMP_EX(%a6) |to double +max | |
460 | bra finish | |
461 | case2: | |
462 | cmpw #0xC07F,ETEMP_EX(%a6) |single -max | |
463 | bnes case3 | |
464 | movew #0xC3FF,ETEMP_EX(%a6) |to double -max | |
465 | bra finish | |
466 | case3: | |
467 | cmpw #0x3F80,ETEMP_EX(%a6) |single +min | |
468 | bnes case4 | |
469 | movew #0x3C00,ETEMP_EX(%a6) |to double +min | |
470 | bra finish | |
471 | case4: | |
472 | cmpw #0xBF80,ETEMP_EX(%a6) |single -min | |
473 | bne fix_done | |
474 | movew #0xBC00,ETEMP_EX(%a6) |to double -min | |
475 | bra finish | |
476 | | | |
477 | | The frame returned is busy. It is not possible to reconstruct | |
478 | | the code sequence to allow completion. fpsp_fmt_error causes | |
479 | | an fline illegal instruction to be executed. | |
480 | | | |
481 | | You should replace the jump to fpsp_fmt_error with a jump | |
482 | | to the entry point used to kill a process. | |
483 | | | |
484 | op2_xb: | |
485 | jmp fpsp_fmt_error | |
486 | ||
487 | | | |
488 | | Enter here if the case is not of the situations affected by | |
489 | | bug #1238, or if the fix is completed, and exit. | |
490 | | | |
491 | finish: | |
492 | fix_done: | |
493 | rts | |
494 | ||
495 | |end |