世界を動かす技術を、日本語で。

イージーRISC-V

概要

  • RISC-Vアセンブリ入門 の日本語要約
  • RISC-Vの特徴 や基本命令セットの紹介
  • エミュレータの使い方 やプログラム例の解説
  • 算術・ビット演算命令 の具体的な使い方
  • 擬似命令やオーバーフロー の扱いについても説明

RISC-Vアセンブリ入門:概要と特徴

  • RISC-VReduced Instruction Set Computer (RISC) アーキテクチャの一つ
  • オープンスタンダード で、誰でも自由に利用・実装可能
  • クリーンな設計 で、フラグや複雑な命令が少なく、学習や実装が容易
  • コミュニティサポート が充実し、教育・研究・組み込みなどで活用事例多数
  • 本記事では RV32I_Zicsr命令セット (32ビット、最小限の命令)を中心に解説

基本命令とRISC-Vの特徴

  • RV32I_Zicsr命令セット は45種類の基本命令で構成
    • 例: lui, auipc, jal, add, sub, and, or, xor, ecall, ebreak など
  • 整数演算・ビット演算・分岐・ロード/ストア などの基礎命令を網羅
  • 拡張命令 (浮動小数点や圧縮命令)は本記事では扱わない

エミュレータの使い方

  • エミュレータ 上でアセンブリを入力・実行し、レジスタやメモリの状態を確認可能
  • Start ボタンでアセンブル・実行開始
  • Run で最後まで実行、 Step で1命令ずつ実行
  • Dump でシンボルテーブルや命令のバイナリ表現を確認
  • pc(プログラムカウンタ)x0~x31レジスタ の状態表示

基本的な算術命令

  • 加算命令 :addi rd, rs1, imm(即値加算)、add rd, rs1, rs2(レジスタ同士の加算)
  • 減算命令 :sub rd, rs1, rs2(rs1-rs2の減算、subiは存在しないがaddiで負数を利用可能)
  • 即値の範囲 :12ビット符号付き(-2048~2047)、命令は32ビット固定長
  • 擬似命令
    • li rd, imm (即値ロード、範囲内ならaddiに展開)
    • mv rd, rs1 (値のコピー、addi rd, rs1, 0に展開)
  • 符号表現 :2の補数、オーバーフロー時は上位ビットが切り捨てられる

ビット演算命令

  • and, or, xor :rs1とrs2のビットごとの論理演算
  • andi, ori, xori :即値を使ったビット演算
  • ビット操作例 や複数回の論理演算の実行例

RISC-Vアセンブリの学習ポイント

  • x0レジスタ は常に0、書き込みは無視、読み出しは0
  • 命令のシンタックス :命令名+カンマ区切りのオペランド
  • シンプルな命令体系 で、初心者でも理解しやすい構成
  • 命令のエンコード や詳細なバイナリ表現も確認可能

まとめ

  • RISC-Vアセンブリ はシンプルかつオープンな設計で学習に最適
  • エミュレータの活用 で、実際に動作を確認しながら理解を深められる
  • 算術・ビット演算・擬似命令 など、基本を押さえることで応用力が身につく
  • 今後の発展 が期待されるアーキテクチャ、学習・研究・開発におすすめ

Hackerたちの意見

いいガイドだね!最初の「私の初めてのRISC-Vアセンブリプログラム」のエミュレーターの部分は、ガイドの最初に置いた方がいいと思う。そうじゃないと、カジュアルな読者はこれがテキストだけの紹介だと思っちゃうかも(タイトルに「インタラクティブ」って書いてあるのにね)。これから数日間、もっと時間をかけてみるつもり。RISC-Vにはすごく興味があるし、明るい未来が待ってると思う。もし今これを読んでるAIの専門家がいたら、ReplitやLovableみたいなものでRISC-Vアセンブリで「Core War」を再現してほしいな。めっちゃ面白そうだよ。[0]: https://en.wikipedia.org/wiki/Core_War

なんで誰かが脳でこれをやらないの?

パターソンとヘネッシーの「コンピュータの構成と設計」という本でアセンブリを学んだんだけど、RISC-VがMIPSからどれだけ影響を受けているかがよくわかる。結局、両方のISAに関わっている人たちがいるし、MIPSの失敗から学んでいる(遅延スロットなし!)。基本的にMIPSから来た人にとっては、アセンブリがすごく似てる。私もそうだったし。今、その本はRISC-V版も出ていて、いろんなRISC ISAの違いを比較する面白い章がある(SH、Alpha、SPARC、PA-RISC、POWER、ARMなど)。でも、最近AArch64も探っていて、こちらも非常に興味深いアイデアがあると思う。RISC-Vほどクリーンではないかもしれないけど、実用的なデザインで、RISC-Vがデザインで保守的すぎたのか疑問に思う選択肢もある。

RISC-V版のリンク、持ってる?MIPS版は持ってるんだけど、RISC-V版も欲しいんだ。

最近AArch64も探っていて、こちらも非常に興味深いアイデアがあると思う。RISC-Vほどクリーンではないかもしれないけど、実用的なデザインで、RISC-Vがデザインで保守的すぎたのか疑問に思う選択肢もある。これについて考えてる人が少ないし、AArch64がどこから来たのか、デザインのガイドラインが何だったのかがかなり曖昧なのも気になる。

AArch64に詳しくない人に聞きたいんだけど、具体的にどの部分を指してるの?私が見つけたのは、共通の命令の組み合わせをつなげることができるってこと、例えばシフト+加算とか、ちょっと複雑なアドレッシングとか。RISC-Vの目的がRISC命令セットだったから、こういうのは余分だと思う。

命令は削除するより追加する方が簡単なんだ。RISC-Vは標準のC/C++コードを効率よく実行するために、最小限の命令セットから始まったんだよ。時間が経つにつれてもっと命令が追加されているけど、新しい命令を提案する人は、その命令を追加するコストと、どれだけの利益が得られるのか、実際のアプリケーションでどう使われるのかを示さないといけないんだ。

記憶がちょっと曖昧だけど、パターソンとヘネッシーの「Computer Architecture: A Quantitative Approach」にはRISC-VやMIPSに関する部分があったと思う。残念ながら、私のコピーはどこかの箱に埋もれてるからページ番号はわからないけど、他の誰かが覚えてるかも…

RISC-VとMIPSの類似性についても、任天堂64のホームブリュー開発に触れた限られた経験から同じ印象を持ってるよ。自分が「お、これAres+Godboltでいじってたやつと全く同じじゃん、ただ遅延スロットがないだけだ」と思ってたことが結構あったのが印象的だね。

基本的な「123」ASMデモの中で、x10が0x00000123になるのはわかるけど、sp(x2)レジスタが0x40100000になってるのはどういうこと?そのspって何?重要なの?なんで0x000000じゃないの?なんで説明がないの?そこで迷っちゃうんだよね。

'sp'は「スタックポインタ」レジスタだよ。スタックについての説明はガイドの後半にあるよ:https://dramforever.github.io/easyriscv/#the-stack

ポジション独立のセクションにエラーがあると思う:start: auipc a0, 3 addi a0, a0, 4 テキストにはこれが0x3004になるはずだって書いてあるけど、この例はstart: lui a0, 3 addi a0, a0, 4のつもりだったのかな?

いや、luiは絶対アドレスを返すから、位置に依存しないものじゃないんだよ。auipc/addiのシーケンスは0x3004にauipc命令自体のアドレスを足したものになる。もしauipcがアドレス0にあれば、結果は同じになるね。

ゼロから引くのは否定だよ。0x123の負の値は何?それは0xfffffeddだ。 > うーん、こっちは0xfffffccdが出たよ。いや、出てないよ。エミュレーターは0xfffffeddを表示してるし、手動でも確認したから。エミュレーターが正しいよ。

https://github.com/triilman25/tcp-socket-in-riscv-assembly RISC-V用のTCPソケットをISA RV64Iを使って書いたよ。リンカのリラクゼーションについて知っておく必要があるし、どう使うかもね。参考文献もいくつかそこに添付してあるよ。

このコンテンツのインタラクティブなスタイルには感心するね。C/C++開発者として、アセンブリはもっと難しいと思ってたけど、このインタラクティブなコンテンツのおかげでアセンブリがわかりやすくなったよ。