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