www.pudn.com > vrtxtst.rar > INTIRQSK.S


;************************************************************************* 
; 
; 
;  IMPORTANT - USE OF THIS SOFTWARE IS SUBJECT TO LICENSE RESTRICTIONS 
;  CAREFULLY READ THE LICENSE AGREEMENT BEFORE USING THE SOFTWARE 
; 
; 
;************************************************************************* 
; ORIGIN UK 35-0450.05-400 
;****************************************************************** 
; 
;       ARM VRTRmc 
; 
;****************************************************************** 
; 
;       Description 
;       =========== 
; 
;       INTIRQSK.S - Interrupt Handler for IRQs with sw stack checking 
; 
; 
;       Revision History 
;       ================ 
; 
;       Version    Date       Author               Reason for Change 
;       1.0        14/03/96   Samsung & P.Cumming  Initial Version 
;                                                  Derived from beta 
;                                                  INTERRUP.S.   
;	1.1        03/06/96   P.Cumming            vmc_keep_FIQ_enable added 
;	1.2        30/09/96   P.Cumming            ui_enter_i check IRQ/FIQ race 
; 
;	This file contains modified versions of the ui_enter & ui_exit 
;	procedures ui_enter_i & ui_exit_i for IRQs with sw stack checking 
;	on.  This change is required because the stack limit register 
;	r10 needs to be loaded at the start of the interrupt with the  
;	correct IRQ stack limit.  This needs to be pushed and popped of 
;	the stack.  
;	This is not required for FIQs as r10 (stack limit) is banked. 
;                                                 
;******************************************************************* 
;**************************************************************************** 
;			ARM Constants 
;**************************************************************************** 
 
ResetV			EQU	0 
UndefInstrV		EQU	4 
SWIV			EQU	8 
PrefAbortV		EQU	&c 
DataAbortV		EQU	&10 
AddrExceptV		EQU	&14 
IRQV			EQU	&18 
FIQV			EQU	&1c 
ErrorV			EQU	&20 
LastV			EQU	&24 
 
UserMode		EQU	&10 
FIQMode			EQU	&11 
IRQMode			EQU	&12 
SVCMode			EQU	&13 
AbortMode		EQU	&17 
UndefMode		EQU	&1b 
MaskMode		EQU	&1f 
 
PSR_32Bit		EQU	&10 
ModeMask		EQU	&0000001f  
SubModeMask		EQU	&0000000f  
NoInt			EQU	&000000c0 
NoIRQInt		EQU	&00000080 
NoFIQInt		EQU	&00000040 
ThumbMode		EQU	&00000020 
IFConfig		EQU	&000000d0 
CCMask			EQU	&f0000000 
 
 
;**************************************************************************** 
;	External Symbols Declaration 
;**************************************************************************** 
 
	IMPORT	vmc_intr_count 
	IMPORT	vmc_timer_ticks 
	IMPORT	vmc_ticker 
	IMPORT	vmc_sched_needed 
	IMPORT	vmc_tresched 
	IMPORT	vmc_keep_FIQ_enabled 
 
	EXPORT	|ui_enter_i| 
	EXPORT	|ui_exit_i| 
 
	AREA	|C$$code$$interrupt|, CODE, READONLY, INTERWORK 
	 
	IF Thumb = {TRUE} 
	CODE32 
	ENDIF 
	 
c_intr_count	DCD	vmc_intr_count 
c_timer_ticks	DCD	vmc_timer_ticks 
c_sched_needed	DCD	vmc_sched_needed 
c_keep_FIQ_enabled DCD  vmc_keep_FIQ_enabled 
 
 
 
;**************************************************************************** 
;		ui_enter_i : Interrupt Enter Routine 
;**************************************************************************** 
; 
;	extern	void	ui_enter_i(void); 
; 
|ui_enter_i| 
; 
;	ui_enter stack frame 
; 
;	+---------------+ 
;	|    v1 - v5	| <---- sp 
;	+---------------+ 
;	|	lr	| 
;	+---------------+ 
;	|	spsr	| <---- ui_enter start part sp 
;	+---------------+ 
;	|    r0 - r3	| 
;	+---------------+ 
;	|	sl	| 
;	+---------------+ 
;	|	ip	| 
;	+---------------+ 
;	|	lr	| 
;	+---------------+ 
; 
	stmfd	sp!,{v1-v5,lr}		;save local variable & return address 
 
	ldr	v1,c_keep_FIQ_enabled	;load address of vmc_keep_FIQ_enabled 
	ldrb	v2,[v1]			;get vmc_keep_FIQ_enables 
	cmp	v2,#0			;check if we keep FIQ enabled 
 
;	interrupt disable --> IRQ & FIQ 
	mrs	v1,cpsr			;get CPSR 
	orreq	v2,v1,#NoInt		;IRQ & FIQ interrupt disable bit set 
	orrne	v2,v1,#NoIRQInt		;IRQ disable bit set 
	msr	cpsr,v2			;interrupt disable 
 
;	interrupt count inc & first interrupt check 
	ldr	v4,c_intr_count		;initial value = 0 
	ldrb	v3,[v4]			;get interrupt count 
	add	v3,v3,#1		;increment interrupt count 
	strb	v3,[v4]			;save interrupt count 
 
;	if not first interrupt, restore status & return 
	cmp	v3,#1			;first interrupt ? 
	beq	check_race 
	msr	cpsr,v1			;restore saved CPSR 
	ldmfd	sp!,{v1-v5,pc}		;return ui_enter_i 
 
check_race 
;	check race condition 
	mrs	v4,spsr			;get interrupted task's status 
	and	lr,v4,#ModeMask 
	cmp	lr,#SVCMode 
	beq	first_interrupt 
	msr	cpsr,v1 
	ldmfd sp!,{v1-v5,pc}		;return ui_enter_i 
 
first_interrupt 
;	first interrupt --> make task's interrupt stack frame 
	ldr	v3,[sp,#(13*4)]		;get interrupted task's return address 
	ldr	v5,[sp,#(11*4)]		;get interrupted task's stack limit 
	 
	mrs	v4,spsr			;get interrupted task's status 
	and	lr,v4,#ModeMask 
	bic	v2,v2,#ModeMask 
	orr	v2,v2,lr 
	msr	cpsr,v2			;change before interrupt mode 
 
	 
;	make task's interrupt stack frame 
; 
;	+---------------+ 
;	|	cpsr	| 
;	+---------------+ 
;	|    r0 - r3	| 
;	+---------------+ 
;	|	sl	| 
;	+---------------+ 
;	|	ip	| 
;	+---------------+ 
;	|	lr	| 
;	+---------------+ 
;	|	pc	| 
;	+---------------+ 
; 
	stmfd	sp!,{v3}		;save interrupted task's return address 
	stmfd	sp!,{r0-r3, v5, ip,lr}	;save scratch register to task's stack 
	stmfd	sp!,{v4}		;save interrupted task's status 
 
;	return to ui_enter start mode 
	msr	cpsr,v1			;return to interrupt mode 
	ldmfd	sp!,{v1-v5,pc}		;return ui_enter 
 
 IF Thumb = {TRUE} 
	CODE16 
;**************************************************************************** 
;		ui_exit_i : Interrupt Exit Routine 
;**************************************************************************** 
; 
;	extern	void	ui_exit(void); 
; 
|ui_exit_i| 
	ldr r2,=ui_exit_32 
	bx r2 
; 
;	ui_exit stack frame 
; 
;	+---------------+ 
;	|	spsr	| <---- Interrupted task processor status 
;	+---------------+ 
;	|    r0 - r3	| 
;	+---------------+ 
;	|	sl	| 
;	+---------------+ 
;	|	ip	| 
;	+---------------+ 
;	|	lr	| <---- Interrupted task program count 
;	+---------------+ 
; 
	CODE32 
	ALIGN 
ui_exit_32 
 ELSE 
|ui_exit_i| 
 ENDIF 
 
	ldr	r0,c_keep_FIQ_enabled	;load address of vmc_keep_FIQ_enabled 
	ldrb	r1,[r0]			;get vmc_keep_FIQ_enables 
	cmp	r1,#0			;check if we keep FIQ enabled 
 
;	interrupt disable --> IRQ & FIQ 
	mrs	r2,cpsr			;get CPSR 
	orreq	lr,r2,#NoInt		;IRQ & FIQ interrupt disable bit set 
	orrne	lr,r2,#NoIRQInt		;IRQ disable bit set 
	msr	cpsr,lr			;interrupt disable 
	 
;	interrupt count decrement & final interrupt exit check 
	ldr	r1,c_intr_count		;initial value = 0 
	ldrb	r3,[r1]			;get interrupt count 
	subs	r3,r3,#1		;check final interrupt exit 
	strb	r3,[r1]			;save interrupt count 
 
;	if not the outermost interrupt exit, return 
	ldmfd	sp!,{lr}		;get SPSR 
	and	r0,lr,#ModeMask		; 
	teqeq	r0,#SVCMode		;if outermost, check race condition 
   
	msrne	spsr,lr			;if not the outermost interrupt, 
 	ldmnefd	sp!,{r0-r3,r10,ip,pc}^	;then return to interrupted mode 
					 
  
 
; 
continue_interrupt 
	stmfd	sp!,{v1,v2,lr}		;save SPSR & v1-v2 
	ldr	v1,c_timer_ticks 
	ldr	r0,[v1]			;get vmc_timer_ticks -> vmc_ticker arg. 
	cmp	r0,#0			;timer tick interrupt issue ? 
	beq	timer_check_done	;if vmc_timer_ticks = 0, done 
	mov	v2,r2			;copy CPSR before interrupt disabling 
	add	r3,r3,#1		;vmc_intr_count++ 
	strb	r3,[r1]			; 
	mov	r1,#0			;clear vmc_timer_ticks 
	str	r1,[v1]			; 
 
handle_timeout 
;	interrupt enable ? 
	msr	cpsr,v2			;interrupt enable  
	bl	vmc_ticker		;void vmc_ticker(int ticks) 
;	interrupt disable ? 
	ldr	r0,c_keep_FIQ_enabled	;load address of vmc_keep_FIQ_enabled 
	ldrb	r1,[r0]			;get vmc_keep_FIQ_enables 
	cmp	r1,#0			;check if we keep FIQ enabled 
 
	orreq	lr,v2,#NoInt		;IRQ & FIQ interrupt disable bit set 
	orrne	lr,v2,#NoIRQInt		;IRQ disable bit set 
 
	msr	cpsr,lr			;interrupt disable 
;	check timer ticks 
	mov	r1,#0			; 
	swp	r0,r1,[v1]		;get & clear vmc_timer_ticks 
	cmp	r0,#0			;timer tick interrupt issue ? 
	bne	handle_timeout 
	ldr	r1,c_intr_count		;initial value = 0 
	ldrb	r3,[r1]			;get interrupt count 
	sub	r3,r3,#1		;check final interrupt exit 
	strb	r3,[r1]			;save interrupt count 
 
timer_check_done 
	ldr	v1,c_keep_FIQ_enabled	;load address of vmc_keep_FIQ_enabled 
	ldrb	v2,[v1]			;get vmc_keep_FIQ_enables 
	cmp	v2,#0			;check if we keep FIQ enabled 
 
	ldmfd	sp!,{v1,v2,lr}		;get SPSR & v1-v2 
	orreq	lr,lr,#NoInt		;FIQ & IRQ interrupt disable 
	orrne	lr,lr,#NoIRQInt		;IRQ disable bit set 
 
 IF Thumb = {TRUE} 
	bic lr,lr,#ThumbMode		;disable thumb mode if enabled 
 ENDIF 
	msr	spsr,lr			; 
	ldmfd	sp!,{r0-r3,r10,ip,lr}	; 
 
	subs	pc,pc,#0		;change to task mode &  
	nop				;interrupt disable 
	nop 
;	Changed to task mode 
	ldr	r2,c_sched_needed	;get rescheduling flag 
	ldrb	r0,[r2]			; 
	cmp	r0,#0			;check rescheduling task 
	blne	vmc_tresched		;call rescheduling procedure 
 
;	return to the interrupted task - interrupted task stack frame 
; 
;	+---------------+ 
;	|	cpsr	| 
;	+---------------+ 
;	|    r0 - r3	| 
;	+---------------+ 
;	|	sl	| 
;	+---------------+ 
;	|	ip	| 
;	+---------------+ 
;	|	lr	| 
;	+---------------+ 
;	|	pc	| 
;	+---------------+ 
; 
	ldmfd	sp!,{lr}		;recover the CPSR when the task was 
;	return to interrupted task will return if ARM or Thumb 
	msr	spsr, lr 
	ldmfd	sp!, {r0-r3,r10,ip,lr,pc}^ ;return to the interrupted task 
 
   
 
	END