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