Home | History | Annotate | Line # | Download | only in fpe
fpu_calcea.c revision 1.23
      1  1.23  tsutsui /*	$NetBSD: fpu_calcea.c,v 1.23 2011/05/25 15:17:21 tsutsui Exp $	*/
      2   1.1   briggs 
      3   1.1   briggs /*
      4   1.1   briggs  * Copyright (c) 1995 Gordon W. Ross
      5   1.1   briggs  * portion Copyright (c) 1995 Ken Nakata
      6   1.1   briggs  * All rights reserved.
      7   1.1   briggs  *
      8   1.1   briggs  * Redistribution and use in source and binary forms, with or without
      9   1.1   briggs  * modification, are permitted provided that the following conditions
     10   1.1   briggs  * are met:
     11   1.1   briggs  * 1. Redistributions of source code must retain the above copyright
     12   1.1   briggs  *    notice, this list of conditions and the following disclaimer.
     13   1.1   briggs  * 2. Redistributions in binary form must reproduce the above copyright
     14   1.1   briggs  *    notice, this list of conditions and the following disclaimer in the
     15   1.1   briggs  *    documentation and/or other materials provided with the distribution.
     16   1.1   briggs  * 3. The name of the author may not be used to endorse or promote products
     17   1.1   briggs  *    derived from this software without specific prior written permission.
     18   1.1   briggs  * 4. All advertising materials mentioning features or use of this software
     19   1.1   briggs  *    must display the following acknowledgement:
     20   1.1   briggs  *      This product includes software developed by Gordon Ross
     21   1.1   briggs  *
     22   1.1   briggs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23   1.1   briggs  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24   1.1   briggs  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25   1.1   briggs  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26   1.1   briggs  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27   1.1   briggs  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28   1.1   briggs  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29   1.1   briggs  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30   1.1   briggs  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31   1.1   briggs  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32   1.1   briggs  */
     33  1.15    lukem 
     34  1.22      mrg #include "opt_m68k_arch.h"
     35  1.22      mrg 
     36  1.15    lukem #include <sys/cdefs.h>
     37  1.23  tsutsui __KERNEL_RCSID(0, "$NetBSD: fpu_calcea.c,v 1.23 2011/05/25 15:17:21 tsutsui Exp $");
     38   1.1   briggs 
     39   1.3   briggs #include <sys/param.h>
     40   1.1   briggs #include <sys/signal.h>
     41   1.4   briggs #include <sys/systm.h>
     42   1.1   briggs #include <machine/frame.h>
     43  1.10       is #include <m68k/m68k.h>
     44   1.1   briggs 
     45   1.1   briggs #include "fpu_emulate.h"
     46   1.1   briggs 
     47   1.1   briggs /*
     48   1.1   briggs  * Prototypes of static functions
     49   1.1   briggs  */
     50  1.23  tsutsui static int decode_ea6(struct frame *, struct instruction *,
     51  1.23  tsutsui 		      struct insn_ea *, int);
     52  1.23  tsutsui static int fetch_immed(struct frame *, struct instruction *, int *);
     53  1.23  tsutsui static int fetch_disp(struct frame *, struct instruction *, int, int *);
     54  1.23  tsutsui static int calc_ea(struct insn_ea *, char *, char **);
     55   1.4   briggs 
     56   1.1   briggs /*
     57   1.1   briggs  * Helper routines for dealing with "effective address" values.
     58   1.1   briggs  */
     59   1.1   briggs 
     60   1.1   briggs /*
     61   1.1   briggs  * Decode an effective address into internal form.
     62   1.1   briggs  * Returns zero on success, else signal number.
     63   1.1   briggs  */
     64   1.1   briggs int
     65  1.23  tsutsui fpu_decode_ea(struct frame *frame, struct instruction *insn,
     66  1.23  tsutsui     struct insn_ea *ea, int modreg)
     67   1.1   briggs {
     68  1.23  tsutsui 	int sig;
     69   1.1   briggs 
     70   1.1   briggs #ifdef DEBUG
     71  1.23  tsutsui 	if (insn->is_datasize < 0)
     72  1.23  tsutsui 		panic("decode_ea: called with uninitialized datasize");
     73   1.1   briggs #endif
     74   1.1   briggs 
     75  1.23  tsutsui 	sig = 0;
     76   1.1   briggs 
     77  1.23  tsutsui 	/* Set the most common value here. */
     78  1.23  tsutsui 	ea->ea_regnum = 8 + (modreg & 7);
     79   1.1   briggs 
     80  1.23  tsutsui 	if ((modreg & 060) == 0) {
     81  1.23  tsutsui 		/* register direct */
     82  1.23  tsutsui 		ea->ea_regnum = modreg & 0xf;
     83  1.23  tsutsui 		ea->ea_flags = EA_DIRECT;
     84   1.8   briggs #ifdef DEBUG_FPE
     85  1.23  tsutsui 		printf("decode_ea: register direct reg=%d\n", ea->ea_regnum);
     86   1.8   briggs #endif
     87  1.23  tsutsui 	} else if ((modreg & 077) == 074) {
     88  1.23  tsutsui 		/* immediate */
     89  1.23  tsutsui 		ea->ea_flags = EA_IMMED;
     90  1.23  tsutsui 		sig = fetch_immed(frame, insn, &ea->ea_immed[0]);
     91   1.8   briggs #ifdef DEBUG_FPE
     92  1.23  tsutsui 		printf("decode_ea: immediate size=%d\n", insn->is_datasize);
     93   1.8   briggs #endif
     94  1.23  tsutsui 	}
     95  1.23  tsutsui 	/*
     96  1.23  tsutsui 	 * rest of the address modes need to be separately
     97  1.23  tsutsui 	 * handled for the LC040 and the others.
     98  1.23  tsutsui 	 */
     99  1.10       is #if 0 /* XXX */
    100  1.23  tsutsui 	else if (frame->f_format == 4 && frame->f_fmt4.f_fa) {
    101  1.23  tsutsui 		/* LC040 */
    102  1.23  tsutsui 		ea->ea_flags = EA_FRAME_EA;
    103  1.23  tsutsui 		ea->ea_fea = frame->f_fmt4.f_fa;
    104  1.23  tsutsui #ifdef DEBUG_FPE
    105  1.23  tsutsui 		printf("decode_ea: 68LC040 - in-frame EA (%p) size %d\n",
    106  1.23  tsutsui 		    (void *)ea->ea_fea, insn->is_datasize);
    107  1.23  tsutsui #endif
    108  1.23  tsutsui 		if ((modreg & 070) == 030) {
    109  1.23  tsutsui 			/* postincrement mode */
    110  1.23  tsutsui 			ea->ea_flags |= EA_POSTINCR;
    111  1.23  tsutsui 		} else if ((modreg & 070) == 040) {
    112  1.23  tsutsui 			/* predecrement mode */
    113  1.23  tsutsui 			ea->ea_flags |= EA_PREDECR;
    114  1.10       is #ifdef M68060
    115  1.10       is #if defined(M68020) || defined(M68030) || defined(M68040)
    116  1.23  tsutsui 			if (cputype == CPU_68060)
    117  1.10       is #endif
    118  1.23  tsutsui 				if (insn->is_datasize == 12)
    119  1.23  tsutsui 					ea->ea_fea -= 8;
    120  1.10       is #endif
    121  1.23  tsutsui 		}
    122   1.1   briggs 	}
    123  1.10       is #endif /* XXX */
    124  1.23  tsutsui 	else {
    125  1.23  tsutsui 		/* 020/030 */
    126  1.23  tsutsui 		switch (modreg & 070) {
    127   1.1   briggs 
    128  1.23  tsutsui 		case 020:			/* (An) */
    129  1.23  tsutsui 			ea->ea_flags = 0;
    130   1.8   briggs #ifdef DEBUG_FPE
    131  1.23  tsutsui 			printf("decode_ea: register indirect reg=%d\n",
    132  1.23  tsutsui 			    ea->ea_regnum);
    133   1.8   briggs #endif
    134  1.23  tsutsui 			break;
    135   1.1   briggs 
    136  1.23  tsutsui 		case 030:			/* (An)+ */
    137  1.23  tsutsui 			ea->ea_flags = EA_POSTINCR;
    138   1.8   briggs #ifdef DEBUG_FPE
    139  1.23  tsutsui 			printf("decode_ea: reg indirect postincrement reg=%d\n",
    140  1.23  tsutsui 			    ea->ea_regnum);
    141   1.8   briggs #endif
    142  1.23  tsutsui 			break;
    143   1.1   briggs 
    144  1.23  tsutsui 		case 040:			/* -(An) */
    145  1.23  tsutsui 			ea->ea_flags = EA_PREDECR;
    146   1.8   briggs #ifdef DEBUG_FPE
    147  1.23  tsutsui 			printf("decode_ea: reg indirect predecrement reg=%d\n",
    148  1.23  tsutsui 			    ea->ea_regnum);
    149   1.8   briggs #endif
    150  1.23  tsutsui 			break;
    151   1.1   briggs 
    152  1.23  tsutsui 		case 050:			/* (d16,An) */
    153  1.23  tsutsui 			ea->ea_flags = EA_OFFSET;
    154  1.23  tsutsui 			sig = fetch_disp(frame, insn, 1, &ea->ea_offset);
    155   1.8   briggs #ifdef DEBUG_FPE
    156  1.23  tsutsui 			printf("decode_ea: reg indirect with displacement "
    157  1.23  tsutsui 			    "reg=%d\n", ea->ea_regnum);
    158   1.8   briggs #endif
    159  1.23  tsutsui 		break;
    160   1.1   briggs 
    161  1.23  tsutsui 		case 060:			/* (d8,An,Xn) */
    162  1.23  tsutsui 			ea->ea_flags = EA_INDEXED;
    163  1.23  tsutsui 			sig = decode_ea6(frame, insn, ea, modreg);
    164  1.23  tsutsui 			break;
    165   1.1   briggs 
    166  1.23  tsutsui 		case 070:			/* misc. */
    167  1.23  tsutsui 			ea->ea_regnum = (modreg & 7);
    168  1.23  tsutsui 			switch (modreg & 7) {
    169   1.8   briggs 
    170  1.23  tsutsui 			case 0:			/* (xxxx).W */
    171  1.23  tsutsui 				ea->ea_flags = EA_ABS;
    172  1.23  tsutsui 				sig = fetch_disp(frame, insn, 1,
    173  1.23  tsutsui 				    &ea->ea_absaddr);
    174   1.8   briggs #ifdef DEBUG_FPE
    175  1.23  tsutsui 				printf("decode_ea: absolute address (word)\n");
    176   1.8   briggs #endif
    177  1.23  tsutsui 				break;
    178   1.1   briggs 
    179  1.23  tsutsui 			case 1:			/* (xxxxxxxx).L */
    180  1.23  tsutsui 				ea->ea_flags = EA_ABS;
    181  1.23  tsutsui 				sig = fetch_disp(frame, insn, 2,
    182  1.23  tsutsui 				    &ea->ea_absaddr);
    183   1.8   briggs #ifdef DEBUG_FPE
    184  1.23  tsutsui 				printf("decode_ea: absolute address (long)\n");
    185   1.8   briggs #endif
    186  1.23  tsutsui 				break;
    187   1.1   briggs 
    188  1.23  tsutsui 			case 2:			/* (d16,PC) */
    189  1.23  tsutsui 				ea->ea_flags = EA_PC_REL | EA_OFFSET;
    190  1.23  tsutsui 				sig = fetch_disp(frame, insn, 1,
    191  1.23  tsutsui 				    &ea->ea_absaddr);
    192   1.8   briggs #ifdef DEBUG_FPE
    193  1.23  tsutsui 				printf("decode_ea: pc relative word "
    194  1.23  tsutsui 				    "displacement\n");
    195   1.8   briggs #endif
    196  1.23  tsutsui 				break;
    197   1.1   briggs 
    198  1.23  tsutsui 			case 3:			/* (d8,PC,Xn) */
    199  1.23  tsutsui 				ea->ea_flags = EA_PC_REL | EA_INDEXED;
    200  1.23  tsutsui 				sig = decode_ea6(frame, insn, ea, modreg);
    201  1.23  tsutsui 				break;
    202   1.8   briggs 
    203  1.23  tsutsui 			case 4:			/* #data */
    204  1.23  tsutsui 				/* it should have been taken care of earlier */
    205  1.23  tsutsui 			default:
    206   1.8   briggs #ifdef DEBUG_FPE
    207  1.23  tsutsui 				printf("decode_ea: invalid addr mode (7,%d)\n",
    208  1.23  tsutsui 				    modreg & 7);
    209   1.8   briggs #endif
    210  1.23  tsutsui 				return SIGILL;
    211  1.23  tsutsui 			}
    212  1.23  tsutsui 			break;
    213  1.23  tsutsui 		}
    214  1.23  tsutsui 	}
    215  1.23  tsutsui 	ea->ea_moffs = 0;
    216   1.1   briggs 
    217  1.23  tsutsui 	return sig;
    218   1.1   briggs }
    219   1.1   briggs 
    220   1.1   briggs /*
    221   1.1   briggs  * Decode Mode=6 address modes
    222   1.1   briggs  */
    223   1.1   briggs static int
    224  1.23  tsutsui decode_ea6(struct frame *frame, struct instruction *insn, struct insn_ea *ea,
    225  1.23  tsutsui     int modreg)
    226   1.1   briggs {
    227  1.23  tsutsui 	int extword, idx;
    228  1.23  tsutsui 	int basedisp, outerdisp;
    229  1.23  tsutsui 	int bd_size, od_size;
    230  1.23  tsutsui 	int sig;
    231  1.23  tsutsui 
    232  1.23  tsutsui 	extword = fusword((void *)(insn->is_pc + insn->is_advance));
    233  1.23  tsutsui 	if (extword < 0) {
    234  1.23  tsutsui 		return SIGSEGV;
    235   1.1   briggs 	}
    236  1.23  tsutsui 	insn->is_advance += 2;
    237   1.1   briggs 
    238  1.23  tsutsui 	/* get register index */
    239  1.23  tsutsui 	ea->ea_idxreg = (extword >> 12) & 0xf;
    240  1.23  tsutsui 	idx = frame->f_regs[ea->ea_idxreg];
    241  1.23  tsutsui 	if ((extword & 0x0800) == 0) {
    242  1.23  tsutsui 		/* if word sized index, sign-extend */
    243  1.23  tsutsui 		idx &= 0xffff;
    244  1.23  tsutsui 		if (idx & 0x8000) {
    245  1.23  tsutsui 			idx |= 0xffff0000;
    246  1.23  tsutsui 		}
    247  1.23  tsutsui 	}
    248  1.23  tsutsui 	/* scale register index */
    249  1.23  tsutsui 	idx <<= ((extword >> 9) & 3);
    250  1.23  tsutsui 
    251  1.23  tsutsui 	if ((extword & 0x100) == 0) {
    252  1.23  tsutsui 		/* brief extension word - sign-extend the displacement */
    253  1.23  tsutsui 		basedisp = (extword & 0xff);
    254  1.23  tsutsui 		if (basedisp & 0x80) {
    255  1.23  tsutsui 			basedisp |= 0xffffff00;
    256  1.23  tsutsui 		}
    257  1.23  tsutsui 
    258  1.23  tsutsui 		ea->ea_basedisp = idx + basedisp;
    259  1.23  tsutsui 		ea->ea_outerdisp = 0;
    260   1.8   briggs #if DEBUG_FPE
    261  1.23  tsutsui 		printf("decode_ea6: brief ext word idxreg=%d, basedisp=%08x\n",
    262  1.23  tsutsui 		    ea->ea_idxreg, ea->ea_basedisp);
    263   1.8   briggs #endif
    264  1.23  tsutsui 	} else {
    265  1.23  tsutsui 		/* full extension word */
    266  1.23  tsutsui 		if (extword & 0x80) {
    267  1.23  tsutsui 			ea->ea_flags |= EA_BASE_SUPPRSS;
    268  1.23  tsutsui 		}
    269  1.23  tsutsui 		bd_size = ((extword >> 4) & 3) - 1;
    270  1.23  tsutsui 		od_size = (extword & 3) - 1;
    271  1.23  tsutsui 		sig = fetch_disp(frame, insn, bd_size, &basedisp);
    272  1.23  tsutsui 		if (sig)
    273  1.23  tsutsui 			return sig;
    274  1.23  tsutsui 		if (od_size >= 0)
    275  1.23  tsutsui 			ea->ea_flags |= EA_MEM_INDIR;
    276  1.23  tsutsui 		sig = fetch_disp(frame, insn, od_size, &outerdisp);
    277  1.23  tsutsui 		if (sig)
    278  1.23  tsutsui 			return sig;
    279  1.23  tsutsui 
    280  1.23  tsutsui 		switch (extword & 0x44) {
    281  1.23  tsutsui 		case 0:			/* preindexed */
    282  1.23  tsutsui 			ea->ea_basedisp = basedisp + idx;
    283  1.23  tsutsui 			ea->ea_outerdisp = outerdisp;
    284  1.23  tsutsui 			break;
    285  1.23  tsutsui 		case 4:			/* postindexed */
    286  1.23  tsutsui 			ea->ea_basedisp = basedisp;
    287  1.23  tsutsui 			ea->ea_outerdisp = outerdisp + idx;
    288  1.23  tsutsui 			break;
    289  1.23  tsutsui 		case 0x40:		/* no index */
    290  1.23  tsutsui 			ea->ea_basedisp = basedisp;
    291  1.23  tsutsui 			ea->ea_outerdisp = outerdisp;
    292  1.23  tsutsui 			break;
    293  1.23  tsutsui 		default:
    294   1.1   briggs #ifdef DEBUG
    295  1.23  tsutsui 			printf("decode_ea6: invalid indirect mode: "
    296  1.23  tsutsui 			    "ext word %04x\n", extword);
    297   1.1   briggs #endif
    298  1.23  tsutsui 			return SIGILL;
    299  1.23  tsutsui 			break;
    300  1.23  tsutsui 		}
    301   1.8   briggs #if DEBUG_FPE
    302  1.23  tsutsui 		printf("decode_ea6: full ext idxreg=%d, basedisp=%x, "
    303  1.23  tsutsui 		    "outerdisp=%x\n",
    304  1.23  tsutsui 		    ea->ea_idxreg, ea->ea_basedisp, ea->ea_outerdisp);
    305   1.8   briggs #endif
    306  1.23  tsutsui 	}
    307   1.8   briggs #if DEBUG_FPE
    308  1.23  tsutsui 	printf("decode_ea6: regnum=%d, flags=%x\n",
    309  1.23  tsutsui 	    ea->ea_regnum, ea->ea_flags);
    310   1.8   briggs #endif
    311  1.23  tsutsui 	return 0;
    312   1.1   briggs }
    313   1.1   briggs 
    314   1.1   briggs /*
    315   1.1   briggs  * Load a value from an effective address.
    316   1.1   briggs  * Returns zero on success, else signal number.
    317   1.1   briggs  */
    318   1.1   briggs int
    319  1.23  tsutsui fpu_load_ea(struct frame *frame, struct instruction *insn, struct insn_ea *ea,
    320  1.23  tsutsui     char *dst)
    321   1.1   briggs {
    322  1.23  tsutsui 	int *reg;
    323  1.23  tsutsui 	char *src;
    324  1.23  tsutsui 	int len, step;
    325  1.23  tsutsui 	int sig;
    326   1.1   briggs 
    327   1.8   briggs #ifdef DIAGNOSTIC
    328  1.23  tsutsui 	if (ea->ea_regnum & ~0xF)
    329  1.23  tsutsui 		panic("load_ea: bad regnum");
    330   1.1   briggs #endif
    331   1.1   briggs 
    332   1.8   briggs #ifdef DEBUG_FPE
    333  1.23  tsutsui 	printf("load_ea: frame at %p\n", frame);
    334   1.8   briggs #endif
    335  1.23  tsutsui 	/* dst is always int or larger. */
    336  1.23  tsutsui 	len = insn->is_datasize;
    337  1.23  tsutsui 	if (len < 4)
    338  1.23  tsutsui 		dst += (4 - len);
    339  1.23  tsutsui 	step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
    340   1.1   briggs 
    341  1.11       is #if 0
    342  1.23  tsutsui 	if (ea->ea_flags & EA_FRAME_EA) {
    343  1.23  tsutsui 		/* Using LC040 frame EA */
    344   1.8   briggs #ifdef DEBUG_FPE
    345  1.23  tsutsui 		if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) {
    346  1.23  tsutsui 			printf("load_ea: frame ea %08x w/r%d\n",
    347   1.8   briggs 		   ea->ea_fea, ea->ea_regnum);
    348  1.23  tsutsui 		} else {
    349  1.23  tsutsui 			printf("load_ea: frame ea %08x\n", ea->ea_fea);
    350  1.23  tsutsui 		}
    351  1.23  tsutsui #endif
    352  1.23  tsutsui 		src = (char *)ea->ea_fea;
    353  1.23  tsutsui 		copyin(src + ea->ea_moffs, dst, len);
    354  1.23  tsutsui 		if (ea->ea_flags & EA_PREDECR) {
    355  1.23  tsutsui 			frame->f_regs[ea->ea_regnum] = ea->ea_fea;
    356  1.23  tsutsui 			ea->ea_fea -= step;
    357  1.23  tsutsui 			ea->ea_moffs = 0;
    358  1.23  tsutsui 		} else if (ea->ea_flags & EA_POSTINCR) {
    359  1.23  tsutsui 			ea->ea_fea += step;
    360  1.23  tsutsui 			frame->f_regs[ea->ea_regnum] = ea->ea_fea;
    361  1.23  tsutsui 			ea->ea_moffs = 0;
    362  1.23  tsutsui 		} else {
    363  1.23  tsutsui 			ea->ea_moffs += step;
    364  1.23  tsutsui 		}
    365  1.23  tsutsui 		/* That's it, folks */
    366  1.23  tsutsui 	} else
    367   1.8   briggs #endif
    368  1.23  tsutsui 	if (ea->ea_flags & EA_DIRECT) {
    369  1.23  tsutsui 		if (len > 4) {
    370   1.1   briggs #ifdef DEBUG
    371  1.23  tsutsui 			printf("load_ea: operand doesn't fit CPU reg\n");
    372   1.1   briggs #endif
    373  1.23  tsutsui 			return SIGILL;
    374  1.23  tsutsui 		}
    375  1.23  tsutsui 		if (ea->ea_moffs > 0) {
    376   1.1   briggs #ifdef DEBUG
    377  1.23  tsutsui 			printf("load_ea: more than one move from CPU reg\n");
    378   1.1   briggs #endif
    379  1.23  tsutsui 			return SIGILL;
    380  1.23  tsutsui 		}
    381  1.23  tsutsui 		src = (char *)&frame->f_regs[ea->ea_regnum];
    382  1.23  tsutsui 		/* The source is an int. */
    383  1.23  tsutsui 		if (len < 4) {
    384  1.23  tsutsui 			src += (4 - len);
    385   1.8   briggs #ifdef DEBUG_FPE
    386  1.23  tsutsui 			printf("load_ea: short/byte opr - addr adjusted\n");
    387   1.8   briggs #endif
    388  1.23  tsutsui 		}
    389   1.8   briggs #ifdef DEBUG_FPE
    390  1.23  tsutsui 		printf("load_ea: src %p\n", src);
    391   1.8   briggs #endif
    392  1.23  tsutsui 		memcpy(dst, src, len);
    393  1.23  tsutsui 	} else if (ea->ea_flags & EA_IMMED) {
    394   1.8   briggs #ifdef DEBUG_FPE
    395  1.23  tsutsui 		printf("load_ea: immed %08x%08x%08x size %d\n",
    396  1.23  tsutsui 		    ea->ea_immed[0], ea->ea_immed[1], ea->ea_immed[2], len);
    397   1.8   briggs #endif
    398  1.23  tsutsui 		src = (char *)&ea->ea_immed[0];
    399  1.23  tsutsui 		if (len < 4) {
    400  1.23  tsutsui 			src += (4 - len);
    401   1.8   briggs #ifdef DEBUG_FPE
    402  1.23  tsutsui 			printf("load_ea: short/byte immed opr - "
    403  1.23  tsutsui 			    "addr adjusted\n");
    404   1.8   briggs #endif
    405  1.23  tsutsui 		}
    406  1.23  tsutsui 		memcpy(dst, src, len);
    407  1.23  tsutsui 	} else if (ea->ea_flags & EA_ABS) {
    408   1.8   briggs #ifdef DEBUG_FPE
    409  1.23  tsutsui 		printf("load_ea: abs addr %08x\n", ea->ea_absaddr);
    410   1.8   briggs #endif
    411  1.23  tsutsui 		src = (char *)ea->ea_absaddr;
    412  1.23  tsutsui 		copyin(src, dst, len);
    413  1.23  tsutsui 	} else /* register indirect */ {
    414  1.23  tsutsui 		if (ea->ea_flags & EA_PC_REL) {
    415   1.8   briggs #ifdef DEBUG_FPE
    416  1.23  tsutsui 			printf("load_ea: using PC\n");
    417   1.8   briggs #endif
    418  1.23  tsutsui 			reg = NULL;
    419  1.23  tsutsui 			/*
    420  1.23  tsutsui 			 * Grab the register contents. 4 is offset to the first
    421  1.23  tsutsui 			 * extension word from the opcode
    422  1.23  tsutsui 			 */
    423  1.23  tsutsui 			src = (char *)insn->is_pc + 4;
    424   1.8   briggs #ifdef DEBUG_FPE
    425  1.23  tsutsui 			printf("load_ea: pc relative pc+4 = %p\n", src);
    426   1.8   briggs #endif
    427  1.23  tsutsui 		} else /* not PC relative */ {
    428   1.8   briggs #ifdef DEBUG_FPE
    429  1.23  tsutsui 			printf("load_ea: using register %c%d\n",
    430  1.23  tsutsui 			(ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7);
    431   1.8   briggs #endif
    432  1.23  tsutsui 			/* point to the register */
    433  1.23  tsutsui 			reg = &frame->f_regs[ea->ea_regnum];
    434   1.1   briggs 
    435  1.23  tsutsui 			if (ea->ea_flags & EA_PREDECR) {
    436   1.8   briggs #ifdef DEBUG_FPE
    437  1.23  tsutsui 				printf("load_ea: predecr mode - "
    438  1.23  tsutsui 				    "reg decremented\n");
    439   1.8   briggs #endif
    440  1.23  tsutsui 				*reg -= step;
    441  1.23  tsutsui 				ea->ea_moffs = 0;
    442  1.23  tsutsui 			}
    443   1.1   briggs 
    444  1.23  tsutsui 			/* Grab the register contents. */
    445  1.23  tsutsui 			src = (char *)*reg;
    446   1.8   briggs #ifdef DEBUG_FPE
    447  1.23  tsutsui 			printf("load_ea: reg indirect reg = %p\n", src);
    448   1.8   briggs #endif
    449  1.23  tsutsui 		}
    450   1.1   briggs 
    451  1.23  tsutsui 		sig = calc_ea(ea, src, &src);
    452  1.23  tsutsui 		if (sig)
    453  1.23  tsutsui 			return sig;
    454   1.1   briggs 
    455  1.23  tsutsui 		copyin(src + ea->ea_moffs, dst, len);
    456   1.1   briggs 
    457  1.23  tsutsui 		/* do post-increment */
    458  1.23  tsutsui 		if (ea->ea_flags & EA_POSTINCR) {
    459  1.23  tsutsui 			if (ea->ea_flags & EA_PC_REL) {
    460   1.1   briggs #ifdef DEBUG
    461  1.23  tsutsui 				printf("load_ea: tried to postincrement PC\n");
    462   1.1   briggs #endif
    463  1.23  tsutsui 				return SIGILL;
    464  1.23  tsutsui 			}
    465  1.23  tsutsui 			*reg += step;
    466  1.23  tsutsui 			ea->ea_moffs = 0;
    467   1.8   briggs #ifdef DEBUG_FPE
    468  1.23  tsutsui 			printf("load_ea: postinc mode - reg incremented\n");
    469   1.8   briggs #endif
    470  1.23  tsutsui 		} else {
    471  1.23  tsutsui 			ea->ea_moffs += len;
    472  1.23  tsutsui 		}
    473   1.1   briggs 	}
    474   1.1   briggs 
    475  1.23  tsutsui 	return 0;
    476   1.1   briggs }
    477   1.1   briggs 
    478   1.1   briggs /*
    479   1.1   briggs  * Store a value at the effective address.
    480   1.1   briggs  * Returns zero on success, else signal number.
    481   1.1   briggs  */
    482   1.1   briggs int
    483  1.23  tsutsui fpu_store_ea(struct frame *frame, struct instruction *insn, struct insn_ea *ea,
    484  1.23  tsutsui     char *src)
    485   1.1   briggs {
    486  1.23  tsutsui 	int *reg;
    487  1.23  tsutsui 	char *dst;
    488  1.23  tsutsui 	int len, step;
    489  1.23  tsutsui 	int sig;
    490   1.1   briggs 
    491   1.1   briggs #ifdef	DIAGNOSTIC
    492  1.23  tsutsui 	if (ea->ea_regnum & ~0xf)
    493  1.23  tsutsui 		panic("store_ea: bad regnum");
    494   1.1   briggs #endif
    495   1.1   briggs 
    496  1.23  tsutsui 	if (ea->ea_flags & (EA_IMMED|EA_PC_REL)) {
    497  1.23  tsutsui 		/* not alterable address mode */
    498   1.1   briggs #ifdef DEBUG
    499  1.23  tsutsui 		printf("store_ea: not alterable address mode\n");
    500   1.1   briggs #endif
    501  1.23  tsutsui 		return SIGILL;
    502  1.23  tsutsui 	}
    503   1.1   briggs 
    504  1.23  tsutsui 	/* src is always int or larger. */
    505  1.23  tsutsui 	len = insn->is_datasize;
    506  1.23  tsutsui 	if (len < 4)
    507  1.23  tsutsui 		src += (4 - len);
    508  1.23  tsutsui 	step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
    509  1.23  tsutsui 
    510  1.23  tsutsui 	if (ea->ea_flags & EA_FRAME_EA) {
    511  1.23  tsutsui 		/* Using LC040 frame EA */
    512  1.23  tsutsui #ifdef DEBUG_FPE
    513  1.23  tsutsui 		if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) {
    514  1.23  tsutsui 			printf("store_ea: frame ea %08x w/r%d\n",
    515  1.23  tsutsui 			    ea->ea_fea, ea->ea_regnum);
    516  1.23  tsutsui 		} else {
    517  1.23  tsutsui 			printf("store_ea: frame ea %08x\n", ea->ea_fea);
    518  1.23  tsutsui 		}
    519  1.23  tsutsui #endif
    520  1.23  tsutsui 		dst = (char *)ea->ea_fea;
    521  1.23  tsutsui 		copyout(src, dst + ea->ea_moffs, len);
    522  1.23  tsutsui 		if (ea->ea_flags & EA_PREDECR) {
    523  1.23  tsutsui 			frame->f_regs[ea->ea_regnum] = ea->ea_fea;
    524  1.23  tsutsui 			ea->ea_fea -= step;
    525  1.23  tsutsui 			ea->ea_moffs = 0;
    526  1.23  tsutsui 		} else if (ea->ea_flags & EA_POSTINCR) {
    527  1.23  tsutsui 			ea->ea_fea += step;
    528  1.23  tsutsui 			frame->f_regs[ea->ea_regnum] = ea->ea_fea;
    529  1.23  tsutsui 			ea->ea_moffs = 0;
    530  1.23  tsutsui 		} else {
    531  1.23  tsutsui 			ea->ea_moffs += step;
    532  1.23  tsutsui 		}
    533  1.23  tsutsui 		/* That's it, folks */
    534  1.23  tsutsui 	} else if (ea->ea_flags & EA_ABS) {
    535  1.23  tsutsui #ifdef DEBUG_FPE
    536  1.23  tsutsui 		printf("store_ea: abs addr %08x\n", ea->ea_absaddr);
    537  1.23  tsutsui #endif
    538  1.23  tsutsui 		dst = (char *)ea->ea_absaddr;
    539  1.23  tsutsui 		copyout(src, dst + ea->ea_moffs, len);
    540  1.23  tsutsui 		ea->ea_moffs += len;
    541  1.23  tsutsui 	} else if (ea->ea_flags & EA_DIRECT) {
    542  1.23  tsutsui 		if (len > 4) {
    543   1.1   briggs #ifdef DEBUG
    544  1.23  tsutsui 			printf("store_ea: operand doesn't fit CPU reg\n");
    545   1.1   briggs #endif
    546  1.23  tsutsui 			return SIGILL;
    547  1.23  tsutsui 		}
    548  1.23  tsutsui 		if (ea->ea_moffs > 0) {
    549   1.1   briggs #ifdef DEBUG
    550  1.23  tsutsui 			printf("store_ea: more than one move to CPU reg\n");
    551   1.1   briggs #endif
    552  1.23  tsutsui 			return SIGILL;
    553  1.23  tsutsui 		}
    554  1.23  tsutsui 		dst = (char *)&frame->f_regs[ea->ea_regnum];
    555  1.23  tsutsui 		/* The destination is an int. */
    556  1.23  tsutsui 		if (len < 4) {
    557  1.23  tsutsui 			dst += (4 - len);
    558   1.8   briggs #ifdef DEBUG_FPE
    559  1.23  tsutsui 			printf("store_ea: short/byte opr - "
    560  1.23  tsutsui 			    "dst addr adjusted\n");
    561   1.8   briggs #endif
    562  1.23  tsutsui 		}
    563   1.8   briggs #ifdef DEBUG_FPE
    564  1.23  tsutsui 		printf("store_ea: dst %p\n", dst);
    565   1.8   briggs #endif
    566  1.23  tsutsui 		memcpy(dst, src, len);
    567  1.23  tsutsui 	} else /* One of MANY indirect forms... */ {
    568   1.8   briggs #ifdef DEBUG_FPE
    569  1.23  tsutsui 		printf("store_ea: using register %c%d\n",
    570  1.23  tsutsui 		    (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7);
    571   1.8   briggs #endif
    572  1.23  tsutsui 		/* point to the register */
    573  1.23  tsutsui 		reg = &(frame->f_regs[ea->ea_regnum]);
    574   1.1   briggs 
    575  1.23  tsutsui 		/* do pre-decrement */
    576  1.23  tsutsui 		if (ea->ea_flags & EA_PREDECR) {
    577   1.8   briggs #ifdef DEBUG_FPE
    578  1.23  tsutsui 			printf("store_ea: predecr mode - reg decremented\n");
    579   1.8   briggs #endif
    580  1.23  tsutsui 			*reg -= step;
    581  1.23  tsutsui 			ea->ea_moffs = 0;
    582  1.23  tsutsui 		}
    583   1.1   briggs 
    584  1.23  tsutsui 		/* calculate the effective address */
    585  1.23  tsutsui 		sig = calc_ea(ea, (char *)*reg, &dst);
    586  1.23  tsutsui 		if (sig)
    587  1.23  tsutsui 			return sig;
    588   1.1   briggs 
    589   1.8   briggs #ifdef DEBUG_FPE
    590  1.23  tsutsui 		printf("store_ea: dst addr=%p+%d\n", dst, ea->ea_moffs);
    591   1.8   briggs #endif
    592  1.23  tsutsui 		copyout(src, dst + ea->ea_moffs, len);
    593   1.1   briggs 
    594  1.23  tsutsui 		/* do post-increment */
    595  1.23  tsutsui 		if (ea->ea_flags & EA_POSTINCR) {
    596  1.23  tsutsui 			*reg += step;
    597  1.23  tsutsui 			ea->ea_moffs = 0;
    598   1.8   briggs #ifdef DEBUG_FPE
    599  1.23  tsutsui 			printf("store_ea: postinc mode - reg incremented\n");
    600   1.8   briggs #endif
    601  1.23  tsutsui 		} else {
    602  1.23  tsutsui 			ea->ea_moffs += len;
    603  1.23  tsutsui 		}
    604   1.1   briggs 	}
    605   1.1   briggs 
    606  1.23  tsutsui 	return 0;
    607   1.1   briggs }
    608   1.1   briggs 
    609   1.1   briggs /*
    610   1.1   briggs  * fetch_immed: fetch immediate operand
    611   1.1   briggs  */
    612   1.1   briggs static int
    613  1.20      dsl fetch_immed(struct frame *frame, struct instruction *insn, int *dst)
    614   1.1   briggs {
    615  1.23  tsutsui 	int data, ext_bytes;
    616   1.1   briggs 
    617  1.23  tsutsui 	ext_bytes = insn->is_datasize;
    618   1.1   briggs 
    619  1.23  tsutsui 	if (0 < ext_bytes) {
    620  1.23  tsutsui 		data = fusword((void *)(insn->is_pc + insn->is_advance));
    621  1.23  tsutsui 		if (data < 0)
    622  1.23  tsutsui 			return SIGSEGV;
    623  1.23  tsutsui 		if (ext_bytes == 1) {
    624  1.23  tsutsui 			/* sign-extend byte to long */
    625  1.23  tsutsui 			data &= 0xff;
    626  1.23  tsutsui 			if (data & 0x80)
    627  1.23  tsutsui 				data |= 0xffffff00;
    628  1.23  tsutsui 		} else if (ext_bytes == 2) {
    629  1.23  tsutsui 			/* sign-extend word to long */
    630  1.23  tsutsui 			data &= 0xffff;
    631  1.23  tsutsui 			if (data & 0x8000)
    632  1.23  tsutsui 			data |= 0xffff0000;
    633  1.23  tsutsui 		}
    634  1.23  tsutsui 		insn->is_advance += 2;
    635  1.23  tsutsui 		dst[0] = data;
    636  1.23  tsutsui 	}
    637  1.23  tsutsui 	if (2 < ext_bytes) {
    638  1.23  tsutsui 		data = fusword((void *)(insn->is_pc + insn->is_advance));
    639  1.23  tsutsui 		if (data < 0)
    640  1.23  tsutsui 			return SIGSEGV;
    641  1.23  tsutsui 		insn->is_advance += 2;
    642  1.23  tsutsui 		dst[0] <<= 16;
    643  1.23  tsutsui 		dst[0] |= data;
    644  1.23  tsutsui 	}
    645  1.23  tsutsui 	if (4 < ext_bytes) {
    646  1.23  tsutsui 		data = fusword((void *)(insn->is_pc + insn->is_advance));
    647  1.23  tsutsui 		if (data < 0)
    648  1.23  tsutsui 			return SIGSEGV;
    649  1.23  tsutsui 		dst[1] = data << 16;
    650  1.23  tsutsui 		data = fusword((void *)(insn->is_pc + insn->is_advance + 2));
    651  1.23  tsutsui 		if (data < 0)
    652  1.23  tsutsui 			return SIGSEGV;
    653  1.23  tsutsui 		insn->is_advance += 4;
    654  1.23  tsutsui 		dst[1] |= data;
    655  1.23  tsutsui 	}
    656  1.23  tsutsui 	if (8 < ext_bytes) {
    657  1.23  tsutsui 		data = fusword((void *)(insn->is_pc + insn->is_advance));
    658  1.23  tsutsui 		if (data < 0)
    659  1.23  tsutsui 			return SIGSEGV;
    660  1.23  tsutsui 		dst[2] = data << 16;
    661  1.23  tsutsui 		data = fusword((void *)(insn->is_pc + insn->is_advance + 2));
    662  1.23  tsutsui 		if (data < 0)
    663  1.23  tsutsui 			return SIGSEGV;
    664  1.23  tsutsui 		insn->is_advance += 4;
    665  1.23  tsutsui 		dst[2] |= data;
    666   1.1   briggs 	}
    667   1.1   briggs 
    668  1.23  tsutsui 	return 0;
    669   1.1   briggs }
    670   1.1   briggs 
    671   1.1   briggs /*
    672  1.12   toshii  * fetch_disp: fetch displacement in full extension words
    673   1.1   briggs  */
    674   1.1   briggs static int
    675  1.21      dsl fetch_disp(struct frame *frame, struct instruction *insn, int size, int *res)
    676   1.1   briggs {
    677  1.23  tsutsui 	int disp, word;
    678   1.1   briggs 
    679  1.23  tsutsui 	if (size == 1) {
    680  1.23  tsutsui 		word = fusword((void *)(insn->is_pc + insn->is_advance));
    681  1.23  tsutsui 		if (word < 0)
    682  1.23  tsutsui 			return SIGSEGV;
    683  1.23  tsutsui 		disp = word & 0xffff;
    684  1.23  tsutsui 		if (disp & 0x8000) {
    685  1.23  tsutsui 			/* sign-extend */
    686  1.23  tsutsui 			disp |= 0xffff0000;
    687  1.23  tsutsui 		}
    688  1.23  tsutsui 		insn->is_advance += 2;
    689  1.23  tsutsui 	} else if (size == 2) {
    690  1.23  tsutsui 		word = fusword((void *)(insn->is_pc + insn->is_advance));
    691  1.23  tsutsui 		if (word < 0)
    692  1.23  tsutsui 			return SIGSEGV;
    693  1.23  tsutsui 		disp = word << 16;
    694  1.23  tsutsui 		word = fusword((void *)(insn->is_pc + insn->is_advance + 2));
    695  1.23  tsutsui 		if (word < 0)
    696  1.23  tsutsui 			return SIGSEGV;
    697  1.23  tsutsui 		disp |= (word & 0xffff);
    698  1.23  tsutsui 		insn->is_advance += 4;
    699  1.23  tsutsui 	} else {
    700  1.23  tsutsui 		disp = 0;
    701   1.1   briggs 	}
    702  1.23  tsutsui 	*res = disp;
    703  1.23  tsutsui 	return 0;
    704   1.1   briggs }
    705   1.1   briggs 
    706   1.1   briggs /*
    707   1.1   briggs  * Calculates an effective address for all address modes except for
    708   1.1   briggs  * register direct, absolute, and immediate modes.  However, it does
    709   1.1   briggs  * not take care of predecrement/postincrement of register content.
    710   1.1   briggs  * Returns a signal value (0 == no error).
    711   1.1   briggs  */
    712   1.1   briggs static int
    713  1.21      dsl calc_ea(struct insn_ea *ea, char *ptr, char **eaddr)
    714  1.21      dsl 	/* ptr:		 base address (usually a register content) */
    715  1.21      dsl 	/* eaddr:	 pointer to result pointer */
    716   1.1   briggs {
    717  1.23  tsutsui 	int data, word;
    718   1.1   briggs 
    719   1.8   briggs #if DEBUG_FPE
    720  1.23  tsutsui 	printf("calc_ea: reg indirect (reg) = %p\n", ptr);
    721   1.8   briggs #endif
    722   1.1   briggs 
    723  1.23  tsutsui 	if (ea->ea_flags & EA_OFFSET) {
    724  1.23  tsutsui 		/* apply the signed offset */
    725   1.8   briggs #if DEBUG_FPE
    726  1.23  tsutsui 		printf("calc_ea: offset %d\n", ea->ea_offset);
    727   1.8   briggs #endif
    728  1.23  tsutsui 		ptr += ea->ea_offset;
    729  1.23  tsutsui 	} else if (ea->ea_flags & EA_INDEXED) {
    730   1.8   briggs #if DEBUG_FPE
    731  1.23  tsutsui 		printf("calc_ea: indexed mode\n");
    732   1.8   briggs #endif
    733   1.1   briggs 
    734  1.23  tsutsui 		if (ea->ea_flags & EA_BASE_SUPPRSS) {
    735  1.23  tsutsui 			/* base register is suppressed */
    736  1.23  tsutsui 			ptr = (char *)ea->ea_basedisp;
    737  1.23  tsutsui 		} else {
    738  1.23  tsutsui 			ptr += ea->ea_basedisp;
    739  1.23  tsutsui 		}
    740   1.1   briggs 
    741  1.23  tsutsui 		if (ea->ea_flags & EA_MEM_INDIR) {
    742   1.8   briggs #if DEBUG_FPE
    743  1.23  tsutsui 			printf("calc_ea: mem indir mode: basedisp=%08x, "
    744  1.23  tsutsui 			    "outerdisp=%08x\n",
    745  1.23  tsutsui 			    ea->ea_basedisp, ea->ea_outerdisp);
    746  1.23  tsutsui 			printf("calc_ea: addr fetched from %p\n", ptr);
    747  1.23  tsutsui #endif
    748  1.23  tsutsui 			/* memory indirect modes */
    749  1.23  tsutsui 			word = fusword(ptr);
    750  1.23  tsutsui 			if (word < 0)
    751  1.23  tsutsui 				return SIGSEGV;
    752  1.23  tsutsui 			word <<= 16;
    753  1.23  tsutsui 			data = fusword(ptr + 2);
    754  1.23  tsutsui 			if (data < 0)
    755  1.23  tsutsui 				return SIGSEGV;
    756  1.23  tsutsui 			word |= data;
    757   1.8   briggs #if DEBUG_FPE
    758  1.23  tsutsui 			printf("calc_ea: fetched ptr 0x%08x\n", word);
    759   1.8   briggs #endif
    760  1.23  tsutsui 			ptr = (char *)word + ea->ea_outerdisp;
    761  1.23  tsutsui 		}
    762   1.1   briggs 	}
    763   1.1   briggs 
    764  1.23  tsutsui 	*eaddr = ptr;
    765   1.1   briggs 
    766  1.23  tsutsui 	return 0;
    767   1.1   briggs }
    768