/*
Copyright Notice
================
BOCHS is Copyright 1994 by Kevin P. Lawton.

BOCHS is shareware for PERSONAL USE only.

For more information, read the file 'LICENSE' included in the bochs
distribution.  If you don't have access to this file, or have questions
regarding the licensing policy, the author may be contacted via:

    US Mail:  Kevin Lawton
              528 Lexington St.
              Waltham, MA 02154

    EMail:    bochs@tiac.net
*/





#include <stdio.h>

#include "bx_bochs.h"



  void
bx_MOV_EbGb() {
  Bit8u op2;
  Bit32u op2_addr, op1_addr;
  int op1_type;
  bx_segment_reg_t *op1_seg_reg;


  bx_decode_exgx(&op2_addr, &op1_addr, &op1_type, &op1_seg_reg);

  /* op2 is a register, op2_addr is an index of a register */
  BX_READ_8BIT_REG(op2, op2_addr);

  /* now write op2 to op1 */
  if (op1_type == BX_REGISTER_REF) {
    BX_WRITE_8BIT_REG(op1_addr, op2);
    }
  else
    bx_access_virtual(op1_seg_reg, op1_addr, 1, BX_WRITE, &op2);
}

  void
bx_MOV_EvGv()
{
  Bit32u op2_addr, op1_addr;
  int op1_type;
  bx_segment_reg_t *op1_seg_reg;

  /* for 32 bit operand size mode */

  Bit32u op2_32;

  /* for 16 bit operand size mode */
  Bit16u op2_16;



  bx_decode_exgx(&op2_addr, &op1_addr, &op1_type, &op1_seg_reg);

  if (bx_32bit_opsize) { /* 32 bit operand size mode */

    /* op2_32 is a register, op2_addr is an index of a register */
    BX_READ_32BIT_REG(op2_32, op2_addr);

    /* op1_32 is a register or memory reference */
    /* now write op2 to op1 */
    if (op1_type == BX_REGISTER_REF) {
      BX_WRITE_32BIT_REG(op1_addr, op2_32);
      }
    else
      bx_access_virtual(op1_seg_reg, op1_addr, 4, BX_WRITE, &op2_32);
    }
  else { /* 16 bit operand size mode */

    /* op2_16 is a register, op2_addr is an index of a register */
    BX_READ_16BIT_REG(op2_16, op2_addr);

    /* op1_16 is a register or memory reference */
    /* now write op2 to op1 */
    if (op1_type == BX_REGISTER_REF) {
      BX_WRITE_16BIT_REG(op1_addr, op2_16);
      }
    else
      bx_access_virtual(op1_seg_reg, op1_addr, 2, BX_WRITE, &op2_16);
    }
}

void bx_MOV_GbEb()
{
  Bit8u op2;
  Bit32u op1_addr, op2_addr;
  int op2_type;
  bx_segment_reg_t *op2_seg_reg;


  bx_decode_exgx(&op1_addr, &op2_addr, &op2_type, &op2_seg_reg);

  /* op1 is a register, op1_addr is an index of a register */
  /* op2 is a register or memory reference */
  if (op2_type == BX_REGISTER_REF) {
    BX_READ_8BIT_REG(op2, op2_addr);
    }
  else
    /* pointer, segment address pair */
    bx_access_virtual(op2_seg_reg, op2_addr, 1, BX_READ, &op2);

  BX_WRITE_8BIT_REG(op1_addr, op2);
}

  void
bx_MOV_GvEv()
{
  Bit32u op1_addr, op2_addr;
  int op2_type;
  bx_segment_reg_t *op2_seg_reg;
  Bit16u op2_16;
  Bit32u op2_32;


  bx_decode_exgx(&op1_addr, &op2_addr, &op2_type, &op2_seg_reg);

  if (bx_32bit_opsize) { /* 32 bit operand size mode */

    /* op1_32 is a register, op1_addr is an index of a register */
    /* op2_32 is a register or memory reference */
    if (op2_type == BX_REGISTER_REF) {
      BX_READ_32BIT_REG(op2_32, op2_addr);
      }
    else
      /* pointer, segment address pair */
      bx_access_virtual(op2_seg_reg, op2_addr, 4, BX_READ, &op2_32);

    BX_WRITE_32BIT_REG(op1_addr, op2_32);
    }
  else { /* 16 bit operand size mode */

    /* op1_16 is a register, op1_addr is an index of a register */
    /* op2_16 is a register or memory reference */
    if (op2_type == BX_REGISTER_REF) {
      BX_READ_16BIT_REG(op2_16, op2_addr);
      }
    else
      /* pointer, segment address pair */
      bx_access_virtual(op2_seg_reg, op2_addr, 2, BX_READ, &op2_16);

    BX_WRITE_16BIT_REG(op1_addr, op2_16);
    }
}

  void
bx_MOV_EwSw()
{
  Bit32u seg_reg_index;
  Bit32u mem_addr;
  Bit16u seg_reg;
  int mem_type;
  bx_segment_reg_t *mem_seg_reg;

  bx_decode_exgx(&seg_reg_index, &mem_addr, &mem_type, &mem_seg_reg);

  seg_reg = bx_read_segment_register(seg_reg_index);

  if (mem_type == BX_REGISTER_REF) {
    BX_WRITE_16BIT_REG(mem_addr, seg_reg);
    }
  else
    bx_access_virtual(mem_seg_reg, mem_addr, 2, BX_WRITE, &seg_reg);
}

  void
bx_MOV_SwEw()
{
  Bit32u seg_reg_index;
  Bit32u op2_addr;
  Bit16u op2_16;
  int    op2_type;
  bx_segment_reg_t *op2_seg_reg;

  bx_decode_exgx(&seg_reg_index, &op2_addr, &op2_type, &op2_seg_reg);

  if (op2_type == BX_REGISTER_REF) {
    BX_READ_16BIT_REG(op2_16, op2_addr);
    }
  else
    bx_access_virtual(op2_seg_reg, op2_addr, 2, BX_READ, &op2_16);

  bx_write_segment_register(seg_reg_index, op2_16);
}

  void
bx_LEA_GvM()
{
  Bit32u op1_addr, op2_addr;
  int op2_type;
  bx_segment_reg_t *op2_seg_reg;

  bx_decode_exgx(&op1_addr, &op2_addr, &op2_type, &op2_seg_reg);

  if (bx_32bit_opsize) { /* 32 bit operand size mode */

    if (op2_type == BX_REGISTER_REF)
      bx_invalid_instruction();

    /* write effective address of op2 in op1 */
    BX_WRITE_32BIT_REG(op1_addr, op2_addr);
    }
  else { /* 16 bit operand size mode */

    /* op2_16 is a register or memory reference */
    if (op2_type == BX_REGISTER_REF)
      bx_invalid_instruction();

    BX_WRITE_16BIT_REG(op1_addr, (Bit16u) op2_addr);
    }
}

  void
bx_XCHG_eCXeAX()
{
  Bit32u temp;
  Bit16u ax, cx;

  if (bx_32bit_opsize) {
    temp = bx_cpu.eax;
    bx_cpu.eax = bx_cpu.ecx;
    bx_cpu.ecx = temp;
    }
  else {
    ax = AX;
    cx = CX;
    AX = cx;
    CX = ax;
    }
}

  void
bx_XCHG_eDXeAX()
{
  Bit32u temp;
  Bit16u ax, dx;

  if (bx_32bit_opsize) {
    temp = bx_cpu.eax;
    bx_cpu.eax = bx_cpu.edx;
    bx_cpu.edx = temp;
    }
  else {
    ax = AX;
    dx = DX;
    AX = dx;
    DX = ax;
    }
}

  void
bx_XCHG_eBXeAX()
{
  Bit32u temp;
  Bit16u ax, bx;

  if (bx_32bit_opsize) {
    temp = bx_cpu.eax;
    bx_cpu.eax = bx_cpu.ebx;
    bx_cpu.ebx = temp;
    }
  else {
    ax = AX;
    bx = BX;
    AX = bx;
    BX = ax;
    }
}

  void
bx_XCHG_eSPeAX()
{
  Bit32u temp;
  Bit16u ax, sp;

  if (bx_32bit_opsize) {
    temp = bx_cpu.eax;
    bx_cpu.eax = bx_cpu.esp;
    bx_cpu.esp = temp;
    }
  else {
    ax = AX;
    sp = SP;
    AX = sp;
    SP = ax;
    }
}

  void
bx_XCHG_eBPeAX()
{
  Bit32u temp;
  Bit16u ax, bp;

  if (bx_32bit_opsize) {
    temp = bx_cpu.eax;
    bx_cpu.eax = bx_cpu.ebp;
    bx_cpu.ebp = temp;
    }
  else {
    ax = AX;
    bp = BP;
    AX = bp;
    BP = ax;
    }
}

  void
bx_XCHG_eSIeAX()
{
  Bit32u temp;
  Bit16u ax, si;

  if (bx_32bit_opsize) {
    temp = bx_cpu.eax;
    bx_cpu.eax = bx_cpu.esi;
    bx_cpu.esi = temp;
    }
  else {
    ax = AX;
    si = SI;
    AX = si;
    SI = ax;
    }
}

  void
bx_XCHG_eDIeAX()
{
  Bit32u temp;
  Bit16u ax, di;

  if (bx_32bit_opsize) {
    temp = bx_cpu.eax;
    bx_cpu.eax = bx_cpu.edi;
    bx_cpu.edi = temp;
    }
  else {
    ax = AX;
    di = DI;
    AX = di;
    DI = ax;
    }
}


  void
bx_MOV_ALOb()
{
  Bit32u addr_32;
  Bit8u  temp_8;

  if (bx_32bit_addrsize) {
    addr_32 = bx_fetch_next_dword();
    }
  else {
    addr_32 = bx_fetch_next_word();
    }

  /* read from memory address */
  if (bx_segment_override)
    bx_access_virtual(bx_segment_override, addr_32, 1, BX_READ, &temp_8);
  else
    bx_access_virtual(&bx_cpu.ds, addr_32, 1, BX_READ, &temp_8);
  

  /* write to register */
  AL = temp_8;
}

  void
bx_MOV_eAXOv()
{
  Bit32u addr_32;
  Bit32u temp_32;
  Bit16u temp_16;


  if (bx_32bit_addrsize) {
    addr_32 = bx_fetch_next_dword();
    }
  else {
    addr_32 = bx_fetch_next_word();
    }

  /* read from memory address */
  if (bx_32bit_opsize) {
    if (bx_segment_override)
      bx_access_virtual(bx_segment_override, addr_32, 4, BX_READ, &temp_32);
    else
      bx_access_virtual(&bx_cpu.ds, addr_32, 4, BX_READ, &temp_32);

    /* write to register */
    EAX = temp_32;
    }
  else { /* 16 bit opsize */
    if (bx_segment_override)
      bx_access_virtual(bx_segment_override, addr_32, 2, BX_READ, &temp_16);
    else
      bx_access_virtual(&bx_cpu.ds, addr_32, 2, BX_READ, &temp_16);

    /* write to register */
    AX = temp_16;
    }
}

  void
bx_MOV_ObAL()
{
  Bit32u addr_32;
  Bit8u  temp_8;

  if (bx_32bit_addrsize) {
    addr_32 = bx_fetch_next_dword();
    }
  else {
    addr_32 = bx_fetch_next_word();
    }

  /* read from register */
  temp_8 = AL;

  /* write to memory address */
  if (bx_segment_override)
    bx_access_virtual(bx_segment_override, addr_32, 1, BX_WRITE, &temp_8);
  else
    bx_access_virtual(&bx_cpu.ds, addr_32, 1, BX_WRITE, &temp_8);
}

  void
bx_MOV_OveAX()
{
  Bit32u addr_32;
  Bit32u temp_32;
  Bit16u temp_16;



  if (bx_32bit_addrsize) {
    addr_32 = bx_fetch_next_dword();
    }
  else {
    addr_32 = bx_fetch_next_word();
    }

  if (bx_32bit_opsize) {
    /* read from register */
    temp_32 = EAX;

    /* write to memory address */
    if (bx_segment_override)
      bx_access_virtual(bx_segment_override, addr_32, 4, BX_WRITE, &temp_32);
    else
      bx_access_virtual(&bx_cpu.ds, addr_32, 4, BX_WRITE, &temp_32);
    }
  else { /* 16 bit opsize */
    /* read from register */
    temp_16 = AX;

    /* write to memory address */
    if (bx_segment_override)
      bx_access_virtual(bx_segment_override, addr_32, 2, BX_WRITE, &temp_16);
    else
      bx_access_virtual(&bx_cpu.ds, addr_32, 2, BX_WRITE, &temp_16);
    }

}

  void
bx_MOV_ALIb()
{
  Bit8u imm8;

  imm8 = bx_fetch_next_byte();
  AL = imm8;
}

  void
bx_MOV_CLIb()
{
  Bit8u imm8;

  imm8 = bx_fetch_next_byte();
  CL = imm8;
}

  void
bx_MOV_DLIb()
{
  Bit8u imm8;

  imm8 = bx_fetch_next_byte();
  DL = imm8;
}

  void
bx_MOV_BLIb()
{
  Bit8u imm8;

  imm8 = bx_fetch_next_byte();
  BL = imm8;
}

  void
bx_MOV_AHIb()
{
  Bit8u imm8;

  imm8 = bx_fetch_next_byte();
  AH = imm8;
}

  void
bx_MOV_CHIb()
{
  Bit8u imm8;

  imm8 = bx_fetch_next_byte();
  CH = imm8;
}

  void
bx_MOV_DHIb()
{
  Bit8u imm8;

  imm8 = bx_fetch_next_byte();
  DH = imm8;
}

  void
bx_MOV_BHIb()
{
  Bit8u imm8;

  imm8 = bx_fetch_next_byte();
  BH = imm8;
}


  void
bx_MOV_eAXIv()
{
  Bit32u imm32;
  Bit16u imm16;

  if (bx_32bit_opsize) {
    imm32 = bx_fetch_next_dword();
    bx_cpu.eax = imm32;
    }
  else {
    imm16 = bx_fetch_next_word();
    AX = imm16;
    }
}

  void
bx_MOV_eCXIv()
{
  Bit32u imm32;
  Bit16u imm16;

  if (bx_32bit_opsize) {
    imm32 = bx_fetch_next_dword();
    ECX = imm32;
    }
  else {
    imm16 = bx_fetch_next_word();
    CX = imm16;
    }
}

  void
bx_MOV_eDXIv()
{
  Bit32u imm32;
  Bit16u imm16;

  if (bx_32bit_opsize) {
    imm32 = bx_fetch_next_dword();
    bx_cpu.edx = imm32;
    }
  else {
    imm16 = bx_fetch_next_word();
    DX = imm16;
    }
}

  void
bx_MOV_eBXIv()
{
  Bit32u imm32;
  Bit16u imm16;

  if (bx_32bit_opsize) {
    imm32 = bx_fetch_next_dword();
    EBX = imm32;
    }
  else {
    imm16 = bx_fetch_next_word();
    BX = imm16;
    }
}

  void
bx_MOV_eSPIv()
{
  Bit32u imm32;
  Bit16u imm16;

  if (bx_32bit_opsize) {
    imm32 = bx_fetch_next_dword();
    ESP = imm32;
    }
  else {
    imm16 = bx_fetch_next_word();
    SP = imm16;
    }
}

  void
bx_MOV_eBPIv()
{
  Bit32u imm32;
  Bit16u imm16;

  if (bx_32bit_opsize) {
    imm32 = bx_fetch_next_dword();
    bx_cpu.ebp = imm32;
    }
  else {
    imm16 = bx_fetch_next_word();
    BP = imm16;
    }
}

  void
bx_MOV_eSIIv()
{
  Bit32u imm32;
  Bit16u imm16;

  if (bx_32bit_opsize) {
    imm32 = bx_fetch_next_dword();
    ESI = imm32;
    }
  else {
    imm16 = bx_fetch_next_word();
    SI = imm16;
    }
}

  void
bx_MOV_eDIIv()
{
  Bit32u imm32;
  Bit16u imm16;

  if (bx_32bit_opsize) {
    imm32 = bx_fetch_next_dword();
    EDI = imm32;
    }
  else {
    imm16 = bx_fetch_next_word();
    DI = imm16;
    }
}



  void
bx_MOV_EbIb()
{
  Bit8u op2;
  Bit32u unused, op1_addr;
  int op1_type;
  bx_segment_reg_t *op1_seg_reg;



  /* op1 is mod+r/m, op2 is an 8bit immediate */
  bx_decode_exgx(&unused, &op1_addr, &op1_type, &op1_seg_reg);

  op2 = bx_fetch_next_byte();


  /* now write op2 back to destination */
  if (op1_type == BX_REGISTER_REF) {
    BX_WRITE_8BIT_REG(op1_addr, op2);
    }
  else
    bx_access_virtual(op1_seg_reg, op1_addr, 1, BX_WRITE, &op2);
}

  void
bx_MOV_EvIv()
{
  Bit32u unused, op1_addr;
  int op1_type;
  bx_segment_reg_t *op1_seg_reg;

  /* for 32 bit operand size mode */
  Bit32u op2_32;

  /* for 16 bit operand size mode */
  Bit16u op2_16;

  bx_decode_exgx(&unused, &op1_addr, &op1_type, &op1_seg_reg);

  if (bx_32bit_opsize) { /* 32 bit operand size mode */

    op2_32 = bx_fetch_next_dword();

    /* now write sum back to destination */
    if (op1_type == BX_REGISTER_REF) {
      BX_WRITE_32BIT_REG(op1_addr, op2_32);
      }
    else
      bx_access_virtual(op1_seg_reg, op1_addr, 4, BX_WRITE, &op2_32);
    }
  else { /* 16 bit operand size mode */

    op2_16 = bx_fetch_next_word();

    /* now write sum back to destination */
    if (op1_type == BX_REGISTER_REF) {
      BX_WRITE_16BIT_REG(op1_addr, op2_16);
      }
    else
      bx_access_virtual(op1_seg_reg, op1_addr, 2, BX_WRITE, &op2_16);
    }
}


void bx_MOVZX_GvEb() {bx_invalid_instruction();}
void bx_MOVZX_GvEw() {bx_invalid_instruction();}
void bx_MOVSX_GvEb() {bx_invalid_instruction();}
void bx_MOVSX_GvEw() {bx_invalid_instruction();}

  void
bx_XLAT()
{
  Bit8u al;
  Bit16u bx;
  Bit32u ebx, offset_32;

  if (bx_32bit_addrsize) {
    al = AL;
    ebx = EBX;
    offset_32 = ebx + al;
    }
  else {
    al = AL;
    bx = BX;
    offset_32 = bx + al;
    }

  if (bx_segment_override)
    bx_access_virtual(bx_segment_override, offset_32, 1, BX_READ, &al);
  else
    bx_access_virtual(&bx_cpu.ds, offset_32, 1, BX_READ, &al);

  bx_cpu.eax = (bx_cpu.eax & 0xFFFFFF00) | al;
}

  void
bx_XCHG_EbGb()
{
  Bit8u op2, op1;
  Bit32u op2_addr, op1_addr;
  int op1_type;
  bx_segment_reg_t *op1_seg_reg;


  bx_decode_exgx(&op2_addr, &op1_addr, &op1_type, &op1_seg_reg);

  /* op2 is a register, op2_addr is an index of a register */
  BX_READ_8BIT_REG(op2, op2_addr);

  /* op1 is a register or memory reference */
  if (op1_type == BX_REGISTER_REF) {
    BX_READ_8BIT_REG(op1, op1_addr);
    }
  else
    /* pointer, segment address pair */
    bx_access_virtual(op1_seg_reg, op1_addr, 1, BX_READ, &op1);


  /* now write values back to opposite locations */
  if (op1_type == BX_REGISTER_REF) {
    BX_WRITE_8BIT_REG(op1_addr, op2);
    }
  else
    bx_access_virtual(op1_seg_reg, op1_addr, 1, BX_WRITE, &op2);
  BX_WRITE_8BIT_REG(op2_addr, op1);
}

  void
bx_XCHG_EvGv()
{
  Bit32u op2_addr, op1_addr;
  int op1_type;
  bx_segment_reg_t *op1_seg_reg;

  /* for 32 bit operand size mode */

  Bit32u op2_32, op1_32;

  /* for 16 bit operand size mode */
  Bit16u op2_16, op1_16;






  bx_decode_exgx(&op2_addr, &op1_addr, &op1_type, &op1_seg_reg);

  if (bx_32bit_opsize) { /* 32 bit operand size mode */

    /* op2_32 is a register, op2_addr is an index of a register */
    BX_READ_32BIT_REG(op2_32, op2_addr);

    /* op1_32 is a register or memory reference */
    if (op1_type == BX_REGISTER_REF) {
      BX_READ_32BIT_REG(op1_32, op1_addr);
      }
    else
      /* pointer, segment address pair */
      bx_access_virtual(op1_seg_reg, op1_addr, 4, BX_READ, &op1_32);

    /* now write operands back to opposite locations */
    if (op1_type == BX_REGISTER_REF) {
      BX_WRITE_32BIT_REG(op1_addr, op2_32);
      }
    else
      bx_access_virtual(op1_seg_reg, op1_addr, 4, BX_WRITE, &op2_32);
    BX_WRITE_32BIT_REG(op2_addr, op1_32);
    }
  else { /* 16 bit operand size mode */

    /* op2_16 is a register, op2_addr is an index of a register */
    BX_READ_16BIT_REG(op2_16, op2_addr);

    /* op1_16 is a register or memory reference */
    if (op1_type == BX_REGISTER_REF) {
      BX_READ_16BIT_REG(op1_16, op1_addr);
      }
    else
      /* pointer, segment address pair */
      bx_access_virtual(op1_seg_reg, op1_addr, 2, BX_READ, &op1_16);

    /* now write sum back to destination */
    if (op1_type == BX_REGISTER_REF) {
      BX_WRITE_16BIT_REG(op1_addr, op2_16);
      }
    else
      bx_access_virtual(op1_seg_reg, op1_addr, 2, BX_WRITE, &op2_16);
    BX_WRITE_16BIT_REG(op2_addr, op1_16);
    }
}
