212 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * File      : trap.c
 | 
						|
 * This file is part of RT-Thread RTOS
 | 
						|
 * COPYRIGHT (C) 2006, RT-Thread Development Team
 | 
						|
 *
 | 
						|
 * The license and distribution terms for this file may be
 | 
						|
 * found in the file LICENSE in this distribution or at
 | 
						|
 * http://openlab.rt-thread.com/license/LICENSE
 | 
						|
 *
 | 
						|
 * Change Logs:
 | 
						|
 * Date           Author       Notes
 | 
						|
 * 2006-08-23     Bernard      first version
 | 
						|
 * 2011-12-17	  nl1031	   for MicroBlaze
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include 	<rtthread.h>
 | 
						|
#include 	"xparameters.h"
 | 
						|
#include 	"xintc.h"
 | 
						|
#include    "xintc_i.h"
 | 
						|
#include    "xintc_l.h"
 | 
						|
 | 
						|
 | 
						|
#define MAX_HANDLERS  XPAR_INTC_MAX_NUM_INTR_INPUTS
 | 
						|
extern XIntc int_ctl; /* The instance of the Interrupt Controller */
 | 
						|
 | 
						|
 | 
						|
extern rt_uint32_t rt_interrupt_nest;
 | 
						|
 | 
						|
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
 | 
						|
rt_uint32_t rt_thread_switch_interrupt_flag;
 | 
						|
 | 
						|
 | 
						|
void rt_hw_interrupt_handler(int vector)
 | 
						|
{
 | 
						|
	rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * This function will initialize hardware interrupt
 | 
						|
 */
 | 
						|
void rt_hw_interrupt_init()
 | 
						|
{
 | 
						|
	rt_base_t index;
 | 
						|
 | 
						|
	XIntc_Config           *CfgPtr;
 | 
						|
 | 
						|
 | 
						|
    CfgPtr = &XIntc_ConfigTable[0];
 | 
						|
 | 
						|
 | 
						|
	for (index = 0; index < MAX_HANDLERS; index ++)
 | 
						|
	{
 | 
						|
		CfgPtr->HandlerTable[index].Handler = (XInterruptHandler)rt_hw_interrupt_handler;
 | 
						|
	}
 | 
						|
 | 
						|
	/* init interrupt nest, and context in thread sp */
 | 
						|
	rt_interrupt_nest = 0;
 | 
						|
	rt_interrupt_from_thread = 0;
 | 
						|
	rt_interrupt_to_thread = 0;
 | 
						|
	rt_thread_switch_interrupt_flag = 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * This function will mask a interrupt.
 | 
						|
 * @param vector the interrupt number
 | 
						|
 */
 | 
						|
void rt_hw_interrupt_mask(int vector)
 | 
						|
{
 | 
						|
	/* disable interrupt */
 | 
						|
	XIntc_Disable(&int_ctl,vector);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * This function will un-mask a interrupt.
 | 
						|
 * @param vector the interrupt number
 | 
						|
 */
 | 
						|
void rt_hw_interrupt_umask(int vector)
 | 
						|
{
 | 
						|
	XIntc_Enable(&int_ctl,vector);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * This function will install a interrupt service routine to a interrupt.
 | 
						|
 * @param vector the interrupt number
 | 
						|
 * @param new_handler the interrupt service routine to be installed
 | 
						|
 * @param old_handler the old interrupt service routine
 | 
						|
 */
 | 
						|
void rt_hw_interrupt_install(int vector, rt_isr_handler_t new_handler, rt_isr_handler_t *old_handler)
 | 
						|
{
 | 
						|
	XIntc_Config           *CfgPtr;
 | 
						|
 | 
						|
    CfgPtr = &XIntc_ConfigTable[0];
 | 
						|
 | 
						|
	if(vector >= 0 && vector < MAX_HANDLERS)
 | 
						|
	{
 | 
						|
		if (*old_handler != RT_NULL) *old_handler = (rt_isr_handler_t)CfgPtr->HandlerTable[vector].Handler;
 | 
						|
		if (new_handler != RT_NULL) CfgPtr->HandlerTable[vector].Handler = (XInterruptHandler)new_handler;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
/** copy from XIntc_DeviceInterruptHandler in xintc_l.c nl1031
 | 
						|
*
 | 
						|
* This function is the primary interrupt handler for the driver. It must be
 | 
						|
* connected to the interrupt source such that is called when an interrupt of
 | 
						|
* the interrupt controller is active. It will resolve which interrupts are
 | 
						|
* active and enabled and call the appropriate interrupt handler. It uses
 | 
						|
* the AckBeforeService flag in the configuration data to determine when to
 | 
						|
* acknowledge the interrupt. Highest priority interrupts are serviced first.
 | 
						|
* The driver can be configured to service only the highest priority interrupt
 | 
						|
* or all pending interrupts using the {XIntc_SetOptions()} function or
 | 
						|
* the {XIntc_SetIntrSrvOption()} function.
 | 
						|
*
 | 
						|
* This function assumes that an interrupt vector table has been previously
 | 
						|
* initialized.  It does not verify that entries in the table are valid before
 | 
						|
* calling an interrupt handler.
 | 
						|
*
 | 
						|
*
 | 
						|
* @return	None.
 | 
						|
*
 | 
						|
* @note
 | 
						|
*
 | 
						|
* The constant XPAR_INTC_MAX_NUM_INTR_INPUTS must be setup for this to compile.
 | 
						|
* Interrupt IDs range from 0 - 31 and correspond to the interrupt input signals
 | 
						|
* for the interrupt controller. XPAR_INTC_MAX_NUM_INTR_INPUTS specifies the
 | 
						|
* highest numbered interrupt input signal that is used.
 | 
						|
*
 | 
						|
******************************************************************************/
 | 
						|
 | 
						|
 | 
						|
void rt_hw_trap_irq(void )
 | 
						|
{
 | 
						|
	u32 intr_status;
 | 
						|
	u32 intr_mask = 1;
 | 
						|
	int intr_number;
 | 
						|
	volatile u32 reg;			/* used as bit bucket */
 | 
						|
	XIntc_Config *cfg_ptr;
 | 
						|
 | 
						|
 | 
						|
	/* Get the configuration data using the device ID */
 | 
						|
	cfg_ptr = &XIntc_ConfigTable[0];
 | 
						|
 | 
						|
	/* Get the interrupts that are waiting to be serviced */
 | 
						|
	intr_status = XIntc_GetIntrStatus(XPAR_INTC_0_BASEADDR);
 | 
						|
 | 
						|
	/* Service each interrupt that is active and enabled by checking each
 | 
						|
	 * bit in the register from LSB to MSB which corresponds to an interrupt
 | 
						|
	 * intput signal
 | 
						|
	 */
 | 
						|
	for (intr_number = 0; intr_number < XPAR_INTC_MAX_NUM_INTR_INPUTS; intr_number++)
 | 
						|
	{
 | 
						|
		if (intr_status & 1)
 | 
						|
		{
 | 
						|
			XIntc_VectorTableEntry *table_ptr;
 | 
						|
 | 
						|
			/* If the interrupt has been setup to acknowledge it
 | 
						|
			 * before servicing the interrupt, then ack it
 | 
						|
			 */
 | 
						|
			if (cfg_ptr->AckBeforeService & intr_mask)
 | 
						|
			{
 | 
						|
				XIntc_AckIntr(cfg_ptr->BaseAddress, intr_mask);
 | 
						|
			}
 | 
						|
 | 
						|
			/* The interrupt is active and enabled, call the
 | 
						|
			 * interrupt handler that was setup with the specified
 | 
						|
			 * parameter
 | 
						|
			 */
 | 
						|
			table_ptr = &(cfg_ptr->HandlerTable[intr_number]);
 | 
						|
			table_ptr->Handler(table_ptr->CallBackRef);
 | 
						|
 | 
						|
			/* If the interrupt has been setup to acknowledge it
 | 
						|
			 * after it has been serviced then ack it
 | 
						|
			 */
 | 
						|
			if ((cfg_ptr->AckBeforeService & intr_mask) == 0)
 | 
						|
			{
 | 
						|
				XIntc_AckIntr(cfg_ptr->BaseAddress, intr_mask);
 | 
						|
			}
 | 
						|
 | 
						|
			/*
 | 
						|
			 * Read the ISR again to handle architectures with posted write
 | 
						|
			 * bus access issues.
 | 
						|
			 */
 | 
						|
			reg = XIntc_GetIntrStatus(cfg_ptr->BaseAddress);
 | 
						|
 | 
						|
			/*
 | 
						|
			 * If only the highest priority interrupt is to be
 | 
						|
			 * serviced, exit loop and return after servicing
 | 
						|
			 * the interrupt
 | 
						|
			 */
 | 
						|
			if (cfg_ptr->Options == XIN_SVC_SGL_ISR_OPTION)
 | 
						|
			{
 | 
						|
				return;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* Move to the next interrupt to check */
 | 
						|
		intr_mask <<= 1;
 | 
						|
		intr_status >>= 1;
 | 
						|
 | 
						|
		/* If there are no other bits set indicating that all interrupts
 | 
						|
		 * have been serviced, then exit the loop
 | 
						|
		 */
 | 
						|
		if (intr_status == 0)
 | 
						|
		{
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 |