text: /*
   *       emu68 - get 68000 addressing mode effective address
   *             Copyright (C) 2001-2009 Benjamin Gerard
   *           <benjihan -4t- users.sourceforge -d0t- net>
   *
   * This  program is  free  software: you  can  redistribute it  and/or
   * modify  it under the  terms of  the GNU  General Public  License as
   * published by the Free Software  Foundation, either version 3 of the
   * License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
   * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
   * General Public License for more details.
   *
   * You should have  received a copy of the  GNU General Public License
   * along with this program.
   * If not, see <http://www.gnu.org/licenses/>.
   *
   */
  
  /* $Id: getea68.c 116 2009-06-18 14:09:54Z benjihan $ */
  
  #ifdef HAVE_CONFIG_H
  # include "config.h"
  #endif
  
  #include "error68.h"
  #include "assert68.h"
  #include "mem68.h"
  
  static addr68_t ea_error(emu68_t * const emu68, const int reg)
  {
    assert(EMU68_BREAK);
    return 0;
  }
  
  /* (AN) */
  static addr68_t ea_inAN(emu68_t * const emu68, const int reg)
  {
    return (s32) REG68.a[reg];
  }
  
  /* (AN)+ */
  static addr68_t ea_inANpb(emu68_t * const emu68, const int reg)
  {
    addr68_t addr = (s32) REG68.a[reg];
    REG68.a[reg]  = (u32) ( REG68.a[reg] + 1 + (reg==7) );
    return addr;
  }
  
  static addr68_t ea_inANpw(emu68_t * const emu68, const int reg)
  {
    addr68_t addr = (s32) REG68.a[reg];
    REG68.a[reg]  = (u32) ( REG68.a[reg] + 2 );
    return addr;
  }
  
  static addr68_t ea_inANpl(emu68_t * const emu68, const int reg)
  {
    addr68_t addr = (s32) REG68.a[reg];
    REG68.a[reg]  = (u32) ( REG68.a[reg] + 4 );
    return addr;
  }
  
  /* -(AN) */
  static addr68_t ea_inmANb(emu68_t * const emu68, const int reg)
  {
    return (s32) ( REG68.a[reg] = (u32) ( REG68.a[reg] - 1 - (reg==7) ) );
  }
  
  static addr68_t ea_inmANw(emu68_t * const emu68, const int reg)
  {
    return (s32) ( REG68.a[reg] = (u32) ( REG68.a[reg] - 2 ) );
  }
  
  static addr68_t ea_inmANl(emu68_t * const emu68, const int reg)
  {
    return (s32) ( REG68.a[reg] = (u32) ( REG68.a[reg] - 4 ) );
  }
  
  /* d(AN) */
  static addr68_t ea_indAN(emu68_t * const emu68, const int reg)
  {
    return (s32) ( REG68.a[reg] + get_nextw() );
  }
  
  /* d(AN,Xi) */
  static addr68_t ea_inANXI(emu68_t * const emu68, const int reg)
  {
    int68_t w = get_nextw();
    int68_t reg2;
    reg2 = ( w >> 12 ) & 15;
    reg2 = ( w & 04000 )
      ? (int68_t) (s32) REG68.d[reg2]
      : (int68_t) (s16) REG68.d[reg2]
      ;
    return (s32) ( REG68.a[reg] + (s8) w + reg2 );
  }
  
  /* ABS.W */
  static addr68_t ea_inABSW(emu68_t * const emu68, const int reg)
  {
    return get_nextw();
  }
  
  /* ABS.L */
  static addr68_t ea_inABSL(emu68_t * const emu68, const int reg)
  {
    return get_nextl();
  }
  
  /* d(PC) */
  static addr68_t ea_inrelPC(emu68_t * const emu68, const int reg)
  {
    addr68_t pc = (s32) REG68.pc;
    return (s32) ( pc + get_nextw() );
  }
  
  /* d(PC,Xi) */
  static addr68_t ea_inPCXI(emu68_t * const emu68, const int reg)
  {
    addr68_t  pc = (s32) REG68.pc;
    int68_t    w = get_nextw();
    int68_t reg2 = ( w >> 12 ) & 15;
    pc += ( w & 04000 )
      ? (int68_t) (s32) REG68.d[reg2]
      : (int68_t) (s16) REG68.d[reg2]
      ;
    pc += (s8) w;
    return (s32) pc;
  }
  
  /* # */
  static addr68_t ea_inIMMb(emu68_t * const emu68, const int reg)
  {
    addr68_t pc = (s32) REG68.pc;
    REG68.pc = (u32) ( pc + 2 );
    return (s32) ( pc + 1 );
  }
  
  static addr68_t ea_inIMMw(emu68_t * const emu68, const int reg)
  {
    s32 pc = REG68.pc;
    REG68.pc = (u32) (pc + 2);
    return pc;
  }
  
  static addr68_t ea_inIMMl(emu68_t * const emu68, const int reg)
  {
    s32 pc = REG68.pc;
    REG68.pc = (u32) ( pc + 4 );
    return pc;
  }
  
  /***************************
   *                          *
   * Opmode tables for Get EA *
   *                          *
   ***************************/
  
  /* Mode 7 tables */
  
  static addr68_t (* const ea_b7[8])(emu68_t * const, const int) =
  {
    ea_inABSW, ea_inABSL, ea_inrelPC, ea_inPCXI,
    ea_inIMMb, ea_error, ea_error, ea_error
  };
  
  static addr68_t (* const ea_w7[8])(emu68_t * const, const int) =
  {
    ea_inABSW, ea_inABSL, ea_inrelPC, ea_inPCXI,
    ea_inIMMw, ea_error, ea_error, ea_error
  };
  
  static addr68_t (* const ea_l7[8])(emu68_t * const, const int) =
  {
    ea_inABSW, ea_inABSL, ea_inrelPC, ea_inPCXI,
    ea_inIMMl, ea_error, ea_error, ea_error
  };
  
  /* Mode 7 redirect functions */
  
  static addr68_t ea_mode7b(emu68_t * const emu68, const int reg)
  {
    return (ea_b7[reg])(emu68, reg);
  }
  
  static addr68_t ea_mode7w(emu68_t * const emu68, const int reg)
  {
    return (ea_w7[reg])(emu68, reg);
  }
  
  static addr68_t ea_mode7l(emu68_t * const emu68, const int reg)
  {
    return (ea_l7[reg])(emu68, reg);
  }
  
  /* Get EA tables */
  
  addr68_t (* const get_eab68[8])(emu68_t * const, const int) =
  {
    ea_error, ea_error, ea_inAN, ea_inANpb,
    ea_inmANb,ea_indAN,ea_inANXI,
    ea_mode7b,
  };
  
  addr68_t (* const get_eaw68[8])(emu68_t * const, const int) =
  {
    ea_error, ea_error, ea_inAN, ea_inANpw,
    ea_inmANw,ea_indAN,ea_inANXI,
    ea_mode7w,
  };
  
  addr68_t (* const get_eal68[8])(emu68_t * const, const int) =
  {
    ea_error, ea_error, ea_inAN, ea_inANpl,
    ea_inmANl,ea_indAN,ea_inANXI,
    ea_mode7l,
  };
  
  