/*	$Id: cpu.h,v 1.37 2008/03/22 04:03:07 monaka Exp $	*/

/*
 * Copyright (c) 2002-2003 NONAKA Kimihiro
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
	Intel Architecture 32-bit Processor Interpreter Engine for Pentium

				Copyright by Yui/Studio Milmake 1999-2000
				Copyright by Norio HATTORI 2000,2001
				Copyright by NONAKA Kimihiro 2002-2004
*/

#ifndef IA32_CPU_CPU_H__
#define IA32_CPU_CPU_H__

#include "interface.h"
#ifdef GEKKO
#include "setjmp.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef union {
#if defined(BYTESEX_LITTLE)
	struct {
		UINT8	l;
		UINT8	h;
		UINT8	_hl;
		UINT8	_hh;
	} b;
	struct {
		UINT16	w;
		UINT16	_hw;
	} w;
#elif defined(BYTESEX_BIG)
	struct {
		UINT8	_hh;
		UINT8	_hl;
		UINT8	h;
		UINT8	l;
	} b;
	struct {
		UINT16	_hw;
		UINT16	w;
	} w;
#endif
	UINT32	d;
} REG32;

typedef struct {
	UINT8	b[10];
} REG80;

#ifdef __cplusplus
}
#endif

#include "segments.h"

#ifdef __cplusplus
extern "C" {
#endif

enum {
	CPU_EAX_INDEX = 0,
	CPU_ECX_INDEX = 1,
	CPU_EDX_INDEX = 2,
	CPU_EBX_INDEX = 3,
	CPU_ESP_INDEX = 4,
	CPU_EBP_INDEX = 5,
	CPU_ESI_INDEX = 6,
	CPU_EDI_INDEX = 7,
	CPU_REG_NUM
};

enum {
	CPU_ES_INDEX = 0,
	CPU_CS_INDEX = 1,
	CPU_SS_INDEX = 2,
	CPU_DS_INDEX = 3,
	CPU_SEGREG286_NUM = 4,
	CPU_FS_INDEX = 4,
	CPU_GS_INDEX = 5,
	CPU_SEGREG_NUM
};

enum {
	CPU_TEST_REG_NUM = 8
};

enum {
	CPU_DEBUG_REG_NUM = 8,
	CPU_DEBUG_REG_INDEX_NUM = 4
};

enum {
	MAX_PREFIX = 8
};

typedef struct {
	REG32		reg[CPU_REG_NUM];
	UINT16		sreg[CPU_SEGREG_NUM];

	REG32		eflags;
	REG32		eip;

	REG32		prev_eip;
	REG32		prev_esp;

	UINT32		tr[CPU_TEST_REG_NUM];
	UINT32		dr[CPU_DEBUG_REG_NUM];
} CPU_REGS;

typedef struct {
	UINT16		gdtr_limit;
	UINT16		pad0;
	UINT32		gdtr_base;
	UINT16		idtr_limit;
	UINT16		pad1;
	UINT32		idtr_base;

	UINT16		ldtr;
	UINT16		tr;

	UINT32		cr0;
	UINT32		cr1;
	UINT32		cr2;
	UINT32		cr3;
	UINT32		cr4;
	UINT32		mxcsr;
} CPU_SYSREGS;

typedef struct {
	descriptor_t	sreg[CPU_SEGREG_NUM];
	descriptor_t	ldtr;
	descriptor_t	tr;

	UINT32		adrsmask;
	UINT32		ovflag;

	UINT8		ss_32;
	UINT8		resetreq;
	UINT8		trap;

	UINT8		page_wp;

	UINT8		protected_mode;
	UINT8		paging;
	UINT8		vm86;
	UINT8		user_mode;

	UINT8		hlt;
	UINT8		bp;	/* break point bitmap */
	UINT8		bp_ev;	/* break point event */

	UINT8		backout_sp;	/* backout ESP, when exception */

	UINT32		pde_base;

	UINT32		ioaddr;		/* I/O bitmap linear address */
	UINT16		iolimit;	/* I/O bitmap count */

	UINT8		nerror;		/* double fault/ triple fault */
	UINT8		prev_exception;
} CPU_STAT;

typedef struct {
	UINT8		op_32;
	UINT8		as_32;
	UINT8		rep_used;
	UINT8		seg_used;
	UINT32		seg_base;
} CPU_INST;

/* FPU */
enum {
	FPU_REG_NUM = 8
};

typedef struct {
	UINT16		seg;
	UINT16		pad;
	UINT32		offset;
} FPU_PTR;

typedef struct {
	UINT16		control;
	UINT16		status;
	UINT16		op;

	FPU_PTR		inst;
	FPU_PTR		data;
} FPU_REGS;

typedef struct {
	UINT8		valid;	/* レジスタ有効 */
	UINT8		sign;	/* 符号 */
	UINT8		zero;	/* ゼロ */
	UINT8		inf;	/* ∞ */
	UINT8		nan;	/* NaN */
	UINT8		denorm;	/* 非正規化 */
	SINT16		exp;	/* 指数部 */
	UINT64		num;	/* 小数部 */
} FP_REG;

typedef struct {
	UINT8		top;	/* スタック位置 */
	UINT8		pc;	/* 精度 */
	UINT8		rc;	/* 丸め */
	UINT8		dmy[1];

	FP_REG		reg[FPU_REG_NUM];
} FPU_STAT;

typedef struct {
	CPU_REGS	cpu_regs;
	CPU_SYSREGS	cpu_sysregs;
	CPU_STAT	cpu_stat;
	CPU_INST	cpu_inst;
	CPU_INST	cpu_inst_default;

#if defined(USE_FPU)
	FPU_REGS	fpu_regs;
	FPU_STAT	fpu_stat;
#endif

	/* protected by cpu shut */
	UINT8		cpu_type;
	UINT8		itfbank;
	UINT16		ram_d0;
	SINT32		remainclock;
	SINT32		baseclock;
	UINT32		clock;
} I386STAT;

typedef struct {
	UINT8		*ext;
	UINT32		extsize;
	UINT8		*extbase;	/* = ext - 0x100000 */
	UINT32		extlimit16mb;	/* = extsize + 0x100000 (MAX:16MB) */
	UINT32		extlimit4gb;	/* = extsize + 0x100000 */
	UINT32		inport;
	UINT8		*ems[4];
} I386EXT;

typedef struct {
	I386STAT	s;				/* STATsaveされる奴 */
	I386EXT		e;
} I386CORE;

extern I386CORE		i386core;

#define	CPU_STATSAVE	i386core.s

#define	CPU_ADRSMASK	i386core.s.cpu_stat.adrsmask
#define	CPU_RESETREQ	i386core.s.cpu_stat.resetreq

#define	CPU_REMCLOCK	i386core.s.remainclock
#define	CPU_BASECLOCK	i386core.s.baseclock
#define	CPU_CLOCK	i386core.s.clock
#define	CPU_ITFBANK	i386core.s.itfbank
#define	CPU_RAM_D000	i386core.s.ram_d0

#define CPU_TYPE	i386core.s.cpu_type
#define CPUTYPE_V30	0x01

#define	CPU_EXTMEM	i386core.e.ext
#define	CPU_EXTMEMSIZE	i386core.e.extsize
#define	CPU_EXTMEMBASE	i386core.e.extbase
#define	CPU_EXTLIMIT16	i386core.e.extlimit16mb
#define	CPU_EXTLIMIT	i386core.e.extlimit4gb
#define	CPU_INPADRS	i386core.e.inport
#define	CPU_EMSPTR	i386core.e.ems

extern sigjmp_buf	exec_1step_jmpbuf;


/*
 * CPUID
 */
/* vendor */
#define	CPU_VENDOR_1	0x756e6547	/* "Genu" */
#define	CPU_VENDOR_2	0x49656e69	/* "ineI" */
#define	CPU_VENDOR_3	0x6c65746e	/* "ntel" */

/* version */
#define	CPU_FAMILY	4
#if defined(USE_FPU)
#define	CPU_MODEL	1	/* 486DX */
#else
#define	CPU_MODEL	2	/* 486SX */
#endif
#define	CPU_STEPPING	3

/* feature */
#define	CPU_FEATURE_FPU		(1 << 0)
#define	CPU_FEATURE_VME		(1 << 1)
#define	CPU_FEATURE_DE		(1 << 2)
#define	CPU_FEATURE_PSE		(1 << 3)
#define	CPU_FEATURE_TSC		(1 << 4)
#define	CPU_FEATURE_MSR		(1 << 5)
#define	CPU_FEATURE_PAE		(1 << 6)
#define	CPU_FEATURE_MCE		(1 << 7)
#define	CPU_FEATURE_CX8		(1 << 8)
#define	CPU_FEATURE_APIC	(1 << 9)
/*				(1 << 10) */
#define	CPU_FEATURE_SEP		(1 << 11)
#define	CPU_FEATURE_MTRR	(1 << 12)
#define	CPU_FEATURE_PGE		(1 << 13)
#define	CPU_FEATURE_MCA		(1 << 14)
#define	CPU_FEATURE_CMOV	(1 << 15)
#define	CPU_FEATURE_FGPAT	(1 << 16)
#define	CPU_FEATURE_PSE36	(1 << 17)
#define	CPU_FEATURE_PN		(1 << 18)
/*				(1 << 19) */
/*				(1 << 20) */
/*				(1 << 21) */
/*				(1 << 22) */
#define	CPU_FEATURE_MMX		(1 << 23)
#define	CPU_FEATURE_FXSR	(1 << 24)
#define	CPU_FEATURE_XMM		(1 << 25)
/*				(1 << 26) */
/*				(1 << 27) */
/*				(1 << 28) */
/*				(1 << 29) */
/*				(1 << 30) */
/*				(1 << 31) */
#if defined(USE_FPU)
#define	CPU_FEATURES		(CPU_FEATURE_CMOV|CPU_FEATURE_FPU)
#else
#define	CPU_FEATURES		(CPU_FEATURE_CMOV)
#endif


#define	CPU_REGS_BYTEL(n)	CPU_STATSAVE.cpu_regs.reg[(n)].b.l
#define	CPU_REGS_BYTEH(n)	CPU_STATSAVE.cpu_regs.reg[(n)].b.h
#define	CPU_REGS_WORD(n)	CPU_STATSAVE.cpu_regs.reg[(n)].w.w
#define	CPU_REGS_DWORD(n)	CPU_STATSAVE.cpu_regs.reg[(n)].d
#define	CPU_REGS_SREG(n)	CPU_STATSAVE.cpu_regs.sreg[(n)]

#define	CPU_STAT_SREG(n)	CPU_STATSAVE.cpu_stat.sreg[(n)]
#define	CPU_STAT_SREGBASE(n)	CPU_STAT_SREG((n)).u.seg.segbase
#define	CPU_STAT_SREGLIMIT(n)	CPU_STAT_SREG((n)).u.seg.limit


#define CPU_AL		CPU_REGS_BYTEL(CPU_EAX_INDEX)
#define CPU_CL		CPU_REGS_BYTEL(CPU_ECX_INDEX)
#define CPU_DL		CPU_REGS_BYTEL(CPU_EDX_INDEX)
#define CPU_BL		CPU_REGS_BYTEL(CPU_EBX_INDEX)
#define CPU_AH		CPU_REGS_BYTEH(CPU_EAX_INDEX)
#define CPU_CH		CPU_REGS_BYTEH(CPU_ECX_INDEX)
#define CPU_DH		CPU_REGS_BYTEH(CPU_EDX_INDEX)
#define CPU_BH		CPU_REGS_BYTEH(CPU_EBX_INDEX)

#define	CPU_AX		CPU_REGS_WORD(CPU_EAX_INDEX)
#define	CPU_CX		CPU_REGS_WORD(CPU_ECX_INDEX)
#define	CPU_DX		CPU_REGS_WORD(CPU_EDX_INDEX)
#define	CPU_BX		CPU_REGS_WORD(CPU_EBX_INDEX)
#define	CPU_SP		CPU_REGS_WORD(CPU_ESP_INDEX)
#define	CPU_BP		CPU_REGS_WORD(CPU_EBP_INDEX)
#define	CPU_SI		CPU_REGS_WORD(CPU_ESI_INDEX)
#define	CPU_DI		CPU_REGS_WORD(CPU_EDI_INDEX)
#define CPU_IP		CPU_STATSAVE.cpu_regs.eip.w.w

#define	CPU_EAX		CPU_REGS_DWORD(CPU_EAX_INDEX)
#define	CPU_ECX		CPU_REGS_DWORD(CPU_ECX_INDEX)
#define	CPU_EDX		CPU_REGS_DWORD(CPU_EDX_INDEX)
#define	CPU_EBX		CPU_REGS_DWORD(CPU_EBX_INDEX)
#define	CPU_ESP		CPU_REGS_DWORD(CPU_ESP_INDEX)
#define	CPU_EBP		CPU_REGS_DWORD(CPU_EBP_INDEX)
#define	CPU_ESI		CPU_REGS_DWORD(CPU_ESI_INDEX)
#define	CPU_EDI		CPU_REGS_DWORD(CPU_EDI_INDEX)
#define CPU_EIP		CPU_STATSAVE.cpu_regs.eip.d
#define CPU_PREV_EIP	CPU_STATSAVE.cpu_regs.prev_eip.d
#define CPU_PREV_ESP	CPU_STATSAVE.cpu_regs.prev_esp.d

#define	CPU_ES		CPU_REGS_SREG(CPU_ES_INDEX)
#define	CPU_CS		CPU_REGS_SREG(CPU_CS_INDEX)
#define	CPU_SS		CPU_REGS_SREG(CPU_SS_INDEX)
#define	CPU_DS		CPU_REGS_SREG(CPU_DS_INDEX)
#define	CPU_FS		CPU_REGS_SREG(CPU_FS_INDEX)
#define	CPU_GS		CPU_REGS_SREG(CPU_GS_INDEX)

#define	CPU_ES_DESC	CPU_STAT_SREG(CPU_ES_INDEX)
#define	CPU_CS_DESC	CPU_STAT_SREG(CPU_CS_INDEX)
#define	CPU_SS_DESC	CPU_STAT_SREG(CPU_SS_INDEX)
#define	CPU_DS_DESC	CPU_STAT_SREG(CPU_DS_INDEX)
#define	CPU_FS_DESC	CPU_STAT_SREG(CPU_FS_INDEX)
#define	CPU_GS_DESC	CPU_STAT_SREG(CPU_GS_INDEX)

#define ES_BASE		CPU_STAT_SREGBASE(CPU_ES_INDEX)
#define CS_BASE		CPU_STAT_SREGBASE(CPU_CS_INDEX)
#define SS_BASE		CPU_STAT_SREGBASE(CPU_SS_INDEX)
#define DS_BASE		CPU_STAT_SREGBASE(CPU_DS_INDEX)
#define FS_BASE		CPU_STAT_SREGBASE(CPU_FS_INDEX)
#define GS_BASE		CPU_STAT_SREGBASE(CPU_GS_INDEX)

#define CPU_EFLAG	CPU_STATSAVE.cpu_regs.eflags.d
#define CPU_FLAG	CPU_STATSAVE.cpu_regs.eflags.w.w
#define CPU_FLAGL	CPU_STATSAVE.cpu_regs.eflags.b.l
#define CPU_FLAGH	CPU_STATSAVE.cpu_regs.eflags.b.h
#define CPU_TRAP	CPU_STATSAVE.cpu_stat.trap
#define CPU_INPORT	CPU_STATSAVE.cpu_stat.inport
#define CPU_OV		CPU_STATSAVE.cpu_stat.ovflag

#define C_FLAG		(1 << 0)
#define P_FLAG		(1 << 2)
#define A_FLAG		(1 << 4)
#define Z_FLAG		(1 << 6)
#define S_FLAG		(1 << 7)
#define T_FLAG		(1 << 8)
#define I_FLAG		(1 << 9)
#define D_FLAG		(1 << 10)
#define O_FLAG		(1 << 11)
#define IOPL_FLAG	(3 << 12)
#define NT_FLAG		(1 << 14)
#define RF_FLAG		(1 << 16)
#define VM_FLAG		(1 << 17)
#define AC_FLAG		(1 << 18)
#define VIF_FLAG	(1 << 19)
#define VIP_FLAG	(1 << 20)
#define ID_FLAG		(1 << 21)
#define	SZP_FLAG	(P_FLAG|Z_FLAG|S_FLAG)
#define	SZAP_FLAG	(P_FLAG|A_FLAG|Z_FLAG|S_FLAG)
#define	SZPC_FLAG	(C_FLAG|P_FLAG|Z_FLAG|S_FLAG)
#define	SZAPC_FLAG	(C_FLAG|P_FLAG|A_FLAG|Z_FLAG|S_FLAG)
#define	ALL_FLAG	(SZAPC_FLAG|T_FLAG|I_FLAG|D_FLAG|O_FLAG|IOPL_FLAG|NT_FLAG)
#define	ALL_EFLAG	(ALL_FLAG|RF_FLAG|VM_FLAG|AC_FLAG|VIF_FLAG|VIP_FLAG|ID_FLAG)

#define	REAL_FLAGREG	((CPU_FLAG & 0xf7ff) | (CPU_OV ? O_FLAG : 0) | 2)
#define	REAL_EFLAGREG	((CPU_EFLAG & 0xfffff7ff) | (CPU_OV ? O_FLAG : 0) | 2)

void FASTCALL set_flags(UINT16 new_flags, UINT16 mask);
void FASTCALL set_eflags(UINT32 new_flags, UINT32 mask);


#define	CPU_INST_OP32		CPU_STATSAVE.cpu_inst.op_32
#define	CPU_INST_AS32		CPU_STATSAVE.cpu_inst.as_32
#define	CPU_INST_REPUSE		CPU_STATSAVE.cpu_inst.rep_used
#define	CPU_INST_SEGUSE		CPU_STATSAVE.cpu_inst.seg_used
#define	CPU_INST_SEGREG_INDEX	CPU_STATSAVE.cpu_inst.seg_base
#define	DS_FIX	(!CPU_INST_SEGUSE ? CPU_DS_INDEX : CPU_INST_SEGREG_INDEX)
#define	SS_FIX	(!CPU_INST_SEGUSE ? CPU_SS_INDEX : CPU_INST_SEGREG_INDEX)

#define	CPU_STAT_CS_BASE	CPU_STAT_SREGBASE(CPU_CS_INDEX)
#define	CPU_STAT_CS_LIMIT	CPU_STAT_SREGLIMIT(CPU_CS_INDEX)

#define	CPU_STAT_ADRSMASK	CPU_STATSAVE.cpu_stat.adrsmask
#define	CPU_STAT_SS32		CPU_STATSAVE.cpu_stat.ss_32
#define	CPU_STAT_RESETREQ	CPU_STATSAVE.cpu_stat.resetreq
#define	CPU_STAT_PM		CPU_STATSAVE.cpu_stat.protected_mode
#define	CPU_STAT_PAGING		CPU_STATSAVE.cpu_stat.paging
#define	CPU_STAT_VM86		CPU_STATSAVE.cpu_stat.vm86
#define	CPU_STAT_WP		CPU_STATSAVE.cpu_stat.page_wp
#define	CPU_STAT_CPL		CPU_CS_DESC.rpl
#define	CPU_STAT_USER_MODE	CPU_STATSAVE.cpu_stat.user_mode
#define	CPU_STAT_PDE_BASE	CPU_STATSAVE.cpu_stat.pde_base
#define	CPU_SET_PREV_ESP1(esp) \
do { \
	CPU_STATSAVE.cpu_stat.backout_sp = 1; \
	CPU_PREV_ESP = (esp); \
} while (/*CONSTCOND*/0)
#define	CPU_SET_PREV_ESP()	CPU_SET_PREV_ESP1(CPU_ESP)
#define	CPU_CLEAR_PREV_ESP(esp) \
do { \
	CPU_STATSAVE.cpu_stat.backout_sp = 0; \
} while (/*CONSTCOND*/0)

#define	CPU_STAT_HLT		CPU_STATSAVE.cpu_stat.hlt

#define	CPU_STAT_IOPL		((CPU_EFLAG & IOPL_FLAG) >> 12)
#define	CPU_IOPL0		0
#define	CPU_IOPL1		1
#define	CPU_IOPL2		2
#define	CPU_IOPL3		3

#define	CPU_STAT_IOADDR		CPU_STATSAVE.cpu_stat.ioaddr
#define	CPU_STAT_IOLIMIT	CPU_STATSAVE.cpu_stat.iolimit

#define	CPU_STAT_PREV_EXCEPTION		CPU_STATSAVE.cpu_stat.prev_exception
#define	CPU_STAT_EXCEPTION_COUNTER		CPU_STATSAVE.cpu_stat.nerror
#define	CPU_STAT_EXCEPTION_COUNTER_INC()	CPU_STATSAVE.cpu_stat.nerror++
#define	CPU_STAT_EXCEPTION_COUNTER_CLEAR()	CPU_STATSAVE.cpu_stat.nerror = 0

#define	CPU_MODE_SUPERVISER	0
#define	CPU_MODE_USER		(1 << 3)

#define CPU_CLI \
do { \
	CPU_FLAG &= ~I_FLAG; \
	CPU_TRAP = 0; \
} while (/*CONSTCOND*/0)

#define CPU_STI \
do { \
	CPU_FLAG |= I_FLAG; \
	CPU_TRAP = (CPU_FLAG & (I_FLAG|T_FLAG)) == (I_FLAG|T_FLAG) ; \
} while (/*CONSTCOND*/0)

#define CPU_GDTR_LIMIT	CPU_STATSAVE.cpu_sysregs.gdtr_limit
#define CPU_GDTR_BASE	CPU_STATSAVE.cpu_sysregs.gdtr_base
#define CPU_IDTR_LIMIT	CPU_STATSAVE.cpu_sysregs.idtr_limit
#define CPU_IDTR_BASE	CPU_STATSAVE.cpu_sysregs.idtr_base
#define CPU_LDTR	CPU_STATSAVE.cpu_sysregs.ldtr
#define CPU_LDTR_DESC	CPU_STATSAVE.cpu_stat.ldtr
#define CPU_LDTR_BASE	CPU_LDTR_DESC.u.seg.segbase
#define CPU_LDTR_LIMIT	CPU_LDTR_DESC.u.seg.limit
#define CPU_TR		CPU_STATSAVE.cpu_sysregs.tr
#define CPU_TR_DESC	CPU_STATSAVE.cpu_stat.tr
#define CPU_TR_BASE	CPU_TR_DESC.u.seg.segbase
#define CPU_TR_LIMIT	CPU_TR_DESC.u.seg.limit

/*
 * control register
 */
#define CPU_MSW			CPU_STATSAVE.cpu_sysregs.cr0

#define CPU_CR0			CPU_STATSAVE.cpu_sysregs.cr0
#define CPU_CR1			CPU_STATSAVE.cpu_sysregs.cr1
#define CPU_CR2			CPU_STATSAVE.cpu_sysregs.cr2
#define CPU_CR3			CPU_STATSAVE.cpu_sysregs.cr3
#define CPU_CR4			CPU_STATSAVE.cpu_sysregs.cr4
#define CPU_MXCSR		CPU_STATSAVE.cpu_sysregs.mxcsr

#define	CPU_CR0_PE		(1 << 0)
#define	CPU_CR0_MP		(1 << 1)
#define	CPU_CR0_EM		(1 << 2)
#define	CPU_CR0_TS		(1 << 3)
#define	CPU_CR0_ET		(1 << 4)
#define	CPU_CR0_NE		(1 << 5)
#define	CPU_CR0_WP		(1 << 16)
#define	CPU_CR0_AM		(1 << 18)
#define	CPU_CR0_NW		(1 << 29)
#define	CPU_CR0_CD		(1 << 30)
#define	CPU_CR0_PG		(1 << 31)
#define	CPU_CR0_ALL		(CPU_CR0_PE|CPU_CR0_MP|CPU_CR0_EM|CPU_CR0_TS|CPU_CR0_ET|CPU_CR0_NE|CPU_CR0_WP|CPU_CR0_AM|CPU_CR0_NW|CPU_CR0_CD|CPU_CR0_PG)

#define	CPU_CR3_PD_MASK		0xfffff000
#define	CPU_CR3_PWT		(1 << 3)
#define	CPU_CR3_PCD		(1 << 4)
#define	CPU_CR3_MASK		(CPU_CR3_PD_MASK|CPU_CR3_PWT|CPU_CR3_PCD)

#define	CPU_CR4_VME		(1 << 0)
#define	CPU_CR4_PVI		(1 << 1)
#define	CPU_CR4_TSD		(1 << 2)
#define	CPU_CR4_DE		(1 << 3)
#define	CPU_CR4_PSE		(1 << 4)
#define	CPU_CR4_PAE		(1 << 5)
#define	CPU_CR4_MCE		(1 << 6)
#define	CPU_CR4_PGE		(1 << 7)
#define	CPU_CR4_PCE		(1 << 8)
#define	CPU_CR4_OSFXSR		(1 << 9)
#define	CPU_CR4_OSXMMEXCPT	(1 << 10)

/*
 * debug register
 */
#define	CPU_DR(r)		CPU_STATSAVE.cpu_regs.dr[(r)]
#define	CPU_DR6			CPU_DR(6)
#define	CPU_DR7			CPU_DR(7)

#define	CPU_STAT_BP		CPU_STATSAVE.cpu_stat.bp
#define	CPU_STAT_BP_EVENT	CPU_STATSAVE.cpu_stat.bp_ev
#define	CPU_STAT_BP_EVENT_B(r)	(1 << (r))
#define	CPU_STAT_BP_EVENT_DR	(1 << 4)	/* fault */
#define	CPU_STAT_BP_EVENT_STEP	(1 << 5)	/* as CPU_TRAP */
#define	CPU_STAT_BP_EVENT_TASK	(1 << 6)
#define	CPU_STAT_BP_EVENT_RF	(1 << 7)	/* RF_FLAG */

#define	CPU_DR6_B(r)		(1 << (r))
#define	CPU_DR6_BD		(1 << 13)
#define	CPU_DR6_BS		(1 << 14)
#define	CPU_DR6_BT		(1 << 15)

#define	CPU_DR7_L(r)		(1 << ((r) * 2))
#define	CPU_DR7_G(r)		(1 << ((r) * 2 + 1))
#define	CPU_DR7_LE		(1 << 8)
#define	CPU_DR7_GE		(1 << 9)
#define	CPU_DR7_GD		(1 << 13)
#define	CPU_DR7_RW(r)		(3 << ((r) * 4 + 16))
#define	CPU_DR7_LEN(r)		(3 << ((r) * 4 + 16 + 2))

#define	CPU_DR7_GET_RW(r)	((CPU_DR7) >> (16 + (r) * 4))
#define	CPU_DR7_RW_CODE		0
#define	CPU_DR7_RW_RO		1
#define	CPU_DR7_RW_IO		2
#define	CPU_DR7_RW_RW		3

#define	CPU_DR7_GET_LEN(r)	((CPU_DR7) >> (16 + 2 + (r) * 4))

void ia32_init(void);
void ia32_initreg(void);
void ia32_setextsize(UINT32 size);
void ia32_setemm(UINT frame, UINT32 addr);

void ia32reset(void);
void ia32shut(void);
void ia32a20enable(BOOL enable);
void ia32(void);
void ia32_step(void);
void CPUCALL ia32_interrupt(int vect, int soft);
void CPUCALL ia32_exception(int vect, int p1, int p2);

void exec_1step(void);
#define	INST_PREFIX	(1 << 0)
#define	INST_STRING	(1 << 1)
#define	REP_CHECKZF	(1 << 7)

void ia32_printf(const char *buf, ...);
void ia32_warning(const char *buf, ...);
void ia32_panic(const char *buf, ...);

void ia32_bioscall(void);

void FASTCALL change_pm(BOOL onoff);
void FASTCALL change_vm(BOOL onoff);
void FASTCALL change_pg(BOOL onoff);

void FASTCALL set_cr3(UINT32 new_cr3);
void FASTCALL set_cpl(int new_cpl);

extern const UINT8 iflags[];
#define	szpcflag	iflags
extern UINT8 szpflag_w[0x10000];

extern UINT8 *reg8_b20[0x100];
extern UINT8 *reg8_b53[0x100];
extern UINT16 *reg16_b20[0x100];
extern UINT16 *reg16_b53[0x100];
extern UINT32 *reg32_b20[0x100];
extern UINT32 *reg32_b53[0x100];

extern const char *reg8_str[8];
extern const char *reg16_str[8];
extern const char *reg32_str[8];

char *cpu_reg2str(void);
#if defined(USE_FPU)
char *fpu_reg2str(void);
#endif
void put_cpuinfo(void);
void dbg_printf(const char *str, ...);


/*
 * FPU
 */
#define	FPU_REGS		CPU_STATSAVE.fpu_regs
#define	FPU_CTRLWORD		FPU_REGS.control
#define	FPU_STATUSWORD		FPU_REGS.status
#define	FPU_INSTPTR		FPU_REGS.inst
#define	FPU_DATAPTR		FPU_REGS.data
#define	FPU_LASTINSTOP		FPU_REGS.op
#define	FPU_INSTPTR_OFFSET	FPU_REGS.inst.offset
#define	FPU_INSTPTR_SEG		FPU_REGS.inst.seg
#define	FPU_DATAPTR_OFFSET	FPU_REGS.data.offset
#define	FPU_DATAPTR_SEG		FPU_REGS.data.seg

#define	FPU_STAT		CPU_STATSAVE.fpu_stat
#define	FPU_STAT_TOP		FPU_STAT.top
#define	FPU_STAT_PC		FPU_STAT.pc
#define	FPU_STAT_RC		FPU_STAT.rc

#define	FPU_ST(i)		FPU_STAT.reg[((i) + FPU_STAT_TOP) & 7]
#define	FPU_REG(i)		FPU_STAT.reg[i]

/* FPU status register */
#define	FP_IE_FLAG	(1 << 0)	/* 無効な動作 */
#define	FP_DE_FLAG	(1 << 1)	/* デノーマライズド・オペランド */
#define	FP_ZE_FLAG	(1 << 2)	/* ゼロによる除算 */
#define	FP_OE_FLAG	(1 << 3)	/* オーバーフロー */
#define	FP_UE_FLAG	(1 << 4)	/* アンダーフロー */
#define	FP_PE_FLAG	(1 << 5)	/* 精度 */
#define	FP_SF_FLAG	(1 << 6)	/* スタックフォルト */
#define	FP_ES_FLAG	(1 << 7)	/* エラーサマリステータス */
#define	FP_C0_FLAG	(1 << 8)	/* 条件コード */
#define	FP_C1_FLAG	(1 << 9)	/* 条件コード */
#define	FP_C2_FLAG	(1 << 10)	/* 条件コード */
#define	FP_TOP_FLAG	(7 << 11)	/* スタックポイントのトップ */
#define	FP_C3_FLAG	(1 << 14)	/* 条件コード */
#define	FP_B_FLAG	(1 << 15)	/* FPU ビジー */

#define	FP_TOP_SHIFT	11
#define	FP_TOP_GET()	((FPU_STATUSWORD & FP_TOP_FLAG) >> FP_TOP_SHIFT)
#define	FP_TOP_SET(v)	((FPU_STATUSWORD & ~FP_TOP_FLAG) | ((v) << FP_TOP_SHIFT))

#define	FPU_STAT_TOP_INC() \
do { \
	FPU_STAT.top = (FPU_STAT.top + 1) & 7; \
} while (/*CONSTCOND*/0)
#define	FPU_STAT_TOP_DEC() \
do { \
	FPU_STAT.top = (FPU_STAT.top - 1) & 7; \
} while (/*CONSTCOND*/0)

/* FPU control register */
#define	FP_CTRL_PC_SHIFT	8	/* 精度制御 */
#define	FP_CTRL_RC_SHIFT	10	/* 丸め制御 */

#define	FP_CTRL_PC_24		0	/* 単精度 */
#define	FP_CTRL_PC_53		1	/* 倍精度 */
#define	FP_CTRL_PC_64		3	/* 拡張精度 */

#define	FP_CTRL_RC_NEAREST_EVEN	0
#define	FP_CTRL_RC_DOWN		1
#define	FP_CTRL_RC_UP		2
#define	FP_CTRL_RC_TO_ZERO	3


/*
 * Misc.
 */
void memory_dump(int idx, UINT32 madr);
void gdtr_dump(UINT32 base, UINT limit);
void idtr_dump(UINT32 base, UINT limit);
void ldtr_dump(UINT32 base, UINT limit);
void tr_dump(UINT16 selector, UINT32 base, UINT limit);
UINT32 pde_dump(UINT32 base, int idx);
void segdesc_dump(descriptor_t *sdp);
UINT32 convert_laddr_to_paddr(UINT32 laddr);
UINT32 convert_vaddr_to_paddr(unsigned int idx, UINT32 offset);

/*
 * disasm
 */
/* context */
typedef struct {
	UINT32 val;

	UINT32 eip;
	BOOL op32;
	BOOL as32;

	UINT32 baseaddr;
	UINT8 opcode[3];
	UINT8 modrm;
	UINT8 sib;

	BOOL useseg;
	int seg;

	UINT8 opbyte[32];
	int nopbytes;

	char str[256];
	size_t remain;

	char *next;
	char *prefix;
	char *op;
	char *arg[3];
	int narg;

	char pad;
} disasm_context_t;

int disasm(UINT32 *eip, disasm_context_t *ctx);

#ifdef __cplusplus
}
#endif

#include "cpu_io.h"
#include "cpu_mem.h"
#include "exception.h"
#include "paging.h"
#include "resolve.h"
#include "task.h"

#endif	/* !IA32_CPU_CPU_H__ */
