|
|
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: struct fpn *
511: fpu_cmp(struct fpemu *fe)
512: {
513: struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;
514:
515: /* take care of special cases */
516: if (x->fp_class < 0) {
517: /* if x is a SNAN, result is x */
518: return x;
519: } else if (y->fp_class < 0) {
520: /* if y is a SNAN, result is y */
521: return y;
522: } else if (x->fp_class == FPC_INF) {
523: if (y->fp_class == FPC_INF) {
524: /* both infinities */
525: if (x->fp_sign == y->fp_sign) {
526: /* return a signed zero */
527: x->fp_class = FPC_ZERO;
528: } else {
529: /* return a faked number w/x's sign */
530: x->fp_class = FPC_NUM;
531: x->fp_exp = 16383;
532: x->fp_mant[0] = FP_1;
533: }
534: } else {
535: /* y is a number */
536: /* return a forged number w/x's sign */
537: x->fp_class = FPC_NUM;
538: x->fp_exp = 16383;
539: x->fp_mant[0] = FP_1;
540: }
541: } else if (y->fp_class == FPC_INF) {
542: /* x is a Num but y is an Inf */
543: /* return a forged number w/y's sign inverted */
544: x->fp_class = FPC_NUM;
545: x->fp_sign = !y->fp_sign;
546: x->fp_exp = 16383;
547: x->fp_mant[0] = FP_1;
548: } else if (x->fp_class == FPC_ZERO && y->fp_class == FPC_ZERO) {
549: /* use x's sign */
550: } else if (x->fp_sign == y->fp_sign &&
551: x->fp_exp == y->fp_exp &&
552: x->fp_mant[0] == y->fp_mant[0] &&
553: x->fp_mant[1] == y->fp_mant[1] &&
554: x->fp_mant[2] == y->fp_mant[2]) {
555: /* x and y are the same, return zero (with sign) */
556: x->fp_class = FPC_ZERO;
557: } else {
558: /*
559: * x and y are both numbers,
560: * or pair of a number and a zero
561: */
562: y->fp_sign = !y->fp_sign;
563: x = fpu_add(fe); /* (x - y) */
564: /*
565: * FCMP does not set Inf bit in CC, so return a forged number
566: * (value doesn't matter) if Inf is the result of fsub.
567: */
568: if (x->fp_class == FPC_INF) {
569: x->fp_class = FPC_NUM;
570: x->fp_exp = 16383;
571: x->fp_mant[0] = FP_1;
572: }
573: }
574: return x;
575: }
576:
577: #if defined(XM6i_FPE)
578: struct fpn *
579: fpu_sglmul(struct fpemu *fe)
580: {
581: struct fpn *r;
582:
583: if (ISNAN(&fe->fe_f1))
584: return &fe->fe_f1;
585: if (ISNAN(&fe->fe_f2))
586: return &fe->fe_f2;
587:
588: /*
589: * 仮数部を(小数以下) 23bit だけにして「精度」を単精度と同じにする。
590: * FSGLMUL では指数部が単精度の範囲を越えても inf 等にならないし、
591: * 68000PRM.pdf で (精度を落とすにあたり) FPCR の現在の丸めモードに
592: * 関係ないと言っているあたりからも、単精度型に変換するとかではなく、
593: * 仮数部のビットを落とすだけなんだと思う。
594: */
595: fe->fe_f1.fp_mant[1] &= 0xf8000000;
596: fe->fe_f1.fp_mant[2] = 0;
597:
598: fe->fe_f2.fp_mant[1] &= 0xf8000000;
599: fe->fe_f2.fp_mant[2] = 0;
600:
601: r = fpu_mul(fe);
602:
603: fpu_round_prec(fe, r);
604: DUMPFP("sglmul:round", r);
605:
606: // 非正規化数の最小値(最下位ビットだけ1) だったら、
607: // 指数部はそのまま、仮数部を単精度の最下位ビット 1 という状態にする。
608: if (r->fp_exp == -EXT_EXP_BIAS - EXT_FRACBITS + 1 &&
609: r->fp_mant[0] == FP_1 &&
610: r->fp_mant[1] == 0 &&
611: r->fp_mant[2] == 0)
612: {
613: r->fp_exp += EXT_FRACBITS - SNG_FRACBITS - 1;
614: }
615: DUMPFP("sglmul:mod ", r);
616:
617: return r;
618: }
619:
620: struct fpn *
621: fpu_sgldiv(struct fpemu *fe)
622: {
623: struct fpn *r;
624:
625: if (ISNAN(&fe->fe_f1))
626: return &fe->fe_f1;
627: if (ISNAN(&fe->fe_f2))
628: return &fe->fe_f2;
629:
630: fe->fe_f1.fp_mant[1] &= 0xf8000000;
631: fe->fe_f1.fp_mant[2] = 0;
632:
633: fe->fe_f2.fp_mant[1] &= 0xf8000000;
634: fe->fe_f2.fp_mant[2] = 0;
635:
636: r = fpu_div(fe);
637:
638: fpu_round_prec(fe, r);
639: DUMPFP("sgldiv:round", r);
640:
641: if (r->fp_exp == -EXT_EXP_BIAS - EXT_FRACBITS + 1 &&
642: r->fp_mant[0] == FP_1 &&
643: r->fp_mant[1] == 0 &&
644: r->fp_mant[2] == 0)
645: {
646: r->fp_exp += EXT_FRACBITS - SNG_FRACBITS - 1;
647: }
648: DUMPFP("sgldiv:mod ", r);
649:
650: return r;
651: }
652: #endif /* XM6i_FPE */
653:
654: #if !defined(XM6i_FPE)
655: /*
656: * arithmetic oprations
657: */
658: static int
659: fpu_emul_arith(struct fpemu *fe, struct instruction *insn)
660: {
661: struct frame *frame = fe->fe_frame;
662: uint32_t *fpregs = &(fe->fe_fpframe->fpf_regs[0]);
663: struct fpn *res;
664: int word1, sig = 0;
665: int regnum, format;
666: int discard_result = 0;
667: uint32_t buf[3];
668: #ifdef DEBUG_FPE
669: int flags;
670: char regname;
671: #endif
672:
673: fe->fe_fpsr &= ~FPSR_EXCP;
674:
675: DUMP_INSN(insn);
676:
677: DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__,
678: fe->fe_fpsr, fe->fe_fpcr));
679:
680: word1 = insn->is_word1;
681: format = (word1 >> 10) & 7;
682: regnum = (word1 >> 7) & 7;
683:
684: /* fetch a source operand : may not be used */
685: DPRINTF(("%s: dst/src FP%d=%08x,%08x,%08x\n", __func__,
686: regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],
687: fpregs[regnum * 3 + 2]));
688:
689: fpu_explode(fe, &fe->fe_f1, FTYPE_EXT, &fpregs[regnum * 3]);
690:
691: DUMP_INSN(insn);
692:
693: /* get the other operand which is always the source */
694: if ((word1 & 0x4000) == 0) {
695: DPRINTF(("%s: FP%d op FP%d => FP%d\n", __func__,
696: format, regnum, regnum));
697: DPRINTF(("%s: src opr FP%d=%08x,%08x,%08x\n", __func__,
698: format, fpregs[format * 3], fpregs[format * 3 + 1],
699: fpregs[format * 3 + 2]));
700: fpu_explode(fe, &fe->fe_f2, FTYPE_EXT, &fpregs[format * 3]);
701: } else {
702: /* the operand is in memory */
703: if (format == FTYPE_DBL) {
704: insn->is_datasize = 8;
705: } else if (format == FTYPE_SNG || format == FTYPE_LNG) {
706: insn->is_datasize = 4;
707: } else if (format == FTYPE_WRD) {
708: insn->is_datasize = 2;
709: } else if (format == FTYPE_BYT) {
710: insn->is_datasize = 1;
711: } else if (format == FTYPE_EXT) {
712: insn->is_datasize = 12;
713: } else {
714: /* invalid or unsupported operand format */
715: sig = SIGFPE;
716: return sig;
717: }
718:
719: /* Get effective address. (modreg=opcode&077) */
720: sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
721: if (sig) {
722: DPRINTF(("%s: error in fpu_decode_ea\n", __func__));
723: return sig;
724: }
725:
726: DUMP_INSN(insn);
727:
728: #ifdef DEBUG_FPE
729: printf("%s: addr mode = ", __func__);
730: flags = insn->is_ea.ea_flags;
731: regname = (insn->is_ea.ea_regnum & 8) ? 'a' : 'd';
732:
733: if (flags & EA_DIRECT) {
734: printf("%c%d\n", regname, insn->is_ea.ea_regnum & 7);
735: } else if (flags & EA_PC_REL) {
736: if (flags & EA_OFFSET) {
737: printf("pc@(%d)\n", insn->is_ea.ea_offset);
738: } else if (flags & EA_INDEXED) {
739: printf("pc@(...)\n");
740: }
741: } else if (flags & EA_PREDECR) {
742: printf("%c%d@-\n", regname, insn->is_ea.ea_regnum & 7);
743: } else if (flags & EA_POSTINCR) {
744: printf("%c%d@+\n", regname, insn->is_ea.ea_regnum & 7);
745: } else if (flags & EA_OFFSET) {
746: printf("%c%d@(%d)\n", regname,
747: insn->is_ea.ea_regnum & 7,
748: insn->is_ea.ea_offset);
749: } else if (flags & EA_INDEXED) {
750: printf("%c%d@(...)\n", regname,
751: insn->is_ea.ea_regnum & 7);
752: } else if (flags & EA_ABS) {
753: printf("0x%08x\n", insn->is_ea.ea_absaddr);
754: } else if (flags & EA_IMMED) {
755: printf("#0x%08x,%08x,%08x\n",
756: insn->is_ea.ea_immed[0],
757: insn->is_ea.ea_immed[1],
758: insn->is_ea.ea_immed[2]);
759: } else {
760: printf("%c%d@\n", regname, insn->is_ea.ea_regnum & 7);
761: }
762: #endif /* DEBUG_FPE */
763:
764: fpu_load_ea(frame, insn, &insn->is_ea, (char*)buf);
765: if (format == FTYPE_WRD) {
766: /* sign-extend */
767: buf[0] &= 0xffff;
768: if (buf[0] & 0x8000)
769: buf[0] |= 0xffff0000;
770: format = FTYPE_LNG;
771: } else if (format == FTYPE_BYT) {
772: /* sign-extend */
773: buf[0] &= 0xff;
774: if (buf[0] & 0x80)
775: buf[0] |= 0xffffff00;
776: format = FTYPE_LNG;
777: }
778: DPRINTF(("%s: src = %08x %08x %08x, siz = %d\n", __func__,
779: buf[0], buf[1], buf[2], insn->is_datasize));
780: fpu_explode(fe, &fe->fe_f2, format, buf);
781: }
782:
783: DUMP_INSN(insn);
784:
785: /*
786: * An arithmetic instruction emulate function has a prototype of
787: * struct fpn *fpu_op(struct fpemu *);
788: *
789: * 1) If the instruction is monadic, then fpu_op() must use
790: * fe->fe_f2 as its operand, and return a pointer to the
791: * result.
792: *
793: * 2) If the instruction is diadic, then fpu_op() must use
794: * fe->fe_f1 and fe->fe_f2 as its two operands, and return a
795: * pointer to the result.
796: *
797: */
798: res = NULL;
799: switch (word1 & 0x7f) {
800: case 0x00: /* fmove */
801: res = &fe->fe_f2;
802: break;
803:
804: case 0x01: /* fint */
805: res = fpu_int(fe);
806: break;
807:
808: case 0x02: /* fsinh */
809: res = fpu_sinh(fe);
810: break;
811:
812: case 0x03: /* fintrz */
813: res = fpu_intrz(fe);
814: break;
815:
816: case 0x04: /* fsqrt */
817: res = fpu_sqrt(fe);
818: break;
819:
820: case 0x06: /* flognp1 */
821: res = fpu_lognp1(fe);
822: break;
823:
824: case 0x08: /* fetoxm1 */
825: res = fpu_etoxm1(fe);
826: break;
827:
828: case 0x09: /* ftanh */
829: res = fpu_tanh(fe);
830: break;
831:
832: case 0x0A: /* fatan */
833: res = fpu_atan(fe);
834: break;
835:
836: case 0x0C: /* fasin */
837: res = fpu_asin(fe);
838: break;
839:
840: case 0x0D: /* fatanh */
841: res = fpu_atanh(fe);
842: break;
843:
844: case 0x0E: /* fsin */
845: res = fpu_sin(fe);
846: break;
847:
848: case 0x0F: /* ftan */
849: res = fpu_tan(fe);
850: break;
851:
852: case 0x10: /* fetox */
853: res = fpu_etox(fe);
854: break;
855:
856: case 0x11: /* ftwotox */
857: res = fpu_twotox(fe);
858: break;
859:
860: case 0x12: /* ftentox */
861: res = fpu_tentox(fe);
862: break;
863:
864: case 0x14: /* flogn */
865: res = fpu_logn(fe);
866: break;
867:
868: case 0x15: /* flog10 */
869: res = fpu_log10(fe);
870: break;
871:
872: case 0x16: /* flog2 */
873: res = fpu_log2(fe);
874: break;
875:
876: case 0x18: /* fabs */
877: fe->fe_f2.fp_sign = 0;
878: res = &fe->fe_f2;
879: break;
880:
881: case 0x19: /* fcosh */
882: res = fpu_cosh(fe);
883: break;
884:
885: case 0x1A: /* fneg */
886: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign;
887: res = &fe->fe_f2;
888: break;
889:
890: case 0x1C: /* facos */
891: res = fpu_acos(fe);
892: break;
893:
894: case 0x1D: /* fcos */
895: res = fpu_cos(fe);
896: break;
897:
898: case 0x1E: /* fgetexp */
899: res = fpu_getexp(fe);
900: break;
901:
902: case 0x1F: /* fgetman */
903: res = fpu_getman(fe);
904: break;
905:
906: case 0x20: /* fdiv */
907: case 0x24: /* fsgldiv: cheating - better than nothing */
908: res = fpu_div(fe);
909: break;
910:
911: case 0x21: /* fmod */
912: res = fpu_mod(fe);
913: break;
914:
915: case 0x28: /* fsub */
916: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
917: /* FALLTHROUGH */
918: case 0x22: /* fadd */
919: res = fpu_add(fe);
920: break;
921:
922: case 0x23: /* fmul */
923: case 0x27: /* fsglmul: cheating - better than nothing */
924: res = fpu_mul(fe);
925: break;
926:
927: case 0x25: /* frem */
928: res = fpu_rem(fe);
929: break;
930:
931: case 0x26:
932: /* fscale is handled by a separate function */
933: break;
934:
935: case 0x30:
936: case 0x31:
937: case 0x32:
938: case 0x33:
939: case 0x34:
940: case 0x35:
941: case 0x36:
942: case 0x37: /* fsincos */
943: res = fpu_sincos(fe, word1 & 7);
944: break;
945:
946: case 0x38: /* fcmp */
947: res = fpu_cmp(fe);
948: discard_result = 1;
949: break;
950:
951: case 0x3A: /* ftst */
952: res = &fe->fe_f2;
953: discard_result = 1;
954: break;
955:
956: default: /* possibly 040/060 instructions */
957: DPRINTF(("%s: bad opcode=0x%x, word1=0x%x\n", __func__,
958: insn->is_opcode, insn->is_word1));
959: sig = SIGILL;
960: }
961:
962: /* for sanity */
963: if (res == NULL)
964: sig = SIGILL;
965:
966: if (sig == 0) {
967: if (!discard_result)
968: fpu_implode(fe, res, FTYPE_EXT, &fpregs[regnum * 3]);
969:
970: /* update fpsr according to the result of operation */
971: fpu_upd_fpsr(fe, res);
972: #ifdef DEBUG_FPE
973: if (!discard_result) {
974: printf("%s: %08x,%08x,%08x stored in FP%d\n", __func__,
975: fpregs[regnum * 3],
976: fpregs[regnum * 3 + 1],
977: fpregs[regnum * 3 + 2],
978: regnum);
979: } else {
980: static const char *class_name[] =
981: { "SNAN", "QNAN", "ZERO", "NUM", "INF" };
982: printf("%s: result(%s,%c,%d,%08x,%08x,%08x) "
983: "discarded\n", __func__,
984: class_name[res->fp_class + 2],
985: res->fp_sign ? '-' : '+', res->fp_exp,
986: res->fp_mant[0], res->fp_mant[1],
987: res->fp_mant[2]);
988: }
989: #endif
990: } else {
991: DPRINTF(("%s: received signal %d\n", __func__, sig));
992: }
993:
994: DPRINTF(("%s: FPSR = %08x, FPCR = %08x\n", __func__,
995: fe->fe_fpsr, fe->fe_fpcr));
996:
997: DUMP_INSN(insn);
998:
999: return sig;
1000: }
1001: #endif /* !XM6i_FPE */
1002:
1003: /*
1004: * test condition code according to the predicate in the opcode.
1005: * returns -1 when the predicate evaluates to true, 0 when false.
1006: * signal numbers are returned when an error is detected.
1007: * ここではシグナルではなく正数なら未実装命令パターン。
1008: */
1009: #if defined(XM6i_FPE)
1010: int
1011: #else
1012: static int
1013: #endif
1014: test_cc(struct fpemu *fe, int pred)
1015: {
1016: int result, sig_bsun;
1017: int fpsr;
1018:
1019: fpsr = fe->fe_fpsr;
1020: fpsr &= ~FPSR_EXCP; /* clear all exceptions */
1021: DPRINTF(("%s: fpsr=0x%08x\n", __func__, fpsr));
1022: pred &= 0x3f; /* lowest 6 bits */
1023:
1024: DPRINTF(("%s: ", __func__));
1025:
1026: if (pred >= 0x20) {
1027: DPRINTF(("Illegal condition code\n"));
1028: return 1;
1029: } else if (pred & 0x10) {
1030: /* IEEE nonaware tests */
1031: sig_bsun = 1;
1032: pred &= 0x0f; /* lower 4 bits */
1033: } else {
1034: /* IEEE aware tests */
1035: DPRINTF(("IEEE "));
1036: sig_bsun = 0;
1037: }
1038:
1039: /*
1040: * condition real 68882
1041: * mnemonic in manual condition
1042: * -------- ---------- ----------
1043: * 0000 F 0 <- = ~NAN & 0 & ~Z | 0
1044: * 0001 EQ Z <- = ~NAN & 0 | Z | 0
1045: * 0010 OGT ~(NAN|Z|N) <- = ~NAN & ~N & ~Z | 0
1046: * 0011 OGE Z|~(NAN|N) <- = ~NAN & ~N | Z | 0
1047: * 0100 OLT N&~(NAN|Z) <- = ~NAN & N & ~Z | 0
1048: * 0101 OLE Z|(N&~NAN) <- = ~NAN & N | Z | 0
1049: * 0110 OGL ~(NAN|Z) <- = ~NAN & 1 & ~Z | 0
1050: * 0111 OR ~NAN Z|~NAN = ~NAN & 1 | Z | 0
1051: *
1052: * 1000 UN NAN <- = 1 & 0 & ~Z | NAN
1053: * 1001 UEQ NAN|Z <- = 1 & 0 | Z | NAN
1054: * 1010 UGT NAN|~(N|Z) <- = 1 & ~N & ~Z | NAN
1055: * 1011 UGE NAN|(Z|~N) <- = 1 & ~N | Z | NAN
1056: * 1100 ULT NAN|(N&~Z) <- = 1 & N & ~Z | NAN
1057: * 1101 ULE NAN|(Z|N) <- = 1 & N | Z | NAN
1058: * 1110 NE ~Z NAN|(~Z) = 1 & 1 & ~Z | NAN
1059: * 1111 T 1 <- = 1 & 1 | Z | NAN
1060: */
1061: if ((pred & 0x08) == 0) {
1062: result = ((fpsr & FPSR_NAN) == 0);
1063: } else {
1064: result = 1;
1065: }
1066: switch (pred & 0x06) {
1067: case 0x00: // 'AND 0'
1068: result &= 0;
1069: break;
1070: case 0x02: // 'AND ~N'
1071: result &= ((fpsr & FPSR_NEG) == 0);
1072: break;
1073: case 0x04: // 'AND N'
1074: result &= ((fpsr & FPSR_NEG) != 0);
1075: break;
1076: case 0x06: // 'AND 1'
1077: result &= 1;
1078: break;
1079: }
1080: if ((pred & 0x01) == 0) {
1081: result &= ((fpsr & FPSR_ZERO) == 0);
1082: } else {
1083: result |= ((fpsr & FPSR_ZERO) != 0);
1084: }
1085: if ((pred & 0x08) != 0) {
1086: result |= ((fpsr & FPSR_NAN) != 0);
1087: }
1088:
1089: DPRINTF(("=> %s (%d)\n", result ? "true" : "false", result));
1090: /* if it's an IEEE unaware test and NAN is set, BSUN is set */
1091: if (sig_bsun && (fpsr & FPSR_NAN)) {
1092: fpsr |= FPSR_BSUN;
1093: }
1094:
1095: /* put fpsr back */
1096: fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;
1097:
1098: return -result;
1099: }
1100:
1101: #if !defined(XM6i_FPE)
1102: /*
1103: * type 1: fdbcc, fscc, ftrapcc
1104: * In this function, we know:
1105: * (opcode & 0x01C0) == 0x0040
1106: */
1107: static int
1108: fpu_emul_type1(struct fpemu *fe, struct instruction *insn)
1109: {
1110: struct frame *frame = fe->fe_frame;
1111: int advance, sig, branch, displ;
1112:
1113: branch = test_cc(fe, insn->is_word1);
1114: fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
1115:
1116: insn->is_advance = 4;
1117: sig = 0;
1118:
1119: switch (insn->is_opcode & 070) {
1120: case 010: /* fdbcc */
1121: if (branch == -1) {
1122: /* advance */
1123: insn->is_advance = 6;
1124: } else if (!branch) {
1125: /* decrement Dn and if (Dn != -1) branch */
1126: uint16_t count = frame->f_regs[insn->is_opcode & 7];
1127:
1128: if (count-- != 0) {
1129: displ = fusword((void *)(insn->is_pc +
1130: insn->is_advance));
1131: if (displ < 0) {
1132: DPRINTF(("%s: fault reading "
1133: "displacement\n", __func__));
1134: return SIGSEGV;
1135: }
1136: /* sign-extend the displacement */
1137: displ &= 0xffff;
1138: if (displ & 0x8000) {
1139: displ |= 0xffff0000;
1140: }
1141: insn->is_advance += displ;
1142: #if 0 /* XXX */
1143: insn->is_nextpc = insn->is_pc +
1144: insn->is_advance;
1145: #endif
1146: } else {
1147: insn->is_advance = 6;
1148: }
1149: /* write it back */
1150: frame->f_regs[insn->is_opcode & 7] &= 0xffff0000;
1151: frame->f_regs[insn->is_opcode & 7] |= (uint32_t)count;
1152: } else { /* got a signal */
1153: sig = SIGFPE;
1154: }
1155: break;
1156:
1157: case 070: /* ftrapcc or fscc */
1158: advance = 4;
1159: if ((insn->is_opcode & 07) >= 2) {
1160: switch (insn->is_opcode & 07) {
1161: case 3: /* long opr */
1162: advance += 2;
1163: case 2: /* word opr */
1164: advance += 2;
1165: case 4: /* no opr */
1166: break;
1167: default:
1168: return SIGILL;
1169: break;
1170: }
1171:
1172: if (branch == 0) {
1173: /* no trap */
1174: insn->is_advance = advance;
1175: sig = 0;
1176: } else {
1177: /* trap */
1178: sig = SIGFPE;
1179: }
1180: break;
1181: }
1182:
1183: /* FALLTHROUGH */
1184: default: /* fscc */
1185: insn->is_advance = 4;
1186: insn->is_datasize = 1; /* always byte */
1187: sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
1188: if (sig) {
1189: break;
1190: }
1191: if (branch == -1 || branch == 0) {
1192: /* set result */
1193: sig = fpu_store_ea(frame, insn, &insn->is_ea,
1194: (char *)&branch);
1195: } else {
1196: /* got an exception */
1197: sig = branch;
1198: }
1199: break;
1200: }
1201: return sig;
1202: }
1203:
1204: /*
1205: * Type 2 or 3: fbcc (also fnop)
1206: * In this function, we know:
1207: * (opcode & 0x0180) == 0x0080
1208: */
1209: static int
1210: fpu_emul_brcc(struct fpemu *fe, struct instruction *insn)
1211: {
1212: int displ, word2;
1213: int sig;
1214:
1215: /*
1216: * Get branch displacement.
1217: */
1218: insn->is_advance = 4;
1219: displ = insn->is_word1;
1220:
1221: if (insn->is_opcode & 0x40) {
1222: word2 = fusword((void *)(insn->is_pc + insn->is_advance));
1223: if (word2 < 0) {
1224: DPRINTF(("%s: fault reading word2\n", __func__));
1225: return SIGSEGV;
1226: }
1227: displ <<= 16;
1228: displ |= word2;
1229: insn->is_advance += 2;
1230: } else {
1231: /* displacement is word sized */
1232: if (displ & 0x8000)
1233: displ |= 0xFFFF0000;
1234: }
1235:
1236: /* XXX: If CC, insn->is_pc += displ */
1237: sig = test_cc(fe, insn->is_opcode);
1238: fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr;
1239:
1240: if (fe->fe_fpsr & fe->fe_fpcr & FPSR_EXCP) {
1241: return SIGFPE; /* caught an exception */
1242: }
1243: if (sig == -1) {
1244: /*
1245: * branch does take place; 2 is the offset to the 1st disp word
1246: */
1247: insn->is_advance = displ + 2;
1248: #if 0 /* XXX */
1249: insn->is_nextpc = insn->is_pc + insn->is_advance;
1250: #endif
1251: } else if (sig)
1252: return SIGILL; /* got a signal */
1253: DPRINTF(("%s: %s insn @ %x (%x+%x) (disp=%x)\n", __func__,
1254: (sig == -1) ? "BRANCH to" : "NEXT",
1255: insn->is_pc + insn->is_advance, insn->is_pc, insn->is_advance,
1256: displ));
1257: return 0;
1258: }
1259: #endif /* !XM6i_FPE */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.