/*
 * Copyright(C) Paul und Scherer (mct.de/mct.net)
 *
 * This example demonstrates how to...
 *
 *  ... install handlers for SWI and FIQ
 *      using the interrupt vector table.
 */

#include <stdio.h>
#include <sys/arm7tdmi.h>
#include <target.h>

/*
 * The interrupt entry points and vectors are located in RAM at the
 * beginning of the data segment. When an exception occurs, program
 * execution is continued at the corresponding entry point.
 *
 * Each entry point contains an instruction loading the PC with the
 * value of the corresponding vector.
 *
 * All vectors - except for the IRQ vector, which is taken from the
 * VIC - are located immediately after the entry points, and are by
 * default initialized with _exit (idle loop).
 *
 *  Address           Entry point            loads vector from
 *  ----------------  ---------------------  -----------------
 *  data start + 0*4: reset (not used)
 *               1*4: undefined instruction  data start + 9*4
 *               2*4: SWI                                10*4
 *               3*4: prefetch abort                     11*4
 *               4*4: data     abort                     12*4
 *               5*4: reserved
 *               6*4: IRQ                    VIC
 *               7*4: FIQ                    data start +15*4
 *
 *                    Vector                 defaults to
 *                    ---------------------  -----------------
 *               8*4: not used
 *               9*4: undefined instruction  _exit
 *              10*4: SWI                    _exit
 *              11*4: prefetch abort         _exit
 *              12*4: data     abort         _exit
 *              13*4: not used
 *              14*4: not used
 *              15*4: FIQ                    _exit
 */
extern char _bdata;				// data start
#define SWI_VEC	(*((long *)&_bdata+10))		// SWI vector
#define FIQ_VEC	(*((long *)&_bdata+15))		// FIQ vector

static int swi_cnt;				// SWI count
static int fiq_cnt;				// FIQ count

/*
 * SWI service
 *
 * Exception handlers other than IRQ and FIQ use
 * a different stack frame, and need to know the
 * kind of exception to handle (UNDEF/SWI/ABORT).
 */
static void __attribute__((interrupt("SWI")))	// handle as SWI-type ISR!
swi_sr(void)
{
	swi_cnt++;				// up count
}

/*
 * FIQ service
 */
static void __attribute__((interrupt))		// handle as ISR!
fiq_sr(void)
{
	Intern_t0ir = 1;			// clear t0 int flag
	Intern_vicvectaddr = 0;			// reset VIC priority logic
	fiq_cnt++;				// up count
}

/*
 * Timer0 is setup to generate a fast interrupt request
 * (FIQ) every second. Hitting 's' generates a software
 * interrupt (SWI). Any key displays the count for each
 * kind of interrupt.
 */
int
main(void)
{
	SWI_VEC = (long)swi_sr;			// set SWI SR addr
	FIQ_VEC = (long)fiq_sr;			//     FIQ SR addr
	Intern_vicintenable =			// enable t0 int
	Intern_vicintselect = 0x10;		// select t0 FIQ

	Intern_t0mr0  = _PCLK-1;		// set MR0 to 1s
	Intern_t0mcr |= 3;			// int on MR0, reset
	Intern_t0tcr  = 1;			// go...

	ENABLE_INTERRUPTS;			// enable core ints

	puts("Hit any key ('s' for SWI) to display interrupt counts...");
	while (1) {
		if (getchar() == 's') asm(" swi");
		printf("\nSWI: %d, FIQ: %d\n", swi_cnt, fiq_cnt);
	}
}

