// CrossWorks Tasking Library.
//
// Copyright (c) 2004 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 <targets/MC9328MXL.h>
#include "ctl_api.h"

#define INTERRUPT_SOURCE_COUNT 64

static CTL_ISR_FN_t vectors[INTERRUPT_SOURCE_COUNT];

#define AITC_NIPRIORITY(n) (*(&AITC_NIPRIORITY7 + ((63 - n) / 8)))

void irq_handler(void) __attribute__((naked));

static void
irq_handler2(void)
{
  unsigned long vecsr = AITC_NIVECSR;
  /* Store current interrupt mask */
  unsigned long nimask = AITC_NIMASK; 
  /* Set the interrupt mask to the current interrupt priority level in order
     to allow only higher priority interrupts to interrupt the ISR if interrupts
     are re-enabled */
  AITC_NIMASK = vecsr & 0x1F;
  /* Increment interrupt count */
  ctl_interrupt_count++;
  /* Call ISR */
  vectors[vecsr >> 16]();
  /* Restore interrupt mask */
  AITC_NIMASK = nimask; 
}

void
irq_handler(void)
{
  asm("stmfd sp!, {r0-r12, lr}"); 
  asm("mrs r0, spsr");
  asm("stmfd sp!, {r0}");
  irq_handler2();
  asm("mov r0, sp");
  asm("ldr r1, =ctl_exit_isr");
  asm("bx r1");
}

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 (oldisr)
    *oldisr = vectors[vector];
  vectors[vector] = isr;
  /* Make sure interrupt is an IRQ interrupt */
  if (vector >= 32)
    AITC_INTTYPEH &= ~(1 << (vector - 32));
  else
    AITC_INTTYPEL &= ~(1 << vector);
  /* Set the interrupt priority level */
  AITC_NIPRIORITY(vector) &= ~(0xF << ((vector % 8) * 4));
  AITC_NIPRIORITY(vector) |= priority << ((vector % 8) * 4);
  return 1;
}

int
ctl_unmask_isr(unsigned int vector)
{
  if (vector >= 32)
    AITC_INTENABLEH |= 1 << (vector - 32);
  else
    AITC_INTENABLEL |= 1 << vector;
  return 1;
}

int
ctl_mask_isr(unsigned int vector)
{
  if (vector >= 32)
    AITC_INTENABLEH &= ~(1 << (vector - 32));
  else
    AITC_INTENABLEL |= ~(1 << vector);
  return 1;
}

