1 /* $NetBSD: fpu_calcea.c,v 1.28 2024/12/28 03:11:09 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.28 2024/12/28 03:11:09 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 idx; 216 int basedisp, outerdisp; 217 int bd_size, od_size; 218 int sig; 219 unsigned short extword; 220 221 if (ufetch_short((void *)(insn->is_pc + insn->is_advance), &extword)) 222 return SIGSEGV; 223 insn->is_advance += 2; 224 225 /* get register index */ 226 ea->ea_idxreg = (extword >> 12) & 0xf; 227 idx = frame->f_regs[ea->ea_idxreg]; 228 if ((extword & 0x0800) == 0) { 229 /* if word sized index, sign-extend */ 230 idx &= 0xffff; 231 if (idx & 0x8000) { 232 idx |= 0xffff0000; 233 } 234 } 235 /* scale register index */ 236 idx <<= ((extword >> 9) & 3); 237 238 if ((extword & 0x100) == 0) { 239 /* brief extension word - sign-extend the displacement */ 240 basedisp = (extword & 0xff); 241 if (basedisp & 0x80) { 242 basedisp |= 0xffffff00; 243 } 244 245 ea->ea_basedisp = idx + basedisp; 246 ea->ea_outerdisp = 0; 247 DPRINTF(("%s: brief ext word idxreg=%d, basedisp=%08x\n", 248 __func__, ea->ea_idxreg, ea->ea_basedisp)); 249 } else { 250 /* full extension word */ 251 if (extword & 0x80) { 252 ea->ea_flags |= EA_BASE_SUPPRSS; 253 } 254 bd_size = ((extword >> 4) & 3) - 1; 255 od_size = (extword & 3) - 1; 256 sig = fetch_disp(frame, insn, bd_size, &basedisp); 257 if (sig) 258 return sig; 259 if (od_size >= 0) 260 ea->ea_flags |= EA_MEM_INDIR; 261 sig = fetch_disp(frame, insn, od_size, &outerdisp); 262 if (sig) 263 return sig; 264 265 switch (extword & 0x44) { 266 case 0: /* preindexed */ 267 ea->ea_basedisp = basedisp + idx; 268 ea->ea_outerdisp = outerdisp; 269 break; 270 case 4: /* postindexed */ 271 ea->ea_basedisp = basedisp; 272 ea->ea_outerdisp = outerdisp + idx; 273 break; 274 case 0x40: /* no index */ 275 ea->ea_basedisp = basedisp; 276 ea->ea_outerdisp = outerdisp; 277 break; 278 default: 279 DPRINTF(("%s: invalid indirect mode: ext word %04x\n", 280 __func__, extword)); 281 return SIGILL; 282 break; 283 } 284 DPRINTF(("%s: full ext idxreg=%d, basedisp=%x, outerdisp=%x\n", 285 __func__, 286 ea->ea_idxreg, ea->ea_basedisp, ea->ea_outerdisp)); 287 } 288 DPRINTF(("%s: regnum=%d, flags=%x\n", 289 __func__, ea->ea_regnum, ea->ea_flags)); 290 return 0; 291 } 292 293 /* 294 * Load a value from an effective address. 295 * Returns zero on success, else signal number. 296 */ 297 int 298 fpu_load_ea(struct frame *frame, struct instruction *insn, struct insn_ea *ea, 299 char *dst) 300 { 301 int *reg; 302 char *src; 303 int len, step; 304 int sig; 305 306 #ifdef DIAGNOSTIC 307 if (ea->ea_regnum & ~0xF) 308 panic("%s: bad regnum", __func__); 309 #endif 310 311 DPRINTF(("%s: frame at %p\n", __func__, frame)); 312 /* dst is always int or larger. */ 313 len = insn->is_datasize; 314 if (len < 4) 315 dst += (4 - len); 316 step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len; 317 318 #if 0 319 if (ea->ea_flags & EA_FRAME_EA) { 320 /* Using LC040 frame EA */ 321 #ifdef DEBUG_FPE 322 if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) { 323 printf("%s: frame ea %08x w/r%d\n", 324 __func__, ea->ea_fea, ea->ea_regnum); 325 } else { 326 printf("%s: frame ea %08x\n", __func__, ea->ea_fea); 327 } 328 #endif 329 src = (char *)ea->ea_fea; 330 copyin(src + ea->ea_moffs, dst, len); 331 if (ea->ea_flags & EA_PREDECR) { 332 frame->f_regs[ea->ea_regnum] = ea->ea_fea; 333 ea->ea_fea -= step; 334 ea->ea_moffs = 0; 335 } else if (ea->ea_flags & EA_POSTINCR) { 336 ea->ea_fea += step; 337 frame->f_regs[ea->ea_regnum] = ea->ea_fea; 338 ea->ea_moffs = 0; 339 } else { 340 ea->ea_moffs += step; 341 } 342 /* That's it, folks */ 343 } else 344 #endif 345 if (ea->ea_flags & EA_DIRECT) { 346 if (len > 4) { 347 DPRINTF(("%s: operand doesn't fit CPU reg\n", 348 __func__)); 349 return SIGILL; 350 } 351 if (ea->ea_moffs > 0) { 352 DPRINTF(("%s: more than one move from CPU reg\n", 353 __func__)); 354 return SIGILL; 355 } 356 src = (char *)&frame->f_regs[ea->ea_regnum]; 357 /* The source is an int. */ 358 if (len < 4) { 359 src += (4 - len); 360 DPRINTF(("%s: short/byte opr - addr adjusted\n", 361 __func__)); 362 } 363 DPRINTF(("%s: src %p\n", __func__, src)); 364 memcpy(dst, src, len); 365 } else if (ea->ea_flags & EA_IMMED) { 366 DPRINTF(("%s: immed %08x%08x%08x size %d\n", __func__, 367 ea->ea_immed[0], ea->ea_immed[1], ea->ea_immed[2], len)); 368 src = (char *)&ea->ea_immed[0]; 369 if (len < 4) { 370 src += (4 - len); 371 DPRINTF(("%s: short/byte immed opr - addr adjusted\n", 372 __func__)); 373 } 374 memcpy(dst, src, len); 375 } else if (ea->ea_flags & EA_ABS) { 376 DPRINTF(("%s: abs addr %08x\n", __func__, ea->ea_absaddr)); 377 src = (char *)ea->ea_absaddr; 378 copyin(src, dst, len); 379 } else /* register indirect */ { 380 if (ea->ea_flags & EA_PC_REL) { 381 DPRINTF(("%s: using PC\n", __func__)); 382 reg = NULL; 383 /* 384 * Grab the register contents. 4 is offset to the first 385 * extension word from the opcode 386 */ 387 src = (char *)insn->is_pc + 4; 388 DPRINTF(("%s: pc relative pc+4 = %p\n", __func__, src)); 389 } else /* not PC relative */ { 390 DPRINTF(("%s: using register %c%d\n", 391 __func__, 392 (ea->ea_regnum >= 8) ? 'a' : 'd', 393 ea->ea_regnum & 7)); 394 /* point to the register */ 395 reg = &frame->f_regs[ea->ea_regnum]; 396 397 if (ea->ea_flags & EA_PREDECR) { 398 DPRINTF(("%s: predecr mode - " 399 "reg decremented\n", __func__)); 400 *reg -= step; 401 ea->ea_moffs = 0; 402 } 403 404 /* Grab the register contents. */ 405 src = (char *)*reg; 406 DPRINTF(("%s: reg indirect reg = %p\n", __func__, src)); 407 } 408 409 sig = calc_ea(ea, src, &src); 410 if (sig) 411 return sig; 412 413 copyin(src + ea->ea_moffs, dst, len); 414 415 /* do post-increment */ 416 if (ea->ea_flags & EA_POSTINCR) { 417 if (ea->ea_flags & EA_PC_REL) { 418 DPRINTF(("%s: tried to postincrement PC\n", 419 __func__)); 420 return SIGILL; 421 } 422 *reg += step; 423 ea->ea_moffs = 0; 424 DPRINTF(("%s: postinc mode - reg incremented\n", 425 __func__)); 426 } else { 427 ea->ea_moffs += len; 428 } 429 } 430 431 return 0; 432 } 433 434 /* 435 * Store a value at the effective address. 436 * Returns zero on success, else signal number. 437 */ 438 int 439 fpu_store_ea(struct frame *frame, struct instruction *insn, struct insn_ea *ea, 440 char *src) 441 { 442 int *reg; 443 char *dst; 444 int len, step; 445 int sig; 446 447 #ifdef DIAGNOSTIC 448 if (ea->ea_regnum & ~0xf) 449 panic("%s: bad regnum", __func__); 450 #endif 451 452 if (ea->ea_flags & (EA_IMMED|EA_PC_REL)) { 453 /* not alterable address mode */ 454 DPRINTF(("%s: not alterable address mode\n", __func__)); 455 return SIGILL; 456 } 457 458 /* src is always int or larger. */ 459 len = insn->is_datasize; 460 if (len < 4) 461 src += (4 - len); 462 step = (len == 1 && ea->ea_regnum == 15 /* sp */) ? 2 : len; 463 464 if (ea->ea_flags & EA_FRAME_EA) { 465 /* Using LC040 frame EA */ 466 #ifdef DEBUG_FPE 467 if (ea->ea_flags & (EA_PREDECR|EA_POSTINCR)) { 468 printf("%s: frame ea %08x w/r%d\n", 469 __func__, ea->ea_fea, ea->ea_regnum); 470 } else { 471 printf("%s: frame ea %08x\n", __func__, ea->ea_fea); 472 } 473 #endif 474 dst = (char *)ea->ea_fea; 475 copyout(src, dst + ea->ea_moffs, len); 476 if (ea->ea_flags & EA_PREDECR) { 477 frame->f_regs[ea->ea_regnum] = ea->ea_fea; 478 ea->ea_fea -= step; 479 ea->ea_moffs = 0; 480 } else if (ea->ea_flags & EA_POSTINCR) { 481 ea->ea_fea += step; 482 frame->f_regs[ea->ea_regnum] = ea->ea_fea; 483 ea->ea_moffs = 0; 484 } else { 485 ea->ea_moffs += step; 486 } 487 /* That's it, folks */ 488 } else if (ea->ea_flags & EA_ABS) { 489 DPRINTF(("%s: abs addr %08x\n", __func__, ea->ea_absaddr)); 490 dst = (char *)ea->ea_absaddr; 491 copyout(src, dst + ea->ea_moffs, len); 492 ea->ea_moffs += len; 493 } else if (ea->ea_flags & EA_DIRECT) { 494 if (len > 4) { 495 DPRINTF(("%s: operand doesn't fit CPU reg\n", 496 __func__)); 497 return SIGILL; 498 } 499 if (ea->ea_moffs > 0) { 500 DPRINTF(("%s: more than one move to CPU reg\n", 501 __func__)); 502 return SIGILL; 503 } 504 dst = (char *)&frame->f_regs[ea->ea_regnum]; 505 /* The destination is an int. */ 506 if (len < 4) { 507 dst += (4 - len); 508 DPRINTF(("%s: short/byte opr - dst addr adjusted\n", 509 __func__)); 510 } 511 DPRINTF(("%s: dst %p\n", __func__, dst)); 512 memcpy(dst, src, len); 513 } else /* One of MANY indirect forms... */ { 514 DPRINTF(("%s: using register %c%d\n", __func__, 515 (ea->ea_regnum >= 8) ? 'a' : 'd', ea->ea_regnum & 7)); 516 /* point to the register */ 517 reg = &(frame->f_regs[ea->ea_regnum]); 518 519 /* do pre-decrement */ 520 if (ea->ea_flags & EA_PREDECR) { 521 DPRINTF(("%s: predecr mode - reg decremented\n", 522 __func__)); 523 *reg -= step; 524 ea->ea_moffs = 0; 525 } 526 527 /* calculate the effective address */ 528 sig = calc_ea(ea, (char *)*reg, &dst); 529 if (sig) 530 return sig; 531 532 DPRINTF(("%s: dst addr=%p+%d\n", __func__, dst, ea->ea_moffs)); 533 copyout(src, dst + ea->ea_moffs, len); 534 535 /* do post-increment */ 536 if (ea->ea_flags & EA_POSTINCR) { 537 *reg += step; 538 ea->ea_moffs = 0; 539 DPRINTF(("%s: postinc mode - reg incremented\n", 540 __func__)); 541 } else { 542 ea->ea_moffs += len; 543 } 544 } 545 546 return 0; 547 } 548 549 /* 550 * fetch_immed: fetch immediate operand 551 */ 552 static int 553 fetch_immed(struct frame *frame, struct instruction *insn, int *dst) 554 { 555 int data, ext_bytes; 556 unsigned short sval; 557 558 ext_bytes = insn->is_datasize; 559 560 if (0 < ext_bytes) { 561 if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 562 &sval)) 563 return SIGSEGV; 564 data = sval; 565 if (ext_bytes == 1) { 566 /* sign-extend byte to long */ 567 data &= 0xff; 568 if (data & 0x80) 569 data |= 0xffffff00; 570 } else if (ext_bytes == 2) { 571 /* sign-extend word to long */ 572 data &= 0xffff; 573 if (data & 0x8000) 574 data |= 0xffff0000; 575 } 576 insn->is_advance += 2; 577 dst[0] = data; 578 } 579 if (2 < ext_bytes) { 580 if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 581 &sval)) 582 return SIGSEGV; 583 insn->is_advance += 2; 584 dst[0] <<= 16; 585 dst[0] |= sval; 586 } 587 if (4 < ext_bytes) { 588 if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 589 &sval)) 590 return SIGSEGV; 591 data = sval; 592 dst[1] = data << 16; 593 if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2), 594 &sval)) 595 return SIGSEGV; 596 insn->is_advance += 4; 597 dst[1] |= sval; 598 } 599 if (8 < ext_bytes) { 600 if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 601 &sval)) 602 return SIGSEGV; 603 data = sval; 604 dst[2] = data << 16; 605 if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2), 606 &sval)) 607 return SIGSEGV; 608 insn->is_advance += 4; 609 dst[2] |= sval; 610 } 611 612 return 0; 613 } 614 615 /* 616 * fetch_disp: fetch displacement in full extension words 617 */ 618 static int 619 fetch_disp(struct frame *frame, struct instruction *insn, int size, int *res) 620 { 621 int disp, word; 622 unsigned short sval; 623 624 if (size == 1) { 625 if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 626 &sval)) 627 return SIGSEGV; 628 disp = sval; 629 if (disp & 0x8000) { 630 /* sign-extend */ 631 disp |= 0xffff0000; 632 } 633 insn->is_advance += 2; 634 } else if (size == 2) { 635 if (ufetch_short((void *)(insn->is_pc + insn->is_advance), 636 &sval)) 637 return SIGSEGV; 638 word = sval; 639 disp = word << 16; 640 if (ufetch_short((void *)(insn->is_pc + insn->is_advance + 2), 641 &sval)) 642 return SIGSEGV; 643 disp |= sval; 644 insn->is_advance += 4; 645 } else { 646 disp = 0; 647 } 648 *res = disp; 649 return 0; 650 } 651 652 /* 653 * Calculates an effective address for all address modes except for 654 * register direct, absolute, and immediate modes. However, it does 655 * not take care of predecrement/postincrement of register content. 656 * Returns a signal value (0 == no error). 657 */ 658 static int 659 calc_ea(struct insn_ea *ea, char *ptr, char **eaddr) 660 /* ptr: base address (usually a register content) */ 661 /* eaddr: pointer to result pointer */ 662 { 663 int word; 664 unsigned short sval; 665 666 DPRINTF(("%s: reg indirect (reg) = %p\n", __func__, ptr)); 667 668 if (ea->ea_flags & EA_OFFSET) { 669 /* apply the signed offset */ 670 DPRINTF(("%s: offset %d\n", __func__, ea->ea_offset)); 671 ptr += ea->ea_offset; 672 } else if (ea->ea_flags & EA_INDEXED) { 673 DPRINTF(("%s: indexed mode\n", __func__)); 674 675 if (ea->ea_flags & EA_BASE_SUPPRSS) { 676 /* base register is suppressed */ 677 ptr = (char *)ea->ea_basedisp; 678 } else { 679 ptr += ea->ea_basedisp; 680 } 681 682 if (ea->ea_flags & EA_MEM_INDIR) { 683 DPRINTF(("%s: mem indir mode: basedisp=%08x, " 684 "outerdisp=%08x\n", 685 __func__, ea->ea_basedisp, ea->ea_outerdisp)); 686 DPRINTF(("%s: addr fetched from %p\n", __func__, ptr)); 687 /* memory indirect modes */ 688 if (ufetch_short((u_short *)ptr, &sval)) 689 return SIGSEGV; 690 word = sval; 691 word <<= 16; 692 if (ufetch_short((u_short *)(ptr + 2), &sval)) 693 return SIGSEGV; 694 word |= sval; 695 DPRINTF(("%s: fetched ptr 0x%08x\n", __func__, word)); 696 ptr = (char *)word + ea->ea_outerdisp; 697 } 698 } 699 700 *eaddr = ptr; 701 702 return 0; 703 } 704