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