aboutsummaryrefslogtreecommitdiff
path: root/rtl/src/control_unit.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/src/control_unit.v')
-rw-r--r--rtl/src/control_unit.v207
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