/*
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 "bx_bochs.h"



  void
bx_PUSH_ES()
{
  Bit16u es;

  es = bx_cpu.es.selector.value;
  bx_push_16(es);
}

  void
bx_PUSH_CS()
{
  Bit16u cs;

  cs = bx_cpu.cs.selector.value;
  bx_push_16(cs);
}

  void
bx_PUSH_SS()
{
  Bit16u ss;

  ss = bx_cpu.ss.selector.value;
  bx_push_16(ss);
}

  void
bx_PUSH_DS()
{
  Bit16u ds;

  ds = bx_cpu.ds.selector.value;
  bx_push_16(ds);
}

  void
bx_PUSH_FS()
{
  Bit16u fs;

  fs = bx_cpu.fs.selector.value;
  bx_push_16(fs);
}

  void
bx_PUSH_GS()
{
  Bit16u gs;

  gs = bx_cpu.gs.selector.value;
  bx_push_16(gs);
}

  void
bx_POP_ES()
{
  Bit16u es;

  bx_pop_16(&es);

  bx_load_seg_reg(&bx_cpu.es, es);
}

  void
bx_POP_SS()
{
  Bit16u ss;

  bx_pop_16(&ss);

  bx_load_seg_reg(&bx_cpu.ss, ss);
}

  void
bx_POP_DS()
{
  Bit16u ds;

  bx_pop_16(&ds);

  bx_load_seg_reg(&bx_cpu.ds, ds);
}

  void
bx_POP_FS()
{
  Bit16u fs;

  bx_pop_16(&fs);

  bx_load_seg_reg(&bx_cpu.fs, fs);
}

  void
bx_POP_GS()
{
  Bit16u gs;

  bx_pop_16(&gs);

  bx_load_seg_reg(&bx_cpu.gs, gs);
}

  void
bx_PUSH_eAX()
{
  Bit16u ax;
  Bit32u eax;

  if (bx_32bit_opsize) {
    eax = bx_cpu.eax;
    bx_push_32(eax);
    }
  else { /* 16 bit opsize */
    ax = AX;
    bx_push_16(ax);
    }
}

  void
bx_PUSH_eCX()
{
  Bit16u cx;
  Bit32u ecx;

  if (bx_32bit_opsize) {
    ecx = bx_cpu.ecx;
    bx_push_32(ecx);
    }
  else { /* 16 bit opsize */
    cx = CX;
    bx_push_16(cx);
    }
}

  void
bx_PUSH_eDX()
{
  Bit16u dx;
  Bit32u edx;

  if (bx_32bit_opsize) {
    edx = bx_cpu.edx;
    bx_push_32(edx);
    }
  else { /* 16 bit opsize */
    dx = DX;
    bx_push_16(dx);
    }
}

  void
bx_PUSH_eBX()
{
  Bit16u bx;
  Bit32u ebx;

  if (bx_32bit_opsize) {
    ebx = bx_cpu.ebx;
    bx_push_32(ebx);
    }
  else { /* 16 bit opsize */
    bx = BX;
    bx_push_16(bx);
    }
}

  void
bx_PUSH_eSP()
{
  Bit16u sp;
  Bit32u esp;

  if (bx_32bit_opsize) {
    esp = bx_cpu.esp;
    bx_push_32(esp);
    }
  else { /* 16 bit opsize */
    sp = SP;
    bx_push_16(sp);
    }
}

  void
bx_PUSH_eBP()
{
  Bit16u bp;
  Bit32u ebp;

  if (bx_32bit_opsize) {
    ebp = bx_cpu.ebp;
    bx_push_32(ebp);
    }
  else { /* 16 bit opsize */
    bp = BP;
    bx_push_16(bp);
    }
}

  void
bx_PUSH_eSI()
{
  Bit16u si;
  Bit32u esi;

  if (bx_32bit_opsize) {
    esi = bx_cpu.esi;
    bx_push_32(esi);
    }
  else { /* 16 bit opsize */
    si = SI;
    bx_push_16(si);
    }
}

  void
bx_PUSH_eDI()
{
  Bit16u di;
  Bit32u edi;

  if (bx_32bit_opsize) {
    edi = bx_cpu.edi;
    bx_push_32(edi);
    }
  else { /* 16 bit opsize */
    di = DI;
    bx_push_16(di);
    }
}


  void
bx_POP_eAX()
{
  Bit16u ax;
  Bit32u eax;

  if (bx_32bit_opsize) {
    bx_pop_32(&eax);
    bx_cpu.eax = eax;
    }
  else { /* 16 bit opsize */
    bx_pop_16(&ax);
    bx_cpu.eax = ax;
    }
}

  void
bx_POP_eCX()
{
  Bit16u cx;
  Bit32u ecx;

  if (bx_32bit_opsize) {
    bx_pop_32(&ecx);
    bx_cpu.ecx = ecx;
    }
  else { /* 16 bit opsize */
    bx_pop_16(&cx);
    bx_cpu.ecx = cx;
    }
}

  void
bx_POP_eDX()
{
  Bit16u dx;
  Bit32u edx;

  if (bx_32bit_opsize) {
    bx_pop_32(&edx);
    bx_cpu.edx = edx;
    }
  else { /* 16 bit opsize */
    bx_pop_16(&dx);
    bx_cpu.edx = dx;
    }
}

  void
bx_POP_eBX()
{
  Bit16u bx;
  Bit32u ebx;

  if (bx_32bit_opsize) {
    bx_pop_32(&ebx);
    bx_cpu.ebx = ebx;
    }
  else { /* 16 bit opsize */
    bx_pop_16(&bx);
    bx_cpu.ebx = bx;
    }
}

  void
bx_POP_eSP()
{
  Bit16u sp;
  Bit32u esp;

  if (bx_32bit_opsize) {
    bx_pop_32(&esp);
    bx_cpu.esp = esp;
    }
  else { /* 16 bit opsize */
    bx_pop_16(&sp);
    bx_cpu.esp = sp;
    }
}

  void
bx_POP_eBP()
{
  Bit16u bp;
  Bit32u ebp;

  if (bx_32bit_opsize) {
    bx_pop_32(&ebp);
    bx_cpu.ebp = ebp;
    }
  else { /* 16 bit opsize */
    bx_pop_16(&bp);
    bx_cpu.ebp = bp;
    }
}

  void
bx_POP_eSI()
{
  Bit16u si;
  Bit32u esi;

  if (bx_32bit_opsize) {
    bx_pop_32(&esi);
    bx_cpu.esi = esi;
    }
  else { /* 16 bit opsize */
    bx_pop_16(&si);
    bx_cpu.esi = si;
    }
}

  void
bx_POP_eDI()
{
  Bit16u di;
  Bit32u edi;

  if (bx_32bit_opsize) {
    bx_pop_32(&edi);
    bx_cpu.edi = edi;
    }
  else { /* 16 bit opsize */
    bx_pop_16(&di);
    bx_cpu.edi = di;
    }
}

void bx_PUSHAD() {bx_invalid_instruction();}
void bx_POPAD() {bx_invalid_instruction();}
void bx_PUSH_Iv() {bx_invalid_instruction();}
void bx_PUSH_Ib() {bx_invalid_instruction();}

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

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

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


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

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

    bx_pop_32(&val32);

    if (op1_type == BX_REGISTER_REF) {
      BX_WRITE_32BIT_REG(op1_addr, val32);
      }
    else
      bx_access_virtual(op1_seg_reg, op1_addr, 4, BX_WRITE, &val32);
    }
  else { /* 16 bit operand size mode */

    bx_pop_16(&val16);

    if (op1_type == BX_REGISTER_REF) {
      BX_WRITE_16BIT_REG(op1_addr, val16);
      }
    else
      bx_access_virtual(op1_seg_reg, op1_addr, 2, BX_WRITE, &val16);
    }
}

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

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

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


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

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

    /* 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);

    bx_push_32(op1_32);
    }
  else { /* 16 bit operand size mode */

    /* 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);

    bx_push_16(op1_16);
    }
}

  void
bx_push_16(Bit16u value16)
{
if (bx_cpu.esp < 2) bx_printf(1, "Error: stack problem!\n");
  bx_cpu.esp -= 2;
  bx_access_virtual(&bx_cpu.ss, bx_cpu.esp, 2, BX_WRITE, &value16);
}

  void
bx_push_32(Bit32u value32)
{
  bx_cpu.esp -= 4;
  bx_access_virtual(&bx_cpu.ss, bx_cpu.esp, 4, BX_WRITE, &value32);
}

  void
bx_pop_16(Bit16u *value16_ptr)
{
  bx_access_virtual(&bx_cpu.ss, bx_cpu.esp, 2, BX_READ, value16_ptr);
  bx_cpu.esp += 2;
}

  void
bx_pop_32(Bit32u *value32_ptr)
{
  bx_access_virtual(&bx_cpu.ss, bx_cpu.esp, 4, BX_READ, value32_ptr);
  bx_cpu.esp += 4;
}


  void
bx_PUSHF_Fv()
{
  Bit16u flags;
  Bit32u eflags;

  /* should be dependent on stack size ??? */

  if (bx_32bit_opsize) {
    eflags = (bx_cpu.eflags.cf) |
             (1 << 1) |
             (bx_cpu.eflags.pf << 2) |
             (bx_cpu.eflags.af << 4) |
             (bx_cpu.eflags.zf << 6) |
             (bx_cpu.eflags.sf << 7) |
             (bx_cpu.eflags.tf << 8) |
             (bx_cpu.eflags.if_ << 9) |
             (bx_cpu.eflags.df << 10) |
             (bx_cpu.eflags.of << 11) |
             (bx_cpu.eflags.iopl << 12) |
             (bx_cpu.eflags.nt << 14) |
             (bx_cpu.eflags.rf << 16) |
             (bx_cpu.eflags.vm << 17) |
             (bx_cpu.eflags.ac << 18);

    bx_push_32(eflags);
    }
  else { /* 16 bit opsize */
    flags = (bx_cpu.eflags.cf) |
             (1 << 1) |
             (bx_cpu.eflags.pf << 2) |
             (bx_cpu.eflags.af << 4) |
             (bx_cpu.eflags.zf << 6) |
             (bx_cpu.eflags.sf << 7) |
             (bx_cpu.eflags.tf << 8) |
             (bx_cpu.eflags.if_ << 9) |
             (bx_cpu.eflags.df << 10) |
             (bx_cpu.eflags.of << 11) |
             (bx_cpu.eflags.iopl << 12) |
             (bx_cpu.eflags.nt << 14);
    
    bx_push_16(flags);
    }
}

  void
bx_POPF_Fv()
{
  Bit16u flags;
  Bit32u eflags;

  if (bx_32bit_opsize) {
    bx_pop_32(&eflags);
    bx_write_eflags(eflags);
    }
  else { /* 16 bit opsize */
    bx_pop_16(&flags);
    bx_write_flags(flags);
    }
}

