OS自作入門 -Advent25-

NO IMAGE

Step7 割り込み処理を実装する 中盤戦

step7の前半戦では一般的な割込み処理について学んだ。なんとなく理解したような気がする。割込みを受け付けることができる特別なピンがCPUにあり、そこに対して各種コントローラが割込み用出力ピン経由で電圧をかけてキックすることになる。割込みが発生したことを検知したら特定のアドレスからジャンプ先アドレスを読み込んで飛び、割込みハンドラの処理を実行する。その際にはプログラムカウンタ、モードレジスタを保存しておき割込みハンドラの処理が終わったら復帰する。というような処理になる。これをH8のプログラム内に記載していく。

H8/3069Fの割込み処理

割込みベクタ

H8の割込みベクタは0x000000から0x0000ffの範囲で、ここにあるアドレスを参照し割込みハンドラに処理を渡すようにしていく。CPUによるがH8の場合は64個の割込み要因を持っており、1つの割込みベクタは4byteなので64*4=256で256バイトとなっている。正確な割込み要因とそれに対応する割込みベクタの位置(ベクタ・アドレス)は仕様書に書いてあるが、例えばSCI1でのシリアル受信が発生すると57番の割込みが発生したこととなり、CPUは0x0000e4のアドレスからジャンプ先アドレスを取得しジャンプする。

割込みベクタの内容の説明が載っていたが簡単に抜粋すると、リセットボタンに対応するリセットベクタ、NMI(ノン・マスカブル・インタラプト)という無効化不能な割込み、トラップ命令による割込み(H8にはシステムコール割込みがないのでこれを使って実装することになる)、外部割込みが6本(周辺I/Oをつけた時に発生する、例えばLANのコントローラとか)、シリアルコントローラ用の受信完了割込み、送信データエンプティ割込み(送信完了)がある。

レジスタの退避

H8のモードレジスタに対応するものとしてコンディションコードレジスタ(CCR)という1byteのレジスタがある。役割としては「割込みの有効/無効」のフラグしかないらしい。他のビットはフラグレジスタと呼ばれるものでそれもあわせて入っているということになる。H8でのプログラムカウンタ、CCRの保存先(退避先)はスタックとなっていて、割込みが発生するとスタックポインタ(ER7)の指す先のメモリ上にこれらの値が保存され、ER7はデクリメントされることになる。

さて以上のことを踏まえて以下の通りのH8に対して行うことになる

  1. 割込み発生時に、スタック上にプログラムカウンタ、CCRの値を保存する
  2. 割込み要因に応じて割込みベクタを参照し、割込みハンドラにジャンプする(プログラムカウンタに割込みベクタの値を代入する)
  3. 割込みハンドラの実行
  4. 割込みハンドラ終了時に割込み復帰命令(rte)を呼び、スタックからプログラムカウンタとCCRの復帰を自動的に行う。
  5. 元の処理に戻る

ブートローダに割込みハンドラを実装する

今回追加するファイル

  • (ブートローダー側)
    • intr.h, intr.S
    • interrupt.h, interrupt.c
  • (OS側)
    • intr.h
    • interrupt.h, interrupt.c

修正するファイル

  • (ブートローダー側)
    • ld.scr
    • vector.c
    • main.c
    • Makefile
  • (OS側)
    • ld.scr
    • serial.h, serial.c
    • main.c
    • Makefile

ソフトウェア割込みベクタ

上述の通り割込みベクタは0x000000から0x0000ffのアドレスでありROM上にある。そのためブートローダ側に実装する必要がある。そのため割込みベクタに設定する値はROMへのブートローダ書き込み時に固定で決まってしまいOS側で変更することはできない。なので以下のような方針で実装を行う。

  1. 割込みハンドラはブートローダ側で用意して、割込みベクタにはそのハンドラのアドレスを設定
  2. RAMの先頭にOS側の割込みハンドラのアドレスを書いておく
  3. ブートローダの割込みハンドラでは、RAMの先頭に書かれているアドレスを見てジャンプする

これでOS側ではRAMの先頭に設定するアドレスを変更するだけで割込みハンドラを自由に登録することができるようになる。またRAMの先頭に設定するアドレスは割込みの種類の応じて複数記述できるようにしておく。このRAM領域先頭の複数のアドレスのことを ソフトウェア割込みベクタ と呼ぶ。

さて、プログラムの書き換えを行なっていこう。今回のstep分はgithubに置いておく。

ld.scrの修正

ソフトウェア割込みベクタ用の領域を定義した。サイズは64byte。ポインタが格納されるので一つのベクタは4バイトになる。これで16種類の割込みを登録することができる。


これ以降ちょっとコード量が多くなるので明日以降にすることにした。次回は割込みハンドラの入口と出口(レジスタの退避とか)から始めるとしよう。

なんだかんだアドベントカレンダー25日間やりきったが全然終わらなかったな6割程度というところか。がっつり年末とか仕事納めたら時間とって終わらせることを目標にしよう。