/*
 * $Date: $
 * $Source: $
 * $Revision: $
 * $State: $
 *
 * $Log: $
 *
 * DANG_END_CHANGELOG
 */

#ifndef _VM86_CPU_H
#define _VM86_CPU_H

#include "config.h"
#include "extern.h"
#include "arch/types.h"

#undef BIOSSEG
#include <sys/vm86.h>

#undef BIOSSEG
#define BIOSSEG 0xf000

#ifdef CONFIG_VM86PLUS
#include "arch/vm86plus.h"
#endif

/*
 * DANG_BEGIN_REMARK
 * The `vm86_struct` is used to pass all the necessary status/registers to
 * DOSEMU when running in vm86 mode.
 * DANG_END_REMARK
 */ 
#ifdef USE_VM86PLUS
  EXTERN struct vm86plus_struct vm86s INIT ( {
    {0},0,0,0,{0},{0}, {VM86PLUS_MAGIC}
  } );
#else
  EXTERN struct vm86_struct vm86s;
#endif

#define _AL      (*(Bit8u *)&vm86s.regs.eax)
#define _BL      (*(Bit8u *)&vm86s.regs.ebx)
#define _CL      (*(Bit8u *)&vm86s.regs.ecx)
#define _DL      (*(Bit8u *)&vm86s.regs.edx)
#define _AH      (*(((Bit8u *)&vm86s.regs.eax)+1))
#define _BH      (*(((Bit8u *)&vm86s.regs.ebx)+1))
#define _CH      (*(((Bit8u *)&vm86s.regs.ecx)+1))
#define _DH      (*(((Bit8u *)&vm86s.regs.edx)+1))
#define _AX      (*(Bit16u *)&vm86s.regs.eax)
#define _BX      (*(Bit16u *)&vm86s.regs.ebx)
#define _CX      (*(Bit16u *)&vm86s.regs.ecx)
#define _DX      (*(Bit16u *)&vm86s.regs.edx)
#define _SI      (*(Bit16u *)&vm86s.regs.esi)
#define _DI      (*(Bit16u *)&vm86s.regs.edi)
#define _BP      (*(Bit16u *)&vm86s.regs.ebp)
#define _SP      (*(Bit16u *)&vm86s.regs.esp)
#define _IP      (*(Bit16u *)&vm86s.regs.eip)
#define _EAX     ((Bit32u)(vm86s.regs.eax))
#define _EBX     ((Bit32u)(vm86s.regs.ebx))
#define _ECX     ((Bit32u)(vm86s.regs.ecx))
#define _EDX     ((Bit32u)(vm86s.regs.edx))
#define _ESI     ((Bit32u)(vm86s.regs.esi))
#define _EDI     ((Bit32u)(vm86s.regs.edi))
#define _EBP     ((Bit32u)(vm86s.regs.ebp))
#define _ESP     ((Bit32u)(vm86s.regs.esp))
#define _EIP     ((Bit32u)(vm86s.regs.eip))
#define _CS      ((Bit16u)(vm86s.regs.cs))
#define _DS      ((Bit16u)(vm86s.regs.ds))
#define _SS      ((Bit16u)(vm86s.regs.ss))
#define _ES      ((Bit16u)(vm86s.regs.es))
#define _FS      ((Bit16u)(vm86s.regs.fs))
#define _GS      ((Bit16u)(vm86s.regs.gs))
#define _EFLAGS  ((Bit32u)(vm86s.regs.eflags))

#define __sti__  (WRITE_FLAGS(READ_FLAGS() | IF))
#define __cli__  (WRITE_FLAGS(READ_FLAGS() & ~IF))
#define __stc__  (WRITE_FLAGS(READ_FLAGS() | CF))
#define __clc__  (WRITE_FLAGS(READ_FLAGS() & ~CF))
#define __std__  (WRITE_FLAGS(READ_FLAGS() | DF))
#define __cld__  (WRITE_FLAGS(READ_FLAGS() & ~DF))
#define CARRY    __stc__
#define NOCARRY  __clc__

/*
 * Instructions to fake PUSH's, POP's, CALLF's, etc.
 */

extern void    _pusha(void);             /* (push a)ll 16-bit regs */
extern void    _pushad(void);            /* (push a)ll 32-bit regs */
extern void    _popa(void);              /* (pop a)ll  16-bit regs */
extern void    _popad(void);             /* (pop a)ll  32-bit regs */

extern void    _pushf(void);             /* push the 16-bit flags */
extern void    _pushfd(void);            /* push the 32-bit flags */
extern void    _pushb(Bit8u value);      /* push an 8-bit value */
extern Bit8u   _popb(void);              /* pop an 8-bit value */
extern void    _pushw(Bit16u value);     /* push a 16-bit value */
extern Bit16u  _popw(void);              /* pop a 16-bit value */
extern void    _pushd(Bit32u value);     /* push a 32-bit value */
extern Bit32u  _popd(void);              /* pop a 32-bit value */

#define _pushseg _pushw                  /* push a segment (always 16 bits) */
#define _popseg  _popw                   /* pop a segment (always 16 bits) */

extern void    _callf(Bit16u seg, Bit16u ofs);  /* call far */
extern void    _calli(Bit16u seg, Bit16u ofs);  /* call interrupt */
extern void    _iret(void);                     /* interrupt ret */
extern void    _retf(Bit16u popw_count);        /* far return w/pop */



#define _regs vm86s.regs

#define MACH_PORT_NULL    NULL
#define UNCHANGED         2

#define MASK8(x)	((x) & 0xff)
#define MASK16(x)	((x) & 0xffff)
#define HIGH(x)		MASK8((unsigned long)(x) >> 8)
#define LOW(x)		MASK8((unsigned long)(x))

#ifndef WORD
#define WORD(x)		MASK16((unsigned long)(x))
#endif

#define SETHIGH(x,y) 	(*(x) = (*(x) & ~0xff00) | ((MASK8(y))<<8))
#define SETLOW(x,y) 	(*(x) = (*(x) & ~0xff) | (MASK8(y)))
#define SETWORD(x,y)	(*(x) = (*(x) & ~0xffff) | (MASK16(y)))

#define Addr_8086(x,y)    (( ((x) & 0xffff) << 4) + ((y) & 0xffff))
#define Addr(s,x,y)       Addr_8086(((s)->x), ((s)->y))

/* all registers as a structure */
#define REGS  vm86s.regs

/* this is used like: REG(eax) = 0xFFFFFFF */
#define REG(reg) (REGS.##reg)
#define READ_SEG_REG(reg) (REGS.##reg)
#define WRITE_SEG_REG(reg, val) REGS.##reg = (val)

/* these are used like:  LO(ax) = 2 (sets al to 2) */
#define LO(reg)  (*(Bit8u *)&REG(e##reg))
#define HI(reg)  (*((Bit8u *)&REG(e##reg) + 1))

#define _LO(reg) (*(Bit8u *)&(scp->e##reg))
#define _HI(reg) (*((Bit8u *)&(scp->e##reg) + 1))

/* these are used like: LWORD(eax) = 65535 (sets ax to 65535) */
#define LWORD(reg)	(*((Bit16u *)&REG(reg)))
#define HWORD(reg)	(*((Bit16u *)&REG(reg) + 1))

#define _LWORD(reg)	(*((Bit16u *)&(scp->##reg)))
#define _HWORD(reg)	(*((Bit16u *)&(scp->##reg) + 1))

/* this is used like: SEG_ADR((char *), es, bx) */
#define SEG_ADR(type, seg, reg)  type((LWORD(seg) << 4) + LWORD(e##reg))

#define WRITE_FLAGS(val)    LWORD(eflags) = (val)
#define WRITE_FLAGSE(val)   REG(eflags) = (val)
#define READ_FLAGS()        LWORD(eflags)
#define READ_FLAGSE()       REG(eflags)

static __inline__ void set_revectored(int nr, struct revectored_struct * bitmap)
{
	__asm__ __volatile__("btsl %1,%0"
		: /* no output */
		:"m" (*bitmap),"r" (nr));
}

static __inline__ void reset_revectored(int nr, struct revectored_struct * bitmap)
{
	__asm__ __volatile__("btrl %1,%0"
		: /* no output */
		:"m" (*bitmap),"r" (nr));
}

/* flags */
#define CF  (1 <<  0)
#define PF  (1 <<  2)
#define AF  (1 <<  4)
#define ZF  (1 <<  6)
#define SF  (1 <<  7)
#define TF  TF_MASK	/* (1 <<  8) */
#define IF  IF_MASK	/* (1 <<  9) */
#define DF  (1 << 10)
#define OF  (1 << 11)
#define NT  NT_MASK	/* (1 << 14) */
#define RF  (1 << 16)
#define VM  VM_MASK	/* (1 << 17) */
#define AC  AC_MASK	/* (1 << 18) */
#define VIF VIF_MASK
#define VIP VIP_MASK
#define ID  ID_MASK

#ifndef IOPL_MASK
#define IOPL_MASK  (3 << 12)
#endif

#define vflags ((READ_FLAGS() & VIF)? WORD(READ_FLAGS()) | IF : WORD(READ_FLAGS()) & ~IF)


struct sigcontext_struct {
  unsigned short gs, __gsh;
  unsigned short fs, __fsh;
  unsigned short es, __esh;
  unsigned short ds, __dsh;
  unsigned long edi;
  unsigned long esi;
  unsigned long ebp;
  unsigned long esp;
  unsigned long ebx;
  unsigned long edx;
  unsigned long ecx;
  unsigned long eax;
  unsigned long trapno;
  unsigned long err;
  unsigned long eip;
  unsigned short cs, __csh;
  unsigned long eflags;
  unsigned long esp_at_signal;
  unsigned short ss, __ssh;
  unsigned long i387;
  unsigned long oldmask;
  unsigned long cr2;
};

#define _gs     (scp->gs)
#define _fs     (scp->fs)
#define _es     (scp->es)
#define _ds     (scp->ds)
#define _edi    (scp->edi)
#define _esi    (scp->esi)
#define _ebp    (scp->ebp)
#define _esp    (scp->esp)
#define _ebx    (scp->ebx)
#define _edx    (scp->edx)
#define _ecx    (scp->ecx)
#define _eax    (scp->eax)
#define _err	(scp->err)
#define _trapno (scp->trapno)
#define _eip    (scp->eip)
#define _cs     (scp->cs)
#define _eflags (scp->eflags)
#define _ss     (scp->ss)

typedef unsigned char ubyte_t;
typedef unsigned short uword_t;
typedef unsigned long udword_t;

#define READ_BYTE(addr)                 (*(ubyte_t *) (addr))
#define WRITE_BYTE(addr, val)           (*(ubyte_t *) (addr) = (val) )
#define READ_WORD(addr)                 (*(uword_t *) (addr))
#define WRITE_WORD(addr, val)           (*(uword_t *) (addr) = (val) )
#define READ_DWORD(addr)                (*(udword_t *) (addr))
#define WRITE_DWORD(addr, val)          (*(udword_t *) (addr) = (val) )

#define MEMCPY_2UNIX(unix_addr, dos_addr, n) \
	memcpy(unix_addr, dos_addr, n)

#define MEMCPY_2DOS(dos_addr, unix_addr, n) \
	memcpy(dos_addr, unix_addr, n)

#define MEMCPY_DOS2DOS(dos_addr, unix_addr, n) \
	memcpy(dos_addr, unix_addr, n)

#define MEMCMP_DOS_VS_UNIX(dos_addr, unix_addr, n) \
	memcmp(dos_addr, unix_addr, n)

#define MEMSET_DOS(dos_addr, val, n) \
	memset(dos_addr, val, n)

extern void dosemu_fault(int, struct sigcontext_struct);

extern void run_vm86(void);
extern void cpu_one_instr(void);

#endif /* _VM86_CPU_H */
