FPGA開発日記

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

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

続いて、制御信号を自動生成してみよう。

github.com

基本的には、命令分類毎に必要な信号の種類がリストアップされているので、 命令分類毎に、各命令で制御信号が必要とされているかをチェックし、必要とされていれば信号線を生成、そうでなければ0とする。

 ##
 ##=== Making all of signals for each kinds of Instruction
 ##
+ctrl_table = Hash.new()
+
 inst_dec_type.each {|inst_type|

   ctrl_signals = Hash.new()
@@ -324,4 +326,56 @@ inst_dec_type.each {|inst_type|
     }
   }
   printf("\n")
+
+  # insert signals table into hash
+  ctrl_table[inst_type] = ctrl_signals;
+}
+
+
+##
+## generate control signals
+##
+
+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("          %-15s : IF_INST_DEC <= {", mne)
+
+  # 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("%s", ctrl_name)
+        found = true
+      end
+    }
+    if found == false then
+      inst_ctrl_fp.printf("%d'h0", ctrl_bitwidth)
+    end
+    if index != (ctrl_table[target_type].size-1) then
+      inst_ctrl_fp.print(", ")
+    end
+  }
+  inst_ctrl_fp.puts("};\n")
 }
+
+inst_ctrl_fp.printf("        endcase\n")
+inst_ctrl_fp.printf("    end\n")
+inst_ctrl_fp.printf("endmodule\n")
+inst_ctrl_fp.close

作られた制御信号は以下のようになった。

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


`default_nettype none

`include "./mips_dec.vh"

module mips_dec (
    input  wire [31: 0] IF_INST,
    output wire [`INST_MAX-1: 0] IF_INST_DEC
);
    always @ (*) begin
        case (1'b1)
          `INST_ADD       : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_SIGN_ADD, 1'h0, 1'h0, 3'h0};
          `INST_ADDI      : IF_INST_DEC <= {DST_RT, R1_RS, 1'h0, ALU_SIGN_ADD, IMM, 1'h0, 3'h0};
          `INST_ADDIU     : IF_INST_DEC <= {DST_RT, R1_RS, 1'h0, ALU_USIGN_ADD, IMM, 1'h0, 3'h0};
          `INST_ADDU      : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_USIGN_ADD, 1'h0, 1'h0, 3'h0};
          `INST_CLO       : IF_INST_DEC <= {DST_RD, R1_RS, 1'h0, ALU_COUNT_ONE, 1'h0, 1'h0, 3'h0};
          `INST_CLZ       : IF_INST_DEC <= {DST_RD, R1_RS, 1'h0, ALU_COUNT_ZERO, 1'h0, 1'h0, 3'h0};
          `INST_DIV       : IF_INST_DEC <= {DST_M, R1_RS, R2_RT, ALU_SIGN_DIV, 1'h0, SEPARATE, 3'h0};
          `INST_DIVU      : IF_INST_DEC <= {DST_M, R1_RS, R2_RT, ALU_USIGN_DIV, 1'h0, SEPARATE, 3'h0};
          `INST_MADD      : IF_INST_DEC <= {DST_M, R1_RS, R2_RT, ALU_SIGN_MADD, 1'h0, SEPARATE, 3'h0};
          `INST_MADDU     : IF_INST_DEC <= {DST_M, R1_RS, R2_RT, ALU_USIGN_MADD, 1'h0, SEPARATE, 3'h0};
          `INST_MSUB      : IF_INST_DEC <= {DST_M, R1_RS, R2_RT, ALU_SIGN_MSUB, 1'h0, SEPARATE, 3'h0};
          `INST_MSUBU     : IF_INST_DEC <= {DST_M, R1_RS, R2_RT, ALU_USIGN_MSUB, 1'h0, SEPARATE, 3'h0};
          `INST_MUL       : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_SIGN_MULT, 1'h0, 1'h0, 3'h0};
          `INST_MULT      : IF_INST_DEC <= {DST_M, R1_RS, R2_RT, ALU_SIGN_MULT, 1'h0, SEPARATE, 3'h0};
          `INST_MULTU     : IF_INST_DEC <= {DST_M, R1_RS, R2_RT, ALU_USIGN_MULT, 1'h0, SEPARATE, 3'h0};
          `INST_SEB       : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_SIGN_EXT_B, 1'h0, 1'h0, 3'h0};
          `INST_SEH       : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_SIGN_EXT_H, 1'h0, 1'h0, 3'h0};
          `INST_SLT       : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_SIGN_SLT, 1'h0, 1'h0, 3'h0};
          `INST_SLTI      : IF_INST_DEC <= {DST_RT, R1_RS, 1'h0, ALU_SIGN_SLT, IMM, 1'h0, 3'h0};
          `INST_SLTIU     : IF_INST_DEC <= {DST_RT, R1_RS, 1'h0, ALU_USIGN_SLT, IMM, 1'h0, 3'h0};
          `INST_SLTU      : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_USIGN_SLT, 1'h0, 1'h0, 3'h0};
          `INST_SUB       : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_SIGN_SUB, 1'h0, 1'h0, 3'h0};
          `INST_SUBU      : IF_INST_DEC <= {DST_RD, R1_RS, R2_RT, ALU_USIGN_SUB, 1'h0, 1'h0, 3'h0};
          `INST_B         : IF_INST_DEC <= {IMM, PC_REL, 1'h0, 1'h0, 1'h0, 3'h0, 1'h0};
          `INST_BAL       : IF_INST_DEC <= {IMM, PC_REL, DST_31, 1'h0, 1'h0, 3'h0, 1'h0};
...

なんとなくうまく出来ている気がする。しかし、あとはレジスタインデックスの切り抜きなど、もうすこし気の効いた生成をしなければならない。見た目もインデントが揃っていなくて気持ちが悪い。 もうちょっと修正していこう。