// Copyright (c) 2001-2005 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.
//
////////////////////////////////////////////////////////////////////////////////
//
//     Logic Product Development SDKLH79524-10  Timer Interrupt Example
//
// Description
// -----------
// This example demonstrates setting up interrupt handlers and timers.
//
////////////////////////////////////////////////////////////////////////////////

#include <targets/LH79524.h>

#define TIMER0_INT 4
#define TIMER1_INT 5

#define EXTENDED_GPIO_REG *((volatile unsigned char *)0x4CB00000)

#define HCLK_FREQUENCY 50803200

static int timer0Count, timer1Count;

static void timer0ISR(void) __attribute__ ((interrupt ("IRQ")));

static void
timer0ISR(void)
{
  if (++timer0Count % 2)
    EXTENDED_GPIO_REG |= 2;
  else
    EXTENDED_GPIO_REG &= ~2;
  /* Clear the timer 0 interrupt */
  TIMER_STATUS0 = 0x4;
  /* Update VIC priorities */
  VIC_VECTADDR = 0;
}

static void timer1ISR(void) __attribute__ ((interrupt ("IRQ")));

static
void
timer1ISR(void)
{
  if (++timer1Count % 2)
    EXTENDED_GPIO_REG |= 4;
  else
    EXTENDED_GPIO_REG &= ~4;
  /* Clear the timer 1 interrupt */
  TIMER_STATUS1 = 0x4;
  /* Update VIC priorities */
  VIC_VECTADDR = 0;
}

int
main(void)
{
  /* Initialise LEDs */
  EXTENDED_GPIO_REG &= ~3;

  /* Write "ldr pc, [pc, #-0xFF0]" instruction to IRQ exception vector */
  *(volatile unsigned long *)(0x00000018) = 0xE51FFFF0; 

  /* Timer 0 interrupt is an IRQ interrupt */
  VIC_INTSELECT &= ~(1 << TIMER0_INT);
  /* Enable timer 0 interrupt */
  VIC_INTENABLE = 1 << TIMER0_INT;
  /* Use slot 0 for timer 0 interrupt */
  VIC_VECTCTRL0 = 0x20 | TIMER0_INT;
  /* Set the address of ISR for slot 0 */
  VIC_VECTADDR0 = (unsigned int)timer0ISR;

  /* Timer 1 interrupt is an IRQ interrupt */
  VIC_INTSELECT &= ~(1 << TIMER1_INT);
  /* Enable timer 1 interrupt */
  VIC_INTENABLE = 1 << TIMER1_INT;
  /* Use slot 1 for timer 1 interrupt */
  VIC_VECTCTRL1 = 0x20 | TIMER1_INT;
  /* Set the address of ISR for slot 1 */
  VIC_VECTADDR1 = (unsigned int)timer1ISR;

  /* Setup comparator to generate interrupts at 1KHz */
  TIMER_T0CMP1 = HCLK_FREQUENCY / 2 / 1000;
  /* Free running timer */
  TIMER_CMP_CAP_CTRL = 0x4000;
  /* Interrupt on compare 1 */
  TIMER_INTEN0 = 0x4; 
  /* Enable interrupts, timer clock frequency = HCLK / 2 */
  TIMER_CTRL0 = 0x2; 

  /* Setup comparator to generate interrupts at 10Hz */
  TIMER_T1CMP1 = HCLK_FREQUENCY / 128 / 10;
  /* Interrupt on compare 1 */
  TIMER_INTEN1 = 0x4;
  /* Enable interrupts, timer clock frequency = HCLK / 128 */
  TIMER_CTRL1 = 0x201A; 

  /* Enable Interrupts */
  __ARMLIB_enableIRQ();
  
  while (timer0Count < 5 && timer1Count < 5);

  return 0; 
}
