OS自作入門 -Advent27-
Step7 割り込み処理を実装する 最終戦
しばらく空いてしまいましたが、step7の最後のポストになりそうです。これまででブートローダへの割込みハンドラの実装を行なってきました。あとは割込みベクタの修正を行い、
割込みハンドラの設定
vector.cの修正
vector.cのようになる。もともとはリセット・ベクタだけであったところにintr_softerr
, intr_syscall
, intr_setintr
の3つのハンドラを設定していく。vectors[8]
〜vectors[11]
には割込み番号8〜11になっているトラップ命令割込みに相当している。具体的にはinterrupt.cにあるsoftvec_setintr()
によって、SOFTVEC_TYPE_SYSCALL
かSOFTVEC_TYPE_SOFTERR
のいずれかに設定されたハンドラが呼ばれる仕組み。
同様にvectors[52]
〜vectors[63]
にはintr_setintr()
が設定されており、シリアル関連の割込みの設定をしている。
ブートローダ側の修正の残りはmain.c
とMakefile
である。
main.cの修正
main.cではソフトウェア・割込みベクタの初期化のためにinit()
の内部でsoftvec_init()
を呼び出している。あとは割込みハンドラの設定が完了するまで割込みが入ってこないようにINTR_DISABLE
で割込みの無効化を行なっている。
main.cのようになる。
Makefileの修正
Makefileはinterrupt.c
をコンパイル対象に加え、intr.S
もアセンブルされるように追加している。
以上がブートローダ側の修正内容となる。
OS側の修正
これまでの実装によりOS側ではソフトウェア・割込みベクタに関数のアドレスを登録しておけば登録された関数がハンドラとして呼ばれることになる。
ソフトウェア・割込みベクタ対応のためのブートローダ側のソースコードを流用するため以下のファイルをos側にコピーする
- intr.h
- interrupt.h, interrupt.c
cp bootload/intr.h bootload/interrupt* os
を実行してコピー。
ld.scrの修正(os側)
次にブートローダ側でも行なったようにリンカスクリプトにソフトウェア・割込みベクタの領域を定義します。
ld.scrのようになる。
シリアル受信割込み
このステップではシリアル受信割込みを受け付けるように改良をする。シリアル・デバイス・ドライバに割込みの機能追加を行う。
seria.h, serial.cの修正
serial.hのようになる。
追加したのは、
int serial_intr_is_send_enable(int index);
void serial_intr_send_enable(int index);
void serial_intr_send_disable(int index);
int serial_intr_is_recv_enable(int index);
void serial_intr_recv_enable(int index);
void serial_intr_recv_disable(int index);
送信・受信の割込みが有効化どうかの判定、および有効化・無効化の関数である。
それぞれ実装をするとserial.cのようになる。
シリアル送信割込みはTIEbit、シリアル受信割込みはRIEbitを立てることでそれぞれ有効化される。これらのbitを立てるとシリアル・コントローラが送信完了/受信完了を検知した際に、CPUに割込みを通知するようになる。
割込みによる動作に変更する
main.c
ではこれまでgets()
で行単位のコンソール入力を受け付け、puts()
で応答を返すようになっている。gets()
はserial.c
のserial_recv_byte()
を呼び出しており、ビジーループでシリアル受信を待つようになっていた。この処理をシリアル受信割込みを受け付けて、割込みハンドラ内部で受信処理を行うように修正する。
main.cの修正(というかほぼ新しいもの)
main.cとなる。なるほど、ここでintr()
関数を定義し、それをsoftvec_setintr(SOFTVEC_TYPE_SERINTR, intr);
で渡すことによってSOFTVEC_TYPE_SERINTR
の割込み(シリアル割込み)に対するハンドラをos側で定義することが可能になるということか。確かに毎回ブートローダへの書き込みは行わなくて良くなっているような気もする。
また、本体の処理としてはsleep
しているだけでその後は割込み処理に任せるというようなコードになっている。その直前にINTR_ENABLE
として、CCRの1bitを落としてCPUの割込みを有効化している。このsleep
は別名「省電力モード」あるいは「スリープモード」と呼ばれ、命令の実行は停止され割込みが入ると動作を再開するようになる。
割込み処理の実体はintr()
で内容はmain.cと大きく変わらない。
Makefileの修正
最後に新しくinterrupt.c
が追加されたため、コンパイル対象に追加しておく。
Makefileとなる。
プログラムの実行
しばらくぶりすぎて忘れそうだが、ログを残しておこう。
- プログラムのビルド
cd bootload make make image cd ../os make
- ブートローダを書き込む
h8を書き込みモードにして書き込むcd bootload make write # ================================================= # H8/3069F Flash Writer for KOZOS (Version 0.2.1) # Copyright(C) 2011-2012 Shinichiro Nakamura # ================================================= # Bitrate sequence: Done. # Inquiry device: Done. # Select device: Done. # Inquiry clock mode: Done. # Select clock mode: Done. # Select bitrate: Done. # Waiting for erase done:.... # Programming:....................... # Program: Done. # Complete.
- ブートローダを起動しosを読み込む
kx_xmodemというtoolを使ってloadまで行なうので少し本とは違うが以下のように。h8を読み込みモードにして
cd os ../../tools/bin/kz_xmodem kozos.elf /dev/tty.usbserial-XXXXXXXXXXXXXXX # ================================================= # XMODEM for KOZOS H8/3069F (Version 0.0.2) # Copyright(C) 2012 Shinichiro Nakamura # ================================================= # Flushing serial port. # Wait. # Setup load condition. # Wait a NAK. # .......... # Transmit the target ELF file. # File(kozos.elf): 34 blocks + 124 bytes # ................................... # Wait a message from the target. # Complete.
- シリアル接続して確認してみる
リセットボタンを押すとloadした内容が消えるので押さないように
シリアル接続してrun
をして適当にecho hogehoge
すると応答してくれるはず。sudo cu -l /dev/tty.usbserial-XXXXXXXX -s 9600 Connected. kzload> # unknown. kzload> run # starting from entry point: ffc020 # kozos boot succeed! > a unknown. > echo test test > echo hoge hoge
うまくいっているっぽい。
次はstep8か。ようやく3/4終了。今月中には終わるか。終わったらまた実装はしないけど本を一読して総まとめ1,2,3くらい書かないと脳内の整理と理解が全然足りない感じがするな。とはいえ割込みが上手くいっているみたいでよかった。
- 前の記事
祝!アドベントカレンダー完走 2017.12.29
- 次の記事
OS自作入門 -Advent28- 2018.01.09