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"] },
多少分かりやすくなったと思う。