Document made with Nvu

SEMB1200A 開発環境の動作確認

SEMB1200A を題材にした、Cygwin 上のクロス開発ツールの使い方と動作確認例です。

インストール方法に関しては Cygwin のインストール を参照してください。



コンテンツ

  1. Test Program の make
  2. SEMB1200A への転送と動作確認
  3. 参考1: SEMB1200A のメモリマップと Boot Sequence
  4. 参考2: SEMB1200A の開発環境で使用可能な標準関数
Home

Test Program の make

Cygwin 環境上で Test Program を make します。

まず、開発環境のページのソースとコンパイル済みバイナリにある SEMB1200A 用の Test Program ソース testlib_src_A61004.tar.gz を任意のフォルダにダウンロードします。

次に Test Program ソースを展開します。この時、[ダウンロードしたディレクトリ] は Cygwin のインストールの開発環境のバイナリのインストール で説明した Cygwin 環境でのディレクトリになります。

展開したら make します。

make は Makefile を見て中に書いてあるルールに従って処理を行うコマンドで、コンパイルなどの (通常複数の) 定型処理を何度も行う場合に使用されます。 

中身は詳しくは説明しませんが、以下のようになっています。 よく使う構文は2つです。

Test Program の Makefile は以下のようになっています。# で始まる行はコメントで、説明用に追加しました。なお、"-Wl,--section-start,.text=0x9FC80000" で指定しているアドレスは、プログラムが実行されるアドレスで、後で説明する UX1200E の転送先のアドレスに合わせる必要があります。また、Test Program では 岡田さん 作成の I/O library を使わせてもらっていますので、-lsemb を指定して libsemb.a をリンクしています。

make を実行して、以下のようなメッセージが表示され、エラーが無く check_libsemb_1.bin,  check_libsemb_2.bin,  check_libsemb_3.bin ができていれば成功です。

これでコンパイルの処理は完了です。

Top Home

SEMB1200A への転送と動作確認

次に作成したバイナリを SEMB1200A に転送して動作確認を行います。

ま ず、PC と SEMB1200A をマニュアルにしたがって、RS-232C クロスケーブルで接続します。SEMB1200A には同じコネクタが複数あり、間違えるとボードや PC を破壊する可能性がありますので、マニュアルをよく読んで注意して接続しましょう。

次にターミナルソフトを開き、接続したシリアルポートでコネクションを張ります。ここでは、Windows 標準の「ハイパーターミナル」を使用していますが、他のソフトでも問題ありません。

SEMB1200A に電源を接続すると、bootloader が立ち上がり、コマンド入力待ちになります。メッセージが表示されない場合は、シリアルポートの設定と SEMB1200A の DIP SW の設定がマニュアルの指定と合っているか確認しましょう。

StepT1

次に、作成したプログラムのオブジェクトを転送します。

"W" そして、"1" を入力します。SEMB1200A が xmodem 受信の待機状態になります。

StepT2

「ハイパーターミナル」 のメニューから「転送」→「ファイルの送信」を選択します。ファイル名は作成した Test Program のバイナリ (check_libsemb_1.bin)、プロトコルは "Xmodem" を選択します。

StepT3

[送信 (S)] をクリックすると転送が開始されます。

StepT4

転 送が終わったら、SEMB1200A が再度コマンド入力待ちになりますので、"R" そして "1" を入力して実行します。下のように "check_libsemb: Version $Id: version.c,v 1.2 2006/10/04 01:09:07 sugi3 Exp sugi3$"のメッセージ (使用した libsemb.a の version によって異なります) が出力されれば正常に転送と実行が出来ています。

StepT5

こ れでユーザ空間1での転送・実行の確認が終わりましたので、ユーザ空間2および3でも同様に確認します。この場合、転送と実行のアドレス指定で "1" の代わりに "2" または "3" を、転送するバイナリに check_libsemb_2.bin または check_libsemb_3.bin を選択します。

アドレスによって、バイナリが異なるの は SEMB1200A の loader (といっても固定アドレスに飛ぶのみ) がや crt0.o がアドレスの動的解決をサポートしないためです。OS を搭載しない場合は、loader を簡略にするためこのようにする場合が多いのですが、代わりに Makefile で指定したような OS 上のアプリケーションのコンパイルでは見慣れない指定が必要になります。実際にはsemb1200a-rom.ld が主にこのアドレス情報を決定しており、Makefile での指定は先頭アドレスを変更するためのみに使用されています。check_libsemb_1.map (実際のアドレス情報) やcheck_libsemb_1.lst (バイナリ逆アセンブル結果) を見ると、アドレスへの配置状況を見ることが出来ます。また、さらに興味がある方は次の Boot Sequence の説明も読んでみてください。

Test Program の転送と動作確認は、以上で完了です。

Top Home

参考1: SEMB1200A のメモリマップと Boot Sequence

SEMB1200A のメモリマップは コラム−MIPS のメモリ空間 でも紹介しましたが、以下のようになっています。

UX1200E Mem Map

MIPS アーキテクチャのプロセッサは論理アドレスの 0xBFC00000 がリセットベクタになりますので、物理アドレスは 0x1FC00000 つまり FlashROM の先頭から実行が開始されます。

UX1200A ではこの空間はシステム領域となっており、リセット後は bootloader が実行されるようになっています。ここからの処理の流れを箇条書きにすると以下のようになります。 (bootloader はソースが非公開なので一部想像 ^_^; を含みます)

bootloader からユーザプログラムへの制御の引渡しは単にエントリアドレス (0x9FC80000 など) に飛ぶのみのようです。これ以降はユーザプログラムの領域ですが、単に実行を開始しても C で作成したプログラムは動作しません。なぜならば、プログラムが書き込まれているのは ROM で、そのままではデータのライトができないためです。

これを処理するのが、crt0 の役目です。したがって、crt0.o は、必ずユーザプログラムの先頭に配置されていないといけません。

SEMB1200A の場合、crt0.o もユーザ作成が前提なので、ここから後はある意味ユーザの自由なのですが、ここではバイナリにも入れさせてもらった岡田さんの crt0.o が必要かつ十分なものなので、この処理を前提にします。

crt0.o は次の処理を行っています。

ユー ザが通常プログラムとして意識するのはこの main() 以降の処理ですが、OS があっても無くても main() の前にはこれだけの処理が行われています。但し、OS が搭載されている場合は、プロセスのスケジューリングやメモリ管理などの処理も行われますので、実際にはもっと複雑です。

Top Home

参考2: SEMB1200A の開発環境で使用可能な標準関数

SEMB1200A など、OS を搭載しない環境では、C の標準関数が全て使用できるわけではありません。これは、これらが通常 OS がサポートするシステムコールを必要としているためです。

も ちろん OS を搭載しなくても、必要なシステムコールに相当する処理を別途行えば、全ての関数を使用可能にすることも不可能ではありません。しかし例えばストレージが 無いシステムでファイルシステムをサポートするメリットはありませんので、何らかの制約が付くのが普通です。

SEMB1200A の環境では、nullmon を使用していますので、I/O 関連やメモリ管理に関する標準関数は基本的には使用できないと考えたほうが良いと思います。

I/O 関連の例
    標準入出力 = putc(), getc(), puts(), printf(), scanf() など
    → メモリ相手の sprintf() などは使用可能ですが、stdio 族はコードサイズが大きいので注意しましょう

メモリ関連の例
    malloc() 関連など

(詳細は後で追加予定です)

Tips: UART への文字列の出力

debug などの用途で UART に文字列を出力する場合下記の2つの書き方ができます。

    snprintf(out_str, "hogehohe %s nado\n", get_str());
    uart1_puts(out_str);

    uart1_puts("hogehoge");
    uart1_puts(get_star());
    uart1_puts("nado\n");

通 常は、I/O を何度も呼ぶイメージがある下の記述よりも上の記述のほうが綺麗に見えます(よね?)。しかし、SEMB1200A のような主記憶サイズの制約が大きいシステムの場合、コードサイズを考えると sprintf は極力使用しないほうが良いでしょう。実際に両方のプログラムを作成してコンパイルしてみるとその差が実感できると思います。

但し、sprintf を一箇所でも使用していれば、何箇所で使用しても増分は同じですので、使用回数を少なくすることには意味はありません。関数の使い方を整理し、必要な関数のみに使用関数種を減らすことがこのような場合には重要です。

な お、実際には sprintf の処理の大部分は vfprintf が分担しており、例えば sprintf と snprintf を使用しても2倍になるわけではありません。理解を深めるためには newlib のソースを読むのが一番ですが、まずはカットアンドトライで感触を掴むのも良いでしょう。

Top Home

Last Update Oct.06/2006
Copyright (C) sugi3 2006