#include "armdefs.h"
#include "arm2x86_self.h"

const uint8_t		table_logic_cc[16] = {
	1, /* and */
	1, /* eor */
	0, /* sub */
	0, /* rsb */
	0, /* add */
	0, /* adc */
	0, /* sbc */
	0, /* rsc */
	1, /* tst */
	1, /* teq */
	0, /* cmp */
	0, /* cmn */
	1, /* orr */
	1, /* mov */
	1, /* bic */
	1, /* mvn */
};
//chy 2005-05-11
#ifndef __CYGWIN__
volatile uint32_t	arm2x86_pfun;
#else
volatile void (*arm2x86_pfun)(void);
#endif
volatile uint32_t	arm2x86_tmp0;

//--------------------------------------------------------------------------------------------------

static __inline__ uint32_t
gen_op_condition(ARMul_State *state, uint32_t cond)
{
	uint32_t	ret;

	switch(cond) {
		case EQ:
			ret = ZFLAG;
			break;
		case NE:
			ret = !ZFLAG;
			break;
		case VS:
			ret = VFLAG;
			break;
		case VC:
			ret = !VFLAG;
			break;
		case MI:
			ret = NFLAG;
			break;
		case PL:
			ret = !NFLAG;
			break;
		case CS:
			ret = CFLAG;
			break;
		case CC:
			ret = !CFLAG;
			break;
		case HI:
			ret = (CFLAG && !ZFLAG);
			break;
		case LS:
			ret = (!CFLAG || ZFLAG);
			break;
		case GE:
			ret = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
			break;
		case LT:
			ret = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
			break;
		case GT:
			ret = ((!NFLAG && !VFLAG && !ZFLAG) || (NFLAG && VFLAG && !ZFLAG));
			break;
		case LE:
			ret = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
			break;
		default:
			ret = 0;
			break;
	}

	return(ret);
}

void
tea_begin(ARMul_State * state)
{
	//debug
	if (state->Emulate == 0) {
		state->trap = TRAP_DEBUG;
		return;
	}
	//fig
	if (!state->NfiqSig && !FFLAG) {
		state->trap = TRAP_FIQ;
		return;
	}
	//irq
	if (!state->NirqSig && !IFLAG) {
		state->trap = TRAP_IRQ;
		return;
	}
	//do io
	io_do_cycle(state);
}

uint32_t
tea_begin_test(ARMul_State * state, uint32_t cond)
{
	//debug
	if (state->Emulate == 0) {
		state->trap = TRAP_DEBUG;
		return;
	}
	//fig
	if (!state->NfiqSig && !FFLAG) {
		state->trap = TRAP_FIQ;
		return;
	}
	//irq
	if (!state->NirqSig && !IFLAG) {
		state->trap = TRAP_IRQ;
		return;
	}
	//do io
	io_do_cycle(state);
	//test_op
	return(gen_op_condition(state, cond));
}
//--------------------------------------------------------------------------------------------------
uint8_t *
get_op_writesr15(int *len)
{
	unsigned int	begin=0,end=0;

	OP_BEGIN("get_op_writesr15");
	st->trap = TRAP_SETS_R15;
	OP_END("get_op_writesr15");
	*len = end - begin;

	return((uint8_t *)begin);
}

uint8_t *
get_op_return(int *len)
{
	unsigned int	begin=0,end=0;

	OP_BEGIN("get_op_return");
	__asm__ __volatile__ ("ret");
	OP_END("get_op_return");
	*len = end - begin;

	return((uint8_t *)begin);
}

uint8_t *
get_op_addpc(int *len)
{
	unsigned int	begin=0,end=0;

	OP_BEGIN("get_op_addpc");
	st->Reg[15] += 4;
	OP_END("get_op_addpc");
	*len = end - begin;

	return((uint8_t *)begin);
}

/*
uint8_t *
get_op_fiqirq(int *len)
{
	unsigned int	begin=0,end=0;

	OP_BEGIN("get_op_fiqirq");
	if (!FFLAG && !st->NfiqSig) {
		st->trap = TRAP_FIQ;
		__asm__ __volatile__ ("ret");
	}
	if (!IFLAG && !st->NirqSig) {
		st->trap = TRAP_IRQ;
		__asm__ __volatile__ ("ret");
	}
	//io_do_cycle(st);
	__asm__ __volatile__ ("subl	$0xc, %esp");
	__asm__ __volatile__ ("push	%"AREG_st);
	arm2x86_pfun = (uint32_t)io_do_cycle;
	__asm__ __volatile__ ("call	*arm2x86_pfun");
	__asm__ __volatile__ ("addl	$0x10, %esp");
	OP_END("get_op_fiqirq");
	*len = end - begin;

	return((uint8_t *)begin);
}
*/

uint8_t *
get_op_begin(int *len)
{
	unsigned int	begin=0,end=0;

	OP_BEGIN("get_op_begin");
	//tea_begin(st);
	__asm__ __volatile__ ("subl	$0xc, %esp");
	__asm__ __volatile__ ("push	%"AREG_st);
	T2 = (uint32_t)tea_begin;
	__asm__ __volatile__ ("call	*%"AREG_T2);
	__asm__ __volatile__ ("addl	$0x10, %esp");
	__asm__ __volatile__ ("movl	%eax, %"AREG_T0);
	if (st->trap) {
		__asm__ __volatile__ ("ret");
	}
	OP_END("get_op_begin");
	*len = end - begin;

	return((uint8_t *)begin);
}

uint8_t *
get_op_begin_test_T0(int *len)
{
	unsigned int	begin=0,end=0;

	OP_BEGIN("get_op_begin_test_T0");
	//T0 = tea_begin_test(st, T0);
	__asm__ __volatile__ ("subl	$0x8, %esp");
	__asm__ __volatile__ ("push	%"AREG_T0);
	__asm__ __volatile__ ("push	%"AREG_st);
	T2 = (uint32_t)tea_begin_test;
	__asm__ __volatile__ ("call	*%"AREG_T2);
	__asm__ __volatile__ ("addl	$0x10, %esp");
	__asm__ __volatile__ ("movl	%eax, %"AREG_T0);

	if (st->trap) {
		__asm__ __volatile__ ("ret");
	}
	if (!T0) {
		__asm__ __volatile__ ("jmp	0xffffffff");
	}
	OP_END("get_op_begin_test_T0");
	*len = end - begin;

	return((uint8_t *)begin);
}

op_table_t	op_writesr15;
op_table_t	op_return;
op_table_t	op_addpc;
//op_table_t	op_fiqirq;
op_table_t	op_begin;
op_table_t	op_begin_test_T0;
int
op_init()
{
	op_writesr15.op = get_op_writesr15(&op_writesr15.len);
	op_return.op = get_op_return(&op_return.len);
	op_addpc.op = get_op_addpc(&op_addpc.len);
//	op_fiqirq.op = get_op_fiqirq(&op_fiqirq.len);
	op_begin.op = get_op_begin(&op_begin.len);
	op_begin_test_T0.op = get_op_begin_test_T0(&op_begin_test_T0.len);

	return(0);
}
//--------------------------------------------------------------------------------------------------
int
arm2x86_init()
{
	op_init();
	arm2x86_test_init();
	if (arm2x86_shift_init()) {
		return(-1);
	}
	arm2x86_psr_init();
	arm2x86_movl_init();
	arm2x86_mul_init();
	arm2x86_mem_init();
	arm2x86_other_init();
	arm2x86_dp_init();

	return(0);
}
