/*
 * opcodes.h  -  opcodes for the 8086 processor
 *
 * Copyright (C) 1997-2007 Gero Kuhlmann   <gero@gkminix.han.de>
 *
 *  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
 *  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.
 *
 * $Id: opcodes.h,v 1.10 2007/01/06 18:31:28 gkminix Exp $
 */


/*
 * Definition of opcodes for 8086 processor
 */
#define OP_JMP_SHORT	0xeb		/* short jump - one byte displacement */
#define OP_JMP_NEAR	0xe9		/* near jump - two byte displacement */
#define OP_JMP_COND8	0x70		/* base of conditional jump (8-bit) */
#define OP_JMP_COND16	0x80		/* base of conditional jump (16-bit) */
#define OP_386		0x0f		/* special operations on i386 */
#define OP_SET_COND	0x90		/* base of bit set operation */
#define OP_CALL		0xe8		/* near call - two byte displacement */
#define OP_RET		0xc3		/* return near */
#define OP_RETNUM	0xc2		/* return near with pop */
#define OP_IMMED	0x80		/* base for immediate arithmetic */
#define OP_NONIM	0xf6		/* base for non-immediate arithmetic */
#define OP_REP		0xf2		/* repeat prefix */
#define OP_REPNE	0xf2		/* repeat while not equal */
#define OP_REPE		0xf3		/* repeat while equal */
#define OP_MOVSB	0xa4		/* move string bytewise */
#define OP_SCASB	0xae		/* scan string bytewise */
#define OP_STOSB	0xaa		/* store string bytewise */
#define OP_LODSB	0xac		/* load a string bytewise */
#define OP_CMPSB	0xa6		/* compare two strings bytewise */
#define OP_MOV_AX	0xa0		/* move AX in/out of immediate memory */
#define OP_MOV_BREGIM	0xb0		/* move immediate value into byte reg */
#define OP_MOV_WREGIM	0xb8		/* move immediate value into word reg */
#define OP_MOV_MEMIM	0xc6		/* move immediate value into mem */
#define OP_MOVZX	0xb6		/* move value with zero-extend */
#define OP_MOVSX	0xbe		/* move value with sign-extend */
#define OP_PUSH_REG	0x50		/* push normal register */
#define OP_PUSH_MEM	0xff		/* push memory */
#define OP_PUSH_IMM	0x68		/* push immediate value */
#define OP_POP_REG	0x58		/* pop normal register */
#define OP_POP_MEM	0x8f		/* pop memory */
#define OP_ADC		0x10		/* add with carry */
#define OP_ADD		0x00		/* add */
#define OP_AND		0x20		/* AND */
#define OP_CMP		0x38		/* compare */
#define OP_MOV		0x88		/* move */
#define OP_OR		0x08		/* OR */
#define OP_SBB		0x18		/* subtract with borrow */
#define OP_SUB		0x28		/* subtract */
#define OP_XOR		0x30		/* XOR */
#define OP_XCHG		0x86		/* exchange */
#define OP_LEA		0x8d		/* load effective address */
#define OP_INC_REG16	0x40		/* increment 16 bit register */
#define OP_DEC_REG16	0x48		/* decrement 16 bit register */
#define OP_INC_MEM	0xfe		/* increment 8 bit reg / mem */
#define OP_DEC_MEM	0xfe		/* decrement 8 bit reg / mem */
#define OP_SHIFT_1	0xd0		/* shift by one bit */
#define OP_SHIFT_CL	0xd2		/* shift by CL bits */
#define OP_SHIFT_NUM	0xc0		/* shift by immediate number of bits */
#define OP_IMUL_IMM8	0x6b		/* 8-bit immediate multiplication */
#define OP_IMUL_IMM16	0x69		/* 16-bit immediate multiplication */
#define OP_JCXZ		0xe3		/* jump if CX zero */
#define OP_LOOP		0xe2		/* decrement CX and jump if not zero */
#define OP_CBW		0x98		/* convert byte to word */
#define OP_CWD		0x99		/* convert word to double-word */
#define OP_BOUND	0x62		/* check array bounds */
#define OP_INT		0xcd		/* call an interrupt */
#define OP_INTO		0xce		/* call int 4 if overflow */
#define OP_ENTER	0xc8		/* enter a procedure */
#define OP_LEAVE	0xc9		/* leave a procedure */
#define OP_NOP		0x90		/* no operation */
#define OP_CLD		0xfc		/* clear direction flag */



/*
 * Arithmetic instructions with immediate values have a base opcode, and
 * the type of instruction is encoded in the reg field of the mod-r/m byte.
 * The same is true for some non-immediate opcodes, and shift/rotate in-
 * structions.
 */
#define OP_IMMED_MASK	0x38		/* mask for opcode */
#define OP_IMMED_ADC	0x10		/* immediate addition with carry */
#define OP_IMMED_ADD	0x00		/* immediate addition */
#define OP_IMMED_AND	0x20		/* immediate AND */
#define OP_IMMED_CMP	0x38		/* immediate comparison */
#define OP_IMMED_OR	0x08		/* immediate OR */
#define OP_IMMED_SBB	0x18		/* immediate subtract with borrow */
#define OP_IMMED_SUB	0x28		/* immediate subtraction */
#define OP_IMMED_XOR	0x30		/* immediate XOR */

#define OP_NONIM_MASK	0x38		/* mask for opcode */
#define OP_NONIM_DIV	0x30		/* unsigned division */
#define OP_NONIM_IDIV	0x38		/* signed division */
#define OP_NONIM_IMUL	0x28		/* signed multiplication */
#define OP_NONIM_MUL	0x20		/* unsigned multiplication */
#define OP_NONIM_NEG	0x18		/* two's complement negation */
#define OP_NONIM_NOT	0x10		/* one's complement negation */

#define OP_SHIFT_MASK	0x38		/* mask for opcode */
#define OP_SHIFT_ROL	0x00		/* rotate left */
#define OP_SHIFT_ROR	0x08		/* rotate right */
#define OP_SHIFT_RCL	0x10		/* rotate left through carry */
#define OP_SHIFT_RCR	0x18		/* rotate right through carry */
#define OP_SHIFT_SHL	0x20		/* shift left (for SHL and SAL) */
#define OP_SHIFT_SHR	0x28		/* shift right */
#define OP_SHIFT_SAR	0x38		/* shift arithmetic right */

#define OP_MEM_MASK	0x38		/* mask for opcode */
#define OP_MEM_PUSH	0x30		/* push memory location */
#define OP_MEM_CALL16	0x10		/* call near indirect */
#define OP_MEM_CALL32	0x18		/* call far indirect */
#define OP_MEM_DEC	0x08		/* decrement */
#define OP_MEM_INC	0x00		/* increment */
#define OP_MEM_JMP16	0x20		/* jmp near indirect */
#define OP_MEM_JMP32	0x28		/* jmp far indirect */



/*
 * Jump conditions. These reflect the lower 4 bits of the conditional jump
 * opcode except for the unconditional jump.
 */
#define JMP_UNCOND	0xff
#define JMP_JO		0x00		/* overflow */
#define JMP_JNO		0x01		/* not overflow */
#define JMP_JC		0x02		/* carry */
#define JMP_JNC		0x03		/* not carry */
#define JMP_JZ		0x04		/* zero */
#define JMP_JNZ		0x05		/* not zero */
#define JMP_JBE		0x06		/* below or equal */
#define JMP_JA		0x07		/* above */
#define JMP_JS		0x08		/* sign */
#define JMP_JNS		0x09		/* not sign */
#define JMP_JP		0x0a		/* parity */
#define JMP_JNP		0x0b		/* not parity */
#define JMP_JL		0x0c		/* lower */
#define JMP_JGE		0x0d		/* greater or equal */
#define JMP_JLE		0x0e		/* lower or equal */
#define JMP_JG		0x0f		/* greater */

#define JMP_MASK	0x0f		/* mask for jump condition */
#define JMP_OPPOSITE	0x01		/* bit to toggle for opposite jump */



/*
 * Register names. The values in the lower byte are the same as used
 * by the processor for the corresponding register. Sometimes the
 * register value is in the lower 3 bits of the mod-r/m field, and
 * sometimes it is in the middle 3 bits. The two macros rmlow and
 * rmmid adjust the register value accordingly.
 */
#define rmlow(a)	(((a) & REG_16BIT_MASK) >> 3)
#define rmmid(a)	((a) & REG_16BIT_MASK)

#define regcmp(a,b)	((a) == (b) || \
			 (a) == ((b) + REG_LOW_MASK + REG_8BIT_FLAG) || \
			 (a) == ((b) + REG_HIGH_MASK + REG_8BIT_FLAG))

#define is8bitofs(a)	((long)(a) >= -127 && (long)(a) <= 127)


#define REG_NONE	0xffff		/* no register specification */
#define REG_16BIT_MASK	0x0038		/* mask for 16 bit registers */
#define REG_8BIT_MASK	0x0018		/* mask for 8 bit registers */
#define REG_LOW_MASK	0x0000		/* mask for lower 8 bit register */
#define REG_HIGH_MASK	0x0020		/* mask for higher 8 bit register */
#define REG_8BIT_FLAG	0x0100		/* flag for 8 bit register */
#define REG_SEG_FLAG	0x0200		/* flag for segment register flag */
#define REG_SPEC_FLAG	0x0400		/* flag for special register flag */
#define REG_MODRM_FLAG	0x0800		/* flag for mod-r/m flag */
#define REG_RELOC_FLAG	0x1000		/* flag for reclocatable displacement */

#define REG_AX		0x0000
#define REG_AL		(REG_AX + REG_LOW_MASK + REG_8BIT_FLAG)
#define REG_AH		(REG_AX + REG_HIGH_MASK + REG_8BIT_FLAG)

#define REG_BX		0x0018
#define REG_BL		(REG_BX + REG_LOW_MASK + REG_8BIT_FLAG)
#define REG_BH		(REG_BX + REG_HIGH_MASK + REG_8BIT_FLAG)

#define REG_CX		0x0008
#define REG_CL		(REG_CX + REG_LOW_MASK + REG_8BIT_FLAG)
#define REG_CH		(REG_CX + REG_HIGH_MASK + REG_8BIT_FLAG)

#define REG_DX		0x0010
#define REG_DL		(REG_DX + REG_LOW_MASK + REG_8BIT_FLAG)
#define REG_DH		(REG_DX + REG_HIGH_MASK + REG_8BIT_FLAG)

#define REG_ES		(0x0000 + REG_SEG_FLAG)
#define REG_CS		(0x0008 + REG_SEG_FLAG)
#define REG_SS		(0x0010 + REG_SEG_FLAG)
#define REG_DS		(0x0018 + REG_SEG_FLAG)

#define REG_SP		(0x0020 + REG_SPEC_FLAG)
#define REG_BP		(0x0028 + REG_SPEC_FLAG)
#define REG_SI		(0x0030 + REG_SPEC_FLAG)
#define REG_DI		(0x0038 + REG_SPEC_FLAG)

#define REG_SI_16DISP	(REG_MODRM_FLAG + OP_MOD_16BIT + OP_RM_IND + OP_RM_SI)
#define REG_SI_8DISP	(REG_MODRM_FLAG + OP_MOD_8BIT + OP_RM_IND + OP_RM_SI)
#define REG_SI_0DISP	(REG_MODRM_FLAG + OP_MOD_DIRECT + OP_RM_IND + OP_RM_SI)
#define REG_DI_16DISP	(REG_MODRM_FLAG + OP_MOD_16BIT + OP_RM_IND + OP_RM_DI)
#define REG_DI_8DISP	(REG_MODRM_FLAG + OP_MOD_8BIT + OP_RM_IND + OP_RM_DI)
#define REG_DI_0DISP	(REG_MODRM_FLAG + OP_MOD_DIRECT + OP_RM_IND + OP_RM_DI)
#define REG_BX_16DISP	(REG_MODRM_FLAG + OP_MOD_16BIT + OP_RM_BX)
#define REG_BX_8DISP	(REG_MODRM_FLAG + OP_MOD_8BIT + OP_RM_BX)
#define REG_BX_0DISP	(REG_MODRM_FLAG + OP_MOD_DIRECT + OP_RM_BX)
#define REG_BP_16DISP	(REG_MODRM_FLAG + OP_MOD_16BIT + OP_RM_BP)
#define REG_BP_8DISP	(REG_MODRM_FLAG + OP_MOD_8BIT + OP_RM_BP)
#define REG_16DISP	(REG_MODRM_FLAG + OP_MOD_DIRECT + OP_RM_BP)



/*
 * Define various masks for constructing the mod-r/m byte and set
 * the direction and word size flags.
 */
#define OP_SIGN_MASK	0x02		/* Sign bit in opcode */
#define OP_DIR_MASK	0x02		/* Direction bit in opcode */
#define OP_WORD_MASK	0x01		/* Operand size bit in opcode */

#define OP_MOD_MASK	0xc0		/* mask for mod field */
#define OP_MOD_DIRECT	0x00		/* use direct displacement */
#define OP_MOD_8BIT	0x40		/* 8 bit displacement */
#define OP_MOD_16BIT	0x80		/* 16 bit displacement */
#define OP_MOD_REG	0xc0		/* register to register operation */

#define OP_RM_MASK	0x07		/* Mask for r/m field */
#define OP_RM_SI	0x00		/* Use SI register for effective addr */
#define OP_RM_DI	0x01		/* Use DI register for effective addr */
#define OP_RM_BXIND	0x00		/* Use BX+indexreg+disp */
#define OP_RM_BPIND	0x02		/* Use BP+indexref+disp */
#define OP_RM_IND	0x04		/* Use indexreg+disp */
#define OP_RM_BP	0x06		/* Use BP+disp or disp without reg */
#define OP_RM_BX	0x07		/* Use BX+disp */

