#include "pcfx.h"
#include "v810_cpu.h"

void snortus(void);

static uint16 InterruptAsserted;
static uint16 InterruptMask = 0;
static uint16 InterruptPriority[2];

static void BuildInterruptCache(void)
{
 uint32 iwithmask = InterruptAsserted &~ InterruptMask;
 uint32 InterruptCache = 0;
 int last_prio = -1;

 for(int level = 8; level < 16; level++)
  if(iwithmask & (1 << (15 - level)))
  {
   int tmp_prio;

   if(level >= 12)
    tmp_prio = (InterruptPriority[0] >> ((15 - level) * 3)) & 0x7;
   else
    tmp_prio = (InterruptPriority[1] >> ((11 - level) * 3)) & 0x7;

   if(tmp_prio >= last_prio)
   {
    if(tmp_prio == last_prio)
    {
     printf("Undefined IRQ behavior: %d, %d", level, tmp_prio);
    }
    InterruptCache = 8 + tmp_prio;
    last_prio = tmp_prio;
   }
  }

 v810_setint(InterruptCache);
}

void PCFXIRQ_Assert(int level, bool assert)
{
 InterruptAsserted &= ~(1 << (15 - level));
 
 if(assert)
  InterruptAsserted |= (1 << (15 - level));

 BuildInterruptCache();
}


uint16 PCFXIRQ_Read16(uint32 A)
{
 uint32 ret = 0x00;
 //printf("IRQRead16: %08x\n", A);
 switch(A & 0xC0)
 {
  case 0x00: puts("Fixme Johnnyyyy");
	     ret = InterruptAsserted; // Just a guess, FIXME?
	     break;
  case 0x40: ret = InterruptMask;break;
  case 0x80: ret = InterruptPriority[0]; break;
  case 0xC0: ret = InterruptPriority[1]; break;
 }
 return(ret);
}

uint8 PCFXIRQ_Read8(uint32 A)
{
 return(PCFXIRQ_Read16(A&~1) >> ((A & 1) * 8));
}

void PCFXIRQ_Write16(uint32 A, uint16 V)
{
 if((A & 0xC0) == 0x40)
 {
  //printf("IRQW: %08x %04x\n", A, V);
 }
 else
 {
  //printf("IRQW: %08x %04x %d %d %d %d\n", A, V, V & 0x7, (V >>3) & 0x7, (V >> 6) & 0x7, (V >>9) & 0x7);
 }

 switch(A & 0xC0)
 {
  case 0x40: InterruptMask = V; BuildInterruptCache(); break;
  case 0x80: InterruptPriority[0] = V; BuildInterruptCache(); break;
  case 0xC0: InterruptPriority[1] = V; BuildInterruptCache(); break;
 }
}

int PCFXIRQ_StateAction(StateMem *sm, int load, int data_only)
{
 SFORMAT StateRegs[] =
 {
  SFVAR(InterruptAsserted),
  SFVAR(InterruptMask),
  SFARRAY16(InterruptPriority, 2),
  SFEND
 };

 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "IRQ");

 if(load)
  BuildInterruptCache();

 return(ret);
}

bool PCFXIRQ_GetRegister(const std::string &name, uint32 &value, std::string *special)
{
 if(name == "IMASK")
 {
  value = InterruptMask;
  if(special)
  {
   char buf[256];
   snprintf(buf, 256, "HuC6273: %d, HuC6270-B: %d, HuC6272: %d, HuC6270-A: %d, Pad: %d, Timer: %d, Reset: %d",
	(int)(bool)(InterruptMask & (1 << 0)), (int)(bool)(InterruptMask & (1 << 1)),
	(int)(bool)(InterruptMask & (1 << 2)), (int)(bool)(InterruptMask & (1 << 3)),
	(int)(bool)(InterruptMask & (1 << 4)), (int)(bool)(InterruptMask & (1 << 6)),
	(int)(bool)(InterruptMask & (1 << 7)));
   *special = std::string(buf);
  }
  return(TRUE);
 }
 else if(name == "IPRIO0")
 {
  value =  InterruptPriority[0];
  if(special)
  {
   char buf[256];
   snprintf(buf, 256, "HuC6273: %d, HuC6270-B: %d, HuC6272: %d, HuC6270-A: %d",
 	 (InterruptPriority[0] >> 0) & 0x7, (InterruptPriority[0] >> 3) & 0x7,
	 (InterruptPriority[0] >> 6) & 0x7, (InterruptPriority[0] >> 9) & 0x7);
   *special = std::string(buf);
  }
  return(TRUE);
 }
 else if(name == "IPRIO1")
 {
  value = InterruptPriority[1];
  if(special)
  {
   char buf[256];
   snprintf(buf, 256, "Pad: %d, ??: %d, Timer: %d, Reset: %d",
         (InterruptPriority[1] >> 0) & 0x7, (InterruptPriority[1] >> 3) & 0x7,
         (InterruptPriority[1] >> 6) & 0x7, (InterruptPriority[1] >> 9) & 0x7);
   *special = std::string(buf);
  }
  return(TRUE);
 }
 else
  return(FALSE);
}
