Home | History | Annotate | Line # | Download | only in fpe
fpu_emulate.c revision 1.1
      1  1.1  gwr /*	$NetBSD: fpu_emulate.c,v 1.1 1995/03/01 04:56:27 gwr Exp $	*/
      2  1.1  gwr 
      3  1.1  gwr /*
      4  1.1  gwr  * Copyright (c) 1995 Gordon W. Ross
      5  1.1  gwr  * All rights reserved.
      6  1.1  gwr  *
      7  1.1  gwr  * Redistribution and use in source and binary forms, with or without
      8  1.1  gwr  * modification, are permitted provided that the following conditions
      9  1.1  gwr  * are met:
     10  1.1  gwr  * 1. Redistributions of source code must retain the above copyright
     11  1.1  gwr  *    notice, this list of conditions and the following disclaimer.
     12  1.1  gwr  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  gwr  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  gwr  *    documentation and/or other materials provided with the distribution.
     15  1.1  gwr  * 3. The name of the author may not be used to endorse or promote products
     16  1.1  gwr  *    derived from this software without specific prior written permission.
     17  1.1  gwr  * 4. All advertising materials mentioning features or use of this software
     18  1.1  gwr  *    must display the following acknowledgement:
     19  1.1  gwr  *      This product includes software developed by Gordon Ross
     20  1.1  gwr  *
     21  1.1  gwr  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  1.1  gwr  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  1.1  gwr  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  1.1  gwr  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  1.1  gwr  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  1.1  gwr  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  1.1  gwr  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  1.1  gwr  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  1.1  gwr  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  1.1  gwr  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  1.1  gwr  */
     32  1.1  gwr 
     33  1.1  gwr /*
     34  1.1  gwr  * mc68881 emulator
     35  1.1  gwr  * XXX - Just a start at it for now...
     36  1.1  gwr  */
     37  1.1  gwr 
     38  1.1  gwr #include <sys/types.h>
     39  1.1  gwr #include <sys/signal.h>
     40  1.1  gwr #include <machine/frame.h>
     41  1.1  gwr 
     42  1.1  gwr #define	DEBUG 1	/* XXX */
     43  1.1  gwr 
     44  1.1  gwr /*
     45  1.1  gwr  * Internal info about a decoded effective address.
     46  1.1  gwr  */
     47  1.1  gwr struct insn_ea {
     48  1.1  gwr 	int regnum;
     49  1.1  gwr 	int immed;
     50  1.1  gwr 	int flags;
     51  1.1  gwr #define	EA_DIRECT	0x01
     52  1.1  gwr #define EA_PREDECR	0x02
     53  1.1  gwr #define	EA_POSTINCR	0x04
     54  1.1  gwr #define EA_OFFSET	0x08	/* mode 5: base+offset */
     55  1.1  gwr #define	EA_INDEXED	0x10	/* mode 6: complicated */
     56  1.1  gwr #define EA_ABS  	0x20	/* mode 7: reg 0 or 1 */
     57  1.1  gwr #define EA_PC_REL	0x40	/* mode 7: reg 2 or 3 */
     58  1.1  gwr #define	EA_IMMED	0x80	/* mode 7: reg 4 */
     59  1.1  gwr };
     60  1.1  gwr 
     61  1.1  gwr struct instruction {
     62  1.1  gwr 	int advance;	/* length of instruction */
     63  1.1  gwr 	int datasize;	/* byte, word, long, float, double, ... */
     64  1.1  gwr 	int	opcode;
     65  1.1  gwr 	int word1;
     66  1.1  gwr 	struct insn_ea ea0;
     67  1.1  gwr 	struct insn_ea ea1;
     68  1.1  gwr };
     69  1.1  gwr 
     70  1.1  gwr int fpu_emul_fmovm(struct frame *frame,
     71  1.1  gwr 				   struct fpframe *fpf,
     72  1.1  gwr 				   struct instruction *insn);
     73  1.1  gwr int fpu_emul_type0(struct frame *frame,
     74  1.1  gwr 				   struct fpframe *fpf,
     75  1.1  gwr 				   struct instruction *insn);
     76  1.1  gwr int fpu_emul_type1(struct frame *frame,
     77  1.1  gwr 				   struct fpframe *fpf,
     78  1.1  gwr 				   struct instruction *insn);
     79  1.1  gwr int fpu_emul_brcc(struct frame *frame,
     80  1.1  gwr 				  struct fpframe *fpf,
     81  1.1  gwr 				  struct instruction *insn);
     82  1.1  gwr 
     83  1.1  gwr static int decode_ea(struct frame *frame,
     84  1.1  gwr 					 struct instruction *insn,
     85  1.1  gwr 					 struct insn_ea *ea,
     86  1.1  gwr 					 int modreg);
     87  1.1  gwr static int load_ea(struct frame *frame,
     88  1.1  gwr 				   struct instruction *insn,
     89  1.1  gwr 				   struct insn_ea *ea,
     90  1.1  gwr 				   char *cpureg);
     91  1.1  gwr static int store_ea(struct frame *frame,
     92  1.1  gwr 					struct instruction *insn,
     93  1.1  gwr 					struct insn_ea *ea,
     94  1.1  gwr 					char *cpureg);
     95  1.1  gwr 
     96  1.1  gwr 
     97  1.1  gwr /*
     98  1.1  gwr  * Emulate a floating-point instruction.
     99  1.1  gwr  * Return zero for success, else signal number.
    100  1.1  gwr  * (Typically: zero, SIGFPE, SIGILL, SIGSEGV)
    101  1.1  gwr  */
    102  1.1  gwr int fpu_emulate(struct frame *frame, struct fpframe *fpf)
    103  1.1  gwr {
    104  1.1  gwr 	struct instruction insn;
    105  1.1  gwr 	int word, optype, sig;
    106  1.1  gwr 
    107  1.1  gwr 	word = fusword(frame->f_pc);
    108  1.1  gwr 	if (word < 0) {
    109  1.1  gwr #ifdef	DEBUG
    110  1.1  gwr 		printf("fpu_emulate: fault reading opcode\n");
    111  1.1  gwr #endif
    112  1.1  gwr 		return SIGSEGV;
    113  1.1  gwr 	}
    114  1.1  gwr 
    115  1.1  gwr 	if ((word & 0xF000) != 0xF000) {
    116  1.1  gwr #ifdef	DEBUG
    117  1.1  gwr 		printf("fpu_emulate: not coproc. insn.: opcode=0x%x\n", word);
    118  1.1  gwr #endif
    119  1.1  gwr 		return SIGILL;
    120  1.1  gwr 	}
    121  1.1  gwr 
    122  1.1  gwr 	if ((word & 0x0E00) != 0x0200) {
    123  1.1  gwr #ifdef	DEBUG
    124  1.1  gwr 		printf("fpu_emulate: bad coproc. id: opcode=0x%x\n", word);
    125  1.1  gwr #endif
    126  1.1  gwr 		return SIGILL;
    127  1.1  gwr 	}
    128  1.1  gwr 
    129  1.1  gwr 	insn.opcode = word;
    130  1.1  gwr 	optype = (word & 0x01C0);
    131  1.1  gwr 
    132  1.1  gwr 	word = fusword(frame->f_pc + 2);
    133  1.1  gwr 	if (word < 0) {
    134  1.1  gwr #ifdef	DEBUG
    135  1.1  gwr 		printf("fpu_emulate: fault reading word1\n");
    136  1.1  gwr #endif
    137  1.1  gwr 		return SIGSEGV;
    138  1.1  gwr 	}
    139  1.1  gwr 	insn.word1 = word;
    140  1.1  gwr 
    141  1.1  gwr 	/*
    142  1.1  gwr 	 * Which family (or type) of opcode is it?
    143  1.1  gwr 	 * Tests ordered by likelihood (hopefully).
    144  1.1  gwr 	 * Certainly, type 0 is the most common.
    145  1.1  gwr 	 */
    146  1.1  gwr 	if (optype == 0x0000) {
    147  1.1  gwr 		/* type=0: generic */
    148  1.1  gwr 		if (insn.word1 & 0x8000) {
    149  1.1  gwr 			sig = fpu_emul_fmovm(frame, fpf, &insn);
    150  1.1  gwr 		} else {
    151  1.1  gwr 			sig = fpu_emul_type0(frame, fpf, &insn);
    152  1.1  gwr 		}
    153  1.1  gwr 	}
    154  1.1  gwr 	else if (optype == 0x0080) {
    155  1.1  gwr 		/* type=2: fbcc, short disp. */
    156  1.1  gwr 		sig = fpu_emul_brcc(frame, fpf, &insn);
    157  1.1  gwr 	}
    158  1.1  gwr 	else if (optype == 0x00C0) {
    159  1.1  gwr 		/* type=3: fbcc, long disp. */
    160  1.1  gwr 		sig = fpu_emul_brcc(frame, fpf, &insn);
    161  1.1  gwr 	}
    162  1.1  gwr 	else if (optype == 0x0040) {
    163  1.1  gwr 		/* type=1: fdbcc, fscc, ftrapcc */
    164  1.1  gwr 		sig = fpu_emul_type1(frame, fpf, &insn);
    165  1.1  gwr 	}
    166  1.1  gwr 	else {
    167  1.1  gwr 		/* type=4: fsave    (privileged) */
    168  1.1  gwr 		/* type=5: frestore (privileged) */
    169  1.1  gwr 		/* type=6: reserved */
    170  1.1  gwr 		/* type=7: reserved */
    171  1.1  gwr #ifdef	DEBUG
    172  1.1  gwr 		printf("fpu_emulate: bad opcode type: opcode=0x%x\n", insn.opcode);
    173  1.1  gwr #endif
    174  1.1  gwr 		sig = SIGILL;
    175  1.1  gwr 	}
    176  1.1  gwr 
    177  1.1  gwr 	if (sig == 0) {
    178  1.1  gwr 		frame->f_pc += insn.advance;
    179  1.1  gwr 	}
    180  1.1  gwr #if defined(DDB) && defined(DEBUG)
    181  1.1  gwr 	else kdb_trap(-1, frame);
    182  1.1  gwr #endif
    183  1.1  gwr 
    184  1.1  gwr 	return (sig);
    185  1.1  gwr }
    186  1.1  gwr 
    187  1.1  gwr /*
    188  1.1  gwr  * type 0: fmovem, fmove <cr>
    189  1.1  gwr  * Separated out of fpu_emul_type0 for efficiency.
    190  1.1  gwr  * In this function, we know:
    191  1.1  gwr  *   (opcode & 0x01C0) == 0
    192  1.1  gwr  *   (word1 & 0x8000) == 0x8000
    193  1.1  gwr  *
    194  1.1  gwr  * No conversion or rounding is done by this instruction,
    195  1.1  gwr  * and the FPSR is not affected.
    196  1.1  gwr  */
    197  1.1  gwr int fpu_emul_fmovm(struct frame *frame,
    198  1.1  gwr 				   struct fpframe *fpf,
    199  1.1  gwr 				   struct instruction *insn)
    200  1.1  gwr {
    201  1.1  gwr 	int word1, sig;
    202  1.1  gwr 	int reglist, regmask, regnum;
    203  1.1  gwr 	int fpu_to_mem, order;
    204  1.1  gwr 	int w1_post_incr;	/* XXX - FP regs order? */
    205  1.1  gwr 	int *fpregs;
    206  1.1  gwr 
    207  1.1  gwr 	insn->advance = 4;
    208  1.1  gwr 	insn->datasize = 12;
    209  1.1  gwr 	word1 = insn->word1;
    210  1.1  gwr 
    211  1.1  gwr 	/* Bit 14 selects FPn or FP control regs. */
    212  1.1  gwr 	if (word1 & 0x4000) {
    213  1.1  gwr 		/*
    214  1.1  gwr 		 * Bits 12,11 select register list mode:
    215  1.1  gwr 		 * 0,0: Static  reg list, pre-decr.
    216  1.1  gwr 		 * 0,1: Dynamic reg list, pre-decr.
    217  1.1  gwr 		 * 1,0: Static  reg list, post-incr.
    218  1.1  gwr 		 * 1,1: Dynamic reg list, post-incr
    219  1.1  gwr 		 */
    220  1.1  gwr 		w1_post_incr = word1 & 0x1000;
    221  1.1  gwr 		if (word1 & 0x0800) {
    222  1.1  gwr 			/* dynamic reg list */
    223  1.1  gwr 			reglist = frame->f_regs[(word1 & 0x70) >> 4];
    224  1.1  gwr 		} else
    225  1.1  gwr 			reglist = word1;
    226  1.1  gwr 		reglist &= 0xFF;
    227  1.1  gwr 	} else {
    228  1.1  gwr 		/* XXX: move to/from control registers */
    229  1.1  gwr 		reglist = word1 & 0x1C00;
    230  1.1  gwr 		return SIGILL;
    231  1.1  gwr 	}
    232  1.1  gwr 
    233  1.1  gwr 	/* Bit 13 selects direction (FPU to/from Mem) */
    234  1.1  gwr 	fpu_to_mem = word1 & 0x2000;
    235  1.1  gwr 
    236  1.1  gwr 	/* Get effective address. (modreg=opcode&077) */
    237  1.1  gwr 	sig = decode_ea(frame, insn, &insn->ea0, insn->opcode);
    238  1.1  gwr 	if (sig) return sig;
    239  1.1  gwr 
    240  1.1  gwr 	/* Get address of soft coprocessor regs. */
    241  1.1  gwr 	fpregs = &fpf->fpf_regs[0];
    242  1.1  gwr 
    243  1.1  gwr 	if (insn->ea0.flags & EA_PREDECR) {
    244  1.1  gwr 		regnum = 7;
    245  1.1  gwr 		order = -1;
    246  1.1  gwr 	} else {
    247  1.1  gwr 		regnum = 0;
    248  1.1  gwr 		order = 1;
    249  1.1  gwr 	}
    250  1.1  gwr 
    251  1.1  gwr 	while ((0 <= regnum) && (regnum < 8)) {
    252  1.1  gwr 		regmask = 1 << regnum;
    253  1.1  gwr 		if (regmask & reglist) {
    254  1.1  gwr 			if (fpu_to_mem)
    255  1.1  gwr 				sig = store_ea(frame, insn, &insn->ea0,
    256  1.1  gwr 							   (char*) &fpregs[regnum]);
    257  1.1  gwr 			else /* mem to fpu */
    258  1.1  gwr 				sig = load_ea(frame, insn, &insn->ea0,
    259  1.1  gwr 							  (char*) &fpregs[regnum]);
    260  1.1  gwr 			if (sig) break;
    261  1.1  gwr 		}
    262  1.1  gwr 		regnum += order;
    263  1.1  gwr 	}
    264  1.1  gwr 
    265  1.1  gwr 	return 0;
    266  1.1  gwr }
    267  1.1  gwr 
    268  1.1  gwr int fpu_emul_type0(struct frame *frame,
    269  1.1  gwr 				   struct fpframe *fpf,
    270  1.1  gwr 				   struct instruction *insn)
    271  1.1  gwr {
    272  1.1  gwr 	int sig;
    273  1.1  gwr 
    274  1.1  gwr 	/* Get effective address */
    275  1.1  gwr 	/* XXX */
    276  1.1  gwr 
    277  1.1  gwr 	switch(insn->word1 & 0x3F) {
    278  1.1  gwr 
    279  1.1  gwr 	case 0x00:	/* fmove */
    280  1.1  gwr 
    281  1.1  gwr 	case 0x01:	/* fint */
    282  1.1  gwr 	case 0x02:	/* fsinh */
    283  1.1  gwr 	case 0x03:	/* fintrz */
    284  1.1  gwr 	case 0x04:	/* fsqrt */
    285  1.1  gwr 	case 0x06:	/* flognp1 */
    286  1.1  gwr 
    287  1.1  gwr 	case 0x09:	/* ftanh */
    288  1.1  gwr 	case 0x0A:	/* fatan */
    289  1.1  gwr 	case 0x0C:	/* fasin */
    290  1.1  gwr 	case 0x0D:	/* fatanh */
    291  1.1  gwr 	case 0x0E:	/* fsin */
    292  1.1  gwr 	case 0x0F:	/* ftan */
    293  1.1  gwr 
    294  1.1  gwr 	case 0x10:	/* fetox */
    295  1.1  gwr 	case 0x11:	/* ftwotox */
    296  1.1  gwr 	case 0x12:	/* ftentox */
    297  1.1  gwr 	case 0x14:	/* flogn */
    298  1.1  gwr 	case 0x15:	/* flog10 */
    299  1.1  gwr 	case 0x16:	/* flog2 */
    300  1.1  gwr 
    301  1.1  gwr 	case 0x18:	/* fabs */
    302  1.1  gwr 	case 0x19:	/* fcosh */
    303  1.1  gwr 	case 0x1A:	/* fneg */
    304  1.1  gwr 	case 0x1C:	/* facos */
    305  1.1  gwr 	case 0x1D:	/* fcos */
    306  1.1  gwr 	case 0x1E:	/* fgetexp */
    307  1.1  gwr 	case 0x1F:	/* fgetman */
    308  1.1  gwr 
    309  1.1  gwr 	case 0x20:	/* fdiv */
    310  1.1  gwr 	case 0x21:	/* fmod */
    311  1.1  gwr 	case 0x22:	/* fadd */
    312  1.1  gwr 	case 0x23:	/* fmul */
    313  1.1  gwr 	case 0x24:	/* fsgldiv */
    314  1.1  gwr 	case 0x25:	/* frem */
    315  1.1  gwr 	case 0x26:	/* fscale */
    316  1.1  gwr 	case 0x27:	/* fsglmul */
    317  1.1  gwr 
    318  1.1  gwr 	case 0x28:	/* fsub */
    319  1.1  gwr 	case 0x38:	/* fcmp */
    320  1.1  gwr 	case 0x3A:	/* ftst */
    321  1.1  gwr 
    322  1.1  gwr 	default:
    323  1.1  gwr #ifdef	DEBUG
    324  1.1  gwr 		printf("fpu_emul_type0: unknown: opcode=0x%x, word1=0x%x\n",
    325  1.1  gwr 			   insn->opcode, insn->word1);
    326  1.1  gwr #endif
    327  1.1  gwr 		sig = SIGILL;
    328  1.1  gwr 
    329  1.1  gwr 	} /* switch */
    330  1.1  gwr 	return (sig);
    331  1.1  gwr }
    332  1.1  gwr 
    333  1.1  gwr /*
    334  1.1  gwr  * type 1: fdbcc, fscc, ftrapcc
    335  1.1  gwr  * In this function, we know:
    336  1.1  gwr  *   (opcode & 0x01C0) == 0x0040
    337  1.1  gwr  */
    338  1.1  gwr int fpu_emul_type1(struct frame *frame,
    339  1.1  gwr 				   struct fpframe *fpf,
    340  1.1  gwr 				   struct instruction *insn)
    341  1.1  gwr {
    342  1.1  gwr 	int sig;
    343  1.1  gwr 
    344  1.1  gwr 	/* Get effective address */
    345  1.1  gwr 	/* XXX */
    346  1.1  gwr 
    347  1.1  gwr 	switch (insn->opcode & 070) {
    348  1.1  gwr 
    349  1.1  gwr 	case 010:	/* fdbcc */
    350  1.1  gwr 		/* XXX: If not CC { Decrement Dn; if (Dn >= 0) branch; } */
    351  1.1  gwr 
    352  1.1  gwr 	case 070:	/* fscc or ftrapcc */
    353  1.1  gwr 		if ((insn->opcode & 07) > 1) {
    354  1.1  gwr 			/* ftrapcc */
    355  1.1  gwr 			/* XXX: If CC, advance and return SIGFPE */
    356  1.1  gwr 			break;
    357  1.1  gwr 		}
    358  1.1  gwr 		/* fallthrough */
    359  1.1  gwr 	default:	/* fscc */
    360  1.1  gwr 		/* XXX: If CC, store ones, else store zero */
    361  1.1  gwr 		sig = SIGILL;
    362  1.1  gwr 		break;
    363  1.1  gwr 
    364  1.1  gwr 	}
    365  1.1  gwr 	return (sig);
    366  1.1  gwr }
    367  1.1  gwr 
    368  1.1  gwr /*
    369  1.1  gwr  * Type 2 or 3: fbcc (also fnop)
    370  1.1  gwr  * In this function, we know:
    371  1.1  gwr  *   (opcode & 0x0180) == 0x0080
    372  1.1  gwr  */
    373  1.1  gwr int fpu_emul_brcc(struct frame *frame,
    374  1.1  gwr 				  struct fpframe *fpf,
    375  1.1  gwr 				  struct instruction *insn)
    376  1.1  gwr {
    377  1.1  gwr 	int displ, word2;
    378  1.1  gwr 	int sig, advance;
    379  1.1  gwr 
    380  1.1  gwr 	/*
    381  1.1  gwr 	 * Get branch displacement.
    382  1.1  gwr 	 */
    383  1.1  gwr 	advance = 4;
    384  1.1  gwr 	displ = insn->word1;
    385  1.1  gwr 	if (displ & 0x8000)
    386  1.1  gwr 		displ |= 0xFFFF0000;
    387  1.1  gwr 
    388  1.1  gwr 	if (insn->opcode & 0x40) {
    389  1.1  gwr 		word2 = fusword(frame->f_pc + 4);
    390  1.1  gwr 		if (word2 < 0) {
    391  1.1  gwr #ifdef	DEBUG
    392  1.1  gwr 			printf("fpu_emul_brcc: fault reading word2\n");
    393  1.1  gwr #endif
    394  1.1  gwr 			return SIGSEGV;
    395  1.1  gwr 		}
    396  1.1  gwr 		displ << 16;
    397  1.1  gwr 		displ |= word2;
    398  1.1  gwr 		advance += 2;
    399  1.1  gwr 	}
    400  1.1  gwr 
    401  1.1  gwr 	/* XXX: If CC, frame->f_pc += displ */
    402  1.1  gwr 	return SIGILL;
    403  1.1  gwr }
    404  1.1  gwr 
    405  1.1  gwr /*
    406  1.1  gwr  * Helper routines for dealing with "effective address" values.
    407  1.1  gwr  */
    408  1.1  gwr 
    409  1.1  gwr /*
    410  1.1  gwr  * Decode an effective address into internal form.
    411  1.1  gwr  * Returns zero on success, else signal number.
    412  1.1  gwr  */
    413  1.1  gwr static int decode_ea(struct frame *frame,
    414  1.1  gwr 					 struct instruction *insn,
    415  1.1  gwr 					 struct insn_ea *ea,
    416  1.1  gwr 					 int modreg)
    417  1.1  gwr {
    418  1.1  gwr 	int immed_bytes = 0;
    419  1.1  gwr 	int data;
    420  1.1  gwr 
    421  1.1  gwr 	/* Set the most common value here. */
    422  1.1  gwr 	ea->regnum = 8 + (modreg & 7);
    423  1.1  gwr 
    424  1.1  gwr 	switch (modreg & 070) {
    425  1.1  gwr 
    426  1.1  gwr 	case 0:	/* Dn */
    427  1.1  gwr 		ea->regnum = (modreg & 7);
    428  1.1  gwr 		ea->flags = EA_DIRECT;
    429  1.1  gwr 		break;
    430  1.1  gwr 
    431  1.1  gwr 	case 010:	/* An */
    432  1.1  gwr 		ea->flags = EA_DIRECT;
    433  1.1  gwr 		break;
    434  1.1  gwr 
    435  1.1  gwr 	case 020:	/* (An) */
    436  1.1  gwr 		ea->flags = 0;
    437  1.1  gwr 		break;
    438  1.1  gwr 
    439  1.1  gwr 	case 030: /* (An)+ */
    440  1.1  gwr 		ea->flags = EA_POSTINCR;
    441  1.1  gwr 		break;
    442  1.1  gwr 
    443  1.1  gwr 	case 040: /* -(An) */
    444  1.1  gwr 		ea->flags = EA_PREDECR;
    445  1.1  gwr 		break;
    446  1.1  gwr 
    447  1.1  gwr 	case 050: /* (d16,An) */
    448  1.1  gwr 		ea->flags = EA_OFFSET;
    449  1.1  gwr 		immed_bytes = 2;
    450  1.1  gwr 		break;
    451  1.1  gwr 
    452  1.1  gwr 	case 060:	/* (d8,An,Xn) */
    453  1.1  gwr 		ea->flags = EA_INDEXED;
    454  1.1  gwr 		immed_bytes = 2;
    455  1.1  gwr 
    456  1.1  gwr 	case 070:	/* misc. */
    457  1.1  gwr 		ea->regnum = (modreg & 7);
    458  1.1  gwr 		switch (modreg & 7) {
    459  1.1  gwr 
    460  1.1  gwr 		case 0: /* (xxxx).W */
    461  1.1  gwr 			ea->flags = EA_ABS;
    462  1.1  gwr 			immed_bytes = 2;
    463  1.1  gwr 			break;
    464  1.1  gwr 
    465  1.1  gwr 		case 1: /* (xxxxxxxx).L */
    466  1.1  gwr 			ea->flags = EA_ABS;
    467  1.1  gwr 			immed_bytes = 4;
    468  1.1  gwr 			break;
    469  1.1  gwr 
    470  1.1  gwr 		case 2: /* (d16,PC) */
    471  1.1  gwr 			ea->flags = EA_PC_REL | EA_OFFSET;
    472  1.1  gwr 			immed_bytes = 2;
    473  1.1  gwr 			break;
    474  1.1  gwr 
    475  1.1  gwr 		case 3: /* (d8,PC,Xn) */
    476  1.1  gwr 			ea->flags = EA_PC_REL | EA_INDEXED;
    477  1.1  gwr 			immed_bytes = 2;
    478  1.1  gwr 			break;
    479  1.1  gwr 
    480  1.1  gwr 		case 4: /* #data */
    481  1.1  gwr 			ea->flags = EA_IMMED;
    482  1.1  gwr 			immed_bytes = insn->datasize;
    483  1.1  gwr 			break;
    484  1.1  gwr 
    485  1.1  gwr 		default:
    486  1.1  gwr 			return SIGILL;
    487  1.1  gwr 		} /* switch for mode 7 */
    488  1.1  gwr 		break;
    489  1.1  gwr 	} /* switch mode */
    490  1.1  gwr 
    491  1.1  gwr 	/* Now fetch any immediate data and advance. */
    492  1.1  gwr 	if (immed_bytes > 0) {
    493  1.1  gwr 		data = fusword(frame->f_pc + insn->advance);
    494  1.1  gwr 		if (data < 0)
    495  1.1  gwr 			return SIGSEGV;
    496  1.1  gwr 		insn->advance += 2;
    497  1.1  gwr 		if (data & 0x8000)
    498  1.1  gwr 			data |= 0xFFFF0000;
    499  1.1  gwr 		ea->immed = data;
    500  1.1  gwr 	}
    501  1.1  gwr 	if (immed_bytes > 2) {
    502  1.1  gwr 		data = fusword(frame->f_pc + insn->advance);
    503  1.1  gwr 		if (data < 0)
    504  1.1  gwr 			return SIGSEGV;
    505  1.1  gwr 		insn->advance += 2;
    506  1.1  gwr 		ea->immed <<= 16;
    507  1.1  gwr 		ea->immed |= data;
    508  1.1  gwr 	}
    509  1.1  gwr 	return 0;
    510  1.1  gwr }
    511  1.1  gwr 
    512  1.1  gwr 
    513  1.1  gwr /*
    514  1.1  gwr  * Load a value from an effective address.
    515  1.1  gwr  * Returns zero on success, else signal number.
    516  1.1  gwr  */
    517  1.1  gwr static int load_ea(struct frame *frame,
    518  1.1  gwr 				   struct instruction *insn,
    519  1.1  gwr 				   struct insn_ea *ea,
    520  1.1  gwr 				   char *dst)
    521  1.1  gwr {
    522  1.1  gwr 	int *reg;
    523  1.1  gwr 	char *src;
    524  1.1  gwr 	int len;
    525  1.1  gwr 
    526  1.1  gwr #ifdef	DIAGNOSTIC
    527  1.1  gwr 	if (ea->regnum & ~0xF)
    528  1.1  gwr 		panic("load_ea: bad regnum");
    529  1.1  gwr #endif
    530  1.1  gwr 
    531  1.1  gwr 	/* The dst is always int or larger. */
    532  1.1  gwr 	len = insn->datasize;
    533  1.1  gwr 	if (len < 4)
    534  1.1  gwr 		dst += (4 - len);
    535  1.1  gwr 
    536  1.1  gwr 	/* point to the register */
    537  1.1  gwr 	if (ea->flags & EA_PC_REL)
    538  1.1  gwr 		reg = &frame->f_pc;
    539  1.1  gwr 	else
    540  1.1  gwr 		reg = &frame->f_regs[ea->regnum];
    541  1.1  gwr 
    542  1.1  gwr 	if (ea->flags & (EA_DIRECT | EA_IMMED)) {
    543  1.1  gwr 		if (ea->flags & EA_DIRECT)
    544  1.1  gwr 			src = (char*) reg;
    545  1.1  gwr 		if (ea->flags & EA_IMMED)
    546  1.1  gwr 			src = (char*) &ea->immed;
    547  1.1  gwr 		if (len > 4)
    548  1.1  gwr 			return SIGILL;
    549  1.1  gwr 		/* The source is an int. */
    550  1.1  gwr 		if (len < 4)
    551  1.1  gwr 			src += (4 - len);
    552  1.1  gwr 		bcopy(src, dst, len);
    553  1.1  gwr 	} else {
    554  1.1  gwr 		/* One of MANY indirect forms... */
    555  1.1  gwr 
    556  1.1  gwr 		/* do pre-decrement */
    557  1.1  gwr 		if (ea->flags & EA_PREDECR)
    558  1.1  gwr 			*reg -= len;
    559  1.1  gwr 
    560  1.1  gwr 		/* Grab the register contents. */
    561  1.1  gwr 		src = (char*) *reg;
    562  1.1  gwr 
    563  1.1  gwr 		/* apply the signed offset */
    564  1.1  gwr 		if (ea->flags & EA_OFFSET)
    565  1.1  gwr 			src += ea->immed;
    566  1.1  gwr 
    567  1.1  gwr 		/* XXX - Don't know how to handle this yet. */
    568  1.1  gwr 		if (ea->flags & EA_INDEXED)
    569  1.1  gwr 			return SIGILL;
    570  1.1  gwr 
    571  1.1  gwr 		copyin(src, dst, len);
    572  1.1  gwr 
    573  1.1  gwr 		/* do post-increment */
    574  1.1  gwr 		if (ea->flags & EA_POSTINCR)
    575  1.1  gwr 			*reg += len;
    576  1.1  gwr 	}
    577  1.1  gwr 
    578  1.1  gwr 	return 0;
    579  1.1  gwr }
    580  1.1  gwr 
    581  1.1  gwr /*
    582  1.1  gwr  * Store a value at the effective address.
    583  1.1  gwr  * Returns zero on success, else signal number.
    584  1.1  gwr  */
    585  1.1  gwr static int store_ea(struct frame *frame,
    586  1.1  gwr 					struct instruction *insn,
    587  1.1  gwr 					struct insn_ea *ea,
    588  1.1  gwr 					char *src)
    589  1.1  gwr {
    590  1.1  gwr 	int *reg;
    591  1.1  gwr 	char *dst;
    592  1.1  gwr 	int len;
    593  1.1  gwr 
    594  1.1  gwr #ifdef	DIAGNOSTIC
    595  1.1  gwr 	if (ea->regnum & ~0xF)
    596  1.1  gwr 		panic("load_ea: bad regnum");
    597  1.1  gwr #endif
    598  1.1  gwr 
    599  1.1  gwr 	/* The src is always int or larger. */
    600  1.1  gwr 	len = insn->datasize;
    601  1.1  gwr 	if (len < 4)
    602  1.1  gwr 		src += (4 - len);
    603  1.1  gwr 
    604  1.1  gwr 	/* point to the register */
    605  1.1  gwr 	if (ea->flags & EA_PC_REL)
    606  1.1  gwr 		reg = &frame->f_pc;
    607  1.1  gwr 	else
    608  1.1  gwr 		reg = &frame->f_regs[ea->regnum];
    609  1.1  gwr 
    610  1.1  gwr 	if (ea->flags & EA_IMMED)
    611  1.1  gwr 		return SIGILL;
    612  1.1  gwr 
    613  1.1  gwr 	if (ea->flags & EA_DIRECT) {
    614  1.1  gwr 		dst = (char*) reg;
    615  1.1  gwr 		if (len > 4)
    616  1.1  gwr 			return SIGILL;
    617  1.1  gwr 		/* The destination is an int. */
    618  1.1  gwr 		if (len < 4)
    619  1.1  gwr 			dst += (4 - len);
    620  1.1  gwr 		bcopy(src, dst, len);
    621  1.1  gwr 	} else {
    622  1.1  gwr 		/* One of MANY indirect forms... */
    623  1.1  gwr 
    624  1.1  gwr 		/* do pre-decrement */
    625  1.1  gwr 		if (ea->flags & EA_PREDECR)
    626  1.1  gwr 			*reg -= len;
    627  1.1  gwr 
    628  1.1  gwr 		/* Grab the register contents. */
    629  1.1  gwr 		dst = (char*) *reg;
    630  1.1  gwr 
    631  1.1  gwr 		/* apply the signed offset */
    632  1.1  gwr 		if (ea->flags & EA_OFFSET)
    633  1.1  gwr 			dst += ea->immed;
    634  1.1  gwr 
    635  1.1  gwr 		/* XXX - Don't know how to handle this yet. */
    636  1.1  gwr 		if (ea->flags & EA_INDEXED)
    637  1.1  gwr 			return SIGILL;
    638  1.1  gwr 
    639  1.1  gwr 		copyout(src, dst, len);
    640  1.1  gwr 
    641  1.1  gwr 		/* do post-increment */
    642  1.1  gwr 		if (ea->flags & EA_POSTINCR)
    643  1.1  gwr 			*reg += len;
    644  1.1  gwr 	}
    645  1.1  gwr 
    646  1.1  gwr 	return 0;
    647  1.1  gwr }
    648