|
|
1.1.1.4 root 1: /* $NetBSD: fpu_emulate.c,v 1.41 2023/09/17 13:14:08 andvar Exp $ */
1.1 root 2:
3: /*
4: * Copyright (c) 1995 Gordon W. Ross
5: * some portion Copyright (c) 1995 Ken Nakata
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. The name of the author may not be used to endorse or promote products
17: * derived from this software without specific prior written permission.
18: * 4. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by Gordon Ross
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34: /*
35: * mc68881 emulator
36: * XXX - Just a start at it for now...
37: */
38:
39: #include "fpu_emulate.h"
40:
41: #define fpe_abort(tfp, ksi, signo, code) \
42: do { \
43: (ksi)->ksi_signo = (signo); \
44: (ksi)->ksi_code = (code); \
45: (ksi)->ksi_addr = (void *)(frame)->f_pc; \
46: return -1; \
47: } while (/* CONSTCOND */ 0)
48:
49: #if !defined(XM6i_FPE)
50: static int fpu_emul_fmovmcr(struct fpemu *, struct instruction *);
51: static int fpu_emul_fmovm(struct fpemu *, struct instruction *);
52: static int fpu_emul_arith(struct fpemu *, struct instruction *);
53: static int fpu_emul_type1(struct fpemu *, struct instruction *);
54: static int fpu_emul_brcc(struct fpemu *, struct instruction *);
55: static int test_cc(struct fpemu *, int);
56: #endif
57:
58: #ifdef DEBUG_FPE
59: #include <stdio.h>
60: #define DUMP_INSN(insn) \
61: printf("%s: insn={adv=%d,siz=%d,op=%04x,w1=%04x}\n", \
62: __func__, \
63: (insn)->is_advance, (insn)->is_datasize, \
64: (insn)->is_opcode, (insn)->is_word1)
65: #define DPRINTF(x) printf x
66: #else
67: #define DUMP_INSN(insn) do {} while (/* CONSTCOND */ 0)
68: #define DPRINTF(x) do {} while (/* CONSTCOND */ 0)
69: #endif
70:
71: #if !defined(XM6i_FPE)
72: /*
73: * Emulate a floating-point instruction.
74: * Return zero for success, else signal number.
75: * (Typically: zero, SIGFPE, SIGILL, SIGSEGV)
76: */
77: int
78: fpu_emulate(struct frame *frame, struct fpframe *fpf, ksiginfo_t *ksi)
79: {
80: static struct instruction insn;
81: static struct fpemu fe;
1.1.1.3 root 82: int optype, sig;
83: unsigned short sval;
1.1 root 84:
85: /* initialize insn.is_datasize to tell it is *not* initialized */
86: insn.is_datasize = -1;
87:
88: fe.fe_frame = frame;
89: fe.fe_fpframe = fpf;
90: fe.fe_fpsr = fpf->fpf_fpsr;
91: fe.fe_fpcr = fpf->fpf_fpcr;
92:
93: DPRINTF(("%s: ENTERING: FPSR=%08x, FPCR=%08x\n",
94: __func__, fe.fe_fpsr, fe.fe_fpcr));
95:
96: /* always set this (to avoid a warning) */
97: insn.is_pc = frame->f_pc;
98: insn.is_nextpc = 0;
99: if (frame->f_format == 4) {
100: /*
101: * A format 4 is generated by the 68{EC,LC}040. The PC is
102: * already set to the instruction following the faulting
103: * instruction. We need to calculate that, anyway. The
104: * fslw is the PC of the faulted instruction, which is what
105: * we expect to be in f_pc.
106: *
107: * XXX - This is a hack; it assumes we at least know the
108: * sizes of all instructions we run across.
109: * XXX TODO: This may not be true, so we might want to save
110: * the PC in order to restore it later.
111: */
112: #if 0
113: insn.is_nextpc = frame->f_pc;
114: #endif
115: insn.is_pc = frame->f_fmt4.f_fslw;
116: frame->f_pc = insn.is_pc;
117: }
118:
1.1.1.3 root 119: if (ufetch_short((void *)(insn.is_pc), &sval)) {
1.1 root 120: DPRINTF(("%s: fault reading opcode\n", __func__));
121: fpe_abort(frame, ksi, SIGSEGV, SEGV_ACCERR);
122: }
123:
1.1.1.3 root 124: if ((sval & 0xf000) != 0xf000) {
1.1 root 125: DPRINTF(("%s: not coproc. insn.: opcode=0x%x\n",
1.1.1.4 root 126: __func__, sval));
1.1 root 127: fpe_abort(frame, ksi, SIGILL, ILL_ILLOPC);
128: }
129:
1.1.1.3 root 130: if ((sval & 0x0E00) != 0x0200) {
1.1.1.4 root 131: DPRINTF(("%s: bad coproc. id: opcode=0x%x\n", __func__, sval));
1.1 root 132: fpe_abort(frame, ksi, SIGILL, ILL_ILLOPC);
133: }
134:
1.1.1.3 root 135: insn.is_opcode = sval;
136: optype = (sval & 0x01C0);
1.1 root 137:
1.1.1.3 root 138: if (ufetch_short((void *)(insn.is_pc + 2), &sval)) {
1.1 root 139: DPRINTF(("%s: fault reading word1\n", __func__));
140: fpe_abort(frame, ksi, SIGSEGV, SEGV_ACCERR);
141: }
1.1.1.3 root 142: insn.is_word1 = sval;
1.1 root 143: /* all FPU instructions are at least 4-byte long */
144: insn.is_advance = 4;
145:
146: DUMP_INSN(&insn);
147:
148: /*
149: * Which family (or type) of opcode is it?
150: * Tests ordered by likelihood (hopefully).
151: * Certainly, type 0 is the most common.
152: */
153: if (optype == 0x0000) {
154: /* type=0: generic */
1.1.1.3 root 155: if ((sval & 0xc000) == 0xc000) {
1.1 root 156: DPRINTF(("%s: fmovm FPr\n", __func__));
157: sig = fpu_emul_fmovm(&fe, &insn);
1.1.1.3 root 158: } else if ((sval & 0xc000) == 0x8000) {
1.1 root 159: DPRINTF(("%s: fmovm FPcr\n", __func__));
160: sig = fpu_emul_fmovmcr(&fe, &insn);
1.1.1.3 root 161: } else if ((sval & 0xe000) == 0x6000) {
1.1 root 162: /* fstore = fmove FPn,mem */
163: DPRINTF(("%s: fmove to mem\n", __func__));
164: sig = fpu_emul_fstore(&fe, &insn);
1.1.1.3 root 165: } else if ((sval & 0xfc00) == 0x5c00) {
1.1 root 166: /* fmovecr */
167: DPRINTF(("%s: fmovecr\n", __func__));
168: sig = fpu_emul_fmovecr(&fe, &insn);
1.1.1.3 root 169: } else if ((sval & 0xa07f) == 0x26) {
1.1 root 170: /* fscale */
171: DPRINTF(("%s: fscale\n", __func__));
172: sig = fpu_emul_fscale(&fe, &insn);
173: } else {
174: DPRINTF(("%s: other type0\n", __func__));
175: /* all other type0 insns are arithmetic */
176: sig = fpu_emul_arith(&fe, &insn);
177: }
178: if (sig == 0) {
179: DPRINTF(("%s: type 0 returned 0\n", __func__));
180: sig = fpu_upd_excp(&fe);
181: }
182: } else if (optype == 0x0080 || optype == 0x00C0) {
183: /* type=2 or 3: fbcc, short or long disp. */
184: DPRINTF(("%s: fbcc %s\n", __func__,
185: (optype & 0x40) ? "long" : "short"));
186: sig = fpu_emul_brcc(&fe, &insn);
187: } else if (optype == 0x0040) {
188: /* type=1: fdbcc, fscc, ftrapcc */
189: DPRINTF(("%s: type1\n", __func__));
190: sig = fpu_emul_type1(&fe, &insn);
191: } else {
192: /* type=4: fsave (privileged) */
193: /* type=5: frestore (privileged) */
194: /* type=6: reserved */
195: /* type=7: reserved */
196: DPRINTF(("%s: bad opcode type: opcode=0x%x\n", __func__,
197: insn.is_opcode));
198: sig = SIGILL;
199: }
200:
201: DUMP_INSN(&insn);
202:
203: /*
204: * XXX it is not clear to me, if we should progress the PC always,
205: * for SIGFPE || 0, or only for 0; however, without SIGFPE, we
206: * don't pass the signalling regression tests. -is
207: */
208: if ((sig == 0) || (sig == SIGFPE))
209: frame->f_pc += insn.is_advance;
210: #if defined(DDB) && defined(DEBUG_FPE)
211: else {
212: printf("%s: sig=%d, opcode=%x, word1=%x\n", __func__,
213: sig, insn.is_opcode, insn.is_word1);
214: kdb_trap(-1, (db_regs_t *)&frame);
215: }
216: #endif
217: #if 0 /* XXX something is wrong */
218: if (frame->f_format == 4) {
219: /* XXX Restore PC -- 68{EC,LC}040 only */
220: if (insn.is_nextpc)
221: frame->f_pc = insn.is_nextpc;
222: }
223: #endif
224:
225: DPRINTF(("%s: EXITING: w/FPSR=%08x, FPCR=%08x\n", __func__,
226: fe.fe_fpsr, fe.fe_fpcr));
227:
228: if (sig)
229: fpe_abort(frame, ksi, sig, 0);
230: return sig;
231: }
232: #endif /* !XM6i_FPE */
233:
234: /* update accrued exception bits and see if there's an FP exception */
235: // 内部用 FPSR:EXCP から FPSR:AEX を更新する。
236: // AEX は積算型(?) なので、常に現在の内部用 FPSR:AEX に OR する。
237: // fe->fe_fpsr (内部用) と fe->fe_fpframe->fpf_fpsr (外部用) 両方の
238: // AEX を更新する。FPSR のうち AEX 以外のバイトには影響を与えない。
239: int
240: fpu_upd_excp(struct fpemu *fe)
241: {
242: uint32_t fpsr;
243: uint32_t fpcr;
244:
245: fpsr = fe->fe_fpsr;
246: fpcr = fe->fe_fpcr;
247: /*
248: * update fpsr accrued exception bits; each insn doesn't have to
249: * update this
250: */
251: if (fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR)) {
252: fpsr |= FPSR_AIOP;
253: }
254: if (fpsr & FPSR_OVFL) {
255: fpsr |= FPSR_AOVFL;
256: }
257: if ((fpsr & FPSR_UNFL) && (fpsr & FPSR_INEX2)) {
258: fpsr |= FPSR_AUNFL;
259: }
260: if (fpsr & FPSR_DZ) {
261: fpsr |= FPSR_ADZ;
262: }
263: if (fpsr & (FPSR_INEX1 | FPSR_INEX2 | FPSR_OVFL)) {
264: fpsr |= FPSR_AINEX;
265: }
266:
267: /* copy AEX byte only */
268: fe->fe_fpsr &= ~FPSR_AEX;
269: fe->fe_fpsr |= (fpsr & FPSR_AEX);
270: fe->fe_fpframe->fpf_fpsr &= ~FPSR_AEX;
271: fe->fe_fpframe->fpf_fpsr |= (fpsr & FPSR_AEX);
272:
273: return (fpsr & fpcr & FPSR_EXCP) ? 1/*SIGFPE*/ : 0;
274: }
275:
276: /* update fpsr according to fp (= result of an fp op) */
277: // fp によって内部 FPSR:CCB を更新し、(ここまでに反映されている分も
278: // 含めた) 内部 FPSR のうち CCB, EXCP, AXE バイトを外部 FPSR にもコピーする。
279: // 外部 FPSR:QTT は更新しない。
280: //
281: // o そのため必ず最後のほうで呼ぶこと。fpu_implode() が FPSR:INEX2 を
282: // 立てるため、その後で呼ばなければいけない。
283: // o FMOD/FREM は QTT バイトを更新するが、それ以外の命令は QTT を更新しては
284: // いけないため、fpu_upd_fpsr() は QTT を外部にコピーしない。
285: // QTT を更新する必要のある FMOD/FREM だけが自力で外部 FPSR を更新すること。
286: uint32_t
287: fpu_upd_fpsr(struct fpemu *fe, struct fpn *fp)
288: {
289: uint32_t fpsr;
290:
291: DPRINTF(("%s: previous fpsr=%08x\n", __func__, fe->fe_fpsr));
292: /* clear all condition code */
293: fpsr = fe->fe_fpsr & ~FPSR_CCB;
294:
295: DPRINTF(("%s: result is a ", __func__));
296: if (fp->fp_sign) {
297: DPRINTF(("negative "));
298: fpsr |= FPSR_NEG;
299: } else {
300: DPRINTF(("positive "));
301: }
302:
303: switch (fp->fp_class) {
304: case FPC_SNAN:
305: DPRINTF(("signaling NAN\n"));
306: fpsr |= (FPSR_NAN | FPSR_SNAN);
307: break;
308: case FPC_QNAN:
309: DPRINTF(("quiet NAN\n"));
310: fpsr |= FPSR_NAN;
311: break;
312: case FPC_ZERO:
313: DPRINTF(("Zero\n"));
314: fpsr |= FPSR_ZERO;
315: break;
316: case FPC_INF:
317: DPRINTF(("Inf\n"));
318: fpsr |= FPSR_INF;
319: break;
320: default:
321: DPRINTF(("Number\n"));
322: /* anything else is treated as if it is a number */
323: break;
324: }
325:
326: /* copy except QTT byte */
327: fe->fe_fpsr = fpsr;
328: fe->fe_fpframe->fpf_fpsr &= FPSR_QTT;
329: fe->fe_fpframe->fpf_fpsr |= (fpsr & ~FPSR_QTT);
330:
331: DPRINTF(("%s: new fpsr=%08x\n", __func__, fe->fe_fpframe->fpf_fpsr));
332:
333: return fpsr;
334: }
335:
336: #if !defined(XM6i_FPE)
337: static int
338: fpu_emul_fmovmcr(struct fpemu *fe, struct instruction *insn)
339: {
340: struct frame *frame = fe->fe_frame;
341: struct fpframe *fpf = fe->fe_fpframe;
342: int sig;
343: int reglist;
344: int fpu_to_mem;
345:
346: /* move to/from control registers */
347: reglist = (insn->is_word1 & 0x1c00) >> 10;
348: /* Bit 13 selects direction (FPU to/from Mem) */
349: fpu_to_mem = insn->is_word1 & 0x2000;
350:
351: insn->is_datasize = 4;
352: insn->is_advance = 4;
353: sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
354: if (sig)
355: return sig;
356:
357: if (reglist != 1 && reglist != 2 && reglist != 4 &&
358: (insn->is_ea.ea_flags & EA_DIRECT)) {
359: /* attempted to copy more than one FPcr to CPU regs */
360: DPRINTF(("%s: tried to copy too many FPcr\n", __func__));
361: return SIGILL;
362: }
363:
364: if (reglist & 4) {
365: /* fpcr */
366: if ((insn->is_ea.ea_flags & EA_DIRECT) &&
367: insn->is_ea.ea_regnum >= 8 /* address reg */) {
368: /* attempted to copy FPCR to An */
369: DPRINTF(("%s: tried to copy FPCR from/to A%d\n",
370: __func__, insn->is_ea.ea_regnum & 7));
371: return SIGILL;
372: }
373: if (fpu_to_mem) {
374: sig = fpu_store_ea(frame, insn, &insn->is_ea,
375: (char *)&fpf->fpf_fpcr);
376: } else {
377: sig = fpu_load_ea(frame, insn, &insn->is_ea,
378: (char *)&fpf->fpf_fpcr);
379: }
380: }
381: if (sig)
382: return sig;
383:
384: if (reglist & 2) {
385: /* fpsr */
386: if ((insn->is_ea.ea_flags & EA_DIRECT) &&
387: insn->is_ea.ea_regnum >= 8 /* address reg */) {
388: /* attempted to copy FPSR to An */
389: DPRINTF(("%s: tried to copy FPSR from/to A%d\n",
390: __func__, insn->is_ea.ea_regnum & 7));
391: return SIGILL;
392: }
393: if (fpu_to_mem) {
394: sig = fpu_store_ea(frame, insn, &insn->is_ea,
395: (char *)&fpf->fpf_fpsr);
396: } else {
397: sig = fpu_load_ea(frame, insn, &insn->is_ea,
398: (char *)&fpf->fpf_fpsr);
399: }
400: }
401: if (sig)
402: return sig;
403:
404: if (reglist & 1) {
405: /* fpiar - can be moved to/from An */
406: if (fpu_to_mem) {
407: sig = fpu_store_ea(frame, insn, &insn->is_ea,
408: (char *)&fpf->fpf_fpiar);
409: } else {
410: sig = fpu_load_ea(frame, insn, &insn->is_ea,
411: (char *)&fpf->fpf_fpiar);
412: }
413: }
414: return sig;
415: }
416:
417: /*
418: * type 0: fmovem
419: * Separated out of fpu_emul_type0 for efficiency.
420: * In this function, we know:
421: * (opcode & 0x01C0) == 0
422: * (word1 & 0x8000) == 0x8000
423: *
424: * No conversion or rounding is done by this instruction,
425: * and the FPSR is not affected.
426: */
427: static int
428: fpu_emul_fmovm(struct fpemu *fe, struct instruction *insn)
429: {
430: struct frame *frame = fe->fe_frame;
431: struct fpframe *fpf = fe->fe_fpframe;
432: int word1, sig;
433: int reglist, regmask, regnum;
434: int fpu_to_mem, order;
435: /* int w1_post_incr; */
436: int *fpregs;
437:
438: insn->is_advance = 4;
439: insn->is_datasize = 12;
440: word1 = insn->is_word1;
441:
442: /* Bit 13 selects direction (FPU to/from Mem) */
443: fpu_to_mem = word1 & 0x2000;
444:
445: /*
446: * Bits 12,11 select register list mode:
447: * 0,0: Static reg list, pre-decr.
448: * 0,1: Dynamic reg list, pre-decr.
449: * 1,0: Static reg list, post-incr.
450: * 1,1: Dynamic reg list, post-incr
451: */
452: /* w1_post_incr = word1 & 0x1000; */
453: if (word1 & 0x0800) {
454: /* dynamic reg list */
455: reglist = frame->f_regs[(word1 & 0x70) >> 4];
456: } else {
457: reglist = word1;
458: }
459: reglist &= 0xFF;
460:
461: /* Get effective address. (modreg=opcode&077) */
462: sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
463: if (sig)
464: return sig;
465:
466: /* Get address of soft coprocessor regs. */
467: fpregs = &fpf->fpf_regs[0];
468:
469: if (insn->is_ea.ea_flags & EA_PREDECR) {
470: regnum = 7;
471: order = -1;
472: } else {
473: regnum = 0;
474: order = 1;
475: }
476:
477: regmask = 0x80;
478: while ((0 <= regnum) && (regnum < 8)) {
479: if (regmask & reglist) {
480: if (fpu_to_mem) {
481: sig = fpu_store_ea(frame, insn, &insn->is_ea,
482: (char *)&fpregs[regnum * 3]);
483: DPRINTF(("%s: FP%d (%08x,%08x,%08x) saved\n",
484: __func__, regnum,
485: fpregs[regnum * 3],
486: fpregs[regnum * 3 + 1],
487: fpregs[regnum * 3 + 2]));
488: } else { /* mem to fpu */
489: sig = fpu_load_ea(frame, insn, &insn->is_ea,
490: (char *)&fpregs[regnum * 3]);
491: DPRINTF(("%s: FP%d (%08x,%08x,%08x) loaded\n",
492: __func__, regnum,
493: fpregs[regnum * 3],
494: fpregs[regnum * 3 + 1],
495: fpregs[regnum * 3 + 2]));
496: }
497: if (sig)
498: break;
499: }
500: regnum += order;
501: regmask >>= 1;
502: }
503:
504: return sig;
505: }
506: #endif /* !XM6i_FPE */
507:
508: #if defined(XM6i_FPE)
509: struct fpn *
510: fpu_sglmul(struct fpemu *fe)
511: {
512: struct fpn *r;
513:
514: if (ISNAN(&fe->fe_f1))
515: return &fe->fe_f1;
516: if (ISNAN(&fe->fe_f2))
517: return &fe->fe_f2;
518:
519: /*
520: * 仮数部を(小数以下) 23bit だけにして「精度」を単精度と同じにする。
521: * FSGLMUL では指数部が単精度の範囲を越えても inf 等にならないし、
522: * 68000PRM.pdf で (精度を落とすにあたり) FPCR の現在の丸めモードに
523: * 関係ないと言っているあたりからも、単精度型に変換するとかではなく、
524: * 仮数部のビットを落とすだけなんだと思う。
525: */
526: fe->fe_f1.fp_mant[1] &= 0xf8000000;
527: fe->fe_f1.fp_mant[2] = 0;
528:
529: fe->fe_f2.fp_mant[1] &= 0xf8000000;
530: fe->fe_f2.fp_mant[2] = 0;
531:
532: r = fpu_mul(fe);
533:
534: fpu_round_prec(fe, r);
535: DUMPFP("sglmul:round", r);
536:
537: // 非正規化数の最小値(最下位ビットだけ1) だったら、
538: // 指数部はそのまま、仮数部を単精度の最下位ビット 1 という状態にする。
539: if (r->fp_exp == -EXT_EXP_BIAS - EXT_FRACBITS + 1 &&
540: r->fp_mant[0] == FP_1 &&
541: r->fp_mant[1] == 0 &&
542: r->fp_mant[2] == 0)
543: {
544: r->fp_exp += EXT_FRACBITS - SNG_FRACBITS - 1;
545: }
546: DUMPFP("sglmul:mod ", r);
547:
548: return r;
549: }
550:
551: struct fpn *
552: fpu_sgldiv(struct fpemu *fe)
553: {
554: struct fpn *r;
555:
556: if (ISNAN(&fe->fe_f1))
557: return &fe->fe_f1;
558: if (ISNAN(&fe->fe_f2))
559: return &fe->fe_f2;
560:
561: fe->fe_f1.fp_mant[1] &= 0xf8000000;
562: fe->fe_f1.fp_mant[2] = 0;
563:
564: fe->fe_f2.fp_mant[1] &= 0xf8000000;
565: fe->fe_f2.fp_mant[2] = 0;
566:
567: r = fpu_div(fe);
568:
569: fpu_round_prec(fe, r);
570: DUMPFP("sgldiv:round", r);
571:
572: if (r->fp_exp == -EXT_EXP_BIAS - EXT_FRACBITS + 1 &&
573: r->fp_mant[0] == FP_1 &&
574: r->fp_mant[1] == 0 &&
575: r->fp_mant[2] == 0)
576: {
577: r->fp_exp += EXT_FRACBITS - SNG_FRACBITS - 1;
578: }
579: DUMPFP("sgldiv:mod ", r);
580:
581: return r;
582: }
583: #endif /* XM6i_FPE */
584:
585: #if !defined(XM6i_FPE)
586: /*
1.1.1.3 root 587: * arithmetic operations
1.1 root 588: */
589: static int
590: fpu_emul_arith(struct fpemu *fe, struct instruction *insn)
591: {
592: struct frame *frame = fe->fe_frame;
593: uint32_t *fpregs = &(fe->fe_fpframe->fpf_regs[0]);
594: struct fpn *res;
595: int word1, sig = 0;
596: int regnum, format;
597: int discard_result = 0;
598: uint32_t buf[3];
599: #ifdef DEBUG_FPE
600: int flags;
601: char regname;
602: #endif
603:
604: fe->fe_fpsr &= ~FPSR_EXCP;
605:
606: DUMP_INSN(insn);
607:
608: DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__,
609: fe->fe_fpsr, fe->fe_fpcr));
610:
611: word1 = insn->is_word1;
612: format = (word1 >> 10) & 7;
613: regnum = (word1 >> 7) & 7;
614:
615: /* fetch a source operand : may not be used */
616: DPRINTF(("%s: dst/src FP%d=%08x,%08x,%08x\n", __func__,
617: regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
618: fpregs[regnum * 3 + 2]));
619:
620: fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &fpregs[regnum * 3]);
621:
622: DUMP_INSN(insn);
623:
624: /* get the other operand which is always the source */
625: if ((word1 & 0x4000) == 0) {
626: DPRINTF(("%s: FP%d op FP%d => FP%d\n", __func__,
627: format, regnum, regnum));
628: DPRINTF(("%s: src opr FP%d=%08x,%08x,%08x\n", __func__,
629: format, fpregs[format * 3], fpregs[format * 3 + 1],
630: fpregs[format * 3 + 2]));
631: fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
632: } else {
633: /* the operand is in memory */
634: if (format == FTYPE_DBL) {
635: insn->is_datasize = 8;
636: } else if (format == FTYPE_SNG || format == FTYPE_LNG) {
637: insn->is_datasize = 4;
638: } else if (format == FTYPE_WRD) {
639: insn->is_datasize = 2;
640: } else if (format == FTYPE_BYT) {
641: insn->is_datasize = 1;
642: } else if (format == FTYPE_EXT) {
643: insn->is_datasize = 12;
644: } else {
645: /* invalid or unsupported operand format */
646: sig = SIGFPE;
647: return sig;
648: }
649:
650: /* Get effective address. (modreg=opcode&077) */
651: sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
652: if (sig) {
653: DPRINTF(("%s: error in fpu_decode_ea\n", __func__));
654: return sig;
655: }
656:
657: DUMP_INSN(insn);
658:
659: #ifdef DEBUG_FPE
660: printf("%s: addr mode = ", __func__);
661: flags = insn->is_ea.ea_flags;
662: regname = (insn->is_ea.ea_regnum & 8) ? 'a' : 'd';
663:
664: if (flags & EA_DIRECT) {
665: printf("%c%d\n", regname, insn->is_ea.ea_regnum & 7);
666: } else if (flags & EA_PC_REL) {
667: if (flags & EA_OFFSET) {
668: printf("pc@(%d)\n", insn->is_ea.ea_offset);
669: } else if (flags & EA_INDEXED) {
670: printf("pc@(...)\n");
671: }
672: } else if (flags & EA_PREDECR) {
673: printf("%c%d@-\n", regname, insn->is_ea.ea_regnum & 7);
674: } else if (flags & EA_POSTINCR) {
675: printf("%c%d@+\n", regname, insn->is_ea.ea_regnum & 7);
676: } else if (flags & EA_OFFSET) {
677: printf("%c%d@(%d)\n", regname,
678: insn->is_ea.ea_regnum & 7,
679: insn->is_ea.ea_offset);
680: } else if (flags & EA_INDEXED) {
681: printf("%c%d@(...)\n", regname,
682: insn->is_ea.ea_regnum & 7);
683: } else if (flags & EA_ABS) {
684: printf("0x%08x\n", insn->is_ea.ea_absaddr);
685: } else if (flags & EA_IMMED) {
686: printf("#0x%08x,%08x,%08x\n",
687: insn->is_ea.ea_immed[0],
688: insn->is_ea.ea_immed[1],
689: insn->is_ea.ea_immed[2]);
690: } else {
691: printf("%c%d@\n", regname, insn->is_ea.ea_regnum & 7);
692: }
693: #endif /* DEBUG_FPE */
694:
695: fpu_load_ea(frame, insn, &insn->is_ea, (char*)buf);
696: if (format == FTYPE_WRD) {
697: /* sign-extend */
698: buf[0] &= 0xffff;
699: if (buf[0] & 0x8000)
700: buf[0] |= 0xffff0000;
701: format = FTYPE_LNG;
702: } else if (format == FTYPE_BYT) {
703: /* sign-extend */
704: buf[0] &= 0xff;
705: if (buf[0] & 0x80)
706: buf[0] |= 0xffffff00;
707: format = FTYPE_LNG;
708: }
709: DPRINTF(("%s: src = %08x %08x %08x, siz = %d\n", __func__,
710: buf[0], buf[1], buf[2], insn->is_datasize));
711: fpu_explode(fe, &fe->fe_f2, format, buf);
712: }
713:
714: DUMP_INSN(insn);
715:
716: /*
717: * An arithmetic instruction emulate function has a prototype of
718: * struct fpn *fpu_op(struct fpemu *);
719: *
720: * 1) If the instruction is monadic, then fpu_op() must use
721: * fe->fe_f2 as its operand, and return a pointer to the
722: * result.
723: *
724: * 2) If the instruction is diadic, then fpu_op() must use
725: * fe->fe_f1 and fe->fe_f2 as its two operands, and return a
726: * pointer to the result.
727: *
728: */
729: res = NULL;
730: switch (word1 & 0x7f) {
731: case 0x00: /* fmove */
732: res = &fe->fe_f2;
733: break;
734:
735: case 0x01: /* fint */
736: res = fpu_int(fe);
737: break;
738:
739: case 0x02: /* fsinh */
740: res = fpu_sinh(fe);
741: break;
742:
743: case 0x03: /* fintrz */
744: res = fpu_intrz(fe);
745: break;
746:
747: case 0x04: /* fsqrt */
748: res = fpu_sqrt(fe);
749: break;
750:
751: case 0x06: /* flognp1 */
752: res = fpu_lognp1(fe);
753: break;
754:
755: case 0x08: /* fetoxm1 */
756: res = fpu_etoxm1(fe);
757: break;
758:
759: case 0x09: /* ftanh */
760: res = fpu_tanh(fe);
761: break;
762:
763: case 0x0A: /* fatan */
764: res = fpu_atan(fe);
765: break;
766:
767: case 0x0C: /* fasin */
768: res = fpu_asin(fe);
769: break;
770:
771: case 0x0D: /* fatanh */
772: res = fpu_atanh(fe);
773: break;
774:
775: case 0x0E: /* fsin */
776: res = fpu_sin(fe);
777: break;
778:
779: case 0x0F: /* ftan */
780: res = fpu_tan(fe);
781: break;
782:
783: case 0x10: /* fetox */
784: res = fpu_etox(fe);
785: break;
786:
787: case 0x11: /* ftwotox */
788: res = fpu_twotox(fe);
789: break;
790:
791: case 0x12: /* ftentox */
792: res = fpu_tentox(fe);
793: break;
794:
795: case 0x14: /* flogn */
796: res = fpu_logn(fe);
797: break;
798:
799: case 0x15: /* flog10 */
800: res = fpu_log10(fe);
801: break;
802:
803: case 0x16: /* flog2 */
804: res = fpu_log2(fe);
805: break;
806:
807: case 0x18: /* fabs */
808: fe->fe_f2.fp_sign = 0;
809: res = &fe->fe_f2;
810: break;
811:
812: case 0x19: /* fcosh */
813: res = fpu_cosh(fe);
814: break;
815:
816: case 0x1A: /* fneg */
817: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
818: res = &fe->fe_f2;
819: break;
820:
821: case 0x1C: /* facos */
822: res = fpu_acos(fe);
823: break;
824:
825: case 0x1D: /* fcos */
826: res = fpu_cos(fe);
827: break;
828:
829: case 0x1E: /* fgetexp */
830: res = fpu_getexp(fe);
831: break;
832:
833: case 0x1F: /* fgetman */
834: res = fpu_getman(fe);
835: break;
836:
837: case 0x20: /* fdiv */
838: case 0x24: /* fsgldiv: cheating - better than nothing */
839: res = fpu_div(fe);
840: break;
841:
842: case 0x21: /* fmod */
843: res = fpu_mod(fe);
844: break;
845:
846: case 0x28: /* fsub */
847: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
848: /* FALLTHROUGH */
849: case 0x22: /* fadd */
850: res = fpu_add(fe);
851: break;
852:
853: case 0x23: /* fmul */
854: case 0x27: /* fsglmul: cheating - better than nothing */
855: res = fpu_mul(fe);
856: break;
857:
858: case 0x25: /* frem */
859: res = fpu_rem(fe);
860: break;
861:
862: case 0x26:
863: /* fscale is handled by a separate function */
864: break;
865:
866: case 0x30:
867: case 0x31:
868: case 0x32:
869: case 0x33:
870: case 0x34:
871: case 0x35:
872: case 0x36:
873: case 0x37: /* fsincos */
874: res = fpu_sincos(fe, word1 & 7);
875: break;
876:
877: case 0x38: /* fcmp */
878: res = fpu_cmp(fe);
879: discard_result = 1;
880: break;
881:
882: case 0x3A: /* ftst */
883: res = &fe->fe_f2;
884: discard_result = 1;
885: break;
886:
887: default: /* possibly 040/060 instructions */
888: DPRINTF(("%s: bad opcode=0x%x, word1=0x%x\n", __func__,
889: insn->is_opcode, insn->is_word1));
890: sig = SIGILL;
891: }
892:
893: /* for sanity */
894: if (res == NULL)
895: sig = SIGILL;
896:
897: if (sig == 0) {
898: if (!discard_result)
899: fpu_implode(fe, res, FTYPE_EXT, &fpregs[regnum * 3]);
900:
901: /* update fpsr according to the result of operation */
902: fpu_upd_fpsr(fe, res);
903: #ifdef DEBUG_FPE
904: if (!discard_result) {
905: printf("%s: %08x,%08x,%08x stored in FP%d\n", __func__,
906: fpregs[regnum * 3],
907: fpregs[regnum * 3 + 1],
908: fpregs[regnum * 3 + 2],
909: regnum);
910: } else {
911: static const char *class_name[] =
912: { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
913: printf("%s: result(%s,%c,%d,%08x,%08x,%08x) "
914: "discarded\n", __func__,
915: class_name[res->fp_class + 2],
916: res->fp_sign ? '-' : '+', res->fp_exp,
917: res->fp_mant[0], res->fp_mant[1],
918: res->fp_mant[2]);
919: }
920: #endif
921: } else {
922: DPRINTF(("%s: received signal %d\n", __func__, sig));
923: }
924:
925: DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__,
926: fe->fe_fpsr, fe->fe_fpcr));
927:
928: DUMP_INSN(insn);
929:
930: return sig;
931: }
932: #endif /* !XM6i_FPE */
933:
934: /*
935: * test condition code according to the predicate in the opcode.
936: * returns -1 when the predicate evaluates to true, 0 when false.
937: * signal numbers are returned when an error is detected.
938: * ここではシグナルではなく正数なら未実装命令パターン。
939: */
940: #if defined(XM6i_FPE)
941: int
942: #else
943: static int
944: #endif
945: test_cc(struct fpemu *fe, int pred)
946: {
947: int result, sig_bsun;
948: int fpsr;
949:
950: fpsr = fe->fe_fpsr;
951: DPRINTF(("%s: fpsr=0x%08x\n", __func__, fpsr));
952: pred &= 0x3f; /* lowest 6 bits */
953:
954: DPRINTF(("%s: ", __func__));
955:
956: if (pred >= 0x20) {
957: DPRINTF(("Illegal condition code\n"));
958: return 1;
959: } else if (pred & 0x10) {
960: /* IEEE nonaware tests */
961: sig_bsun = 1;
962: pred &= 0x0f; /* lower 4 bits */
963: } else {
964: /* IEEE aware tests */
965: DPRINTF(("IEEE "));
966: sig_bsun = 0;
967: }
968:
969: /*
970: * condition real 68882
971: * mnemonic in manual condition
972: * -------- ---------- ----------
973: * 0000 F 0 <- = ~NAN & 0 & ~Z | 0
974: * 0001 EQ Z <- = ~NAN & 0 | Z | 0
975: * 0010 OGT ~(NAN|Z|N) <- = ~NAN & ~N & ~Z | 0
976: * 0011 OGE Z|~(NAN|N) <- = ~NAN & ~N | Z | 0
977: * 0100 OLT N&~(NAN|Z) <- = ~NAN & N & ~Z | 0
978: * 0101 OLE Z|(N&~NAN) <- = ~NAN & N | Z | 0
979: * 0110 OGL ~(NAN|Z) <- = ~NAN & 1 & ~Z | 0
980: * 0111 OR ~NAN Z|~NAN = ~NAN & 1 | Z | 0
981: *
982: * 1000 UN NAN <- = 1 & 0 & ~Z | NAN
983: * 1001 UEQ NAN|Z <- = 1 & 0 | Z | NAN
984: * 1010 UGT NAN|~(N|Z) <- = 1 & ~N & ~Z | NAN
985: * 1011 UGE NAN|(Z|~N) <- = 1 & ~N | Z | NAN
986: * 1100 ULT NAN|(N&~Z) <- = 1 & N & ~Z | NAN
987: * 1101 ULE NAN|(Z|N) <- = 1 & N | Z | NAN
988: * 1110 NE ~Z NAN|(~Z) = 1 & 1 & ~Z | NAN
989: * 1111 T 1 <- = 1 & 1 | Z | NAN
990: */
991: if ((pred & 0x08) == 0) {
992: result = ((fpsr & FPSR_NAN) == 0);
993: } else {
994: result = 1;
995: }
996: switch (pred & 0x06) {
997: case 0x00: // 'AND 0'
998: result &= 0;
999: break;
1000: case 0x02: // 'AND ~N'
1001: result &= ((fpsr & FPSR_NEG) == 0);
1002: break;
1003: case 0x04: // 'AND N'
1004: result &= ((fpsr & FPSR_NEG) != 0);
1005: break;
1006: case 0x06: // 'AND 1'
1007: result &= 1;
1008: break;
1009: }
1010: if ((pred & 0x01) == 0) {
1011: result &= ((fpsr & FPSR_ZERO) == 0);
1012: } else {
1013: result |= ((fpsr & FPSR_ZERO) != 0);
1014: }
1015: if ((pred & 0x08) != 0) {
1016: result |= ((fpsr & FPSR_NAN) != 0);
1017: }
1018:
1019: DPRINTF(("=> %s (%d)\n", result ? "true" : "false", result));
1020: /* if it's an IEEE unaware test and NAN is set, BSUN is set */
1021: if (sig_bsun && (fpsr & FPSR_NAN)) {
1022: fpsr |= FPSR_BSUN;
1023: }
1.1.1.5 ! root 1024: /* if BSUN is set, IOP is set */
! 1025: if ((fpsr & FPSR_BSUN)) {
! 1026: fpsr |= FPSR_AIOP;
! 1027: }
1.1 root 1028:
1029: /* put fpsr back */
1030: fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
1031:
1032: return -result;
1033: }
1034:
1035: #if !defined(XM6i_FPE)
1036: /*
1037: * type 1: fdbcc, fscc, ftrapcc
1038: * In this function, we know:
1039: * (opcode & 0x01C0) == 0x0040
1040: */
1041: static int
1042: fpu_emul_type1(struct fpemu *fe, struct instruction *insn)
1043: {
1044: struct frame *frame = fe->fe_frame;
1045: int advance, sig, branch, displ;
1.1.1.3 root 1046: unsigned short sval;
1.1 root 1047:
1048: branch = test_cc(fe, insn->is_word1);
1049: fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
1050:
1051: insn->is_advance = 4;
1052: sig = 0;
1053:
1054: switch (insn->is_opcode & 070) {
1055: case 010: /* fdbcc */
1056: if (branch == -1) {
1057: /* advance */
1058: insn->is_advance = 6;
1059: } else if (!branch) {
1060: /* decrement Dn and if (Dn != -1) branch */
1061: uint16_t count = frame->f_regs[insn->is_opcode & 7];
1062:
1063: if (count-- != 0) {
1.1.1.3 root 1064: if (ufetch_short((void *)(insn->is_pc +
1065: insn->is_advance),
1066: &sval)) {
1.1 root 1067: DPRINTF(("%s: fault reading "
1068: "displacement\n", __func__));
1069: return SIGSEGV;
1070: }
1.1.1.3 root 1071: displ = sval;
1.1 root 1072: /* sign-extend the displacement */
1073: displ &= 0xffff;
1074: if (displ & 0x8000) {
1075: displ |= 0xffff0000;
1076: }
1077: insn->is_advance += displ;
1078: #if 0 /* XXX */
1079: insn->is_nextpc = insn->is_pc +
1080: insn->is_advance;
1081: #endif
1082: } else {
1083: insn->is_advance = 6;
1084: }
1085: /* write it back */
1086: frame->f_regs[insn->is_opcode & 7] &= 0xffff0000;
1087: frame->f_regs[insn->is_opcode & 7] |= (uint32_t)count;
1088: } else { /* got a signal */
1089: sig = SIGFPE;
1090: }
1091: break;
1092:
1093: case 070: /* ftrapcc or fscc */
1094: advance = 4;
1095: if ((insn->is_opcode & 07) >= 2) {
1096: switch (insn->is_opcode & 07) {
1097: case 3: /* long opr */
1098: advance += 2;
1099: case 2: /* word opr */
1100: advance += 2;
1101: case 4: /* no opr */
1102: break;
1103: default:
1104: return SIGILL;
1105: break;
1106: }
1107:
1108: if (branch == 0) {
1109: /* no trap */
1110: insn->is_advance = advance;
1111: sig = 0;
1112: } else {
1113: /* trap */
1114: sig = SIGFPE;
1115: }
1116: break;
1117: }
1118:
1119: /* FALLTHROUGH */
1120: default: /* fscc */
1121: insn->is_advance = 4;
1122: insn->is_datasize = 1; /* always byte */
1123: sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
1124: if (sig) {
1125: break;
1126: }
1127: if (branch == -1 || branch == 0) {
1128: /* set result */
1129: sig = fpu_store_ea(frame, insn, &insn->is_ea,
1130: (char *)&branch);
1131: } else {
1132: /* got an exception */
1133: sig = branch;
1134: }
1135: break;
1136: }
1137: return sig;
1138: }
1139:
1140: /*
1141: * Type 2 or 3: fbcc (also fnop)
1142: * In this function, we know:
1143: * (opcode & 0x0180) == 0x0080
1144: */
1145: static int
1146: fpu_emul_brcc(struct fpemu *fe, struct instruction *insn)
1147: {
1148: int displ, word2;
1149: int sig;
1.1.1.3 root 1150: unsigned short sval;
1.1 root 1151:
1152: /*
1153: * Get branch displacement.
1154: */
1155: insn->is_advance = 4;
1156: displ = insn->is_word1;
1157:
1158: if (insn->is_opcode & 0x40) {
1.1.1.3 root 1159: if (ufetch_short((void *)(insn->is_pc + insn->is_advance),
1160: &sval)) {
1.1 root 1161: DPRINTF(("%s: fault reading word2\n", __func__));
1162: return SIGSEGV;
1163: }
1.1.1.3 root 1164: word2 = sval;
1.1 root 1165: displ <<= 16;
1166: displ |= word2;
1167: insn->is_advance += 2;
1168: } else {
1169: /* displacement is word sized */
1170: if (displ & 0x8000)
1171: displ |= 0xFFFF0000;
1172: }
1173:
1174: /* XXX: If CC, insn->is_pc += displ */
1175: sig = test_cc(fe, insn->is_opcode);
1176: fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
1177:
1178: if (fe->fe_fpsr & fe->fe_fpcr & FPSR_EXCP) {
1179: return SIGFPE; /* caught an exception */
1180: }
1181: if (sig == -1) {
1182: /*
1183: * branch does take place; 2 is the offset to the 1st disp word
1184: */
1185: insn->is_advance = displ + 2;
1186: #if 0 /* XXX */
1187: insn->is_nextpc = insn->is_pc + insn->is_advance;
1188: #endif
1189: } else if (sig)
1190: return SIGILL; /* got a signal */
1191: DPRINTF(("%s: %s insn @ %x (%x+%x) (disp=%x)\n", __func__,
1192: (sig == -1) ? "BRANCH to" : "NEXT",
1193: insn->is_pc + insn->is_advance, insn->is_pc, insn->is_advance,
1194: displ));
1195: return 0;
1196: }
1197: #endif /* !XM6i_FPE */
1.1.1.5 ! root 1198:
! 1199: #if defined(XM6i_FPE)
! 1200: // fpn のタグ情報のうち、ゼロ、Inf、NAN、それ以外(ここでは正規化数)を返す。
! 1201: // 非正規化数とアンノーマル数はここに来る前に弾いてある。
! 1202: // 68040 の FSAVE で使う。
! 1203: int
! 1204: fpu_gettag(const struct fpn *fpn)
! 1205: {
! 1206: if (ISZERO(fpn)) {
! 1207: return 1;
! 1208: }
! 1209: if (ISINF(fpn)) {
! 1210: return 2;
! 1211: }
! 1212: if (ISNAN(fpn)) {
! 1213: return 3;
! 1214: }
! 1215: return 0;
! 1216: }
! 1217: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.