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