やかんです。

引き続き、頑張ってプロセッサを作っていこうと思います。もう、意味わからんけどね。頑張る。

day4はこちら↓

まだまだデコーダ。

まだまだデコーダです。デコーダの姿からはまだまだ遠いんですけどね、、

さて。作業と並行して、デコーダについての解像度も上げていこうと思います。

デコーダとは?

前回記事(こちら)では、デコーダについて「『命令セットを入力として受け取り、制御信号を出力する』装置」という理解を示しました。

これについて解像度を上げてみると、

  • 入力値:命令セット(命令ワード)
  • 出力値:opcodeやfunction_codeに応じて適切に値ごとに分割されたデータ

となるのではと思っています。

出力については、より具体的に言うとソースレジスタやデスティネーションレジスタなど。この理解に基けば、前回記事で書いていたコードにも結構修正が加わります。

東大生やかんのブログ
やかん

今日も書いていくよ

コーディング。

前回のコードを維持したまま書き進めてみるとこんな感じ。

module decoder_ver2(
  input[31:0] iword,
  
  output reg[4:0] rs1,
  output reg[4:0] rs2,
  output reg[4:0] rd,
  output reg[6:0] opcode,
  output reg[2:0] funct3,
  output reg[6:0] funct7,

  // 算術論理演算命令
  output reg LUI,
  output reg AUIPC,
  output reg ADDI,
  output reg SLTI,
  output reg SLTIU,
  output reg XORI,
  output reg ORI,
  output reg ANDI,
  output reg SLLI,
  output reg SRLI,
  output reg SRAI,
  output reg ADD,
  output reg SUB,
  output reg SLL,
  output reg SLT,
  output reg SLTU,
  output reg XOR,
  output reg SRL,
  output reg SRA,
  output reg OR,
  output reg AND,

  // 制御命令
  output reg JAL,
  output reg JALR,
  output reg BEQ,
  output reg BNE,
  output reg BLT,
  output reg BGE,
  output reg BLTU,
  output reg BGEU,

  // データ転送命令
  output reg LB,
  output reg LH,
  output reg LW,
  output reg LBU,
  output reg LHU,
  output reg SB,
  output reg SH,
  output reg SW,

  // システム命令は省略
);
  always @(iword) begin
    reg[7:0] opcode = iword[6:0];
    reg[2:0] funct3 = iword[14:12];
    reg[6:0] funct7 = iword[31:25];

    case(opcode)
    // 算術論理演算命令
      7'b0110111: LUI = 1;
      7'b0010111: AUIPC = 1;
      7'b0010011: ADDi = 1;
      7'b0010011:begin
        case(funct3)
          3'b000: ADDI = 1;
          3'b010: SLTI = 1;
          3'b011: SLTIU = 1;
          3'b100: XORI = 1;
          3'b110: ORI = 1;
          3'b111: ANDI = 1;
          3'b001: SLLI = 1;
          3'b101: begin
            reg[6:0] funct7 = iword[31:25];
            case(funct7)
              7'b0000000: SRLI = 1;
              7'b0100000: SRAI = 1;
            endcase
          end
        endcase
      end
      7'b0110011: begin
        case(funct3)
          3'b000: begin
            funct7 = iword[31:25];
            case(funct7)
              7'0000000: ADD = 1;
              7'b0100000: SUB = 1;
            endcase
          end
          3'b001: SLL = 1;
          3'b010: SLT = 1;
          3'b011: SLTU = 1;
          3'b100: XOR = 1;
          3'b101: begin
            funct7 = iword[31:25];
            case(funct7)
              7'0000000: SRL = 1;
              7'b0100000: SRA = 1;
            endcase
          end
          3'b110: OR = 1;
          3'b111: AND = 1;
        endcase
      end

      // 制御命令
      7'b1101111: JAL = 1;
      7'b1100111: JALR = 1;
      7'b1100011: begin
        case(funct3)
          3'b000: BEQ = 1; // BRANCH on EQUAL
          3'b001: BNE = 1; // BRANCH on NOT EQUAL
          3'b100: BLT = 1; // BRANCH on LESS THAN
          3'b101: BGE = 1; // BRANCH on GREATER THAN or EQUAL
          3'b110: BLTU = 1; // BRANCH on LESS THAN UNSIGNED
          3'b111: BGEU = 1; // BRANCH on GREATER THAN or EQUAL UNSIGNED
        endcase
      end

      // データ転送命令
      7'b0000011: begin
        case(funct3)
          3'b000: LB = 1;
          3'b001: LH = 1;
          3'b010: LW = 1;
          3'b100: LBU = 1;
          3'b101: LHU = 1;
        endcase
      end
      7'b0100011:begin
        case(funct3)
          3'b000: SB = 1;
          3'b001: SH = 1;
          3'b010: SW = 1;
        endcase
      end
    endcase
  end
endmodule

うん。長え。

これもよく頑張ったと思いますが、出力として命令のフラグを返す必要はないですね。修正しましょう。

あってるか分かりませんが、前述の課題を解消しようとした結果こんなコードになりました。

module decoder_ver2(
  input[31:0] iword,
  
  output reg[4:0] rs1,
  output reg[4:0] rs2,
  output reg[3:0] rd,
  output reg[6:0] opcode,
  output reg[2:0] funct3,
  output reg[6:0] funct7,
  output reg imm,
);
  always @(iword) begin
    reg[7:0] opcode = iword[6:0];
    reg[3:0] rd = iword[11:7];
    reg[2:0] funct3 = iword[14:12];
    reg[6:0] funct7 = iword[31:25];

    case(opcode)
    // 算術論理演算命令
      7'b0110111: begin
        // LUI (LOAD UPPER IMMEDIATE)
        reg imm = iword[31:12];
      end
      7'b0010111: begin
        // AUIPC (ADD UPPER IMMEDIATE TO PC)
        reg imm = iword[31:12];
      end
      7'b0010011:begin
        case(funct3)
          3'b000: begin
            // ADDI (ADDITION IMMEDIATE)
            reg imm = iword[31:20];
          end
          3'b010: begin
            // SLTI (SET LESS THAN IMMEDIATE)
            reg imm = iword[31:20];
          end
          3'b011:begin
            // SLTIU (SET LESS THAN IMMEDIATE UNSIGNED)
            reg imm = iword[31:20];
          end
          3'b100: begin
            // XORI (EXCLUSIVE OR IMMEDIATE)
            reg imm = iword[31:20];
          end
          3'b110: begin
            // ORI (OR IMMEDIATE)
            reg imm = iword[31:20];
          end
          3'b111: begin
            // ANDI (AND IMMEDIATE)
            reg imm = iword[31:20];
          end
          3'b001: begin
            // SLLI (SHIFT LEFT LOGICAL IMMEDIATE)
            reg imm = iword[4:0];
          end
          3'b101: begin
            case(funct7)
              7'b0000000: begin
                // SRLI (SHIFT RIGHT LOGICAL IMMEDIATE)
                reg imm = iword[24:20];
              end
              7'b0100000: begin
                // SRAI (SHIFT RIGHT ARITHMETIC IMMEDIATE)
                reg imm = iword[24:20];
              end
            endcase
          end
        endcase
      end
      7'b0110011: begin
        case(funct3)
          3'b000: begin
            case(funct7)
              7'0000000: begin
                // ADD (ADDITION)
              end
              7'b0100000: begin
                // SUB (SUBTRACTION)
              end
            endcase
          end
          3'b001: begin
            // SLL (SHIFT LEFT LOGICAL)
          end
          3'b010: begin
            // SLT (SET LESS THAN)
          end
          3'b011: begin
            // SLTU (SET LESS THAN UNSIGNED)
          end
          3'b100: begin
            // XOR (EXCLUSIVE OR)
          end
          3'b101: begin
            case(funct7)
              7'0000000: begin
                // SRL (SHIFT RIGHT LOGICAL)
              end
              7'b0100000: begin
                // SRA (SHIFT RIGHT ARITHMETIC)
              end
            endcase
          end
          3'b110: begin
            // OR (OR)
          end
          3'b111: begin
            // AND (AND)
          end
        endcase
      end

      // 制御命令
      7'b1101111: begin
        // JAL (JUMP AND LINK)
        // JALの即値は意味がわからないから一旦後回し。
      end
      7'b1100111: begin
        // JALR (JUMP AND LINK REGISTER)
        reg imm = iword[31:20];
      end
      7'b1100011: begin
        case(funct3)
          3'b000: begin
            // (BEQ) BRANCH on EQUAL
            // BEQの即値も意味がわからないから後回し。
          end
          3'b001: begin
            // BNE (BRANCH on NOT EQUAL)
            // BNEの即値も意味がわからないから後回し。
          end
          3'b100: begin
            // BLT (BRANCH on LESS THAN)
            // BLTの即値も意味がわからないから後回し。
          end
          3'b101: begin
            // BGE (BRANCH on GREATER THAN or EQUAL)
            // BGEの即値も意味がわからないから後回し。
          end
          3'b110: begin
            // BLTU (BRANCH on LESS THAN UNSIGNED)
            // BLTUの即値も意味がわからないから後回し。
          end
          3'b111: begin
            // BGEU (BRANCH on GREATER THAN or EQUAL UNSIGNED)
            // BGEUの即値も意味がわからないから後回し。
          end
        endcase
      end

      // データ転送命令
      7'b0000011: begin
        case(funct3)
          3'b000: begin
            // LB (LOAD BYTE)
            reg imm = iword[31:20];
          end
          3'b001: begin
            // LH (LOAD HALFWORD)
            reg imm = iword[31:20];
          end
          3'b010: begin
            // LW (LOAD WORD)
            reg imm = iword[31:20];
          end
          3'b100: begin
            // LBU (LOAD BYTE UNSIGNED)
            reg imm = iword[31:20];
          end
          3'b101: begin
            // LHU (LOAD HALFWORD UNSIGNED)
            reg imm = iword[31:20];
          end
        endcase
      end
      7'b0100011:begin
        case(funct3)
          3'b000: begin
            // SB (STORE BYTE)
            reg imm = iword[31:25];
          end
          3'b001: begin
            // SH (STORE HALFWORD)
            reg imm = iword[31:25];
          end
          3'b010: begin
            // SW (STORE WORD)
            reg imm = iword[31:25];
          end
        endcase
      end
    endcase
  end
endmodule

うーん、頑張ったとは思うけど多分これアンチパターンはまってるよな。

GPT-4の助けを借りた!

いやー、本当にいつもお世話になってばっかりで恐縮でございます。。いつもありがとうねGPT-4くん。

東大生やかんのブログ
やかん

今度菓子折りでも持ってくか

always文の中で使用する値はレジスタじゃない。

上記コードではalways文の中でreg型の変数を宣言してましたが、どうやら使い方が違うようです。reg型はalways分の外側で使うっぽい。

begin…endは消せる。

上記のコードで冗長な部分が一掃され、コードがスッキリします。

↑この2点など、GPT-4くんが提供してくれたコードがこちら。

module decoder_ver2(
  input [31:0] iword,

  output reg [4:0] rs1,
  output reg [4:0] rs2,
  output reg [3:0] rd,
  output reg [6:0] opcode,
  output reg [2:0] funct3,
  output reg [6:0] funct7,
  output reg [31:0] imm  // データ幅の修正
);

always @(iword) begin
  opcode = iword[6:0];
  rd = iword[11:7];
  funct3 = iword[14:12];
  funct7 = iword[31:25];
  
  case(opcode)
    // 算術論理演算命令
    7'b0110111: imm = iword[31:12];  // LUI (LOAD UPPER IMMEDIATE)
    7'b0010111: imm = iword[31:12];  // AUIPC (ADD UPPER IMMEDIATE TO PC)
    7'b0010011: begin
      case(funct3)
        3'b000: imm = iword[31:20];  // ADDI (ADDITION IMMEDIATE)
        3'b010: imm = iword[31:20];  // SLTI (SET LESS THAN IMMEDIATE)
        3'b011: imm = iword[31:20];  // SLTIU (SET LESS THAN IMMEDIATE UNSIGNED)
        3'b100: imm = iword[31:20];  // XORI (EXCLUSIVE OR IMMEDIATE)
        3'b110: imm = iword[31:20];  // ORI (OR IMMEDIATE)
        3'b111: imm = iword[31:20];  // ANDI (AND IMMEDIATE)
        3'b001: imm = {27'b0, iword[24:20]};  // SLLI (SHIFT LEFT LOGICAL IMMEDIATE)
        3'b101: begin
          case(funct7)
            7'b0000000: imm = {27'b0, iword[24:20]};  // SRLI (SHIFT RIGHT LOGICAL IMMEDIATE)
            7'b0100000: imm = {27'b0, iword[24:20]};  // SRAI (SHIFT RIGHT ARITHMETIC IMMEDIATE)
          endcase
        end
      endcase
    end
    // コントロールとブランチ命令は即値の処理を省略
    7'b1101111: imm = iword[31:20];  // JAL (JUMP AND LINK)
    7'b1100111: imm = iword[31:20];  // JALR (JUMP AND LINK REGISTER)
    7'b0000011: begin
      case(funct3)
        3'b000: imm = iword[31:20];  // LB (LOAD BYTE)
        3'b001: imm = iword[31:20];  // LH (LOAD HALFWORD)
        3'b010: imm = iword[31:20];  // LW (LOAD WORD)
        3'b100: imm = iword[31:20];  // LBU (LOAD BYTE UNSIGNED)
        3'b101: imm = iword[31:20];  // LHU (LOAD HALFWORD UNSIGNED)
      endcase
    end
    7'b0100011: begin
      case(funct3)
        3'b000: imm = {20'b0, iword[31:25], iword[11:7]};  // SB (STORE BYTE)
        3'b001: imm = {20'b0, iword[31:25], iword[11:7]};  // SH (STORE HALFWORD)
        3'b010: imm = {20'b0, iword[31:25], iword[11:7]};  // SW (STORE WORD)
      endcase
    end
  endcase
end

endmodule
東大生やかんのブログ
やかん

神か

で、このコードを自分の進捗に合わせて編集したものがこちら。

// 即値の符号拡張等は未実装

module decoder_ver3(
  input [31:0] iword,

  output reg [4:0] rs1,
  output reg [4:0] rs2,
  output reg [3:0] rd,
  output reg [6:0] opcode,
  output reg [2:0] funct3,
  output reg [6:0] funct7,
  output reg [31:0] imm
);

  always @(iword) begin
    opcode = iword[6:0];
    rd = iword[11:7];
    funct3 = iword[14:12];
    funct7 = iword[31:25];

    case(opcode)
      // 算術論理演算命令
      7'b0110111: imm = iword[31:12];  // LUI (LOAD UPPER IMMEDIATE)
      7'b0010111: imm = iword[31:12];  // AUIPC (ADD UPPER IMMEDIATE TO PC)
      7'b0010011: begin
        case(funct3)
          3'b000: imm = iword[31:20];  // ADDI (ADDITION IMMEDIATE)
          3'b010: imm = iword[31:20];  // SLTI (SET LESS THAN IMMEDIATE)
          3'b011: imm = iword[31:20];  // SLTIU (SET LESS THAN IMMEDIATE UNSIGNED)
          3'b100: imm = iword[31:20];  // XORI (EXCLUSIVE OR IMMEDIATE)
          3'b110: imm = iword[31:20];  // ORI (OR IMMEDIATE)
          3'b111: imm = iword[31:20];  // ANDI (AND IMMEDIATE)
          3'b001: imm = iword[24:20];  // SLLI (SHIFT LEFT LOGICAL IMMEDIATE)
          3'b101: begin
            case(funct7)
              7'b0000000: imm = iword[24:20];  // SRLI (SHIFT RIGHT LOGICAL IMMEDIATE)
              7'b0100000: imm = iword[24:20];  // SRAI (SHIFT RIGHT ARITHMETIC IMMEDIATE)
            endcase
          end
        endcase
      end

      // 制御命令
      7'b1101111: // JAL (JUMP AND LINK)
      7'b1100111: // JALR (JUMP AND LINK REGISTER)
      7'b1100011: begin
        case(funct3)
          3'b000: // BEQ (BRANCH EQUAL)
          3'b001: // BNE (BRANCH NOT EQUAL)
          3'b100: // BLT (BRANCH LESS THAN)
          3'b101: // BGE (BRANCH GREATER THAN OR EQUAL)
          3'b110: // BLTU (BRANCH LESS THAN UNSIGNED)
          3'b111: // BGEU (BRANCH GREATER THAN OR EQUAL UNSIGNED)
        endcase
      end

      // データ転送命令
      7'b0000011: begin
        case(funct3)
          3'b000: imm = iword[31:20];  // LB (LOAD BYTE)
          3'b001: imm = iword[31:20];  // LH (LOAD HALFWORD)
          3'b010: imm = iword[31:20];  // LW (LOAD WORD)
          3'b100: imm = iword[31:20];  // LBU (LOAD BYTE UNSIGNED)
          3'b101: imm = iword[31:20];  // LHU (LOAD HALFWORD UNSIGNED)
        endcase
      end
      7'b0100011: begin
        case(funct3)
          3'b000: // SB (STORE BYTE)
          3'b001: // SH (STORE HALFWORD)
          3'b010: // SW (STORE WORD)
        endcase
      end
    endcase
  end

endmodule

まだ即値の符号拡張とかは行ってないので未完成ではありますが。

今日のまとめ。

「仕様書とにらめっこする」と教授が言っていたが、その意味がなんとなくわかりつつある気がする。まだわかってないけど。

ということで、day5の奮闘記は終了。最後までお読みいただき、ありがとうございます。