セミホスティング
セミホスティングは、組込みデバイスがホスト上でI/Oを行う仕組みです。主に、ホストのコンソールにログ出力するために使われます。 セミホスティングには、デバッグセッションが必要ですが、他には何も必要としません(追加の配線は不要です)。そのため、非常に便利です。 欠点は、非常に低速であることです。ハードウェアデバッガ(例えば、ST-Link)によっては、書き込み操作が数ミリ秒かかります。
cortex-m-semihosting
クレートは、Cortex-Mデバイス上でセミホスティング操作をするためのAPIを提供します。
下のプログラムは、セミホスティングバージョンの「Hello, world!」です。
#![no_main] #![no_std] extern crate panic_halt; use cortex_m_rt::entry; use cortex_m_semihosting::hprintln; #[entry] fn main() -> ! { hprintln!("Hello, world!").unwrap(); loop {} }
このプログラムをハードウェア上で実行すると、OpenOCDのログに、「Hello world!」のメッセージが表示されます。
$ openocd
(..)
Hello, world!
(..)
最初に、GDBからOpenOCDのセミホスティングを有効化する必要があります。
(gdb) monitor arm semihosting enable
semihosting is enabled
QEMUはセミホスティング操作を理解しているため、上のプログラムは、デバッグセッションを開始していないqemu-system-arm
でも動作します。
セミホスティングサポートを有効化するため、QEMUに-semihosting-config
フラグを渡す必要があることに注意して下さい。
これらのフラグは、テンプレートの.cargo/config
ファイルに既に含まれています。
$ # このプログラムは端末をブロックします
$ cargo run
Running `qemu-system-arm (..)
Hello, world!
exit
セミホスティング操作もあり、QEMUプロセスを終了するために使われます。
重要:ハードウェア上でdebug::exit
を使用しないで下さい。この関数は、OpenOCDセッションを破壊する可能性があり、
OpenOCDを再起動しない限り、それ以上のプログラムのデバッグができなくなります。
#![no_main] #![no_std] extern crate panic_halt; use cortex_m_rt::entry; use cortex_m_semihosting::debug; #[entry] fn main() -> ! { let roses = "blue"; if roses == "red" { debug::exit(debug::EXIT_SUCCESS); } else { debug::exit(debug::EXIT_FAILURE); } loop {} }
$ cargo run
Running `qemu-system-arm (..)
$ echo $?
1
最後のヒント:パニック時の挙動を、exit(EXIT_FAILURE)
に設定することができます。
これで、QEMU上で実行できるno_std
ランパステストを書くことができます。
利便性のために、panic-semihosting
クレートは、「exit」フィーチャを持っています。
このフィーチャが有効化されていると、ホストの標準エラーにパニックメッセージをログ出力した後、exit(EXIT_FAILURE)
を呼び出します。
#![no_main] #![no_std] extern crate panic_semihosting; // features = ["exit"] use cortex_m_rt::entry; use cortex_m_semihosting::debug; #[entry] fn main() -> ! { let roses = "blue"; assert_eq!(roses, "red"); loop {} }
$ cargo run
Running `qemu-system-arm (..)
panicked at 'assertion failed: `(left == right)`
left: `"blue"`,
right: `"red"`', examples/hello.rs:15:5
$ echo $?
1