Home | History | Annotate | Line # | Download | only in fpe
      1 /*	$NetBSD: fpu_calcea.c,v 1.28 2024/12/28 03:11:09 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.28 2024/12/28 03:11:09 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 idx;
    216 	int basedisp, outerdisp;
    217 	int bd_size, od_size;
    218 	int sig;
    219 	unsigned short extword;
    220 
    221 	if (ufetch_short((void *)(insn->is_pc + insn->is_advance), &extword))
    222 		return SIGSEGV;
    223 	insn->is_advance += 2;
    224 
    225 	/* get register index */
    226 	ea->ea_idxreg = (extword >> 12) & 0xf;
    227 	idx = frame->f_regs[ea->ea_idxreg];
    228 	if ((extword & 0x0800) == 0) {
    229 		/* if word sized index, sign-extend */
    230 		idx &= 0xffff;
    231 		if (idx & 0x8000) {
    232 			idx |= 0xffff0000;
    233 		}
    234 	}
    235 	/* scale register index */
    236 	idx <<= ((extword >> 9) & 3);
    237 
    238 	if ((extword & 0x100) == 0) {
    239 		/* brief extension word - sign-extend the displacement */
    240 		basedisp = (extword & 0xff);
    241 		if (basedisp & 0x80) {
    242 			basedisp |= 0xffffff00;
    243 		}
    244 
    245 		ea->ea_basedisp = idx + basedisp;
    246 		ea->ea_outerdisp = 0;
    247 		DPRINTF(("%s: brief ext word idxreg=%d, basedisp=%08x\n",
    248 		    __func__, ea->ea_idxreg, ea->ea_basedisp));
    249 	} else {
    250 		/* full extension word */
    251 		if (extword & 0x80) {
    252 			ea->ea_flags |= EA_BASE_SUPPRSS;
    253 		}
    254 		bd_size = ((extword >> 4) & 3) - 1;
    255 		od_size = (extword & 3) - 1;
    256 		sig = fetch_disp(frame, insn, bd_size, &basedisp);
    257 		if (sig)
    258 			return sig;
    259 		if (od_size >= 0)
    260 			ea->ea_flags |= EA_MEM_INDIR;
    261 		sig = fetch_disp(frame, insn, od_size, &outerdisp);
    262 		if (sig)
    263 			return sig;
    264 
    265 		switch (extword & 0x44) {
    266 		case 0:			/* preindexed */
    267 			ea->ea_basedisp = basedisp + idx;
    268 			ea->ea_outerdisp = outerdisp;
    269 			break;
    270 		case 4:			/* postindexed */
    271 			ea->ea_basedisp = basedisp;
    272 			ea->ea_outerdisp = outerdisp + idx;
    273 			break;
    274 		case 0x40:		/* no index */
    275 			ea->ea_basedisp = basedisp;
    276 			ea->ea_outerdisp = outerdisp;
    277 			break;
    278 		default:
    279 			DPRINTF(("%s: invalid indirect mode: ext word %04x\n",
    280 			    __func__, extword));
    281 			return SIGILL;
    282 			break;
    283 		}
    284 		DPRINTF(("%s: full ext idxreg=%d, basedisp=%x, outerdisp=%x\n",
    285 		    __func__,
    286 		    ea->ea_idxreg, ea->ea_basedisp, ea->ea_outerdisp));
    287 	}
    288 	DPRINTF(("%s: regnum=%d, flags=%x\n",
    289 	    __func__, ea->ea_regnum, ea->ea_flags));
    290 	return 0;
    291 }
    292 
    293 /*
    294  * Load a value from an effective address.
    295  * Returns zero on success, else signal number.
    296  */
    297 int
    298 fpu_load_ea(struct frame *frame, struct instruction *insn, struct insn_ea *ea,
    299 	char *dst)
    300 {
    301 	int *reg;
    302 	char *src;
    303 	int len, step;
    304 	int sig;
    305 
    306 #ifdef DIAGNOSTIC
    307 	if (ea->ea_regnum & ~0xF)
    308 		panic("%s: bad regnum", __func__);
    309 #endif
    310 
    311 	DPRINTF(("%s: frame at %p\n", __func__, frame));
    312 	/* dst is always int or larger. */
    313 	len = insn->is_datasize;
    314 	if (len < 4)
    315 		dst += (4 - len);
    316 	step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
    317 
    318 #if 0
    319 	if (ea->ea_flags & EA_FRAME_EA) {
    320 		/* Using LC040 frame EA */
    321 #ifdef DEBUG_FPE
    322 		if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) {
    323 			printf("%s: frame ea %08x w/r%d\n",
    324 			    __func__, ea->ea_fea, ea->ea_regnum);
    325 		} else {
    326 			printf("%s: frame ea %08x\n", __func__, ea->ea_fea);
    327 		}
    328 #endif
    329 		src = (char *)ea->ea_fea;
    330 		copyin(src + ea->ea_moffs, dst, len);
    331 		if (ea->ea_flags & EA_PREDECR) {
    332 			frame->f_regs[ea->ea_regnum] = ea->ea_fea;
    333 			ea->ea_fea -= step;
    334 			ea->ea_moffs = 0;
    335 		} else if (ea->ea_flags & EA_POSTINCR) {
    336 			ea->ea_fea += step;
    337 			frame->f_regs[ea->ea_regnum] = ea->ea_fea;
    338 			ea->ea_moffs = 0;
    339 		} else {
    340 			ea->ea_moffs += step;
    341 		}
    342 		/* That's it, folks */
    343 	} else
    344 #endif
    345 	if (ea->ea_flags & EA_DIRECT) {
    346 		if (len > 4) {
    347 			DPRINTF(("%s: operand doesn't fit CPU reg\n",
    348 			    __func__));
    349 			return SIGILL;
    350 		}
    351 		if (ea->ea_moffs > 0) {
    352 			DPRINTF(("%s: more than one move from CPU reg\n",
    353 			    __func__));
    354 			return SIGILL;
    355 		}
    356 		src = (char *)&frame->f_regs[ea->ea_regnum];
    357 		/* The source is an int. */
    358 		if (len < 4) {
    359 			src += (4 - len);
    360 			DPRINTF(("%s: short/byte opr - addr adjusted\n",
    361 			    __func__));
    362 		}
    363 		DPRINTF(("%s: src %p\n", __func__, src));
    364 		memcpy(dst, src, len);
    365 	} else if (ea->ea_flags & EA_IMMED) {
    366 		DPRINTF(("%s: immed %08x%08x%08x size %d\n", __func__,
    367 		    ea->ea_immed[0], ea->ea_immed[1], ea->ea_immed[2], len));
    368 		src = (char *)&ea->ea_immed[0];
    369 		if (len < 4) {
    370 			src += (4 - len);
    371 			DPRINTF(("%s: short/byte immed opr - addr adjusted\n",
    372 			    __func__));
    373 		}
    374 		memcpy(dst, src, len);
    375 	} else if (ea->ea_flags & EA_ABS) {
    376 		DPRINTF(("%s: abs addr %08x\n", __func__, ea->ea_absaddr));
    377 		src = (char *)ea->ea_absaddr;
    378 		copyin(src, dst, len);
    379 	} else /* register indirect */ {
    380 		if (ea->ea_flags & EA_PC_REL) {
    381 			DPRINTF(("%s: using PC\n", __func__));
    382 			reg = NULL;
    383 			/*
    384 			 * Grab the register contents. 4 is offset to the first
    385 			 * extension word from the opcode
    386 			 */
    387 			src = (char *)insn->is_pc + 4;
    388 			DPRINTF(("%s: pc relative pc+4 = %p\n", __func__, src));
    389 		} else /* not PC relative */ {
    390 			DPRINTF(("%s: using register %c%d\n",
    391 			    __func__,
    392 			    (ea->ea_regnum >= 8) ? 'a' : 'd',
    393 			    ea->ea_regnum & 7));
    394 			/* point to the register */
    395 			reg = &frame->f_regs[ea->ea_regnum];
    396 
    397 			if (ea->ea_flags & EA_PREDECR) {
    398 				DPRINTF(("%s: predecr mode - "
    399 				    "reg decremented\n", __func__));
    400 				*reg -= step;
    401 				ea->ea_moffs = 0;
    402 			}
    403 
    404 			/* Grab the register contents. */
    405 			src = (char *)*reg;
    406 			DPRINTF(("%s: reg indirect reg = %p\n", __func__, src));
    407 		}
    408 
    409 		sig = calc_ea(ea, src, &src);
    410 		if (sig)
    411 			return sig;
    412 
    413 		copyin(src + ea->ea_moffs, dst, len);
    414 
    415 		/* do post-increment */
    416 		if (ea->ea_flags & EA_POSTINCR) {
    417 			if (ea->ea_flags & EA_PC_REL) {
    418 				DPRINTF(("%s: tried to postincrement PC\n",
    419 				    __func__));
    420 				return SIGILL;
    421 			}
    422 			*reg += step;
    423 			ea->ea_moffs = 0;
    424 			DPRINTF(("%s: postinc mode - reg incremented\n",
    425 			    __func__));
    426 		} else {
    427 			ea->ea_moffs += len;
    428 		}
    429 	}
    430 
    431 	return 0;
    432 }
    433 
    434 /*
    435  * Store a value at the effective address.
    436  * Returns zero on success, else signal number.
    437  */
    438 int
    439 fpu_store_ea(struct frame *frame, struct instruction *insn, struct insn_ea *ea,
    440 	char *src)
    441 {
    442 	int *reg;
    443 	char *dst;
    444 	int len, step;
    445 	int sig;
    446 
    447 #ifdef DIAGNOSTIC
    448 	if (ea->ea_regnum & ~0xf)
    449 		panic("%s: bad regnum", __func__);
    450 #endif
    451 
    452 	if (ea->ea_flags & (EA_IMMED|EA_PC_REL)) {
    453 		/* not alterable address mode */
    454 		DPRINTF(("%s: not alterable address mode\n", __func__));
    455 		return SIGILL;
    456 	}
    457 
    458 	/* src is always int or larger. */
    459 	len = insn->is_datasize;
    460 	if (len < 4)
    461 		src += (4 - len);
    462 	step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
    463 
    464 	if (ea->ea_flags & EA_FRAME_EA) {
    465 		/* Using LC040 frame EA */
    466 #ifdef DEBUG_FPE
    467 		if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) {
    468 			printf("%s: frame ea %08x w/r%d\n",
    469 			    __func__, ea->ea_fea, ea->ea_regnum);
    470 		} else {
    471 			printf("%s: frame ea %08x\n", __func__, ea->ea_fea);
    472 		}
    473 #endif
    474 		dst = (char *)ea->ea_fea;
    475 		copyout(src, dst + ea->ea_moffs, len);
    476 		if (ea->ea_flags & EA_PREDECR) {
    477 			frame->f_regs[ea->ea_regnum] = ea->ea_fea;
    478 			ea->ea_fea -= step;
    479 			ea->ea_moffs = 0;
    480 		} else if (ea->ea_flags & EA_POSTINCR) {
    481 			ea->ea_fea += step;
    482 			frame->f_regs[ea->ea_regnum] = ea->ea_fea;
    483 			ea->ea_moffs = 0;
    484 		} else {
    485 			ea->ea_moffs += step;
    486 		}
    487 		/* That's it, folks */
    488 	} else if (ea->ea_flags & EA_ABS) {
    489 		DPRINTF(("%s: abs addr %08x\n", __func__, ea->ea_absaddr));
    490 		dst = (char *)ea->ea_absaddr;
    491 		copyout(src, dst + ea->ea_moffs, len);
    492 		ea->ea_moffs += len;
    493 	} else if (ea->ea_flags & EA_DIRECT) {
    494 		if (len > 4) {
    495 			DPRINTF(("%s: operand doesn't fit CPU reg\n",
    496 			    __func__));
    497 			return SIGILL;
    498 		}
    499 		if (ea->ea_moffs > 0) {
    500 			DPRINTF(("%s: more than one move to CPU reg\n",
    501 			    __func__));
    502 			return SIGILL;
    503 		}
    504 		dst = (char *)&frame->f_regs[ea->ea_regnum];
    505 		/* The destination is an int. */
    506 		if (len < 4) {
    507 			dst += (4 - len);
    508 			DPRINTF(("%s: short/byte opr - dst addr adjusted\n",
    509 			    __func__));
    510 		}
    511 		DPRINTF(("%s: dst %p\n", __func__, dst));
    512 		memcpy(dst, src, len);
    513 	} else /* One of MANY indirect forms... */ {
    514 		DPRINTF(("%s: using register %c%d\n", __func__,
    515 		    (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7));
    516 		/* point to the register */
    517 		reg = &(frame->f_regs[ea->ea_regnum]);
    518 
    519 		/* do pre-decrement */
    520 		if (ea->ea_flags & EA_PREDECR) {
    521 			DPRINTF(("%s: predecr mode - reg decremented\n",
    522 			    __func__));
    523 			*reg -= step;
    524 			ea->ea_moffs = 0;
    525 		}
    526 
    527 		/* calculate the effective address */
    528 		sig = calc_ea(ea, (char *)*reg, &dst);
    529 		if (sig)
    530 			return sig;
    531 
    532 		DPRINTF(("%s: dst addr=%p+%d\n", __func__, dst, ea->ea_moffs));
    533 		copyout(src, dst + ea->ea_moffs, len);
    534 
    535 		/* do post-increment */
    536 		if (ea->ea_flags & EA_POSTINCR) {
    537 			*reg += step;
    538 			ea->ea_moffs = 0;
    539 			DPRINTF(("%s: postinc mode - reg incremented\n",
    540 			    __func__));
    541 		} else {
    542 			ea->ea_moffs += len;
    543 		}
    544 	}
    545 
    546 	return 0;
    547 }
    548 
    549 /*
    550  * fetch_immed: fetch immediate operand
    551  */
    552 static int
    553 fetch_immed(struct frame *frame, struct instruction *insn, int *dst)
    554 {
    555 	int data, ext_bytes;
    556 	unsigned short sval;
    557 
    558 	ext_bytes = insn->is_datasize;
    559 
    560 	if (0 < ext_bytes) {
    561 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance),
    562 				  &sval))
    563 			return SIGSEGV;
    564 		data = sval;
    565 		if (ext_bytes == 1) {
    566 			/* sign-extend byte to long */
    567 			data &= 0xff;
    568 			if (data & 0x80)
    569 				data |= 0xffffff00;
    570 		} else if (ext_bytes == 2) {
    571 			/* sign-extend word to long */
    572 			data &= 0xffff;
    573 			if (data & 0x8000)
    574 				data |= 0xffff0000;
    575 		}
    576 		insn->is_advance += 2;
    577 		dst[0] = data;
    578 	}
    579 	if (2 < ext_bytes) {
    580 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance),
    581 				  &sval))
    582 			return SIGSEGV;
    583 		insn->is_advance += 2;
    584 		dst[0] <<= 16;
    585 		dst[0] |= sval;
    586 	}
    587 	if (4 < ext_bytes) {
    588 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance),
    589 				  &sval))
    590 			return SIGSEGV;
    591 		data = sval;
    592 		dst[1] = data << 16;
    593 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2),
    594 				  &sval))
    595 			return SIGSEGV;
    596 		insn->is_advance += 4;
    597 		dst[1] |= sval;
    598 	}
    599 	if (8 < ext_bytes) {
    600 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance),
    601 				  &sval))
    602 			return SIGSEGV;
    603 		data = sval;
    604 		dst[2] = data << 16;
    605 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2),
    606 				  &sval))
    607 			return SIGSEGV;
    608 		insn->is_advance += 4;
    609 		dst[2] |= sval;
    610 	}
    611 
    612 	return 0;
    613 }
    614 
    615 /*
    616  * fetch_disp: fetch displacement in full extension words
    617  */
    618 static int
    619 fetch_disp(struct frame *frame, struct instruction *insn, int size, int *res)
    620 {
    621 	int disp, word;
    622 	unsigned short sval;
    623 
    624 	if (size == 1) {
    625 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance),
    626 				  &sval))
    627 			return SIGSEGV;
    628 		disp = sval;
    629 		if (disp & 0x8000) {
    630 			/* sign-extend */
    631 			disp |= 0xffff0000;
    632 		}
    633 		insn->is_advance += 2;
    634 	} else if (size == 2) {
    635 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance),
    636 				  &sval))
    637 			return SIGSEGV;
    638 		word = sval;
    639 		disp = word << 16;
    640 		if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2),
    641 				  &sval))
    642 			return SIGSEGV;
    643 		disp |= sval;
    644 		insn->is_advance += 4;
    645 	} else {
    646 		disp = 0;
    647 	}
    648 	*res = disp;
    649 	return 0;
    650 }
    651 
    652 /*
    653  * Calculates an effective address for all address modes except for
    654  * register direct, absolute, and immediate modes.  However, it does
    655  * not take care of predecrement/postincrement of register content.
    656  * Returns a signal value (0 == no error).
    657  */
    658 static int
    659 calc_ea(struct insn_ea *ea, char *ptr, char **eaddr)
    660 	/* ptr:		 base address (usually a register content) */
    661 	/* eaddr:	 pointer to result pointer */
    662 {
    663 	int word;
    664 	unsigned short sval;
    665 
    666 	DPRINTF(("%s: reg indirect (reg) = %p\n", __func__, ptr));
    667 
    668 	if (ea->ea_flags & EA_OFFSET) {
    669 		/* apply the signed offset */
    670 		DPRINTF(("%s: offset %d\n", __func__, ea->ea_offset));
    671 		ptr += ea->ea_offset;
    672 	} else if (ea->ea_flags & EA_INDEXED) {
    673 		DPRINTF(("%s: indexed mode\n", __func__));
    674 
    675 		if (ea->ea_flags & EA_BASE_SUPPRSS) {
    676 			/* base register is suppressed */
    677 			ptr = (char *)ea->ea_basedisp;
    678 		} else {
    679 			ptr += ea->ea_basedisp;
    680 		}
    681 
    682 		if (ea->ea_flags & EA_MEM_INDIR) {
    683 			DPRINTF(("%s: mem indir mode: basedisp=%08x, "
    684 			    "outerdisp=%08x\n",
    685 			    __func__, ea->ea_basedisp, ea->ea_outerdisp));
    686 			DPRINTF(("%s: addr fetched from %p\n", __func__, ptr));
    687 			/* memory indirect modes */
    688 			if (ufetch_short((u_short *)ptr, &sval))
    689 				return SIGSEGV;
    690 			word = sval;
    691 			word <<= 16;
    692 			if (ufetch_short((u_short *)(ptr + 2), &sval))
    693 				return SIGSEGV;
    694 			word |= sval;
    695 			DPRINTF(("%s: fetched ptr 0x%08x\n", __func__, word));
    696 			ptr = (char *)word + ea->ea_outerdisp;
    697 		}
    698 	}
    699 
    700 	*eaddr = ptr;
    701 
    702 	return 0;
    703 }
    704