// CrossWorks Target Library.
//
// Copyright (c) 2004, 2009 Rowley Associates Limited.
//
// This file may be distributed under the terms of the License Agreement
// provided with this software.
//
// THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#include "ctl_api.h"

#define AIC_SMR0 (*(volatile unsigned *)0xFFFFF000)
#define AIC_SMR0_OFFSET 0x0

#define AIC_SMR1 (*(volatile unsigned *)0xFFFFF004)
#define AIC_SMR1_OFFSET 0x4

#define AIC_SMR2 (*(volatile unsigned *)0xFFFFF008)
#define AIC_SMR2_OFFSET 0x8

#define AIC_SMR3 (*(volatile unsigned *)0xFFFFF00C)
#define AIC_SMR3_OFFSET 0xC

#define AIC_SMR4 (*(volatile unsigned *)0xFFFFF010)
#define AIC_SMR4_OFFSET 0x10

#define AIC_SMR5 (*(volatile unsigned *)0xFFFFF014)
#define AIC_SMR5_OFFSET 0x14

#define AIC_SMR6 (*(volatile unsigned *)0xFFFFF018)
#define AIC_SMR6_OFFSET 0x18

#define AIC_SMR7 (*(volatile unsigned *)0xFFFFF01C)
#define AIC_SMR7_OFFSET 0x1C

#define AIC_SMR8 (*(volatile unsigned *)0xFFFFF020)
#define AIC_SMR8_OFFSET 0x20

#define AIC_SMR9 (*(volatile unsigned *)0xFFFFF024)
#define AIC_SMR9_OFFSET 0x24

#define AIC_SMR10 (*(volatile unsigned *)0xFFFFF028)
#define AIC_SMR10_OFFSET 0x28

#define AIC_SMR11 (*(volatile unsigned *)0xFFFFF02C)
#define AIC_SMR11_OFFSET 0x2C

#define AIC_SMR12 (*(volatile unsigned *)0xFFFFF030)
#define AIC_SMR12_OFFSET 0x30

#define AIC_SMR13 (*(volatile unsigned *)0xFFFFF034)
#define AIC_SMR13_OFFSET 0x34

#define AIC_SMR14 (*(volatile unsigned *)0xFFFFF038)
#define AIC_SMR14_OFFSET 0x38

#define AIC_SMR15 (*(volatile unsigned *)0xFFFFF03C)
#define AIC_SMR15_OFFSET 0x3C

#define AIC_SMR16 (*(volatile unsigned *)0xFFFFF040)
#define AIC_SMR16_OFFSET 0x40

#define AIC_SMR17 (*(volatile unsigned *)0xFFFFF044)
#define AIC_SMR17_OFFSET 0x44

#define AIC_SMR18 (*(volatile unsigned *)0xFFFFF048)
#define AIC_SMR18_OFFSET 0x48

#define AIC_SMR19 (*(volatile unsigned *)0xFFFFF04C)
#define AIC_SMR19_OFFSET 0x4C

#define AIC_SMR20 (*(volatile unsigned *)0xFFFFF050)
#define AIC_SMR20_OFFSET 0x50

#define AIC_SMR21 (*(volatile unsigned *)0xFFFFF054)
#define AIC_SMR21_OFFSET 0x54

#define AIC_SMR22 (*(volatile unsigned *)0xFFFFF058)
#define AIC_SMR22_OFFSET 0x58

#define AIC_SMR23 (*(volatile unsigned *)0xFFFFF05C)
#define AIC_SMR23_OFFSET 0x5C

#define AIC_SMR24 (*(volatile unsigned *)0xFFFFF060)
#define AIC_SMR24_OFFSET 0x60

#define AIC_SMR25 (*(volatile unsigned *)0xFFFFF064)
#define AIC_SMR25_OFFSET 0x64

#define AIC_SMR26 (*(volatile unsigned *)0xFFFFF068)
#define AIC_SMR26_OFFSET 0x68

#define AIC_SMR27 (*(volatile unsigned *)0xFFFFF06C)
#define AIC_SMR27_OFFSET 0x6C

#define AIC_SMR28 (*(volatile unsigned *)0xFFFFF070)
#define AIC_SMR28_OFFSET 0x70

#define AIC_SMR29 (*(volatile unsigned *)0xFFFFF074)
#define AIC_SMR29_OFFSET 0x74

#define AIC_SMR30 (*(volatile unsigned *)0xFFFFF078)
#define AIC_SMR30_OFFSET 0x78

#define AIC_SMR31 (*(volatile unsigned *)0xFFFFF07C)
#define AIC_SMR31_OFFSET 0x7C

#define AIC_SVR0 (*(volatile unsigned *)0xFFFFF080)
#define AIC_SVR0_OFFSET 0x80

#define AIC_SVR1 (*(volatile unsigned *)0xFFFFF084)
#define AIC_SVR1_OFFSET 0x84

#define AIC_SVR2 (*(volatile unsigned *)0xFFFFF088)
#define AIC_SVR2_OFFSET 0x88

#define AIC_SVR3 (*(volatile unsigned *)0xFFFFF08C)
#define AIC_SVR3_OFFSET 0x8C

#define AIC_SVR4 (*(volatile unsigned *)0xFFFFF090)
#define AIC_SVR4_OFFSET 0x90

#define AIC_SVR5 (*(volatile unsigned *)0xFFFFF094)
#define AIC_SVR5_OFFSET 0x94

#define AIC_SVR6 (*(volatile unsigned *)0xFFFFF098)
#define AIC_SVR6_OFFSET 0x98

#define AIC_SVR7 (*(volatile unsigned *)0xFFFFF09C)
#define AIC_SVR7_OFFSET 0x9C

#define AIC_SVR8 (*(volatile unsigned *)0xFFFFF0A0)
#define AIC_SVR8_OFFSET 0xA0

#define AIC_SVR9 (*(volatile unsigned *)0xFFFFF0A4)
#define AIC_SVR9_OFFSET 0xA4

#define AIC_SVR10 (*(volatile unsigned *)0xFFFFF0A8)
#define AIC_SVR10_OFFSET 0xA8

#define AIC_SVR11 (*(volatile unsigned *)0xFFFFF0AC)
#define AIC_SVR11_OFFSET 0xAC

#define AIC_SVR12 (*(volatile unsigned *)0xFFFFF0B0)
#define AIC_SVR12_OFFSET 0xB0

#define AIC_SVR13 (*(volatile unsigned *)0xFFFFF0B4)
#define AIC_SVR13_OFFSET 0xB4

#define AIC_SVR14 (*(volatile unsigned *)0xFFFFF0B8)
#define AIC_SVR14_OFFSET 0xB8

#define AIC_SVR15 (*(volatile unsigned *)0xFFFFF0BC)
#define AIC_SVR15_OFFSET 0xBC

#define AIC_SVR16 (*(volatile unsigned *)0xFFFFF0C0)
#define AIC_SVR16_OFFSET 0xC0

#define AIC_SVR17 (*(volatile unsigned *)0xFFFFF0C4)
#define AIC_SVR17_OFFSET 0xC4

#define AIC_SVR18 (*(volatile unsigned *)0xFFFFF0C8)
#define AIC_SVR18_OFFSET 0xC8

#define AIC_SVR19 (*(volatile unsigned *)0xFFFFF0CC)
#define AIC_SVR19_OFFSET 0xCC

#define AIC_SVR20 (*(volatile unsigned *)0xFFFFF0D0)
#define AIC_SVR20_OFFSET 0xD0

#define AIC_SVR21 (*(volatile unsigned *)0xFFFFF0D4)
#define AIC_SVR21_OFFSET 0xD4

#define AIC_SVR22 (*(volatile unsigned *)0xFFFFF0D8)
#define AIC_SVR22_OFFSET 0xD8

#define AIC_SVR23 (*(volatile unsigned *)0xFFFFF0DC)
#define AIC_SVR23_OFFSET 0xDC

#define AIC_SVR24 (*(volatile unsigned *)0xFFFFF0E0)
#define AIC_SVR24_OFFSET 0xE0

#define AIC_SVR25 (*(volatile unsigned *)0xFFFFF0E4)
#define AIC_SVR25_OFFSET 0xE4

#define AIC_SVR26 (*(volatile unsigned *)0xFFFFF0E8)
#define AIC_SVR26_OFFSET 0xE8

#define AIC_SVR27 (*(volatile unsigned *)0xFFFFF0EC)
#define AIC_SVR27_OFFSET 0xEC

#define AIC_SVR28 (*(volatile unsigned *)0xFFFFF0F0)
#define AIC_SVR28_OFFSET 0xF0

#define AIC_SVR29 (*(volatile unsigned *)0xFFFFF0F4)
#define AIC_SVR29_OFFSET 0xF4

#define AIC_SVR30 (*(volatile unsigned *)0xFFFFF0F8)
#define AIC_SVR30_OFFSET 0xF8

#define AIC_SVR31 (*(volatile unsigned *)0xFFFFF0FC)
#define AIC_SVR31_OFFSET 0xFC

#define AIC_IVR (*(volatile unsigned *)0xFFFFF100)
#define AIC_IVR_OFFSET 0x100

#define AIC_FVR (*(volatile unsigned *)0xFFFFF104)
#define AIC_FVR_OFFSET 0x104

#define AIC_ISR (*(volatile unsigned *)0xFFFFF108)
#define AIC_ISR_OFFSET 0x108

#define AIC_IPR (*(volatile unsigned *)0xFFFFF10C)
#define AIC_IPR_OFFSET 0x10C

#define AIC_IMR (*(volatile unsigned *)0xFFFFF110)
#define AIC_IMR_OFFSET 0x110

#define AIC_CISR (*(volatile unsigned *)0xFFFFF114)
#define AIC_CISR_OFFSET 0x114

#define AIC_IECR (*(volatile unsigned *)0xFFFFF120)
#define AIC_IECR_OFFSET 0x120

#define AIC_IDCR (*(volatile unsigned *)0xFFFFF124)
#define AIC_IDCR_OFFSET 0x124

#define AIC_ICCR (*(volatile unsigned *)0xFFFFF128)
#define AIC_ICCR_OFFSET 0x128

#define AIC_ISCR (*(volatile unsigned *)0xFFFFF12C)
#define AIC_ISCR_OFFSET 0x12C

#define AIC_EOICR (*(volatile unsigned *)0xFFFFF130)
#define AIC_EOICR_OFFSET 0x130

#define AIC_SPU (*(volatile unsigned *)0xFFFFF134)
#define AIC_SPU_OFFSET 0x134

#define AIC_FFER (*(volatile unsigned long *)0xFFFFF140)
#define AIC_FFSR (*(volatile unsigned long *)0xFFFFF148)

#define INTERRUPT_SOURCE_COUNT 32
#define MAX_IRQ_PRIORITY 8

#define AIC_SMR(n) (*(&AIC_SMR0 + n))
#define AIC_SVR(n) (*(&AIC_SVR0 + n))

static void
forcedFIQHandler()
{
  unsigned i;
  unsigned ffpr = AIC_IPR & AIC_FFSR;
  for (i=1;i<32;i++)
    if (ffpr & (1<<i))
      {
        ((CTL_ISR_FN_t)*(&AIC_SVR0+i))();
        AIC_ICCR = 1<<i;
      }
}

int
ctl_set_isr(unsigned int vector, unsigned int priority, CTL_ISR_TRIGGER_t trigger, CTL_ISR_FN_t isr, CTL_ISR_FN_t *oldisr)
{
  if (vector < INTERRUPT_SOURCE_COUNT)
    {
      if (oldisr)
        *oldisr = (CTL_ISR_FN_t)AIC_SVR(vector);
      if (isr)
        {
#ifdef CHECK_INTERRUPT_INSTALLED
          if (AIC_SVR(vector))
            return 0; /* ISR already installed at this interrupt priority */
#endif
         /* Install as a FIQ */
         if (priority > MAX_IRQ_PRIORITY)
            {
              AIC_FFER = 1 << vector;
              AIC_SVR0 = (CTL_ISR_FN_t)forcedFIQHandler;
            }
          /* Installing an ISR */
          switch (trigger)
            {
              case CTL_ISR_TRIGGER_NEGATIVE_EDGE:
                priority = (priority & 0xFFFFFF9F) | 0x00000020;
                break;
              case CTL_ISR_TRIGGER_HIGH_LEVEL:
                priority = (priority & 0xFFFFFF9F) | 0x00000040;
                break;
              case CTL_ISR_TRIGGER_POSITIVE_EDGE:
                priority |= 0x00000060;
                break;
            }
          AIC_SMR(vector) = priority;
          AIC_SVR(vector) = (unsigned int)isr;
        }
      else
        {
          /* Removing an ISR */
          AIC_SMR(vector) = 0;
          AIC_SVR(vector) = 0;
        }
      return 1;
    }
  else if (vector == 0xFFFFFFFF)
    {
      /* Installing a spurious interrupt handler */
      if (oldisr)
        *oldisr = (CTL_ISR_FN_t)AIC_SPU;
      AIC_SPU = (unsigned int)isr;
      return 1;
    }
  return 0;
}

int
ctl_unmask_isr(unsigned int vector)
{
  AIC_IECR = 1 << vector;
  return 1;
}

int
ctl_mask_isr(unsigned int vector)
{
  AIC_IDCR = 1 << vector;
  return 1;
}

