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

📄 os_cpu_a.s79

📁 ucosii在sharp7a400上的移植
💻 S79
字号:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $Workfile:   os_cpu_a.s79  $
; $Revision:   1.0  $
; $Author:   WellsK  $
; $Date:   Apr 27 2004 12:11:04  $
; 
; Project: Lh7A400 MicroCos-II assembly code
;
; Description:
;     Assembly language files for the MicroCos-II OS and the LH7A400
;     port.
;
; Revision history:
; $Log:   //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps/lh7a400/ports/ucosii/os_cpu_a.s79-arc  $
;
;   Rev 1.0   Apr 27 2004 12:11:04   WellsK
;Initial revision.
;
;  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
; OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
; AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES, 
; SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
; 
; SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY 
; FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A 
; SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
; FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
; 
; COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
;     CAMAS, WA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    EXPORT ucos_irq_handler
    EXPORT OSStartHighRdy
    EXPORT OS_TASK_SW
    EXPORT OSCtxSw
    EXPORT OSIntCtxSw

    IMPORT OSRunning
    IMPORT OSTaskSwHook
    IMPORT OSTCBHighRdy
    IMPORT OSTCBCur
    IMPORT OSPrioHighRdy
    IMPORT OSPrioCur
    IMPORT OSIntNesting
    IMPORT OSIntEnter
    IMPORT OSTimeTick
    IMPORT OSIntExit
    IMPORT irq_func_ptrs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Private defines and data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MODE_SVC             EQU 0x00000013
MODE_DIS_IRQ         EQU 0x00000080
INTC_BASE_ADDR       EQU 0x80000500
INTC_SOURCE_OFF      EQU 0x00000000
INTC_TIMER1_INT_MASK EQU 0x00000100
TIMER1_INT_CLR       EQU 0x80000C0C
INTC_FIRST_IRQ       EQU 5

    RSEG CODESEG : CODE (2)
    CODE32 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: OSStartHighRdy
;
; Purpose: Set highest priority uCos-II task ready to run
;
; Description:
;     Call the OSTaskSwHook() function. Set OSRunning to TRUE. Get the
;     address of the highest priority task control block. Get the
;     stack pointer for the highest prior task (from the fetched TCB).
;     Set the current stack pointer to the fetched stack pointer. Set
;     the current task control block pointer to the highest priority
;     task control block pointer. Restore the new task's SPSR and CPSR
;     registers. Restore all ARM registers for the task and continue
;     the task.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes: This function should never be called from the IRQ level.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
OSStartHighRdy
    BL OSTaskSwHook                   ; Call OSTaskSwHook
    LDR r0, =OSRunning
    MOV r1, #1
    STRB r1, [r0]                     ; OSRunning = TRUE

    LDR r0, =OSTCBHighRdy             ; Get highest priority TCB
    LDR r0, [r0]                      ; Get waiting task TCB address
    LDR sp, [r0]                      ; Switch to the new task stack

    B OSCtxSw_from_start              ; Start first task

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: OS_TASK_SW (also known as OSCtxSw)
;
; Purpose: Task level context switch
;
; Description:
;     Save the current task registers and status on the task stack.
;     Save the current task stack pointer in the current TCB. Call
;     the OSTaskSwHook() function. Set OSPrioCur = OSPrioHighRdy.
;     Branch to the switch_tcb() function to restore the context of
;     the new task.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes: This function should never be called from the IRQ level.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
OS_TASK_SW
OSCtxSw
    STMFD sp!, {lr}                   ; Save resume address
    STMFD sp!, {r0-r12, lr}           ; Save current task registers
    MRS r0, cpsr
    STMFD sp!, {r0}                   ; Save current CPSR

    LDR r0, =OSTCBCur
    LDR r0, [r0]                      ; Get pointer to current TCB
    STR sp, [r0]                      ; Save stack pointer of cur task

    BL OSTaskSwHook                   ; Call OSTaskSwHook

OSCtxSw_from_int
    LDR r0, =OSTCBHighRdy             ; Get highest priority TCB
    LDR r2, [r0]                      ; Get waiting task TCB address
    LDR r0, =OSTCBCur                 ; Get current TCB
    STR r2, [r0]                      ; OSTCBCur = OSTCBHighRdy
    LDR sp, [r2]                      ; Get new task stack pointer

    LDR r0, =OSPrioHighRdy            ; Get highest priority address
    LDRB r1, [r0]                     ; Get highest priority
    LDR r0, =OSPrioCur                ; Get current priority address
    STRB r1, [r0]                     ; OSPrioCur = OSPrioHighRdy

OSCtxSw_from_start
    LDMFD sp!, {r0}                   ; Get CPSR value - this will be
    MSR spsr_cf, r0                   ; restored on function resume
    LDMFD sp!, {r0-r12, lr, pc}^      ; Load task registers and continue
                                      ; task 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: OSTickISR
;
; Purpose: OS timer tick
;
; Description:
;     See function comments.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes:
;     This function will always be called from ucos_irq_handler() on
;     a timer interrupt. All other interrupts are handled directly in
;     the ucos_irq_handler() function.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
OSTickISR
; At this point, the real handling of the interrupt is done and the
; context change for the task and ARM core may need to be done. The ARM
; core is presently in the ARM IRQ mode and may have nested interrupts.
; Call the OSIntEnter(), OSTimeTick(), and OSIntExit() functions.
    BL OSIntEnter                     ; Call OSIntEnter()
    BL OSTimeTick                     ; Call OSTimeTick()
    BL OSIntExit                      ; Call OSIntExit()

; A task context is not needed if the current and highest priority
; tasks are the same. Check the TCB pointers. If they are the same,
; just return from the interrupt and continue the task that was
; already running.
    LDR r8, =OSTCBCur
    LDR r9, =OSTCBHighRdy
    LDR r8, [r8]
    LDR r9, [r9]
    CMP r8, r9                        ; Are current and next TCB's
                                      ; the same?
    BEQ no_switch                     ; If the same, then just exit IRQ

; The ARM core is still in IRQ mode. The task's r0-12 registers and the
; task resume address (lr) are saved on the IRQ mode stack, but need to
; be saved on the task's stack. The task's original link register (lr
; in the task's mode) and the task's ARM core mode (CSPR) also need to
; be saved on the task's stack).

    BL OSTaskSwHook                   ; Call OSTaskSwHook()

    MRS r0, spsr                      ; Get interrupted task's mode
    STMFD sp!, {r0}                   ; Save task's CPSR on IRQ stack
                                      ; so task mode can use it

; Restore the IRQ stack pointer
    ADD sp, sp, #4                    ; Restore stack pointer from CPSR
    LDMFD sp!, {r0-r12, lr}           ; Restore registers to task state

; Go into task mode with interrupts disabled
    MRS r0, spsr                      ; Get interrupted task's mode
    ORR r0, r0, #MODE_DIS_IRQ         ; Disable interrupts in task mode
    MOV r1, sp                        ; Get IRQ stack pointer - this is
                                      ; need for task mode
    MSR cpsr_cf, r0                   ; Switch to task mode with
                                      ; interrupts disabled

; Get task's PC from IRQ stack
    LDR r0, [r1, #-4]                 ; Get task's resume address
    STMFD sp!, {r0}                   ; Save resume address

    STMFD sp!, {r2-r12, lr}           ; Save task's registers
    LDR r0, [r1, #-60]                ; Get task's CPSR
    LDR r2, [r1, #-52]                ; Restore task's r1
    LDR r1, [r1, #-56]                ; Restore task's r0
    STMFD sp!, {r0-r2}                ; Save r0, r1, and CPSR

; The task state is now saved on the task stack. Adjsut the stack size
; by one more word to account for the saved resume address and save
; the task stack pointer
    LDR r0, =OSTCBCur
    LDR r0, [r0]                      ; Get pointer to current TCB
    STR sp, [r0]                      ; Save stack pointer of cur task

    B OSCtxSw_from_int                ; Switch to new task

no_switch
    LDMFD sp!, {r0-r12, pc}^          ; Restore and exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: OSIntCtxSw
;
; Purpose: OS interrupt level task context switch
;
; Description:
;     This function does nothing. The real interrupt level task context
;     switch is done after the return from the OSIntExit() function in
;     OSTickISR() function. It's a bit easier to do it there, makes
;     register restoration easier, and the IRQ mode stack pointer is
;     already in the correct position. The call to OSTaskSwHook() is
;     still performed here.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes:
;     This function is called from OSIntExit() to perform a task level
;     context switch.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
OSIntCtxSw
    MOV pc, lr

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Function: ucos_irq_handler
;
; Purpose: Main interrupt (IRQ) handler for uCos-II
;
; Description:
;     See function comments.
;
; Parameters: NA
;
; Outputs; NA
;
; Returns: NA
;
; Notes:
;     This function works with the LH7A404 interrupt driver and uses
;     data initialized and maintained with that driver.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ucos_irq_handler
; Save registers we use for the interrupt
    SUB    lr, lr, #4                 ; Adjust lr to real return address
    STMFD  sp!, {r0-r12, lr}

; Read the interrupt controller pending register
    LDR    r1, =INTC_BASE_ADDR
    LDR    r0, [r1, #INTC_SOURCE_OFF]

; Was it a timer 1 interrupt?
    LDR r2, =INTC_TIMER1_INT_MASK
    AND r3, r0, r2                    ; Mask off timer 1 interrupt bit
    CMP r3, r2                        ; Was it a timer 1 interrupt?
    BNE intc_not_timer                ; Not a timer interrupt

; This was a timer interrupt, so clear the timer and perform ThreadX
; context switching
    LDR r3, =TIMER1_INT_CLR           ; Timer 1 interrupt clear address
    STR r0, [r3]                      ; Clear the timer 1 interrupt
    B OSTickISR                       ; Perform OS timer tick

intc_not_timer
; Loop through all the enabled interrupts and jump to the function
; for the first pending interrupt
    LDR r1, =INTC_FIRST_IRQ           ; Get first interrupt to check
    MOV r2, #0x00000001               ; Interrupt bit mask

; Start checking pending interrupt states
int_check
    MOV r3, r2, LSL r1                ; Build interrupt mask
    AND r4, r0, r3                    ; Check just one bit at a time
    CMP r4, r3                        ; Is interrupt pending?
    BEQ int_found                     ; Interrupt was found, handle it
    ADD r1, r1, #1                    ; Check next interrupt bit
    CMP r1, #0x1F                     ; Was this the last interrupt?
    BLE int_check                     ; Check next interrupt

; If the program made it to here, then the interrupt was not found,
; so just return to the caller, as we can do nothing
int_not_found
    B int_exit

; A pending interrupt was found, so jump to it's handler
int_found
    LDR r0, =irq_func_ptrs            ; Get address of jump table
    ADD r0, r0, r1, LSL #2            ; Add by interrupt offset
    LDR r0, [r0]                      ; Get handler address
    CMP r0, #0                        ; Is handler address NULL?
    BEQ int_exit                      ; If null, the exit
    MOV lr, pc                        ; Will return to int_exit
                                      ; handler, it is best to save all
                                      ; registers, so none get corrupted
    MOV pc, r0                        ; Jump to handler

; Exit the interrupt function
int_exit
    LDMFD sp!, {r0-r12, pc}^          ; Restore and exit

    END

⌨️ 快捷键说明

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