⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpu_a.s

📁 UC/OS 在SparcLite 上的移植范例
💻 S
字号:
/*
; -----------------------------------------------------------------------
; File: cpuspl_a.s - Fujitsu SPARCLite CPU specific low level routines
;
; uC/OS Real-time multitasking kernel for the SPARCLite processor.
;
; Written by Brad Denniston (bradd@vpeng.com) Sept 1998
;
; Functions defined in this module:
;	void IRQTrap(void)			IRQ trap wrapper
;	void OSDisableInt(void)		disable interrupts when in SVC
;	void OSEnableInt(void)		enable interrupts when in SVC
;	void OSCtxSw(void)			context switch
;	void OSStartHighRdy(void)	start highest priority task
;	int IRQSetIntLevel( int ) 	Enable IRQs above level passed in. 
;   int IRQIntEnable(int IRQNumber) Enable interrupt level passed in
; -----------------------------------------------------------------------
*/

#include "bsp.h"
#include "cpu.h"

	.extern _OSTCBCur,4
	.extern _OSTCBHighRdy,4
/* DEBUG CODE */
	.extern _debval1,4
	.extern _debval2,4
	.extern _debval3,4
	.extern _debval4,4
/* END DEBUG CODE */

	.text
	.align 4
/*
; -----------------------------------------------------------------------
; IRQTrap - IRQ trap handler
; Wrapper to service the trap and call a high-level handler. This function 
; is called when any hardware interrupt occurs. The interrupt controller masks
; are modified to enable nested interrupts.
; At input, l1 is PC and l2 is NPC. Traps are disabled.
; 
; -----------------------------------------------------------------------
*/
	.globl _IRQTrap
_IRQTrap:
#if 0
/* DEBUG */
	sethi	%hi(_debval2), %l7
	st		%l6, [%lo(_debval2) + %l7] /* save %g1 */
/* END DEBUG */
#endif
	rd		%psr, %l0
	/* CRITICAL region - disable interrupts */
	or		%l0, 0x0F00, %l0
	wr		%l0, %g0, %psr

	/* From here on preserve l0, l1, l2 */
	sub		%sp, 104, %sp		

	/* check if in invalid register window before enabling interrupts */
	mov		%wim, %l4
	srl		%l4, %l0, %l5		/* wim >> cwp */
	cmp		%l5, 1
	bne		CPU_window_fine		/* Branch if not in the invalid window */
	nop
	
	/* 
	 * OH OOH, we are in the last window, handle window overflow
	 * %l4 is wim, cwp is at marked window. Save only next window onto stack
	 */
	mov		%g1, %l6		/* Save g1, we use it to hold the wim */
	srl		%l4, 1, %g1		/* create new wim by shifting 1 bit right */
	tst		%g1
	bg		CPU_good_wim	/* Branch if new wim is non-zero */
	nop

	/* 
  	 * At this point, we need to bring a 1 into the high order bit of the wim.
  	 * Since we don't want to make any assumptions about the number of register
  	 * windows, we figure it out dynamically so as to set up the wim correctly.
	 */
	not		%g1				/* Fill g1 with ones */
	mov		%g1, %wim		/* Fill the wim with ones */
	nop
	nop
	nop
	mov		%wim, %g1	/* Read back the wim */
	inc		%g1				/* Now g1 has 1 just to left of wim */
	srl		%g1, 1, %g1		/* Now put 1 at top of wim */
	mov		%g0, %wim		/* Clear wim so that subsequent save */
	nop						/*  won't trap */
	nop
	nop

CPU_good_wim:
	save					/* Slip into next window just to save registers */
	mov		%g1, %wim		/* Install the new wim */

	std		%l0, [%sp + 0 * 4]	/* save L & I registers */
	std		%l2, [%sp + 2 * 4]	/* stack space already set aside by */
	std		%l4, [%sp + 4 * 4]	/* the interrupted routine */
	std		%l6, [%sp + 6 * 4]

	std		%i0, [%sp + 8 * 4]
	std		%i2, [%sp + 10 * 4]
	std		%i4, [%sp + 12 * 4]
	std		%i6, [%sp + 14 * 4]

	restore					/* Go back to trap window. */
	mov		%l6, %g1		/* Restore %g1 */

CPU_window_fine:

	mov		%tbr, %l3			/* get the interrupt number  */
	and		%l3, 0x0FF0, %l3		/* l3 is value of tbr */
	srl		%l3, 4, %l3
	sub		%l3, 16, %o0			/* interrupt number (1 thru 15) in %o0 */

	/* clear the current interrupt in the interrupt sense register */
	mov		1,%l3
	sll		%l3,%o0,%l3				/* interrupt bit, min is 2 */
	set		(IRC_BASE), %l4
	add		%l4, 0x0C, %l4        	/* Base + 0C = Req Clear Reg address.*/
	sta     %l3, [%l4] IRC_ASI		/* clear interrupt sense bit */

	/* set IRLC to clear the interrupt latch, accept new interrupts */
	set		(IRC_BASE), %l4
	add     %l4, 0x14, %l4        	/* Base + 14 = IRLClear Register */
	set     (IRL_CLEAR>>16), %l3 	/* clear IRL latch via IRCL bit.*/
	sta     %l3, [%l4] IRC_ASI
	lda		[%l4] IRC_ASI, %l3		/* flush cache words to device */

	/* End of critical region. Enable all interrupts, allows nesting */
	andn	%l0, 0x0F00, %o1		/* hardware interrupts enabled */
	or		%o1, 0x0020, %o1		/* traps enabled */
	wr		%o1, %g0, %psr
	nop
	nop

	/* Call the high level interrupt dispatch routine */
	call	_CPUDispatchIRQ			/* call ISR dispatcher */	
	nop

	/* Critical region. Disable interrupts */
	or		%l0, 0x0F00, %o1		/* disable hardware ints */
	wr      %o1, %g0, %psr

	cmp		%o0, 0
	be		CPU_NoTaskSwitch
	nop
	call	_OSCtxSw				/* a different task must run */
	nop

	/* return to instruction where interrupt occured */
CPU_NoTaskSwitch:

	/* End Critical Region. Enable interrupts, disable traps */
	andn	%l0, 0x0F20, %o1		/* traps off, hardware interrupts on */
	wr		%o1, %g0, %psr

	or		%g0, 0x1, %l3			/* Set Restore Lock bit,*/
	or		%g0, 0x10, %l4			/*  in case an autolock sequence*/
	sta		%l3, [%l4] 1			/*  is in effect.*/

	jmpl	%l1, %g0				/* Return to instruction at pc */
	rett	%l2

/*
; -----------------------------------------------------------------------
;	OSDisableInt(void)
;	Disable IRQ via trap mode bit is PSW. This is a leaf routine.
; -----------------------------------------------------------------------
*/
	.globl	_OSDisableInt
_OSDisableInt:
	rd      %psr, %o0
	or		%o0, 0x0F00, %o0	/* disable hardware ints */
	wr      %o0, %g0, %psr
	retl						/* return to caller */
	nop

/*
; -----------------------------------------------------------------------
;	void OSEnableInt()
;	Enable IRQ via trap mode bit in PSW. This is a leaf routine
; -----------------------------------------------------------------------
*/
	.globl	_OSEnableInt
_OSEnableInt:
	rd		%psr, %o0
	andn	%o0, 0x0F00, %o0	/* interrupts enabled */
	wr		%o0, %g0, %psr
	retl						/* return to caller */
	nop

/*
; -----------------------------------------------------------------------
;	int IRQSetIntLevel( int ) Enable IRQs above level passed in. 
;	0 enables all interrupts. 15 cannot be blocked.
;	%o0 contains the new level. %o0 returns the old level.
;	This is a leaf function.
; -----------------------------------------------------------------------
*/
	.globl	_IRQSetIntLevel
_IRQSetIntLevel:
	sll		%o0, 8, %o1			/* line up bits with PSW level bits */	
	rd		%psr, %o0			/* put into o0 to return the value */
	andn	%o0, 0x0F00, %o2	/* turn off level bits, all ints enabled */
	or		%o1, %02, %o2
	wr		%o2, %g0, %psr
	and		%o0, 0x0F00, %o0
	retl
	srl		%o0, 8, %o0			/* return old level to caller */

/*
; -----------------------------------------------------------------------
; IRQIntEnable(int IRQNumber) Enable interrupt level passed in %o0. 
; Sets the corresponding bit of the Interrupt Mask Register.
; IRQNumber = 1..15
; This is a leaf routine.
; -----------------------------------------------------------------------
*/
	.globl IRQIntEnable
IRQIntEnable:
	set     (IRC_BASE), %o4
	add     %o4, 0x14, %o3        	/* %o3=IRLAT, IRLCLEAR address.*/
	add     %o4, 0x0C, %o4        	/* %o4=Req Clear Reg address.*/

	srl		%o1, 4, %o1				/* change tbr:tt to 1 bit mask */
	sub		%o1, 16, %o1
	mov		1, %o2
	sll		%o2, %o1, %o2			/* min value is 2 */
	sta     %o2, [%o4] IRC_ASI		/* clear interrupt sense bit */

	set     (IRL_CLEAR>>16), %o1 	/* clear IRL latch via IRCL bit.*/
	sta     %o1, [%o3] IRC_ASI

	lda		[%o4] IRC_ASI, %o1		/* flush cache words to device */
	nop
	nop

	lda		[%o3] IRC_ASI, %o1
	nop
	nop

	retl
	nop

/*
; -----------------------------------------------------------------------
;	void OSCtxSw(void)
;		Perform a context switch. Interrupts are disabled by caller.
;		Current context is caller's (OSSched) context.
; -----------------------------------------------------------------------
*/
	.globl	_OSCtxSw
_OSCtxSw:

	/* Save the current (caller's) context. First adjust stack space. */
	sub		%sp, 144, %sp		/* preserve double word alignment */

	std		%o6, [%sp + 30 * 4]	/* sp and pc */
	std		%o4, [%sp + 28 * 4]
	std		%o2, [%sp + 26 * 4]
	std		%o0, [%sp + 24 * 4]

	std		%g6, [%sp + 22 * 4]
	std		%g4, [%sp + 20 * 4]
	std		%g2, [%sp + 18 * 4]
	st		%g1, [%sp + 17 * 4]

	mov		%wim, %g2
	mov		%psr, %g3
	mov		%tbr, %g4
	mov		%y, %g5
	std		%g2, [%sp + 34 * 4] 	/* %psr in sp-1, %wim in sp-2 */
	std		%g4, [%sp + 32 * 4] 	/* %y in sp-3,  %tbr in sp-4 */

	/* Change sp in current TCB. */
	sethi	%hi(_OSTCBCur), %g1
	ld		[%lo(_OSTCBCur) + %g1], %g3	/* %g3 is addr of sp in TCB */
	st		%sp, [%g3]

	/* Save the current context and every context above this one.
	 * Since a call just occured but no save,
	 *  	we are not in last register window. 
	 */
	mov		%g2, %g1		/* copy %wim to %g3 */
	sll		%g1, 8, %g1
	or		%g1, %g2, %g1	/* %g1 has copy of wim in each of 2 low bytes */
	mov		1, %g3
	mov		%psr, %g4
	sll		%g3, %g4, %g3	/* g3 looks like wim but shows current window */
							/* will shift g3 left till it matches a bit in g2 */
	mov		%g0, %wim		/* blocks reg window underflow trap */
save_current_registers:
	/* Save this register window (and all previous windows) to stack.
	 * If csw not same as wim, restore (move up) and repeat
	 */
	std		%i6, [%sp + 14 * 4]
	std		%i4, [%sp + 12 * 4]
	std		%i2, [%sp + 10 * 4]
	std		%i0, [%sp + 8 * 4]

	std		%l6, [%sp + 6 * 4]
	std		%l4, [%sp + 4 * 4]
	std		%l2, [%sp + 2 * 4]
	std		%l0, [%sp + 0 * 4]

	/* Back up towards invalid window. */	
	restore
	sll		%g3, 1, %g3
	andcc	%g1, %g3, %g0
	be		save_current_registers
	nop
CPU_all_windows_saved:
	save
	mov		%g2, %wim

	/* NOTE: NO RETURN HERE */

/*
; -----------------------------------------------------------------------
;	void OSStartHighRdy(void)
;		Start the task with the highest priority;
; -----------------------------------------------------------------------
*/
	.globl	_OSStartHighRdy
_OSStartHighRdy:
	/* Change to stack of HighRdy task */
	sethi	%hi(_OSTCBHighRdy), %l0
	ld		[%lo(_OSTCBHighRdy) + %l0], %l1 /* points to TCB */
	sethi	%hi(_OSTCBCur), %l0
	st		%l1, [%lo(_OSTCBCur) + %l0]	/* change current TCB to HighRdy */
	ld		[%l1], %l1				/* first TCB word is pointer to stack */
	mov		%l1, %sp				/* sp now set to new context */
	nop
	nop

	/* restore the new context */
	ld		[%sp + 31 * 4], %o7	/* sp, pc */
	ldd		[%sp + 28 * 4], %o4
	ldd		[%sp + 26 * 4], %o2
	ldd		[%sp + 24 * 4], %o0

	ldd		[%sp + 22 * 4], %g6
	ldd		[%sp + 20 * 4], %g4
	ldd		[%sp + 18 * 4], %g2
	ld		[%sp + 17 * 4], %g1

	ldd		[%sp + 14 * 4], %i6
	ldd		[%sp + 12 * 4], %i4
	ldd		[%sp + 10 * 4], %i2
	ldd		[%sp + 8 * 4], %i0

	ldd		[%sp + 6 * 4], %l6
	ldd		[%sp + 4 * 4], %l4
	ldd		[%sp + 2 * 4], %l2	/* load current window registers */
	/* %l0 and %l1 used as working registers, restored later */

	ldd		[%sp + 32 * 4], %l0 	/* get %tbr and %y */
	mov		%l0, %tbr		/* note: most debuggers show this reg wrong */
	mov		%l1, %y

	/* keep csw of current %psr but get old PIL and PS bits */
	sethi	%hi(preserveg1), %l0
	st		%g1, [%lo(preserveg1) + %l0] /* save %g1 */
	rd      %psr, %g1
	and		%g1, 0xFFFFF0BF, %g1	/* keep current csw, S and ET (disabled) */
	ld		[%sp + 35 * 4], %l1 	/* get old psr */
	and		%l1, 0x0FC0, %l1		/* keep old int mask, PS bits */
	or		%l1, %g1, %g1			/* merge */
		/* @@@ NOTE: forces Supervisor mode for all code */
		/* Only use User mode when traps are used to get to OS */

	/*
	 * DURING RESTORE - only restore current register window.
	 * Set the wim to next higher window so that window underflow trap 
	 * restores those registers.
	 */
	and		%g1, 0x0007, %l0		/* WATCH OUT - check #windows in processor */
	add		%l0, 1, %l0				/* want to set wim to next window */
	and		%l0, 0x0007, %l0		/* clear any overflow */
	mov		1, %l1
	sll		%l1, %l0, %l1	
	mov		%l1, %wim				/* wim now at csw + 1 (wrapped to 0) */

	/* restore working registers */
	ldd		[%sp], %l0
	add		%sp, 144, %sp			/* recover area used for task state */

	/* put in the new psr (enables interrupts) */
	mov		%g1, %psr
	sethi	%hi(preserveg1), %g1
	retl							/* leaf return via %o7 */
	ld		[%lo(preserveg1) + %g1], %g1 /* restore %g1 */

/******************* End OSStartHighRdy ************************/

/*
; -----------------------------------------------------------------------
;	CPUDebugWriteMem
;	Write debug data to a memory location starting at debugptr.
; -----------------------------------------------------------------------
*/
	.globl	_CPUDebugWriteMem
	.reserve debugwritearea, 0x400, "bss", 8 
_CPUDebugWriteMem:
	sethi	%hi(debugptr), %o1
	ld		[%lo(debugptr) + %o1], %o2 	/* get addr of current byte */
	stb		%o0,[%o2]						/* write the byte */
	inc		%o2								/* address next byte */
	retl						/* return to caller */
	st		%o2,[%lo(debugptr) + %o1] 

	.data
curIRQlevel: 
	.word  -1
preserveg1:
	.word	0
debugptr:
	.word	debugwritearea
dplace:
	.word	debugwritearea
	.text

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -