今回は、前回動作させた「Hello World」のソースコードについて解説し、組み込みソフトウェアでのHello Worldの動作の仕組みを見ていきます。その中身は、意外と奥深いものです。
本連載では、学習用・ホビー用の組み込みOS「KOZOS」を使ってマイコンボード上でいろいろと実験をしつつ、フルスクラッチで組み込みOSを自作していく過程を体験してみます。最終的には、ソフトウェア完全自作のWebサーバを動かします。
前回「フルスクラッチの“Hello World”を動かしてみよう」では、「H8/3069Fマイコンボード」上でフルスクラッチの「Hello World」を動かしてみました。第2回の今回は、前回動作させた「Hello World」のソースコードについて解説し、組み込みソフトウェアでのHello Worldの動作の仕組みについて見ていきます。
本連載では秋月電子通商の「H8/3069Fネット対応マイコンLANボード(完成品)」(図1)を利用します。マイコンボードの詳細については、連載第1回を参照してください。
このマイコンボードは3750円(税込)と非常に安価で、さらに入手性も良く、個人で誰でも購入できます。通販でも販売していますので、興味のある読者の方はマイコンボードを購入して本連載の内容を試してみてください。
前回動作させた「Hello World」のソースコードは、KOZOSのWebサイトからダウンロードできます。
上記のWebサイトから「osbook_03.zip」をダウンロードし解凍すると、図2のフォルダ構成でファイルが展開されます。これは筆者の書籍「12ステップで作る組込みOS自作入門」の各章(ステップ)に応じたソースコードになっています。
osbook_03 ─┬─ 01 ── bootload ── main.c ┐ │ startup.s │(1stステップのソースコード) │ vector.c │ │ … ┘ ├─ 02 ── bootload ── …(2ndステップのソースコード) ├─ 03 ── bootload ── …(3rdステップのソースコード) … └─ 12 ┬─ bootload ── …(12thステップのブートローダーのソースコード) └─ os ───── …(12thステップのOSのソースコード)
前回は、開発環境を構築して「Hello World」を動作させただけでしたので、ソースコードの中身については特に触れませんでした。今回は、ソースコードを詳しく見ていきたいと思います。
前回動作させた「Hello World」のソースコードは、図2の「osbook_03/01/bootload」というフォルダに格納されており、ファイル構成は表1のようになっています。
ファイル名 | 行数 | 内容 |
---|---|---|
defines.h | 11 | 各種定義 |
ld.scr | 31 | リンカスクリプト |
lib.c | 19 | ライブラリ |
lib.h | 7 | lib.cのヘッダファイル |
main.c | 15 | メイン関数 |
serial.c | 90 | シリアルドライバ |
serial.h | 8 | serial.cのヘッダファイル |
startup.s | 10 | スタートアップ(アセンブラ) |
vector.c | 18 | 割り込みベクターのテーブル |
合計 | 209 | 全ソースコードの総ステップ数 |
表1 ソースコード一覧 |
「Hello World」をシリアル出力するだけのプログラムなのにファイル数は9つ、ステップ数の総量は200行を超えています。
これはソフトウェアを全て自作し、必要な全ての処理を自前で用意しているからです。単に「Hello World」を出力するだけでも、最低これくらいの行数は必要になります。
「Hello Worldの出力だけで“200行”」と聞いて、ちょっと引いてしまう方もいるかもしれません。しかし、言い換えれば、この200行を理解することで、コンピュータが起動してから決められた動作を行うまでに必要な処理の全てを理解できるということです。重要な処理がたったの200行に凝縮されているわけですから、密度の高いソースコードでコンピュータの動作原理を効率良く学習できるということでもあります。このあたりが、フルスクラッチプログラミングの醍醐味(だいごみ)といったところでしょうか。
では、ファイルを1つ1つ見ていきましょう。なお、ここでは各ファイルを簡潔に説明しますが、内容をより詳しく知りたい方は参考文献[1]を併せて参照してください。
まずは「起動」について考えてみましょう。
そもそもマイコンボードの電源をONにしたとき、どのようにプログラムの実行が開始されるのでしょうか? 最初に実行されるコードはどこなのでしょうか? そして、それはどのようにして決定されるのでしょうか?
現在のCPUのほとんどは、「割り込み」の機能を持っています。割り込みは、あるイベントの発生時に、現在の処理を中断して別の処理を強制的に開始する機能です。
本連載で使用している「H8」マイコンも、もちろん割り込みの機能を持っています。H8マイコンは、割り込みの発生時に以下のように動作します。
この“メモリ上の特定の位置”を一般に「割り込みベクター」と呼びます。つまり、割り込み発生時には、メモリ上の割り込みベクターに書き込まれている値をジャンプ先アドレスとして読み込み、その先にジャンプすることになります。
割り込みベクターには、割り込み発生時のジャンプ先アドレスが配列状に格納されています。このように割り込みベクターを利用して割り込み処理にジャンプする方法を、一般に「ベクター割り込み方式」と呼びます。
表2は、H8マイコンの割り込みベクターの一覧です。表中の「ベクターアドレス」を見れば分かるように、H8マイコンの割り込みベクターには、メモリ上のアドレス「0x000000」〜「0x0000fc」の位置が割り当てられています。
割り込み要因 | 割り込み番号 | ベクターアドレス |
---|---|---|
リセット | 0 | 0x000000 |
NMI | 7 | 0x00001c |
トラップ命令 | 8〜11 | 0x000020〜0x00002c |
外部割り込み | 12〜17 | 0x000030〜0x000044 |
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜(中略)〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 | ||
シリアル0関連 | 52〜55 | 0x0000d0〜0x0000dc |
シリアル1関連 | 56〜59 | 0x0000e0〜0x0000ec |
シリアル2関連 | 60〜63 | 0x0000f0〜0x0000fc |
表2 H8/3069Fの割り込みベクター(主要なもの) |
割り込みベクターには、実際の割り込み処理が配置されているアドレスをあらかじめ設定しておきます。これにより、割り込み発生時に行われる処理を自由に設定することができます。このような割り込み発生時に呼び出される処理プログラムのことを、一般に「割り込みハンドラ」と呼びます。
割り込みの種類は表2にあるように1つだけではなく、多数存在します。例えば、外部ハードウェアからの割り込みを受け付けるための外部割り込みや、CPU内部のシリアルコントローラーからの割り込み、OSのシステムコールなどを実現するためのトラップ命令による割り込みなどです。
その中でも重要なのが、次節で説明する「リセット割り込み」です。
ここまでで割り込みの説明をしてきたのには理由があります。それは“割り込み処理が電源ONでの起動処理に密接に関係する”からです。
表2にもあるように、H8マイコンはリセット割り込みという割り込み種別を持っています。これはリセットボタンを押下したときに発生する割り込みです。本連載で使用しているH8/3069Fマイコンボードでは、モード設定用のディップスイッチの隣にリセットボタンがあります(図3)。
つまり、図3のリセットボタンを押下するとリセット割り込みが発生し、表2のベクターアドレス「0x000000」に格納されているアドレス値をジャンプ先として、その先にジャンプします。
さらに、H8マイコンにおける電源ONはリセット割り込みの発生と同様に扱われます。よって、電源ONの直後には、ベクターアドレス「0x000000」が指しているアドレスから動作を開始することになります。H8マイコンの「0x000000」というアドレスは、実は内蔵フラッシュROM上にあるため、内蔵フラッシュの先頭(つまり、リセット割り込みの割り込みベクターの位置)にあらかじめどのようなアドレス値を書いておくかによって、電源ON直後の動作開始位置を自由に決めることができるのです。実際には、フラッシュROMへの書き込みは専用のツール(連載第1回の3ページを参照)によって行われますので、ツールによるプログラム書き込み時に割り込みベクターも同時に固定で設定されることになります。
割り込みベクターはフラッシュROM上にあるため、「Hello World」では割り込みベクターの値もあらかじめ設定しておく必要があります。これは「リンカスクリプト」というファイルで行われます。
Copyright © ITmedia, Inc. All Rights Reserved.