/******************************************************************************

	z80.c

	Handling CZ80 core.

******************************************************************************/

#include "emumain.h"
#include "cz80.h"

static u8 irq_state;

int z80_irq_callback(int line)
{
	if (irq_state == HOLD_LINE)
	{
		irq_state = CLEAR_LINE;
		Cz80_Clear_IRQ(&CZ80);
	}
	return 0xff;
}


void z80_init(void)
{
	Cz80_Init(&CZ80);
#if (EMU_SYSTEM == CPS1)
	Cz80_Set_Fetch(&CZ80, 0x0000, 0xffff, (u32)memory_region_cpu2);
	if (memory_region_user2)
	{
		Cz80_Set_Encrypt_Range(&CZ80, 0x0000, 0x8000, (u32)memory_region_user2);
	}
	Cz80_Set_ReadB(&CZ80, z80_read_memory_8);
	Cz80_Set_WriteB(&CZ80, z80_write_memory_8);
#elif (EMU_SYSTEM == CPS2)
	Cz80_Set_Fetch(&CZ80, 0x0000, 0xffff, (u32)memory_region_cpu2);
	Cz80_Set_ReadB(&CZ80, &z80_read_memory_8);
	Cz80_Set_WriteB(&CZ80, &z80_write_memory_8);
#elif (EMU_SYSTEM == MVS)
	Cz80_Set_Fetch(&CZ80, 0x0000, 0xffff, (u32)memory_region_cpu2);
	Cz80_Set_ReadB(&CZ80, &z80_read_memory_8);
	Cz80_Set_WriteB(&CZ80, &z80_write_memory_8);
	Cz80_Set_INPort(&CZ80, &neogeo_z80_port_r);
	Cz80_Set_OUTPort(&CZ80, &neogeo_z80_port_w);
#endif
	Cz80_Set_IRQ_Callback(&CZ80, &z80_irq_callback);
	Cz80_Reset(&CZ80);
}


void z80_reset(void)
{
	irq_state = CLEAR_LINE;
	Cz80_Reset(&CZ80);
}


void z80_exit(void)
{
	/* nothing to do ? */
}

int z80_execute(int cycles)
{
	return Cz80_Exec(&CZ80, cycles);
}


INLINE void z80_assert_irq(int irqline)
{
	if (irqline == IRQ_LINE_NMI)
		Cz80_Set_NMI(&CZ80);
	else
		Cz80_Set_IRQ(&CZ80, irqline);
}


INLINE void z80_clear_irq(int irqline)
{
	Cz80_Clear_IRQ(&CZ80);
}


void z80_set_irq_line(int irqline, int state)
{
	irq_state = state;

	switch (state)
	{
	case CLEAR_LINE:
		z80_clear_irq(irqline);
		return;

	case ASSERT_LINE:
		z80_assert_irq(irqline);
		return;

	default:
		z80_assert_irq(irqline);
		return;
	}
}

int get_z80_size(void){
	return(
		2 + //state_save_word(&CZ80.BC.W, 1);
		2 + //state_save_word(&CZ80.DE.W, 1);
		2 + //state_save_word(&CZ80.HL.W, 1);
		2 + //state_save_word(&CZ80.AF.W, 1);
		2 + //state_save_word(&CZ80.IX.W, 1);
		2 + //state_save_word(&CZ80.IY.W, 1);
		2 + //state_save_word(&CZ80.SP.W, 1);
		4 + //state_save_long(&pc, 1);
		2 + //state_save_word(&CZ80.BC2.W, 1);
		2 + //state_save_word(&CZ80.DE2.W, 1);
		2 + //state_save_word(&CZ80.HL2.W, 1);
		2 + //state_save_word(&CZ80.AF2.W, 1);
		2 + //state_save_word(&CZ80.R.W, 1);
		2 + //state_save_word(&CZ80.IFF.W, 1);
		1 + //state_save_byte(&CZ80.I, 1);
		1 + //state_save_byte(&CZ80.IM, 1);
		1 + //state_save_byte(&CZ80.IRQState, 1);
		1 + //state_save_byte(&CZ80.HaltState, 1);
		1 );//state_save_byte(&irq_state, 1);
	
	
}

int save_z80_to_mem(unsigned char *stor){
	unsigned char *pos_ini = stor;
	u32 pc = Cz80_Get_PC(&CZ80);

	//state_save_word(&CZ80.BC.W, 1);
	memcpy(stor, &CZ80.BC.W, 2);
	stor += 2;
	
	//state_save_word(&CZ80.DE.W, 1);
	memcpy(stor, &CZ80.DE.W, 2);
	stor += 2;
	
	//state_save_word(&CZ80.HL.W, 1);
	memcpy(stor, &CZ80.HL.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.AF.W, 1);
	memcpy(stor, &CZ80.AF.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.IX.W, 1);
	memcpy(stor, &CZ80.IX.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.IY.W, 1);
	memcpy(stor, &CZ80.IY.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.SP.W, 1);
	memcpy(stor, &CZ80.SP.W, 2);
	stor += 2;
	
	
	//state_save_long(&pc, 1);
	memcpy(stor, &pc, 4);
	stor += 4;
	
	
	//state_save_word(&CZ80.BC2.W, 1);
	memcpy(stor, &CZ80.BC2.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.DE2.W, 1);
	memcpy(stor, &CZ80.DE2.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.HL2.W, 1);
	memcpy(stor, &CZ80.HL2.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.AF2.W, 1);
	memcpy(stor, &CZ80.AF2.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.R.W, 1);
	memcpy(stor, &CZ80.R.W, 2);
	stor += 2;
	
	
	//state_save_word(&CZ80.IFF.W, 1);
	memcpy(stor, &CZ80.IFF.W, 2);
	stor += 2;
	
	
	//state_save_byte(&CZ80.I, 1);
	*stor = CZ80.I;
	stor++;
	
	
	
	//state_save_byte(&CZ80.IM, 1);
	*stor = CZ80.IM;
	stor++;
	
	
	
	//state_save_byte(&CZ80.IRQState, 1);
	*stor = CZ80.IRQState;
	stor++;
	
	
	
	//state_save_byte(&CZ80.HaltState, 1);
	*stor = CZ80.HaltState;
	stor++;
	
	
	//state_save_byte(&irq_state, 1);
	*stor = irq_state;
	stor++;
	

	return (stor - pos_ini);
}

#ifdef SAVE_STATE
STATE_SAVE( z80 )
{
	u32 pc = Cz80_Get_PC(&CZ80);

	state_save_word(&CZ80.BC.W, 1);
	state_save_word(&CZ80.DE.W, 1);
	state_save_word(&CZ80.HL.W, 1);
	state_save_word(&CZ80.AF.W, 1);
	state_save_word(&CZ80.IX.W, 1);
	state_save_word(&CZ80.IY.W, 1);
	state_save_word(&CZ80.SP.W, 1);
	state_save_long(&pc, 1);
	state_save_word(&CZ80.BC2.W, 1);
	state_save_word(&CZ80.DE2.W, 1);
	state_save_word(&CZ80.HL2.W, 1);
	state_save_word(&CZ80.AF2.W, 1);
	state_save_word(&CZ80.R.W, 1);
	state_save_word(&CZ80.IFF.W, 1);
	state_save_byte(&CZ80.I, 1);
	state_save_byte(&CZ80.IM, 1);
	state_save_byte(&CZ80.IRQState, 1);
	state_save_byte(&CZ80.HaltState, 1);
	state_save_byte(&irq_state, 1);
}

STATE_LOAD( z80 )
{
	u32 pc;

	state_load_word(&CZ80.BC.W, 1);
	state_load_word(&CZ80.DE.W, 1);
	state_load_word(&CZ80.HL.W, 1);
	state_load_word(&CZ80.AF.W, 1);
	state_load_word(&CZ80.IX.W, 1);
	state_load_word(&CZ80.IY.W, 1);
	state_load_word(&CZ80.SP.W, 1);
	state_load_long(&pc, 1);
	state_load_word(&CZ80.BC2.W, 1);
	state_load_word(&CZ80.DE2.W, 1);
	state_load_word(&CZ80.HL2.W, 1);
	state_load_word(&CZ80.AF2.W, 1);
	state_load_word(&CZ80.R.W, 1);
	state_load_word(&CZ80.IFF.W, 1);
	state_load_byte(&CZ80.I, 1);
	state_load_byte(&CZ80.IM, 1);
	state_load_byte(&CZ80.IRQState, 1);
	state_load_byte(&CZ80.HaltState, 1);
	state_load_byte(&irq_state, 1);

	Cz80_Set_PC(&CZ80, pc);
}
#endif



int load_z80_from_mem(unsigned char *stor){
	unsigned char *pos_ini = stor;
	u32 pc;

	//state_load_word(&CZ80.BC.W, 1);
	memcpy(  &CZ80.BC.W, stor, 2);
	stor += 2;
	
	//state_load_word(&CZ80.DE.W, 1);
	memcpy(  &CZ80.DE.W, stor, 2);
	stor += 2;
	
	//state_load_word(&CZ80.HL.W, 1);
	memcpy(  &CZ80.HL.W, stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.AF.W, 1);
	memcpy(  &CZ80.AF.W,  stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.IX.W, 1);
	memcpy(  &CZ80.IX.W,  stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.IY.W, 1);
	memcpy(  &CZ80.IY.W,  stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.SP.W, 1);
	memcpy(  &CZ80.SP.W,  stor, 2);
	stor += 2;
	
	
	//state_load_long(&pc, 1);
	memcpy(  &pc, stor, 4);
	stor += 4;
	
	
	//state_load_word(&CZ80.BC2.W, 1);
	memcpy(  &CZ80.BC2.W, stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.DE2.W, 1);
	memcpy(  &CZ80.DE2.W,  stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.HL2.W, 1);
	memcpy(  &CZ80.HL2.W,  stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.AF2.W, 1);
	memcpy(  &CZ80.AF2.W,  stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.R.W, 1);
	memcpy(  &CZ80.R.W, stor, 2);
	stor += 2;
	
	
	//state_load_word(&CZ80.IFF.W, 1);
	memcpy(  &CZ80.IFF.W, stor, 2);
	stor += 2;
	
	
	//state_load_byte(&CZ80.I, 1);
	CZ80.I = *stor;
	stor++;
	
	
	
	//state_load_byte(&CZ80.IM, 1);
	CZ80.IM = *stor;
	stor++;
	
	
	
	//state_load_byte(&CZ80.IRQState, 1);
	CZ80.IRQState = *stor;
	stor++;
	
	
	
	//state_load_byte(&CZ80.HaltState, 1);
	CZ80.HaltState = *stor;
	stor++;
	
	
	//state_load_byte(&irq_state, 1);
	irq_state = *stor;
	stor++;
	
	Cz80_Set_PC(&CZ80, pc);

	return (stor - pos_ini);
	
}



