<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