自作ISSでは、MIPSのRelease-5までの基本的な命令と、RISC-Vの基本的な命令を対応させている。 浮動小数点の命令などはまだ実装していないが、まだ検証する方法が無いし、使っていないので今のところ実装してない。
Imaginationから新しいコアもリリースされて、いよいよMIPS R6が主流になるようなので、デコーダの実装と新規命令の実装をしてようと思う。
Compact Branch命令のデコード
さっそく引掛ったのは、Compact Branch命令のバリエーションだ。 Compact Branch命令は、R6から新規に追加された命令で、ついに遅延スロットが実行されない命令となっている。
以下は MIPS R6のアーキテクチャリファレンスマニュアルより抜粋:
Compact branches have no delay slot: the instruction after the branch is NOT executed if the branch is taken.
ところが、こいつらのデコードがちょっと難しい。レジスタの指定方法によって、命令の種類が変わったりする。
RSとRTが0だったり0で無かったり、あるいはRS==RTかRS!=RTかで命令の種類が変わってしまうのだ。 このようなデコードは、現在の自作ISSではサポートしていない。どのようにすればサポートできるのか検討しよう。
デコードテーブルに制限を記載できるようにする
以下のような記述ができることが理想だ。
$arch_table[142] = Array['blezalc d[20:16],h[15:0]', '000110', '00000', 'XXXXX!=00', 'XXXXX', 'XXXXX', 'XXXXXX', 'BRANCH', Array[ ], Array['OPCODE', 'RT', 'RS']] $arch_table[143] = Array['bgezalc d[20:16],h[15:0]', '000110', 'XXXXX!=00', 'XXXXX!=00==RS', 'XXXXX', 'XXXXX', 'XXXXXX', 'BRANCH', Array[ ], Array['OPCODE', 'RT', 'RS']] $arch_table[144] = Array['bgtzalc d[20:16],h[15:0]', '000111', '00000', 'XXXXX!=00', 'XXXXX', 'XXXXX', 'XXXXXX', 'BRANCH', Array[ ], Array['OPCODE', 'RT', 'RS']] $arch_table[145] = Array['bltzalc d[20:16],h[15:0]', '000111', 'XXXXX', 'XXXXX!=00==RS', 'XXXXX', 'XXXXX', 'XXXXXX', 'BRANCH', Array[ ], Array['OPCODE', 'RT', 'RS']] $arch_table[144] = Array['beqzalc d[20:16],h[15:0]', '001000', '00000', 'XXXXX!=00', 'XXXXX', 'XXXXX', 'XXXXXX', 'BRANCH', Array[ ], Array['OPCODE', 'RT', 'RS']] $arch_table[145] = Array['bnezalc d[20:16],h[15:0]', '011000', '00000', 'XXXXX!=00', 'XXXXX', 'XXXXX', 'XXXXXX', 'BRANCH', Array[ ], Array['OPCODE', 'RT', 'RS']]
ちょっと横長で見えにくいが、デコードテーブルで、基本的にX(=0,1どちらのビットでも構わない)のだが、それでも全体の5ビットで0以外でなければならない、例えば、
XXXXX!=00
であるとか、全体の5ビットが隣のRSフィールドよりも値が大きくなければならない、かつ0以外、例えば、
XXXXX!=00>RS
とか記述できるようになりたい。そのためには、デコード生成機の抜本的な改良が不可欠だ。
制約条件を Parse できるようにする
Rubyのscan()を使って、「演算子+定数orレジスタ名」で制約を認識できるようにする。
def MakeConstraintFuncStr (inst_info, key_table, code_str) actual_code_str = code_str.scan(/(==|!=|<|>)([\w\d]+)/) func_str = "%s_%s_"%([inst_info[DEC::FUNC_STR], key_table[0]]) actual_code_str.each {|code| if code[0] == "==" then func_str="%s_EQ_%s"%([func_str, code[1]]) elsif code[0] == "!=" then func_str="%s_NE_%s"%([func_str, code[1]]) elsif code[0] == "<" then func_str="%s_LS_%s"%([func_str, code[1]]) elsif code[0] == ">" then func_str="%s_GT_%s"%([func_str, code[1]]) end } return func_str end
もしビットフィールドがこの制約に該当するならば、1つずつデコードし直して、制約に合うデコード用の関数を追加していく訳だ。 もし'XXXXX!=00>RS'という制約が存在するならば、まずはscanにより以下のような配列に変換され、
[["!=", 00], [">", RS]]
定数ならばそのまま比較、別のビットフィールドとの比較なら抽出オペレータを生成する訳だ。 複数の制約が存在すれば、これを&&演算子で結んでいく。
def PrintIfExpWithConst(fp, key_table, func_str, code_str) actual_code_str = code_str.scan(/(==|!=|<|>)([\w\d]+)/) actual_code_str.each_with_index {|code, index| if index == 0 then fp.printf(" if (") end if $arch_list_def[code[1]] == nil then fp.printf("Extract%sField (inst_hex) %s %s", key_table, code[0], code[1]) else fp.printf("Extract%sField (inst_hex) %s Extract%sField (inst_hex)", key_table, code[0], code[1]) end if index == actual_code_str.size - 1 then fp.printf(") {\n") else fp.printf(" &&\n ") end } end
そうすると、以下のようなデコード用のC++コードが生成されるようになる。
if (ExtractRTField (inst_hex) != 00 && ExtractRTField (inst_hex) > ExtractRSField (inst_hex)) { int32_t ret = MIPS_DEC_OPCODE_0x8_RT__NE_00_GT_RS (inst_hex); if (ret != -1) return ret; }
とりあえず、これでデコードテーブルが生成できるようになった。 しかし、まだきちんとデコード出来ていないのか、Coremarkが最後まで完走していない。これは調査しなければ。
途中から不定領域のメモリアクセスが始まるし、どこかで制御ループのミスが発生しているかな。
354 : [800007a0] 004b10d9 : muhu_r6 r02,r02,r11 r02=>0000001f r11=>cccccccd r02<=00000018 355 : [800007a4] 10000006 : beq r00,r00,0x0006 r00=>00000000 r00=>00000000 pc<=800007a8 pc<=800007c0 356 : [800007a8] 00025882 : srl r11,r02,0x02 r02=>00000018 r11<=00000006 357 : [800007c0] 8d0a0000 : lw r10,0x0000(r08) r08=>00000000 (00000000)=>00000f41 r10<=00000f41 358 : [800007c4] 31220007 : andi r02,r09,0x0007 r09=>00000002 r02<=00000002 359 : [800007c8] 00663826 : xor r07,r03,r06 r03=>00000001 r06=>00000000 r07<=00000001 360 : [800007cc] 00021200 : sll r02,r02,0x08 r02=>00000002 r02<=00000200 361 : [800007d0] 11400006 : beq r10,r00,0x0006 r10=>00000f41 r00=>00000000 pc<=800007d4 362 : [800007d4] 00471025 : or r02,r02,r07 r02=>00000200 r07=>00000001 r02<=00000201 363 : [800007d8] 1c6bfff4 : bltuc r03,r11,0xfff4 r03=>00000001 r11=>00000006 364 : [800007dc] 8d040004 : lw r04,0x0004(r08) r08=>00000000 (00000004)=>756e6700 r04<=756e6700 365 : [800007e0] 30423fff : andi r02,r02,0x3fff r02=>00000201 r02<=00000201 366 : [800007e4] 1000fff3 : beq r00,r00,0xfff3 r00=>00000000 r00=>00000000 pc<=800007e8 pc<=800007b4 367 : [800007e8] a4820002 : sh r02,0x0002(r02) r04=>756e6700 r02=>00000201 (756e6702)<=00000201 368 : [800007b4] 25290001 : addiu r09,r09,0x0001 r09=>00000002 r09<=00000003 369 : [800007b8] 24630001 : addiu r03,r03,0x0001 r03=>00000001 r03<=00000002 370 : [800007bc] 01404021 : addu r08,r10,r00 r10=>00000f41 r00=>00000000 r08<=00000f41 <Warning: Memory 00000f41 MisAlign Access.> 371 : [800007c0] 8d0a0000 : lw r10,0x0000(r08) r08=>00000f41 (00000f41)=>00007ffe r10<=00007ffe 372 : [800007c4] 31220007 : andi r02,r09,0x0007 r09=>00000003 r02<=00000003 373 : [800007c8] 00663826 : xor r07,r03,r06 r03=>00000002 r06=>00000000 r07<=00000002 374 : [800007cc] 00021200 : sll r02,r02,0x08 r02=>00000003 r02<=00000300 375 : [800007d0] 11400006 : beq r10,r00,0x0006 r10=>00007ffe r00=>00000000 pc<=800007d4 376 : [800007d4] 00471025 : or r02,r02,r07 r02=>00000300 r07=>00000002 r02<=00000302