mcommit's message

ソフトウェア開発の仕事をしているsimotinといいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

RV32C ~圧縮命令ってなんだ?~

モナリザ本の第7章を読んでみました。

RISC-V原典  オープンアーキテクチャのススメ

RISC-V原典 オープンアーキテクチャのススメ

前回の記事でRISC-Vのアセンブラについて調べていて気になっていた圧縮命令について書かれた章です。章といいつつこの章は実は参考文献のリストなどをあわせても7ページしかありません。

RISCのデメリット

RISC系のCPUは命令セットがシンプルな分アセンブラのコード量が多くなりがちです。シンプルな命令の組み合わせつつ、パイプラインを有効活用する事で命令あたりのクロックサイクルを少なくすることがRISCの戦略ということになりますが、命令を組み合わせる分、使用する命令数(サイズ)はCISC系と比べて多くなります。*1

使用する命令数(サイズ)が多くなるということは、テキストセクションのサイズが大きくなるということで、これは組込ソフトにおいてプログラム使用するROMのサイズが大きくなります。

マイコンの値段は内蔵ROMのサイズで変わってきますので、プログラム領域もデータ領域も(もちろん使用するメモリサイズも)小さいに越したことはありません。

前置きが長くなりましたが、ようするにRISCではプログラムサイズが多くなるというのがデメリットとして存在するわけですが、この問題に対するRISC-Vとしての解答がRV32Cの圧縮命令ということのようです。

圧縮命令の特徴

命令長が短い版の命令セットがあるという点ではARMのThumb命令も同じですのであまり珍しく感じませんでした。

RISC-Vの圧縮命令の特徴は何かあるのでしょうか。
7章を読んでみて分かったのですが、この圧縮命令はアセンブラとリンカだけが意識し、コンパイラ開発者やアセンブリ言語プログラマは圧縮命令を意識する必要がないそうです。

お前は何を言っているんだ?


という気持ちになったのですが、要するに1つの命令のニーモニックは通常のRV32IでもRV32C(圧縮命令)でも共通になるということです。

気になったので改めて確認してみました。

実験

前回の記事、
mcommit.hatenadiary.com

でも少し触れましたが、同じli(load immediate)命令であってもエンコードのされ方に違いがあります。
asコマンドでアセンブリした場合、


$ cat tmp.s
li a0,0
$ riscv64-unknown-elf-as tmp.s # a.out が生成される
$ riscv64-unknown-elf-objdump.exe -S a.out
a.out: file format elf64-littleriscv

Disassembly of section .text:

0000000000000000 <.text>:
0: 00000513 li a0,0

00000513という32bitエンコードされています。

では、C言語で同様のアセンブリを期待したコードを書いて試してみます。


$ cat tmp.c
int return_zero(void)
{
return 0;
}

$ riscv64-unknown-elf-gcc tmp.c -c -O1
$ riscv64-unknown-elf-objdump.exe -S tmp.o

tmp.o: file format elf64-littleriscv


Disassembly of section .text:

0000000000000000 :
0: 4501 li a0,0
2: 8082 ret

C言語コンパイラを通すとなんと16bitエンコードされています。
*2

コンパイラ開発者・アセンブリプログラマは圧縮命令を意識しなくてよい

というのはつまりこういうことなんだと思います。
ここでは同じ li a0, 0という命令が16bitにも32bitにもエンコードされました。

これはありがたい反面、コンパイラ(アセンブラ)の実装によっては思わぬトラブルを生み出しそうな気もします。
組込ソフト開発の場合、書いたコードがどういったバイナリになっているかをシビアに意識しないといけないケースもありますので出来れば明示的にコントロールしたいところです。

一般的にはこういった場合コンパイラに対するオプションとかで指定できたりすると思うのですが、gccの場合どう対応しているのでしょうか。まだそのあたりは調べれていませんが気になります。

*1:あと速度最適化の選択肢が少なくなると思います

*2:コンパイル時に-O1をつけましたがこれは最適化を付けないと冗長なアセンブラが吐かれるためです。-O1なしでも16bitでエンコードされます

RISC-Vのアセンブラについて調べてみた

昨日はFreedom Studioでデバッグする方法について書きましたが今日はRICV-Vに慣れるためにレジスタアセンブラについて少し調べてみました。
mcommit.hatenadiary.com

概要

HiFive1 Rev.Bで使用されているCPUはFE310-G002。命令セットはRV32IMACというISAらしい。
名前を知ったところで現時点では何も分からない。

よく出てくる命令

とりあえずCのコードの逆アセを眺めて出てきた命令を列挙してみました。

命令 意味(英語) 処理
jal Jump and Link 関数呼び出し
add Add 加算(レジスタ)
addi Add Immediate 加算(直値)
sw store word メモリへのストア(word)
sd store double メモリへのストア(double)
li load Immediate レジスタへのロード

jal

X86のCALL、ARMのBL(Branch with Link)命令相当。
RISC-Vでは$raがARMのリンクレジスタに相当するらしい。

add, addi

レジスタを使った加算はadd。直値を使う場合はaddiになる。
レジスタか直値で命令が違うのはあまりみたことがなかった。
デコードするときに扱える値の範囲が変わるというメリットはあるかもしれない。

sw,sd

オフセット(レジスタ名)
例). 8($sp)
のような表記になります。一度覚えてしまうとわかりやすい表現方法のような気がします。

gcc の冗長さ

最適化をかけないと関数の入り口と出口で、使おうが使うまいが愚直にプロローグコードとエピローグコード(ローカル変数用領域の確保と解放)を出力しています。
また reutrn 0 や return 1 のような直値を返す関数であっても一度a5レジスタを介してa0に書き込みをしています...
MIPS流のお作法なのかもしれないがさすがに冗長ですよね...

なお、この状況なコードは -O1 の最適化をつけると一瞬にして素直なコードになりました。


直値のエンコードの謎

Cで0を返すコード(return 0;)をコンパイルしてみました。
0を返す機械語が4501になっていたので不思議に思い0~5までの直値を返す関数のアセンブラを見てみました。

int return_zero(void)
{
    return 0;
}

int return_one(void)
{
    return 1;
}

int return_two(void)
{
    return 2;
}

int return_three(void)
{
    return 3;
}

int return_four(void)
{
    return 4;
}

int return_five(void)
{
    return 5;
}

結果、

0000000000000002 <return_zero>:
   2:	4501                	li	a0,0
   4:	8082                	ret

0000000000000006 <return_one>:
   6:	4505                	li	a0,1
   8:	8082                	ret

000000000000000a <return_two>:
   a:	4509                	li	a0,2
   c:	8082                	ret

000000000000000e <return_three>:
   e:	450d                	li	a0,3
  10:	8082                	ret

0000000000000012 <return_four>:
  12:	4511                	li	a0,4
  14:	8082                	ret

0000000000000016 <return_five>:
  16:	4515                	li	a0,5
  18:	8082                	ret

0→4501を開始として、1:4505 2:4509 3:450d ... と直値は4ずつ増えてエンコードされているようです。
どこまでつづくのかは分かりませんが、ぱっと見た限りでは、4 * n + 1 がエンコードされた値になります。

ちなみに、関数の戻り値は a0 レジスタで受け渡しするようです。

圧縮命令ってなんだ?


li a0, 1

を tmp.sというファイルに保存して、riscv64-unknown-elf-asでアセンブルしてみました。objdumpで見てみると、上記のC言語からコンパイルしたコードとは違うコードが生成されました。
上記のC言語からコンパイルしたアセンブラでは16bitでエンコードされています。
ところがアセンブラエンコードされたコードは同じニーモニックにも関わらず 4byteでエンコードされています。

調べてみるとRISC-Vには圧縮命令という命令セットがあり、短い命令長でエンコードされるようです。雰囲気的にはARMのThumb命令と似たような感じでしょうか...
ただし、ARMの場合は命令のアラインメント位置でThumb命令かどうかの判別ができますがRISC-Vの場合ぱっと見では32bit命令なのか圧縮命令なのか分かりませんね。

つまり、上記の

0000000000000002 <return_zero>:
   2:	4501                	li	a0,0
   4:	8082                	ret

のような2byteでエンコードされた命令は圧縮命令になります。

見比べてみた限りでは、li命令は 32bit命令では 0513 が下位ワードに来るようですので1ワードの特定のビットでスムーズにデコードできるようになっているんだと思います。
圧縮命令は4501や4505なので14bit目のようにも見えます。この辺は真面目に命令セットの仕様を見てみないとよくわかりません。

直値が4ずつ増えるのも圧縮命令と関係がありそうな気もします。

とりあえず手元のモナリザ本を開いてみると7章にRV32C:圧縮命令の章がありました。

RISC-V原典  オープンアーキテクチャのススメ

RISC-V原典 オープンアーキテクチャのススメ

今日は疲れたので、明日はこの章と第2章のRV32I:RISC-V基本整数ISAの章を読んでみたいと思います。

HiFive1 RevB を買った

SiFive社から販売されているHiFive1 RevBのボードを買いました。

f:id:simotin13:20190527001529j:plain
Hifive1 Rev.B

目次

  • 目次
  • 注文してから届くまで
    • 郵送について
  • 開発の始め方
  • デバッグ
    • フォーラムについて
  • 感想

注文してから届くまで

GW前になんとなく欲しくなってポチっていました。元々HiFive1の存在は知っていましたが単純にArduino互換ボードで開発の自由度が高そうではなかったのであまり興味がもてませんでした。
今回購入したHiFive1 Rev.Bはオンボードでデバッガが搭載されているのでRISC-Vアーキテクチャの勉強に使えそうです。

CrowdSupply order detail
CrowdSupplyの注文明細

注文履歴を見ると4/25に注文しています。届いたのは5/22なのでほぼ1か月かかっています。
といっても入荷日が5/9だったようなので実質的には2週間もあれば届くようですね。

郵送について

商品はUSPSで発送されます。
発送後はネットで最新の情報が見られるので、自分が注文した商品がいまどこにあるのかワクワクしながら届くのを待つことができます。
履歴を見ているとアメリカのオレゴン州ポートランドを出発して、成田に到着するまで約3日程度でした。*1
ここまではかなりスムーズに配達されているように感じたのですが、関税の関係のためか成田についてから何日も待たされます。

開発の始め方

ドキュメント類の入手

とりあえずマニュアルやら回路図やらを公式サイトからダウンロードします。
www.sifive.com

Getting Started Guide が提供されているのでまずはこれを読むのがよさそうです。
https://sifive.cdn.prismic.io/sifive%2F8d7b8385-64e3-4914-8608-8568412c8aae_hifive1b-getting-started-guide.pdf

この Getting Started Guide は開発環境や基板の概要について説明してくれています。全部で26ページとボリュームはないので一読しましょう。

Freedom E310-G002 Manualはチップのハードウェアマニュアルですね。開発環境の構築が終わったらじっくり読んでいきたいですね。*2
https://sifive.cdn.prismic.io/sifive%2F9ecbb623-7c7f-4acc-966f-9bb10ecdb62e_fe310-g002.pdf

*1:なぜか途中で逆方向のダラスに到着しているのを見たときは少し不安になりました

*2:116PしかないのでこちらもH/Wマニュアルにしては簡潔な気がしますが

続きを読む

MySQLサーバに外部から接続できないとき

自分用メモ。

MySQLサーバにホスト外から接続できず調べるのに時間がかかりましたのでメモを残しておきます。
ただし、これは開発環境として利用する場合の設定ですので、本番の環境としてはこのような設定はしないでください

ユーザー権限の設定

例えばrootユーザでどこからでも接続されたい場合は


grant all privileges on *.* to root@"%" identified by 'rooのpassword' with grant option;

mysqlにログインして実行します。

bind-addressの設定

さて、ユーザ設定をしたのはいいのですが外部から接続できません。
色々調べた結果、/etc/mysql/mysql.conf.d/mysqld.cnf に*1


bind-address = 127.0.0.1
の記載を変更してあげる必要がありました。

bind-address = 0.0.0.0

う~ん...bindアドレスも設定ファイルで制御できるようになっているんですね。
知りませんでした。


詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

*1:/etc/mysql/mysql.conf.d/mysqld.cnfは私の使っている環境Linux Mint(Ubuntu系での例です)

pcduinoでOSを自作する ~第1回 環境構築~

最近OSの仕組みを勉強しているのですが、教科書的な勉強だけだとなんだか退屈してしまうのでARMの基板でOS自作してみることにしました。
この手の趣味プロジェクトはなかなか長続きしないことが多いのですが、モチベーション維持のためにも活動記録をあげておきたいと思います。

ターゲット

ターゲットにするのはpcDuinoという基板です。
f:id:simotin13:20190414214420j:plain


pcDuino Linux Dev Board
akizukidenshi.com

私の手元にはこの基板があるのですが、V2という新しいバージョンの基板も出ているようです。*1
akizukidenshi.com

なぜこの基板にしたのか?

Coretex-A8はA系のCPUとしては古いCPUになりますが、あえてこのCPUで試してみたいと思います。
理由はコア数が1だからという単純な理由です。RaspberryPiのような最近の基板では、CPUが64bitだったり複数コアだったりします。
今回のOS自作は自分の勉強・教育が目的なのでできれば機能が少ない方がやりやすいかな考えています。*2

目標

ざっくりとはARMの基板でOSを作るということですが、もう少し具体的なゴールを決めておきたいと思います。

MMUを使うこと

組み込みの仕事をしているのでMMUのないマイコンを扱うことが多いです。あるいはCortex-A系のマイコンを使う場合はBSPのLinuxが載ること多いので、MMUを扱うOSのことが今だによく分かっていません。

これを機会にMMUの扱い・仮想メモリ・ページングといった機能についてきちんと理解することを目標にしたいと思います。

Ethnernetコントローラを動かす

せっかくOSを書くのであれば最低限Ethernetは対応したいです。
でもプロトコルスタックどうしよう。まぁそれはそれでネットワークの勉強にもなって一石二鳥になるはず。

HDMIGUI出力をすること

HDMIのコントローラとか触ったことないですが、夢は大きく持ちたいと思います。*3

環境構築

OSを開発するにあたって準備が必要です。

用意するもの(ハードウェア)

  • pcDuino

秋月電子から購入しました。

  • usb miniBケーブル

電源用です。

  • USB-シリアル変換ケーブル

OS自作する場合、最初はパソコンのような「画面」が存在しません。動作確認はもっぱらLEDやUARTを使って行います。
パソコンからUARTの出力を確認するためにUSB-シリアル変換ケーブルが必要になります。
この手のケーブルは秋月電子やアマゾンで購入できます。合わせてオス-メスのジャンパワイヤも必要になります。

  • micro SDカード

自作したOSはmicro SDカードに書き込んで起動させます。
*4

開発するPCを除くと、物理的に必要なものは上記4点になります。
開発作業はLinux環境で行います。開発用のツールチェインがインストールでき、microSDカードを認識できればなんでも構いません。
私はMintLinux 18.3を使用して開発をしていきます。ツールチェインのインストールはXxxで説明します。

開発環境の構築

開発環境の構築としては、

  1. クロス開発用のツールチェインのインストール
  2. AllWinner用のイメージ作成ツールのビルド

の2ステップが必要です。

クロス開発用のツールチェインのインストール


sudo apt install gcc-arm-none-eabi
で完了です。
/usr/bin/ 以下に arm-none-eabi-*** のツールチェイン一式がインストールされます。

AllWinner用のイメージ作成ツールのビルド

自作したOSはSDカードに書き込んでブートするのですが、単純にプログラムが書き込んであるだけでは駄目で、AllWinner用のブートイメージに変換する必要があります。イメージのロードをBROM内のプログラムがロードしてくれるのですが、チェックサムなどのチェックを行っているようです。

変換ツールはu-bootのビルドツールの1つとして公開されているようですが、手っ取り早くビルドできるよう
こちらの方が修正されたコードを公開されていますので利用させて頂きした。
github.com


git clone https://github.com/hipboi/mksunxiboot.git
cd mksunxiboot
make
sudo cp mksunxiboot /usr/local/bin

参考にするレポジトリ

これでBaremetalからのOS自作の準備は整いましたが、ブートやUARTの実装など、こちらの実装を参考にさせて頂きます。

github.com

つづき

環境構築はできたので、さっそく開発に着手しますがこの記事はここまでにしておきます。

次の記事では、CPUのリセット後の状態、UARTの有効化、Lチカ等について行った成果を挙げたいと思います。

*1:CPUは同じCoretex-A8のようです

*2:それでもワンチップマイコンからすると多機能なので途中で挫折する可能性が高いですが

*3:コントローラのレジスタ数多そうだな

*4:容量は4GBや8GBの少ないサイズでも問題無いと思います

Web+DB vol.109 を読んだ

Ruby2.6の記事が気になって買ってみたのですが、面白い記事があったのでとりあえず自分のためにメモを残しておきたいと思います。
最近は雑誌を買っても一度も開かずに積本になることもあるのでとりあえずこういったメモをアウトプットするだけでも、後々振り返ったりする際に道しるべになりそうなので質と量はともかく書いておきます。

WEB+DB PRESS Vol.109

WEB+DB PRESS Vol.109

  • 作者: 佐藤歩,加藤賢一,原一成,加藤圭佑,大塚健司,磯部有司,村田賢太,末永恭正,久保田祐史,吉川竜太,牧大輔,ytnobody(わいとん),前田雅央,浜田真成,竹馬光太郎,池田拓司,はまちや2,竹原,原田裕介,西立野翔磨,田中孝明
  • 出版社/メーカー: 技術評論社
  • 発売日: 2019/02/23
  • メディア: 単行本
  • この商品を含むブログを見る

Ruby 2.6徹底解剖

@mrkn さんの記事。

Rubyのリリース予定について

Ruby3.0が2020年12月25日のリリースを目標としているなんて知らなかった。2019年12月25日が2.7のリリース予定日らしい。2.8と2.9はどうなるのか....

2.6 を試したいとき

Dockerで2.6の実行環境が配布されているとのこと。*1

Procの合成

合成演算子というものをつかってProcを合成できるらしい。

感想

とりあえず目に留まったものをメモとして書いてみましたが他にもいろいろと変更点があるようです。

Puppetterの記事

GUIを持たないChromeとそれを扱うライブラリであるPuppeteerの記事。
「note」のタイムラインをスクレイピングするという記事が書かれていました。

私もnoteの記事をスクレイピングしたいと思っていてSeleniumuの勉強を始めたところでした。
PuppeteerとSeleniumの違いとかどうなんだろう。

Selenium実践入門 ―― 自動化による継続的なブラウザテスト (WEB+DB PRESS plus)

Selenium実践入門 ―― 自動化による継続的なブラウザテスト (WEB+DB PRESS plus)

筆一本はいかに実現したか

結城先生へのインタビュー記事。何を意識して執筆活動をされているのかが書かれていてとても面白かった。
上記の「note」も結城先生の数学ガールを読むために購読しています。
自分が発信する言葉が相手に伝わってどう解釈されるかを意識しながら書いているという言葉がとても印象に残りました。

記事を読んで、ダウンタウンのまっちゃんが

紳助さんの笑いは耳で聴く笑いやけど、ぼくの笑いは耳で聴いて一回頭でイメージして面白いってなる笑いやから

って話されていたのを思い出しました。
言葉を使って商売されている方はやはり相手にどう伝わるかに対してとても敏感なんですね。
私もこれから意識していきたいと思いました。

感想

全体的に面白い記事が多かったです。買ってよかった!

*1:自分の手元には一応ビルドした2.6は入っている

KLEE を試してみた。

シンボリック実行のツールとして公開されているKLEEを試してみました。

dockerのインストール

KLEEの環境を構築するのはdockerのイメージを使うのが一番手軽に試せるようです。
dockerについてはこちらの記事を参考にインストールしてみました。
qiita.com

dockerイメージの実行

dockerのインストールが完了したらイメージを取得して実行します。


# イメージの取得
$ docker pull klee/klee
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
klee/klee latest f0052ebadb00 7 months ago 1.31GB

# 実行
$ docker run --rm -ti --ulimit='stack=-1:-1' klee/klee

# dockerのコンテナを起動するとシェルが立ち上がります。
klee@684a74481856:~$ pwd
/home/klee
klee@684a74481856:~$ ls
klee_build klee_src

チュートリアル

KLEEの最初のチュートリアルがこちらのサイトで解説されています。
klee.github.io

シンボリック実行を試すコードは以下のようなコードとして示されています。
引数で渡された数値の符号を判定する関数のようです。

/*
 * First KLEE tutorial: testing a small function
 */

#include <klee/klee.h>

int get_sign(int x) {
  if (x == 0)
     return 0;
  
  if (x < 0)
     return -1;
  else 
     return 1;
} 

int main() {
  int a;
  klee_make_symbolic(&a, sizeof(a), "a");
  return get_sign(a);
} 

チュートリアル自体は丁寧に解説が書かれていますのでここでは詳細は書きませんが、注意点として、上記のコンテナのシェル上では、 klee/klee.hは klee_src/include に展開されています。
従って get_sign.c を /home/klee 以下で配置した場合にビットコードにコンパイルするコマンドは


$ clang -I klee_src/include -emit-llvm -c -g get_sign.c

になります。

感想

dockerを普段使うことがないのでとまどいました(というかまだよくわかっていないのでもう少しdockerに対する勉強が必要そうです。
今回は以前に買って積本になっていたdocker教科書第2版が役に立ちました。

プログラマのためのDocker教科書 第2版 インフラの基礎知識&コードによる環境構築の自動化

プログラマのためのDocker教科書 第2版 インフラの基礎知識&コードによる環境構築の自動化

KLEE本体がちゃちゃっとmakeして使えないのは不便な気もしますが、dockerで配布しているということはmacwindowsでも使えるということですよね。KLEEをwindowsでも使えないか試してみたいと思います。

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)