2012/05/12

組込み用RTOS作成(μITRON風)2

タスクのディスパッチは、出来そうなので次は初っ端のタスク呼び出しをどうするか?考えた。要は最初のディスパッチのときにタスク関数のアドレスがスタックに積まれていれば、そこに戻る(ジャンプする)のでタスクを生成した時点でスタックの中身をいじっておけば良い。
こんな感じ。

/****************************************************/
// タスクの生成
// int taskID タスクID(0~TASK_MAX-1)
// void (*func_task)() タスク関数のアドレス
/****************************************************/
void cre_tsk(int taskID, void (*func_task)())
{
// スタック初期化
char* taskSP; // スタックポインタ
taskSP = &cTaskStack[taskID][0]; // スタック先頭アドレス
taskSP += TASK_STACK_SIZE; // スタック領域の終端
// 最初のdispatch用にタスクの先頭アドレスをスタックにセット
*--taskSP = (char)((long)func_task >> 24); // PUSH 戻りアドレス
*--taskSP = (char)((long)func_task >> 16); // PUSH 戻りアドレス
*--taskSP = (char)((long)func_task >> 8); // PUSH 戻りアドレス
*--taskSP = (char)((long)func_task); // PUSH 戻りアドレス
// 最初のdispatch用にダミーのレジスタ値をスタックにセット
*--taskSP = 0xa0; // PUSH A (dummy)
*--taskSP = 0x0a; // PUSH X (dummy)
*--taskSP = 0xbb; // PUSH B (dummy)
*--taskSP = 0xcc; // PUSH C (dummy)
*--taskSP = 0xdd; // PUSH D (dummy)
*--taskSP = 0xee; // PUSH E (dummy)
*--taskSP = 0x50; // PUSH H (dummy)
*--taskSP = 0x05; // PUSH L (dummy)
// TCB設定
TCB[taskID].iSP = (int)taskSP; // スタックポインタ保存
TCB[taskID].iWaitTime = 0; // 待ち時間設定
}

※ *--taskSP がわかりにくい表現だが、ポインタをデクリメントしてから値を代入している=スタックにPUSHする動作と同じ

これで、最初のディスパッチの時にタスク関数へ戻る(ジャンプする)準備ができた。
では、最初のディスパッチをしてみよう。
こんな感じ。

/****************************************************/
// リアルタイムOSのスタート
// 全タスク生成後1度だけコールする。
// コール後はタスクを起動し戻ってこない
/****************************************************/
void sta_TmRtos(void)
{
int i_dummy_sp; // OS起動前のスタックポインタ値保存用
TAU0_Channel0_Start(); // TmRtosOS用タイマ起動
iCurrentTaskID = 0; // TaskID = 0からスタート
dispatch(&i_dummy_sp, TCB[iCurrentTaskID].iSP); // ディスパッチ
}

※TAU0_Channel0_Start();は、これから作成するdly_tsk()で使用するインターバルタイマの起動。

タスク関連の変数などの定義はこんな感じ。


#define TASK_MAX 3 // タスク数
#define TASK_STACK_SIZE 128 // タスクスタックサイズ

typedef struct _TaskControlBlock{
int iSP; // スタックポインタ保存用
int iWaitTime; // 待ち時間
}TaskControlBlock;

TaskControlBlock TCB[TASK_MAX]; // タスクコントロールブロック
char cTaskStack[TASK_MAX][TASK_STACK_SIZE]; // タスク用スタック領域
int iCurrentTaskID; // 実行中タスクID

extern void dispatch(int* pSaveSP, int iRestoreSP);


次はrot_rdqとdly_tskを実装しよう。
続く


0 件のコメント:

コメントを投稿