/*
================================ COPYRIGHT ================================
The contents of this file are subject to the VTech Informations Ltd. License
of VT-OS Ver. 1.1 operating system (the "License"); you may not use this
file except in compliance with the License.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
for the specific language governing rights and limitations under the License.

The Original Code is VT-OS Ver. 1.1 Operating System, released
on October 1st, 1999

The Initial Developer of the Original Code is VTech Informations Ltd.  All
codes are Copyright (C) VTech Informations Ltd. 1999.  All Rights Reserved.
===========================================================================
*/

/*
===========================================================================
File        :   ints.s
Author(s)   :   Thomas Cheng
Company     :   VTech Informations Ltd.
Project     :   Helio
Date:	    :   October 1st, 1999
Purpose:	:   Interrupt solving
Revision    :   1.1
Note        :   None
===========================================================================
*/

// Include files ---------------------------------------------------------------
#include "include\mips_asm.h"
#include "include\datatype.h"
#include "include\pr3910.h"
#include "include\pr31700s.h"

// Local define constants ------------------------------------------------------
//#define DEBUG_INT
#define C_EPC		1
#define C_STATUS	(C_EPC + 1)
#define C_RA		(C_STATUS + 1)
#define C_AT		(C_RA + 1)
#define C_V0		(C_AT + 1)
#define C_V1		(C_V0 + 1)
#define C_A0		(C_V1 + 1)
#define C_A1		(C_A0 + 1)
#define C_A2		(C_A1 + 1)
#define C_A3		(C_A2 + 1)
#define C_T0		(C_A3 + 1)
#define C_T1		(C_T0 + 1)
#define C_T2		(C_T1 + 1)
#define C_T3		(C_T2 + 1)
#define C_T4		(C_T3 + 1)
#define C_T5		(C_T4 + 1)
#define C_T6		(C_T5 + 1)
#define C_T7		(C_T6 + 1)
#define C_T8		(C_T7 + 1)
#define C_T9		(C_T8 + 1)
#define C_LO		(C_T9 + 1)
#define C_HI		(C_LO + 1)
#define C_IHSIZE	(C_HI)

#define	INT_DEBUG_PIN	1

// Local macros ----------------------------------------------------------------
// upon exception, push all registers into current stack
#define	EXCPT_PUSH_REGS()	\
				mfc0	k0, C0_EPC;	\
				subu	sp, C_IHSIZE*4;	\
				sw		k0, (C_IHSIZE-C_EPC)*4(sp);	\
				mfc0	k0, C0_STATUS;	\
				sw		ra, (C_IHSIZE-C_RA)*4(sp);	\
				sw		k0, (C_IHSIZE-C_STATUS)*4(sp);	\
				sw		AT, (C_IHSIZE-C_AT)*4(sp);	\
				sw		v0, (C_IHSIZE-C_V0)*4(sp);	\
				sw		v1, (C_IHSIZE-C_V1)*4(sp);	\
				sw		a0, (C_IHSIZE-C_A0)*4(sp);	\
				sw		a1, (C_IHSIZE-C_A1)*4(sp);	\
				sw		a2, (C_IHSIZE-C_A2)*4(sp);	\
				sw		a3, (C_IHSIZE-C_A3)*4(sp);	\
				sw		t0, (C_IHSIZE-C_T0)*4(sp);	\
				sw		t1, (C_IHSIZE-C_T1)*4(sp);	\
				sw		t2, (C_IHSIZE-C_T2)*4(sp);	\
				sw		t3, (C_IHSIZE-C_T3)*4(sp);	\
				sw		t4, (C_IHSIZE-C_T4)*4(sp);	\
				sw		t5, (C_IHSIZE-C_T5)*4(sp);	\
				sw		t6, (C_IHSIZE-C_T6)*4(sp);	\
				sw		t7, (C_IHSIZE-C_T7)*4(sp);	\
				mflo	k0;	\
				sw		t8, (C_IHSIZE-C_T8)*4(sp);	\
				sw		k0, (C_IHSIZE-C_LO)*4(sp);	\
				mfhi	k0;	\
				sw		t9, (C_IHSIZE-C_T9)*4(sp);	\
				sw		k0, (C_IHSIZE-C_HI)*4(sp)

// upon finished exception, pop all registers from current stack
#define	EXCPT_POP_REGS()	\
				lw		k0, (C_IHSIZE-C_HI)*4(sp);	\
				lw		t9, (C_IHSIZE-C_T9)*4(sp);	\
				mthi	k0;	\
				lw		k0, (C_IHSIZE-C_LO)*4(sp);	\
				lw		t8, (C_IHSIZE-C_T8)*4(sp);	\
				mtlo	k0;	\
				lw		t7, (C_IHSIZE-C_T7)*4(sp);	\
				lw		t6, (C_IHSIZE-C_T6)*4(sp);	\
				lw		t5, (C_IHSIZE-C_T5)*4(sp);	\
				lw		t4, (C_IHSIZE-C_T4)*4(sp);	\
				lw		t3, (C_IHSIZE-C_T3)*4(sp);	\
				lw		t2, (C_IHSIZE-C_T2)*4(sp);	\
				lw		t1, (C_IHSIZE-C_T1)*4(sp);	\
				lw		t0, (C_IHSIZE-C_T0)*4(sp);	\
				lw		a3, (C_IHSIZE-C_A3)*4(sp);	\
				lw		a2, (C_IHSIZE-C_A2)*4(sp);	\
				lw		a1, (C_IHSIZE-C_A1)*4(sp);	\
				lw		a0, (C_IHSIZE-C_A0)*4(sp);	\
				lw		v1, (C_IHSIZE-C_V1)*4(sp);	\
				lw		v0, (C_IHSIZE-C_V0)*4(sp);	\
				lw		AT, (C_IHSIZE-C_AT)*4(sp);	\
				lw		k0, (C_IHSIZE-C_STATUS)*4(sp);	\
				lw		ra, (C_IHSIZE-C_RA)*4(sp);	\
				mtc0	k0, C0_STATUS;	\
				lw		k0, (C_IHSIZE-C_EPC)*4(sp);	\
				addu	sp, C_IHSIZE*4

#define	UTLB_PUSH_REGS()	EXCPT_PUSH_REGS()
#define	UTLB_POP_REGS()		EXCPT_POP_REGS()
#define	INTH_PUSH_REGS()	EXCPT_PUSH_REGS()
#define	INTH_POP_REGS()		EXCPT_POP_REGS()
#define	INTL_PUSH_REGS()	EXCPT_PUSH_REGS()
#define	INTL_POP_REGS()		EXCPT_POP_REGS()

// Global variables	------------------------------------------------------------
				.data
				GLOBAL_WORD(SysSP, 0)			// System Stack Pointer
				GLOBAL_WORD(AppSP, 0)			// Application Stack Pointer
				GLOBAL_WORD(TmpSysSP, 0)		// Temporary System Stack Pointer
				GLOBAL_WORD(TmpAppSP, 0)		// Temporary Application Stack Pointer
				GLOBAL_WORD(TmpSP, 0)			// Temporary Stack Pointer
				GLOBAL_WORD(INT1, 0)			//
				GLOBAL_WORD(INT2, 0)			//
				GLOBAL_WORD(INT3, 0)			//
				GLOBAL_WORD(INT4, 0)			//
				GLOBAL_WORD(INT5, 0)			//
				GLOBAL_WORD(ClkTick1, 0)		//
				GLOBAL_WORD(ClkTick2, 0)		//

GLOBAL(IntHighVect)
				.word	OtherIntHighHandle		// Null
				.word	OtherIntHighHandle		// IOPOSINT(0) or IONEGINT(0)
				.word	OtherIntHighHandle		// CHIDMACNTINT
				.word	OtherIntHighHandle		// TELDMACNTINT
				.word	OtherIntHighHandle		// SNDDMACNTINT
				.word	OtherIntHighHandle		// Reserved
				.word	OtherIntHighHandle		// IONEGINT(6) or IONEGINT(5)
				.word	OtherIntHighHandle		// Reserved
				.word	OtherIntHighHandle		// IOPOSINT(6) or IOPOSINT(5)
				.word	OtherIntHighHandle		// Reserved
				.word	OtherIntHighHandle		// UARTBRXINT
				.word	Int_UartaRx				// UARTARXINT
				.word	OtherIntHighHandle		// Reserved
				.word	Int_Per					// PERINT
				.word	Int_Alarm				// ALARMINT
				.word	Int_PowerOk				// POSPWROKINT or NEGPWROKINT

				.text
//==============================================================================
// UTLB Exception Handling Routine
NESTED_FUNC(UtlbExcHandle, C_IHSIZE, k0)
				.set 	noat
				.set	reorder

#ifdef DEBUG_INT
				li		k0, CPU_REGS_BASE_ADDR
				lw		k1, MFIO_DATA_OUT(k0)
				ori		k1, k1, INT_DEBUG_PIN
				sw		k1, MFIO_DATA_OUT(k0)
#endif
				lui		k0,	0x8000
				ori		k0, k0,0x1204
				sw		sp, 0(k0)

				UTLB_PUSH_REGS()					// push all register into current stack

				mfc0	k0, C0_CAUSE				// Extract Exception Code
				andi	k1, k0, CAUSE_EXCMASK		//   |

				li		k0, EXC_TLBL				// Q: Utlb load exception ?
				beq		k1, k0, utlb_load			// Y:
				li		k0, EXC_TLBS				// Q: Utlb store exception ?
				beq		k1, k0, utlb_store			// Y:
				b		UtlbExc_end					// N: (should not reach here)

utlb_load:		jal		UtlbLoadExcHandle			// Utlb Load Exception
				b		UtlbExc_end					// exit

utlb_store:		jal		UtlbStoreExcHandle			// Utlb Store Exception
//				b		UtlbExc_end					// exit

UtlbExc_end:

#ifdef DEBUG_INT
				li		k0, CPU_REGS_BASE_ADDR
				lw		k1, MFIO_DATA_OUT(k0)
				andi	k1, k1, ~INT_DEBUG_PIN
				sw		k1, MFIO_DATA_OUT(k0)
#endif

				UTLB_POP_REGS()						// pop all register from current stack
				.set 	noreorder
UtlbExc_exit:	j		k0							// return from exception
				rfe									//   |
				.set	reorder
FUNC_END(UtlbExcHandle)


//==============================================================================
// General Exception Handling Routine
NESTED_FUNC(GenExcHandle, C_IHSIZE, k0)
				.set 	noat
				.set	reorder
#ifdef DEBUG_INT
				li		k0, CPU_REGS_BASE_ADDR
				lw		k1, MFIO_DATA_OUT(k0)
				ori		k1, k1, INT_DEBUG_PIN
				sw		k1, MFIO_DATA_OUT(k0)
#endif

				mfc0	k0, C0_CAUSE				// Q: External Interrupt ?
				andi	k1, k0, CAUSE_EXCMASK		//      |
				beq		k1, zero, Exc_Interrupt		// Y:
				li		k0, EXC_SYS					// Q: Syscall Exception ?
				beq		k1, k0, Exc_Syscall			// Y:
				jal		OtherGenExcHandle			// N:
				b		Irq_High_exit				// exit

// External Interrupt ----------------------------------------------------------
Exc_Interrupt:	li		k1, CPU_REGS_BASE_ADDR		// load Interrupt Status 6 Register
				lw		k0, INT_STATUS_6(k1)		// Q: IRQ priority high (bit-32) ?
				bltz	k0, Irq_High				// Y:
// low priority IRQ ------------------------------------------------------------
Irq_Low:		INTL_PUSH_REGS()					// push all register into current stack

				lw		t1, INT_STATUS_1(k1)		// Check Interrupt Status 1 Register
				lw		t2, INT_ENABLE_1(k1)		//   |
				and		t1, t1, t2					//   |
				bne		t1, zero, poll_intst1		//   |
				lw		t1, INT_STATUS_2(k1)		// Check Interrupt Status 2 Register
				lw		t2, INT_ENABLE_2(k1)		//   |
				and		t1, t1, t2					//   |
				bne		t1, zero, poll_intst2		//   |
				lw		t1, INT_STATUS_3(k1)		// Check Interrupt Status 3 Register
				lw		t2, INT_ENABLE_3(k1)		//   |
				and		t1, t1, t2					//   |
				bne		t1, zero, poll_intst3		//   |
				lw		t1, INT_STATUS_4(k1)		// Check Interrupt Status 4 Register
				lw		t2, INT_ENABLE_4(k1)		//   |
				and		t1, t1, t2					//   |
				bne		t1, zero, poll_intst4		//   |
				lw		t1, INT_STATUS_5(k1)		// Check Interrupt Status 5 Register
				lw		t2, INT_ENABLE_5(k1)		//   |
				and		t1, t1, t2					//   |
				bne		t1, zero, poll_intst5		//   |

Irq_Low_end:	//jal		DisableGlobal

#ifdef DEBUG_INT
				li		k0, CPU_REGS_BASE_ADDR
				lw		k1, MFIO_DATA_OUT(k0)
				andi	k1, k1, ~INT_DEBUG_PIN
				sw		k1, MFIO_DATA_OUT(k0)
#endif

				INTL_POP_REGS()						// pop all register from current stack
				.set 	noreorder
Irq_Low_exit:	j		k0							// return from exception
				rfe									//   |
				.set	reorder

// Interrupt Status 1 Register .................................................
poll_intst1:	li		t2, SIBSF0INT				// Check Sib SF0 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_SIB_SF0
				li		t2, SIBSF1INT				// Check Sib SF1 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_SIB_SF1
				li		t2, SIBIRQPOSINT			// Check Sib Irq Positive Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_SIB_pos
				li		t2, TEL0_5INT				// Check Tel DMA Half Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_TelDMAhalf
				li		t2, TEL1_0INT				// CheckTel DMA Full Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_TelDMAfull
				li      t2, SND1_0INT				// Check Snd DMA Full Interrupt
				and		t2, t2, t1
				bne     t2, zero, int_SndDMAfull
				jal		OtherIntLow1Handle			// Others
				b		Irq_Low_end

int_SIB_SF0:	sw		t2, INT_STATUS_1(k1)		// Sib SF0 Interrupt
				jal		SF0Isr
				b		Irq_Low_end

int_SIB_SF1:	sw		t2, INT_STATUS_1(k1)		// Sib SF1 Interrupt
				jal		SF1Isr
				b		Irq_Low_end

int_SIB_pos:	sw		t2, INT_STATUS_1(k1)		// Sib Irq Positive Interrupt
				jal		SibIrqPosISR
				b		Irq_Low_end

int_TelDMAhalf:	sw		t2, INT_STATUS_1(k1)		// Tel DMA Half Interrupt
				jal		Tel0_5ISR
				b		Irq_Low_end

int_TelDMAfull:	sw		t2, INT_STATUS_1(k1)		// Tel DMA Full Interrupt
				jal		Tel1_0ISR
				b		Irq_Low_end

int_SndDMAfull:	sw		t2, INT_STATUS_1(k1)		// Snd DMA Full Interrupt
				jal     SndIntHandler
				b		Irq_Low_end

// Interrupt Status 2 Register .................................................
poll_intst2:	li		t2, UARTARXINT				// Check UartA Rx Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_UartaRx
				li		t2, UARTARXOVERRUNINT		// Check UartA Rx Overrun Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_UartaRxOv
				li		t2, UARTADMAFULLINT			// Check UartA DMA Full Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_UartaDMAfull
				jal		OtherIntLow2Handle			// Others
				b		Irq_Low_end

int_UartaRx:	sw		t2, INT_STATUS_2(k1)		// UartA Rx Interrupt
				jal		UartIsrRx
				b		Irq_Low_end

int_UartaRxOv:	sw		t2, INT_STATUS_2(k1)		// UartA Rx Overrun Interrupt
				b		Irq_Low_end

int_UartaDMAfull:									// UartA DMA Full Interrupt
				sw		t2, INT_STATUS_2(k1)
				jal		UartADmaFullIsr
				b		Irq_Low_end

// Interrupt Status 3 Register .................................................
poll_intst3:	li		t2, MFIOPOSINT(0)			// Check MFIO 0 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_MFIO_p0
				li      t2, MFIOPOSINT(25)			// Check MFIO 25 Interrupt
				and		t2, t2, t1
				bne     t2, zero, int_MFIO_p25
				li      t2, MFIOPOSINT(30)			// Check MFIO 30 Interrupt
				and		t2, t2, t1
				bne     t2, zero, int_MFIO_p30
				li      t2, MFIOPOSINT(8)			// Check MFIO 8 Interrupt
				and		t2, t2, t1
				bne     t2, zero, int_MFIO_p8
				jal		OtherIntLow3Handle			// Others
				b		Irq_Low_end

int_MFIO_p0:	sw		t2, INT_STATUS_3(k1)		// MFIO 0 Interrupt
				jal     CheckKey8
				b		Irq_Low_end

int_MFIO_p25:	sw		t2, INT_STATUS_3(k1)		// MFIO 25 Interrupt
				jal     DisHotSynCheck
				b		Irq_Low_end

int_MFIO_p30:	sw		t2, INT_STATUS_3(k1)		// MFIO 30 Interrupt
				jal     DisSioDevDet
				b		Irq_Low_end

int_MFIO_p8:	sw		t2, INT_STATUS_3(k1)		// MFIO Pos 8 Interrupt
				jal     PosBatDoorIntISR
				b		Irq_Low_end


// Interrupt Status 4 Register .................................................
poll_intst4:	li      t2, MFIONEGINT(25)			// Check MFIO 25 Interrupt
				and     t2, t2, t1
				bne     t2, zero, int_MFIO_n25
				li      t2, MFIONEGINT(28)			// Check MFIO 28 Interrupt
				and     t2, t2, t1
				bne     t2, zero, int_MFIO_n28
				li      t2, MFIONEGINT(30)			// Check MFIO 30 Interrupt
				and     t2, t2, t1
				bne     t2, zero, int_MFIO_n30
				li		t2, MFIONEGINT(8)			// Check MFIO 8 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_MFIO_n8
				jal		OtherIntLow4Handle			// Others
				b		Irq_Low_end

int_MFIO_n25:	sw      t2, INT_STATUS_4(k1)		// MFIO 25 Interrupt
				jal     HotSynDebounCheck
				b		Irq_Low_end

int_MFIO_n28:	sw      t2, INT_STATUS_4(k1)		// MFIO 28 Interrupt
				jal     SIORdy
				b		Irq_Low_end

int_MFIO_n30:	sw      t2, INT_STATUS_4(k1)		// MFIO 30 Interrupt
				jal     SIODebounCheck
				b		Irq_Low_end

int_MFIO_n8:	sw      t2, INT_STATUS_4(k1)		// MFIO Neg 8 Interrupt
				jal     NegBatDoorIntISR
				b		Irq_Low_end

// Interrupt Status 5 Register .................................................
poll_intst5:	li		t2, PERINT					// Check Periodic Timer Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_Per
				li		t2, ALARMINT				// Check Alarm Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_Alarm
				li		t2, NEGONBUTNINT			// Check Negative On Button Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_ButtOn_n
				li		t2, IOPOSINT(6)				// Check GPIO 6 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_GPIO_6
				li		t2, IOPOSINT(5)				// Check GPIO 5 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_GPIO_5
				li		t2, IOPOSINT(4)				// Check GPIO 4 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_GPIO_4
				li		t2, IOPOSINT(3)				// Check GPIO 3 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_GPIO_3
				li		t2, IOPOSINT(2)				// Check GPIO 2 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_GPIO_2
				li		t2, IOPOSINT(1)				// Check GPIO 1 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_GPIO_1
				li		t2, IOPOSINT(0)				// Check GPIO 0 Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_GPIO_0
				li		t2, POSONBUTNINT			// Check positive On Button Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_ButtOn_p
				li		t2, NEGPWROKINT				// Check NegPwrOk Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_PwrOk_n
				li		t2, POSPWROKINT				// Check PosPwrOk Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_PwrOk_p
				li		t2, NEGPWRINT				// Check NegPwr Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_Pwr_n
				li		t2, POSPWRINT				// Check PosPwrOk Interrupt
				and		t2, t2, t1
				bne		t2, zero, int_Pwr_p
				jal		OtherIntLow5Handle			// Others
				b		Irq_Low_end

int_Per:		sw		t2, INT_STATUS_5(k1)		// Periodic Timer Interrupt
				jal		TmrISR
				b		Irq_Low_end

int_Alarm:		sw		t2, INT_STATUS_5(k1)		// Alarm Interrupt
				jal		AlmISR
				b		Irq_Low_end

int_ButtOn_n:	sw		t2, INT_STATUS_5(k1)		// Negative Edge On Button Interrupt
				jal		NegOnButnISR
				b		Irq_Low_end

int_GPIO_6:		sw      t2, INT_STATUS_5(k1)		// GPIO Interrupt
				jal     KeyStop
				b		Irq_Low_end

int_GPIO_5:		sw      t2, INT_STATUS_5(k1)		// GPIO Interrupt
				jal     PlaySoundKey
				b		Irq_Low_end

int_GPIO_4:		sw      t2, INT_STATUS_5(k1)		// GPIO Interrupt
				jal     KeyDown
				b		Irq_Low_end

int_GPIO_3:		sw      t2, INT_STATUS_5(k1)		// GPIO Interrupt
				jal     KeyUp
				b		Irq_Low_end

int_GPIO_2:		sw      t2, INT_STATUS_5(k1)		// GPIO Interrupt
				jal     IOCtrl
				b		Irq_Low_end

int_GPIO_1:		sw      t2, INT_STATUS_5(k1)		// GPIO Interrupt
				jal     IOCtrl
				b		Irq_Low_end

int_GPIO_0:		sw      t2, INT_STATUS_5(k1)		// GPIO Interrupt
				jal     IOCtrl
				b		Irq_Low_end

int_ButtOn_p:	sw      t2, INT_STATUS_5(k1)		// Positive On Button Interrupt
				jal     PowerCtrl
				b		Irq_Low_end

int_PwrOk_n:	sw      t2, INT_STATUS_5(k1)		// NegPwrOk Interrupt
				jal     NegPwrOkIntISR
				b		Irq_Low_end

int_PwrOk_p:	sw      t2, INT_STATUS_5(k1)		// PosPwrOk Interrupt
				jal     PosPwrOkIntISR
				b		Irq_Low_end

int_Pwr_n:		sw      t2, INT_STATUS_5(k1)		// NegPwr Interrupt
				jal     NegPwrIntISR
				b		Irq_Low_end

int_Pwr_p:		sw      t2, INT_STATUS_5(k1)		// PosPwr Interrupt
				jal     PosPwrIntISR
				b		Irq_Low_end

// high priority IRQ -----------------------------------------------------------
Irq_High:		INTH_PUSH_REGS()					// push all register into current stack

				lw		t1, INT_STATUS_6(k1)		// lookup IntHighVect vector table
				la		t2, IntHighVect				//   and branch according to
				andi	t1, INTVECTMASK				//   INT_STATUS_6's INTVECT
				addu	t1, t2						//   |
				lw		t2, 0(t1)					//   |
				jr		t2							//   |

// Periodic Timer Interrupt ....................................................
Int_Per:		li		t2, PERINT
				sw		t2, INT_STATUS_5(k1)
				jal		TmrISR
				b		Irq_High_end

// Alarm Interrupt .............................................................
Int_Alarm:		li		t2, ALARMINT
				sw		t2, INT_STATUS_5(k1)
				jal		AlmISR
				b		Irq_High_end

// Uart A Rx Interrupt .........................................................
Int_UartaRx:	li		t2, UARTARXINT
				sw		t2, INT_STATUS_5(k1)
				jal		UartIsrRx
				b		Irq_High_end

// Pwr Ok Interrupt ............................................................
Int_PowerOk:	lw		t1, INT_STATUS_5(k1)		// Check Interrupt Status 5 Register
				lw		t2, INT_ENABLE_5(k1)
				and		t1, t1, t2
				li		t2, NEGPWROKINT				// Check NegPwrOk Interrupt
				and		t2, t2, t1
				bne		t2, zero, Int_NegPwrOk
				li		t2, POSPWROKINT				// Check PosPwrOk Interrupt
				and		t2, t2, t1
				bne		t2, zero, Int_PosPwrOk
				//temp, ???
Int_NegPwrOk:	sw      t2, INT_STATUS_5(k1)
				jal     NegPwrOkIntISR
				b		Irq_High_end

Int_PosPwrOk:	sw      t2, INT_STATUS_5(k1)
				jal     PosPwrOkIntISR
//				b		Irq_High_end

Irq_High_end:
#ifdef DEBUG_INT
				li		k0, CPU_REGS_BASE_ADDR
				lw		k1, MFIO_DATA_OUT(k0)
				andi	k1, k1, ~INT_DEBUG_PIN
				sw		k1, MFIO_DATA_OUT(k0)
#endif

				INTH_POP_REGS()						// pop all register from current stack
				.set 	noreorder
Irq_High_exit:	j		k0							// return from exception
				rfe									//   |

// Syscall Exception -----------------------------------------------------------

#ifdef Helio_Compatible
				.set	reorder
Exc_Syscall1:	bltz	v0, sc_hook					//
sc_default:		sll		v0, 2						// Jump To Corresponding Syscall Handler
				la		k0, SysCallFptr				//   |
				b		sc_com						//   |
sc_hook:		sll		v0, v0, 3					// Jump To Corresponding Hooked Syscall Handler
				la		k0, SysCallHookedFptr		//   |
sc_com:			addu	v0, k0						//   |

#ifdef DEBUG_INT
				li		k0, CPU_REGS_BASE_ADDR
				lw		k1, MFIO_DATA_OUT(k0)
				andi	k1, k1, ~INT_DEBUG_PIN
				sw		k1, MFIO_DATA_OUT(k0)
#endif

				lw		k0, 0(v0)					//
				.set 	noreorder
				j		k0							// goto the syscall sub-routine
				rfe									//   |
				.set	reorder
#endif Helio_Compatible


///////////////////////////////////////////////////
/*
	SYSCALL : 000000 | CODE(20bits) | 001100
	CODE 	: SYSCALLTABLE(6bits) | SYSCALL #(14bits)
*/
				.set	reorder
Exc_Syscall:
				mfc0	k0, C0_EPC
    			lui		k1, %hi(SysCallTable)
				lw		k0, 0(k0)                   // k0 contain the SYSCALL instruction
				srl		k0, 20
				sll		k0, 2						// k0 = upper 6 bit of CODE << 2
				addu	k1, k1, k0
//
				mfc0	k0, C0_EPC
    			lw		k1, %lo(SysCallTable)(k1)	// k1 = one of the 64 syscall table entries
				lw		k0, 0(k0)                   // k0 contain the SYSCALL instruction
				sll		k0, 12
				srl		k0, 16						// k0 = lower 14 bit of CODE << 2
				addu	k1, k1, k0
				lw		k0, 0(k1)
				.set	noreorder
				j		k0
				rfe
				.set	reorder

///////////////////////////////////////////////////

#ifdef simple_syscall

Exc_Syscall2:
				mfc0	k0, C0_EPC
				lui		k1, %hi(SysCallFptr)
				lw		k0, 0(k0)
				srl		k0, 4
				addu	k1, k0
				lw		k0, %lo(SysCallFptr)(k1)
				.set	noreorder
				j		k0
				rfe
				.set	reorder
#endif simple_syscall

FUNC_END(GenExcHandle)


//******************************************************************************
// sub-routines

				.set	reorder
				.set	noat

//==============================================================================
LEAF_FUNC(SyscallHook)
				sll		v0, v0, 3					// Jump To Corresponding Hooked Syscall Handler
				la		k0, SysCallHookedFptr		//   |
				addu	v0, k0						//   |
				lw		k0, 0(v0)					//
				.set 	noreorder
				j		k0							// goto the syscall sub-routine
				rfe									//   |
				.set	reorder
FUNC_END(SyscallHook)

//==============================================================================
LEAF_FUNC(EnableGlobal)
				mfc0	t1, C0_STATUS
				ori		t1, 1
				mtc0	t1, C0_STATUS
				j		ra
FUNC_END(EnableGlobal)

//==============================================================================
LEAF_FUNC(DisableGlobal)
				mfc0	t0, C0_STATUS
				li		t1, 0xFFFFFFFE
				and		t0, t1
				mtc0	t0, C0_STATUS
				j		ra
FUNC_END(DisableGlobal)

//==============================================================================
LEAF_FUNC(RunISR)
				subu	sp, 10*4
				sw		a0, 9*4(sp)
				sw		a1, 8*4(sp)
				sw		a2, 7*4(sp)
				sw		ra, 6*4(sp)
				li		a2, 0x30000000				// device driver start addres
				add		a1, a1, a2
				jal		a1
				nop
				lw		a0, 9*4(sp)
				lw		a1, 8*4(sp)
				lw		a2, 7*4(sp)
				lw		ra, 6*4(sp)
				addu	sp, 10*4
				j		ra
FUNC_END(RunISR)

//==============================================================================
LEAF_FUNC(GetRA)
				subu	sp, 10*4
				sw		a0, 7*4(sp)
				sw		ra, 6*4(sp)
				addu	a0, v0, 0
				jal		PrintRA
				nop
				lw		a0, 7*4(sp)
				lw		ra, 6*4(sp)
				addu	sp, 10*4
				j		ra
FUNC_END(GetRA)

//==============================================================================
// Set Software Interrupt Bit 0
LEAF_FUNC(IntSetSW0)
				mfc0	t0, C0_CAUSE
				ori		t0, t0, 0x0100
				mtc0	t0, C0_CAUSE
				j		ra
FUNC_END(IntSetSW0)

//==============================================================================
// Set Software Interrupt Bit 1
LEAF_FUNC(IntSetSW1)
				mfc0	t0, C0_CAUSE
				ori		t0, t0, 0x0200
				mtc0	t0, C0_CAUSE
				j		ra
FUNC_END(IntSetSW1)

//==============================================================================
// Clear Software Interrupt Bit 0
LEAF_FUNC(IntClrSW0)
				mfc0	t0, C0_CAUSE
				li		t1, 0xFFFFFEFF
				and		t0, t0, t1
				mtc0	t0, C0_CAUSE
				j		ra
FUNC_END(IntClrSW0)

//==============================================================================
// Clear Software Interrupt Bit 1
LEAF_FUNC(IntClrSW1)
				mfc0	t0, C0_CAUSE
				li		t1, 0xFFFFFDFF
				and		t0, t0, t1
				mtc0	t0, C0_CAUSE
				j		ra
FUNC_END(IntClrSW1)

//==============================================================================
LEAF_FUNC(ReduceFreq)
				subu	sp, 10*4
				sw		a0, 5*4(sp)
				sw		ra, 4*4(sp)
				mfc0	t0, v1
				li		t1, 0xFFFFF3FF
				add		t0, t0, t1
				addiu	a0, a0, 0x3
				sll		a0, a0, 10
				or		t0, t0, a0
				mtc0	t0, v1
				j		ra
FUNC_END(ReduceFreq)

//==============================================================================
LEAF_FUNC(SaveTmpSP)
				la		t0, TmpSP
				sw		sp, 0(t0)
				la		t0, TmpSysSP
				la		t1, SysSP
				lw		t2, 0(t1)
				sw		t2, 0(t0)
				la		t0, TmpAppSP
				la		t1, AppSP
				lw		t2, 0(t1)
				sw		t2, 0(t0)
AENT_FUNC(RestoreTmpSP)
				la		t0, TmpSP
				sw		sp, 0(t0)
				la		t0, TmpSysSP
				la		t1, SysSP
				lw		t2, 0(t1)
				sw		t2, 0(t0)
				la		t0, TmpAppSP
				la		t1, AppSP
				lw		t2, 0(t1)
				sw		t2, 0(t0)
				la		t0, SaveTmpSPBack
				j		t0
FUNC_END(SaveTmpSP)
//==============================================================================
				.data
SysCallTable:
				.word	SysCallFptr

