FPGA開発日記

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

RISC-Vシミュレータの命令定義のテーブルをJSONを使って書き直す

f:id:msyksphinz:20180916025750p:plain

GitHub上に公開している自作RISC-Vシミュレータは、命令を定義しやすいように、Rubyの配列上に命令の定義、オペランド、ビットフィールドなどを定義してある。

Rubyの配列で直接記述することで、スクリプトで簡単に読み込むことができるのだけれども、統一されたフォーマットとはいいがたいし、フィールドに挿入したいフィールドが長くなると対応し切れなくなる。

例えば浮動小数点の変換命令を見ると、定義はこんな感じで非常に長くなる。非常に長すぎて意味不明になる。

$arch_table.push(Array['fsqrt.s    f[11:7],f[19:15]'                                                , 32,  32,      '01011', '00',     '00000', 'XXXXX', 'XXX',    'XXXXX',    '10100',    '11', 'FPU',      "",           ["D", "D", "return InstOps::FloatSqrt (op1, softfloat_round_near_even, fflags)"]                                                                                                            , Array['RD_R3', 'R1_R1'         ]                                       ])
$arch_table.push(Array['fsgnj.s    f[11:7],f[19:15],f[24:20]'                                       , 32,  32,      '00100', '00',     'XXXXX', 'XXXXX', '000',    'XXXXX',    '10100',    '11', 'FPU',      "",           ["D", "D", "D", "DWord_t c_op1 = ConvertNaNBoxing(op1); DWord_t c_op2 = ConvertNaNBoxing(op2); return (c_op1 & 0x7FFFFFFFULL) | ( c_op2          & 0x80000000ULL) | 0xffffffff00000000ULL"] , Array['RD_R3', 'R1_R1', 'R2_R2']                                       ])
$arch_table.push(Array['fsgnjn.s   f[11:7],f[19:15],f[24:20]'                                       , 32,  32,      '00100', '00',     'XXXXX', 'XXXXX', '001',    'XXXXX',    '10100',    '11', 'FPU',      "",           ["D", "D", "D", "DWord_t c_op1 = ConvertNaNBoxing(op1); DWord_t c_op2 = ConvertNaNBoxing(op2); return (c_op1 & 0x7FFFFFFFULL) | (~c_op2          & 0x80000000ULL) | 0xffffffff00000000ULL"] , Array['RD_R3', 'R1_R1', 'R2_R2']                                       ])
$arch_table.push(Array['fsgnjx.s   f[11:7],f[19:15],f[24:20]'                                       , 32,  32,      '00100', '00',     'XXXXX', 'XXXXX', '010',    'XXXXX',    '10100',    '11', 'FPU',      "",           ["D", "D", "D", "DWord_t c_op1 = ConvertNaNBoxing(op1); DWord_t c_op2 = ConvertNaNBoxing(op2); return (c_op1 & 0x7FFFFFFFULL) | ((c_op1 ^ c_op2) & 0x80000000ULL) | 0xffffffff00000000ULL"] , Array['RD_R3', 'R1_R1', 'R2_R2']                                       ])
$arch_table.push(Array['fmin.s     f[11:7],f[19:15],f[24:20]'                                       , 32,  32,      '00101', '00',     'XXXXX', 'XXXXX', '000',    'XXXXX',    '10100',    '11', 'FPU',      "",           ["D", "D", "D", "return InstOps::FloatMin (op1, op2, fflags)"]                                                                                                                              , Array['RD_R3', 'R1_R1', 'R2_R2']                                       ])

そこで、このような煩雑な形式は止めてJSONを導入してみる。JSONで命令フォーマットを記述して、それをRubyで読み込ませて命令定義のプリプロセスを行う。

JSONのフォーマットを用いて以下のように書き直した。

    {
        "name":"fsqrt.s    f[11:7],f[19:15]",
        "length":"32", "dlength":"32",
        "field":["01011", "00", "00000", "XXXXX", "XXX", "XXXXX", "10100", "11"],
        "category":"FPU",
        "func_suffix":"",
        "impl":["D", "D", "return InstOps::FloatSqrt (op1, softfloat_round_near_even, fflags)"],
        "inst_ctrl":["RD_R3", "R1_R1"         ]
    },
    {
        "name":"fsgnj.s    f[11:7],f[19:15],f[24:20]",
        "length":"32", "dlength":"32",
        "field":["00100", "00", "XXXXX", "XXXXX", "000", "XXXXX", "10100", "11"],
        "category":"FPU",
        "func_suffix":"",
        "impl":["D", "D", "D", "DWord_t c_op1 = ConvertNaNBoxing(op1); DWord_t c_op2 = ConvertNaNBoxing(op2); return (c_op1 & 0x7FFFFFFFULL) | ( c_op2          & 0x80000000ULL) | 0xffffffff00000000ULL"],
        "inst_ctrl":["RD_R3", "R1_R1", "R2_R2"]
    },
    {
        "name":"fsgnjn.s   f[11:7],f[19:15],f[24:20]",
        "length":"32", "dlength":"32",
        "field":["00100", "00", "XXXXX", "XXXXX", "001", "XXXXX", "10100", "11"],
        "category":"FPU",
        "func_suffix":"",
        "impl":["D", "D", "D", "DWord_t c_op1 = ConvertNaNBoxing(op1); DWord_t c_op2 = ConvertNaNBoxing(op2); return (c_op1 & 0x7FFFFFFFULL) | (~c_op2          & 0x80000000ULL) | 0xffffffff00000000ULL"],
        "inst_ctrl":["RD_R3", "R1_R1", "R2_R2"]
    },

多少分かりやすくなったと思う。

この形式に対応できるようにプリプロセッサスクリプトをいくつか書き換えた。

github.com

これでリコンパイルしてリグレッションテストを流した。特に問題は無いようだ。