import cpu_types::* ; module instruction_decoder( input [31:0] instruction, // whether to write to to memory (write enabled) // either from alu or pc+4 output reg store_memory, // whether to load memory to rd output reg load_memory, output memory_mask_t memory_mask, output reg memory_sign_extension, // put alu_jump to alu if conditional_jump // // if unconditional_jump, source of pd is alu // elsif conditional_jump, source of pd is pd + imm // else source of pd is pd + 4 // // if store pd => rd = pd + 4 // inputs for alu, in case instruction is not conditional_jump output [2:0] alu_reg_op, // the operation selection for alu output reg alu_reg_add_one, // whether to add one to rs2 (may be used for two's complement) output reg alu_reg_negate, // whether to negate rs2 (may be used for two's complement) output alu_reg_signed, // whether the operation for alu is signed output reg load_pc, // should load pc to alu #1 output reg store_pc, // should store pc + 4 to memory output reg unconditional_jump, // jump, always. To alu output. // jump if alu zero_flag, to pc + imm output reg conditional_jump, // should jump if alu zero_flag correct output reg [2:0] alu_jump_op, // operation for alu for conditional jumps output reg alu_jump_negate, output reg alu_jump_add_one, // add one for conditional jumps output reg jump_negate_zero, // whether to negate zero flag from alu // whether to use immediate instead of rs2. // if false, immediate still may be added to second operand output reg use_immediate, output reg load_immediate, output reg [31:0] immediate, // inputs to register file output reg [4:0] reg_rs1, output reg [4:0] reg_rs2, output reg [4:0] reg_rd, output reg reg_we, output reg ebreak ); typedef enum bit[2:0] {Unknown, R, I, S, SB, U, UJ} instruction_type_type; instruction_type_type instruction_type; wire [2:0] funct3; wire [6:0] funct7; wire [6:0] opcode; assign funct3 = instruction[14:12]; assign funct7 = instruction[31:25]; assign opcode = instruction[6:0]; // load memory mask/size always_comb begin memory_mask = MEM_WORD; memory_sign_extension = 1'b0; case (funct3) 3'b000: begin memory_mask = MEM_BYTE; // sign extends memory_sign_extension = 1'b1; end 3'b001: begin memory_mask = MEM_HALFWORD; // sign extends memory_sign_extension = 1'b1; end 3'b010: begin memory_mask = MEM_WORD; // sign extends memory_sign_extension = 1'b1; end 3'b100: begin memory_mask = MEM_BYTE; // zero extends end 3'b101: begin memory_mask = MEM_HALFWORD; // zero extends end default : ; endcase end // immediate load always_comb begin case (instruction_type) // beware, slli, srai and srli, are I, but have funct7 I : immediate = {{20{instruction[31]}}, instruction[31:20]}; S : immediate = {{20{instruction[31]}}, instruction[31:25], instruction[11:7]}; SB : immediate = {{20{instruction[31]}}, instruction[7], instruction[30:25], instruction[11:8], 1'b0}; U : immediate = {instruction[31:12], 12'b0}; UJ : immediate = {{12{instruction[31]}}, instruction[19:12], instruction[20], instruction[30:21], 1'b0}; default: immediate = 32'b0; endcase end // alu subtraction always_comb begin alu_reg_add_one = 1'b0; alu_reg_negate = 1'b0; if (instruction_type == R && funct3 == 0 && funct7[5] == 1) begin // subtraction alu_reg_add_one = 1'b1; alu_reg_negate = 1'b1; end end // immediate instructions always_comb begin if (instruction_type == I || instruction_type == U || instruction_type == UJ || instruction_type == S) begin use_immediate = 1'b1; end else begin use_immediate = 1'b0; end end // conditional jump alu always_comb begin alu_jump_op = 3'b000; alu_jump_add_one = 1'b0; alu_jump_negate = 1'b0; jump_negate_zero = 1'b0; case (funct3) 3'b000 : begin // beq // subtraction alu_jump_op = 3'b000; alu_jump_add_one = 1'b1; alu_jump_negate = 1'b1; end 3'b001 : begin // bne // subtraction alu_jump_op = 3'b000; alu_jump_add_one = 1'b1; alu_jump_negate = 1'b1; jump_negate_zero = 1'b1; end 3'b100 : begin // blt alu_jump_op = 3'b010; jump_negate_zero = 1'b1; // less than 011 end 3'b101 : begin // bge alu_jump_op = 3'b010; end 3'b110 : begin // bltu alu_jump_op = 3'b011; jump_negate_zero = 1'b1; end 3'b111 : begin // bgeu alu_jump_op = 3'b011; end default : ; endcase end assign alu_reg_op = funct3; assign alu_reg_signed = funct7[5]; always_comb begin case (opcode[6:2]) 5'b00000 : instruction_type = I; 5'b00011 : instruction_type = I; // fence 5'b00100 : instruction_type = I; 5'b00101 : instruction_type = U; // auipc 5'b00110 : instruction_type = I; 5'b01000 : instruction_type = S; 5'b01100 : instruction_type = R; 5'b01101 : instruction_type = U; // lui 5'b01110 : instruction_type = R; 5'b11000 : instruction_type = SB; 5'b11001 : instruction_type = I; // jalr 5'b11011 : instruction_type = UJ; // jal 5'b11100 : instruction_type = I; default : instruction_type = Unknown; endcase; end; always_comb begin store_memory = 1'b0; load_memory = 1'b0; load_pc = 1'b0; store_pc = 1'b0; reg_we = 1'b1; conditional_jump = 1'b0; unconditional_jump = 1'b0; load_immediate = 1'b0; ebreak = 1'b0; reg_rs1 = instruction[19:15]; reg_rs2 = instruction[24:20]; reg_rd = instruction[11:7]; // TODO: multiplication // NOTE: ecall, ebreak, CSRRW, CSRRS, SCRRC, CSRRWI, CSRRSI, CSRRCI unsupported case (opcode[6:2]) 5'b01100 : reg_we = 1'b1; 5'b00100 : reg_we = 1'b1; 5'b00000 : load_memory = 1'b1; 5'b01000 : begin store_memory = 1'b1; reg_we = 1'b0; end 5'b11000 : begin // branches conditional_jump = 1'b1; reg_we = 1'b0; end 5'b11011 : begin // jump and link load_pc = 1'b1; // relative to pc unconditional_jump = 1'b1; // jump store_pc = 1'b1; // link #1 reg_we = 1'b1; // link #2 end 5'b11001 : begin // jump and link register unconditional_jump = 1'b1; // jump store_pc = 1'b1; // link #1 reg_we = 1'b1; // link #2 end 5'b01101 : begin // load upper imm reg_we = 1'b1; load_immediate = 1'b1; reg_rs1 = 5'b0; end 5'b00101 : begin // add upper imm to PC load_pc = 1'b1; reg_we = 1'b1; end 5'b11100 : begin if (funct3 == 3'b0) ebreak = 1'b1; end default : ; endcase; end; endmodule