やかんです。

とりあえず、デコーダを頑張って作ろうと思います。

そもそもデコーダとは?

ざっくり言えば、「命令セットを入力として受け取り、制御信号を出力する」装置なはず。

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

ほんとか?

まあ、現状の理解なので、理解に進展があったら改めます。

順々に書き始めてみる。

まずは、算術演算の命令から。

多分、まずはこんな感じになる。出力として盛り込みたい算術演算命令を列挙。

module decoder_ver2(
  input[31:0] instr,
  
  output reg[4:0] rs1,
  output reg[4:0] rs2,
  output reg[4:0] rd,
  output reg[6:0] opcode,

  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,
);
endmodule

で、instrから7bitのopcodeを取得して、それに応じてcase文で分岐させる。

module decoder_ver2(
  input[31:0] instr,
  
  output reg[4:0] rs1,
  output reg[4:0] rs2,
  output reg[4:0] rd,
  output reg[6:0] opcode,

  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,
);
  always @(instr) begin
    opcode = instr[6:0];

    case(opcode)
      7'b0110111: LUI = 1;
      7'b0010111: AUIPC = 1;
      7'b0010011: ADDi = 1;
      
      // ここに記述 
     
     endcase
  end
endmodule

うん。あってるかわからんが、とりあえず良さそうだ。で、ここで問題というか、一癖出てくるわけだ。

opcodeが等しいものをfunction_codeで場合分けする場合がある!

まあ、当然と言えば当然なんですが。一生懸命分岐させたものが多分こちら。

module decoder_ver2(
  input[31:0] instr,
  
  output reg[4:0] rs1,
  output reg[4:0] rs2,
  output reg[4:0] rd,
  output reg[6:0] opcode,

  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,
);
  always @(instr) begin
    opcode = instr[6:0];

    case(opcode)
      7'b0110111: LUI = 1;
      7'b0010111: AUIPC = 1;
      7'b0010011: ADDi = 1;

      7'b0010011:begin
        reg[2:0] funct3 = instr[14:12];
        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 = instr[31:25];
            case(funct7)
              7'b0000000: SRLI = 1;
              7'b0100000: SRAI = 1;
            endcase
          end
        endcase
      end

      7'b0110011: begin
        funct3 = instr[14:12];
        case(funct3)
          3'b000: begin
            funct7 = instr[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 = instr[31:25];
            case(funct7)
              7'0000000: SRL = 1;
              7'b0100000: SRA = 1;
            endcase
          end

          3'b110: OR = 1;
          3'b111: AND = 1;
        endcase
      end
    endcase
  end
endmodule

頑張った、、、

まあ、あってるかはテストベンチ作って地道に動作確認するしかないですね。

今回のまとめ。

いや、めっちゃ大変だわ。でも、面白い。楽しい。頑張る!

次は、テストベンチ作っていい感じだったら算術演算以外の命令について一生懸命網羅する。

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