FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

自作ISSのRelease-6への対応を検討する

自作ISSでは、MIPSのRelease-5までの基本的な命令と、RISC-Vの基本的な命令を対応させている。 浮動小数点の命令などはまだ実装していないが、まだ検証する方法が無いし、使っていないので今のところ実装してない。

Imaginationから新しいコアもリリースされて、いよいよMIPS R6が主流になるようなので、デコーダの実装と新規命令の実装をしてようと思う。

Compact Branch命令のデコード

さっそく引掛ったのは、Compact Branch命令のバリエーションだ。 Compact Branch命令は、R6から新規に追加された命令で、ついに遅延スロットが実行されない命令となっている。

以下は MIPS R6のアーキテクチャリファレンスマニュアルより抜粋:

f:id:msyksphinz:20151121142322p:plain

Compact branches have no delay slot: the instruction after the branch is NOT executed if the branch is taken.

ところが、こいつらのデコードがちょっと難しい。レジスタの指定方法によって、命令の種類が変わったりする。

f:id:msyksphinz:20151121142447p:plain

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;
    }

github.com

とりあえず、これでデコードテーブルが生成できるようになった。 しかし、まだきちんとデコード出来ていないのか、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