#include "types.h"
#include "holly_intc.h"

#include "hw/sh4/sh4_interrupts.h"
#include "hw/holly/sb.h"
#include "hw/maple/maple_if.h"

/*
	ASIC Interrupt controller
	part of the holly block on dc
*/

//asic_RLXXPending: Update the intc flags for pending interrupts
void asic_RL6Pending(void)
{
	bool t1=(SB_ISTNRM & SB_IML6NRM)!=0;
	bool t2=(SB_ISTERR & SB_IML6ERR)!=0;
	bool t3=(SB_ISTEXT & SB_IML6EXT)!=0;

	InterruptPend(sh4_IRL_9,t1|t2|t3);
}

void asic_RL4Pending(void)
{
	bool t1=(SB_ISTNRM & SB_IML4NRM)!=0;
	bool t2=(SB_ISTERR & SB_IML4ERR)!=0;
	bool t3=(SB_ISTEXT & SB_IML4EXT)!=0;

	InterruptPend(sh4_IRL_11,t1|t2|t3);
}

void asic_RL2Pending(void)
{
	bool t1=(SB_ISTNRM & SB_IML2NRM)!=0;
	bool t2=(SB_ISTERR & SB_IML2ERR)!=0;
	bool t3=(SB_ISTEXT & SB_IML2EXT)!=0;

	InterruptPend(sh4_IRL_13,t1|t2|t3);
}

//Raise interrupt interface
void RaiseAsicNormal(HollyInterruptID inter)
{
	if (inter==holly_SCANINT2)
		maple_vblank();

	u32 Interrupt = 1<<(u8)inter;
	SB_ISTNRM |= Interrupt;

	asic_RL2Pending();
	asic_RL4Pending();
	asic_RL6Pending();
}

void RaiseAsicExt(HollyInterruptID inter)
{
	u32 Interrupt = 1<<(u8)inter;
	SB_ISTEXT |= Interrupt;

	asic_RL2Pending();
	asic_RL4Pending();
	asic_RL6Pending();
}

void RaiseAsicErr(HollyInterruptID inter)
{
	u32 Interrupt = 1<<(u8)inter;
	SB_ISTERR |= Interrupt;

	asic_RL2Pending();
	asic_RL4Pending();
	asic_RL6Pending();
}

void asic_RaiseInterrupt(HollyInterruptID inter)
{
	u8 m=inter>>8;
	switch(m)
	{
	case 0:
		RaiseAsicNormal(inter);
		break;
	case 1:
		RaiseAsicExt(inter);
		break;
	case 2:
		RaiseAsicErr(inter);
		break;
	}
}

u32 Read_SB_ISTNRM(u32 addr)
{
   /* Note that the two highest bits indicate
    * the OR'ed result of all the bits in
    * SB_ISTEXT and SB_ISTERR, respectively,
    * and writes to these two bits are ignored. */
	u32 v = SB_ISTNRM & 0x3FFFFFFF;

	if (SB_ISTEXT)
		v |= 0x40000000;

	if (SB_ISTERR)
		v |= 0x80000000;

	return v;
}

void Write_SB_ISTNRM(u32 addr, u32 value)
{
   /* writing a 1 clears the interrupt */
	SB_ISTNRM &= ~value;

   asic_RL2Pending();
   asic_RL4Pending();
   asic_RL6Pending();
}

void asic_CancelInterrupt(HollyInterruptID inter)
{
	SB_ISTEXT&=~(1<<(u8)inter);

   asic_RL2Pending();
   asic_RL4Pending();
   asic_RL6Pending();
}

void Write_SB_ISTEXT(u32 addr, u32 data)
{
	//nothing happens -- asic_CancelInterrupt is used instead
}

void Write_SB_ISTERR(u32 addr, u32 data)
{
	SB_ISTERR &= ~data;

   asic_RL2Pending();
   asic_RL4Pending();
   asic_RL6Pending();
}

void Write_SB_IML2NRM(u32 addr, u32 data)
{
	SB_IML2NRM=data;

	asic_RL2Pending();
}

void Write_SB_IML4NRM(u32 addr, u32 data)
{
	SB_IML4NRM=data;

	asic_RL4Pending();
}

void Write_SB_IML6NRM(u32 addr, u32 data)
{
	SB_IML6NRM=data;

	asic_RL6Pending();
}

void Write_SB_IML6EXT(u32 addr, u32 data)
{
	SB_IML6EXT=data;

	asic_RL6Pending();
}

void Write_SB_IML4EXT(u32 addr, u32 data)
{
	SB_IML4EXT=data;

	asic_RL4Pending();
}

void Write_SB_IML2EXT(u32 addr, u32 data)
{
	SB_IML2EXT=data;

	asic_RL2Pending();
}

void Write_SB_IML6ERR(u32 addr, u32 data)
{
	SB_IML6ERR=data;

	asic_RL6Pending();
}

void Write_SB_IML4ERR(u32 addr, u32 data)
{
	SB_IML4ERR=data;

	asic_RL4Pending();
}

void Write_SB_IML2ERR(u32 addr, u32 data)
{
	SB_IML2ERR=data;

	asic_RL2Pending();
}

void asic_reg_Init(void)
{
	sb_rio_register(SB_ISTNRM_addr,RIO_FUNC,&Read_SB_ISTNRM,&Write_SB_ISTNRM);
	sb_rio_register(SB_ISTEXT_addr,RIO_WF,0,&Write_SB_ISTEXT);
	sb_rio_register(SB_ISTERR_addr,RIO_WF,0,&Write_SB_ISTERR);

	//NRM
	//6
	sb_rio_register(SB_IML6NRM_addr,RIO_WF,0,&Write_SB_IML6NRM);
	//4
	sb_rio_register(SB_IML4NRM_addr,RIO_WF,0,&Write_SB_IML4NRM);
	//2
	sb_rio_register(SB_IML2NRM_addr,RIO_WF,0,&Write_SB_IML2NRM);
	//EXT
	//6
	sb_rio_register(SB_IML6EXT_addr,RIO_WF,0,&Write_SB_IML6EXT);
	//4
	sb_rio_register(SB_IML4EXT_addr,RIO_WF,0,&Write_SB_IML4EXT);
	//2
	sb_rio_register(SB_IML2EXT_addr,RIO_WF,0,&Write_SB_IML2EXT);
	//ERR
	//6
	sb_rio_register(SB_IML6ERR_addr,RIO_WF,0,&Write_SB_IML6ERR);
	//4
	sb_rio_register(SB_IML4ERR_addr,RIO_WF,0,&Write_SB_IML4ERR);
	//2
	sb_rio_register(SB_IML2ERR_addr,RIO_WF,0,&Write_SB_IML2ERR);
}

void asic_reg_Term(void)
{

}

//Reset -> Reset - Initialise to default values
void asic_reg_Reset(bool Manual)
{
}
