リアルタイムモニタ(ZealMon)の製作 [Z80]
Twitter(X)のタイムラインで Z80 のスタックを使ったタスク管理の話題(スタック上にタスクアドレスを並べて順次呼び出すもの)を見てリアルタイムモニタ(リアルタイムOS)を作ってみたくなりました。
リアルタイムOSに関してはネット上にも多くの情報があり、例えばここや "リアルタイム処理の基礎知識" 等に簡潔にまとめられています。
とは言ってもあまり本格的なものではなく、ライトウェイトである程度高速なものを作りたいと思います。今回作成した Z80 用のリアルタイムモニタ(以降、ZealMon と記す)の特徴を列挙すると
イベント管理、セマフォ、タスク間のメッセージ管理などの機能はまだありませんが、タイマー管理と同様にすることで追加実装は割合楽だと思います。
タスクコントロールブロック(TCB)の構造は下記のようにしました。
最近動かしている手持ちの Z80 ボードではタイマー割込みを自由に設定できるものが無かったのでネット上で公開されている MSX のエミュレータである MSXPen で試すことにしました。
周期割込みとして MSX の垂直帰線割り込み(1/60秒周期)を使用します。割込みモードは mode1(RST 38H 実行) です。
リアルタイムモニタが動作中の時は割込みでタスク切替が発生しているのでディバッガでブレークしてもディバッガ自身がブレークしたタスクと同じタスクの扱いになり、他のタスクが文字表示等のシステムコールをしている場合、リエントラントにコールすることになるので直ぐにハングしてしまいます。
結局ディバッガはあまり役に立たずに机上ディバッグ(若しくは割込み機能を停止した上のでブレーク確認)がメインになります。仕事であればICEが使えるのですが、個人としてはそんな高価なものは持っていません。
下図は MSXPen でデモプログラムを実行した際の画面です。
表示が競合し易くなるように1文字表示毎にタイマーウェイトを入れています。
下図はディスパッチが最初に実行される直前とタスク3が実行開始した時点でのワークエリアのダンプ表示です。割込みの影響を無くすため、フックした新たな割込み処理の先頭をリターンコードに書き換えています。
画面中央のダンプ情報からディスパッチ前はタスク1~3がプライオリティ 0 のレディキューにつながっているのが判ります。タスク0は前述のアイドルタスクでプライオリティ3のレディキューにつながっています。下側のダンプはタスク3実行開始時のメモリで実行タスク番号が3でタイマーウェイトキューにタスク1とタスク2が繋がっています。
まだ最適化はしていませんが、ソースも貼っておきます。無いとは思いますが今後、Z80 でリアルタイム制御したい場合に役に立つかもしれませんw
Twitter(X)に投稿した動画付きメッセージを貼っておきます。
本確認で実施した割込み試験プログラムのリストを下記に示します。割込みが入った場合、リターンアドレスとコール元のコードを保存するようにしました。
★追記 2023/10/06
上記の様にシステムコール内で割込み許可していることが判ったので、システムコール時は割込みは許可状態のままにしてタスクをディスパッチしない様にしてみました(システムコール毎のタイマーウェイトを無くし、ラウンドロビンコールを追加)。
その結果、下図のように表示が競合する場合には互いに1文字ずつ表示するようになりました。割込み処理の空振りが無いのでタイマー管理も正確になったはずです。
MSX-DOS 上で GAME 言語を使って BIOS 内の EI(0FBH)を検索した結果を貼っておきます。38H の割込みのエントリーが 0DDA9H なので割込み処理も含まれているのでしょうが結構あるものですね。
ざっと見た感じ、最後の二つは相対ジャンプのオフセット値ですが、他は EI 命令のコードのようですね。
[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]
リアルタイムOSに関してはネット上にも多くの情報があり、例えばここや "リアルタイム処理の基礎知識" 等に簡潔にまとめられています。
とは言ってもあまり本格的なものではなく、ライトウェイトである程度高速なものを作りたいと思います。今回作成した Z80 用のリアルタイムモニタ(以降、ZealMon と記す)の特徴を列挙すると
- 実装機能は必要最小限
- 実行中のタスクの中断(プリエンプト)可能
- タイマーウェイト機能
- プライオリティは4レベル(拡張は容易)
- ラウンドロビンタスク切替え要求機能
- ライトウェイト
モニタ本体のコードは約 300 バイト
- タスクの状態遷移はキューで管理
TCB(タスクコントロールブロック)内にタスク状態情報を持たず状態書換え処理を省略し軽量化
- アイドルタスクの実装省略
最低プライオリティでウェイト状態にならないタスクを持ついことで、レディ状態のタスクが無い時に実行するアイドルタスクの実装を省きました。番兵的な発想ですね。
イベント管理、セマフォ、タスク間のメッセージ管理などの機能はまだありませんが、タイマー管理と同様にすることで追加実装は割合楽だと思います。
タスクコントロールブロック(TCB)の構造は下記のようにしました。
name | offset | bytes | mearn |
---|---|---|---|
TcList | 0 | 2 | address for TCB link |
TcTskNo | 2 | 1 | high nibble:priority(0:highest) low nibble:task No. |
TcTim | 3 | 1 | timer count |
TcEvCnt | 4 | 1 | how many waiting event except timer |
TcSP | 5 | 2 | stack pointer save area |
TcStat | 7 | 1 | task status !! not used !! |
最近動かしている手持ちの Z80 ボードではタイマー割込みを自由に設定できるものが無かったのでネット上で公開されている MSX のエミュレータである MSXPen で試すことにしました。
周期割込みとして MSX の垂直帰線割り込み(1/60秒周期)を使用します。割込みモードは mode1(RST 38H 実行) です。
リアルタイムモニタが動作中の時は割込みでタスク切替が発生しているのでディバッガでブレークしてもディバッガ自身がブレークしたタスクと同じタスクの扱いになり、他のタスクが文字表示等のシステムコールをしている場合、リエントラントにコールすることになるので直ぐにハングしてしまいます。
結局ディバッガはあまり役に立たずに机上ディバッグ(若しくは割込み機能を停止した上のでブレーク確認)がメインになります。仕事であればICEが使えるのですが、個人としてはそんな高価なものは持っていません。
MSXPen 上では動作が中々安定せず悩みましたが、割込み禁止(DI)中でも割込みが入るらしく、DI と共に 38H をリターンコードに書き換えるようにしたら安定して動作するようになりました。※1
※1)原因判明(2023/10/05 の追記部分を参照)下図は MSXPen でデモプログラムを実行した際の画面です。
表示が競合し易くなるように1文字表示毎にタイマーウェイトを入れています。
MSXPen でデモプログラム実行時の様子 |
|
下図はディスパッチが最初に実行される直前とタスク3が実行開始した時点でのワークエリアのダンプ表示です。割込みの影響を無くすため、フックした新たな割込み処理の先頭をリターンコードに書き換えています。
画面中央のダンプ情報からディスパッチ前はタスク1~3がプライオリティ 0 のレディキューにつながっているのが判ります。タスク0は前述のアイドルタスクでプライオリティ3のレディキューにつながっています。下側のダンプはタスク3実行開始時のメモリで実行タスク番号が3でタイマーウェイトキューにタスク1とタスク2が繋がっています。
ZealMon 実行時のメモリ状態 |
|
まだ最適化はしていませんが、ソースも貼っておきます。無いとは思いますが今後、Z80 でリアルタイム制御したい場合に役に立つかもしれませんw
リアルタイムモニタ(ZealMon)とデモのソース(Z80アセンブラ) |
|
Twitter(X)に投稿した動画付きメッセージを貼っておきます。
タイムラインでZ80のスタックを使ったタスク管理の話題を見かけリアルタイムモニタを作ってみたくなりました
— skyriver (@wcinp) October 3, 2023
必要最小限の機能の実装ですがデモをMSXPenで動かしてみました
詳細は下記urlを参照して下さいhttps://t.co/mB0lGvejzS#ZealMon #Z80 #RealTimeMonitor pic.twitter.com/1gC0Ji3ZHg
★追記 2023/10/05
上記の DI 中に割込みが入っている現象の原因が判りました。
下記の割込みテストプログラムで確認した結果が下の画面です。繰り返し行っても同様の結果でした。BIOS の1文字表示処理の ROM 内のコードで EI を実施しているため、割込みが入っているようです。
上記の DI 中に割込みが入っている現象の原因が判りました。
下記の割込みテストプログラムで確認した結果が下の画面です。繰り返し行っても同様の結果でした。BIOS の1文字表示処理の ROM 内のコードで EI を実施しているため、割込みが入っているようです。
割込み試験実施結果 |
|
本確認で実施した割込み試験プログラムのリストを下記に示します。割込みが入った場合、リターンアドレスとコール元のコードを保存するようにしました。
割込み試験プログラムのソース(Z80アセンブラ) |
|
★追記 2023/10/06
上記の様にシステムコール内で割込み許可していることが判ったので、システムコール時は割込みは許可状態のままにしてタスクをディスパッチしない様にしてみました(システムコール毎のタイマーウェイトを無くし、ラウンドロビンコールを追加)。
その結果、下図のように表示が競合する場合には互いに1文字ずつ表示するようになりました。割込み処理の空振りが無いのでタイマー管理も正確になったはずです。
割込み対処後のデモ画面例 |
|
MSX-DOS 上で GAME 言語を使って BIOS 内の EI(0FBH)を検索した結果を貼っておきます。38H の割込みのエントリーが 0DDA9H なので割込み処理も含まれているのでしょうが結構あるものですね。
ざっと見た感じ、最後の二つは相対ジャンプのオフセット値ですが、他は EI 命令のコードのようですね。
MSX-DOS BIOS 内の 0FBH コードのサーチ結果 |
|
[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]