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