diff options
Diffstat (limited to 'rtl/src/control_unit.v')
-rw-r--r-- | rtl/src/control_unit.v | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/rtl/src/control_unit.v b/rtl/src/control_unit.v new file mode 100644 index 0000000..28f37d9 --- /dev/null +++ b/rtl/src/control_unit.v @@ -0,0 +1,207 @@ +module control_unit ( + input clk, + input rstn, + + input [31:0] instr, + input alu_zero, + + output reg [2:0] imm_src, + output pc_we, + + output reg mem_addr_src, + output reg mem_we, + + output reg instr_we, + + output reg rf_we, + output [4:0] ra1, ra2, wa3, + + output reg [2:0] alu_a_src, + output reg [1:0] alu_b_src, + output [3:0] alu_op, + + output reg [1:0] result_src +); + +`include "include/consts.vh" + +wire [6:0] opcode; +wire [2:0] funct3; +wire [6:0] funct7; + +reg branch; +reg pc_update; +reg alu_ctrl; + +assign opcode = instr[6:0]; +assign funct3 = instr[14:12]; +assign funct7 = instr[31:25]; + +assign ra1 = instr[19:15]; +assign ra2 = instr[24:20]; +assign wa3 = instr[11:7]; + +assign pc_we = ((alu_zero ^ funct3[0] ^ funct3[2]) & branch) | pc_update; + +reg [3:0] state, next_state; + +alu_op_decode alu_op_decode ( + .opcode(opcode), + .alu_ctrl(alu_ctrl), + .funct3(funct3), + .funct7(funct7), + .alu_op(alu_op) +); + +always @ (*) begin + case (opcode) + OPCODE_REG: imm_src = INSTR_FORMAT_R; // ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND + OPCODE_IMM: imm_src = INSTR_FORMAT_I; // ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI + OPCODE_LOAD: imm_src = INSTR_FORMAT_I; // LB, LH, LW, LBU, LHU + OPCODE_JALR: imm_src = INSTR_FORMAT_I; // JALR + OPCODE_STORE: imm_src = INSTR_FORMAT_S; // SB, SH, SW + OPCODE_BRANCH: imm_src = INSTR_FORMAT_B; // BEQ, BNE, BLT, BGE, BLTU, BGEU + OPCODE_LUI: imm_src = INSTR_FORMAT_U; // LUI + OPCODE_AUIPC: imm_src = INSTR_FORMAT_U; // AUIPC + OPCODE_JAL: imm_src = INSTR_FORMAT_J; // JAL + OPCODE_SYNC: imm_src = INSTR_FORMAT_I; // FENCE + OPCODE_SYS: imm_src = INSTR_FORMAT_I; // ECALL, EBREAK + default: imm_src = INSTR_FORMAT_UNKNOWN; + endcase +end + +always @ (posedge clk or negedge rstn) begin + if (!rstn) state <= STATE_FETCH; + else state <= next_state; +end + +always @ (*) begin + case(state) + STATE_FETCH: next_state = STATE_DECODE; + STATE_DECODE: case(opcode) + OPCODE_LOAD: next_state = STATE_MEM_ADDR; + OPCODE_STORE: next_state = STATE_MEM_ADDR; + OPCODE_REG: next_state = STATE_EXECUTE_R; + OPCODE_IMM: next_state = STATE_EXECUTE_I; + OPCODE_JAL: next_state = STATE_JAL; + OPCODE_JALR: next_state = STATE_JALR; + OPCODE_LUI: next_state = STATE_LUI; + OPCODE_AUIPC: next_state = STATE_AUIPC; + OPCODE_BRANCH: next_state = STATE_BRANCH; + default: next_state = STATE_FETCH; + endcase + STATE_MEM_ADDR: case(opcode) + OPCODE_LOAD: next_state = STATE_MEM_LOAD; + OPCODE_STORE: next_state = STATE_MEM_STORE; + default: next_state = STATE_FETCH; + endcase + STATE_MEM_LOAD: next_state = STATE_MEM_WB; + STATE_MEM_WB: next_state = STATE_FETCH; + STATE_MEM_STORE: next_state = STATE_FETCH; + STATE_EXECUTE_R: next_state = STATE_ALU_WB; + STATE_ALU_WB: next_state = STATE_FETCH; + STATE_EXECUTE_I: next_state = STATE_ALU_WB; + STATE_JAL: next_state = STATE_ALU_WB; + STATE_JALR: next_state = STATE_ALU_WB; + STATE_LUI: next_state = STATE_ALU_WB; + STATE_AUIPC: next_state = STATE_ALU_WB; + STATE_BRANCH: next_state = STATE_FETCH; + default: next_state = STATE_FETCH; + endcase +end + + + +always @ (*) begin + mem_addr_src = MEM_ADDR_SRC_RESULT; + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_RD2_BUF; + alu_ctrl = ALU_CTRL_OP; + result_src = RESULT_SRC_ALU_RESULT; + mem_we = MEM_WE_DISABLE; + rf_we = RF_WE_DISABLE; + instr_we = INSTR_WE_DISABLE; + pc_update = PC_UPDATE_DISABLE; + branch = BRANCH_DISABLE; + case(state) + STATE_FETCH: begin + mem_addr_src = MEM_ADDR_SRC_PC; + alu_a_src = ALU_A_SRC_PC; + alu_b_src = ALU_B_SRC_4; + alu_ctrl = ALU_CTRL_ADD; + result_src = RESULT_SRC_ALU_RESULT; + instr_we = INSTR_WE_ENABLE; + pc_update = PC_UPDATE_ENABLE; + end + STATE_DECODE: begin + alu_a_src = (opcode == OPCODE_JALR) ? ALU_A_SRC_RD1 : ALU_A_SRC_PC_BUF; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_ADD; + end + STATE_MEM_ADDR: begin + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_ADD; + end + STATE_MEM_LOAD: begin + mem_addr_src = MEM_ADDR_SRC_RESULT; + result_src = RESULT_SRC_ALU_RESULT_BUF; + end + STATE_MEM_WB: begin + result_src = RESULT_SRC_DATA_BUF; + rf_we = RF_WE_ENABLE; + end + STATE_MEM_STORE: begin + mem_addr_src = MEM_ADDR_SRC_RESULT; + result_src = RESULT_SRC_ALU_RESULT_BUF; + mem_we = MEM_WE_ENABLE; + end + STATE_EXECUTE_R: begin + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_RD2_BUF; + alu_ctrl = ALU_CTRL_OP; + end + STATE_ALU_WB: begin + result_src = RESULT_SRC_ALU_RESULT_BUF; + rf_we = RF_WE_ENABLE; + end + STATE_EXECUTE_I: begin + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_OP; + end + STATE_JAL: begin + alu_a_src = ALU_A_SRC_PC_BUF; + alu_b_src = ALU_B_SRC_4; + alu_ctrl = ALU_CTRL_ADD; + result_src = RESULT_SRC_ALU_RESULT_BUF; + pc_update = PC_UPDATE_ENABLE; + end + STATE_JALR: begin + alu_a_src = ALU_A_SRC_PC_BUF; + alu_b_src = ALU_B_SRC_4; + alu_ctrl = ALU_CTRL_ADD; + result_src = RESULT_SRC_ALU_RESULT_BUF; + pc_update = PC_UPDATE_ENABLE; + end + STATE_LUI: begin + alu_a_src = ALU_A_SRC_0; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_ADD; + end + STATE_AUIPC: begin + alu_a_src = ALU_A_SRC_PC_BUF; + alu_b_src = ALU_B_SRC_IMM; + alu_ctrl = ALU_CTRL_ADD; + end + STATE_BRANCH: begin + alu_a_src = ALU_A_SRC_RD1_BUF; + alu_b_src = ALU_B_SRC_RD2_BUF; + alu_ctrl = ALU_CTRL_OP; + result_src = RESULT_SRC_ALU_RESULT_BUF; + branch = BRANCH_ENABLE; + end + endcase +end + +endmodule |