FPGA開発日記

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

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

さて、ハードウェアデコーダとして、制御信号を生成していこう。

命令毎のテーブルから、信号を取り出すために、以下のようなRubyのコードを用いて自動生成してみる。

github.com

inst_ctrl_fp.printf(mnemonic, max_ctrl_bitwidth)

inst_ctrl_fp.printf("    always @ (*) begin\n")

inst_ctrl_fp.printf("        case (1'b1)\n")

$arch_table.each_with_index {|target_inst, index|
  target_signals = target_inst[ARCH::INST_CTRL];
  target_type    = target_inst[ARCH::INST_TYPE];

  mne = "`INST_%s"%([target_inst[ARCH::NAME].split(" ")[0].gsub(/\./,'_').upcase])

  inst_ctrl_fp.printf("          IF_INST_DEC[%-15s] : IF_INST_CTRL <= {", mne)

  # insert dummy signal
  if ctrl_remain_bitwidth[target_type] != 0 then
    inst_ctrl_fp.printf("%d'b%0*b, ", ctrl_remain_bitwidth[target_type], ctrl_remain_bitwidth[target_type], 0)
  end

  # traverse all of control signals in the inst-type
  ctrl_table[target_type].each_with_index {|(key, ctrl_list), index|
    if ctrl_list.size == 1 then
      ctrl_bitwidth = 1
    else
      ctrl_bitwidth = Math::log2(ctrl_list.size).to_i
    end

    # traverse all of control signals in the inst-type
    found = false
    ctrl_list.each_with_index {|ctrl_pair, ctrl_index|
      ctrl_name = ctrl_pair[0]
      if target_signals.include?(ctrl_name) then
        inst_ctrl_fp.printf("`CTRL_%s_%s", target_type, ctrl_name)
        found = true
      end
    }
    if found == false then
      inst_ctrl_fp.printf("%d'b%0*b", ctrl_bitwidth, ctrl_bitwidth, 0)
    end
    if index != (ctrl_table[target_type].size-1) then
      inst_ctrl_fp.print(", ")
    end
  }
  inst_ctrl_fp.printf("};\t\t")
  inst_ctrl_fp.printf("// %s\n", target_type)
}

inst_ctrl_fp.printf("          default : IF_INST_CTRL <= %d'b%0*b;\n", max_ctrl_bitwidth, max_ctrl_bitwidth, 0)

inst_ctrl_fp.printf("        endcase\n")
inst_ctrl_fp.printf("    end\n")
inst_ctrl_fp.printf("endmodule\n")

この結果、以下のようなmips_ctrl.vが生成される。

/* CAUTION! THIS SOURCE CODE IS GENERATED AUTOMATICALLY. DON'T MODIFY BY HAND. */


`default_nettype none

`include "./mips_dec.vh"
`include "./mips_ctrl.vh"

module mips_ctrl (
    input wire  [`INST_MAX-1: 0] IF_INST_DEC,
    output reg  [18-1: 0] IF_INST_CTRL
);

    always @ (*) begin
        case (1'b1)
          IF_INST_DEC[`INST_ADD      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_ADD, 1'b0, 1'b0, 3'b000};               // ALU
          IF_INST_DEC[`INST_ADDI     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RT, `CTRL_ALU_R1_RS, 1'b0, `CTRL_ALU_OP_SIGN_ADD, `CTRL_ALU_IMM, 1'b0, 3'b000};         // ALU
          IF_INST_DEC[`INST_ADDIU    ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RT, `CTRL_ALU_R1_RS, 1'b0, `CTRL_ALU_OP_USIGN_ADD, `CTRL_ALU_IMM, 1'b0, 3'b000};                // ALU
          IF_INST_DEC[`INST_ADDU     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_USIGN_ADD, 1'b0, 1'b0, 3'b000};              // ALU
          IF_INST_DEC[`INST_CLO      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, 1'b0, `CTRL_ALU_OP_COUNT_ONE, 1'b0, 1'b0, 3'b000};         // ALU
          IF_INST_DEC[`INST_CLZ      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, 1'b0, `CTRL_ALU_OP_COUNT_ZERO, 1'b0, 1'b0, 3'b000};                // ALU
          IF_INST_DEC[`INST_DIV      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_M, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_DIV, 1'b0, `CTRL_ALU_SEPARATE, 3'b000};          // ALU
          IF_INST_DEC[`INST_DIVU     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_M, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_USIGN_DIV, 1'b0, `CTRL_ALU_SEPARATE, 3'b000};         // ALU
          IF_INST_DEC[`INST_MADD     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_M, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_MADD, 1'b0, `CTRL_ALU_SEPARATE, 3'b000};         // ALU
          IF_INST_DEC[`INST_MADDU    ] : IF_INST_CTRL <= {`CTRL_ALU_DST_M, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_USIGN_MADD, 1'b0, `CTRL_ALU_SEPARATE, 3'b000};                // ALU
          IF_INST_DEC[`INST_MSUB     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_M, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_MSUB, 1'b0, `CTRL_ALU_SEPARATE, 3'b000};         // ALU
          IF_INST_DEC[`INST_MSUBU    ] : IF_INST_CTRL <= {`CTRL_ALU_DST_M, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_USIGN_MSUB, 1'b0, `CTRL_ALU_SEPARATE, 3'b000};                // ALU
          IF_INST_DEC[`INST_MUL      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_MULT, 1'b0, 1'b0, 3'b000};              // ALU
          IF_INST_DEC[`INST_MULT     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_M, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_MULT, 1'b0, `CTRL_ALU_SEPARATE, 3'b000};         // ALU
          IF_INST_DEC[`INST_MULTU    ] : IF_INST_CTRL <= {`CTRL_ALU_DST_M, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_USIGN_MULT, 1'b0, `CTRL_ALU_SEPARATE, 3'b000};                // ALU
          IF_INST_DEC[`INST_SEB      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_EXT_B, 1'b0, 1'b0, 3'b000};             // ALU
          IF_INST_DEC[`INST_SEH      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_EXT_H, 1'b0, 1'b0, 3'b000};             // ALU
          IF_INST_DEC[`INST_SLT      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_SLT, 1'b0, 1'b0, 3'b000};               // ALU
          IF_INST_DEC[`INST_SLTI     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RT, `CTRL_ALU_R1_RS, 1'b0, `CTRL_ALU_OP_SIGN_SLT, `CTRL_ALU_IMM, 1'b0, 3'b000};         // ALU
          IF_INST_DEC[`INST_SLTIU    ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RT, `CTRL_ALU_R1_RS, 1'b0, `CTRL_ALU_OP_USIGN_SLT, `CTRL_ALU_IMM, 1'b0, 3'b000};                // ALU
          IF_INST_DEC[`INST_SLTU     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_USIGN_SLT, 1'b0, 1'b0, 3'b000};              // ALU
          IF_INST_DEC[`INST_SUB      ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_SUB, 1'b0, 1'b0, 3'b000};               // ALU
          IF_INST_DEC[`INST_SUBU     ] : IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_USIGN_SUB, 1'b0, 1'b0, 3'b000};              // ALU
          IF_INST_DEC[`INST_B        ] : IF_INST_CTRL <= {7'b0000000, `CTRL_BRANCH_IMM, `CTRL_BRANCH_PC_REL, 1'b0, 1'b0, 1'b0, 3'b000, 1'b0};           // BRANCH
          IF_INST_DEC[`INST_BAL      ] : IF_INST_CTRL <= {7'b0000000, `CTRL_BRANCH_IMM, `CTRL_BRANCH_PC_REL, `CTRL_BRANCH_DST_31, 1'b0, 1'b0, 3'b000, 1'b0};            // BRANCH
          IF_INST_DEC[`INST_BEQ      ] : IF_INST_CTRL <= {7'b0000000, 1'b0, `CTRL_BRANCH_PC_REL, 1'b0, `CTRL_BRANCH_R1_RS, `CTRL_BRANCH_R2_RT, `CTRL_BRANCH_OP_SIGN_EQ, 1'b0};          // BRANCH
...

でも、実際問題MIPSデコーダ専用のコードになっちゃってるんだよな。。。Pyverilogとかを使えば、もうちょっと楽できるかもしれない。

github.com