aboutsummaryrefslogtreecommitdiff
path: root/rtl/src
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/src')
-rw-r--r--rtl/src/alu.v47
-rw-r--r--rtl/src/alu_a_src_mux.v25
-rw-r--r--rtl/src/alu_b_src_mux.v21
-rw-r--r--rtl/src/alu_op_decode.v43
-rw-r--r--rtl/src/alu_result_reg.v14
-rw-r--r--rtl/src/arithmetic_unit.v27
-rw-r--r--rtl/src/clock_divider.v29
-rw-r--r--rtl/src/control_unit.v207
-rw-r--r--rtl/src/cpu.v172
-rw-r--r--rtl/src/data_reg.v14
-rw-r--r--rtl/src/immediate_extend.v22
-rw-r--r--rtl/src/instruction_reg.v20
-rw-r--r--rtl/src/io.v30
-rw-r--r--rtl/src/logic_unit.v21
-rw-r--r--rtl/src/mem_addr_src_mux.v20
-rw-r--r--rtl/src/memory_interface.v84
-rw-r--r--rtl/src/pc_reg.v18
-rw-r--r--rtl/src/ram.v23
-rw-r--r--rtl/src/register_file.v93
-rw-r--r--rtl/src/register_file_reg.v22
-rw-r--r--rtl/src/reset_synchronizer.v16
-rw-r--r--rtl/src/result_mux.v22
-rw-r--r--rtl/src/rom.v25
-rw-r--r--rtl/src/shift_unit.v21
-rw-r--r--rtl/src/top.v38
25 files changed, 1074 insertions, 0 deletions
diff --git a/rtl/src/alu.v b/rtl/src/alu.v
new file mode 100644
index 0000000..8a265ee
--- /dev/null
+++ b/rtl/src/alu.v
@@ -0,0 +1,47 @@
+module alu (
+ input [31:0] a,
+ input [31:0] b,
+
+ input [3:0] op,
+
+ output reg [31:0] result,
+ output zero
+);
+
+wire [31:0] arithmetic_result, logic_result, shift_result;
+
+arithmetic_unit au (
+ .a(a),
+ .b(b),
+ .op(op[1:0]),
+ .result(arithmetic_result)
+);
+
+logic_unit lu (
+ .a(a),
+ .b(b),
+ .op(op[1:0]),
+ .result(logic_result)
+);
+
+shift_unit su (
+ .a(a),
+ .b(b[4:0]),
+ .op(op[1:0]),
+ .result(shift_result)
+);
+
+`include "include/consts.vh"
+
+always @ (*) begin
+ case (op[3:2])
+ ALU_OP_ARITHMETIC: result = arithmetic_result; // ARITHMETIC
+ ALU_OP_LOGIC: result = logic_result; // LOGIC
+ ALU_OP_SHIFT: result = shift_result; // SHIFT
+ default: result = 31'b0;
+ endcase
+end
+
+assign zero = result == 32'b0;
+
+endmodule
diff --git a/rtl/src/alu_a_src_mux.v b/rtl/src/alu_a_src_mux.v
new file mode 100644
index 0000000..fef701b
--- /dev/null
+++ b/rtl/src/alu_a_src_mux.v
@@ -0,0 +1,25 @@
+module alu_a_src_mux (
+ input [31:0] src_pc,
+ input [31:0] src_pc_buf,
+ input [31:0] src_rd1,
+ input [31:0] src_rd1_buf,
+
+ input [2:0] alu_a_src,
+
+ output reg [31:0] alu_a
+);
+
+`include "include/consts.vh"
+
+always @(*) begin
+ case (alu_a_src)
+ ALU_A_SRC_PC: alu_a = src_pc;
+ ALU_A_SRC_PC_BUF: alu_a = src_pc_buf;
+ ALU_A_SRC_RD1: alu_a = src_rd1;
+ ALU_A_SRC_RD1_BUF: alu_a = src_rd1_buf;
+ ALU_A_SRC_0: alu_a = 32'b0;
+ default: alu_a = 32'b0;
+ endcase
+end
+
+endmodule
diff --git a/rtl/src/alu_b_src_mux.v b/rtl/src/alu_b_src_mux.v
new file mode 100644
index 0000000..5932f9e
--- /dev/null
+++ b/rtl/src/alu_b_src_mux.v
@@ -0,0 +1,21 @@
+module alu_b_src_mux (
+ input [31:0] src_rd2_buf,
+ input [31:0] src_imm,
+
+ input [1:0] alu_b_src,
+
+ output reg [31:0] alu_b
+);
+
+`include "include/consts.vh"
+
+always @(*) begin
+ case (alu_b_src)
+ ALU_B_SRC_RD2_BUF: alu_b = src_rd2_buf;
+ ALU_B_SRC_IMM: alu_b = src_imm;
+ ALU_B_SRC_4: alu_b = 32'h4;
+ default: alu_b = 32'b0;
+ endcase
+end
+
+endmodule
diff --git a/rtl/src/alu_op_decode.v b/rtl/src/alu_op_decode.v
new file mode 100644
index 0000000..4523255
--- /dev/null
+++ b/rtl/src/alu_op_decode.v
@@ -0,0 +1,43 @@
+module alu_op_decode (
+ input [6:0] opcode,
+ input [2:0] funct3,
+ input [6:0] funct7,
+
+ input alu_ctrl,
+
+ output reg [3:0] alu_op
+);
+
+`include "include/consts.vh"
+
+always @ (*) begin
+ if (alu_ctrl == ALU_CTRL_ADD) begin
+ alu_op = ALU_OP_ADD;
+ end else if (opcode == OPCODE_REG || opcode == OPCODE_IMM) begin
+ case (funct3)
+ FUNCT3_ALU_ADD_SUB: alu_op = (opcode == OPCODE_REG && funct7 == FUNCT7_ALU_SUB) ? ALU_OP_SUB : ALU_OP_ADD;
+ FUNCT3_ALU_SLL: alu_op = ALU_OP_SLL;
+ FUNCT3_ALU_SLT: alu_op = ALU_OP_SLT;
+ FUNCT3_ALU_SLTU: alu_op = ALU_OP_SLTU;
+ FUNCT3_ALU_XOR: alu_op = ALU_OP_XOR;
+ FUNCT3_ALU_SR: alu_op = funct7 == FUNCT7_ALU_SRL ? ALU_OP_SRL : ALU_OP_SRA;
+ FUNCT3_ALU_OR: alu_op = ALU_OP_OR;
+ FUNCT3_ALU_AND: alu_op = ALU_OP_AND;
+ default: alu_op = ALU_OP_ADD;
+ endcase
+ end else if (opcode == OPCODE_BRANCH) begin
+ case (funct3)
+ FUNCT3_BRANCH_BEQ: alu_op = ALU_OP_SUB;
+ FUNCT3_BRANCH_BNE: alu_op = ALU_OP_SUB;
+ FUNCT3_BRANCH_BLT: alu_op = ALU_OP_SLT;
+ FUNCT3_BRANCH_BGE: alu_op = ALU_OP_SLT;
+ FUNCT3_BRANCH_BLTU: alu_op = ALU_OP_SLTU;
+ FUNCT3_BRANCH_BGEU: alu_op = ALU_OP_SLTU;
+ default: alu_op = ALU_OP_ADD;
+ endcase
+ end else begin
+ alu_op = ALU_OP_ADD;
+ end
+end
+
+endmodule
diff --git a/rtl/src/alu_result_reg.v b/rtl/src/alu_result_reg.v
new file mode 100644
index 0000000..cece9e4
--- /dev/null
+++ b/rtl/src/alu_result_reg.v
@@ -0,0 +1,14 @@
+module alu_result_reg (
+ input clk,
+ input rstn,
+
+ input [31:0] alu_result_in,
+ output reg [31:0] alu_result_buf
+);
+
+always @ (posedge clk or negedge rstn) begin
+ if (!rstn) alu_result_buf <= 32'b0;
+ else alu_result_buf <= alu_result_in;
+end
+
+endmodule
diff --git a/rtl/src/arithmetic_unit.v b/rtl/src/arithmetic_unit.v
new file mode 100644
index 0000000..1a2282b
--- /dev/null
+++ b/rtl/src/arithmetic_unit.v
@@ -0,0 +1,27 @@
+module arithmetic_unit (
+ input [31:0] a,
+ input [31:0] b,
+
+ input [1:0] op,
+
+ output reg [31:0] result
+);
+
+`include "include/consts.vh"
+
+wire signed [31:0] a_signed, b_signed;
+
+assign a_signed = a;
+assign b_signed = b;
+
+always @ (*) begin
+ case (op)
+ ARITHMETIC_OP_ADD: result = a + b; // ADD
+ ARITHMETIC_OP_SUB: result = a - b; // SUB
+ ARITHMETIC_OP_SLT: result = { {31{1'b0}}, a_signed < b_signed }; // SLT
+ ARITHMETIC_OP_SLTU: result = { {31{1'b0}}, a < b }; // SLTU
+ default: result = 32'b0;
+ endcase
+end
+
+endmodule
diff --git a/rtl/src/clock_divider.v b/rtl/src/clock_divider.v
new file mode 100644
index 0000000..a63e943
--- /dev/null
+++ b/rtl/src/clock_divider.v
@@ -0,0 +1,29 @@
+module clock_divider #(
+ parameter N = 2
+)(
+ input clk,
+ input rstn,
+
+ output reg clk_div
+);
+
+reg [31:0] counter = 0;
+
+always @(posedge clk or negedge rstn) begin
+ if (!rstn) begin
+ counter <= 0;
+ clk_div <= 0;
+ end else begin
+ if (counter == (N-1)/2) begin
+ clk_div <= ~clk_div;
+ counter <= counter + 1;
+ end else if (counter >= (N-1)) begin
+ clk_div <= ~clk_div;
+ counter <= 0;
+ end else begin
+ counter <= counter + 1;
+ end
+ end
+end
+
+endmodule
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
diff --git a/rtl/src/cpu.v b/rtl/src/cpu.v
new file mode 100644
index 0000000..a3b94ff
--- /dev/null
+++ b/rtl/src/cpu.v
@@ -0,0 +1,172 @@
+module cpu (
+ input clk,
+ input rstn,
+ input [31:0] io_in,
+ output [31:0] io_out
+);
+
+
+wire [31:0] pc, pc_buf;
+wire pc_we;
+
+wire [31:0] mem_addr;
+wire mem_addr_src;
+wire [31:0] mem_rd;
+wire mem_we;
+
+wire instr_we;
+wire [31:0] instr;
+
+wire [31:0] imm;
+wire [2:0] imm_src;
+
+wire [31:0] data_buf;
+
+wire rf_we;
+wire [4:0] ra1, ra2, wa3;
+wire [31:0] rd1, rd2;
+wire [31:0] rd1_buf, rd2_buf;
+
+wire [31:0] alu_a, alu_b;
+wire [2:0] alu_a_src;
+wire [1:0] alu_b_src;
+wire [3:0] alu_op;
+wire [31:0] alu_result;
+wire alu_zero;
+wire [31:0] alu_result_buf;
+
+wire [1:0] result_src;
+wire [31:0] result;
+
+
+control_unit control_unit (
+ .clk(clk),
+ .rstn(rstn),
+ .instr(instr),
+ .imm_src(imm_src),
+ .alu_zero(alu_zero),
+ .pc_we(pc_we),
+ .mem_addr_src(mem_addr_src),
+ .mem_we(mem_we),
+ .instr_we(instr_we),
+ .result_src(result_src),
+ .alu_op(alu_op),
+ .alu_a_src(alu_a_src),
+ .alu_b_src(alu_b_src),
+ .rf_we(rf_we),
+ .ra1(ra1),
+ .ra2(ra2),
+ .wa3(wa3)
+);
+
+
+pc_reg pc_reg (
+ .clk(clk),
+ .rstn(rstn),
+ .we(pc_we),
+ .pc_in(result),
+ .pc(pc)
+);
+
+mem_addr_src_mux mem_addr_src_mux (
+ .src_pc(pc),
+ .src_result(result),
+ .mem_addr_src(mem_addr_src),
+ .mem_addr(mem_addr)
+);
+
+memory_interface memory_interface (
+ .clk(clk),
+ .rstn(rstn),
+ .we(mem_we),
+ .addr(mem_addr),
+ .rd(mem_rd),
+ .wd(rd2_buf),
+ .io_in(io_in),
+ .io_out(io_out)
+);
+
+instruction_reg instruction_reg (
+ .clk(clk),
+ .rstn(rstn),
+ .we(instr_we),
+ .pc_in(pc),
+ .instr_in(mem_rd),
+ .pc_buf(pc_buf),
+ .instr(instr)
+);
+
+data_reg data_reg (
+ .clk(clk),
+ .rstn(rstn),
+ .data_in(mem_rd),
+ .data_buf(data_buf)
+);
+
+immediate_extend immediate_extend (
+ .instr(instr),
+ .imm_src(imm_src),
+ .imm(imm)
+);
+
+register_file register_file (
+ .clk(clk),
+ .rstn(rstn),
+ .we(rf_we),
+ .ra1(ra1),
+ .ra2(ra2),
+ .wa3(wa3),
+ .rd1(rd1),
+ .rd2(rd2),
+ .wd3(result)
+);
+
+register_file_reg register_file_reg (
+ .clk(clk),
+ .rstn(rstn),
+ .rd1_in(rd1),
+ .rd2_in(rd2),
+ .rd1_buf(rd1_buf),
+ .rd2_buf(rd2_buf)
+);
+
+alu_a_src_mux alu_a_src_mux(
+ .src_pc(pc),
+ .src_pc_buf(pc_buf),
+ .src_rd1(rd1),
+ .src_rd1_buf(rd1_buf),
+ .alu_a_src(alu_a_src),
+ .alu_a(alu_a)
+);
+
+alu_b_src_mux alu_b_src_mux (
+ .src_rd2_buf(rd2_buf),
+ .src_imm(imm),
+ .alu_b_src(alu_b_src),
+ .alu_b(alu_b)
+);
+
+alu alu (
+ .a(alu_a),
+ .b(alu_b),
+ .op(alu_op),
+ .result(alu_result),
+ .zero(alu_zero)
+);
+
+alu_result_reg alu_result_reg (
+ .clk(clk),
+ .rstn(rstn),
+ .alu_result_in(alu_result),
+ .alu_result_buf(alu_result_buf)
+);
+
+result_mux result_mux (
+ .src_alu_result(alu_result),
+ .src_alu_result_buf(alu_result_buf),
+ .src_data_buf(data_buf),
+ .result_src(result_src),
+ .result(result)
+);
+
+endmodule
diff --git a/rtl/src/data_reg.v b/rtl/src/data_reg.v
new file mode 100644
index 0000000..473d50a
--- /dev/null
+++ b/rtl/src/data_reg.v
@@ -0,0 +1,14 @@
+module data_reg (
+ input clk,
+ input rstn,
+
+ input [31:0] data_in,
+ output reg [31:0] data_buf
+);
+
+always @ (posedge clk or negedge rstn) begin
+ if (!rstn) data_buf <= 32'b0;
+ else data_buf <= data_in;
+end
+
+endmodule
diff --git a/rtl/src/immediate_extend.v b/rtl/src/immediate_extend.v
new file mode 100644
index 0000000..14a9a33
--- /dev/null
+++ b/rtl/src/immediate_extend.v
@@ -0,0 +1,22 @@
+module immediate_extend (
+ input [31:0] instr,
+ input [2:0] imm_src,
+
+ output reg [31:0] imm
+);
+
+`include "include/consts.vh"
+
+always @ (*) begin
+ case (imm_src)
+ INSTR_FORMAT_I: imm = { {21{instr[31]}}, instr[30:20] }; // I
+ INSTR_FORMAT_S: imm = { {21{instr[31]}}, instr[30:25], instr[11:7] }; // S
+ INSTR_FORMAT_B: imm = { {20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0 }; // B
+ INSTR_FORMAT_U: imm = { instr[31:12], 12'b0 }; // U
+ INSTR_FORMAT_J: imm = { {12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 }; // J
+ default: imm = 32'b0; // Unknown
+ endcase
+end
+
+
+endmodule
diff --git a/rtl/src/instruction_reg.v b/rtl/src/instruction_reg.v
new file mode 100644
index 0000000..d98ab6d
--- /dev/null
+++ b/rtl/src/instruction_reg.v
@@ -0,0 +1,20 @@
+module instruction_reg (
+ input clk,
+ input rstn,
+
+ input we,
+ input [31:0] pc_in, instr_in,
+ output reg [31:0] pc_buf, instr
+);
+
+always @ (posedge clk or negedge rstn) begin
+ if (!rstn) begin
+ pc_buf <= 32'b0;
+ instr <= 32'b0;
+ end else if (we) begin
+ pc_buf <= pc_in;
+ instr <= instr_in;
+ end
+end
+
+endmodule
diff --git a/rtl/src/io.v b/rtl/src/io.v
new file mode 100644
index 0000000..f53062b
--- /dev/null
+++ b/rtl/src/io.v
@@ -0,0 +1,30 @@
+module io (
+ input clk,
+ input rstn,
+
+ input we,
+ input [31:0] addr,
+ input [31:0] wd,
+
+ output reg [31:0] rd,
+
+ input [31:0] io_in,
+ output reg [31:0] io_out
+);
+
+`include "include/consts.vh"
+
+always @ (posedge clk or negedge rstn) begin
+ if (!rstn) begin
+ io_out <= 32'b0;
+ end else if (we && addr == 32'h0000_0004) begin
+ io_out <= wd;
+ end
+end
+
+always @ (posedge clk) begin
+ if (addr == 32'h0000_0000) rd <= io_in;
+ else if (addr == 32'h0000_0004) rd <= io_out;
+ else rd <= 32'b0;
+end
+endmodule \ No newline at end of file
diff --git a/rtl/src/logic_unit.v b/rtl/src/logic_unit.v
new file mode 100644
index 0000000..8d8b31d
--- /dev/null
+++ b/rtl/src/logic_unit.v
@@ -0,0 +1,21 @@
+module logic_unit (
+ input [31:0] a,
+ input [31:0] b,
+
+ input [1:0] op,
+
+ output reg [31:0] result
+);
+
+`include "include/consts.vh"
+
+always @ (*) begin
+ case (op)
+ LOGIC_OP_AND: result = a & b; // AND
+ LOGIC_OP_OR: result = a | b; // OR
+ LOGIC_OP_XOR: result = a ^ b; // XOR
+ default: result = 32'b0;
+ endcase
+end
+
+endmodule
diff --git a/rtl/src/mem_addr_src_mux.v b/rtl/src/mem_addr_src_mux.v
new file mode 100644
index 0000000..1f34fe1
--- /dev/null
+++ b/rtl/src/mem_addr_src_mux.v
@@ -0,0 +1,20 @@
+module mem_addr_src_mux (
+ input [31:0] src_pc,
+ input [31:0] src_result,
+
+ input mem_addr_src,
+
+ output reg [31:0] mem_addr
+);
+
+`include "include/consts.vh"
+
+always @(*) begin
+ case (mem_addr_src)
+ MEM_ADDR_SRC_PC: mem_addr = src_pc;
+ MEM_ADDR_SRC_RESULT: mem_addr = src_result;
+ default: mem_addr = 32'b0;
+ endcase
+end
+
+endmodule
diff --git a/rtl/src/memory_interface.v b/rtl/src/memory_interface.v
new file mode 100644
index 0000000..09f05cb
--- /dev/null
+++ b/rtl/src/memory_interface.v
@@ -0,0 +1,84 @@
+module memory_interface (
+ input clk,
+ input rstn,
+
+ input we,
+ input [31:0] addr,
+ input [31:0] wd,
+
+ output reg [31:0] rd,
+
+ input [31:0] io_in,
+ output [31:0] io_out
+);
+
+`include "include/consts.vh"
+
+reg ram_we;
+reg io_we;
+wire [31:0] ram_rd, rom_rd;
+reg [31:0] rel_addr;
+
+ram #(.N(32), .SIZE(1024)) ram(
+ .clk(clk),
+ .rstn(rstn),
+ .we(ram_we),
+ .addr(rel_addr),
+ .data_read(ram_rd),
+ .data_write(wd)
+);
+
+rom #(.N(32), .SIZE(1024), .ROM_FILE("../../build/rom.hex")) rom(
+ .clk(clk),
+ .addr(rel_addr),
+ .data_read(rom_rd)
+);
+
+io io(
+ .clk(clk),
+ .rstn(rstn),
+ .we(io_we),
+ .addr(rel_addr),
+ .rd(io_rd),
+ .wd(wd),
+ .io_in(io_in),
+ .io_out(io_out)
+);
+
+
+// 0000 0000 Reserved
+// 0000 FFFF
+//
+// 0001 0000 ROM
+// 000F FFFF
+//
+// 0010 0000 RAM
+// FF0F FFFF
+//
+// FF10 0000 Reserved
+// FFFF FFFF
+
+
+always @ (*) begin
+ rd = 0;
+ rel_addr = 0;
+ ram_we = 0;
+ io_we = 0;
+ if ( addr >= ROM_BEGIN && addr <= ROM_END) begin
+ rd = rom_rd;
+ rel_addr = addr - ROM_BEGIN;
+ end else if (addr >= RAM_BEGIN && addr <= RAM_END) begin
+ ram_we = we;
+ rd = ram_rd;
+ rel_addr = addr - RAM_BEGIN;
+ end else if (addr >= IO_BEGIN && addr <= IO_END) begin
+ io_we = we;
+ rd = io_rd;
+ rel_addr = addr - IO_BEGIN;
+ end else begin
+ rd = 0;
+ rel_addr = 0;
+ end
+end
+
+endmodule
diff --git a/rtl/src/pc_reg.v b/rtl/src/pc_reg.v
new file mode 100644
index 0000000..d8dfbec
--- /dev/null
+++ b/rtl/src/pc_reg.v
@@ -0,0 +1,18 @@
+module pc_reg (
+ input clk,
+ input rstn,
+
+ input we,
+ input [31:0] pc_in,
+
+ output reg [31:0] pc
+);
+
+`include "include/consts.vh"
+
+always @ (posedge clk or negedge rstn) begin
+ if (!rstn) pc <= PC_INITIAL;
+ else if (we) pc <= pc_in;
+end
+
+endmodule
diff --git a/rtl/src/ram.v b/rtl/src/ram.v
new file mode 100644
index 0000000..541096e
--- /dev/null
+++ b/rtl/src/ram.v
@@ -0,0 +1,23 @@
+module ram #(
+ parameter N = 32,
+ parameter SIZE = 1024
+)(
+ input clk,
+ input rstn,
+ input we,
+ input [N-1:0] addr,
+ input [N-1:0] data_write,
+ output reg [N-1:0] data_read
+);
+
+`include "include/log2.vh"
+
+//(* RAM_STYLE="BLOCK" *)
+reg [N-1:0] mem [0:SIZE-1];
+
+always @(posedge clk) begin
+ if (we) mem[addr >> 2] <= data_write;
+ data_read <= mem[addr >> 2];
+end
+
+endmodule
diff --git a/rtl/src/register_file.v b/rtl/src/register_file.v
new file mode 100644
index 0000000..dda44e8
--- /dev/null
+++ b/rtl/src/register_file.v
@@ -0,0 +1,93 @@
+module register_file (
+ input clk,
+ input rstn,
+
+ input we,
+ input [4:0] ra1,
+ input [4:0] ra2,
+ input [4:0] wa3,
+
+ input [31:0] wd3,
+
+ output [31:0] rd1,
+ output [31:0] rd2
+);
+
+reg [31:0] regs[31:1];
+
+// For debugging purposes:
+wire [31:0] reg_x0_zero,
+ reg_x1_ra,
+ reg_x2_sp,
+ reg_x3_gp,
+ reg_x4_tp,
+ reg_x5_t0,
+ reg_x6_t1,
+ reg_x7_t2,
+ reg_x8_s0_fp,
+ reg_x9_s1,
+ reg_x10_a0,
+ reg_x11_a1,
+ reg_x12_a2,
+ reg_x13_a3,
+ reg_x14_a4,
+ reg_x15_a5,
+ reg_x16_a6,
+ reg_x17_a7,
+ reg_x18_s2,
+ reg_x19_s3,
+ reg_x20_s4,
+ reg_x21_s5,
+ reg_x22_s6,
+ reg_x23_s7,
+ reg_x24_s8,
+ reg_x25_s9,
+ reg_x26_s10,
+ reg_x27_s11,
+ reg_x28_t3,
+ reg_x29_t4,
+ reg_x30_t5,
+ reg_x31_t6;
+
+assign reg_x0_zero = 32'b0;
+assign reg_x1_ra = regs[1];
+assign reg_x2_sp = regs[2];
+assign reg_x3_gp = regs[3];
+assign reg_x4_tp = regs[4];
+assign reg_x5_t0 = regs[5];
+assign reg_x6_t1 = regs[6];
+assign reg_x7_t2 = regs[7];
+assign reg_x8_s0_fp = regs[8];
+assign reg_x9_s1 = regs[9];
+assign reg_x10_a0 = regs[10];
+assign reg_x11_a1 = regs[11];
+assign reg_x12_a2 = regs[12];
+assign reg_x13_a3 = regs[13];
+assign reg_x14_a4 = regs[14];
+assign reg_x15_a5 = regs[15];
+assign reg_x16_a6 = regs[16];
+assign reg_x17_a7 = regs[17];
+assign reg_x18_s2 = regs[18];
+assign reg_x19_s3 = regs[19];
+assign reg_x20_s4 = regs[20];
+assign reg_x21_s5 = regs[21];
+assign reg_x22_s6 = regs[22];
+assign reg_x23_s7 = regs[23];
+assign reg_x24_s8 = regs[24];
+assign reg_x25_s9 = regs[25];
+assign reg_x26_s10 = regs[26];
+assign reg_x27_s11 = regs[27];
+assign reg_x28_t3 = regs[28];
+assign reg_x29_t4 = regs[29];
+assign reg_x30_t5 = regs[30];
+assign reg_x31_t6 = regs[31];
+
+
+assign rd1 = ra1 == 0 ? 32'b0 : regs[ra1];
+assign rd2 = ra2 == 0 ? 32'b0 : regs[ra2];
+
+always @ (posedge clk) begin
+ if (we && (wa3 != 0)) regs[wa3] <= wd3;
+end
+
+endmodule
diff --git a/rtl/src/register_file_reg.v b/rtl/src/register_file_reg.v
new file mode 100644
index 0000000..b1bd4fc
--- /dev/null
+++ b/rtl/src/register_file_reg.v
@@ -0,0 +1,22 @@
+module register_file_reg (
+ input clk,
+ input rstn,
+
+ input [31:0] rd1_in,
+ input [31:0] rd2_in,
+
+ output reg [31:0] rd1_buf,
+ output reg [31:0] rd2_buf
+);
+
+always @ (posedge clk or negedge rstn) begin
+ if (!rstn) begin
+ rd1_buf <= 32'b0;
+ rd2_buf <= 32'b0;
+ end else begin
+ rd1_buf <= rd1_in;
+ rd2_buf <= rd2_in;
+ end
+end
+
+endmodule
diff --git a/rtl/src/reset_synchronizer.v b/rtl/src/reset_synchronizer.v
new file mode 100644
index 0000000..dc7a80a
--- /dev/null
+++ b/rtl/src/reset_synchronizer.v
@@ -0,0 +1,16 @@
+module reset_synchronizer (
+ input clk,
+ input rstn_async,
+ output rstn
+);
+
+reg [1:0] rstn_sync;
+
+always @(posedge clk or negedge rstn_async) begin
+ if (!rstn_async) rstn_sync <= 2'b00;
+ else rstn_sync <= {rstn_sync[0], 1'b1};
+end
+
+assign rstn = rstn_sync[1];
+
+endmodule \ No newline at end of file
diff --git a/rtl/src/result_mux.v b/rtl/src/result_mux.v
new file mode 100644
index 0000000..3c94617
--- /dev/null
+++ b/rtl/src/result_mux.v
@@ -0,0 +1,22 @@
+module result_mux (
+ input [31:0] src_alu_result,
+ input [31:0] src_alu_result_buf,
+ input [31:0] src_data_buf,
+
+ input [1:0] result_src,
+
+ output reg [31:0] result
+);
+
+`include "include/consts.vh"
+
+always @(*) begin
+ case (result_src)
+ RESULT_SRC_DATA_BUF: result = src_data_buf;
+ RESULT_SRC_ALU_RESULT_BUF: result = src_alu_result_buf;
+ RESULT_SRC_ALU_RESULT: result = src_alu_result;
+ default: result = 32'b0;
+ endcase
+end
+
+endmodule
diff --git a/rtl/src/rom.v b/rtl/src/rom.v
new file mode 100644
index 0000000..29de1da
--- /dev/null
+++ b/rtl/src/rom.v
@@ -0,0 +1,25 @@
+module rom #(
+ parameter N = 32,
+ parameter SIZE = 1024,
+ parameter ROM_FILE = "../../build/rom.hex"
+)(
+ input clk,
+ input [N-1:0] addr,
+ output reg [N-1:0] data_read
+);
+
+`include "include/log2.vh"
+
+
+//(* RAM_STYLE="BLOCK" *)
+reg [N-1:0] mem [0:SIZE-1];
+
+initial begin
+ $readmemh(ROM_FILE, mem, 0, SIZE-1);
+end
+
+always @(negedge clk) begin
+ data_read <= mem[addr >> 2];
+end
+
+endmodule
diff --git a/rtl/src/shift_unit.v b/rtl/src/shift_unit.v
new file mode 100644
index 0000000..ea83e4a
--- /dev/null
+++ b/rtl/src/shift_unit.v
@@ -0,0 +1,21 @@
+module shift_unit (
+ input signed [31:0] a,
+ input [4:0] b,
+
+ input [1:0] op,
+
+ output reg [31:0] result
+);
+
+`include "include/consts.vh"
+
+always @ (*) begin
+ case (op)
+ SHIFT_OP_SLL: result = a << b; // SLL
+ SHIFT_OP_SRL: result = a >> b; // SRL
+ SHIFT_OP_SRA: result = a >>> b; // SRA
+ default: result = 32'b0;
+ endcase
+end
+
+endmodule
diff --git a/rtl/src/top.v b/rtl/src/top.v
new file mode 100644
index 0000000..b10fbca
--- /dev/null
+++ b/rtl/src/top.v
@@ -0,0 +1,38 @@
+module top (
+ input clk,
+ input key,
+ input rst,
+ output [5:0] led
+);
+
+wire rstn, rstn_async, clk_cpu;
+assign rstn_async = rst;
+
+wire [31:0] io_in;
+wire [31:0] io_out;
+
+reset_synchronizer reset_synchronizer (
+ .clk(clk),
+ .rstn_async(rstn_async),
+ .rstn(rstn)
+);
+
+clock_divider #(.N(1)) clkdiv (
+ .clk(clk),
+ .rstn(rstn),
+ .clk_div(clk_cpu)
+);
+
+assign led[0] = ~clk_cpu;
+assign led[5:1] = ~io_out[4:0];
+assign io_in[0] = key;
+
+
+cpu cpu (
+ .clk(clk_cpu),
+ .rstn(rstn),
+ .io_in(io_in),
+ .io_out(io_out)
+);
+
+endmodule