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