OSDN Git Service

チケット #25999 「SIOポートのピン割り当ての変更」に対応
[toppersasp4lpc/asp.git] / asp / arch / arm_m_gcc / prc_support.S
1 /*
2  *  TOPPERS/ASP Kernel
3  *      Toyohashi Open Platform for Embedded Real-Time Systems/
4  *      Advanced Standard Profile Kernel
5  * 
6  *  Copyright (C) 2008 by Embedded and Real-Time Systems Laboratory
7  *              Graduate School of Information Science, Nagoya Univ., JAPAN
8  * 
9  *  上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
10  *  ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
11  *  変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
12  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
14  *      スコード中に含まれていること.
15  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
18  *      の無保証規定を掲載すること.
19  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
21  *      と.
22  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
23  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
24  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
25  *        報告すること.
26  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
27  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
28  *      また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
29  *      由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
30  *      免責すること.
31  * 
32  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
33  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
34  *  に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
35  *  アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
36  *  の責任を負わない.
37  * 
38  *  @(#) $Id: prc_support.S 1365 2008-09-28 07:23:15Z futl-takaki $
39  */
40
41 /*
42  *  プロセッサ依存モジュール アセンブリ言語部(ARM-M用)
43  */
44
45 #define TOPPERS_MACRO_ONLY
46 #define UINT_C(val)             (val)           /* uint_t型の定数を作るマクロ */
47 #define ULONG_C(val)    (val)           /* ulong_t型の定数を作るマクロ */
48 #define CAST(type, val) (val)           /* 型キャストを行うマクロ */
49
50 #include "kernel_impl.h"
51 #include "arm_m.h"
52 #include "offset.h"
53
54
55 /*
56  *  タスクディスパッチャ
57  */
58         .text
59         .syntax unified
60         .code 16
61         .global dispatch
62         .type dispatch, function
63 dispatch:
64         /*
65          *
66          *  このルーチンは,タスクコンテキスト・CPUロック状態・ディパッチ許可状態
67          *  ・(モデル上の)割込み優先度マスク全開状態で呼び出される.
68          */
69         stmfd sp!,{r4-r11,lr}         /* レジスタの保存 */
70         ldr   r0, =p_runtsk           /* p_runtskを読み込む */
71         ldr   r1, [r0]
72         str   sp, [r1,#TCB_sp]        /* タスクスタックを保存 */
73         ldr   lr, =dispatch_r         /* 実行再開番地を保存 */
74         str   lr, [r1,#TCB_pc]        
75         b     dispatcher
76
77         .text
78         .syntax unified
79         .code 16
80         .type dispatch_r, function
81 dispatch_r:
82         ldmfd sp!,{r4 - r11,lr}       /* レジスタの復帰 */
83         /*
84          * タスク例外処理ルーチンの起動
85          * dispatcherから呼び出されるため,TCBのアドレスはr1に入っている
86          */
87         ldrb  r0,[r1,#TCB_enatex]
88         tst   r0,#TCB_enatex_mask
89         beq   dispatch_r_1            /* enatex が false ならリターン */
90         ldr   r0,[r1,#TCB_texptn]     /* texptn が0でなければ         */
91         tst   r0,r0                 
92         bne   call_texrtn             /* タスク例外ルーチンの呼び出し */
93 dispatch_r_1:                     /* タスクへのcall_textnから戻る */
94         mov   pc,lr
95
96
97 /*
98  *  CPU例外エントリ
99  *
100  *  割込みエントリと処理の内容は同等だが,ログの種類が異なるため,
101  *  分けている.
102  */
103         .align 2
104         .syntax unified
105         .code 16
106         .global exc_entry_point
107         .type exc_entry_point, function
108 exc_entry_point:
109         /*
110          *  例外/割込みが発生すると,発生時にアクティブなスタックにスクラ
111          *  ッチレジスタ等が保存される.
112          *  この内容に加えて,CPU例外ハンドラへの情報として,basepri の値と,
113          *  EXC_RETURNの情報を加えて保存する.basepriの値は,CPU例外からの
114          *  リターン時に割込み優先度マスクの値を元に戻すためにも用いられる.
115          *
116          *   -----------
117          *  | EXC_RETURN|  
118          *   -----------
119          *  |  basepri  |  
120          *   -----------
121          *  |    R0     |  
122          *   -----------
123          *  |    R1     |
124          *   -----------
125          *  |    R2     |
126          *   -----------
127          *  |    R3     |
128          *   -----------
129          *  |    R12    |
130          *   -----------
131          *  |    LR     |
132          *   -----------
133          *  |    PC     |
134          *   -----------
135          *  |   xPSR    |
136          *   -----------
137          *
138          */
139
140         /*
141          *  割込み発生時の割込み優先度マスクをスタックに保存するため取得
142          */
143         mrs   r2, basepri             /* baepriの値を取得 */
144
145         /*
146          * 多重割込みかチェック
147          * EXC_RETURN(割込み時にLRに設定される値)をチェックして,例外発生時に
148          * アクティブなスタックを特定することで多重割込みか判定する.
149          */
150         tst   lr, #EXC_RETURN_PSP    /* 割込み元がMSPなら多重割込み */
151         beq   exc_entry_1            /* 多重割込みならexc_entry_1へ */
152         mrs   r0, psp                /* 一段目の割込みの場合はPSP上に */
153         stmfd r0!,{r2}               /* 割込み発生時の割込み優先度マスクを積む */
154         stmfd r0!,{lr}               /* EXC_RETURN を積む             */
155         msr   psp, r0                /* CPU例外ハンドラへの引数となる */
156         push  {lr}                   /* MSP上にもEXC_RETURN を積む    */ 
157         b     exc_entry_2
158 exc_entry_1:                     /* 多重割込みの場合 */
159         push  {r2}                   /* 割込み発生時の割込み優先度マスクを積む */
160         push  {lr}                   /* EXC_RETURN を積む             */ 
161         mov   r0, sp                 /* CPU例外ハンドラへの引数となる */
162
163         /*
164          *  共通処理
165          */
166 exc_entry_2:                     
167         mrs   r3, ipsr               /* ハンドラアドレスを取得 */
168         ldr   r1, =_kernel_exc_tbl
169         ldr   r2, [r1, r3, lsl #2]
170
171 #ifdef LOG_EXC_ENTER
172         push  {r0,r2,r3}
173         mov   r0, r3                 /* 例外番号をパラメータに  */
174         bl    log_exc_enter          /* log_exc_enterを呼び出す */
175         pop   {r0,r2,r3}
176         push  {r3}                   /* 例外番号をスタックへ    */
177 #endif /* LOG_EXC_ENTER */
178
179         /*
180          *  CPU例外ハンドラの呼び出し
181          */
182         blx   r2
183
184 #ifdef LOG_EXC_ENTER
185         pop   {r0}                   /* 例外番号を引数に        */
186         bl    log_exc_leave          /* log_exc_leaveを呼び出す */
187 #endif /* LOG_EXC_ENTER */
188
189         b     ret_exc
190
191
192 /*
193  *  割込みエントリ
194  */
195         .align 2
196         .syntax unified
197         .code 16
198         .global int_entry_point
199         .type int_entry_point, function
200 int_entry_point:
201         /*
202          *  割込み発生時の割込み優先度マスクをスタックに保存するため取得
203          */
204         mrs   r2, basepri             /* baepriの値を取得 */
205
206         /*
207          * 多重割込みかチェック
208          * EXC_RETURN(割込み時にLRに設定される値)をチェックして,例外発生時に
209          * アクティブなスタックを特定することで多重割込みか判定する.
210          */
211         tst   lr, #EXC_RETURN_PSP    /* 割込み元がMSPなら多重割込み */
212         beq   int_entry_1            /* 多重割込みならint_entry_1へ    */
213         mrs   r0, psp                /* 一段目の割込みの場合はPSP上に */
214         stmfd r0!,{r2}               /* 割込み発生時の割込み優先度マスクを積む */
215         stmfd r0!,{lr}               /* EXC_RETURN を積む             */
216         msr   psp, r0                /* CPU例外ハンドラへの引数となる */
217         push  {lr}                   /* MSP上にもEXC_RETURN を積む    */ 
218         b     int_entry_2
219 int_entry_1:                     /* 多重割込みの場合 */
220         push  {r2}                   /* 割込み発生時の割込み優先度マスクを積む */
221         push  {lr}                   /* EXC_RETURN を積む             */ 
222         mov   r0, sp                 /* 未定義の割込みが発生した場合の情報とする */
223
224         /*
225          *  共通処理
226          */
227 int_entry_2:                     
228         mrs   r3, ipsr               /* ハンドラアドレスを取得 */
229         ldr   r1, =_kernel_exc_tbl
230         ldr   r2, [r1, r3, lsl #2]
231
232 #ifdef LOG_EXC_ENTER
233         push  {r0,r2,r3}
234         mov   r0, r3                 /* 例外番号をパラメータに  */
235         bl    log_inh_enter          /* log_exc_enterを呼び出す */
236         pop   {r0,r2,r3}
237         push  {r3}                   /* 例外番号をスタックへ    */
238 #endif /* LOG_EXC_ENTER */
239
240         /*
241          *  割込みハンドラの呼び出し
242          */
243         blx   r2
244
245 #ifdef LOG_EXC_ENTER
246         pop   {r0}                   /* 例外番号を引数に        */
247         bl    log_exc_leave          /* log_exc_leaveを呼び出す */
248 #endif /* LOG_EXC_ENTER */
249
250
251
252 /*
253  *  割込み/例外出口
254  *
255  *  ret_exc/ret_intは,CPU例外/割込みハンドラから戻った直後に実行する
256  *  ルーチンである.
257  */
258 ret_exc:
259 ret_int:
260         /*
261          *  割込みロック状態とする.この時点では,CPUロック状態にはならない
262          * (basepriとlock_flagとsaved_iipmは更新しない).
263          *
264          *  割込みロック状態とするのは,戻り先のコンテキストのチェックと,
265          *  戻り先が非タスクコンテキストであった場合のリターンをアトミック
266          *  に行うためである.bsepriをCPUロックの値にすることでもアトミッ
267          *  クなチェックと復帰は可能であるが,割込みからリターンしても,
268          *  basepri の設定内容は元に戻らないため,使用することができない. 
269          *  一方,FAULTMASKは,割込みからのリターン処理によって,'0'にクリ
270          *  アされる.
271          */
272         cpsid f                        
273
274         /*
275          *  戻り先のコンテキストの判定
276          * 
277          *  割込みハンドラ実行にLRにセットされるEXC_RETURNをチェックして,戻り
278          *  先でMSPが使われていれば,割込み先が非タスクコンテキストと判定する.
279          */
280         pop   {r3}                     /* lrをスタックから取得         */
281         tst   r3, #EXC_RETURN_PSP      /* 戻り先がPSPなら ret_int_1 へ */
282         bne   ret_int_1
283         pop   {r1}                     /* 元の割込み優先度マスク(basepri)をr1へ */
284         b     ret_int_2                /* の値をMSPから取得 */
285
286         /*
287          *  一段目の割込みの出口処理
288          */
289 ret_int_1:
290         /*
291          *  PSP上からEXC_RETURNを削除
292          */
293         mrs   r2, psp                 
294         add   r2, r2, #4
295         msr   psp, r2                 
296
297         /*
298          *  reqflgをチェックする
299          * 
300          *  カーネル管理内の割込みは禁止した状態で実行する必要があるため,
301          *  FAULTMASKを'1'にした状態で実行する.
302          *  reqflgをチェックする前に割込みを禁止するのは,reqflgをチェック
303          *  した直後に割込みハンドラが起動され,その中でディスパッチが要求
304          *  された場合に,すぐにディスパッチされないという問題が生じるため
305          *  である.
306          */
307         ldr   r0, =reqflg             /* reqflgがfalseならそのまま戻る */
308         ldr   r1, [r0]
309         cbnz  r1, ret_int_3           /* trueならret_int_3へ           */
310         mrs   r2, psp                 /* 元の割込み優先度マスク(basepri) */
311         ldmfd r2!, {r1}               /* の値をPSPから取得 */
312         msr   psp, r2                 
313
314 ret_int_2:
315         /*
316          *  ここには割込みロック状態(FAULTMASKがセット)された状態で来る.
317          *  Threadモードからのリターンにより自動的に割込みロック解除状態になる.
318          *  割込み優先度マスクは割込み前に状態に戻す.
319          */ 
320         msr   basepri, r1             /* 割込み優先度マスクを割込み前に状態へ */
321         bx    r3                      /* リターン */
322
323
324 ret_int_3:
325         /*
326          *  ここでは,戻り先がタスクであり,PSP上にスクラッチレジスタと割
327          *  込み優先度マスク(basepri)が保存された状態になっている.また,
328          *  プロセッサは,Handlerモード・割込みロック状態となっている.
329          *  また,r0には,reqflgのアドレス,r3には割込み受付時のlrの値が保
330          *  持されている.
331          */
332         mov   r1, #0                   /* reqflgをfalseに */
333         str   r1, [r0]
334
335         /*
336          *  CPUロック状態に移行する.
337          *
338          *  カーネルの管理内の割込みを禁止するようにbasepriを設定し,
339          *  lock_flag と saved_iipm を更新する.saved_iipmは,戻り先の割込み
340          *  優先度マスク(の内部表現)に設定する.
341          *  この時点でCPUロック状態とするのは,dispatcherへ分岐する時と,
342          *  call_texrtnを呼び出す時に,CPUロック状態になっている必要がある
343          *  ためである.
344      *  なお,この処理の後,Threadモードへの移行処理を行なうため,割込み
345      *  ロック状態(FAULTMASKを"1")は保持する.
346          */
347         ldr   r1, =IIPM_LOCK          /* CPUロック状態 */ 
348         msr   basepri, r1          
349         mov   r1, #0x01               /* lock_flag を trueに */
350         ldr   r0, =lock_flag          
351         str   r1, [r0]             
352         mrs   r2, psp                 /* 割込み前の割込み優先度マスクを */
353         ldr   r1, [r2]                /* タスクスタックから取得         */
354         ldr   r0, =saved_iipm         /* saved_iipmに保存 */
355         str   r1, [r0]             
356
357         /*
358          *  Threadモードへ移行する.
359          *
360          *  dispatcherやcall_texrnを呼び出す場合は,Threadモードである必
361          *  要があるため,PSPスタック上にダミーの例外フレームを置いて,
362          *  擬似的に割込みハンドラからリターンする.
363          *  リターンと同時にFAULTMASKが自動的にクリアされ,カーネル管理外の
364          *  割込みが許可される.
365          */
366         ldr   r0, =ret_int_4          /* PC   */
367         ldr   r1, =EPSR_T             /* xPSR(Tビットが'1'である必要がある) */
368         stmfd r2!, {r0-r1}            /* ダミーフレームをスタック上に積む   */
369         sub   r2, #(EXC_FRAME_SIZE - (4*2)) /* r0-r3,r12,lrの内容は設定する必要がない */
370         msr   psp,r2                  
371         bx    r3                      /* Threadモードへ移行 */
372     
373 ret_int_4:
374         /*
375          *  上記の処理により,Threadモードで実行される.
376          *  dspflgがfalseである場合と,p_runtskとp_schedtskが同じ場合には,
377          *  ディスパッチを行わない.このチェックが必要なのは,タスク例外処
378          *  理ルーチンの呼出しが必要な場合に,ディスパッチが必要なくても,
379          *  reqflgをtrueにするためである.
380          */
381         ldr   r0, =p_runtsk       /* ディスパッチを行わない場合でも,r1にp_runtsk の値(TCB) */
382         ldr   r1, [r0]            /* が入っている必要があるので,先に読み込む */
383         ldr   r0, =dspflg         
384         ldr   r2, [r0]
385         cbz   r2, ret_int_r_1     /* dspflgがfalseならret_int_r_1へ */
386         ldr   r0, =p_schedtsk     
387         ldr   r2, [r0]
388         cmp   r1, r2              /* p_runtskとp_schedtskが同じなら */
389         beq   ret_int_r_1         /*                  ret_int_r_1へ */
390         stmfd sp!, {r4-r11}       /* 残りのレジスタを保存 */
391         str   sp, [r1,#TCB_sp]    /* タスクスタックを保存 */
392         ldr   lr, =ret_int_r      /* 実行再開番地を保存   */
393         str   lr, [r1,#TCB_pc]
394         b     dispatcher          /* ディスパッチャへ */
395
396 /*
397  * 割込みによりプリエンプトされたタスクへのリターン処理
398  *
399  * Threadモードで,ディスパッチャや割込みの出口処理から呼び出される.
400  * 割込みによりプリエンプトされたタスクへリターンするには,いったん
401  * Handlerモードに移行し,PCに0xfffffffdを代入してリターンする必要
402  * がある.そのため,SVCにより,SVCハンドラを呼び出し,Handlerモー
403  * ドへ移行する.
404  */
405         .text
406         .syntax unified
407         .code 16
408         .type ret_int_r, function
409 ret_int_r:
410         pop {r4-r11}                  /* レジスタの復帰 */
411 ret_int_r_1:
412         /*
413          *  enatexがtrueで,texptnが0でなければ,タスク例外処理ルーチンを
414          *  呼び出す.
415          *  dispatcherから呼び出されるため,TCBのアドレスはr1に入っている
416          */
417         ldrb  r0, [r1,#TCB_enatex]
418         tst   r0, #TCB_enatex_mask
419         beq   ret_int_r_2           /* enatex が false なら ret_int_r_2へ */
420         ldr   r0, [r1,#TCB_texptn]  /* texptnをロード                     */
421         cbz   r0, ret_int_r_2       /* '0'ならリターン */
422         bl    call_texrtn           /* タスク例外ルーチンの呼び出し */
423 ret_int_r_2:
424         svc   0                     /* SVCの呼び出し */
425
426 /*
427  *  SVCハンドラ
428  */
429         .text
430         .syntax unified
431         .thumb
432         .thumb_func
433         .global svc_handler
434         .type svc_handler, function
435 svc_handler:
436         /*
437          *  割込み処理からのリターンにより,CPUロック解除状態に移行するよ
438          *  う準備する.
439          */
440         cpsid f                       /* 割込みロック状態へ */
441         mrs   r0, psp
442         add   r0, #EXC_FRAME_SIZE     /* スタックを捨てる   */
443         msr   psp, r0
444         mov   r0, #0
445         ldr   r1, =lock_flag          /* CPUロック解除状態へ */
446         str   r0, [r1]
447         mrs   r0, psp                 /* 割込み優先度マスクをタスクスタック */
448         ldmfd r0!, {r1}               /* から取得                           */
449         msr   psp, r0
450         msr   basepri, r1             /* 割込み優先度マスクを設定           */
451         bx    lr                      /* リターン     */
452
453 /*
454  *  ディスパッチャの動作開始
455  */
456         .align  2
457         .thumb
458         .thumb_func
459         .globl start_dispatch
460 start_dispatch:
461         /*
462          *  このルーチンは,カーネル起動時に,すべての割込みを禁止した状態
463          * (割込みロック状態と同等)で呼び出される.また,割込みモード(非
464          *  タスクコンテキストと同等)で呼び出されることを想定している.
465          *
466          *  prc_initializeで,lock_flagをtrueに,saved_iipmをIIPM_ENAALLに
467          *  初期化しているため,カーネル管理外の割込みを許可することで,
468          *  CPUロック状態・(モデル上の)割込み優先度マスク全解除状態になる.
469          *  また,task_initializeでdisdspをfalseに初期化しているため,ディ
470          *  スパッチ許可状態になっている.
471          */
472         ldr   r0,=istkpt              /* MSPを初期化   */
473         ldr   r1,[r0]                 /* start_dispatch呼び出し時に呼び出し用に */
474         msr   msp, r1                 /* 使用しているため初期化する             */
475         ldr   r1, =IIPM_LOCK          /* カーネル管理内の割込みを禁止 */
476         msr   basepri, r1 
477         cpsie f                       /* カーネル管理外の割込みを許可 */
478         mov   r0, #CONTROL_PSP        /* PSPを有効に  */
479         msr   control, r0
480         isb                           /* control の操作後に必要 */
481
482 /*
483  *  現在のコンテキストを捨ててディスパッチ
484  */
485         .align  2
486         .thumb
487         .thumb_func
488     .globl exit_and_dispatch
489 exit_and_dispatch:
490         /* ディスパッチャ本体(dispatcher)へ */ 
491
492
493 /*
494  *  ディスパッチャ本体
495  */
496 dispatcher:
497         /*
498          *  このルーチンは,タスクコンテキスト・CPUロック状態・ディスパッチ
499          *  許可状態・(モデル上の)割込み優先度マスク全解除状態で呼び出さ
500          *  れる.
501          *
502          *  すなわち,Threadモード・lock_flagがtrue・disdspがfalse・dspflg
503          *  がtrue・saved_iipmがIIPM_ENAALLとなっている.実行再開番地へもこ
504          *  の状態のまま分岐する.
505          */
506 #ifdef LOG_DSP_ENTER
507         ldr   r1, =p_runtsk     /* p_runtskをパラメータに */
508         ldr   r0, [r1]        
509         bl    log_dsp_enter
510 #endif /* LOG_DSP_ENTER */
511 dispatcher_0:
512         ldr   r0, =p_schedtsk   /* p_schedtskをp_runtskに */
513         ldr   r1, [r0]
514         ldr   r2, =p_runtsk   
515         str   r1, [r2]        
516         cmp   r1, #0            /* p_runtskがNULLならdispatcher_1へ */
517         beq   dispatcher_1             
518         ldr   sp, [r1,#TCB_sp]  /* タスクスタックを復帰 */
519 #ifdef LOG_DSP_LEAVE
520         mov   r0, r1            /* p_runtskをパラメータに */
521         mov   r4, r1            /* r1はスクラッチレジスタなので保存 */
522         bl    log_dsp_leave
523         mov   r1, r4
524 #endif /* LOG_DSP_LEAVE */
525         ldr   pc, [r1,#TCB_pc]  /* 実行再開番地を復帰   */    
526 dispatcher_1:
527         /*
528          * CPUロック状態の解除と,非タスクコンテキスト実行状態への
529          * 準備をする
530          */
531         mov   r0, #CONTROL_MSP  /* MSPを有効に  */
532         msr   control, r0       
533         isb                     /* control の操作後に必要 */
534         ldr   r2, =reqflg       /* r2 <- reqflg */
535         ldr   r1, =IIPM_LOCK    /* 割込みロック状態の割込み優先度マスクの値 */
536         mov   r0, #0
537         ldr   r4, =lock_flag    /* CPUロック解除状態へ */
538         str   r0, [r4]
539 dispatcher_2:
540         /*
541          *  割込みを許可し,非タスクコンテキスト実行状態とし割込みを待つ.
542          *
543          *  ここで非タスクコンテキスト実行状態に切り換えるのは,ここで発生
544          *  する割込み処理にどのスタックを使うかという問題の解決と,割込み
545          *  ハンドラ内でのタスクディスパッチの防止という2つの意味がある.
546          *
547          *  プロセッサを割込み待ちに移行させる処理と,割込み許可とは,不可
548          *  分に行なう必要がある.
549          *  これを不可分に行なわない場合,割込みを許可した直後に割込
550          *  みが入り,その中でタスクが実行可能状態になると,実行すべきタス
551          *  クがあるにもかかわらずプロセッサが割込み待ちになってしまう.
552          *  ARM-Mでは,PRIMASKをセットした状態でWFIを呼び出すことで実現できる.
553          *  この状態で割込みが入ると,割込みは実行されず,WFIからリターンす
554          *  ることになるので,一旦割込みを許可して割込みハンドラを実行する.
555          *
556          *  割込み待ちの間は,p_runtskをNULL(=0)に設定しなければならな
557          *  い.このように設定しないと,割込みハンドラからiget_tidを呼び出
558          *  した際の動作が仕様に合致しなくなる.
559          *
560          */
561 #ifdef TOPPERS_CUSTOM_IDEL
562         toppers_asm_custom_idle
563 #else
564         cpsid i               /* PRIMASK をセット */
565         msr   basepri, r0     /* 全割込み許可 */ 
566         wfi
567         cpsie i               /* PRIMASK をクリア(割込みを受け付ける) */
568         msr   basepri, r1     /* CPUロック状態へ */ 
569 #endif /* TOPPERS_CUSTOM_IDLE */
570
571         ldr   r6, [r2]        /* reqflgがfalseならdispatcher_2へ */
572         cmp   r6, #0
573         beq   dispatcher_2
574         str   r0, [r2]        /* reqflgをfalseに */
575
576         /*
577          *  CPUロック状態に戻す.割込み待ちの間に実行した割込みハンドラによ
578          *  り,saved_iipmが書き換えられる可能性があるため,元の値に戻す必
579          *  要がある.dispatcherが実行される時は,saved_iipmがIIPM_ENAALL
580          *  となっているため,ここではsaved_iipmをIIPM_ENAALL(=0)に戻せ
581          *  ばよい.
582          */
583         mov   r0, #CONTROL_PSP  /* PSPを有効に  */ 
584         msr   control, r0      
585         isb                     /* control の操作後に必要 */
586         mov   r2, #1            /* lock_flagをtrueへ */
587         ldr   r4, =lock_flag  
588         str   r2, [r4]
589         ldr   r4, =saved_iipm   /* saved_iipm を0に */
590         mov   r0, #0
591         str   r0, [r4]
592         b     dispatcher_0
593
594
595 /*
596  *  カーネルの終了処理の呼出し
597  *
598  *  スタックを非タスクコンテキスト用に切り替え.
599  *  
600  */
601         .text
602         .syntax unified
603         .code 16
604         .globl call_exit_kernel
605         .type call_exit_kernel, function
606 call_exit_kernel:
607         mov   r0, #CONTROL_MSP
608         msr   control, r0       /* MSPを有効に  */
609         isb                     /* control の操作後に必要 */
610         b     exit_kernel       /* カーネルの終了処理を呼ぶ */
611
612
613 /*
614  *  タスク起動処理
615  *
616  *  dispatcherから呼び出されるため,TCBのアドレスはr1に入っている
617  *
618  */ 
619         .text
620         .syntax unified
621         .code 16
622         .global start_r
623         .type start_r, function
624 start_r:
625         mov   r0, #0
626         ldr   r4, =lock_flag                    /* CPUロック解除状態へ */
627         str   r0, [r4]
628         msr   basepri, r0                       /* 割込み許可   */
629         ldr   lr, =ext_tsk                      /* 戻り番地設定 */
630         ldr   r2, [r1, #TCB_p_tinib]            /* p_runtsk->p_tinibをr2に  */
631         ldr   r0, [r2, #TINIB_exinf]            /* exinfを引数レジスタr0に  */
632         ldr   r1, [r2, #TINIB_task]             /* タスク起動番地にジャンプ */
633         mov   pc, r1 
634
635 /*
636  *  微少時間待ち
637  */
638         .text
639         .syntax unified
640         .code 16
641         .globl sil_dly_nse
642         .type sil_dly_nse, function
643 sil_dly_nse:
644         sub   r0, r0, #SIL_DLY_TIM1
645         cmp   r0, #0
646         bgt   sil_dly_nse1
647         mov   pc, lr
648 sil_dly_nse1:
649         sub   r0, r0, #SIL_DLY_TIM2
650         cmp   r0, #0
651         bgt   sil_dly_nse1
652         mov   pc, lr