コンピューターが本当にわかる言葉は0か1のカタマリ(2進法)で表現されたマシン語だけです。

どのような2進法表現でどう動くかはコンピューターによって違います。


IchigoJam Rで使っているコンピューターは、16コの0か1のカタマリ(16bit/16ビット)で動きをコントロールします。

0000010100000101

これはX10レジスタというコンピューターの一時記憶の1番目に1を足すというマシン語です。(RV32C RISC-Vマシン語表

最初の3bitと最後の2bitが足し算をしろという命令コード(c.addi)、一つ飛ばして5bitが使うレジスタの番号、残りの6bit(bit12とbit6-2)が足す数です。

000 0 01010 00001 01

これをPOKE文を使ってメモリに書き込みます。

POKE#700,`00000101,`00000101

#700はメモリの位置を表します。`は2進法で数値を表します。
下位の8bitを先に、上位の8bitを後に書くのがこのコンピューターのルールです(リトルエンディアン)。

動かすにはもう1つ命令が必要です。IchigoJamからの呼び出しから戻って来いという命令です。 (BASICのGOSUBに対して、RETURN的なもの)

1000000010000010

この呼び出し元に戻るマシン語も同じようにメモリに書き込みます。

POKE#702,`10000010,`10000000

準備ができたので実行してみます。

?USR(#700,1)

結果に正しく2と返って来ましたか?
マシン語は間違えると、IchigoJamのシステム自体が停止してしまいます。
安全策が無い分、コンピューターのフルパワーが出せるのがマシン語の最大のメリットです!
長いプログラムをつくった時は、保存してから動かしましょう。

USRコマンドは呼び出しメモリ位置と、渡す数を指定します。100を渡して結果を確認してみてください。

?USR(#700,100)

メモリを書き換えて5足すプログラムに変更してみましょう。(ビット演算で2bitずらし、c.addi命令を表す末尾01を足す。リトルエンディアンなので後8bitがメモリ上では先にくることに注意)

POKE#700,5<<2+1 ?USR(#700,100)

足す数を変更できました。

このような計算命令や、計算した結果によって処理を変更する命令などのマシン語でコンピューターは動いているわけです。

応用編「IchigoJam Rβでも輝くWS2812B、RISC-Vマシン語で10ナノ秒単位で制御する
RISC-V版マシン語はじめのいっぽの連載、はじめます!

- 連載、IchigoJamではじめる、Armマシン語入門
1. はじめてのマシン語
2. ハンドアセンブルで超速計算!
3. マシン語メモリアクセスで画面超速表示!
4. マシン語でLEDを光らせよう!
5. 楽しさ広がるマルチバイトメモリアクセスとスタック
6. マシン語使いこなしTIPS
7. カジュアルに使うインラインマシン語
8. アセンブラを使って楽しよう
9. マシン語で高速SPI
10. マシン語を制するもの時間を制す
11. 画面をイチゴで埋め尽くす12の方法
12. レジスタ不足に上位レジスタとスタック操作
13. コンパイラはじめのいっぽ、EVAL実現法とマシン語生成
14. サイズを取るかスピードを取るか、割り算のアルゴリズムとマシン語実装
15. マシン語化で1万倍速!? セットで学ぶアルゴリズムとコンピューター

- 参考リンク
命令一覧「Cortex-M0 テクニカルリファレンス マニュアル - Arm
マシン語の仕様「Armv6-M アーキテクチャ リファレンス マニュアル - Arm」 - 登録するとダウンロードできます
マシン語の仕様(日本語)「Armv5 Architecture Reference Manual Japanese - Arm」 - バージョン違いですが、日本語です
Arm Cortex-M0 1,500円 BASICパソコン 「IchigoJam
福野ツイート「プログラミングをC言語からはじめるのは、免許取っていきなりランボルギーニ乗るようなもの

PCN仙台の荒木さんと訪問した仙台高専の縁で実現、小中学生向けローカルプロコン「みやぎプロコン」。 第二回目「みやぎプロコン2020」のオンラインプレゼンをオンライン審査!

オンライン参加してくれたこどもたちも含めて記念撮影!高専企画のローカルプログラミング&電子工作コンテスト、オススメです!ぜひ、高専生にも審査員してもらいましょう。

PCN仙台でのキラキラワークショップ」こどもたちの喜ぶ顔に応えたIchigoJamのコマンド、WS.LED。IchigoJam Rでも対応します!

パラメーターを調整し、WS2811にも対応!
IchigoJam BASIC 1.5b02 ファームウェア (RISC-V版 IchigoJam R用)
- IchigoJam 1.5β2
WS.LED対応、IOT.IN()/IOT.OUT対応(未検証)、VER(2)でキーボード状態が反映されないバグ修正

書き込み方はこちら参照、または「IJUtilities」でどうぞ!

WS2811/WS2812B前期/WS2812B後期とちょっとずつパラメータが違いました。だいたい大丈夫なように調整。

2811 (PL9823) 0 high 200nsec-500nsec, low 1200nsec-1500nsec 1 high 1200nsec-1500nsec, low 200nsec-500nsec reset 50,000nsec 2812b before 0 high 150nsec-550nsec, low 700nsec-1000nsec 1 high 650nsec-950nsec, low 300nsec-600nsec reset 50,000nsec 2812b new 0 high 220nsec-380nsec, low 580nsec-1000nsec 1 high 580nsec-1000nsec, low 580nsec-1000nsec reset 280,000nsec IchigoJam R 0 high 220nsec, low 1000nsec 1 high 1000nsec, low 580nsec

正式版をお楽しみに!バグ報告やご要望、お待ちしています!

マシン語の楽しさはコンピューターをフルに使い切れること。1秒間1億回、約100MHzで動作するIchigoJam RとWS2812Bで実験です!(仕様上の最高性能は108MHzですが、現在は96MHzで動作させています)

IchigoJam RのLEDは、ピン配置を見ると汎用入出力(GPIO)のポートAの14番(PA14)を使っていることがわかります。


GD32VF103のドキュメントより」
コンピュータの仕様書にメモリにマップされたアドレスが記載されています。このアドレスに対して書き込むことで出力を変更できます。 まずは単純に付けてみましょう。出力制御のGPIOx_BOPを使います。PA14は、#40010810の14bit目を1にすればONにできます。(Arm版の例)

MODE RV32C R11=#4 'R1=#40010810 R11<<=12 R11+=1 R11<<=8 R11+=8 R11<<=8 R11+=#10 R12=1 R12<<=14 [R11+0]L=R12 ' set BOP RET

みけCATさんが、RISC-V版にも対応してくれたasm15を使ってアセンブルできます。


Volume 1, Unprivileged Spec v. 20191213より」
RISC-Vのレジスタは31コ(X0は0固定)。X10〜X17がパラメータ、X10/X11が返り値かつ、元の値を保存せずに使えます。RV32Cの16bit縮小命令で使える範囲外ですが、X5〜X7/X28〜X31も元の値を保存せずに使えます。 asm15ではX??レジスタはR??レジスタとして記述します。

LEDを消すときは上記のset BOP を下記のように変更します

[R11+1]L=R12 ' clear BC

続いて、WS2812Bを制御しましょう、データシートを見ると、1コに付き24bitを、0の時は短く(220ナノ秒)ON、1の時は長めに(580ナノ秒)ONの後、しばらく(580ナノ秒)OFFという制御をすればいいことがわかります。 96MHzで動くRISCアーキテクチャーのコンピューターは1命令を10.417ナノ秒でこなします。220ナノ秒待つためにループを使います。

R10=100 R10+=-1 IF R10 GOTO -1

これで100回ループします。R10-=1という命令はないので、-1を足し算します。フラグがない代わりにレジスタが0じゃないかどうかで判定してのループです。

Armでは1ループ4clockでしたが、RISC-V(GD32VF103)ではどうなるでしょう?割り込みを禁止して、10秒間停止させる実験をしたところ、分岐は1clock短縮の2clock、つまり1ループ、3clockです。

あとは、Arm版のWS2812BのドライバをRISC-V用に改造です。

' LED WS2812B R11とR5を変更でOUTnに変更可能 ' R10 - 開始アドレス 送信byte数low,送信byte数high,G1,R1,B1,G2,R2,B2 .... ' R11 - base address (初期はRAM offset) ' R12 - temp ' R13 - data value ' R14 - data count ' R15 - bit count ' R5 - OUT value ' R8 - wait count ' R9 - wait count MODE RV32C @WS2812B SP+=-2 PUSH R8,0 PUSH R9,1 CPSID R10=R10+R11 'R11=#40010810 R11=#4 R11<<=12 R11+=1 R11<<=8 R11+=8 R11<<=8 R11+=#10 R5=1 R5<<=14 R14=[R10+0]W R10+=1 @LOOP_DATA R15=#8 R15<<=4 R10+=1 R13=[R10+0] @LOOP_BIT [R11+0]L=R5 R9=20 '3clock*20=60 <- 58-100 R8=20 '3clock*20=60 <- 58-100 R12=R13&R15 IF R12 GOTO @SKIP R9=8 '3clock*8=24 <- 22-38 @SKIP R9+=-1 'wait R9*3 clock IF R9 GOTO -1 [R11+4]L=R5 ' *offset 4byte R8+=-1 'wait R8*3 clock IF R8 GOTO -1 R15>>=1 IF R15 GOTO @LOOP_BIT R14+=-1 '+6clock IF R14 GOTO @LOOP_DATA CPSIE POP R9,1 POP R8,0 SP+=2 RET

CPSID/CPSIEに対応させたasm15を使うとアセンブルできます。

WS2812B光りました!12コのWS2812Bの実験プログラム for IchigoJam Rβ

10 POKE#700,61,113,34,192,38,194,243,119,4,48,51,5,181,0,145,69,178,5,133,5,162,5,161,5,162,5,193,5,133,66,186,2,3,87,5,0,5,5,161,71,146,7,5,5,131,70,5,0,35,160,85,0,209,68,81,68,51,246,246,0,17,226 20 POKE#73E,161,68,253,20,253,252,35,162,85,0,125,20,125,252,133,131,237,243,125,23,113,251,243,103,4,48,146,68,2,68,5,97,130,128 30 POKE#800,12*3,0 40 FOR I=0 TO 11:POKE#802+I*3,I,12-I,0:NEXT:?USR(#700,#800):WAIT30 50 FOR I=0 TO 11:POKE#802+I*3,0,12-I,I:NEXT:?USR(#700,#800):WAIT30 60 FOR I=0 TO 11:POKE#802+I*3,12-I,0,I:NEXT:?USR(#700,#800):WAIT30 70 GOTO 40

WS.LED命令として組み込む準備ができました。

PCNの新製品発表会にて、新型IchigoJam「IchigoJam R」発表!

PCN新製品発表会


じゃん、こちらがIchigoJam R x IchigoSand


目玉はUSBキーボード対応!


IchigoSand、鯖江のメガネテクノロジー、人肌にやさしい石油を使わない素材、アセテートを使ったIchigoJam R専用ケース by EIGHT SENSE!


メガネ同様、いろいろな柄がかわいい!


テクニカルな大発表、IchigoJamは、ArmからRISC-Vへ。
2014.4.1誕生から長らく使ってきたCPU、NXP社のLPC1114、Arm Cortex-M0アーキテクチャーに加え、オープンなアーキテクチャーRISC-Vに対応!
(LPC1114向けサポートも続きますのでご安心を!)


なんとインタプリター、10倍速!
CPU周波数が倍、ビデオ信号の出力が、DMA(Direct Memory Access)によって空いちゃいました。


RISC-V Internationalメンバー、コネクトフリー社代表、Zen言語開発者、帝都久利寿!


Zen言語は、C言語に代わる、安全、快適、高速なプログラミング言語。


Zen言語zen4ij を使って、プログラムは全く一緒で、RISC-Vマシン語をコンパイルできます!

例えば、引数を1足すだけのシンプルなZen言語プログラム

export fn main(param: i32) i32 { return param + 1; }

Arm版 (make build; make dump)

0000000 1c40 4770

RISC-V版 (make buildr; make dump)

0000000 0505 8082

共に16bitのマシン語命令、オープンなアーキテクチャーなので、学習教材としても本気開発環境としてもフリーに大いに活用できます。
比べてみよう、RISC-VとArm、RISC-V対応かんたんマシン語「asm15r」

One more thing...


エンジニア大好きHHKB(Happy Hacking Keyboard)のPFU社、松本さん出演!
USB接続するHHKBにも対応したのを記念した、HHKBxIchigoJam コラボ!(USBハブ機能付きは未対応)


HHKB x IchigoJam コラボ企画 - Happy Hakking with Kids
なんと、Twitter投稿でIchigoJam R 墨とHHKBが当たる!


IchigoJam R 墨、かっこいい!

加速する、こどもプログラミング環境、こプサミレポートへ続く!
プログラミングは水泳の如し、全学年10時間カリキュラムに挑戦「クイズ タシテ テン!」

links
- こども達と楽しくプログラミングしよう!USBキーボードに対応した新「IchigoJam R」で、HHKB墨とのコラボ決定!Happy Hacking with KIDS! – about yrm
- 今年最後のイベントは「IchigoJam R」の発売発表 | SABAE CREATIVE COMMUNITY

Intel 8086から現代のCore iシリーズまで、脈々と続くx86アーキテクチャ。実は、誕生1978年と私と同い年。RISC-Vのシンプルさと合わせて引き合いに出される古の命令「AAA」を動かしてみました。


参考図書「8086マシン語秘伝の書 単行本 – 1990/10 by 日高徹氏、青山学氏
MSXでマシン語を使ってみたくて買った「Z80マシン語秘伝の書」の8086版! 16bit CPUである8086向けに、変更、セグメントなどx86ならではの項目が追加されている。Z80同様、古典と思いきや、普通に現代のMacでも普通に使えてしまうことに驚きます。

AAA命令もちゃんと載ってました!
2進法/16進法が基本のコンピューターと、10進法が基本の人をつなぐ命令の一つ。0から15までの数を2byte2桁表現にしてくれる便利命令でした。(src on GitHub)

_main: mov eax, 0 main_loop: push eax clc ; reset carry flag AAA call putnumhex pop eax inc eax cmp eax, 16 jne main_loop mov al, 0 ret

こちら実行結果

0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 0100 0101 0102 0103 0104 0105

こちら0から15までをAXレジスタにセットして、AAA命令を通した結果です。確かに2byteになってくれると表示しやすくて便利です。

このような基本的な部分は一度作ってモジュール化してしまえば、再度作る必要はないので、専用の命令はリソースの無駄になります。 実際、x86アーキテクチャでも64bit環境ではAAA命令は削除されているので、上記プログラムは32bitモード(-f macho32)でコンパイルしています。(syscallの呼び出し方も違うので注意!)


こちら、8086マシン語秘伝の書から、144倍するという定数による掛け算を分解してする高速化するテクニック(main.s src on GitHub

SHL AX, 1 SHL AX, 1 SHL AX, 1 SHL AX, 1 MOV BX, AX SHL AX, 1 SHL AX, 1 SHL AX, 1 ADD AX, BX

144倍=128倍+16倍であることを利用して、シフトと足し算命令を使って実現しています。8086には掛け算命令MULがあるにも関わらずなぜこのテクニックが必要だったか?

秘伝の書記載の仕様によると、16bitの掛け算(MUL)にかかるクロック数はなんと118〜133。1bitシフト(SHL)も9クロックかかるとはいえ圧倒的に速いわけです。 現代CPUは掛け算も足し算も1クロックで終了するので、このテクニック自体は不要です。

そういえば、なぜわざわざ1bitずつシフトしているのでしょう?

SHL AX, 4 MOV BX, AX SHL AX, 3 ADD AX, BX

と書けばもっと短く、高速です。実は、この元になったZ80マシン語秘伝の書でも同じ内容があって、Z80には1bitシフトしかないので、ベタ移植したままになってしまったと想像。(追記、・・・違いました。8086にはイミディエイトのシフトは1限定。上記は80186から加えられた命令でした。 thanks! > @fujitanozomu

MOV CL, 4 SHL AX, CL MOV BX, AX MOV CL, 3 SHL AX, CL ADD AX, BX

8086命令を使って、このように書くこともできますが、2クロックで終わる1bitシフトと比較し、CLを使ったシフトは 8+4N クロックと遅く、速度を取るなら秘伝書記載の通りが正解でした。

コンピューターの特性を知り、いかに活かすか、今でも大事な基本ですね!
普段使っているCPUに近づくマシン語の世界、こちらのサンプルや入門をどうぞ!(x86asm src on GitHub

links
- 日本人が創ったCPUの歴史、MacのCPU Intel 64 マシン語はじめのいっぽ
- ハンドアセンブルで高速計算! RISC-V、RV32ICエミュレーターのC言語実装
- はじめてのマシン語 - IchigoJamではじめるArmマシン語その1

人気のArmマシン語入門の「つぎのいっぽ」ハンドアセンブルをRISC-Vでやってみました。


参考図書「RISC-V原典 オープンアーキテクチャのススメ | デイビッド・パターソン, アンドリュー・ウォーターマン, 成田 光彰
著者、デイビッド・パターソン氏は、RISC生みの親!

せっかくなのでハンドアセンブルしやすく実行効率の良い、16bitの圧縮命令拡張RV32Cを使いたいので、以前使用したエミュレーターにC拡張を勉強ついでに追加実装。(rv32emuの元、TinyEMUはC対応してます)

R11=0 R11+=R10 R10-=1 IF R10 GOTO -2 R10=R11 RET

RISC-VのC言語呼び出し規約では、R10が第一引数で返り値となり、R11も一時レジスタとして使用可能なので、R10/R11を使用。C拡張の命令のみを使ってasm15r表記で作成。

比較のためにこちらがArm Cortex-M0用、asm15表記ですが、ほぼ同じですね。

R1=0 R0=R0+R1 R0=R0-1 IF !0 GOTO -2 R0=R1 RET

RISC-Vにはフラグがない代わりに分岐命令で比較が可能です(比較した結果を0か1かで代入する命令でキャリーフラグを代用できます)。 足りない命令は、32bit命令を使えばOKなので、割り切ったコンパクトな設計が美しい。

RV32C RISC-Vマシン語表」を見ながらハンドアセンブルします。

0b0010010110000001, // R11=0 0b1001010110101010, // R11+=R10 0b0001010101111101, // R10-=1 0b1111110101110101, // IF R10 GOTO -2 0b1000010100101110, // R10=R11 0b1000000010000010, // RET

こちらを emu-rv32i-test-c.c で、仮想RAMに書き込んで、実行!
繰り返し足し算するプログラムが動きました!(src on GitHub


ArmのThmubと違って、C拡張はハードウェアで実装する別名的扱い。 よく使われる命令に絞って実装されており、32bit命令と併用できるのが特徴。たった400ゲートで実装できると言うだけあって、C言語での実装も約200行とコンパクト。(関数 convert_insn_from_c / src on GitHub

16bit命令を使うことで30%ほど容量が削減できて、ArmのThumbとほぼ近いサイズくらいになります。レジスタを複数PUSHするなどの命令を削減したため、より小さくはなりませんが、ハードウェアコストや実行性能にメリットあり。後発優位でもありますが、この辺りのバランス感覚が気持ちいい。

64bit時代にプログラムの容量削減に意味はあるのか?大有りなのです。メモリとのアクセスは時間がかかるので、何段ものキャッシュを使って実行効率を上げている現代CPU、命令がコンパクトになるとその分キャッシュヒット率が向上し、速く動作するわけです。実行時間=電力消費量=コストなので、省エネ化にもつながります。

RISC-V原典、一番おもしろかったのはV(ベクトル)拡張。CPU+GPUの歴史が変わりそう!V実装のフィックスと実CPUの広まり、大いに楽しみです。
(参考、RISC-Vベクトル拡張について解説する - Fixstars Tech Blog /proc/cpuinfoArm64のSIMD

理研のスパコンに使われたり、格安ハードが登場した2019年のRISC-V。今年もかなり伸びそうな予感のCPU、RISC-V(リスク・ファイブ)。RISC-V版Androidや、RISC-V版ノートパソコンの発売もあるかも?

RISC-Vは、由緒正しいハーバード大生まれのRISCアーキテチャーの第五世代。ライセンスフリーで自由に利用できるオープンかつ時代に合わせたチューニングによるハイパフォーマンスが特徴です。 以前32bit版で紹介しましたが、短くシンプルな16bitの縮小命令RV32Cを使って、Arm Cortex-M0学習用のasm15をRISC-Vに対応させたasm15rを設計。

そもそも、コンピューターとは何でしょう?
コンピューターとは、膨大な数を記憶し、正確かつ超高速に計算するものです。

どう記憶しどう計算するかを指示する数、それがマシン語。 CPUが違えばマシン語が違います。各メーカーによって系統があり、具体的なCPUによって使える命令が異なりますが、基本的はどれも一緒です。


RV32C RISC-Vマシン語表 (asm15r)
こちらまとめたRISC-Vマシン語です(抜粋)
RISC-Vのラインナップは、32bit/64bit/128bitの大きく三種類。今回は入門しやすい32bitで縮小命令、掛け算割り算命令対応版をセレクト。

32bitコンピューターでの記憶は大きく2種類。数個から数十個ある32bit(4byte)のレジスタと呼ばれるものと、数KBから数GBまでのメモリ(RAMやROM)と呼ばれるもので記憶します。 RISCアーキテクチャでは計算はレジスタを使って行い、メモリとレジスタとのやり取りは別の命令で行います。


こちらがメモリとレジスタをやりとりする命令。

ここでRISC-Vを使った超シンプルなRISC-V 32bitコンピューターを仮定します。
1. メモリはアドレス0から始まる32byteのROM(16bitずつ16セットのスイッチで0/1切り替え可能、上下8bit入れ替え)
2. アドレス32から始まる4byte(32bit)には、対応する32コのLEDがついている(エンディアン入れ替え)
3. アドレス0から始めるリセットボタン

この架空のRISC-Vコンピューターに1+1を計算させるプログラムを上記asm15rを使った組みます。

R10=1 R10+=1 R11=32 [R11]=R10

メモリアクセスにレジスタR8以降しか使えないので、計算もレジスタR10とR11を使うことにします。


他にも、コンピューターにおいて大事な分岐や、複雑な計算の一時記憶に便利な機構スタックを実現する命令などが定義されています。

計算が終わった後もどんどん次のメモリを命令として実行していってしまうので、GOTO命令を使ってはじめに戻してあげましょう。

R10=1 R10+=1 R11=32 [R11+0]=R10 GOTO -4

この5つ、20byteの命令を命令表を見ながらビット列に置き換える、ハンドアセンブルし、スイッチを設定。(この作業を自動化するソフトがアセンブラやコンパイラ)

001 0 01010 00001 01 :'R10=1 000 0 01010 00001 01 :'R10+=1 001 1 01011 00000 01 :'R11=32 110 000 011 0 0 010 00 :'[R11+0]=R10 101 1 1 11 1 1 1 100 1 0 1 :'GOTO -4

これでLEDの右から2つ目だけが光って、1+1の計算結果が2であることを出してくれるプログラム、完成です!
スイッチをいじって、2+1の計算などにしてみましょう。

この架空のコンピューター、作ってみたくなりますね!
RISC-Vは誰もがオープンに使えるアーキテクチャ、また本ブログもCC BYのオープンデータ、自由に作って遊んだり売ったりして、OKです!

Armは、スマホや、IchigoJam、開発中の日本のスパコン富岳など、世界で最も普及しているCPUアーキテクチャ。Armの一番シンプルなCortex-M0のマシン語と比較してみましょう。

Cortex-M0 Armマシン語表 (asm15)
こちらも16bitが基本、似てますね。RISC-Vの縮小命令は32bitの標準命令と下位2bitで区別できるので混在できるのが特徴です。(RISC-Vの縮小命令には掛け算割り算がないので、32bit命令を使用)

Cortex-M0はレジスタ16本(プログラムカウンター含む)、RISC-Vは32本(内R0は0固定、プログラムカウンターは別)など、細かな違いの理由に思いを馳せるのもまた一興。

IchigoJamで、いますぐ遊べるマシン語の世界もぜひどうぞ!
はじめてのマシン語 - IchigoJamではじめるArmマシン語その1

CPUの世界にもオープンデータ。オープンソースでオープンライセンス(BSDライセンス)なCPUアーキテクチャ「RISC-V(リスク・ファイブ)」の実機が続々登場! 1981年にバークレー大学から発表されたRISC-Iからスタートして5世代目のRISC-V、Google / NVIDIA / NXP / Qualcomm など、数多くの企業をメンバー企業に支えられて躍進前夜。

Amazonが発表した自社開発CPU、Graviton2はArmベースでしたが、次世代がRISC-Vになっても不思議はありません。(現時点でAmazonはまだメンバーではないが、オープンに誰でも使えるため、使用するのにメンバーである必要もない)

そんな RISC-V というオープンなコンピューターの気持ちになってみましょう!
IchigoJamで試した、はじめてマシン語Arm編のように、はじめのいっぽはハンドアセンブル!
Specifications - RISC-V Foundation(RISC-V仕様書 P130より)

Instructionsとは、RISC-Vというコンピューターができること一覧、基本は32bit(4byte)、メモリに書かれた命令にしたがって、どんどん計算していきます。 レジスタは基本32コ、そのうち0番レジスタX0は0固定。実行位置を表すプログラムカウンタ(PC)は別となっています。

ひとまず、1+1をさせてみましょう。
レジスタ同士の足し算は ADD (上の図の一番下)

ADD rd,rs1,rs2

rd = rs1 + rs2 という足し算をします。
RISC-Vは、32コあるレジスタ(X0-X31)の内、x10,x11...を引数や、返り値に使うことになっています(x10,x11は別名a0,a1)

ADD x10,x10,x11

こちらをマシン語表を見て、二進法32桁の数値に変換します。(RISC-Vのマシン語の基本は32bit、16bitの圧縮版もあります)

0000000 01011 01010 000 01010 0110011         rs2 rs1 rd

これを16進法に表すと

-> #00b50533

この4byteをメモリに書き込めばOKです!(RISC-Vは、little endian なので、#33,#05,#b5,#00 の順)

ただ、これだけではプログラムの終わりがわからずどんどんよくわからない計算が進んでしまうので、戻す(RETURN)命令を加えます。 RISC-Vでは、戻り先がレジスタ1番に入っているので、そちらへのジャンプ(GOTO)すればOK。 命令表の中から Brunch の JALR x1 を上記同様に16進法に変換します。(x1は別名ra)

JALR x1 (JALR rd,rs1) 0b00000000000 000001 000 00000 1100111         rs1 rd -> #00008067

できました!

実機で動かしてみたいところですが、今回は誰でも使えるエミュレーターを使います。

WebAssemblyにも対応し、ブラウザ上でRISC-V版Linux(JSLinux)まで動かしてしまうTinyEMUをベースにしたコンパクトなエミュレーターrv32emuを使います。

いろいろ組み込みに便利なようにコア部分を分離するように改造した rv32emu を作りました。
emu-rv32i.h をインクルードし、下記のように使います。

#include "emu-rv32i.h" #include <stdio.h> int main(int argc, char** argv) { uint32_t start = 0; ram_start = 0; uint32_t end = 0xfffffffe; *(uint*)(ram + start + 0) = 0x00b50533; // ADD x10,x10,x11 *(uint*)(ram + start + 4) = 0x00008067; // JALR x1 pc = start; reg[2] = ram_start + RAM_SIZE; // sp - stack pointer reg[1] = end; // ra - return adderss reg[10] = 1; // a0 reg[11] = 1; // a1 while (machine_running) { next_pc = pc + 4; insn = get_insn32(pc); printf("[%08x]=%08x\n", pc, insn); execute_instruction(); pc = next_pc; if (pc == end) break; } printf("x10 a0: %08x\n", reg[10]); return 0; }

結果はこちら

x10 a0: 00000002

見事、x10に 1+1 の結果、2が入っていますね!
reg[10]やreg[11]の初期値を変えたり、他の命令をハンドアセンブルしてみたりと、いろいろ試してみましょう。

MacでRISC-Vの開発環境を入れるなら、Homebrewを使うと楽ですよ!

$ brew tap riscv/riscv $ brew install riscv-tools

links
- はじめてのマシン語 - IchigoJamではじめるArmマシン語その1

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / RSS