fpu_calcea.c revision 1.14 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