FPGA開発日記

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

ISSからハードウェアデコーダを自動生成してみる

github.com

ISSの命令デコーダは、rubyから自動生成している。これを活用すると、ハードウェアのデコーダも自動生成できないだろうか。 とりあえず作ってみると、こんな感じになった。 まず、ISSデコーダRubyのテーブルで以下のように構成されている。

これのデコードテーブルの部分だけ取り出して、Xの入っていない部分(実際にデコードしなければならない部分)を取り出してみる。 Rubyで書いてみたのだが、以下のようにしてみた。 RISC-Vのデコードテーブルにがっつり依存しているので、記述としてはあまり良くないなあ。 ちょっと汎用化していきたい。

github.com

# generate instruction list
$arch_table.each_with_index {|inst_info, index|
  is_generate_and = false

  mne = "INST_%s"%([inst_info[ARCH::NAME].split(" ")[0].gsub(/\./,'_').upcase])
  mnemonic = "    assign IF_INST_DEC[`" + mne + "] = "
  if not inst_info[ARCH::R3].include?("X") then
    mnemonic = mnemonic + "(IF_INST[31:27] == 5'b"
    mnemonic = mnemonic + inst_info[ARCH::R3] + ")"
    is_generate_and = true
  end

  if not inst_info[ARCH::F2].include?("X") then
    if is_generate_and == true then
      mnemonic = mnemonic + " & ";
    end
    mnemonic = mnemonic + "(IF_INST[26:25] == 2'b"
    mnemonic = mnemonic + inst_info[ARCH::F2] + ")"
    is_generate_and = true
  end

  if not inst_info[ARCH::R2].include?("X") then
    if is_generate_and == true then
      mnemonic = mnemonic + " & ";
    end
    mnemonic = mnemonic + "(IF_INST[24:20] == 5'b"
    mnemonic = mnemonic + inst_info[ARCH::R2] + ")"
    is_generate_and = true
  end

  if not inst_info[ARCH::R1].include?("X") then
    if is_generate_and == true then
      mnemonic = mnemonic + " & ";
    end
    mnemonic = mnemonic + "(IF_INST[19:15] == 5'b"
    mnemonic = mnemonic + inst_info[ARCH::R1] + ")"
    is_generate_and = true
  end
...

実際に生成されたVerilog-HDLファイルがこれだ。一応、Vivadoで合成してみて、エラーは発生していないようだ。

github.com

`default_nettype none

`include "./riscv_dec.vh"

module riscv_dec (
    input  wire [31: 0] IF_INST,
    output wire [136: 0] IF_INST_DEC
);
    assign IF_INST_DEC[`INST_LUI] = (IF_INST[ 6: 0] == 7'b0110111);
    assign IF_INST_DEC[`INST_AUIPC] = (IF_INST[ 6: 0] == 7'b0010111);
    assign IF_INST_DEC[`INST_JAL] = (IF_INST[ 6: 0] == 7'b1101111);
    assign IF_INST_DEC[`INST_JALR] = (IF_INST[14:12] == 3'b000) & (IF_INST[ 6: 0] == 7'b1100111);
    assign IF_INST_DEC[`INST_BEQ] = (IF_INST[14:12] == 3'b000) & (IF_INST[ 6: 0] == 7'b1100011);
    assign IF_INST_DEC[`INST_BNE] = (IF_INST[14:12] == 3'b001) & (IF_INST[ 6: 0] == 7'b1100011);
    assign IF_INST_DEC[`INST_BLT] = (IF_INST[14:12] == 3'b100) & (IF_INST[ 6: 0] == 7'b1100011);
    assign IF_INST_DEC[`INST_BGE] = (IF_INST[14:12] == 3'b101) & (IF_INST[ 6: 0] == 7'b1100011);
    assign IF_INST_DEC[`INST_BLTU] = (IF_INST[14:12] == 3'b110) & (IF_INST[ 6: 0] == 7'b1100011);
    assign IF_INST_DEC[`INST_BGEU] = (IF_INST[14:12] == 3'b111) & (IF_INST[ 6: 0] == 7'b1100011);
    assign IF_INST_DEC[`INST_LB] = (IF_INST[14:12] == 3'b000) & (IF_INST[ 6: 0] == 7'b0000011);
    assign IF_INST_DEC[`INST_LH] = (IF_INST[14:12] == 3'b001) & (IF_INST[ 6: 0] == 7'b0000011);
    assign IF_INST_DEC[`INST_LW] = (IF_INST[14:12] == 3'b010) & (IF_INST[ 6: 0] == 7'b0000011);
    assign IF_INST_DEC[`INST_LBU] = (IF_INST[14:12] == 3'b100) & (IF_INST[ 6: 0] == 7'b0000011);
...