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