LoginSignup
1
0

More than 5 years have passed since last update.

RISC-Vソースコード読書会(7)

Last updated at Posted at 2018-01-10

<ID>

命令デコーダ

RISCVの命令デコーダであり、RV32Iの一部となっている。一部というのは除算が省略されているため。また、自身がマイクロアーキ屋であることから、ISAは命令デコーダで吸収できるから何でも良くあまり興味が無いため、とおり一編の説明となってしまう。

src/fpga/decoder.v
`include "constants.vh"
`include "rv32_opcodes.vh"
`include "alu_ops.vh"

`default_nettype none
module decoder(
           input wire [31:0]          inst,
           output reg [`IMM_TYPE_WIDTH-1:0]   imm_type,
           output wire [`REG_SEL-1:0]     rs1,
           output wire [`REG_SEL-1:0]     rs2,
           output wire [`REG_SEL-1:0]     rd,
           output reg [`SRC_A_SEL_WIDTH-1:0]  src_a_sel,
               output reg [`SRC_B_SEL_WIDTH-1:0]  src_b_sel,
           output reg             wr_reg,

           output reg             uses_rs1,
           output reg             uses_rs2,
           output reg             illegal_instruction,
           output reg [`ALU_OP_WIDTH-1:0]     alu_op,
           output reg [`RS_ENT_SEL-1:0]       rs_ent,
//         output reg             dmem_use,
//         output reg             dmem_write,
           output wire [2:0]          dmem_size,
           output wire [`MEM_TYPE_WIDTH-1:0]  dmem_type, 
           output reg [`MD_OP_WIDTH-1:0]      md_req_op,
           output reg             md_req_in_1_signed,
           output reg             md_req_in_2_signed,
           output reg [`MD_OUT_SEL_WIDTH-1:0] md_req_out_sel

           );

   wire [`ALU_OP_WIDTH-1:0]               srl_or_sra;
   wire [`ALU_OP_WIDTH-1:0]               add_or_sub;
   wire [`RS_ENT_SEL-1:0]             rs_ent_md;

   wire [6:0]           opcode = inst[6:0];
   wire [6:0]           funct7 = inst[31:25];
   wire [11:0]          funct12 = inst[31:20];
   wire [2:0]           funct3 = inst[14:12];
// reg [`MD_OP_WIDTH-1:0]   md_req_op;
   reg [`ALU_OP_WIDTH-1:0]  alu_op_arith;

   assign rd = inst[11:7];
   assign rs1 = inst[19:15];
   assign rs2 = inst[24:20];

   assign dmem_size = {1'b0,funct3[1:0]};
   assign dmem_type = funct3;

以下は組み合わせ回路

   always @ (*) begin
      imm_type = `IMM_I;
      src_a_sel = `SRC_A_RS1;
      src_b_sel = `SRC_B_IMM;
      wr_reg = 1'b0;
      uses_rs1 = 1'b1;
      uses_rs2 = 1'b0;
      illegal_instruction = 1'b0;
      //      dmem_use = 1'b0;
      //     dmem_write = 1'b0;
      rs_ent = `RS_ENT_ALU;
      alu_op = `ALU_OP_ADD;

      case (opcode)
    `RV32_LOAD : begin
//           dmem_use = 1'b1;
           wr_reg = 1'b1;
       rs_ent = `RS_ENT_LDST;
//           wb_src_sel_DX = `WB_SRC_MEM;
        end
        `RV32_STORE : begin
           uses_rs2 = 1'b1;
           imm_type = `IMM_S;
//           dmem_use = 1'b1;
 //          dmem_write = 1'b1;
       rs_ent = `RS_ENT_LDST;
        end
        `RV32_BRANCH : begin
           uses_rs2 = 1'b1;
           //branch_taken_unkilled = cmp_true;
           src_b_sel = `SRC_B_RS2;
           case (funct3)
             `RV32_FUNCT3_BEQ : alu_op = `ALU_OP_SEQ;
             `RV32_FUNCT3_BNE : alu_op = `ALU_OP_SNE;
             `RV32_FUNCT3_BLT : alu_op = `ALU_OP_SLT;
             `RV32_FUNCT3_BLTU : alu_op = `ALU_OP_SLTU;
             `RV32_FUNCT3_BGE : alu_op = `ALU_OP_SGE;
             `RV32_FUNCT3_BGEU : alu_op = `ALU_OP_SGEU;
             default : illegal_instruction = 1'b1;
           endcase // case (funct3)
       rs_ent = `RS_ENT_BRANCH;
        end
        `RV32_JAL : begin
       //           jal_unkilled = 1'b1;
           uses_rs1 = 1'b0;
           src_a_sel = `SRC_A_PC;
           src_b_sel = `SRC_B_FOUR;
           wr_reg = 1'b1;
       rs_ent = `RS_ENT_JAL;
        end
        `RV32_JALR : begin
           illegal_instruction = (funct3 != 0);
       //           jalr_unkilled = 1'b1;
           src_a_sel = `SRC_A_PC;
           src_b_sel = `SRC_B_FOUR;
           wr_reg = 1'b1;
       rs_ent = `RS_ENT_JALR;
        end

fence命令の実装がコメントアウトされている。

    /*
        `RV32_MISC_MEM : begin
           case (funct3)
             `RV32_FUNCT3_FENCE : begin
                if ((inst[31:28] == 0) && (rs1 == 0) && (reg_to_wr_DX == 0))
                  ; // most fences are no-ops
                else
                  illegal_instruction = 1'b1;
             end
             `RV32_FUNCT3_FENCE_I : begin
                if ((inst[31:20] == 0) && (rs1 == 0) && (reg_to_wr_DX == 0))
                  fence_i = 1'b1;
                else
                  illegal_instruction = 1'b1;
             end
             default : illegal_instruction = 1'b1;
           endcase // case (funct3)
        end
     */
        `RV32_OP_IMM : begin
           alu_op = alu_op_arith;
           wr_reg = 1'b1;
        end
        `RV32_OP  : begin
           uses_rs2 = 1'b1;
           src_b_sel = `SRC_B_RS2;
           alu_op = alu_op_arith;
           wr_reg = 1'b1;
           if (funct7 == `RV32_FUNCT7_MUL_DIV) begin
//              uses_md_unkilled = 1'b1;
          rs_ent = rs_ent_md;
//              wb_src_sel_DX = `WB_SRC_MD;
           end
        end

System命令(CSR)の実装がコメントアウトされている。

    /*
        `RV32_SYSTEM : begin
           wb_src_sel_DX = `WB_SRC_CSR;
           wr_reg = (funct3 != `RV32_FUNCT3_PRIV);
           case (funct3)
             `RV32_FUNCT3_PRIV : begin
                if ((rs1 == 0) && (reg_to_wr_DX == 0)) begin
                   case (funct12)
                     `RV32_FUNCT12_ECALL : ecall = 1'b1;
                     `RV32_FUNCT12_EBREAK : ebreak = 1'b1;
                     `RV32_FUNCT12_ERET : begin
                        if (prv == 0)
                          illegal_instruction = 1'b1;
                        else
                          eret_unkilled = 1'b1;
                     end
                     default : illegal_instruction = 1'b1;
                   endcase // case (funct12)
                end // if ((rs1 == 0) && (reg_to_wr_DX == 0))
             end // case: `RV32_FUNCT3_PRIV
             `RV32_FUNCT3_CSRRW : csr_cmd = (rs1 == 0) ? `CSR_READ : `CSR_WRITE;
             `RV32_FUNCT3_CSRRS : csr_cmd = (rs1 == 0) ? `CSR_READ : `CSR_SET;
             `RV32_FUNCT3_CSRRC : csr_cmd = (rs1 == 0) ? `CSR_READ : `CSR_CLEAR;
             `RV32_FUNCT3_CSRRWI : csr_cmd = (rs1 == 0) ? `CSR_READ : `CSR_WRITE;
             `RV32_FUNCT3_CSRRSI : csr_cmd = (rs1 == 0) ? `CSR_READ : `CSR_SET;
             `RV32_FUNCT3_CSRRCI : csr_cmd = (rs1 == 0) ? `CSR_READ : `CSR_CLEAR;
             default : illegal_instruction = 1'b1;
           endcase // case (funct3)
        end
     */
        `RV32_AUIPC : begin
           uses_rs1 = 1'b0;
           src_a_sel = `SRC_A_PC;
           imm_type = `IMM_U;
           wr_reg = 1'b1;
        end
        `RV32_LUI : begin
           uses_rs1 = 1'b0;
           src_a_sel = `SRC_A_ZERO;
           imm_type = `IMM_U;
           wr_reg = 1'b1;
        end
        default : begin
           illegal_instruction = 1'b1;
        end
      endcase // case (opcode)
   end // always @ (*)

   assign add_or_sub = ((opcode == `RV32_OP) && (funct7[5])) ? `ALU_OP_SUB : `ALU_OP_ADD;
   assign srl_or_sra = (funct7[5]) ? `ALU_OP_SRA : `ALU_OP_SRL;

以下は組み合わせ回路

   always @(*) begin
      case (funct3)
        `RV32_FUNCT3_ADD_SUB : alu_op_arith = add_or_sub;
        `RV32_FUNCT3_SLL : alu_op_arith = `ALU_OP_SLL;
        `RV32_FUNCT3_SLT : alu_op_arith = `ALU_OP_SLT;
        `RV32_FUNCT3_SLTU : alu_op_arith = `ALU_OP_SLTU;
        `RV32_FUNCT3_XOR : alu_op_arith = `ALU_OP_XOR;
        `RV32_FUNCT3_SRA_SRL : alu_op_arith = srl_or_sra;
        `RV32_FUNCT3_OR : alu_op_arith = `ALU_OP_OR;
        `RV32_FUNCT3_AND : alu_op_arith = `ALU_OP_AND;
        default : alu_op_arith = `ALU_OP_ADD;
      endcase // case (funct3)
   end // always @ begin


   //assign md_req_valid = uses_md;
   assign rs_ent_md = (
               (funct3 == `RV32_FUNCT3_MUL) ||
               (funct3 == `RV32_FUNCT3_MULH) ||
               (funct3 == `RV32_FUNCT3_MULHSU) ||
               (funct3 == `RV32_FUNCT3_MULHU)
               ) ? `RS_ENT_MUL : `RS_ENT_DIV;

以下は組み合わせ回路

   always @(*) begin
      md_req_op = `MD_OP_MUL;
      md_req_in_1_signed = 0;
      md_req_in_2_signed = 0;
      md_req_out_sel = `MD_OUT_LO;
      case (funct3)
        `RV32_FUNCT3_MUL : begin
        end
        `RV32_FUNCT3_MULH : begin
           md_req_in_1_signed = 1;
           md_req_in_2_signed = 1;
           md_req_out_sel = `MD_OUT_HI;
        end
        `RV32_FUNCT3_MULHSU : begin
           md_req_in_1_signed = 1;
           md_req_out_sel = `MD_OUT_HI;
        end
        `RV32_FUNCT3_MULHU : begin
           md_req_out_sel = `MD_OUT_HI;
        end
        `RV32_FUNCT3_DIV : begin
           md_req_op = `MD_OP_DIV;
           md_req_in_1_signed = 1;
           md_req_in_2_signed = 1;
        end
        `RV32_FUNCT3_DIVU : begin
           md_req_op = `MD_OP_DIV;
        end
        `RV32_FUNCT3_REM : begin
           md_req_op = `MD_OP_REM;
           md_req_in_1_signed = 1;
           md_req_in_2_signed = 1;
           md_req_out_sel = `MD_OUT_REM;
        end
        `RV32_FUNCT3_REMU : begin
           md_req_op = `MD_OP_REM;
           md_req_out_sel = `MD_OUT_REM;
        end
      endcase
   end


endmodule // decoder
`default_nettype wire
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0