Home | History | Annotate | Line # | Download | only in fpe
fpu_calcea.c revision 1.4
      1 /*	$NetBSD: fpu_calcea.c,v 1.4 1996/04/30 11:52:11 briggs 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 <sys/param.h>
     35 #include <sys/signal.h>
     36 #include <sys/systm.h>
     37 #include <machine/frame.h>
     38 
     39 #include "fpu_emulate.h"
     40 
     41 /*
     42  * Prototypes of static functions
     43  */
     44 static int decode_ea6 __P((struct frame *frame, struct instruction *insn,
     45 			   struct insn_ea *ea, int modreg));
     46 static int fetch_immed __P((struct frame *frame, struct instruction *insn,
     47 			    int *dst));
     48 static int fetch_disp __P((struct frame *frame, struct instruction *insn,
     49 			   int size, int *res));
     50 static int calc_ea __P((struct insn_ea *ea, char *ptr, char **eaddr));
     51 
     52 int fusword __P((void *));
     53 
     54 /*
     55  * Helper routines for dealing with "effective address" values.
     56  */
     57 
     58 /*
     59  * Decode an effective address into internal form.
     60  * Returns zero on success, else signal number.
     61  */
     62 int
     63 fpu_decode_ea(frame, insn, ea, modreg)
     64      struct frame *frame;
     65      struct instruction *insn;
     66      struct insn_ea *ea;
     67      int modreg;
     68 {
     69     int sig;
     70 
     71 #ifdef DEBUG
     72     if (insn->is_datasize < 0) {
     73 	panic("decode_ea: called with uninitialized datasize\n");
     74     }
     75 #endif
     76 
     77     sig = 0;
     78 
     79     /* Set the most common value here. */
     80     ea->ea_regnum = 8 + (modreg & 7);
     81 
     82     switch (modreg & 070) {
     83     case 0:			/* Dn */
     84 	ea->ea_regnum &= 7;
     85     case 010:			/* An */
     86 	ea->ea_flags = EA_DIRECT;
     87 	if (fpu_debug_level & DL_DECODEEA) {
     88 	    printf("  decode_ea: register direct reg=%d\n", ea->ea_regnum);
     89 	}
     90 	break;
     91 
     92     case 020:			/* (An) */
     93 	ea->ea_flags = 0;
     94 	if (fpu_debug_level & DL_DECODEEA) {
     95 	    printf("  decode_ea: register indirect reg=%d\n", ea->ea_regnum);
     96 	}
     97 	break;
     98 
     99     case 030:			/* (An)+ */
    100 	ea->ea_flags = EA_POSTINCR;
    101 	if (fpu_debug_level & DL_DECODEEA) {
    102 	    printf("  decode_ea: reg indirect postincrement reg=%d\n",
    103 		   ea->ea_regnum);
    104 	}
    105 	break;
    106 
    107     case 040:			/* -(An) */
    108 	ea->ea_flags = EA_PREDECR;
    109 	if (fpu_debug_level & DL_DECODEEA) {
    110 	    printf("  decode_ea: reg indirect predecrement reg=%d\n",
    111 		   ea->ea_regnum);
    112 	}
    113 	break;
    114 
    115     case 050:			/* (d16,An) */
    116 	ea->ea_flags = EA_OFFSET;
    117 	sig = fetch_disp(frame, insn, 1, &ea->ea_offset);
    118 	if (fpu_debug_level & DL_DECODEEA) {
    119 	    printf("  decode_ea: reg indirect with displacement reg=%d\n",
    120 		   ea->ea_regnum);
    121 	}
    122 	break;
    123 
    124     case 060:			/* (d8,An,Xn) */
    125 	ea->ea_flags = EA_INDEXED;
    126 	sig = decode_ea6(frame, insn, ea, modreg);
    127 	break;
    128 
    129     case 070:			/* misc. */
    130 	ea->ea_regnum = (modreg & 7);
    131 	switch (modreg & 7) {
    132 
    133 	case 0:			/* (xxxx).W */
    134 	    ea->ea_flags = EA_ABS;
    135 	    sig = fetch_disp(frame, insn, 1, &ea->ea_absaddr);
    136 	    if (fpu_debug_level & DL_DECODEEA) {
    137 		printf("  decode_ea: absolute address (word)\n");
    138 	    }
    139 	    break;
    140 
    141 	case 1:			/* (xxxxxxxx).L */
    142 	    ea->ea_flags = EA_ABS;
    143 	    sig = fetch_disp(frame, insn, 2, &ea->ea_absaddr);
    144 	    if (fpu_debug_level & DL_DECODEEA) {
    145 		printf("  decode_ea: absolute address (long)\n");
    146 	    }
    147 	    break;
    148 
    149 	case 2:			/* (d16,PC) */
    150 	    ea->ea_flags = EA_PC_REL | EA_OFFSET;
    151 	    sig = fetch_disp(frame, insn, 1, &ea->ea_absaddr);
    152 	    if (fpu_debug_level & DL_DECODEEA) {
    153 		printf("  decode_ea: pc relative word displacement\n");
    154 	    }
    155 	    break;
    156 
    157 	case 3:			/* (d8,PC,Xn) */
    158 	    ea->ea_flags = EA_PC_REL | EA_INDEXED;
    159 	    sig = decode_ea6(frame, insn, ea, modreg);
    160 	    break;
    161 
    162 	case 4:			/* #data */
    163 	    ea->ea_flags = EA_IMMED;
    164 	    sig = fetch_immed(frame, insn, &ea->ea_immed[0]);
    165 	    if (fpu_debug_level & DL_DECODEEA) {
    166 		printf("  decode_ea: immediate size=%d\n", insn->is_datasize);
    167 	    }
    168 	    break;
    169 
    170 	default:
    171 	    if (fpu_debug_level & DL_DECODEEA) {
    172 		printf("  decode_ea: invalid addr mode (7,%d)\n", modreg & 7);
    173 	    }
    174 	    return SIGILL;
    175 	} /* switch for mode 7 */
    176 	break;
    177     } /* switch mode */
    178 
    179     ea->ea_tdisp = 0;
    180 
    181     return sig;
    182 }
    183 
    184 /*
    185  * Decode Mode=6 address modes
    186  */
    187 static int
    188 decode_ea6(frame, insn, ea, modreg)
    189      struct frame *frame;
    190      struct instruction *insn;
    191      struct insn_ea *ea;
    192      int modreg;
    193 {
    194     int extword, idx;
    195     int basedisp, outerdisp;
    196     int bd_size, od_size;
    197     int sig;
    198 
    199     extword = fusword((void *) (frame->f_pc + insn->is_advance));
    200     if (extword < 0) {
    201 	return SIGSEGV;
    202     }
    203     insn->is_advance += 2;
    204 
    205     /* get register index */
    206     ea->ea_idxreg = (extword >> 12) & 0xf;
    207     idx = frame->f_regs[ea->ea_idxreg];
    208     if ((extword & 0x0800) == 0) {
    209 	/* if word sized index, sign-extend */
    210 	idx &= 0xffff;
    211 	if (idx & 0x8000) {
    212 	    idx |= 0xffff0000;
    213 	}
    214     }
    215     /* scale register index */
    216     idx <<= ((extword >>9) & 3);
    217 
    218     if ((extword & 0x100) == 0) {
    219 	/* brief extention word - sign-extend the displacement */
    220 	basedisp = (extword & 0xff);
    221 	if (basedisp & 0x80) {
    222 	    basedisp |= 0xffffff00;
    223 	}
    224 
    225 	ea->ea_basedisp = idx + basedisp;
    226 	ea->ea_outerdisp = 0;
    227 	if (fpu_debug_level & DL_DECODEEA) {
    228 	    printf("  decode_ea6: brief ext word idxreg=%d, basedisp=%08x\n",
    229 		   ea->ea_idxreg, ea->ea_basedisp);
    230 	}
    231     } else {
    232 	/* full extention word */
    233 	if (extword & 0x80) {
    234 	    ea->ea_flags |= EA_BASE_SUPPRSS;
    235 	}
    236 	bd_size = ((extword >> 4) & 3) - 1;
    237 	od_size = (extword & 3) - 1;
    238 	sig = fetch_disp(frame, insn, bd_size, &basedisp);
    239 	if (sig) {
    240 	    return sig;
    241 	}
    242 	if (od_size >= 0) {
    243 	    ea->ea_flags |= EA_MEM_INDIR;
    244 	}
    245 	sig = fetch_disp(frame, insn, od_size, &outerdisp);
    246 	if (sig) {
    247 	    return sig;
    248 	}
    249 
    250 	switch (extword & 0x44) {
    251 	case 0:			/* preindexed */
    252 	    ea->ea_basedisp = basedisp + idx;
    253 	    ea->ea_outerdisp = outerdisp;
    254 	    break;
    255 	case 4:			/* postindexed */
    256 	    ea->ea_basedisp = basedisp;
    257 	    ea->ea_outerdisp = outerdisp + idx;
    258 	    break;
    259 	case 0x40:		/* no index */
    260 	    ea->ea_basedisp = basedisp;
    261 	    ea->ea_outerdisp = outerdisp;
    262 	    break;
    263 	default:
    264 #ifdef DEBUG
    265 	    printf("  decode_ea6: invalid indirect mode: ext word %04x\n",
    266 		   extword);
    267 #endif
    268 	    return SIGILL;
    269 	    break;
    270 	}
    271 	if (fpu_debug_level & DL_DECODEEA) {
    272 	    printf("  decode_ea6: full ext idxreg=%d, basedisp=%x, outerdisp=%x\n",
    273 		   ea->ea_idxreg, ea->ea_basedisp, ea->ea_outerdisp);
    274 	}
    275     }
    276     if (fpu_debug_level & DL_DECODEEA) {
    277 	printf("  decode_ea6: regnum=%d, flags=%x\n",
    278 	       ea->ea_regnum, ea->ea_flags);
    279     }
    280     return 0;
    281 }
    282 
    283 /*
    284  * Load a value from an effective address.
    285  * Returns zero on success, else signal number.
    286  */
    287 int
    288 fpu_load_ea(frame, insn, ea, dst)
    289      struct frame *frame;
    290      struct instruction *insn;
    291      struct insn_ea *ea;
    292      char *dst;
    293 {
    294     int *reg;
    295     char *src;
    296     int len, step;
    297     int sig;
    298 
    299 #ifdef	DIAGNOSTIC
    300     if (ea->ea_regnum & ~0xF) {
    301 	panic("  load_ea: bad regnum");
    302     }
    303 #endif
    304 
    305     if (fpu_debug_level & DL_LOADEA) {
    306 	printf("  load_ea: frame at %p\n", frame);
    307     }
    308     /* The dst is always int or larger. */
    309     len = insn->is_datasize;
    310     if (len < 4) {
    311 	dst += (4 - len);
    312     }
    313     step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
    314 
    315     if (ea->ea_flags & EA_DIRECT) {
    316 	if (len > 4) {
    317 #ifdef DEBUG
    318 	    printf("  load_ea: operand doesn't fit cpu reg\n");
    319 #endif
    320 	    return SIGILL;
    321 	}
    322 	if (ea->ea_tdisp > 0) {
    323 #ifdef DEBUG
    324 	    printf("  load_ea: more than one move from cpu reg\n");
    325 #endif
    326 	    return SIGILL;
    327 	}
    328 	src = (char *)&frame->f_regs[ea->ea_regnum];
    329 	/* The source is an int. */
    330 	if (len < 4) {
    331 	    src += (4 - len);
    332 	    if (fpu_debug_level & DL_LOADEA) {
    333 		printf("  load_ea: short/byte opr - addr adjusted\n");
    334 	    }
    335 	}
    336 	if (fpu_debug_level & DL_LOADEA) {
    337 	    printf("  load_ea: src %p\n", src);
    338 	}
    339 	bcopy(src, dst, len);
    340     } else if (ea->ea_flags & EA_IMMED) {
    341 	if (fpu_debug_level & DL_LOADEA) {
    342 	    printf("  load_ea: immed %08x%08x%08x size %d\n",
    343 		   ea->ea_immed[0], ea->ea_immed[1], ea->ea_immed[2], len);
    344 	}
    345 	src = (char *)&ea->ea_immed[0];
    346 	if (len < 4) {
    347 	    src += (4 - len);
    348 	    if (fpu_debug_level & DL_LOADEA) {
    349 		printf("  load_ea: short/byte immed opr - addr adjusted\n");
    350 	    }
    351 	}
    352 	bcopy(src, dst, len);
    353     } else if (ea->ea_flags & EA_ABS) {
    354 	if (fpu_debug_level & DL_LOADEA) {
    355 	    printf("  load_ea: abs addr %08x\n", ea->ea_absaddr);
    356 	}
    357 	src = (char *)ea->ea_absaddr;
    358 	copyin(src, dst, len);
    359     } else /* register indirect */ {
    360 	if (ea->ea_flags & EA_PC_REL) {
    361 	    if (fpu_debug_level & DL_LOADEA) {
    362 		printf("  load_ea: using PC\n");
    363 	    }
    364 	    reg = NULL;
    365 	    /* Grab the register contents. 4 is offset to the first
    366 	       extention word from the opcode */
    367 	    src = (char *)frame->f_pc + 4;
    368 	    if (fpu_debug_level & DL_LOADEA) {
    369 		printf("  load_ea: pc relative pc+4 = %p\n", src);
    370 	    }
    371 	} else /* not PC relative */ {
    372 	    if (fpu_debug_level & DL_LOADEA) {
    373 		printf("  load_ea: using register %c%d\n",
    374 		       (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7);
    375 	    }
    376 	    /* point to the register */
    377 	    reg = &frame->f_regs[ea->ea_regnum];
    378 
    379 	    if (ea->ea_flags & EA_PREDECR) {
    380 		if (fpu_debug_level & DL_LOADEA) {
    381 		    printf("  load_ea: predecr mode - reg decremented\n");
    382 		}
    383 		*reg -= step;
    384 		ea->ea_tdisp = 0;
    385 	    }
    386 
    387 	    /* Grab the register contents. */
    388 	    src = (char *)*reg;
    389 	    if (fpu_debug_level & DL_LOADEA) {
    390 		printf("  load_ea: reg indirect reg = %p\n", src);
    391 	    }
    392 	}
    393 
    394 	sig = calc_ea(ea, src, &src);
    395 	if (sig)
    396 	    return sig;
    397 
    398 	copyin(src + ea->ea_tdisp, dst, len);
    399 
    400 	/* do post-increment */
    401 	if (ea->ea_flags & EA_POSTINCR) {
    402 	    if (ea->ea_flags & EA_PC_REL) {
    403 #ifdef DEBUG
    404 		printf("  load_ea: tried to postincrement PC\n");
    405 #endif
    406 		return SIGILL;
    407 	    }
    408 	    *reg += step;
    409 	    ea->ea_tdisp = 0;
    410 	    if (fpu_debug_level & DL_LOADEA) {
    411 		printf("  load_ea: postinc mode - reg incremented\n");
    412 	    }
    413 	} else {
    414 	    ea->ea_tdisp += len;
    415 	}
    416     }
    417 
    418     return 0;
    419 }
    420 
    421 /*
    422  * Store a value at the effective address.
    423  * Returns zero on success, else signal number.
    424  */
    425 int
    426 fpu_store_ea(frame, insn, ea, src)
    427      struct frame *frame;
    428      struct instruction *insn;
    429      struct insn_ea *ea;
    430      char *src;
    431 {
    432     int *reg;
    433     char *dst;
    434     int len, step;
    435     int sig;
    436 
    437 #ifdef	DIAGNOSTIC
    438     if (ea->ea_regnum & ~0xF) {
    439 	panic("  store_ea: bad regnum");
    440     }
    441 #endif
    442 
    443     if (ea->ea_flags & (EA_IMMED|EA_PC_REL)) {
    444 	/* not alterable address mode */
    445 #ifdef DEBUG
    446 	printf("  store_ea: not alterable address mode\n");
    447 #endif
    448 	return SIGILL;
    449     }
    450 
    451     if (fpu_debug_level & DL_STOREEA) {
    452 	printf("  store_ea: frame at %p\n", frame);
    453     }
    454     /* The src is always int or larger. */
    455     len = insn->is_datasize;
    456     if (len < 4) {
    457 	src += (4 - len);
    458     }
    459     step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
    460 
    461     if (ea->ea_flags & EA_ABS) {
    462 	if (fpu_debug_level & DL_STOREEA) {
    463 	    printf("  store_ea: abs addr %08x\n", ea->ea_absaddr);
    464 	}
    465 	dst = (char *)ea->ea_absaddr;
    466 	copyout(src, dst + ea->ea_tdisp, len);
    467 	ea->ea_tdisp += len;
    468     } else if (ea->ea_flags & EA_DIRECT) {
    469 	if (len > 4) {
    470 #ifdef DEBUG
    471 	    printf("  store_ea: operand doesn't fit cpu reg\n");
    472 #endif
    473 	    return SIGILL;
    474 	}
    475 	if (ea->ea_tdisp > 0) {
    476 #ifdef DEBUG
    477 	    printf("  store_ea: more than one move to cpu reg\n");
    478 #endif
    479 	    return SIGILL;
    480 	}
    481 	dst = (char*)&frame->f_regs[ea->ea_regnum];
    482 	/* The destination is an int. */
    483 	if (len < 4) {
    484 	    dst += (4 - len);
    485 	    if (fpu_debug_level & DL_STOREEA) {
    486 		printf("  store_ea: short/byte opr - dst addr adjusted\n");
    487 	    }
    488 	}
    489 	if (fpu_debug_level & DL_STOREEA) {
    490 	    printf("  store_ea: dst %p\n", dst);
    491 	}
    492 	bcopy(src, dst, len);
    493     } else /* One of MANY indirect forms... */ {
    494 	if (fpu_debug_level & DL_STOREEA) {
    495 	    printf("  store_ea: using register %c%d\n",
    496 		   (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7);
    497 	}
    498 	/* point to the register */
    499 	reg = &(frame->f_regs[ea->ea_regnum]);
    500 
    501 	/* do pre-decrement */
    502 	if (ea->ea_flags & EA_PREDECR) {
    503 	    if (fpu_debug_level & DL_STOREEA) {
    504 		printf("  store_ea: predecr mode - reg decremented\n");
    505 	    }
    506 	    *reg -= step;
    507 	    ea->ea_tdisp = 0;
    508 	}
    509 
    510 	/* calculate the effective address */
    511 	sig = calc_ea(ea, (char *)*reg, &dst);
    512 	if (sig)
    513 	    return sig;
    514 
    515 	if (fpu_debug_level & DL_STOREEA) {
    516 	    printf("  store_ea: dst addr=%p+%d\n", dst, ea->ea_tdisp);
    517 	}
    518 	copyout(src, dst + ea->ea_tdisp, len);
    519 
    520 	/* do post-increment */
    521 	if (ea->ea_flags & EA_POSTINCR) {
    522 	    *reg += step;
    523 	    ea->ea_tdisp = 0;
    524 	    if (fpu_debug_level & DL_STOREEA) {
    525 		printf("  store_ea: postinc mode - reg incremented\n");
    526 	    }
    527 	} else {
    528 	    ea->ea_tdisp += len;
    529 	}
    530     }
    531 
    532     return 0;
    533 }
    534 
    535 /*
    536  * fetch_immed: fetch immediate operand
    537  */
    538 static int
    539 fetch_immed(frame, insn, dst)
    540      struct frame *frame;
    541      struct instruction *insn;
    542      int *dst;
    543 {
    544     int data, ext_bytes;
    545 
    546     ext_bytes = insn->is_datasize;
    547 
    548     if (0 < ext_bytes) {
    549 	data = fusword((void *) (frame->f_pc + insn->is_advance));
    550 	if (data < 0) {
    551 	    return SIGSEGV;
    552 	}
    553 	if (ext_bytes == 1) {
    554 	    /* sign-extend byte to long */
    555 	    data &= 0xff;
    556 	    if (data & 0x80) {
    557 		data |= 0xffffff00;
    558 	    }
    559 	} else if (ext_bytes == 2) {
    560 	    /* sign-extend word to long */
    561 	    data &= 0xffff;
    562 	    if (data & 0x8000) {
    563 		data |= 0xffff0000;
    564 	    }
    565 	}
    566 	insn->is_advance += 2;
    567 	dst[0] = data;
    568     }
    569     if (2 < ext_bytes) {
    570 	data = fusword((void *) (frame->f_pc + insn->is_advance));
    571 	if (data < 0) {
    572 	    return SIGSEGV;
    573 	}
    574 	insn->is_advance += 2;
    575 	dst[0] <<= 16;
    576 	dst[0] |= data;
    577     }
    578     if (4 < ext_bytes) {
    579 	data = fusword((void *) (frame->f_pc + insn->is_advance));
    580 	if (data < 0) {
    581 	    return SIGSEGV;
    582 	}
    583 	dst[1] = data << 16;
    584 	data = fusword((void *) (frame->f_pc + insn->is_advance + 2));
    585 	if (data < 0) {
    586 	    return SIGSEGV;
    587 	}
    588 	insn->is_advance += 4;
    589 	dst[1] |= data;
    590     }
    591     if (8 < ext_bytes) {
    592 	data = fusword((void *) (frame->f_pc + insn->is_advance));
    593 	if (data < 0) {
    594 	    return SIGSEGV;
    595 	}
    596 	dst[2] = data << 16;
    597 	data = fusword((void *) (frame->f_pc + insn->is_advance + 2));
    598 	if (data < 0) {
    599 	    return SIGSEGV;
    600 	}
    601 	insn->is_advance += 4;
    602 	dst[2] |= data;
    603     }
    604 
    605     return 0;
    606 }
    607 
    608 /*
    609  * fetch_disp: fetch displacement in full extention words
    610  */
    611 static int
    612 fetch_disp(frame, insn, size, res)
    613      struct frame *frame;
    614      struct instruction *insn;
    615      int size, *res;
    616 {
    617     int disp, word;
    618 
    619     if (size == 1) {
    620 	word = fusword((void *) (frame->f_pc + insn->is_advance));
    621 	if (word < 0) {
    622 	    return SIGSEGV;
    623 	}
    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 *) (frame->f_pc + insn->is_advance));
    632 	if (word < 0) {
    633 	    return SIGSEGV;
    634 	}
    635 	disp = word << 16;
    636 	word = fusword((void *) (frame->f_pc + insn->is_advance + 2));
    637 	if (word < 0) {
    638 	    return SIGSEGV;
    639 	}
    640 	disp |= (word & 0xffff);
    641 	insn->is_advance += 4;
    642     } else {
    643 	disp = 0;
    644     }
    645     *res = disp;
    646     return 0;
    647 }
    648 
    649 /*
    650  * Calculates an effective address for all address modes except for
    651  * register direct, absolute, and immediate modes.  However, it does
    652  * not take care of predecrement/postincrement of register content.
    653  * Returns a signal value (0 == no error).
    654  */
    655 static int
    656 calc_ea(ea, ptr, eaddr)
    657      struct insn_ea *ea;
    658      char *ptr;		/* base address (usually a register content) */
    659      char **eaddr;	/* pointer to result pointer */
    660 {
    661     int data, word;
    662 
    663     if (fpu_debug_level & DL_EA) {
    664 	printf("  calc_ea: reg indirect (reg) = %p\n", ptr);
    665     }
    666 
    667     if (ea->ea_flags & EA_OFFSET) {
    668 	/* apply the signed offset */
    669 	if (fpu_debug_level & DL_EA) {
    670 	    printf("  calc_ea: offset %d\n", ea->ea_offset);
    671 	}
    672 	ptr += ea->ea_offset;
    673     } else if (ea->ea_flags & EA_INDEXED) {
    674 	if (fpu_debug_level & DL_EA) {
    675 	    printf("  calc_ea: indexed mode\n");
    676 	}
    677 
    678 	if (ea->ea_flags & EA_BASE_SUPPRSS) {
    679 	    /* base register is suppressed */
    680 	    ptr = (char *)ea->ea_basedisp;
    681 	} else {
    682 	    ptr += ea->ea_basedisp;
    683 	}
    684 
    685 	if (ea->ea_flags & EA_MEM_INDIR) {
    686 	    if (fpu_debug_level & DL_EA) {
    687 		printf("  calc_ea: mem indir mode: basedisp=%08x, outerdisp=%08x\n",
    688 		       ea->ea_basedisp, ea->ea_outerdisp);
    689 		printf("  calc_ea: addr fetched from %p\n", ptr);
    690 	    }
    691 	    /* memory indirect modes */
    692 	    word = fusword(ptr);
    693 	    if (word < 0) {
    694 		return SIGSEGV;
    695 	    }
    696 	    word <<= 16;
    697 	    data = fusword(ptr + 2);
    698 	    if (data < 0) {
    699 		return SIGSEGV;
    700 	    }
    701 	    word |= data;
    702 	    if (fpu_debug_level & DL_STOREEA) {
    703 		printf(" calc_ea: fetched ptr 0x%08x\n", word);
    704 	    }
    705 	    ptr = (char *)word + ea->ea_outerdisp;
    706 	}
    707     }
    708 
    709     *eaddr = ptr;
    710 
    711     return 0;
    712 }
    713