/home/tnishinaga/TechMEMO

日々行ったこと、面白かったことを書き留めます。

ARMアセンブラの16bit即値代入でコンパイルエラーが出た件

以下の様な16bit即値をレジスタr0に代入するコードをコンパイルしたところ,エラーとなったので,解決策をメモする.

ターゲットはRaspberry Pi 2.コンパイラgcc 4.7.2

mov r0, #0xffff

ARMの公式ドキュメントを読んでみると

ARMv6T2 以上のアーキテクチャでは、MOV は 0x0-0xFFFF (0 ~ 65535)範囲内にある任意の 16 ビットの数値をロードできます。

と書かれているので,armv7-aなRaspberry Pi 2では問題ないはずだが……

数分後...

エラーログで調べてみると,stackoverflowに同じ問題で悩んでいる人が居た.

stackoverflow.com

読んでみると,コンパイラアーキテクチャを教えない場合,armv5としてコンパイルが行われるので,movの範囲が0x00~0xffに制限されてしまうようだ.

ということは,コンパイルオプションに以下を追加してarmv7-aであると知らせるだけで治る...とおもったら,うまくいかなかった.

-march=armv7-a

最終的にmov命令をmovw命令に変更したところ,コンパイルが通った.

movw #0xffff

ARM_VMM: Cortex-A7でMMUを有効化する方法メモ

ARMの仮想化支援機能を使ってみたかったので, 現在しゅううさん(@syuu1228)と一緒に教育用自作VMMを作成中です. もちろん,BareMetalで.

対象ボードは,とりあえずCortex-A7を積んだRaspberry Pi 2を予定中. (ARM64なボードが届いたらそちらに移るかも?)

まだ色々調べている段階なので,道中わかったことをメモしていきます.

ARMの仮想化支援

ARMの仮想化支援機構は,Cortex-A15(+ Cortex-A7)から導入された. ここで行われた主なアーキテクチャ拡張は以下の3つ:

  • ハイパバイザモードの追加
  • 2重メモリアドレス変換機能
  • 物理アドレス空間の40bitへの拡張

各機能の詳細はまだ調べきれていない. 以下の資料を参照.

http://www.hotchips.org/wp-content/uploads/hc_archives/hc22/HC22.23.220-1-Brash-ARMv7A.pdf

VMMの概要

ホストOSとゲストOSの動作イメージが,うまくつかめていない.

以下の資料を見る限りだと,VMMはHYPモードで動くが,ホストOSとゲストOSはどちらもSystemモードとユーザーモードで動くらしい.

http://www.linux-kvm.org/wiki/images/d/d4/2012-forum-arm-christoffer-dall.pdf

つまり,

モード OS
User ゲストOS
System ホストOS
HYP ハイパバイザ

ではなく

モード OS
User ホスト & ゲストOS
System ホスト & ゲストOS
HYP ハイパバイザ

というイメージで動くっぽい.

ゲストOSからハイパバイザへの復帰,HWアクセスのトラップ方法についてはまだわかってない(後者はSystem MMUというのを使うっぽい?).

System MMUの資料(要ログイン)

MMUの有効化方法

VMMを作るにはMMUの理解が必須だと思うけれど,私はMMUについて全く知らない.

これではまずいので,MMUについて理解を深めるため,まずはRaspberry Pi 2のMMUを有効化する方法について調べ始めた.

資料

資料は以下の3つ:

一番最後の資料はRenesasの資料.

日本語なのでわかりやすいけど,説明が一部間違っているようなので注意.

VMSAとPMSA

アーキテクチャマニュアルを読むと,メモリシステムアーキテクチャの項目が,VMSAとPMSAの2つある.両者の違いは以下.

アーキテクチャ 説明
VMSA MMUベースの仮想メモリシステムアーキテクチャ.Cortex-A対象
PMSA MPUベースの保護メモリシステムアーキテクチャ.Cortex-R対象

つまり今回はCortex-A7が対象なので,VMSAについて調べれば良い.

Renesasの資料は,どうも一部の記述がVMSAとPMSAを間違えているようなので,適宜読み替えて読む(もしかするとRenesasのCortex-A9では正しいのかもしれない)

MMUアドレス変換の仕組み

まだ説明できるほど理解してない.

とりあえず,アドレスの変換のレイアウトを物理アドレスと同じにすれば,物理アドレスの時と同じように扱えるっぽい.

MMUの初期化

起動直後はMMUが無効になっているので,有効にしないといけない.

各種L2キャッシュはMMUが動いていないと使えないので,MMU動かすついでにL2キャッシュも有効にしてあげるといいらしい.

有効化までの手順は先ほど上げたRenesasの資料にわかりやすく書かれており,以下のようにすれば良い.

  1. TLBの初期化
  2. 命令キャッシュの初期化(Invalidate)
  3. データキャッシュの初期化
  4. 予測分岐の初期化
  5. MMU, 命令キャッシュ,データキャッシュ, 分岐予測の有効化

MMUの初期化手順のみなら,アーキテクチャマニュアルの「Enabling MMUs」にも書かれている.

コプロセッサ設定のやり方

MMUやキャッシュの設定はメモリの特定アドレスにアクセスして行うのではなく,コプロセッサに対し専用命令を使って行う.

専用命令は以下の2つ. 前者が書き込み命令で,後者が読み込み命令

命令 構文
mcr mcr pn, Op1, Rt, CRn, CRm, Op2
mrc mrr pn, Op1, Rt, CRn, CRm, Op2

構文の各項目の意味は以下.

項目 説明
pn 命令が実行されるコプロセッサ
Op1,2 コプロセッサ固有のオペコード
Rt コプロセッサとデータをやりとりするARMレジスタ
CRn, CRm コプロセッサレジスタ

Rtを除く項目は,アーキテクチャマニュアルに命令と項目の対応表があるので,参考に設定する.

TLBの初期化

TLBの初期化(Invalidate)は,TLBIALLレジスタを叩いて行う. Rtの値は不問.

mcr p15, 0, r0, c8, c7, 0

命令キャッシュの初期化

キャッシュにはゴミが残ってる可能性があり,これを掃除しないと実メモリにゴミが書かれてしまうかもしれないので,こちらも初期化を行う.

命令キャッシュの初期化はICIALLUレジスタに0を書き込んで行う.

mov r0, #0
mcr p15, 0, r0, c7, c7, 0

データキャッシュの初期化

データキャッシュの初期化はDCISWレジスタに0を書き込んで行う.

mcr p15, 0, r0, c7, c6, 0

分岐予測キャッシュの初期化

分岐予測の初期化はDCISWレジスタに0を書き込んで行う.

mcr p15, 0, r0, c7, c5, 6

MMU, 命令キャッシュ, データキャッシュ, 分岐予測 の有効化

MMUとキャッシュの有効化は,システム制御レジスタ SCTLR で行う. このレジスタのキャッシュとMMUに関するビットを立てると,各機能が有効になる.

ビット 機能
12 命令キャッシュ
11 分岐予測
1 データキャッシュ
0 MMU

SCTLRレジスタの詳細はアーキテクチャマニュアルを参照.

movw r0, #0x1803
mcr p15, 0, r0, c1, c0, 0

MMUの初期設定

今後の課題.

参考になりそうなサイトとか

d.hatena.ne.jp

Enabling HYP mode on the Raspberry Pi 2 | flexVDI

http://www.linux-kvm.org/wiki/images/d/d4/2012-forum-arm-christoffer-dall.pdf

続く...

go言語コンパイラをソースからビルドする

go言語コンパイラのビルド方法が,半年前に触ったときと違ったので,現在の方法をメモっておく.

環境

  • Fedora 21 x86_64
  • Golang 1.4.2 ( c62b003eba484d54c2707b379d29240e5367e98f )

インストール方法

ソースのクローン

半年前はmercurialで管理していた気がするが,いつの間にかgitに移っていた. リポジトリgoogle codeのものとgithubのものがあるが,後者はミラーリポジトリなので,前者からクローンする.

$ cd ~/
$ git clone https://go.googlesource.com/go

ビルド済みGo言語コンパイラのインストール

ここからが半年前と違うところ.

以前はgoコンパイラが既に入っているかいないかにかかわらず, ~/go/src/ 以下で all.bash を実行するだけで,go言語コンパイラをビルドできたような記憶がある. しかし,今は all.bash を実行すると,以下のように ~/go1.4 にgo言語(v1.4)の実行環境を入れるよう怒られる.

$ ./all.bash 
##### Building Go bootstrap tool.
cmd/dist
ERROR: Cannot find /home/tnishinaga/go1.4/bin/go.
Set $GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4.
./make.bash: line 121: /home/tnishinaga/go1.4/bin/go: No such file or directory

そのため,go1.4の実行環境を落としてきて ~/go1.4 に置く. go言語コンパイラの実行環境は,以下から持ってこられる.

$ mkdir tmp
$ wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz
$ tar zxvf go1.4.2.linux-amd64.tar.gz -C tmp/
$ mv tmp/go ~/go1.4

go言語コンパイラのビルド

後は普通に all.bash を実行するだけ.

$ cd ~/go/src/
$ ./all.bash

ビルドが終わったあとは, .bashrc などに

export GOROOT=$HOME/go
export PATH=$PATH:$GOROOT/bin

と書いておくと,ビルドしたgo言語コンパイラにパスが通って使えるようになる.

以上.

Raspberry Pi 2さわってみた

f:id:tnishinaga:20150207145351j:plain

Raspberry Pi 2が届いたので、とりあえず使用感・性能・消費電流について簡単にチェックしてみました。

使用感

かなり快適です。感動しました。

Raspberry Pi 1はCUIですら反応が遅く、デスクトップを起動すると遅すぎてとても使えないレベルでした。

しかし、Raspberry Pi 2は違います。 最初のraspi-config画面の時点から、動作が軽快です。 Raspberry Pi 1ではLocale設定などを行おうとすると、1アクションに10秒ほど待たされましたが、Raspberry Pi 2ではほとんどありません。

GUIを起動しても動作は快適。 ブラウザもすぐ立ち上がりますし、2,3枚ウィンドウ開いても軽快に動作します。

この使用感で4000円程度なら、日常で使う管理コンソールマシンとして、またはVNCクライアントマシンなどの用途に、十分使えるレベルだと思います。

性能

UnixBenchとLinpackで簡単にベンチマークをとってみました。 Raspberry Pi 1との比較は行っていないので、 どなたか比較結果の作成をよろしくお願いします。

UnixBench


Benchmark Run: 4 CPUs; 1 parallel process

Time: 03:32:52 - 04:01:10; 28m 18s

System Benchmarks

Test Score Unit Time Iters. Baseline Index
Dhrystone 2 using register variables 2961984.8 lps 10.0 s 7 116700.0 253.8
Double-Precision Whetstone 497.9 MWIPS 10.0 s 7 55.0 90.5
Execl Throughput 370.2 lps 29.9 s 2 43.0 86.1
File Copy 1024 bufsize 2000 maxblocks 74390.2 KBps 30.0 s 2 3960.0 187.9
File Copy 256 bufsize 500 maxblocks 21577.5 KBps 30.0 s 2 1655.0 130.4
File Copy 4096 bufsize 8000 maxblocks 193781.0 KBps 30.0 s 2 5800.0 334.1
Pipe Throughput 172660.3 lps 10.0 s 7 12440.0 138.8
Pipe-based Context Switching 31772.9 lps 10.0 s 7 4000.0 79.4
Process Creation 1279.5 lps 30.0 s 2 126.0 101.6
Shell Scripts (1 concurrent) 1186.8 lpm 60.1 s 2 42.4 279.9
Shell Scripts (8 concurrent) 332.4 lpm 60.2 s 2 6.0 554.0
System Call Overhead 412119.5 lps 10.0 s 7 15000.0 274.7
System Benchmarks Index Score: 174.0


Benchmark Run: 4 CPUs; 4 parallel processes

Time: 04:01:10 - 04:29:41; 28m 31s

System Benchmarks

Test Score Unit Time Iters. Baseline Index
Dhrystone 2 using register variables 11810261.3 lps 10.0 s 7 116700.0 1012.0
Double-Precision Whetstone 1989.9 MWIPS 10.0 s 7 55.0 361.8
Execl Throughput 1332.2 lps 29.9 s 2 43.0 309.8
File Copy 1024 bufsize 2000 maxblocks 116037.8 KBps 30.0 s 2 3960.0 293.0
File Copy 256 bufsize 500 maxblocks 32386.9 KBps 30.0 s 2 1655.0 195.7
File Copy 4096 bufsize 8000 maxblocks 305329.3 KBps 30.0 s 2 5800.0 526.4
Pipe Throughput 686642.0 lps 10.0 s 7 12440.0 552.0
Pipe-based Context Switching 122410.7 lps 10.0 s 7 4000.0 306.0
Process Creation 2840.9 lps 30.0 s 2 126.0 225.5
Shell Scripts (1 concurrent) 2660.6 lpm 60.1 s 2 42.4 627.5
Shell Scripts (8 concurrent) 351.6 lpm 60.3 s 2 6.0 585.9
System Call Overhead 1572755.6 lps 10.0 s 7 15000.0 1048.5
System Benchmarks Index Score: 438.3

Linpack

消費電流

アイドル時

f:id:tnishinaga:20150207155113j:plain

4コア100%使用時(Linpack実行時)

f:id:tnishinaga:20150207155137j:plain

各結果の感想

性能

Linpackを用いたRaspberry Pi 2の性能結果は、単体で1G FLOPSの結果が出ました。

以前、計算工学ナビさまの記事で、Raspberry Pi 1 Type B+を16台つなげた際の結果は2.66G FLOPSでした。 なので単純に考えれば、Raspberry Pi 2 1台はRaspberry Pi 1 Type B+ 6台分の性能が得られています(通信コストなどは考慮していないので、正確な比較結果ではありません)。

消費電流

Raspberry Pi 1 Type B+の消費電流は、アイドル時とCPU100%使用時どちらも変わらず200mAでした(USB接続なし。LAN接続あり)

Raspberry Pi 2はアイドル時で+30mA、CPU100%使用時は+300mA程度増えています。 これに加えてUSB機器などを接続すると、消費電流は1Aを超えるでしょう。

よって、Raspberry Pi 2を用いる際は、2A出力のACアダプタを使用したほうが、安全だと思います。

おわりに

Raspberry Pi 2は以前に比べ性能が上がり、実用レベルになりました。 これからRaspberry Piを初められるかたはぜひRaspberry Pi 2を…とすすめたいところですが、Raspberry Pi 2はペリフェラルマニュアルや回路図をまだ見つけられていない(まだ公開されていない?)ので、ちょっと不安です。

ペリフェラルマニュアル等が公開されたら、また調べて本を書いたりしたいと思います。

WindowsでARMCCを用いてmbedライブラリをビルドする

LPC812をmbedライブラリを用いて開発したかったので、mbedライブラリのビルド方法を調べました。

事前準備

  • Python2.xのインストールとパスの設定
  • Keil MDK-ARM v5のインストール

インストール方法

基本は高橋さんの記事のとおりですが、少々変更点があります。

mbedのビルドをOS X上で行う - Qiita

Windows上でARMCCを用いてビルドするに必要なこと

LPC812のビルドはARMCC(Keil MDK-ARMに入ってるコンパイラ)以外ではできません。 よって高橋さんの記事を参考に、以下のビルドコマンドでビルドを行います。

$ python workspace_tools\build.py -m LPC812 -t uARM

しかし、以下のエラーが出てビルドができません。

[WARNING] Using default settings. Define your settings in the file "workspace_tools/private_settings.py" or in "./mbed_settings.py"
Building library CMSIS (LPC812, uARM)
[Error 2] 指定されたファイルが見つかりません。

Completed in: (0.01)s

  Build failures:
  * uARM::LPC812

-vオプションを付けて問題の詳細を確認し、printデバッグで調べたところ、どうやらコンパイラの場所指定がおかしいことがわかりました。 もう少し調べてみると、mbedライブラリではMDK-ARM v4を前提としており、加えてデフォルトではMDK-ARMではなく、スタンドアローンなARMCCを用いるようになっていました。

当該ファイルは workspace_tools\settings.py です。 これをMDK-ARM v5を用いるよう、以下のように書き換えます。

diff --git a/workspace_tools/settings.py b/workspace_tools/settings.py
index 3444f86..23090c1 100644
--- a/workspace_tools/settings.py
+++ b/workspace_tools/settings.py
@@ -30,13 +30,14 @@ ROOT = abspath(join(dirname(__file__), ".."))
 BUILD_DIR = abspath(join(ROOT, "build"))
 
 # ARM
-armcc = "standalone" # "keil", or "standalone", or "ds-5"
+armcc = "keil" # "keil", or "standalone", or "ds-5"
 
 if armcc == "keil":
-    ARM_PATH = "C:/Keil_4_54/ARM"
-    ARM_BIN = join(ARM_PATH, "BIN40")
-    ARM_INC = join(ARM_PATH, "RV31", "INC")
-    ARM_LIB = join(ARM_PATH, "RV31", "LIB")
+    #ARM_PATH = "C:/Keil_4_54/ARM"
+    ARM_PATH = "C:/Keil_v5/ARM"
+    ARM_BIN = join(ARM_PATH, "ARMCC", "bin")
+    ARM_INC = join(ARM_PATH, "ARMCC", "include")
+    ARM_LIB = join(ARM_PATH, "ARMCC", "lib")
 
 elif armcc == "standalone":
     ARM_PATH = "C:/Program Files/ARM/armcc_4.1_791"

あとは再度、以下のコマンドを実行すればビルドが完了します。

$ python workspace_tools\build.py -m LPC812 -t uARM

mbed LPC1768でWatchDogTimerを扱う

mbed LPC1768でWDTを使う方法を調べたので、備忘録として記す。

リファレンス

WDTとは

Watch Dog Timer、直訳で番犬タイマー。 マイコンの暴走や無限ループに陥った際、強制的にリセットをかける機構。

WDTはカウントダウンタイマーである。値がセットされるとカウントダウンを開始し、0になるとマイコンをリセットさせる。 この機能を活かして、マイコンの動作を監視する。

以下、監視の手順を簡単に説明する。 監視対象のプログラムに、一定時間以内にWDTのカウンタを再セット(タップ)する処理を入れる。すると、正常に動作している間はWDTが0になる前にタップが行われるため、WDTによるリセットはかからない。 しかし、マイコンの暴走や無限ループなどの理由によりWDTへのタップが行われなくなった場合、WDTのカウンタが0となり、強制リセットが行われる。

register description

以下、LPC1768のWDTに関するレジスタとその説明を記す。

Name Description
WDMOD WDTのモード設定とステータス確認用レジスタ
WDTC タイムアウト値設定レジスタ
WDFEED 0xAAの後に0x55を書き込むと、WDTCにセットした値がWDTのカウンタにセットされる
WDTV 現在のWDTカウンタ値を確認するレジスタ
WDCLKSEL WDTのクロックソースを選択するレジスタ

WDMOD

Bit Symbol Description
0 WDEN WDTを有効化する。1の場合はWDT実行中。
1 WDRESET WDTによる強制リセットを有効化する。1にすると有効となる
2 WDTOF WDTのタイムアウトフラグ。WDTによるリセットが行われると1になる。自動でクリアされないので、ソフトウェアでクリアする
3 WDINT WDT割り込みフラグ。読み込み専用
31:4 - 予約

WDENとWDRESETは一度設定すると、その後ソフトウェアからは無効化できない。

WDTは独立して動作する。そのため、デバッグ等で動作を止める場合、WDEN,WDRESETがともに1となっているとWDTによるリセットがかかり、デバッグができない。

WDTC

WDTのカウンタ値をセットする。 初期値は0xFFとなっている。

最小値はT_WDCLK * 256 * 4 (T_WDCLK = 1 / WDTクロックソースの周波数 ) 最大値は書かれていないため 0xffffffff と予想する。

WDFEED

ここに0xAA,0x55が書き込まれると、WDTCにセットされた値がカウンタにリロードされる。 つまり、WDTのタップ操作になる。

WDTV

現在のWDTカウンタの値を表示する。 ただしカウンタとの同期に6 WDCLKサイクル、加えて6 PCLKサイクルかかるため、実際のクロックの値に比べてWDTVの値は古くなる。

Name Description
WDCLK WDTのクロックソースから供給されるクロック
PCLK ペリフェラルクロック

WDCLKSEL

Bit Symbol Description
0:1 WDSEL クロックソースを設定する。詳細は後述
30:2 - 予約
31 WDLOCK 1を書き込むとWDTのクロックソースをロックできる。一度ロックされると、リセットがかかるまでクロックソースが変更不可となる。

WDSELは0x00~0x10をセットすることでクロックソースを設定できる。

Value Description
0x00 内蔵RCオシレータ
0x01 ペリフェラルクロック
0x02 RTCオシレーター
0x03 予約

プログラム例

mbed LPC1768でWatchDogTimerの動作を確認するコード

Macでmbedをデバッグする方法についてのまとめ

mbed Advent Calendar 2014の11日目です。

まえおき

mbedとの関わり

f:id:tnishinaga:20141211171140j:plain

現在私はmbedのプログラムを アセンブリ言語でコードをゴリゴリ実装して、バグを作っては治すを繰り返す日々をおくっています。

デバッガは必須

アセンブリ言語はCに比べて低級な言語なので、コーディング中に混乱して、バグを作ることが多いです(主観的発言)。 よくあるバグとしては、メモリ破壊、スタック破壊、リターンアドレスのpop忘れ、etc……。 簡単なデバッグ方法としてはprintfを用いたデバッグがありますが、今回はアセンブリで実装しているため、printfを挟むのは少々コストが大きいです。

そこで活躍するのがデバッガです。 このデバッガがあれば、プログラムを1命令ごと、レジスタの値を監視しながらデバッグすることができます。 これによりprintfでは調査しづらい細かな処理を追うことが可能となり、デバッグの効率を格段に上げることができます。 よって、デバッガは必須なのです。

mbedのデバッグ機構

f:id:tnishinaga:20141211171149j:plain

mbedの一部の製品には、メインのマイコンの他に、mbed interfaceと呼ばれる機能を持ったマイコンがついています。 このmbed interfaceはCMSIS−DAPデバッガとしての機能を持っているため、このmbed interfaceを持った一部の製品は、それ単体でデバッグを行うことができます。

f:id:tnishinaga:20141211172046p:plain

※ CMSIS-DAPの説明は特殊電子回路株式会社さまの「CMSIS-DAPって何?」を参照してください。

Macでmbedデバッグ

前置きが長くなりましたが、本題です。 Macでmbedのデバッグを行いましょう。

プログラムのエクスポート

mbedはプログラムをオンラインでコンパイルするという、画期的なシステムを採用しています。 しかし、このオンラインのシステムはコンパイルは出来ますが、デバッグを行うことができません。 デバッグのためにはオンラインのコードをローカルに保存し、オフラインコンパイル環境を用いる必要があります。 この方法については以下のページを参照し、「Exporting to GCC ARM Embedded」でGCC用のコードをエクスポートしてください。

デバッグ環境の整備

私は普段はMac OS Xを用いています。Windows機も所持していますが、もっぱらゲーム専用機としてしか使っていません。

残念なことに、ARM社謹製の統合開発環境 MDK-ARMは、現状Windows専用ソフトウェアです。 そのためMac環境ではライセンス料が云々の前に、使うこと自体ができません。 それでもなんとかMacで開発を行うため、GNUのフリーな環境を用いて開発環境・デバッグ環境を整えます。 その方法は以前ブログ記事にまとめたので、こちらを参照してください。

Tips: GNU開発環境でのアセンブリ利用時の注意

GNUな開発環境とMDK-ARMでは、アセンブリコードの書き方が異なるため、アセンブリコードの互換性がありません。 そのため、アセンブリで開発する際は、デバッガの使えないオンライン上で完結させるか、WindowsでMDK-ARMを用いて開発を行うか、もしくはオンラインへ戻ることを諦めてGNUな書き方を行うかを判断する必要があります。

私は青mbedのプログラムフラッシュが豊富であり、MDK-ARMを用いずともメモリが足りているので、GNUツールで開発することにしました。 オンラインへの復帰は、開発が完了した後に手動でアセンブリコードを書きなおして行う予定です。

GDBの操作方法(簡易説明)

GDBを用いてデバッグする方法を、簡単に説明します。

GDBサーバーへの接続

(gdb) target remote localhost:3333

プログラムのmake

(gdb) make

プログラムのロード

(gdb) load

なお、以前ロードしたプログラムと新しくロードするプログラムに差異がある場合は、後述のdisplayの設定が削除されます。 breakpointの設定は残ります。

状態の表示

displayコマンドを用いると、レジスタやメモリの値を逐次表示することができます。 自分のおすすめは以下。

(gdb) display/i $pc
(gdb) display/x $r0
(gdb) display/x $r1
(gdb) display/x $r2
(gdb) display/x $r3
(gdb) display/x $r4
(gdb) display/x $r5
(gdb) display/x $r6
(gdb) display/x $r7
(gdb) display/x $r8
(gdb) display/x $r9
(gdb) display/x $r10

これでプログラムカウンタの指すアセンブリコードを表示しつつ、レジスタr0~r10までの値を16進数で確認できます。

再実行

(gdb) continue

プログラムカウンタの指す場所から処理を再開します。 後述のbreakpointに引っかかるまで止まらないので注意してください。 強制的に止めたい場合はCtrl+Cを入力します。

breakpoint

(gdb) breakpoint *0x0000a410

特定のアドレスにbreakpointを仕込んで、その位置で処理を止めることができます。 上記のコマンドでは、プログラムカウンタがメモリアドレス0x0000a410になった時、処理を止めることができます。

なお、本来condition等を用いれば変数の値が変化した際に止める……ということができますが、pyOCDの環境で使ったらpyOCDがハングしました。 再現性の確認等ができていないので、バグ報告は行えていません。

1命令実行

(gdb) stepi
(gdb) nexti

アセンブリでは1命令ごと実行する必要があるため、 C言語のstep命令はstepi、next命令はnextiとなります。

おわりに

以上、Macでmbedをデバッグする方法についての簡易デバッグ説明でした。 デバッグ時にgdbサーバーを建てるため使用したpyOCDをもう少し活用すると、より柔軟なデバッグも可能ですが……今回はここまで。 要望があれば、PyOCDを使ってHard Fault原因を探る方法を、再度advendカレンダーに書こうかとおもいます。

緩募

  • ARMマイコン発売から現在までのシェア情報の書かれた資料
  • mbed発売から現在までのシェア情報の書かれた資料

次の人

次はjksoftさんです。よろしくおねがいします。