www.pudn.com > arch.rar > core_support.S


/*
 *  TOPPERS/ASP Kernel
 *      Toyohashi Open Platform for Embedded Real-Time Systems/
 *      Advanced Standard Profile Kernel
 * 
 *  Copyright (C) 2000-2004 by Embedded and Real-Time Systems Laboratory
 *                              Toyohashi Univ. of Technology, JAPAN
 *  Copyright (C) 2006-2007 by Embedded and Real-Time Systems Laboratory
 *              Graduate School of Information Science, Nagoya Univ., JAPAN
 * 
 *  上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
 *  ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
 *  変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
 *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
 *      スコード中に含まれていること.
 *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
 *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
 *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
 *      の無保証規定を掲載すること.
 *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
 *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
 *      と.
 *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
 *        作権表示,この利用条件および下記の無保証規定を掲載すること.
 *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
 *        報告すること.
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
 *      また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
 *      由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
 *      免責すること.
 * 
 *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
 *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
 *  に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
 *  アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
 *  の責任を負わない.
 * 
 *  @(#) $Id: core_support.S 948 2008-04-14 08:34:27Z ertl-honda $
 */

/*
 *        コア依存モジュール アセンブリ言語部(ARM用)
 */

#define TOPPERS_MACRO_ONLY
#define TOPPERS_ASM_MACRO
#define UINT_C(val)		(val)		/* uint_t型の定数を作るマクロ */
#define ULONG_C(val)	(val)		/* ulong_t型の定数を作るマクロ */
#include "kernel_impl.h"
#include "offset.h"

#ifdef VECTOR_KERNEL
/*
 * 例外ベクタ
 */
    .section .vector,"a"
    .global vector_table
vector_table:
    ldr pc, reset_vector       /* リセット             */
    ldr pc, undef_vector       /* 未定義命令           */
    ldr pc, swi_vector         /* ソフトウェア割込み   */
    ldr pc, prefech_vector     /* プリフェッチアボード */
    ldr pc, data_abort_vector  /* データアボード       */
    ldr pc, reset_vector
    ldr pc, irq_vector         /* IRQ                  */
    ldr pc, fiq_vector         /* FIQ                  */


/*
 *  例外ベクタの命令から参照される
 *  ジャンプ先アドレス
 */
    .global vector_ref_tbl
vector_ref_tbl:
reset_vector:
    .long   start
undef_vector:
    .long   undef_handler
swi_vector:
    .long   swi_handler
prefech_vector:
    .long   prefetch_handler
data_abort_vector:
    .long   data_abort_handler
irq_vector:
    .long   irq_handler
fiq_vector:
    .long   fiq_handler
#endif

/*
 *  タスクディスパッチャ
 *
 */
    .text
    .align 2    
    .globl dispatch
dispatch:
    /*
     *  このルーチンは,タスクコンテキスト・CPUロック状態・ディスパッチ
     *  許可状態・(モデル上の)割込み優先度マスク全解除状態で呼び出さ
     *  れる.
     */
    stmfd sp!, {r4 - r11,lr}           /* レジスタの保存 */
    ldr   r0, =p_runtsk                /* p_runtskを読み込む */
    ldr   r1, [r0]
    str   sp, [r1,#TCB_sp]             /* タスクスタックを保存 */
    adr   r2, dispatch_r
    str   r2, [r1,#TCB_pc]             /* 実行再開番地を保存 */
    b     dispatcher

dispatch_r:
    ldmfd sp!,{r4 - r11,lr}     /* レジスタの復帰 */
    /*
     * タスク例外処理ルーチンの起動
     * dispatcherから呼び出されるため,TCBのアドレスはr1に入っている
     */
    ldrb  r0,[r1,#TCB_enatex]
    tst   r0,#TCB_enatex_mask
    beq   dispatch_r_1          /* enatex が false ならリターン */
    ldr   r0,[r1,#TCB_texptn]   /* texptn が0でなければ         */
    tst   r0,r0                 
    bne   call_texrtn           /* タスク例外ルーチンの呼び出し */
dispatch_r_1:   
    mov   pc,lr        


/*
 *  ディスパッチャの動作開始(cpu_support.S)
 */
    .globl start_dispatch
start_dispatch:
    /*
     *  このルーチンは,カーネル起動時に,すべての割込みを禁止した状態
     * (割込みロック状態と同等)で呼び出される.また,割込みモード(非
     *  タスクコンテキストと同等)で呼び出されることを想定している.
     *
     *  dispatcherは,CPUロック状態,(モデル上の)割込み優先度マスク全
     *  解除状態,例外(割込み/CPU例外)のネスト回数0で呼び出す.     
     *  target_initializeでは,(モデル上の)割込み優先度マスク全解除
     *  とし,カーネル管理外の割込みであるFIQを許可することで,
     *  CPUロック状態・(モデル上の)割込み優先度マスク全解除状態になる.
     *  また,task_initializeでdisdspをfalseに初期化しているため,ディ
     *  スパッチ許可状態になっている.
     *  
     */    
    msr   cpsr, #(CPSR_SVC|CPSR_CPULOCK|CPSR_ALWAYS_SET) /* CPUロック状態へ */
    ldr   r2, =excpt_nest_count            /* 例外(割込み/CPU例外)のネスト回数 */
    mov   r0, #0                           /* を0に                              */
    str   r0, [r2]
    b     dispatcher_0

/*
 *  現在のコンテキストを捨ててディスパッチ
 */
    .globl exit_and_dispatch
exit_and_dispatch:
    /* ディスパッチャ本体(dispatcher)へ */    

/*
 *  ディスパッチャ本体
 */
dispatcher:
    /*
     *  このルーチンは,タスクコンテキスト・CPUロック状態・ディスパッチ
     *  許可状態・(モデル上の)割込み優先度マスク全解除状態で呼び出さ
     *  れる.実行再開番地へもこの状態のまま分岐する.
     *
     *  すなわち,スーパーバイザーモード,IRQ禁止・disdspがfalse・dspflg
     *  がtrueとなっている.実行再開番地へもこの状態のまま分岐する.
     */
#ifdef LOG_DSP_ENTER
    ldr   r1, =p_runtsk     /* p_runtskをパラメータに */
    ldr   r0, [r1]        
    bl    log_dsp_enter
#endif /* LOG_DSP_ENTER */
dispatcher_0:
    ldr   r0, =p_schedtsk   /* p_schedtskをp_runtskに */
    ldr   r1, [r0]
    ldr   r2, =p_runtsk   
    str   r1, [r2]        
    cmp   r1, #0            /* p_runtskがNULLならdispatcher_1へ */
    beq   dispatcher_1             
    ldr   sp, [r1,#TCB_sp]  /* タスクスタックを復帰 */
#ifdef LOG_DSP_LEAVE
    mov   r0, r1            /* p_runtskをパラメータに */
    mov   r4, r1            /* r1はスクラッチレジスタなので保存 */
    bl    log_dsp_leave
    mov   r1, r4
#endif /* LOG_DSP_LEAVE */
    ldr   pc, [r1,#TCB_pc]  /* 実行再開番地を復帰   */    
dispatcher_1:
    /*
     * CPUロック状態の解除と,非タスクコンテキスト実行状態への
     * 準備をする
     */
    ldr   r0, =_kernel_istk            /* 非タスクコンテキストのスタックへ */
    ldr   sp, [r0]    
    ldr   r1, =_kernel_istksz
    ldr   r3, [r1]
    add   sp, sp, r3
    ldr   r2, =reqflg                  /* r2 <- reqflg */
    ldr   r3, =excpt_nest_count        /* r3 <-excpt_nest_count */
    mov   r0, #0
    mov   r1, #1
dispatcher_2:
    /*
     *  割込みを許可し,非タスクコンテキスト実行状態とし割込みを待つ.
     *
     *  ここで非タスクコンテキスト実行状態に切り換えるのは,ここで発生
     *  する割込み処理にどのスタックを使うかという問題の解決と,割込み
     *  ハンドラ内でのタスクディスパッチの防止という2つの意味がある.
     *
     *  プロセッサを割込み待ちに移行させる処理と,割込み許可とは,不可
     *  分に行なう必要がある.
     *  これを不可分に行なわない場合,割込みを許可した直後に割込
     *  みが入り,その中でタスクが実行可能状態になると,実行すべきタス
     *  クがあるにもかかわらずプロセッサが割込み待ちになってしまう.
     *
     *  割込み待ちの間は,p_runtskをNULL(=0)に設定しなければならな
     *  い.このように設定しないと,割込みハンドラからiget_tidを呼び出
     *  した際の動作が仕様に合致しなくなる.
     *
     *  ターゲットによっては,省電力モード等に移行するため,標準の方法と
     *  異なる手順が必要な場合がある.
     *  そのようなターゲットでは,ターゲット依存において,TOPPERS_CUSTOM_IDLE
     *  を定義し,アセンブラマクロとして,toppers_asm_custom_idle を用意
     *  すればよい.toppers_asm_custom_idle の記述にあたっては,次のレジ
     *  スタは使用できない.
     *     r0, r1, r2, r3, sp 
     *
     */
    str   r1, [r3]                          /* excpt_nest_count = 1 */

#ifdef TOPPERS_CUSTOM_IDLE
    toppers_asm_custom_idle
#else
    msr   cpsr, #(CPSR_SVC|CPSR_ALWAYS_SET) /* 割り込み許可(システムモード) */
    nop
    msr   cpsr, #(CPSR_SVC|CPSR_CPULOCK|CPSR_ALWAYS_SET) /* CPUロック(システムモード) */
#endif /* TOPPERS_CUSTOM_IDLE */

    ldr   r6, [r2]        /* reqflgがfalseならdispatcher_2へ */
    cmp   r6, #0          
    beq   dispatcher_2                 
    str   r0, [r2]        /* reqflgをfalseに */
    str   r0, [r3]        /* excpt_nest_count = 0 */
    b     dispatcher_0


/*
 *  カーネルの終了処理の呼出し
 *
 *  モードとスタックを非タスクコンテキスト用に切り替え.
 */
    .globl call_exit_kernel
call_exit_kernel:
    msr   cpsr, #(CPSR_SVC|CPSR_ALWAYS_SET) 
    ldr  r0, =_kernel_istkpt       /* 非タスクコンテキストのスタックへ */
    ldr  sp, [r0]
    b     exit_kernel


/*
 *  タスク開始時処理
 *
 *  dispatcherから呼び出されるため,TCBのアドレスはr1に入っている
 */
    .text
    .globl start_r
start_r:
    msr   cpsr, #(CPSR_SVC|CPSR_ALWAYS_SET) /* CPUロック解除状態に */
    ldr   lr, =ext_tsk                      /* 戻り番地設定 */
    ldr   r2, [r1, #TCB_p_tinib]            /* p_runtsk->p_tinibをr2に  */
    ldr   r0, [r2, #TINIB_exinf]            /* exinfを引数レジスタr0に  */
    ldr   r1, [r2, #TINIB_task]             /* タスク起動番地にジャンプ */
    mov   pc, r1 


/*
 *  割込みハンドラ/CPU例外ハンドラ出口処理
 *
 *  ret_intは,割込みハンドラから戻った直後に実行するルーチンで,
 *  割込みハンドラ終了後,ターゲット依存の処理を実行した後,
 *  カーネル管理の割込みを禁止,スタックを割込み前のスタックにした
 *  状態で呼び出される.
 */
    .text
    .global ret_int
    .global ret_exc
ret_int:
ret_exc:
    /*
     *  例外・割込みのネストカウント(excpt_nest_count)のデクリメント
     */        
    ldr   r0, =excpt_nest_count   /* r0 <-excpt_nest_count */
    ldr   r1, [r0]
    sub   r2, r1, #1
    str   r2, [r0]
    cmp   r2, #0                  /* 戻り先が非タスクコンテキストなら */
    bne   ret_int_1               /* すぐにリターン                   */

    /*
     *  reqflgをチェックする前に割込みを禁止するのは,reqflgをチェック
     *  した直後に割込みハンドラが起動され,その中でディスパッチが要求
     *  された場合に,すぐにディスパッチされないという問題が生じるため
     *  である.
     */
    ldr   r0, =reqflg
    ldr   r1, [r0]
    cmp   r1, #0                  /* reqflgがtrueであればret_int_2へ */
    bne   ret_int_2
ret_int_1:
    /*
     *  割込み処理からのリターンにより,CPUロック解除状態に移行しなければ
     *  ならない.    
     *  ARMでは,CPSRのIRQビットでCPUロック解除状態とするため,単にリターン
     *  すればよい.
     */                
    ldmfd sp!,{r1}              /* CPSRの復帰処理 */
    msr   spsr, r1              /* 戻り先のcpsrをspsrに設定 */
    ldmfd sp!,{r0-r3,ip,lr,pc}^ /* コンテキストの復帰,^付きなので、cpsr <- spsr */

    
ret_int_2:
ret_int_3:
    /*
     *  ここへは,CPU例外ハンドラの出口処理からも分岐してくる.
     *
     *  ここでは,戻り先がタスクであり,スタックは,タスクスタックの上
     *  にスクラッチレジスタのみが保存された状態になっている.また,
     *  プロセッサは,スーパーバイザーモード・カーネル管理の割込みを禁止
     *  した状態となっている.
     */    
    ldr   r0, =reqflg    /* reqflgをfalseに */
    mov   r1, #0
    str   r1, [r0]
    /*
     *  CPUロック状態に移行する.
     *
     *  この時点でCPUロック状態とするのは,dispatcherへ分岐する時と,
     *  call_texrtnを呼び出す時に,CPUロック状態になっている必要がある
     *  ためである.
     *
     *  ARMでは,CPSRのIRQビットでCPUロック状態を表現するため,ここでは,
     *  特に何も行わない.
     */
    
    /*
     *  dspflgがfalseである場合と,p_runtskとp_schedtskが同じ場合には,
     *  ディスパッチを行わない.このチェックが必要なのは,タスク例外処
     *  理ルーチンの呼出しが必要な場合に,ディスパッチが必要なくても,
     *  reqflgをtrueにするためである.
     */

    ldr   r0, =p_runtsk       /* p_runtsk をr1に読み込む */
    ldr   r1, [r0]
    ldr   r0, =dspflg
    ldr   r2, [r0]
    cmp   r2, #0              /* dspflgがfalseならret_int_4へ */
    beq   ret_int_4
    ldr   r0, =p_schedtsk     /* p_schedtsk をr2に読み込む */
    ldr   r2, [r0]
    cmp   r1, r2              /* p_runtskとp_schedtskが同じなら */
    beq   ret_int_4           /*                    ret_int_4へ */
    stmfd sp!, {r4-r11}       /* 残りのレジスタを保存 */
    str   sp, [r1,#TCB_sp]    /* タスクスタックを保存 */
    adr   r0, ret_int_r       /* 実行再開番地を保存   */
    str   r0, [r1,#TCB_pc]
    b     dispatcher

ret_int_r: 
    ldmfd sp!, {r4-r11}       /* レジスタの復帰 */    
ret_int_4:
    /*
     *  enatexがtrueで,texptnが0でなければ,タスク例外処理ルーチンを
     *  呼び出す.
     *  dispatcherから呼び出されるため,TCBのアドレスはr1に入っている
     */
    ldrb  r0, [r1,#TCB_enatex]
    tst   r0, #TCB_enatex_mask
    beq   ret_int_5              /* enatex が false なら ret_int5へ */
    ldr   r0, [r1,#TCB_texptn]   /* texptnをロード               */
    tst   r0, r0                 /* texptn が0で無ければ         */
    blne  call_texrtn            /* タスク例外ルーチンの呼び出し */            
ret_int_5:
    /*
     *  割込み処理からのリターンにより,CPUロック解除状態に移行するよ
     *  うにする.ARMはCPSRのIRQビットによってCPUロック状態を表してい
     *  るため,そのままリターンすればよい.
     */        
    ldmfd sp!, {r0}             /* spsr を復帰 */
    msr   spsr,r0               /* 戻り先のcpsrをspsrに設定 */
    ldmfd sp!,{r0-r3,ip,lr,pc}^ /* タスクに復帰 ^付きなので、cpsr <- spsr */    
    

/*
 * CPU例外ハンドラ
 *
 * CPU例外ハンドラは,非タスクコンテキストで実行する.
 * 
 */

/*
 *  未定義命令 例外ハンドラ
 */
    .text
    .align 2
    .global undef_handler
undef_handler:
    /* 
     *  タスクの動作時モード(スーパーバイザーモード)へ
     */
    msr   cpsr, #(CPSR_SVC|CPSR_CPULOCK|CPSR_ALWAYS_SET) 
    stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */

    /*
     * spsrと戻り番地を取得するために未定義モードへ
     */
    msr   cpsr, #(CPSR_UND|CPSR_CPULOCK|CPSR_ALWAYS_SET)
    mov   r0, lr
    mrs   r1, spsr    
    mov   r2, #EXCH_NO_UNDEF
    b     target_exc_handler


/*
 *  SWI 例外ハンドラ
 */
    .text
    .align 2
    .global swi_handler
swi_handler:
    /* 
     *  タスクの動作時モード(スーパーバイザーモード)へ
     *  元々スーパーバイザーモードだが,CPUロック状態とする
     */
    msr   cpsr, #(CPSR_SVC|CPSR_CPULOCK|CPSR_ALWAYS_SET) 
    stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */
    mov   r0, lr
    mrs   r1, spsr    
    mov   r2, #EXCH_NO_SWI
    b     target_exc_handler


/*
 *  プリフェッチアボード 例外ハンドラ
 */
    .text
    .align 2
    .global prefetch_handler
prefetch_handler:
    /* 
     *  タスクの動作時モード(スーパーバイザーモード)へ
     */
    msr   cpsr, #(CPSR_SVC|CPSR_CPULOCK|CPSR_ALWAYS_SET) 
    stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */

    /*
     * spsrと戻り番地を取得するためにアボートモードへ
     */
    msr   cpsr, #(CPSR_ABT|CPSR_CPULOCK|CPSR_ALWAYS_SET)
    mov   r0, lr
    mrs   r1, spsr    
    mov   r2, #EXCH_NO_PABORT
    b     target_exc_handler


/*
 *  データアボード 例外ハンドラ
 */
    .text
    .align 2
    .global data_abort_handler
data_abort_handler:
    /* 
     *  タスクの動作時モード(スーパーバイザーモード)へ
     */
    msr   cpsr, #(CPSR_SVC|CPSR_CPULOCK|CPSR_ALWAYS_SET) 
    stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */

    /*
     * spsrと戻り番地を取得するためにアボートモードへ
     */
    msr   cpsr, #(CPSR_ABT|CPSR_CPULOCK|CPSR_ALWAYS_SET)
    mov   r0, lr
    mrs   r1, spsr    
    mov   r2, #EXCH_NO_DABORT
    b     target_exc_handler


#ifndef TARGET_FIQ_HANDLER
/*
 *  FIQ 例外ハンドラ
 */
    .text
    .align 2
    .global fiq_handler
fiq_handler:
    /* 
     *  タスクの動作時モード(スーパーバイザーモード)へ
     */
    msr   cpsr, #(CPSR_SVC|CPSR_FIQ_BIT|CPSR_CPULOCK|CPSR_ALWAYS_SET) 
    stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */

    /*
     * spsrと戻り番地を取得するためにFIQモードへ
     */
    msr   cpsr, #(CPSR_FIQ|CPSR_FIQ_BIT|CPSR_CPULOCK|CPSR_ALWAYS_SET)
    mov   r0, lr
    mrs   r1, spsr    
    mov   r2, #EXCH_NO_FIQ
    b     target_exc_handler
#endif /* TARGET_FIQ_HANDLER */

/*
 *  微少時間待ち
 */
    .globl _sil_dly_nse
_sil_dly_nse:
    sub   r0, r0, #SIL_DLY_TIM1
    cmp   r0, #0
    bgt   _sil_dly_nse1
    movle pc, lr
_sil_dly_nse1:
    sub   r0, r0, #SIL_DLY_TIM2
    cmp   r0, #0
    bgt   _sil_dly_nse1
    movle pc, lr