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