ARM版マイコンシミュレータを Mac/Linux/Windows 環境で自作した話

#概要
この記事では，ARM版マイコンシミュレータをソフトウェア上で自作しよう！という試みをつらつらと書いています．

#動機と目標
そもそもなぜARM版のマイコンシミュレータを自作するんですか？という問いがあるかと思います．

有名どころでは，[QEMU](https://ja.wikipedia.org/wiki/QEMU) というオープンソースがあるのに，なんでわざわざ作るの？と聞かれそうです．少なくともこれまでの自分はそう思っていました．

##動機
数年前，マイコンシミュレータ([athrill](https://qiita.com/kanetugu2018/items/1f2ef93c9e1fa7a29f97))を自作しました．
とてもマイナーで，きっと誰もしらないと思います．

これまでqiita記事とか発表させてもらえる場では積極的に宣伝してきましたが
やっぱりマイナーなんだよね〜って職場の同僚につぶやいたところ，
「やっぱり対応しているCPUがV850だからなんでは？」
という結論に至りました．
※きっと，一般の方はv850なんて知らないですよね？車載系では昔よく使われていたんですけどね．．

##そうはいっても
自作したマイコンシミュレータ athrill は，様々なCPUアーキに対応できるように設計していました．さらに，LinuxとWindows/docker上で実行できるようにしていました．

[TOPPERS](https://www.toppers.jp/index.html) の RTOS も色々と動かせるようにしましたし，さらには Unity と連携して [ETロボコンシミュレータ](https://qiita.com/kanetugu2018/items/0e521f4779cd680dab18)として利用できるようにもしました．

「でも，CPUがv850なんすよね〜．IoT機器はARMだっていうのに，v850ではもうダメですよ(心の声)．」

QEMU使えば良いじゃん！っていう人もいらっしゃるかもしれませんが，やっぱり自作にこだわってます．

##目標
そんなわけで，athrill を ARM 対応しようって決めたわけですが，いくつか大きな目標を考えました．

1. 開発環境を完全クロスプラットフォーム化する(Mac/Linux/Windows)！
* ARM版のathrillからは DSL で命令記述して開発を効率化する！
* TOPPERS の RTOS をこれまでどおり動かせるようにする！
* ETロボコンのターゲットCPUはARMなので，現状のETロボコンシミュレータをARM化する！
* MMU対応して，Linuxさえもサクサクっと動かせるようにする！

こんな大きな目標ぶちあげて大丈夫なの？と思われるかもしれませんが，地道にコツコツやっていればいつか実現できるはずですよ〜．くらいの気持ちで始めることにしました．

#進捗状況
2020/02/02の進捗状況としては，「３」まで終わりました．
今，４ やってます．案外やればできるもんです．

ARM版のathrillは以下で公開しました．ARMv7-Aです．

https://github.com/tmori/athrill-target

対応している命令は ARM命令だけで thumb 命令はまだです．さらに，ARMは約400個の命令ありますが，まだ80個くらいしか実装してないです．それでも，RTOSが動くための最低限の命令セットの実装はしています．

2020/03/01の進捗状況としては，「４」がほぼ終わりました．
もちろん ETロボコンシミュレータ動いてます．実装した命令数はちょうど100個です．

https://qiita.com/kanetugu2018/items/0e521f4779cd680dab18

でも，サンプルサンプルプログラムが動いただけなもので，まだ何が起きるか未知数です．
もし，デコードエラーになった場合は，以下に issue を挙げていただければ対応します．

https://github.com/tmori/athrill-target

この際，調査用に頂きたい情報は以下になります．
1. athrillが出力したエラーメッセージ
　例．CPU(pc=<アドレス>) Exception!!
2. エラー発生した箇所のアセンブラ命令コード(objdumpの結果)
　例．arm-none-eabi-objdump -D asp | less

objdumpの出力書式は以下の通りです．
<アドレス>: <機械語(16進数) <アセンブラ命令> <オペランド>

実行すると，こんな感じで出力されますから，この内容をコピペ頂ければと．

```
1800504c <main_task>:
1800504c: e92d4800 push {fp, lr}
18005050: ed2d8b02 vpush {d8}
18005054: e28db00c add fp, sp, #12
18005058: e24dd010 sub sp, sp, #16
1800505c: e50b0018 str r0, [fp, #-24] ; 0xffffffe8
```


#クロスプラットフォーム化について
athrillは元々，クロスプラットフォームを意識して設計・実装していました．
POSIX系のAPIを積極的に利用して，移植しやすくしています．

さらに，今回からコンパイラを gcc だけでなく，clang でもビルドできるようにしましたので，Mac との親和性よくなりました．

gcc のビルドディレクトリ(Linux/WSL用)：
　https://github.com/tmori/athrill-target/tree/master/ARMv7-A/build_linux

clang のビルドディレクトリ(Mac用)：
　https://github.com/tmori/athrill-target/tree/master/ARMv7-A/build_mac

ちなみに，clangだと，[サニタイザ](https://clang.llvm.org/docs/AddressSanitizer.html)色々あるので，今後の athrillのバグとりに期待してたります．

#DSLによる命令セットの記述について
職場のちょー優秀な同僚が，ARM命令セットをDSLで記述すると機械語をデコードするプログラムを自動生成してくれるツールを作ってくれました．

現在，athrillでの試作開発中なので，まだ一般公開されていませんが，ある程度実績できたら一般公開されるそうです．

このツールのおかげで，私の命令セット実装コストは大幅に削減されました．
早ければ１命令，約１０分で実装できます．

DSL は，yaml でこんな感じで記述します(レジスタベースのADD命令です)．

```
   - name: arm_add_reg_a1
     format:xxxx:cond|00|0|0100|x:S|xxxx:Rn|xxxx:Rd|xxxxx:imm5|xx:type|0|xxxx:Rm 
     unmatch_condition: > 
                         (cond == 0b1111)  
                         or ( (Rd == 0b1111) and (S == 1) )  
                         or (Rn == 0b1101) 
```
こんな感じで記述しておくと，自動的に機械語命令のパーサーができてしまうんですから，とても開発は楽チンです．

現時点の定義内容は以下で公開しています．

https://github.com/tmori/athrill-target/blob/master/ARMv7-A/mcdecoder/instruction/arm.yaml


#athrillのインストール方法
ARM版athrillのインストール手順は以下の通りです．

* athrill のチェックアウト
* athrill-target のチェックアウト
* コンパイラのインストール
* ビルド＆インストール

##athrill のチェックアウト
athrill は，設計上，CPUアーキに依存しない共通コードとCPU依存するコードを分離しています．

共通コードのチェックアウトは，以下の通りです．

```
$ git clone https://github.com/tmori/athrill.git
```

##athrill-target のチェックアウト
CPUアーキに依存するコードは，athrill-target側で管理しています．
今回のARM対応版は，ここにあります．

```
$ git clone https://github.com/tmori/athrill-target.git
```

なお，athrill と athrill-targetを以下のフォルダ構成にしてください．

```
.
├── athrill
└── athrill-target
```

#コンパイラのインストール
Linux の方は，gcc をインストールください．
Windows の方は，WSL上で gcc をインストールください．
Mac の方は，clang をインストールください．

##ビルド＆インストール
ビルド方法ですが，端末上でathrill-target/ARMv7-A に移動してください．

Linux/Windowsの方は，さらに build_linux に移動してください．
Macの方は，build_mac に移動してください．

移動終わったら，以下コマンド実行するだけです．

```
make clean;make
```

ビルド成功すると，athrill側の bin/linux 配下に athrill2 というバイナリが配置されるはずです．

```
$ ls -l ../../../athrill/bin/linux/athrill2 
-rwxr-xr-x  1 tmori  staff  628260  2  2 16:40 ../../../athrill/bin/linux/athrill2
```

そして，このパスを .bashrcに登録してもらえれば，インストール終了です．
以下，設定例です．

```
export PATH=<athrill配置フォルダパス>/athrill/bin/linux:${PATH}
```

#ARM開発環境について
ここまでくれば，athrillは普通に使えるようになりますが，肝心のARM開発環境を準備しておく必要があります．

最低限必要なのはARM用のクロスコンパイラだけです．

お使いの環境上で，arm-none-eabi-gcc をインストールしてください．
Linux/WSL/Mac どこでも，ARMのgccコンパイラは容易にインストールできます．
※v850だとこれができないんだな〜(汗

#リアルタイムOSを動かしてみる
今回，GR-PEACH用のTOPPERS RTOS(ASP) をARM対応版athrillで動作できるようにしました．

サンプルコードは，以下で公開しています．

https://github.com/tmori/athrill-sample/tree/master/os/asp_arm

RTOSの実行デモは，以下でつぶやいてみました．

https://twitter.com/i/status/1218447669929988096

タスク起動確認までできています．

#今後について

##2020/02/02時点
RTOSはなんとなく動くようになったので，次は，ETロボコンシミュレータ用に浮動小数点演算命令の実装を粛々とやっています．

とりあえず，四則演算はできるようになったので，EV3RTをARM用にビルドして，Unityと結合してみようと思っています．

これができれば，ETロボコンシミュレータのARM対応ができるようになりますから，v850とはおさらばです．ETロボコン競技者の開発準備はとても楽になることでしょう．こうご期待ください．

##2020/03/01時点
運良くETロボコンシミュレータが動き出したので，お次はLinuxか？と思いましたが，ハードル高すぎなので，もう少しETロボコンシミュレータと遊ぼうと決めました．

ETロボコンシミュレータ使っていただいている方々から沢山のコメントいただいているので，もっと機能拡張しないとなという使命感がふつふつと湧いてきました．

やっぱり，あれですかね．コメント頂いている，制御用プログラムの変数の時系列情報を出力する機能かな？