さて、ハードウェアデコーダとして、制御信号を生成していこう。
命令毎のテーブルから、信号を取り出すために、以下のようなRubyのコードを用いて自動生成してみる。
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とかを使えば、もうちょっと楽できるかもしれない。