FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

2020-08-01から1ヶ月間の記事一覧

Binary Translation型エミュレータを作る(レジスタ+レジスタ /レジスタ+即値 演算の実装)

Binary Translation型エミュレータを作っている。ゲストマシンはRISC-Vで、ホストマシンはx86である。ADDI命令は簡単なものであれば実装できるようになった(ソースレジスタがx0の場合に限る)。どんどん実装を進めていこう。次は普通のADDI命令と、ADD命令を…

Binary Translation型エミュレータを作る(ELFローダの組み込み)

Binary Translation型エミュレータを作っている。ゲストマシンはRISC-Vで、ホストマシンはx86である。基本的な命令が動き出したので、以前に作ったELFファイルローダを使ってBinary Translation型エミュレータにELFファイルをロードする機能を実装して行きた…

Binary Translation型エミュレータを作る(レジスタアクセスを実現する)

同じ事を自作QEMUで実現しよう。自作QEMUが変換後のアセンブリコードを実行するとき、引数として仮想CPUのレジスタが格納されているアドレスの先頭を渡す。 unsafe fn reflect(instructions: &[u8], gpr_base: *const [u64; 32]) { let map = match MemoryMa…

QEMUを作る(TCGからx86へのDynamic Translation)

RISC-Vの機械語から簡単なTCGが生成できるようになったので、次はx86のコードに変換する。基本的な考え方は、特定のTCGを特定の命令に変換していくのだが、例えばRISC-VのADDI x10, x11, 20などの命令をx86に置き換えるならば、 x11が定義されている場所(ア…

QEMUを作る(RISC-VからTCGへのDynamic Translation)

QEMUの構造について勉強したので、似たようなものをRustで作ってみたくなった。Rustの勉強も兼ねている。ターゲットについてはゲストコードをRISC-V、ホストコードをx86としてとりあえず何か動くものを作ってみたい。 RISC-Vの機械語は、例えば以下のような…

プログラム中に埋め込んだ機械語命令を実行するプログラムをRustで書く

何を言っているのだかわからないかもしれないが、これはつまりQEMUのまねごとをRustで実現したいという話。 QEMUではTCGによって変換されたゲストの機械語をホストに変換する際、TCGを機械語に変換したものをメモリ上に配置し、これを機械語とみなして実行す…

「実践Rustプログラミング入門」を買いました

「実践Rustプログラミング入門」を買いました。Amazonで注文しました。 Rustは昨年からチマチマ触っており、CQ出版のインターフェースにシミュレータの話を寄稿したが、Rustの機能は自分でもまだわかっていないところが多い。 特にC++には無い機能、ライフタ…

CIRCTのcirct-translateの内部構造を解析する (CIRCTに新しいPassを追加する試行)

CIRCTは、FIRのファイルを受け取りMLIRの構造に変換し、それをVerilogに変換する構造になっている。このFIRParserを理解し、MLIRについての理解を深めるためには自分で別のPassを作りそこに同じような実装を加えてみるのがいいだろう。そこで、まずは既存のF…

CIRCTのcirct-translateの内部構造を解析する (EmitVerilogモジュールの解析)

CIRCTの続き。CIRCTにはMLIRのモジュール構造をVerilogに出力するためのモジュールが実装されている。 lib/EmitVerilog/EmitVerilog.cpp LogicalResult circt::emitVerilog(ModuleOp module, llvm::raw_ostream &os) { VerilogEmitterState state(os); Circu…

CIRCTのcirct-translateの内部構造を解析する (FIRParserの解析)

CIRCTの解析続き。CIRCTのツールの一つににcirct-translateというツールがあり、これが各種ハードウェア記述言語からMLIRへの変換、そしてターゲットコードへの変換を司っているらしい。 circt-translate.cppのソースコードを眺めてみても良いが、まずはFIRR…

QEMUのTCG(Tiny Code Generator)を読み解く(6. QEMUのTCGが生成される仕組み)

QEMUはTCG(Tiny Code Generator)と呼ばれる仕組みを使ってゲストマシンの機械語をホストマシンの機械語に変換している。ゲストマシンの機械語は、QEMU実行中にTCGに変換され、これをなるべく最小のホスト機械語に変換することでほぼネイティブなホスト機械…

QEMUのTCG(Tiny Code Generator)を読み解く(5. x86のアプリケーションブートコードの解析)

前回の、QEMUにおけるプロローグコードおよびターゲット関数呼び出しのルーチンを見て、もう少しx86のアセンブリコードについて勉強してみようと思った。 QEMUの実行ログを見ると、最初のブートコードは以下のようになっている。 PROLOGUE: [size=45] 0x7f13…

QEMUのTCG(Tiny Code Generator)を読み解く(4. QEMUがカーネルを呼ぶ際に実行するPrologueコードを読み解く)

TCGの続き。続いて、TCGを使ってどのようにRISC-Vのコードをx86上で実行しているのかをチェックする。このためには、まずは関数のプロローグを調べていく必要があるだろう。 デバッグ情報を出力しながらQEMUを実行する。 $ qemu-system-riscv64 --machine vi…

QEMUのTCG(Tiny Code Generator)を読み解く(3. TCGContextによりホスト命令がターゲット命令に変換される流れ)

TCGの続き。TCGによるエンコードをもっと詳しく見るために、TCGContextを眺めてみる。 qemu/include/tcg/tcg.h struct TCGContext { uint8_t *pool_cur, *pool_end; TCGPool *pool_first, *pool_current, *pool_first_large; int nb_labels; ... TCGTemp *fr…

RISC-V Vector命令をサポートした自作命令セットシミュレータの実装検討 (8. VX, VI命令の実装)

自作RISC-V命令セットシミュレータの実装続き。算術演算命令について説明すると、RISC-V Vector Extensionには大きく分けで3つの演算命令種が定義されている。 .VV 命令:ベクトルレジスタとベクトルレジスタ同士を算術演算して、その結果をベクトルレジスタ…

RISC-V Vector命令をサポートした自作命令セットシミュレータの実装検討 (7. 単純な算術演算の実装)

自作RISC-V命令セットシミュレータ、Vector Extensionのサポート続き。メモリアクセスが一応実装できたので、次は基本的な四則演算を実装して行きたい。 基本的な四則演算として、整数の四則演算を見ていく。対象としては、 VADD.VV : 加算 VSUB.VV : 減算 V…

RISC-V Vector命令をサポートした自作命令セットシミュレータの実装検討 (6. StridedメモリアクセスおよびIndex Stridedメモリアクセス)

自作RISC-V命令セットシミュレータ、Vector Extensionのサポート続き。Unit Strideのメモリアクセス命令は追加したのだが、あと2種類のメモリアクセス命令についても追加する。それがStridedメモリアクセス命令とIndex Stridedメモリアクセス命令である。 復…

Rustで作ったRISC-VシミュレータにELFロード機能を追加する

Rustを使ってELFファイルをダンプするプログラムが動くようになったので、今度はこれをRISC-VシミュレータにインポートしてELFファイルを読み込むことができるようにする。 まずはELF Loaderをインポートして、ELFファイルを読み込んだら、すべてのセクショ…

RISC-V Vector命令をサポートした自作命令セットシミュレータの実装検討 (5. ベクトルマスクレジスタ用のテスト作成)

自作命令セットシミュレータのRISC-V Vector Extensionサポート、基本的なベクトルロードストア命令の実装が終わった。 テストを追加したいのだが、一応マスクレジスタのテストをしておきたい。Vector Extensionのマスクについてここでまとめておいて、シミ…

RustでELFファイルを開く方法を調査する (5. ディスアセンブル機能を実装する)

RustでELFを解析してダンプするプログラムを書いている。せっかくELFの中身をダンプできるようになったので、次はディスアセンブルを表示してみたい。ELFの中身をデコードできるようになれば、最終目的であるエミュレータまでの道が見えてくる。まずは依然作…

RustでELFファイルを開く方法を調査する (4. リファクタリング)

RustでELFファイルを開いてダンプするプログラムを書いている。正しく動作するようになったところで、多少のリファクタリングを加えていく。 情報に合わせてstructを定義する。ELFHeader, ProgramHeader, SectionHeaderを定義した。 pub struct ELFHeader { …

RustでELFファイルを開く方法を調査する (3. Section Headerを読み取る)

Program Headerを読み取ることができるようになったので、次はSection Headerを読み取ることにする。Section Headerに関する情報は、ELFファイルの先頭から、ELFヘッダテーブルにおけるSHOFFバイトの位置から開始している。また、各セクションの大きさは、SH…

RustでELFファイルを開く方法を調査する (2. Program Headerを読み取る)

RustでELFファイルを開く続き。次はProgram Headerを読むコードを書いていく。Program Headerはセグメント領域の情報が格納されている。セグメントにはコードセグメントとデータセグメントが存在し、コードセグメントにはプログラム、データセグメントにはデ…

RustでELFファイルを開く方法を調査する (1. ELFファイルをRustで開く方法)

非常に久しぶりにRustを触っている。RISC-Vシミュレータ以外にもRustでやってみたいことがあって色々調べているのだが、RustでELFファイルなどのバイナリを扱う方法を少し調べていた。シミュレータの用途でもあるし、別の用途でもELFファイルを扱えるといろ…

Circuit IRコンパイラのCIRCTを試す

"CIRCT"は"Circuit IR Compiler and Tools"の略称で、MLIRを用いた回路構成を生成するコンパイラツールである。 https://github.com/llvm/circt ソースコードが構成されており、面白そうなのでダウンロードしてビルドしてみることにした。 まずはソースコー…

QEMUのTCG(Tiny Code Generator)を読み解く(2. TCGが生成したx86機械語を読む)

TCGの続き。TCGによるエンコードをもっと詳しく見るために、最適化を抑制すべくいろいろ変更してみた。 git diff tcg/i386/tcg-target.inc.c diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c index ec083bddcf..d86ccdf05b 100644 --- …

QEMUのTCG(Tiny Code Generator)を読み解く

QEMUは高速なエミュレーションが可能な理由の一つに、TCGを使った高速なバイナリ変換機構がある。TCGの役割は、ターゲットバイナリからTCG(Tiny Code Generator)を用いた中間表現に変換し、ホスト形式のバイナリに変換する2つの機構が存在している。 TCGがど…

QEMUに入門してみる(20. CSRレジスタの追加)

QEMU実装の続き。CSR命令の実装が足りていないので、いくつか主要なものを実装していく。現時点ではmhartidしか実装していないので追加していく。csr.cにはCSR命令追加のテンプレートが用意されているのでこれを使っていく。 qemu/target/myriscvx/csr.c /* …

QEMUに入門してみる(19. 分岐命令の実装方法)

QEMU実装の続き。命令実装を進めていく中で、次に実装すべきは分岐命令だ。QEMUで分岐命令をどのように実装するかについて検討を行う。 まずは分岐命令の定義だ。分岐命令はデコードテーブルの中で以下のようにして定義する。 qemu/target/myriscvx/insn32.d…

QEMUに入門してみる(18. ディスアセンブル機能の実装)

前回のQEMUの実行ログを見ると、命令のニーモニックが出力されていなかった。どうしたら命令のディスアセンブルが表示されるんだろう?ということでいろいろ調査した。 IN: Priv: 3; Virt: 0 0x0000000000001000: OBJD-T: 9702000093850202732540f1 このOBJD…