/***************************************************************************
 * 
 * All modifications in this file to the original code are
 * (C) Copyright 1992, ..., 2004 the "DOSEMU-Development-Team".
 *
 * for details see file COPYING in the DOSEMU distribution
 *
 *
 *  SIMX86 a Intel 80x86 cpu emulator
 *  Copyright (C) 1997,2001 Alberto Vignani, FIAT Research Center
 *				a.vignani@crf.it
 *
 *  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 2 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, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Additional copyright notes:
 *
 * 1. The kernel-level vm86 handling was taken out of the Linux kernel
 *  (linux/arch/i386/kernel/vm86.c). This code originaly was written by
 *  Linus Torvalds with later enhancements by Lutz Molgedey and Hans Lermen.
 *
 ***************************************************************************/

#ifndef _EMU86_CODEGEN_H
#define _EMU86_CODEGEN_H

#include "syncpu.h"
#include "trees.h"
#include "dpmi.h"

/////////////////////////////////////////////////////////////////////////////

#define L_NOP		0

#define LEA_DI_R	1
#define A_DI_0		2
#define A_DI_1		3
#define A_DI_2		4
#define A_DI_2D		5
#define A_SR_SH4	6
#define O_FOP		7

#define L_REG		10
#define S_REG		11
#define L_REG2REG	12
#define L_IMM		13
#define L_IMM_R1	14
#define S_DI_IMM	15
#define S_DI_R		16
#define L_MOVZS		17
#define L_LXS1		18
#define L_LXS2		19
#define L_ZXAX		20
#define L_CR0		21
#define L_DI_R1		22
#define L_VGAREAD	22
#define S_DI		23
#define L_VGAWRITE	23

#define O_ADD_R		30
#define O_OR_R		31
#define O_ADC_R		32
#define O_SBB_R		33
#define O_AND_R		34
#define O_SUB_R		35
#define O_XOR_R		36
#define O_CMP_R		37
#define O_INC_R		38
#define O_DEC_R		39
#define O_SBB_M		40
#define O_SUB_M		41
#define O_CMP_M		42
#define O_CBWD		43
#define O_XCHG		44
#define O_XCHG_R	45
#define O_INC		46
#define O_DEC		47
#define O_NOT		48
#define O_NEG		49
#define O_MUL		50
#define O_IMUL		51
#define O_DIV		52
#define O_IDIV		53
#define O_ROL		54
#define O_ROR		55
#define O_RCL		56
#define O_RCR		57
#define O_SHL		58
#define O_SHR		59
#define O_SAR		60
#define O_OPAX		61
#define O_XLAT		62
#define O_CJMP		63	// unused
#define O_SLAHF		64
#define O_SETFL		65
#define O_BSWAP		66
#define O_SETCC		67
#define O_BITOP		68
#define O_SHFD		69
#define O_CLEAR		70	// xor r,r
#define O_TEST		71	// and r,r; or r,r
#define O_SBSELF	72	// sbb r,r

#define O_PUSH		80
#define O_PUSHI		81
#define O_POP		82
#define O_PUSHA		83
#define O_POPA		84
#define O_PUSH1		85
#define O_PUSH2		86
#define O_PUSH2F	87
#define O_PUSH3		88
#define O_POP1		89
#define O_POP2		90
#define O_POP3		91
#define O_LEAVE		92

#define O_MOVS_SetA	100
#define O_MOVS_MovD	101
#define O_MOVS_SavA	102
#define O_MOVS_LodD	103
#define O_MOVS_StoD	104
#define O_MOVS_ScaD	105
#define O_MOVS_CmpD	106
#define O_RDTSC		107

#define O_INPDX		108
#define O_INPPC		109
#define O_OUTPDX	110
#define O_OUTPPC	111

#define JMP_LINK	112
#define JB_LINK		113
#define JF_LINK		114
#define JLOOP_LINK	115

/////////////////////////////////////////////////////////////////////////////
//
#define ADDR16	0x00000001
#define ADDR32	0x00000000
#define BitADDR16	0
#define DATA16	0x00000002
#define DATA32	0x00000000
#define BitDATA16	1
#define MBYTE	0x00000004
#define IMMED	0x00000008
#define RM_REG	0x00000010
#define RSHIFT	0x00000020
#define SEGREG	0x00000040
#define MLEA	0x00000080
#define MREP	0x00000100
#define MREPNE	0x00000200
#define MEMADR	0x00000400
#define NOFLDR	0x00000800
#define XECFND	0x00001000
#define MBYTX	0x00002000
#define MOVSSRC	0x00004000
#define MOVSDST	0x00008000

#define CKSIGN	0x00100000	// check signal: for jumps
#define SKIPOP	0x00200000
// for HOST_ARCH_SIM
#define CLROVF	0x00200000
#define SETOVF	0x00400000
#define IGNOVF	0x00800000

// as seqflg takes mode>>16, these must go together in pairs
// (bits 0-3 are accumulated in the sequence head node):
#define M_FPOP	0x00010000
#define F_FPOP	0x0001
#define M_HITC	0x00020000
#define F_HITC	0x0002
#define M_SLFL	0x00040000
#define F_SLFL	0x0004

/////////////////////////////////////////////////////////////////////////////

/* x386 */
#define GetSWord(w)	*((unsigned short *)(w))=*((unsigned short *)(LONG_SS+sp))
#define GetSLong(l)	*((unsigned long *)(l))=*((unsigned long *)(LONG_SS+sp))
#define PutSWord(w)	*((unsigned short *)(LONG_SS+sp))=*((unsigned short *)(w))
#define PutSLong(l)	*((unsigned long *)(LONG_SS+sp))=*((unsigned long *)(l))

static __inline__ void POP(int m, void *w)
{
	unsigned long sp = TheCPU.esp & TheCPU.StackMask;
	if (m&DATA16) {
		GetSWord(w); sp+=2;
	}
	else {
		GetSLong(w); sp+=4;
	}
	TheCPU.esp = (sp&TheCPU.StackMask) | (TheCPU.esp&~TheCPU.StackMask);
}

static __inline__ void TOS_WORD(int m, void *w)		// for segments
{
	unsigned long sp = TheCPU.esp & TheCPU.StackMask;
	GetSWord(w);
}

static __inline__ void NOS_WORD(int m, void *w)		// for segments
{
	unsigned long sp = (TheCPU.esp+(m&DATA16? 2:4)) & TheCPU.StackMask;
	GetSWord(w);
}

static __inline__ void POP_ONLY(int m)
{
	unsigned long sp = TheCPU.esp + (m&DATA16? 2:4);
	TheCPU.esp = (sp&TheCPU.StackMask) | (TheCPU.esp&~TheCPU.StackMask);
}


/////////////////////////////////////////////////////////////////////////////

/* Code generation macros for x86 */
#define	G1(b,p)		*(p)++=(unsigned char)(b)
#define	G2(w,p)		{*((unsigned short *)(p))=(w);(p)+=2;}
#define	G2M(c,b,p)	{*((unsigned short *)(p))=((b)<<8)|(c);(p)+=2;}
#define	G3(l,p)		{*((unsigned long *)(p))=(l);(p)+=3;}
#define	G3M(c,b1,b2,p)	{*((unsigned long *)(p))=((b2)<<16)|((b1)<<8)|(c);(p)+=3;}
#define	G4(l,p)		{*((unsigned long *)(p))=(l);(p)+=4;}
#define	G4M(c,b1,b2,b3,p) {*((unsigned long *)(p))=((b3)<<24)|((b2)<<16)|((b1)<<8)|(c);\
				(p)+=4;}
#define	G5(l1,b2,p)	{*((unsigned long *)(p))=(l1),(p)[4]=(unsigned char)(b2);\
				(p)+=5;}
#define	G6(l1,w2,p)	{*((unsigned long *)(p))=(l1),\
			 *((unsigned short *)((p)+4))=(w2);(p)+=6;}
#define	G7(l1,l2,p)	{*((unsigned long *)(p))=(l1),\
			 *((unsigned long *)((p)+4))=(l2);(p)+=7;}
#define	G8(l1,l2,p)	{*((unsigned long *)(p))=(l1),\
			 *((unsigned long *)((p)+4))=(l2);(p)+=8;}
#define GNX(d,s,l)	{__memcpy((d),(s),(l));(d)+=(l);}

/////////////////////////////////////////////////////////////////////////////
//
void InitGen(void);
int  NewIMeta(unsigned char *newa, int mode, int *rc);
void Gen(int op, int mode, ...);
void AddrGen(int op, int mode, ...);
int  Fp87_op(int exop, int reg);
void NodeUnlinker(TNode *G);
unsigned char *CloseAndExec(unsigned char *PC, TNode *G, int mode, int ln);
void EndGen(void);
//
extern char InterOps[];
extern int  GendBytesPerOp[];
extern char RmIsReg[];
extern char OpIsPush[];

int Cpatch(unsigned char *eip);
int UnCpatch(unsigned char *eip);

#endif
