📄 cpu_a.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 + -