FPGA開発日記

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

Binary Translation型エミュレータを作る(Fused-Multiply-Add向けヘルパー関数の実装)

Binary Translation方式のエミュレータをRustで作る実装、浮動小数点命令を実装している。加減算命令については特に問題なく実装が進んだのだが、FMADDなどの3オペランド命令の実装についてサポートを追加した。FMADD.DなどのFused Multiply-Add命令は入力オペランドが3つ、出力オペランドが1つなので合計4オペランド必要だ。さらに第1引数として構造体へのポインタを渡すので合計5つの引数を渡す必要が生じる。これまでの実装では最大で4つまでの引数を渡せるようにしていたが、5つ目の引数は考えていなかったのだった。

調査していると、x86は以下の順番で引数をレジスタに設定するらしい。

  • RDI, RSI, RDX, RCX, R8, R9

R8とR9ってなんだ?これらのレジスタオペランドとして指定するためには拡張ビットを設定する必要があるらしい。いつもお世話になっている以下のページを参考にした。

www.wdic.org

f:id:msyksphinz:20200923005849p:plain:w400

ふむ、REX.Bというビットを設定するとR8/R9にアクセスできるようになるらしい。これはどのように設定するかというと、

wiki.osdev.org

いつも使っているREXプレフィックスの0ビット目を1に設定すればいいのか。なるほど。

という訳でR8レジスタを指定する際のオプションを実装した。

    fn tcg_gen_imm_u64(dest: X86TargetRM, imm: u64, mc: &mut Vec<u8>) -> usize {
        let mut gen_size = 0;
        if dest == X86TargetRM::R8 {
            gen_size += Self::tcg_out(0x49, 1, mc);
        } else {
            gen_size += Self::tcg_out(0x48, 1, mc);
        }
        gen_size += Self::tcg_out(X86Opcode::MOV_EAX_IV as u64 + ((dest as u64) & 0x7), 1, mc);
        gen_size += Self::tcg_out(imm, 8, mc);
        gen_size
    }

とりあえずものすごく雑な実装になってしまった。。。R8/R9が指定されるとREX.Bビットを無理やりONにする。そしてレジスタ指定フィールドについてはレジスタ定義の下位3ビットだけを抽出して設定する。結果として以下のようなx86命令が生成される。

0x4001ce10be:  48 bf e0 ad 8a 01 40 00  movabsq  $0x40018aade0, %rdi
0x4001ce10c6:  00 00
0x4001ce10c8:  48 be 03 00 00 00 00 00  movabsq  $0x3, %rsi
0x4001ce10d0:  00 00
0x4001ce10d2:  48 ba 00 00 00 00 00 00  movabsq  $0x0, %rdx
0x4001ce10da:  00 00
0x4001ce10dc:  48 b9 01 00 00 00 00 00  movabsq  $0x1, %rcx
0x4001ce10e4:  00 00
0x4001ce10e6:  49 b8 02 00 00 00 00 00  movabsq  $0x2, %r8
0x4001ce10ee:  00 00
0x4001ce10f0:  ff 95 70 03 00 00        callq    *0x370(%rbp)

r8浮動小数点演算のヘルパー関数における第5引数として動作する。これでFMADD.D fd,fs1,fs2,fs3のすべての情報を渡せるようになった。テストを実行してみよう。

ans = 0x138
x00 = 0000000000000000  x01 = 0000000000000000  x02 = 0000000000000000  x03 = 0000000000000002
x04 = 0000000000000000  x05 = 0000000000000108  x06 = 000000000000b109  x07 = 0000000000000000
x08 = 0000000000000000  x09 = 0000000000000000  x10 = 400c000000000000  x11 = 0000000000000000
x12 = 0000000000000000  x13 = 400c000000000000  x14 = 0000000000000000  x15 = 0000000000000000
x16 = 0000000000000000  x17 = 0000000000000000  x18 = 0000000000000000  x19 = 0000000000000000
x20 = 0000000000000000  x21 = 0000000000000000  x22 = 0000000000000000  x23 = 0000000000000000
x24 = 0000000000000000  x25 = 0000000000000000  x26 = 0000000000000000  x27 = 0000000000000000
x28 = 0000000000000000  x29 = 0000000000000000  x30 = 0000000000000000  x31 = 0000000000000000

f00 = 3ff0000000000000  f01 = 4004000000000000  f02 = 3ff0000000000000  f03 = 400c000000000000
f04 = 0000000000000000  f05 = 0000000000000000  f06 = 0000000000000000  f07 = 0000000000000000
f08 = 0000000000000000  f09 = 0000000000000000  f10 = 0000000000000000  f11 = 0000000000000000
f12 = 0000000000000000  f13 = 0000000000000000  f14 = 0000000000000000  f15 = 0000000000000000
f16 = 0000000000000000  f17 = 0000000000000000  f18 = 0000000000000000  f19 = 0000000000000000
f20 = 0000000000000000  f21 = 0000000000000000  f22 = 0000000000000000  f23 = 0000000000000000
f24 = 0000000000000000  f25 = 0000000000000000  f26 = 0000000000000000  f27 = 0000000000000000
f28 = 0000000000000000  f29 = 0000000000000000  f30 = 0000000000000000  f31 = 0000000000000000

良さそうだ。FMADD系のテストパタンはすべてPassできることを確認した。