fpu_calcea.c revision 1.10 1 /* $NetBSD: fpu_calcea.c,v 1.10 2001/01/05 19:54:30 is 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\n");
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 extention 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 extention 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 (ea->ea_flags & EA_FRAME_EA) {
347 /* Using LC040 frame EA */
348 #ifdef DEBUG_FPE
349 if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) {
350 printf("load_ea: frame ea %08x w/r%d\n",
351 ea->ea_fea, ea->ea_regnum);
352 } else {
353 printf("load_ea: frame ea %08x\n", ea->ea_fea);
354 }
355 #endif
356 src = (char *)ea->ea_fea;
357 copyin(src + ea->ea_moffs, dst, len);
358 if (ea->ea_flags & EA_PREDECR) {
359 frame->f_regs[ea->ea_regnum] = ea->ea_fea;
360 ea->ea_fea -= step;
361 ea->ea_moffs = 0;
362 } else if (ea->ea_flags & EA_POSTINCR) {
363 ea->ea_fea += step;
364 frame->f_regs[ea->ea_regnum] = ea->ea_fea;
365 ea->ea_moffs = 0;
366 } else {
367 ea->ea_moffs += step;
368 }
369 /* That's it, folks */
370 } else if (ea->ea_flags & EA_DIRECT) {
371 if (len > 4) {
372 #ifdef DEBUG
373 printf("load_ea: operand doesn't fit cpu reg\n");
374 #endif
375 return SIGILL;
376 }
377 if (ea->ea_moffs > 0) {
378 #ifdef DEBUG
379 printf("load_ea: more than one move from cpu reg\n");
380 #endif
381 return SIGILL;
382 }
383 src = (char *)&frame->f_regs[ea->ea_regnum];
384 /* The source is an int. */
385 if (len < 4) {
386 src += (4 - len);
387 #ifdef DEBUG_FPE
388 printf("load_ea: short/byte opr - addr adjusted\n");
389 #endif
390 }
391 #ifdef DEBUG_FPE
392 printf("load_ea: src %p\n", src);
393 #endif
394 bcopy(src, dst, len);
395 } else if (ea->ea_flags & EA_IMMED) {
396 #ifdef DEBUG_FPE
397 printf("load_ea: immed %08x%08x%08x size %d\n",
398 ea->ea_immed[0], ea->ea_immed[1], ea->ea_immed[2], len);
399 #endif
400 src = (char *)&ea->ea_immed[0];
401 if (len < 4) {
402 src += (4 - len);
403 #ifdef DEBUG_FPE
404 printf("load_ea: short/byte immed opr - addr adjusted\n");
405 #endif
406 }
407 bcopy(src, dst, len);
408 } else if (ea->ea_flags & EA_ABS) {
409 #ifdef DEBUG_FPE
410 printf("load_ea: abs addr %08x\n", ea->ea_absaddr);
411 #endif
412 src = (char *)ea->ea_absaddr;
413 copyin(src, dst, len);
414 } else /* register indirect */ {
415 if (ea->ea_flags & EA_PC_REL) {
416 #ifdef DEBUG_FPE
417 printf("load_ea: using PC\n");
418 #endif
419 reg = NULL;
420 /* Grab the register contents. 4 is offset to the first
421 extention word from the opcode */
422 src = (char *)insn->is_pc + 4;
423 #ifdef DEBUG_FPE
424 printf("load_ea: pc relative pc+4 = %p\n", src);
425 #endif
426 } else /* not PC relative */ {
427 #ifdef DEBUG_FPE
428 printf("load_ea: using register %c%d\n",
429 (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7);
430 #endif
431 /* point to the register */
432 reg = &frame->f_regs[ea->ea_regnum];
433
434 if (ea->ea_flags & EA_PREDECR) {
435 #ifdef DEBUG_FPE
436 printf("load_ea: predecr mode - reg decremented\n");
437 #endif
438 *reg -= step;
439 ea->ea_moffs = 0;
440 }
441
442 /* Grab the register contents. */
443 src = (char *)*reg;
444 #ifdef DEBUG_FPE
445 printf("load_ea: reg indirect reg = %p\n", src);
446 #endif
447 }
448
449 sig = calc_ea(ea, src, &src);
450 if (sig)
451 return sig;
452
453 copyin(src + ea->ea_moffs, dst, len);
454
455 /* do post-increment */
456 if (ea->ea_flags & EA_POSTINCR) {
457 if (ea->ea_flags & EA_PC_REL) {
458 #ifdef DEBUG
459 printf("load_ea: tried to postincrement PC\n");
460 #endif
461 return SIGILL;
462 }
463 *reg += step;
464 ea->ea_moffs = 0;
465 #ifdef DEBUG_FPE
466 printf("load_ea: postinc mode - reg incremented\n");
467 #endif
468 } else {
469 ea->ea_moffs += len;
470 }
471 }
472
473 return 0;
474 }
475
476 /*
477 * Store a value at the effective address.
478 * Returns zero on success, else signal number.
479 */
480 int
481 fpu_store_ea(frame, insn, ea, src)
482 struct frame *frame;
483 struct instruction *insn;
484 struct insn_ea *ea;
485 char *src;
486 {
487 int *reg;
488 char *dst;
489 int len, step;
490 int sig;
491
492 #ifdef DIAGNOSTIC
493 if (ea->ea_regnum & ~0xf) {
494 panic("store_ea: bad regnum");
495 }
496 #endif
497
498 if (ea->ea_flags & (EA_IMMED|EA_PC_REL)) {
499 /* not alterable address mode */
500 #ifdef DEBUG
501 printf("store_ea: not alterable address mode\n");
502 #endif
503 return SIGILL;
504 }
505
506 /* src is always int or larger. */
507 len = insn->is_datasize;
508 if (len < 4) {
509 src += (4 - len);
510 }
511 step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len;
512
513 if (ea->ea_flags & EA_FRAME_EA) {
514 /* Using LC040 frame EA */
515 #ifdef DEBUG_FPE
516 if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) {
517 printf("store_ea: frame ea %08x w/r%d\n",
518 ea->ea_fea, ea->ea_regnum);
519 } else {
520 printf("store_ea: frame ea %08x\n", ea->ea_fea);
521 }
522 #endif
523 dst = (char *)ea->ea_fea;
524 copyout(src, dst + ea->ea_moffs, len);
525 if (ea->ea_flags & EA_PREDECR) {
526 frame->f_regs[ea->ea_regnum] = ea->ea_fea;
527 ea->ea_fea -= step;
528 ea->ea_moffs = 0;
529 } else if (ea->ea_flags & EA_POSTINCR) {
530 ea->ea_fea += step;
531 frame->f_regs[ea->ea_regnum] = ea->ea_fea;
532 ea->ea_moffs = 0;
533 } else {
534 ea->ea_moffs += step;
535 }
536 /* That's it, folks */
537 } else if (ea->ea_flags & EA_ABS) {
538 #ifdef DEBUG_FPE
539 printf("store_ea: abs addr %08x\n", ea->ea_absaddr);
540 #endif
541 dst = (char *)ea->ea_absaddr;
542 copyout(src, dst + ea->ea_moffs, len);
543 ea->ea_moffs += len;
544 } else if (ea->ea_flags & EA_DIRECT) {
545 if (len > 4) {
546 #ifdef DEBUG
547 printf("store_ea: operand doesn't fit cpu reg\n");
548 #endif
549 return SIGILL;
550 }
551 if (ea->ea_moffs > 0) {
552 #ifdef DEBUG
553 printf("store_ea: more than one move to cpu reg\n");
554 #endif
555 return SIGILL;
556 }
557 dst = (char*)&frame->f_regs[ea->ea_regnum];
558 /* The destination is an int. */
559 if (len < 4) {
560 dst += (4 - len);
561 #ifdef DEBUG_FPE
562 printf("store_ea: short/byte opr - dst addr adjusted\n");
563 #endif
564 }
565 #ifdef DEBUG_FPE
566 printf("store_ea: dst %p\n", dst);
567 #endif
568 bcopy(src, dst, len);
569 } else /* One of MANY indirect forms... */ {
570 #ifdef DEBUG_FPE
571 printf("store_ea: using register %c%d\n",
572 (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7);
573 #endif
574 /* point to the register */
575 reg = &(frame->f_regs[ea->ea_regnum]);
576
577 /* do pre-decrement */
578 if (ea->ea_flags & EA_PREDECR) {
579 #ifdef DEBUG_FPE
580 printf("store_ea: predecr mode - reg decremented\n");
581 #endif
582 *reg -= step;
583 ea->ea_moffs = 0;
584 }
585
586 /* calculate the effective address */
587 sig = calc_ea(ea, (char *)*reg, &dst);
588 if (sig)
589 return sig;
590
591 #ifdef DEBUG_FPE
592 printf("store_ea: dst addr=%p+%d\n", dst, ea->ea_moffs);
593 #endif
594 copyout(src, dst + ea->ea_moffs, len);
595
596 /* do post-increment */
597 if (ea->ea_flags & EA_POSTINCR) {
598 *reg += step;
599 ea->ea_moffs = 0;
600 #ifdef DEBUG_FPE
601 printf("store_ea: postinc mode - reg incremented\n");
602 #endif
603 } else {
604 ea->ea_moffs += len;
605 }
606 }
607
608 return 0;
609 }
610
611 /*
612 * fetch_immed: fetch immediate operand
613 */
614 static int
615 fetch_immed(frame, insn, dst)
616 struct frame *frame;
617 struct instruction *insn;
618 int *dst;
619 {
620 int data, ext_bytes;
621
622 ext_bytes = insn->is_datasize;
623
624 if (0 < ext_bytes) {
625 data = fusword((void *) (insn->is_pc + insn->is_advance));
626 if (data < 0) {
627 return SIGSEGV;
628 }
629 if (ext_bytes == 1) {
630 /* sign-extend byte to long */
631 data &= 0xff;
632 if (data & 0x80) {
633 data |= 0xffffff00;
634 }
635 } else if (ext_bytes == 2) {
636 /* sign-extend word to long */
637 data &= 0xffff;
638 if (data & 0x8000) {
639 data |= 0xffff0000;
640 }
641 }
642 insn->is_advance += 2;
643 dst[0] = data;
644 }
645 if (2 < ext_bytes) {
646 data = fusword((void *) (insn->is_pc + insn->is_advance));
647 if (data < 0) {
648 return SIGSEGV;
649 }
650 insn->is_advance += 2;
651 dst[0] <<= 16;
652 dst[0] |= data;
653 }
654 if (4 < ext_bytes) {
655 data = fusword((void *) (insn->is_pc + insn->is_advance));
656 if (data < 0) {
657 return SIGSEGV;
658 }
659 dst[1] = data << 16;
660 data = fusword((void *) (insn->is_pc + insn->is_advance + 2));
661 if (data < 0) {
662 return SIGSEGV;
663 }
664 insn->is_advance += 4;
665 dst[1] |= data;
666 }
667 if (8 < ext_bytes) {
668 data = fusword((void *) (insn->is_pc + insn->is_advance));
669 if (data < 0) {
670 return SIGSEGV;
671 }
672 dst[2] = data << 16;
673 data = fusword((void *) (insn->is_pc + insn->is_advance + 2));
674 if (data < 0) {
675 return SIGSEGV;
676 }
677 insn->is_advance += 4;
678 dst[2] |= data;
679 }
680
681 return 0;
682 }
683
684 /*
685 * fetch_disp: fetch displacement in full extention words
686 */
687 static int
688 fetch_disp(frame, insn, size, res)
689 struct frame *frame;
690 struct instruction *insn;
691 int size, *res;
692 {
693 int disp, word;
694
695 if (size == 1) {
696 word = fusword((void *) (insn->is_pc + insn->is_advance));
697 if (word < 0) {
698 return SIGSEGV;
699 }
700 disp = word & 0xffff;
701 if (disp & 0x8000) {
702 /* sign-extend */
703 disp |= 0xffff0000;
704 }
705 insn->is_advance += 2;
706 } else if (size == 2) {
707 word = fusword((void *) (insn->is_pc + insn->is_advance));
708 if (word < 0) {
709 return SIGSEGV;
710 }
711 disp = word << 16;
712 word = fusword((void *) (insn->is_pc + insn->is_advance + 2));
713 if (word < 0) {
714 return SIGSEGV;
715 }
716 disp |= (word & 0xffff);
717 insn->is_advance += 4;
718 } else {
719 disp = 0;
720 }
721 *res = disp;
722 return 0;
723 }
724
725 /*
726 * Calculates an effective address for all address modes except for
727 * register direct, absolute, and immediate modes. However, it does
728 * not take care of predecrement/postincrement of register content.
729 * Returns a signal value (0 == no error).
730 */
731 static int
732 calc_ea(ea, ptr, eaddr)
733 struct insn_ea *ea;
734 char *ptr; /* base address (usually a register content) */
735 char **eaddr; /* pointer to result pointer */
736 {
737 int data, word;
738
739 #if DEBUG_FPE
740 printf("calc_ea: reg indirect (reg) = %p\n", ptr);
741 #endif
742
743 if (ea->ea_flags & EA_OFFSET) {
744 /* apply the signed offset */
745 #if DEBUG_FPE
746 printf("calc_ea: offset %d\n", ea->ea_offset);
747 #endif
748 ptr += ea->ea_offset;
749 } else if (ea->ea_flags & EA_INDEXED) {
750 #if DEBUG_FPE
751 printf("calc_ea: indexed mode\n");
752 #endif
753
754 if (ea->ea_flags & EA_BASE_SUPPRSS) {
755 /* base register is suppressed */
756 ptr = (char *)ea->ea_basedisp;
757 } else {
758 ptr += ea->ea_basedisp;
759 }
760
761 if (ea->ea_flags & EA_MEM_INDIR) {
762 #if DEBUG_FPE
763 printf("calc_ea: mem indir mode: basedisp=%08x, outerdisp=%08x\n",
764 ea->ea_basedisp, ea->ea_outerdisp);
765 printf("calc_ea: addr fetched from %p\n", ptr);
766 #endif
767 /* memory indirect modes */
768 word = fusword(ptr);
769 if (word < 0) {
770 return SIGSEGV;
771 }
772 word <<= 16;
773 data = fusword(ptr + 2);
774 if (data < 0) {
775 return SIGSEGV;
776 }
777 word |= data;
778 #if DEBUG_FPE
779 printf("calc_ea: fetched ptr 0x%08x\n", word);
780 #endif
781 ptr = (char *)word + ea->ea_outerdisp;
782 }
783 }
784
785 *eaddr = ptr;
786
787 return 0;
788 }
789