From 9135170576cc2bdd12c10e06288224c42e923e62 Mon Sep 17 00:00:00 2001 From: UnbalancedCat Date: Fri, 23 May 2025 00:15:19 +0800 Subject: [PATCH] init repo: update to RV32IMA (M mode) --- .gitignore | 37 ++ rv_cpu.srcs/sources_1/new/cpu_top.v | 271 ++++++++++++ rv_cpu.srcs/sources_1/new/exe_stage.v | 287 +++++++++++++ rv_cpu.srcs/sources_1/new/id_stage.v | 308 ++++++++++++++ rv_cpu.srcs/sources_1/new/if_stage.v | 146 +++++++ rv_cpu.srcs/sources_1/new/mem_stage.v | 180 ++++++++ rv_cpu.srcs/sources_1/new/sub_unit/alu.v | 116 ++++++ .../sources_1/new/sub_unit/csr/csr_reg_file.v | 387 ++++++++++++++++++ .../sub_unit/csr/onehot32_to_hex5_decoder.v | 31 ++ .../sources_1/new/sub_unit/csr_reg_file.v | 266 ++++++++++++ .../sources_1/new/sub_unit/inst_decoder.v | 336 +++++++++++++++ .../new/sub_unit/m_ext_unit/divider.v | 274 +++++++++++++ .../new/sub_unit/m_ext_unit/m_ext_unit.v | 109 +++++ .../new/sub_unit/m_ext_unit/multiplier.v | 231 +++++++++++ .../sources_1/new/sub_unit/pre_if_stage.v | 67 +++ rv_cpu.srcs/sources_1/new/sub_unit/reg_file.v | 63 +++ rv_cpu.srcs/sources_1/new/wb_stage.v | 98 +++++ rv_cpu.xpr | 302 ++++++++++++++ 18 files changed, 3509 insertions(+) create mode 100644 .gitignore create mode 100644 rv_cpu.srcs/sources_1/new/cpu_top.v create mode 100644 rv_cpu.srcs/sources_1/new/exe_stage.v create mode 100644 rv_cpu.srcs/sources_1/new/id_stage.v create mode 100644 rv_cpu.srcs/sources_1/new/if_stage.v create mode 100644 rv_cpu.srcs/sources_1/new/mem_stage.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/alu.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/csr/csr_reg_file.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/csr/onehot32_to_hex5_decoder.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/csr_reg_file.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/inst_decoder.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/divider.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/m_ext_unit.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/multiplier.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/pre_if_stage.v create mode 100644 rv_cpu.srcs/sources_1/new/sub_unit/reg_file.v create mode 100644 rv_cpu.srcs/sources_1/new/wb_stage.v create mode 100644 rv_cpu.xpr diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c857a2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +* +!*/ + +# track this file or dic +!.gitignore +!readme.md + +doc/** +!others/** + +# vivado +!rv_cpu.xpr + +## srcs +!rv_cpu.srcs/constrs_1/** + +!rv_cpu.srcs/sources_1/ip/*/*.xci +!rv_cpu.srcs/sources_1/ip/*/*.coe + +!rv_cpu.srcs/sources_1/new/** +!rv_cpu.srcs/sources_1/imports/** +!rv_cpu.srcs/sources_1/bd/** + +## sims +!rv_cpu.srcs/sim_1/** + +!rv_cpu.sim/sim_1/behav/modelsim/*.do +rv_cpu.sim/sim_1/behav/xsim/*.wdb +!rv_cpu.sim/sim_1/*.wcfg + +## bits +!rv_cpu.runs/impl_1/*.bit +!rv_cpu.runs/impl_1/*.bin +!rv_cpu.runs/impl_1/*.ltx +!rv_cpu.runs/bits/*.bit +!rv_cpu.runs/bits/*.bin +!rv_cpu.runs/bits/*.ltx \ No newline at end of file diff --git a/rv_cpu.srcs/sources_1/new/cpu_top.v b/rv_cpu.srcs/sources_1/new/cpu_top.v new file mode 100644 index 0000000..56f8486 --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/cpu_top.v @@ -0,0 +1,271 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 14:00:00 +// Design Name: cpu_top +// Module Name: cpu_top +// Project Name: rv_cpu +// Target Devices: +// Tool Versions: +// Description: Top module for the RISC-V CPU, connecting pipeline stages. +// +// Dependencies: if_stage, id_stage, exe_stage, mem_stage, wb_stage +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + +module cpu_top ( + // Global signals + input clk_i, + input rstn_i, + + // Instruction SRAM interface + output inst_sram_en_o, + output [ 3:0] inst_sram_wen_o, + output [31:0] inst_sram_addr_o, + output [31:0] inst_sram_wdata_o, + input [31:0] inst_sram_rdata_i, + + // Data SRAM interface + output data_sram_en_o, + output [ 3:0] data_sram_wen_o, + output [31:0] data_sram_addr_o, + output [31:0] data_sram_wdata_o, + input [31:0] data_sram_rdata_i, + + // Debug signals from WB stage + output [31:0] debug_wb_pc_o, + output [ 3:0] debug_wb_rf_wen_o, + output [ 4:0] debug_wb_rf_waddr_o, + output [31:0] debug_wb_rf_wdata_o +); + + // Define local parameters for bus widths based on stage module parameters + localparam FS_TO_DS_BUS_WIDTH = 65; + localparam DS_TO_ES_BUS_WIDTH = 315; + localparam ES_TO_MS_BUS_WIDTH = 164; + localparam MS_TO_WS_BUS_WIDTH = 70; + localparam WS_TO_DS_BUS_WIDTH = 38; + localparam ES_TO_DS_FWD_BUS_WIDTH = 39; + localparam MS_TO_DS_FWD_BUS_WIDTH = 38; + + // Wires for IF <-> ID pipeline registers + wire [FS_TO_DS_BUS_WIDTH-1:0] fs_to_ds_bus_data; + wire fs_to_ds_bus_valid; + wire fs_to_ds_bus_ready; + + // Wires for ID <-> EXE pipeline registers + wire [DS_TO_ES_BUS_WIDTH-1:0] ds_to_es_bus_data; + wire ds_to_es_bus_valid; + wire ds_to_es_bus_ready; + + // Wires for EXE <-> MEM pipeline registers + wire [ES_TO_MS_BUS_WIDTH-1:0] es_to_ms_bus_data; + wire es_to_ms_bus_valid; + wire es_to_ms_bus_ready; + + // Wires for MEM <-> WB pipeline registers + wire [MS_TO_WS_BUS_WIDTH-1:0] ms_to_ws_bus_data; + wire ms_to_ws_bus_valid; + wire ms_to_ws_bus_ready; + + // Wires for WB -> ID (write-back path) + wire [WS_TO_DS_BUS_WIDTH-1:0] ws_to_ds_bus_data; + wire ws_to_ds_bus_valid; + + // Wires for branch prediction (EXE -> IF) + wire [31:0] br_target; + wire br_taken; + + // Fowarding buses for ID stage + wire [ES_TO_DS_FWD_BUS_WIDTH-1:0] es_to_ds_fwd_bus_data; + wire [MS_TO_DS_FWD_BUS_WIDTH-1:0] ms_to_ds_fwd_bus_data; + + wire [ 1:0] csr_mpp; + + wire es_a_ext_stall; + wire ms_a_ext_stall; + + wire load_stall; + wire m_ext_stall; + wire a_ext_stall; + + wire csr_flush; + wire br_flush; + + wire es_data_sram_en; + wire [ 3:0] es_data_sram_wen; + wire [31:0] es_data_sram_addr; + wire [31:0] es_data_sram_wdata; + + wire ms_data_sram_en; + wire [ 3:0] ms_data_sram_wen; + wire [31:0] ms_data_sram_addr; + wire [31:0] ms_data_sram_wdata; + + assign a_ext_stall = es_a_ext_stall | ms_a_ext_stall; + + // Instantiate IF Stage + if_stage #( + .FS_TO_DS_BUS_WIDTH(FS_TO_DS_BUS_WIDTH) + ) inst_if_stage ( + .clk_i (clk_i), + .rstn_i (rstn_i), + + .load_stall_i (load_stall), + .m_ext_stall_i (m_ext_stall), + .a_ext_stall_i (a_ext_stall), + .br_flush_i (br_flush), + .csr_flush_i (csr_flush), + + .br_target_i (br_target), + .br_taken_i (br_taken), + + .fs_to_ds_bus_ready_i (fs_to_ds_bus_ready), + .fs_to_ds_bus_data_o (fs_to_ds_bus_data), + .fs_to_ds_bus_valid_o (fs_to_ds_bus_valid), + + .inst_sram_en_o (inst_sram_en_o), + .inst_sram_wen_o (inst_sram_wen_o), + .inst_sram_addr_o (inst_sram_addr_o), + .inst_sram_wdata_o (inst_sram_wdata_o), + .inst_sram_rdata_i (inst_sram_rdata_i) + ); + + + + // Instantiate ID Stage + id_stage #( + .FS_TO_DS_BUS_WIDTH(FS_TO_DS_BUS_WIDTH), + .DS_TO_ES_BUS_WIDTH(DS_TO_ES_BUS_WIDTH), + .WS_TO_DS_BUS_WIDTH(WS_TO_DS_BUS_WIDTH), + .ES_TO_DS_FWD_BUS_WIDTH(ES_TO_DS_FWD_BUS_WIDTH), + .MS_TO_DS_FWD_BUS_WIDTH(MS_TO_DS_FWD_BUS_WIDTH) + ) inst_id_stage ( + .clk_i (clk_i), + .rstn_i (rstn_i), + + .csr_mpp_i (csr_mpp), + + .csr_flush_i (csr_flush), + .m_ext_stall_i (m_ext_stall), + .a_ext_stall_i (a_ext_stall), + + .fs_to_ds_bus_ready_o (fs_to_ds_bus_ready), + .fs_to_ds_bus_data_i (fs_to_ds_bus_data), + .fs_to_ds_bus_valid_i (fs_to_ds_bus_valid), + + .ds_to_es_bus_ready_i (ds_to_es_bus_ready), + .ds_to_es_bus_data_o (ds_to_es_bus_data), + .ds_to_es_bus_valid_o (ds_to_es_bus_valid), + + .ws_to_ds_bus_data_i (ws_to_ds_bus_data), + .ws_to_ds_bus_valid_i (ws_to_ds_bus_valid), + + .es_to_ds_fwd_bus_data_i (es_to_ds_fwd_bus_data), + .ms_to_ds_fwd_bus_data_i (ms_to_ds_fwd_bus_data), + + .br_flush_o (br_flush), + .load_stall_o (load_stall) + ); + + // Instantiate EXE Stage + exe_stage #( + .DS_TO_ES_BUS_WIDTH(DS_TO_ES_BUS_WIDTH), + .ES_TO_MS_BUS_WIDTH(ES_TO_MS_BUS_WIDTH), + .ES_TO_DS_FWD_BUS_WIDTH(ES_TO_DS_FWD_BUS_WIDTH) + ) inst_exe_stage ( + .clk_i (clk_i), + .rstn_i (rstn_i), + + .ds_to_es_bus_ready_o (ds_to_es_bus_ready), + .ds_to_es_bus_data_i (ds_to_es_bus_data), + .ds_to_es_bus_valid_i (ds_to_es_bus_valid), + + .es_to_ms_bus_ready_i (es_to_ms_bus_ready), + .es_to_ms_bus_data_o (es_to_ms_bus_data), + .es_to_ms_bus_valid_o (es_to_ms_bus_valid), + + .br_target_o (br_target), + .br_taken_o (br_taken), + + .data_sram_en_o (es_data_sram_en), + .data_sram_wen_o (es_data_sram_wen), + .data_sram_addr_o (es_data_sram_addr), + .data_sram_wdata_o (es_data_sram_wdata), + + .es_to_ds_fwd_bus_data_o(es_to_ds_fwd_bus_data), + + .csr_mpp_o (csr_mpp), + + .m_ext_stall_o (m_ext_stall), + .a_ext_stall_o (es_a_ext_stall), + .csr_flush_o (csr_flush) + ); + + // Instantiate MEM Stage + mem_stage #( + .ES_TO_MS_BUS_WIDTH(ES_TO_MS_BUS_WIDTH), + .MS_TO_WS_BUS_WIDTH(MS_TO_WS_BUS_WIDTH), + .MS_TO_DS_FWD_BUS_WIDTH(MS_TO_DS_FWD_BUS_WIDTH) + ) inst_mem_stage ( + .clk_i (clk_i), + .rstn_i (rstn_i), + + .csr_flush_i (csr_flush), + + .es_to_ms_bus_ready_o (es_to_ms_bus_ready), + .es_to_ms_bus_data_i (es_to_ms_bus_data), + .es_to_ms_bus_valid_i (es_to_ms_bus_valid), + + .ms_to_ws_bus_ready_i (ms_to_ws_bus_ready), + .ms_to_ws_bus_data_o (ms_to_ws_bus_data), + .ms_to_ws_bus_valid_o (ms_to_ws_bus_valid), + + .data_sram_rdata_i (data_sram_rdata_i), + .data_sram_en_o (ms_data_sram_en), + .data_sram_wen_o (ms_data_sram_wen), + .data_sram_addr_o (ms_data_sram_addr), + .data_sram_wdata_o (ms_data_sram_wdata), + + .a_ext_stall_o (ms_a_ext_stall), + .ms_to_ds_fwd_bus_data_o(ms_to_ds_fwd_bus_data) + ); + + // Instantiate WB Stage + wb_stage #( + .MS_TO_WS_BUS_WIDTH(MS_TO_WS_BUS_WIDTH), + .WS_TO_DS_BUS_WIDTH(WS_TO_DS_BUS_WIDTH) + ) inst_wb_stage ( + .clk_i (clk_i), + .rstn_i (rstn_i), + + .ms_to_ws_bus_ready_o (ms_to_ws_bus_ready), + .ms_to_ws_bus_data_i (ms_to_ws_bus_data), + .ms_to_ws_bus_valid_i (ms_to_ws_bus_valid), + + .ws_to_ds_bus_data_o (ws_to_ds_bus_data), + .ws_to_ds_bus_valid_o (ws_to_ds_bus_valid), + + .debug_wb_pc_o (debug_wb_pc_o), + .debug_wb_rf_wen_o (debug_wb_rf_wen_o), + .debug_wb_rf_waddr_o (debug_wb_rf_waddr_o), + .debug_wb_rf_wdata_o (debug_wb_rf_wdata_o) + ); + + assign data_sram_en_o = es_data_sram_en + | ms_data_sram_en; + assign data_sram_wen_o = {4{es_data_sram_en}} & es_data_sram_wen + | {4{ms_data_sram_en}} & ms_data_sram_wen; + assign data_sram_addr_o = {32{es_data_sram_en}} & es_data_sram_addr + | {32{ms_data_sram_en}} & ms_data_sram_addr; + assign data_sram_wdata_o = {32{es_data_sram_en}} & es_data_sram_wdata + | {32{ms_data_sram_en}} & ms_data_sram_wdata; + + +endmodule diff --git a/rv_cpu.srcs/sources_1/new/exe_stage.v b/rv_cpu.srcs/sources_1/new/exe_stage.v new file mode 100644 index 0000000..7cd646d --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/exe_stage.v @@ -0,0 +1,287 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 04:05:18 +// Design Name: +// Module Name: exe_stage +// Project Name: +// Target Devices: +// Tool Versions: +// Desrciption: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module exe_stage #( + parameter DS_TO_ES_BUS_WIDTH = 315, + parameter ES_TO_MS_BUS_WIDTH = 164, + parameter ES_TO_DS_FWD_BUS_WIDTH = 39 +) +( + input clk_i, + input rstn_i, + + output ds_to_es_bus_ready_o, + input [DS_TO_ES_BUS_WIDTH-1:0] ds_to_es_bus_data_i, + input ds_to_es_bus_valid_i, + + input es_to_ms_bus_ready_i, + output [ES_TO_MS_BUS_WIDTH-1:0] es_to_ms_bus_data_o, + output es_to_ms_bus_valid_o, + + output [31:0] br_target_o, + output br_taken_o, + + output data_sram_en_o, + output [ 3:0] data_sram_wen_o, + output [31:0] data_sram_addr_o, + output [31:0] data_sram_wdata_o, + + // fowarding bus to ID stage + output [ES_TO_DS_FWD_BUS_WIDTH-1:0] es_to_ds_fwd_bus_data_o, + + output [ 1:0] csr_mpp_o, + + output m_ext_stall_o, + output a_ext_stall_o, + output csr_flush_o + ); + + reg ds_to_es_bus_valid; + reg [DS_TO_ES_BUS_WIDTH-1:0] ds_to_es_bus_data; + + wire es_pipeline_stall; + + wire es_to_ms_bus_valid; + + wire [31:0] es_inst; + wire [31:0] es_pc; + + wire [ 4:0] es_rs1; + wire [ 4:0] es_rs2; + wire [ 4:0] es_rd; + wire [31:0] es_imm; + wire [ 4:0] es_shamt; + wire [11:0] es_csr; + wire [ 4:0] es_zimm; + + wire [10:0] es_alu_op; + wire [ 3:0] es_calc_src1_sel; + wire [ 3:0] es_calc_src2_sel; + wire [ 1:0] es_jump_op; + wire [ 5:0] es_load_op; + wire [ 2:0] es_store_op; + wire [11:0] es_amo_op; + + wire [31:0] es_rs1_value; + wire [31:0] es_rs2_value; + + wire [31:0] es_br_target; + wire es_br_taken; + + wire [ 2:0] es_csr_op; + wire [ 7:0] es_m_ext_op; + + wire es_op_is_alu; + wire es_op_is_m_ext; + wire es_op_is_jump; + wire es_op_is_branch; + wire es_op_is_load; + wire es_op_is_store; + wire es_op_is_csr; + wire es_op_is_amo; + + wire [31:0] es_calc_src1; + wire [31:0] es_calc_src2; + + wire [31:0] es_excp_vec; + + wire [31:0] es_alu_result; + + wire [31:0] es_result; + + wire [ 2:0] es_result_sel; + wire [31:0] es_m_ext_result; + wire es_m_ext_valid; + + wire [31:0] es_csr_result; + wire es_csr_taken; + wire [31:0] es_csr_target; + + assign es_pipeline_stall = m_ext_stall_o; + + assign { + es_excp_vec, // 314:283 (32 bits) + es_amo_op, // 282:271 (12 bits) + es_csr_op, // 270:268 (3 bits) + es_m_ext_op, // 267:260 (8 bits) + es_br_taken, // 259:259 (1 bit) + es_br_target, // 258:227 (32 bits) + es_store_op, // 226:224 (3 bits) + es_load_op, // 223:218 (6 bits) + es_jump_op, // 217:216 (2 bits) + es_alu_op, // 215:205 (11 bits) + es_calc_src2_sel, // 204:201 (4 bits) + es_calc_src1_sel, // 200:197 (4 bits) + es_rd, // 196:192 (5 bits) + es_rs2, // 191:187 (5 bits) + es_rs1, // 186:182 (5 bits) + es_zimm, // 181:177 (5 bits) + es_csr, // 176:165 (12 bits) + es_shamt, // 164:160 (5 bits) + es_imm, // 159:128 (32 bits) + es_rs2_value, // 127:96 (32 bits) + es_rs1_value, // 95:64 (32 bits) + es_pc, // 63:32 (32 bits) + es_inst // 31:0 (32 bits) + } = ds_to_es_bus_data; + + assign es_to_ms_bus_valid = !es_pipeline_stall; + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + ds_to_es_bus_valid <= 1'b0; + end + else if (csr_flush_o) begin + ds_to_es_bus_valid <= 1'b0; + end + else if (ds_to_es_bus_ready_o) begin + ds_to_es_bus_valid <= ds_to_es_bus_valid_i; + end + else begin + ds_to_es_bus_valid <= ds_to_es_bus_valid; + end + end + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + ds_to_es_bus_data <= {DS_TO_ES_BUS_WIDTH{1'b0}}; + end + else if (ds_to_es_bus_valid_i && ds_to_es_bus_ready_o) begin + ds_to_es_bus_data <= ds_to_es_bus_data_i; + end + else begin + ds_to_es_bus_data <= ds_to_es_bus_data; + end + end + + assign es_op_is_alu = |es_alu_op; + assign es_op_is_m_ext = |es_m_ext_op; + assign es_op_is_jump = |es_jump_op; + assign es_op_is_branch = |es_br_taken; + assign es_op_is_load = |es_load_op; + assign es_op_is_store = |es_store_op; + assign es_op_is_csr = |es_csr_op; + assign es_op_is_amo = |es_amo_op; + + assign es_calc_src1 = {32{es_calc_src1_sel[0]}} & es_rs1_value + | {32{es_calc_src1_sel[1]}} & es_pc + | {32{es_calc_src1_sel[2]}} & 32'b0 + | {32{es_calc_src1_sel[3]}} & es_zimm; + assign es_calc_src2 = {32{es_calc_src2_sel[0]}} & es_rs2_value + | {32{es_calc_src2_sel[1]}} & es_imm + | {32{es_calc_src2_sel[2]}} & 32'h4 + | {32{es_calc_src2_sel[3]}} & es_shamt; + + alu inst_alu( + .alu_op_i (es_alu_op), + .alu_src1_i (es_calc_src1), + .alu_src2_i (es_calc_src2), + .alu_result_o (es_alu_result) + ); + + m_ext_unit inst_m_ext_unit ( + .clk_i (clk_i), + .rstn_i (rstn_i), + .m_ext_op_i (es_m_ext_op), + .m_ext_src1_i (es_calc_src1), + .m_ext_src2_i (es_calc_src2), + .m_ext_result_o (es_m_ext_result), + .m_ext_valid_o (es_m_ext_valid), + .m_ext_stall_o (m_ext_stall_o) + ); + + csr_reg_file inst_csr_reg_file ( + .clk_i (clk_i), + .rstn_i (rstn_i), + .csr_pc_i (es_pc), + .csr_inst_i (es_inst), + .csr_op_i (es_csr_op), + .csr_addr_i (es_csr), + .csr_wdata_i (es_calc_src1), + .csr_rdata_o (es_csr_result), + .csr_excp_vec_i (es_excp_vec), + .csr_mpp_o (csr_mpp_o), + .csr_taken_o (es_csr_taken), + .csr_target_o (es_csr_target) + ); + + + assign data_sram_en_o = ds_to_es_bus_valid && (es_op_is_store || es_op_is_load || es_op_is_amo); + assign data_sram_wen_o = {4{(ds_to_es_bus_valid && es_op_is_store)}} + & ( + ( + {4{es_store_op[0]}} + & ({4{es_alu_result[1:0] == 2'b00}} & 4'b0001) + | ({4{es_alu_result[1:0] == 2'b01}} & 4'b0010) + | ({4{es_alu_result[1:0] == 2'b10}} & 4'b0100) + | ({4{es_alu_result[1:0] == 2'b11}} & 4'b1000) + ) + | ( + {4{es_store_op[1]}} + & ({4{es_alu_result[1:0] == 2'b00}} & 4'b0011) + | ({4{es_alu_result[1:0] == 2'b10}} & 4'b1100) + ) + | ( + {4{es_store_op[2]}} & 4'b1111 + ) + ); + assign data_sram_addr_o = es_op_is_amo ? es_calc_src1 : es_alu_result; + assign data_sram_wdata_o = ({32{es_store_op[0]}} & {4{es_rs2_value[ 7:0]}}) + | ({32{es_store_op[1]}} & {2{es_rs2_value[15:0]}}) + | ({32{es_store_op[2]}} & es_rs2_value ); + + assign es_result_sel = {es_op_is_amo, es_op_is_load, (es_op_is_csr || es_op_is_jump || (es_op_is_alu || es_op_is_m_ext) && !(es_op_is_store || es_op_is_load))}; + assign es_result = {32{es_op_is_alu }} & es_alu_result + | {32{es_op_is_m_ext}} & es_m_ext_result + | {32{es_op_is_csr }} & es_csr_result; + + assign es_to_ms_bus_data_o = { // Total 164 bits + es_result_sel, // 163:161 (3 bits) + es_result, // 160:129 (32 bits) + es_calc_src2, // 128:97 (32 bits) + es_calc_src1, // 96:65 (32 bits) + es_amo_op, // 64:53 (12 bits) + es_load_op, // 52:47 (6 bits) + es_rd, // 46:42 (5 bits) + es_rs2, // 41:37 (5 bits) + es_rs1, // 36:32 (5 bits) + es_pc // 31:0 (32 bits) + }; + + assign br_target_o = {32{es_br_taken}} & es_br_target + | {32{es_csr_taken}} & es_csr_target; + assign br_taken_o = ds_to_es_bus_valid && (es_br_taken || es_csr_taken); + + assign ds_to_es_bus_ready_o = !ds_to_es_bus_valid || (es_to_ms_bus_valid && es_to_ms_bus_ready_i); + assign es_to_ms_bus_valid_o = ds_to_es_bus_valid && es_to_ms_bus_valid; + + assign es_to_ds_fwd_bus_data_o = { + ds_to_es_bus_valid && es_op_is_load, // 38:38 + ds_to_es_bus_valid && (es_op_is_jump || es_op_is_m_ext || es_op_is_csr || (es_op_is_alu && !(es_op_is_store || es_op_is_load))), // 37:37 + es_rd, // 36:32 + es_result // 31:0 + }; + + assign a_ext_stall_o = ds_to_es_bus_valid && es_op_is_amo; + assign csr_flush_o = ds_to_es_bus_valid && es_csr_taken; + +endmodule diff --git a/rv_cpu.srcs/sources_1/new/id_stage.v b/rv_cpu.srcs/sources_1/new/id_stage.v new file mode 100644 index 0000000..db7231b --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/id_stage.v @@ -0,0 +1,308 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 01:26:38 +// Design Name: +// Module Name: id_stage +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module id_stage #( + parameter FS_TO_DS_BUS_WIDTH = 65, + parameter DS_TO_ES_BUS_WIDTH = 315, + parameter WS_TO_DS_BUS_WIDTH = 38, + parameter ES_TO_DS_FWD_BUS_WIDTH = 39, + parameter MS_TO_DS_FWD_BUS_WIDTH = 38 +) +( + input clk_i, + input rstn_i, + + input m_ext_stall_i, + input a_ext_stall_i, + input csr_flush_i, + + input [1:0] csr_mpp_i, + + output fs_to_ds_bus_ready_o, + input [FS_TO_DS_BUS_WIDTH-1:0] fs_to_ds_bus_data_i, + input fs_to_ds_bus_valid_i, + + input ds_to_es_bus_ready_i, + output [DS_TO_ES_BUS_WIDTH-1:0] ds_to_es_bus_data_o, + output ds_to_es_bus_valid_o, + + input [WS_TO_DS_BUS_WIDTH-1:0] ws_to_ds_bus_data_i, + input ws_to_ds_bus_valid_i, + + input [ES_TO_DS_FWD_BUS_WIDTH-1:0] es_to_ds_fwd_bus_data_i, + input [MS_TO_DS_FWD_BUS_WIDTH-1:0] ms_to_ds_fwd_bus_data_i, + + output br_flush_o, + output load_stall_o + ); + + reg fs_to_ds_bus_valid; + reg [FS_TO_DS_BUS_WIDTH-1:0] fs_to_ds_bus_data; + + wire ds_pipeline_stall; + wire ds_pipeline_flush; + + wire ds_to_es_bus_valid; + + wire [31:0] ds_inst; + wire [31:0] ds_pc; + + wire ds_we; + wire [ 4:0] ds_waddr; + wire [31:0] ds_wdata; + + wire [ 4:0] ds_rs1; + wire [ 4:0] ds_rs2; + wire [ 4:0] ds_rd; + wire [31:0] ds_imm; + wire [ 4:0] ds_shamt; + wire [11:0] ds_csr; + wire [ 4:0] ds_zimm; + + wire [10:0] ds_alu_op; + wire [ 3:0] ds_calc_src1_sel; + wire [ 3:0] ds_calc_src2_sel; + wire [ 1:0] ds_jump_op; + wire [ 5:0] ds_load_op; + wire [ 2:0] ds_store_op; + wire [ 5:0] ds_branch_op; + wire [ 7:0] ds_m_ext_op; + wire [ 2:0] ds_csr_op; + wire [11:0] ds_amo_op; + wire ds_excp_illegal_inst; + wire ds_excp_breakpoint; + wire ds_excp_env_call; + + wire [31:0] ds_excp_vec; + + wire ds_op_is_calc; + wire ds_op_is_jump; + wire ds_op_is_branch; + wire ds_op_is_load; + wire ds_op_is_store; + + wire [ 4:0] ds_raddr1; + wire [31:0] ds_rdata1; + wire [ 4:0] ds_raddr2; + wire [31:0] ds_rdata2; + + wire [31:0] ds_rs1_value; + wire [31:0] ds_rs2_value; + + wire ds_rs1_eq_rs2; + wire ds_rs1_lt_rs2; + wire ds_rs1_lt_rs2u; + + wire [31:0] ds_br_target; + wire ds_br_taken; + + wire es_fwd_we; + wire [ 4:0] es_fwd_rd; + wire [31:0] es_fwd_value; + + wire es_load_use; + wire ms_fwd_we; + wire [ 4:0] ms_fwd_rd; + wire [31:0] ms_fwd_value; + + assign ds_pipeline_stall = load_stall_o || m_ext_stall_i || a_ext_stall_i; + assign ds_pipeline_flush = br_flush_o || csr_flush_i; + + assign { + ds_excp_inst_addr_misalign, // 64:64 + ds_inst, // 63:32 + ds_pc // 31:0 + } = fs_to_ds_bus_data; + + assign { + ds_we, // 37:37 + ds_waddr, // 36:32 + ds_wdata // 31:0 + } = {38{ws_to_ds_bus_valid_i}} & ws_to_ds_bus_data_i; + + assign { + es_load_use, + es_fwd_we, + es_fwd_rd, + es_fwd_value + } = es_to_ds_fwd_bus_data_i; + + assign { + ms_fwd_we, + ms_fwd_rd, + ms_fwd_value + } = ms_to_ds_fwd_bus_data_i; + + assign ds_to_es_bus_valid = !ds_pipeline_stall; + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + fs_to_ds_bus_valid <= 1'b0; + end + else if (ds_pipeline_flush) begin + fs_to_ds_bus_valid <= 1'b0; + end + else if (fs_to_ds_bus_ready_o) begin + fs_to_ds_bus_valid <= fs_to_ds_bus_valid_i; + end + else begin + fs_to_ds_bus_valid <= fs_to_ds_bus_valid; + end + end + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + fs_to_ds_bus_data <= {FS_TO_DS_BUS_WIDTH{1'b0}}; + end + else if (fs_to_ds_bus_valid_i && fs_to_ds_bus_ready_o) begin + fs_to_ds_bus_data <= fs_to_ds_bus_data_i; + end + else begin + fs_to_ds_bus_data <= fs_to_ds_bus_data; + end + end + + inst_decoder inst_inst_decoder( + .inst_i (ds_inst), + .rs1_o (ds_rs1), + .rs2_o (ds_rs2), + .rd_o (ds_rd), + .imm_o (ds_imm), + .shamt_o (ds_shamt), + .pred_o (), + .succ_o (), + .csr_o (ds_csr), + .zimm_o (ds_zimm), + .alu_op_o (ds_alu_op), + .calc_src1_sel_o (ds_calc_src1_sel), + .calc_src2_sel_o (ds_calc_src2_sel), + .jump_op_o (ds_jump_op), + .load_op_o (ds_load_op), + .store_op_o (ds_store_op), + .branch_op_o (ds_branch_op), + .m_ext_op_o (ds_m_ext_op), + .csr_op_o (ds_csr_op), + .amo_op_o (ds_amo_op), + .amo_aq_o (), + .amo_rl_o (), + .excp_illegal_inst_o (ds_excp_illegal_inst), + .excp_breakpoint_o (ds_excp_breakpoint), + .excp_env_call_o (ds_excp_env_call) + ); + + reg_file inst_reg_file( + .clk_i (clk_i), + .rstn_i (rstn_i), + .raddr1_i (ds_raddr1), + .rdata1_o (ds_rdata1), + .raddr2_i (ds_raddr2), + .rdata2_o (ds_rdata2), + .we_i (ds_we), + .waddr_i (ds_waddr), + .wdata_i (ds_wdata) + ); + + assign ds_excp_vec = { + 16'b0, // reserved + 1'b0, // store page fault + 1'b0, // expc code 14 + 2'b0, // isnt & load page fault + ds_excp_env_call && (csr_mpp_i == 2'b11), + 1'b0, // excp code 10 + ds_excp_env_call && (csr_mpp_i == 2'b01), + 1'b0, // env call from u mode + 4'b0, // load & store addr misalign & access fault + ds_excp_breakpoint, + ds_excp_illegal_inst, + 1'b0, // ds_excp_inst_access_fault + ds_excp_inst_addr_misalign + }; + + assign ds_op_is_calc = |ds_alu_op || |ds_m_ext_op || |ds_csr_op; + assign ds_op_is_jump = |ds_jump_op; + assign ds_op_is_branch = |ds_branch_op; + assign ds_op_is_load = |ds_load_op; + assign ds_op_is_store = |ds_store_op; + + assign ds_raddr1 = ds_rs1; + assign ds_raddr2 = ds_rs2; + assign ds_rs1_value = ((es_fwd_rd != 5'b0) && es_fwd_we && (es_fwd_rd == ds_rs1)) ? es_fwd_value : + ((ms_fwd_rd != 5'b0) && ms_fwd_we && (ms_fwd_rd == ds_rs1)) ? ms_fwd_value : + ds_rdata1; + assign ds_rs2_value = ((es_fwd_rd != 5'b0) && es_fwd_we && (es_fwd_rd == ds_rs2)) ? es_fwd_value : + ((ms_fwd_rd != 5'b0) && ms_fwd_we && (ms_fwd_rd == ds_rs2)) ? ms_fwd_value : + ds_rdata2; + + assign ds_rs1_eq_rs2 = (ds_rs1_value == ds_rs2_value); + assign ds_rs1_lt_rs2 = ($signed(ds_rs1_value) < $signed(ds_rs2_value)); + assign ds_rs1_lt_rs2u = (ds_rs1_value < ds_rs2_value); + + assign ds_to_es_bus_data_o = { // Total 315 bits + ds_excp_vec, // 314:283 (32 bits) + ds_amo_op, // 282:271 (12 bits) + ds_csr_op, // 270:268 (3 bits) + ds_m_ext_op, // 267:260 (8 bits) + ds_br_taken, // 259:259 (1 bit) + ds_br_target, // 258:227 (32 bits) + ds_store_op, // 226:224 (3 bits) + ds_load_op, // 223:218 (6 bits) + ds_jump_op, // 217:216 (2 bits) + ds_alu_op, // 215:205 (11 bits) + ds_calc_src2_sel, // 204:201 (4 bits) + ds_calc_src1_sel, // 200:197 (4 bits) + ds_rd, // 196:192 (5 bits) + ds_rs2, // 191:187 (5 bits) + ds_rs1, // 186:182 (5 bits) + ds_zimm, // 181:177 (5 bits) + ds_csr, // 176:165 (12 bits) + ds_shamt, // 164:160 (5 bits) + ds_imm, // 159:128 (32 bits) + ds_rs2_value, // 127:96 (32 bits) + ds_rs1_value, // 95:64 (32 bits) + ds_pc, // 63:32 (32 bits) + ds_inst // 31:0 (32 bits) + }; + + + assign ds_br_target = ({32{ ds_jump_op[0] }} & (ds_pc + ds_imm) ) + | ({32{ ds_jump_op[1] }} & (ds_rs1_value + ds_imm) & ~32'b1) + | ({32{ds_branch_op[0] & ds_rs1_eq_rs2 }} & (ds_pc + ds_imm) ) + | ({32{ds_branch_op[1] & !ds_rs1_eq_rs2 }} & (ds_pc + ds_imm) ) + | ({32{ds_branch_op[2] & ds_rs1_lt_rs2 }} & (ds_pc + ds_imm) ) + | ({32{ds_branch_op[3] & !ds_rs1_lt_rs2 }} & (ds_pc + ds_imm) ) + | ({32{ds_branch_op[4] & ds_rs1_lt_rs2u}} & (ds_pc + ds_imm) ) + | ({32{ds_branch_op[5] & !ds_rs1_lt_rs2u}} & (ds_pc + ds_imm) ); + assign ds_br_taken = ds_jump_op[0] + | ds_jump_op[1] + | (ds_branch_op[0] & ds_rs1_eq_rs2 ) + | (ds_branch_op[1] & !ds_rs1_eq_rs2 ) + | (ds_branch_op[2] & ds_rs1_lt_rs2 ) + | (ds_branch_op[3] & !ds_rs1_lt_rs2 ) + | (ds_branch_op[4] & ds_rs1_lt_rs2u) + | (ds_branch_op[5] & !ds_rs1_lt_rs2u); + + assign fs_to_ds_bus_ready_o = !fs_to_ds_bus_valid || (ds_to_es_bus_valid && ds_to_es_bus_ready_i); + assign ds_to_es_bus_valid_o = fs_to_ds_bus_valid && ds_to_es_bus_valid; + + assign br_flush_o = fs_to_ds_bus_valid && ds_br_taken && !ds_pipeline_stall; + assign load_stall_o = fs_to_ds_bus_valid && es_load_use && (ds_op_is_branch || ds_op_is_jump || (ds_op_is_calc && !(ds_op_is_store || ds_op_is_load))) && ((es_fwd_rd != 5'b0) && (es_fwd_rd == ds_rs1 || (es_fwd_rd == ds_rs2))); +endmodule diff --git a/rv_cpu.srcs/sources_1/new/if_stage.v b/rv_cpu.srcs/sources_1/new/if_stage.v new file mode 100644 index 0000000..58333e0 --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/if_stage.v @@ -0,0 +1,146 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/16 19:31:31 +// Design Name: +// Module Name: if_stage +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module if_stage #( + parameter FS_TO_DS_BUS_WIDTH = 65 +) +( + input clk_i, + input rstn_i, + + input br_flush_i, + input csr_flush_i, + input load_stall_i, + input m_ext_stall_i, + input a_ext_stall_i, + + input [31:0] br_target_i, + input br_taken_i, + + input fs_to_ds_bus_ready_i, + output [FS_TO_DS_BUS_WIDTH-1:0] fs_to_ds_bus_data_o, + output fs_to_ds_bus_valid_o, + + output inst_sram_en_o, + output [ 3:0] inst_sram_wen_o, + output [31:0] inst_sram_addr_o, + output [31:0] inst_sram_wdata_o, + input [31:0] inst_sram_rdata_i + ); + + reg pre_fs_to_fs_valid; + reg [31:0] fs_pc; + reg fs_excp_inst_addr_misalign; + + wire fs_pipeline_stall; + wire fs_pipeline_flush; + + wire pre_fs_to_fs_ready; + wire fs_to_ds_bus_valid; + + wire pre_fs_to_fs_valid_internal; + + wire [31:0] fs_next_pc; + + wire [31:0] fs_inst; + + assign fs_pipeline_stall = load_stall_i || m_ext_stall_i || a_ext_stall_i; + assign fs_pipeline_flush = br_flush_i; + + assign fs_inst = inst_sram_rdata_i; + + pre_if_stage inst_pre_if_stage( + .rstn_i (rstn_i), + .pre_fs_to_fs_ready_i (pre_fs_to_fs_ready), + .pre_fs_to_fs_pc_o (fs_next_pc), + .pre_fs_to_fs_valid_o (pre_fs_to_fs_valid_internal), + + .load_stall_i (load_stall_i), + .m_ext_stall_i (m_ext_stall_i), + .a_ext_stall_i (a_ext_stall_i), + + .br_target_i (br_target_i), + .br_taken_i (br_taken_i), + + .fs_pc_i (fs_pc), + + .inst_sram_en_o (inst_sram_en_o), + .inst_sram_wen_o (inst_sram_wen_o), + .inst_sram_addr_o (inst_sram_addr_o), + .inst_sram_data_o (inst_sram_wdata_o) + ); + + assign fs_to_ds_bus_valid = !fs_pipeline_stall; + assign pre_fs_to_fs_ready = !pre_fs_to_fs_valid || (fs_to_ds_bus_valid && fs_to_ds_bus_ready_i); + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + pre_fs_to_fs_valid <= 1'b0; + end + else if (fs_pipeline_flush) begin + pre_fs_to_fs_valid <= 1'b0; + end + else if (pre_fs_to_fs_ready) begin + pre_fs_to_fs_valid <= pre_fs_to_fs_valid_internal; + end + else begin + pre_fs_to_fs_valid <= pre_fs_to_fs_valid; + end + end + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + fs_pc <= 32'h7fff_fffc; + end + else if (pre_fs_to_fs_valid_internal && pre_fs_to_fs_ready) begin + fs_pc <= fs_next_pc; + end + else begin + fs_pc <= fs_pc; + end + end + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + fs_excp_inst_addr_misalign <= 1'b0; + end + else if(pre_fs_to_fs_valid_internal && pre_fs_to_fs_ready) begin + if (fs_next_pc[1:0] != 2'b00) begin + fs_excp_inst_addr_misalign <= 1'b1; + end + else begin + fs_excp_inst_addr_misalign <= 1'b0; + end + end + else begin + fs_excp_inst_addr_misalign <= fs_excp_inst_addr_misalign; + end + end + + assign fs_to_ds_bus_data_o = { + fs_excp_inst_addr_misalign, // 64:64 + fs_inst, // 63:32 + fs_pc // 31:0 + }; + assign fs_to_ds_bus_valid_o = pre_fs_to_fs_valid && fs_to_ds_bus_valid; + +endmodule diff --git a/rv_cpu.srcs/sources_1/new/mem_stage.v b/rv_cpu.srcs/sources_1/new/mem_stage.v new file mode 100644 index 0000000..b58ce16 --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/mem_stage.v @@ -0,0 +1,180 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 10:24:07 +// Design Name: +// Module Name: mem_stage +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module mem_stage #( + parameter ES_TO_MS_BUS_WIDTH = 164, + parameter MS_TO_WS_BUS_WIDTH = 70, + parameter MS_TO_DS_FWD_BUS_WIDTH = 38 +)( + input clk_i, + input rstn_i, + + input csr_flush_i, + + output es_to_ms_bus_ready_o, + input [ES_TO_MS_BUS_WIDTH-1:0] es_to_ms_bus_data_i, + input es_to_ms_bus_valid_i, + + input ms_to_ws_bus_ready_i, + output [MS_TO_WS_BUS_WIDTH-1:0] ms_to_ws_bus_data_o, + output ms_to_ws_bus_valid_o, + + input [ 31:0] data_sram_rdata_i, + output data_sram_en_o, + output [ 3:0] data_sram_wen_o, + output [31:0] data_sram_addr_o, + output [31:0] data_sram_wdata_o, + + output a_ext_stall_o, + // fowarding bus to ID stage + output [MS_TO_DS_FWD_BUS_WIDTH-1:0] ms_to_ds_fwd_bus_data_o + ); + + reg es_to_ms_bus_valid; + reg [ES_TO_MS_BUS_WIDTH-1:0] es_to_ms_bus_data; + + wire ms_to_ws_bus_valid; + + wire [ 2:0] ms_result_sel; + wire [ 31:0] ms_es_result; + wire [ 31:0] ms_calc_src2; + wire [ 31:0] ms_calc_src1; + wire [ 11:0] ms_amo_op; + wire [ 5:0] ms_load_op; + wire [ 4:0] ms_rd; + wire [ 4:0] ms_rs2; + wire [ 4:0] ms_rs1; + wire [ 31:0] ms_pc; + + wire [ 31:0] ms_lb_result; + wire [ 31:0] ms_lh_result; + wire [ 31:0] ms_lw_result; + + wire [ 31:0] ms_load_result; + wire [ 31:0] ms_amo_result; + wire [ 31:0] ms_result; + + wire [ 31:0] ms_rf_wdata; + wire [ 4:0] ms_rf_waddr; + wire ms_rf_we; + + assign { + ms_result_sel, // 163:161 (3 bits) + ms_es_result, // 160:129 (32 bits) + ms_calc_src2, // 128:97 (32 bits) + ms_calc_src1, // 96:65 (32 bits) + ms_amo_op, // 64:53 (12 bits) + ms_load_op, // 52:47 (6 bits) + ms_rd, // 46:42 (5 bits) + ms_rs2, // 41:37 (5 bits) + ms_rs1, // 36:32 (5 bits) + ms_pc // 31:0 (32 bits) + } = es_to_ms_bus_data; + + assign ms_to_ws_bus_valid = 1'b1; + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + es_to_ms_bus_valid <= 1'b0; + end + else if (csr_flush_i) begin + es_to_ms_bus_valid <= 1'b0; + end + else if (es_to_ms_bus_ready_o) begin + es_to_ms_bus_valid <= es_to_ms_bus_valid_i; + end + else begin + es_to_ms_bus_valid <= es_to_ms_bus_valid; + end + end + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + es_to_ms_bus_data <= {ES_TO_MS_BUS_WIDTH{1'b0}}; + end + else if (es_to_ms_bus_valid_i && es_to_ms_bus_ready_o) begin + es_to_ms_bus_data <= es_to_ms_bus_data_i; + end + else begin + es_to_ms_bus_data <= es_to_ms_bus_data; + end + end + + assign ms_lb_result = ({32{(ms_es_result[1:0] == 2'b00)}} & {{24{ms_load_op[0] ? data_sram_rdata_i[ 7] : 1'b0 }}, data_sram_rdata_i[ 7:0 ]}) + | ({32{(ms_es_result[1:0] == 2'b01)}} & {{24{ms_load_op[0] ? data_sram_rdata_i[15] : 1'b0 }}, data_sram_rdata_i[15:8 ]}) + | ({32{(ms_es_result[1:0] == 2'b10)}} & {{24{ms_load_op[0] ? data_sram_rdata_i[23] : 1'b0 }}, data_sram_rdata_i[23:16]}) + | ({32{(ms_es_result[1:0] == 2'b11)}} & {{24{ms_load_op[0] ? data_sram_rdata_i[31] : 1'b0 }}, data_sram_rdata_i[31:24]}); + assign ms_lh_result = ({32{(ms_es_result[1:0] == 2'b00)}} & {{16{ms_load_op[1] ? data_sram_rdata_i[15] : 1'b0 }}, data_sram_rdata_i[15:0 ]}) + | ({32{(ms_es_result[1:0] == 2'b10)}} & {{16{ms_load_op[1] ? data_sram_rdata_i[31] : 1'b0 }}, data_sram_rdata_i[31:16]}); + assign ms_lw_result = data_sram_rdata_i; + + assign ms_load_result = ({32{ms_load_op[0] || ms_load_op[3]}} & ms_lb_result) + | ({32{ms_load_op[1] || ms_load_op[4]}} & ms_lh_result) + | ({32{ms_load_op[2] }} & ms_lw_result); + assign ms_amo_result = data_sram_rdata_i; + + assign ms_result = {32{ms_result_sel[0]}} & ms_es_result + | {32{ms_result_sel[1]}} & ms_load_result + | {32{ms_result_sel[2]}} & ms_amo_result; + + assign ms_rf_wdata = ms_result; + assign ms_rf_waddr = ms_rd; + assign ms_rf_we = es_to_ms_bus_valid && |ms_result_sel; + + assign ms_to_ws_bus_data_o = { + ms_rf_we, // 69:69 + ms_rf_waddr, // 68:64 + ms_rf_wdata, // 63:32 + ms_pc // 31:0 + }; + + assign es_to_ms_bus_ready_o = !es_to_ms_bus_valid || (ms_to_ws_bus_valid && ms_to_ws_bus_ready_i); + assign ms_to_ws_bus_valid_o = es_to_ms_bus_valid && ms_to_ws_bus_valid; + + assign ms_to_ds_fwd_bus_data_o = { + ms_rf_we, // 37:37 + ms_rf_waddr, // 36:32 + ms_rf_wdata // 31:0 + }; + + wire ms_mem_lt_rs2; + wire ms_mem_lt_rs2u; + + assign ms_mem_lt_rs2 = ($signed(data_sram_rdata_i) < $signed(ms_calc_src2)); + assign ms_mem_lt_rs2u = (data_sram_rdata_i < ms_calc_src2); + + assign data_sram_en_o = es_to_ms_bus_valid && (|ms_result_sel || |ms_amo_op[9:0]); + assign data_sram_wen_o = {4{es_to_ms_bus_valid && |ms_amo_op[9:0]}}; + assign data_sram_addr_o = ms_calc_src1; + assign data_sram_wdata_o = {32{ms_amo_op[0]}} & (({32{ ms_mem_lt_rs2u}} & ms_calc_src2) | ({32{!ms_mem_lt_rs2u}} & data_sram_rdata_i)) // inst_amomaxu_w + | {32{ms_amo_op[1]}} & (({32{!ms_mem_lt_rs2u}} & ms_calc_src2) | ({32{ ms_mem_lt_rs2u}} & data_sram_rdata_i)) // inst_amominu_w + | {32{ms_amo_op[2]}} & (({32{ ms_mem_lt_rs2 }} & ms_calc_src2) | ({32{!ms_mem_lt_rs2 }} & data_sram_rdata_i)) // inst_amomax_w + | {32{ms_amo_op[3]}} & (({32{!ms_mem_lt_rs2 }} & ms_calc_src2) | ({32{ ms_mem_lt_rs2 }} & data_sram_rdata_i)) // inst_amomin_w + | {32{ms_amo_op[4]}} & (data_sram_rdata_i | ms_calc_src2) // inst_amoor_w + | {32{ms_amo_op[5]}} & (data_sram_rdata_i & ms_calc_src2) // inst_amoand_w + | {32{ms_amo_op[6]}} & (data_sram_rdata_i ^ ms_calc_src2) // inst_amoxor_w + | {32{ms_amo_op[7]}} & (data_sram_rdata_i + ms_calc_src2) // inst_amoadd_w + | {32{ms_amo_op[8]}} & (ms_calc_src2) // inst_amoswap_w + | {32{ms_amo_op[9]}} & (ms_calc_src2); // inst_sc_w + + assign a_ext_stall_o = ms_to_ws_bus_valid && |ms_amo_op; +endmodule diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/alu.v b/rv_cpu.srcs/sources_1/new/sub_unit/alu.v new file mode 100644 index 0000000..9deda56 --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/alu.v @@ -0,0 +1,116 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 00:11:46 +// Design Name: +// Module Name: alu +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module alu( + input [10:0] alu_op_i , + input [31:0] alu_src1_i , + input [31:0] alu_src2_i , + + output [31:0] alu_result_o + ); + wire op_lui; + wire op_add; + wire op_sub; + wire op_or; + wire op_slt; + wire op_sltu; + wire op_xor; + wire op_and; + wire op_sll; + wire op_srl; + wire op_sra; + + assign { + op_lui, + op_add, + op_sub, + op_slt, + op_sltu, + op_xor, + op_or, + op_and, + op_sll, + op_srl, + op_sra + } = alu_op_i; + + + wire [31:0] lui_result; + wire [31:0] add_sub_result; + wire [31:0] slt_result; + wire [31:0] sltu_result; + wire [31:0] xor_result; + wire [31:0] or_result; + wire [31:0] and_result; + wire [31:0] sll_result; + wire [31:0] sr64_result; + wire [31:0] sr_result; + + // 32-bit adder + wire [31:0] adder_a; + wire [31:0] adder_b; + wire adder_cin; + wire [31:0] adder_result; + wire adder_cout; + + assign adder_a = alu_src1_i; + assign adder_b = (op_sub | op_slt | op_sltu) ? ~alu_src2_i : alu_src2_i; + assign adder_cin = (op_sub | op_slt | op_sltu) ? 1'b1 : 1'b0; + assign {adder_cout, adder_result} = adder_a + adder_b + adder_cin; + + // ADD, SUB result + assign add_sub_result = adder_result; + + // SLT result + assign slt_result[31:1] = 31'b0; + assign slt_result[0] = (alu_src1_i[31] & ~alu_src2_i[31]) + | ((alu_src1_i[31] ~^ alu_src2_i[31]) & adder_result[31]); + + // SLTU result + assign sltu_result[31:1] = 31'b0; + assign sltu_result[0] = ~adder_cout; + + // bitwise operation + assign or_result = alu_src1_i | alu_src2_i; + assign and_result = alu_src1_i & alu_src2_i; + assign xor_result = alu_src1_i ^ alu_src2_i; + assign lui_result = alu_src2_i; + + // SLL result + assign sll_result = alu_src1_i << alu_src2_i[4:0]; + + // SRL, SRA result + assign sr64_result = {{32{op_sra & alu_src1_i[31]}}, alu_src1_i[31:0]} >> alu_src2_i[4:0]; + + assign sr_result = sr64_result[31:0]; + + // final result mux + assign alu_result_o = ({32{op_add|op_sub}} & add_sub_result) + | ({32{op_slt }} & slt_result) + | ({32{op_sltu }} & sltu_result) + | ({32{op_or }} & or_result) + | ({32{op_xor }} & xor_result) + | ({32{op_and }} & and_result) + | ({32{op_lui }} & lui_result) + | ({32{op_sll }} & sll_result) + | ({32{op_srl|op_sra}} & sr_result); +endmodule diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/csr/csr_reg_file.v b/rv_cpu.srcs/sources_1/new/sub_unit/csr/csr_reg_file.v new file mode 100644 index 0000000..3954f8c --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/csr/csr_reg_file.v @@ -0,0 +1,387 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/19 09:13:42 +// Design Name: +// Module Name: csr_csr_reg_file +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module csr_reg_file( + input clk_i, + input rstn_i, + + input csr_pc_i, + input csr_inst_i, + + input [ 2:0] csr_op_i, + input [11:0] csr_addr_i, + input [31:0] csr_wdata_i, + output [31:0] csr_rdata_o, + input [ 4:0] csr_intr_vec_i, + input [31:0] csr_excp_vec_i, + + output [ 1:0] csr_mpp_o, + + output csr_taken_o, + output [31:0] csr_target_o + ); + + reg [31:0] csr_mstatus_reg; // 0x300 + reg [31:0] csr_misa_reg; // 0x301 + reg [31:0] csr_medeleg_reg; // 0x302 not used + reg [31:0] csr_mideleg_reg; // 0x303 not used + reg [31:0] csr_mie_reg; // 0x304 + reg [31:0] csr_mtvec_reg; // 0x305 + reg [31:0] csr_mcounteren_reg; // 0x306 not used + reg [31:0] csr_medelegh_reg; // 0x312 not used + reg [31:0] csr_mepc_reg; // 0x341 + reg [31:0] csr_mcause_reg; // 0x342 + reg [31:0] csr_mtval_reg; // 0x343 + reg [31:0] csr_mip_reg; // 0x344 + reg [31:0] csr_mscratch_reg; // 0x340 + + reg [31:0] csr_pmpcfg0_reg; // 0x3A0 not used + reg [31:0] csr_pmpcfg1_reg; // 0x3A1 not used + reg [31:0] csr_pmpcfg2_reg; // 0x3A2 not used + reg [31:0] csr_pmpcfg3_reg; // 0x3A3 not used + reg [31:0] csr_pmpcfg4_reg; // 0x3A4 not used + reg [31:0] csr_pmpcfg5_reg; // 0x3A5 not used + reg [31:0] csr_pmpcfg6_reg; // 0x3A6 not used + reg [31:0] csr_pmpcfg7_reg; // 0x3A7 not used + reg [31:0] csr_pmpcfg8_reg; // 0x3A8 not used + reg [31:0] csr_pmpcfg9_reg; // 0x3A9 not used + reg [31:0] csr_pmpcfg10_reg; // 0x3AA not used + reg [31:0] csr_pmpcfg11_reg; // 0x3AB not used + reg [31:0] csr_pmpcfg12_reg; // 0x3AC not used + reg [31:0] csr_pmpcfg13_reg; // 0x3AD not used + reg [31:0] csr_pmpcfg14_reg; // 0x3AE not used + reg [31:0] csr_pmpcfg15_reg; // 0x3AF not used + reg [31:0] csr_pmpaddr0_reg; // 0x3B0 not used + reg [31:0] csr_pmpaddr1_reg; // 0x3B1 not used + reg [31:0] csr_pmpaddr2_reg; // 0x3B2 not used + reg [31:0] csr_pmpaddr3_reg; // 0x3B3 not used + reg [31:0] csr_pmpaddr4_reg; // 0x3B4 not used + reg [31:0] csr_pmpaddr5_reg; // 0x3B5 not used + reg [31:0] csr_pmpaddr6_reg; // 0x3B6 not used + reg [31:0] csr_pmpaddr7_reg; // 0x3B7 not used + reg [31:0] csr_pmpaddr8_reg; // 0x3B8 not used + reg [31:0] csr_pmpaddr9_reg; // 0x3B9 not used + reg [31:0] csr_pmpaddr10_reg; // 0x3BA not used + reg [31:0] csr_pmpaddr11_reg; // 0x3BB not used + reg [31:0] csr_pmpaddr12_reg; // 0x3BC not used + reg [31:0] csr_pmpaddr13_reg; // 0x3BD not used + reg [31:0] csr_pmpaddr14_reg; // 0x3BE not used + reg [31:0] csr_pmpaddr15_reg; // 0x3BF not used + reg [31:0] csr_pmpaddr16_reg; // 0x3C0 not used + reg [31:0] csr_pmpaddr17_reg; // 0x3C1 not used + reg [31:0] csr_pmpaddr18_reg; // 0x3C2 not used + reg [31:0] csr_pmpaddr19_reg; // 0x3C3 not used + reg [31:0] csr_pmpaddr20_reg; // 0x3C4 not used + reg [31:0] csr_pmpaddr21_reg; // 0x3C5 not used + reg [31:0] csr_pmpaddr22_reg; // 0x3C6 not used + reg [31:0] csr_pmpaddr23_reg; // 0x3C7 not used + reg [31:0] csr_pmpaddr24_reg; // 0x3C8 not used + reg [31:0] csr_pmpaddr25_reg; // 0x3C9 not used + reg [31:0] csr_pmpaddr26_reg; // 0x3CA not used + reg [31:0] csr_pmpaddr27_reg; // 0x3CB not used + reg [31:0] csr_pmpaddr28_reg; // 0x3CC not used + reg [31:0] csr_pmpaddr29_reg; // 0x3CD not used + reg [31:0] csr_pmpaddr30_reg; // 0x3CE not used + reg [31:0] csr_pmpaddr31_reg; // 0x3CF not used + reg [31:0] csr_pmpaddr32_reg; // 0x3D0 not used + reg [31:0] csr_pmpaddr33_reg; // 0x3D1 not used + reg [31:0] csr_pmpaddr34_reg; // 0x3D2 not used + reg [31:0] csr_pmpaddr35_reg; // 0x3D3 not used + reg [31:0] csr_pmpaddr36_reg; // 0x3D4 not used + reg [31:0] csr_pmpaddr37_reg; // 0x3D5 not used + reg [31:0] csr_pmpaddr38_reg; // 0x3D6 not used + reg [31:0] csr_pmpaddr39_reg; // 0x3D7 not used + reg [31:0] csr_pmpaddr40_reg; // 0x3D8 not used + reg [31:0] csr_pmpaddr41_reg; // 0x3D9 not used + reg [31:0] csr_pmpaddr42_reg; // 0x3DA not used + reg [31:0] csr_pmpaddr43_reg; // 0x3DB not used + reg [31:0] csr_pmpaddr44_reg; // 0x3DC not used + reg [31:0] csr_pmpaddr45_reg; // 0x3DD not used + reg [31:0] csr_pmpaddr46_reg; // 0x3DE not used + reg [31:0] csr_pmpaddr47_reg; // 0x3DF not used + reg [31:0] csr_pmpaddr48_reg; // 0x3E0 not used + reg [31:0] csr_pmpaddr49_reg; // 0x3E1 not used + reg [31:0] csr_pmpaddr50_reg; // 0x3E2 not used + reg [31:0] csr_pmpaddr51_reg; // 0x3E3 not used + reg [31:0] csr_pmpaddr52_reg; // 0x3E4 not used + reg [31:0] csr_pmpaddr53_reg; // 0x3E5 not used + reg [31:0] csr_pmpaddr54_reg; // 0x3E6 not used + reg [31:0] csr_pmpaddr55_reg; // 0x3E7 not used + reg [31:0] csr_pmpaddr56_reg; // 0x3E8 not used + reg [31:0] csr_pmpaddr57_reg; // 0x3E9 not used + reg [31:0] csr_pmpaddr58_reg; // 0x3EA not used + reg [31:0] csr_pmpaddr59_reg; // 0x3EB not used + reg [31:0] csr_pmpaddr60_reg; // 0x3EC not used + reg [31:0] csr_pmpaddr61_reg; // 0x3ED not used + reg [31:0] csr_pmpaddr62_reg; // 0x3EE not used + reg [31:0] csr_pmpaddr63_reg; // 0x3EF not used + + reg [31:0] csr_rdata_internal; + + wire csr_we; + + wire excp_inst_addr_misalign; + wire excp_inst_access_fault; // not used + wire excp_illegal_inst; + wire excp_breakpoint; + wire excp_load_addr_misalign; // hardware solved + wire excp_load_access_fault; // not used + wire excp_store_addr_misalign; // hardware solved + wire excp_store_access_fault; // not used + wire excp_env_call_from_u; // not used + wire excp_env_call_from_s; + wire excp_reserved_code_10; // reserved + wire excp_env_call_from_m; + wire excp_inst_page_fault; // not used + wire excp_load_page_fault; // not used + wire excp_reserved_code_14; // reserved + wire excp_store_page_fault; // not used + wire [15:0] excp_reserved; // reserved + + wire [31:0] csr_wdata_internal; + wire csr_excp; + wire [ 4:0] csr_excp_code; + + wire csr_mstatus_uie; + wire csr_mstatus_sie; + wire csr_mstatus_mie; + wire csr_mstatus_upie; + wire csr_mstatus_spie; + wire csr_mstatus_mpie; + wire csr_mstatus_spp; + wire [1:0] csr_mstatus_mpp; + wire [1:0] csr_mstatus_fs; + wire [1:0] csr_mstatus_xs; + wire csr_mstatus_mprv; + wire csr_mstatus_sum; + wire csr_mstatus_mxr; + wire csr_mstatus_tvm; + wire csr_mstatus_tw; + wire csr_mstatus_tsr; + wire csr_mstatus_sd; + + assign csr_we = (csr_op_i[0] ) // read & write + || (csr_op_i[1] && (|csr_wdata_i)) // if wdata == 0, only read + || (csr_op_i[2] && (|csr_wdata_i)); // if wdata == 0, only read + + assign { + excp_reserved, + excp_store_page_fault, + excp_reserved_code_14, + excp_load_page_fault, + excp_inst_page_fault, + excp_reserved_code_10, + excp_env_call_from_m, + excp_env_call_from_s, + excp_env_call_from_u, + excp_store_access_fault, + excp_store_addr_misalign, + excp_load_access_fault, + excp_load_addr_misalign, + excp_breakpoint, + excp_illegal_inst, + excp_inst_access_fault, + excp_inst_addr_misalign + } = csr_excp_vec_i; + + assign csr_mstatus_uie = csr_mstatus_reg[ 0]; // not used in current design + assign csr_mstatus_sie = csr_mstatus_reg[ 1]; + assign csr_mstatus_mie = csr_mstatus_reg[ 3]; + assign csr_mstatus_upie = csr_mstatus_reg[ 4]; // not used in current design + assign csr_mstatus_spie = csr_mstatus_reg[ 5]; + assign csr_mstatus_mpie = csr_mstatus_reg[ 7]; + assign csr_mstatus_spp = csr_mstatus_reg[ 8]; + assign csr_mstatus_mpp = csr_mstatus_reg[12:11]; + assign csr_mstatus_fs = csr_mstatus_reg[14:13]; // not used in current design + assign csr_mstatus_xs = csr_mstatus_reg[16:15]; // not used in current design + assign csr_mstatus_mprv = csr_mstatus_reg[17]; // not used in current design + assign csr_mstatus_sum = csr_mstatus_reg[18]; + assign csr_mstatus_mxr = csr_mstatus_reg[19]; + assign csr_mstatus_tvm = csr_mstatus_reg[20]; + assign csr_mstatus_tw = csr_mstatus_reg[21]; // not used in current design + assign csr_mstatus_tsr = csr_mstatus_reg[22]; + assign csr_mstatus_sd = csr_mstatus_reg[31]; // not used in current design + + assign csr_wdata_internal = {32{csr_op_i[0]}} & csr_wdata_i + | {32{csr_op_i[1]}} & (csr_rdata_internal | csr_wdata_i) + | {32{csr_op_i[2]}} & (csr_rdata_internal & ~csr_wdata_i); + + assign csr_excp = |csr_excp_vec_i; + + // csr read logic + always @(*) begin + case (csr_addr_i) + // 0x300-0x3FF Standard read/write + 12'h300: begin // mstatus + csr_rdata_internal = csr_mstatus_reg; + end + 12'h301: begin // misa + csr_rdata_internal = csr_misa_reg; + end + 12'h304: begin // mie + csr_rdata_internal = csr_mie_reg; + end + 12'h305: begin // mtvec + csr_rdata_internal = csr_mtvec_reg; + end + 12'h340: begin // mscratch + csr_rdata_internal = csr_mscratch_reg; + end + 12'h341: begin // mepc + csr_rdata_internal = csr_mepc_reg; + end + 12'h342: begin // mcause + csr_rdata_internal = csr_mcause_reg; + end + 12'h343: begin // mtval + csr_rdata_internal = csr_mtval_reg; + end + 12'h344: begin // mip + csr_rdata_internal = csr_mip_reg; + end + default: begin + csr_rdata_internal = 32'b0; + end + endcase + end + + onehot32_to_hex5_decoder inst_onehot32_to_hex5_decoder( + .onehot_i (csr_excp_vec_i), + .hex_o (csr_excp_code) + ); + + // csr write logic + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + // Reset mstatus: MPP is set to M-mode (2'b11 at bits 12:11), other fields are typically 0. + // 32'h00001800 corresponds to: + // MPP (bits 12:11) = 2'b11 (Machine mode) + // All other implemented bits are 0. + // For RV32, SD bit (bit 31) is 0. FS and XS fields (bits 14:13, 16:15) are 0 (initial/dirty). + csr_mstatus_reg <= 32'h0000_1800; + //csr_misa_reg <= 32'h4000_1101; // RV32IMA + csr_misa_reg <= 32'h4040_1101; // test only + csr_mie_reg <= 32'b0; + csr_mtvec_reg <= 32'b0; + csr_mscratch_reg <= 32'b0; + csr_mepc_reg <= 32'b0; + csr_mcause_reg <= 32'b0; + csr_mtval_reg <= 32'b0; + csr_mip_reg <= 32'b0; + end + else if(csr_excp) begin + csr_mstatus_reg <= { + csr_mstatus_sd, + 8'b0, // reserved + csr_mstatus_tsr, + csr_mstatus_tw, + csr_mstatus_tvm, + csr_mstatus_mxr, + csr_mstatus_sum, + csr_mstatus_mprv, + csr_mstatus_xs, + csr_mstatus_fs, + 2'b11, // MPP (bits 12:11) set to M-mode (2'b11) + 2'b0, // reserved + csr_mstatus_spp, // Bit 8 (SPP, typically unchanged or reflects S-mode if coming from S) + csr_mstatus_mie, // MPIE (bit 7) gets the old MIE (bit 3) value + 1'b0, // reserved + csr_mstatus_spie, + csr_mstatus_upie, + 1'b0, // MIE (bit 3) is cleared + 1'b0, // reserved + csr_mstatus_sie, + csr_mstatus_uie + }; + csr_mepc_reg <= csr_pc_i; + csr_mcause_reg <= {1'b0, 26'b0, csr_excp_code}; // {excp_sign, reserved, excp_code} + csr_mtval_reg <= {32{excp_inst_addr_misalign}} & csr_pc_i + | {32{excp_illegal_inst }} & csr_inst_i + | {32{excp_breakpoint }} & 32'b0 + | {32{excp_env_call_from_m }} & 32'b0; + end + else begin + case({32{csr_we}} & csr_addr_i) + // 0x300-0x3FF Standard read/write + 12'h300: begin // mstatus + csr_mstatus_reg <= { + csr_mstatus_sd, // read-only + 8'b0, // reserved + csr_wdata_internal[22], // TSR + csr_mstatus_tw, // not used + csr_wdata_internal[20], // TVM + csr_wdata_internal[19], // MXR + csr_wdata_internal[18], // SUM + csr_mstatus_mprv, // not used + csr_mstatus_xs, // not used + csr_mstatus_fs, // not used + csr_wdata_internal[12:11], // MPP + 2'b0, // reserved + csr_wdata_internal[8], // SPP + csr_wdata_internal[7], // MPIE + 1'b0, // reserved + csr_wdata_internal[5], // SPIE + csr_mstatus_upie, // not used + csr_wdata_internal[3], // MIE + 1'b0, // reserved + csr_wdata_internal[1], // SIE + csr_mstatus_uie // not used + }; // WARL + end + 12'h301: begin // misa + csr_misa_reg <= {2'b01, 4'b0, 13'b0, csr_wdata_internal[12], 3'b0, csr_wdata_internal[8], 7'b0, csr_wdata_internal[0]}; // WARL + end + 12'h304: begin // mie + csr_mie_reg <= csr_wdata_internal; + end + 12'h305: begin // mtvec + csr_mtvec_reg <= csr_wdata_internal; + end + 12'h340: begin // mscratch + csr_mscratch_reg <= csr_wdata_internal; + end + 12'h341: begin // mepc + csr_mepc_reg <= csr_wdata_internal; + end + 12'h342: begin // mcause + csr_mcause_reg <= csr_wdata_internal; + end + 12'h343: begin // mtval + csr_mtval_reg <= csr_wdata_internal; + end + 12'h344: begin // mip + csr_mip_reg <= csr_wdata_internal; + end + default: begin + // do nothing + end + endcase + end + end + + assign csr_mpp_o = csr_mstatus_mpp; + + assign csr_taken_o = csr_excp; + assign csr_target_o = csr_mtvec_reg; + + assign csr_rdata_o = csr_rdata_internal; +endmodule diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/csr/onehot32_to_hex5_decoder.v b/rv_cpu.srcs/sources_1/new/sub_unit/csr/onehot32_to_hex5_decoder.v new file mode 100644 index 0000000..aeaec5a --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/csr/onehot32_to_hex5_decoder.v @@ -0,0 +1,31 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/21 15:47:30 +// Design Name: +// Module Name: onehot_i32_to_hex_o5_decoder +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + +module onehot32_to_hex5_decoder ( + input [31:0] onehot_i, + output [ 4:0] hex_o +); + assign hex_o[0] = |(onehot_i & 32'haaaa_aaaa); + assign hex_o[1] = |(onehot_i & 32'hcccc_cccc); + assign hex_o[2] = |(onehot_i & 32'hf0f0_f0f0); + assign hex_o[3] = |(onehot_i & 32'hff00_ff00); + assign hex_o[4] = |(onehot_i & 32'hffff_0000); +endmodule diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/csr_reg_file.v b/rv_cpu.srcs/sources_1/new/sub_unit/csr_reg_file.v new file mode 100644 index 0000000..005e3bb --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/csr_reg_file.v @@ -0,0 +1,266 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/19 09:13:42 +// Design Name: +// Module Name: csr_csr_reg_file +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module csr_reg_file( + input clk_i, + input rstn_i, + + input csr_pc_i, + input csr_inst_i, + + input [ 2:0] csr_op_i, + input [11:0] csr_addr_i, + input [31:0] csr_wdata_i, + output [31:0] csr_rdata_o, + input [31:0] csr_excp_vec_i, + + output csr_taken_o, + output [31:0] csr_target_o + ); + + reg [31:0] csr_mstatus_reg; + reg [31:0] csr_mie_reg; + reg [31:0] csr_mtvec_reg; + reg [31:0] csr_mepc_reg; + reg [31:0] csr_mcause_reg; + reg [31:0] csr_mtval_reg; + reg [31:0] csr_mip_reg; + reg [31:0] csr_mscratch_reg; + + reg [31:0] csr_rdata_internal; + + wire csr_re; + wire csr_we; + + wire excp_inst_addr_misalign; + wire excp_inst_access_fault; // not used in current design + wire excp_illegal_inst; + wire excp_breakpoint; + wire excp_load_addr_misalign; // hardware solved + wire excp_load_access_fault; // not used in current design + wire excp_store_addr_misalign; // hardware solved + wire excp_store_access_fault; // not used in current design + wire excp_env_call_from_u; // not used in current design + wire excp_env_call_from_s; // not used in current design + wire excp_reserved_code_10; // not used in current design + wire excp_env_call_from_m; + wire excp_inst_page_fault; // not used in current design + wire excp_load_page_fault; // not used in current design + wire excp_reserved_code_14; // not used in current design + wire excp_store_page_fault; // not used in current design + wire [15:0] excp_reserved; // not used in current design + + wire [31:0] csr_wdata_internal; + wire csr_excp; + wire [ 4:0] csr_excp_code; + + wire csr_mstatus_uie; + wire csr_mstatus_sie; + wire csr_mstatus_mie; + wire csr_mstatus_upie; + wire csr_mstatus_spie; + wire csr_mstatus_mpie; + wire csr_mstatus_spp; + wire [1:0] csr_mstatus_mpp; + wire [1:0] csr_mstatus_fs; + wire [1:0] csr_mstatus_xs; + wire csr_mstatus_mprv; + wire csr_mstatus_sum; + wire csr_mstatus_mxr; + wire csr_mstatus_tvm; + wire csr_mstatus_tw; + wire csr_mstatus_tsr; + wire csr_mstatus_sd; + + assign csr_re = |csr_op_i; + assign csr_we = |csr_op_i; + + assign { + excp_reserved, + excp_store_page_fault, + excp_reserverd_code_14, + excp_load_page_fault, + excp_inst_page_fault, + excp_reserved_code_10, + excp_env_call_from_m, + excp_env_call_from_s, + excp_env_call_from_u, + excp_store_access_fault, + excp_store_addr_misalign, + excp_load_access_fault, + excp_load_addr_misalign, + excp_breakpoint, + excp_illegal_inst, + excp_inst_access_fault, + excp_inst_addr_misalign + } = csr_excp_vec_i; + + assign csr_mstatus_uie = csr_mstatus_reg[ 0]; + assign csr_mstatus_sie = csr_mstatus_reg[ 1]; + assign csr_mstatus_mie = csr_mstatus_reg[ 3]; + assign csr_mstatus_upie = csr_mstatus_reg[ 4]; + assign csr_mstatus_spie = csr_mstatus_reg[ 5]; + assign csr_mstatus_mpie = csr_mstatus_reg[ 7]; + assign csr_mstatus_spp = csr_mstatus_reg[ 8]; + assign csr_mstatus_mpp = csr_mstatus_reg[12:11]; + assign csr_mstatus_fs = csr_mstatus_reg[14:13]; + assign csr_mstatus_xs = csr_mstatus_reg[16:15]; + assign csr_mstatus_mprv = csr_mstatus_reg[17]; + assign csr_mstatus_sum = csr_mstatus_reg[18]; + assign csr_mstatus_mxr = csr_mstatus_reg[19]; + assign csr_mstatus_tvm = csr_mstatus_reg[20]; + assign csr_mstatus_tw = csr_mstatus_reg[21]; + assign csr_mstatus_tsr = csr_mstatus_reg[22]; + assign csr_mstatus_sd = csr_mstatus_reg[31]; + + assign csr_wdata_internal = {32{csr_op_i[0]}} & csr_wdata_i + | {32{csr_op_i[1]}} & (csr_rdata_internal | csr_wdata_i) + | {32{csr_op_i[2]}} & (csr_rdata_internal & ~csr_wdata_i); + + assign csr_excp = |csr_excp_vec_i; + + // csr read logic + always @(*) begin + case (csr_addr_i) + // 0x300-0x3FF Standard read/write + 12'h300: begin // mstatus + csr_rdata_internal = csr_mstatus_reg; + end + 12'h304: begin // mie + csr_rdata_internal = csr_mie_reg; + end + 12'h305: begin // mtvec + csr_rdata_internal = csr_mtvec_reg; + end + 12'h341: begin // mepc + csr_rdata_internal = csr_mepc_reg; + end + 12'h342: begin // mcause + csr_rdata_internal = csr_mcause_reg; + end + 12'h343: begin // mtval + csr_rdata_internal = csr_mtval_reg; + end + 12'h344: begin // mip + csr_rdata_internal = csr_mip_reg; + end + 12'h340: begin // mscratch + csr_rdata_internal = csr_mscratch_reg; + end + default: begin + csr_rdata_internal = 32'b0; + end + endcase + end + + onehot32_to_hex5_decoder inst_onehot32_to_hex5_decoder( + .onehot_i (csr_excp_vec_i), + .hex_o (csr_excp_code) + ); + + // csr write logic + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + // Reset mstatus: MPP is set to M-mode (2'b11 at bits 12:11), other fields are typically 0. + // 32'h00001800 corresponds to: + // MPP (bits 12:11) = 2'b11 (Machine mode) + // All other implemented bits are 0. + // For RV32, SD bit (bit 31) is 0. FS and XS fields (bits 14:13, 16:15) are 0 (initial/dirty). + csr_mstatus_reg <= 32'h00001800; + csr_mie_reg <= 32'b0; + csr_mtvec_reg <= 32'b0; + csr_mepc_reg <= 32'b0; + csr_mcause_reg <= 32'b0; + csr_mtval_reg <= 32'b0; + csr_mip_reg <= 32'b0; + csr_mscratch_reg <= 32'b0; + end + else if(csr_excp) begin + csr_mstatus_reg <= { + csr_mstatus_sd, + csr_mstatus_reg[30:23], // hard wired, keep old value + csr_mstatus_tsr, + csr_mstatus_tw, + csr_mstatus_tvm, + csr_mstatus_mxr, + csr_mstatus_sum, + csr_mstatus_mprv, + csr_mstatus_xs, + csr_mstatus_fs, + 2'b11, // MPP (bits 12:11) set to M-mode (2'b11) + csr_mstatus_reg[10:9], // hard wired, keep old value + csr_mstatus_spp, // Bit 8 (SPP, typically unchanged or reflects S-mode if coming from S) + csr_mstatus_mie, // MPIE (bit 7) gets the old MIE (bit 3) value + csr_mstatus_reg[6], // hard wired, keep old value + csr_mstatus_spie, + csr_mstatus_upie, + 1'b0, // MIE (bit 3) is cleared + csr_mstatus_reg[2], // hard wired, keep old value + csr_mstatus_sie, + csr_mstatus_uie + }; + csr_mepc_reg <= csr_pc_i; + csr_mcause_reg <= {1'b0, 26'b0, csr_excp_code}; // {excp_sign, reserved, excp_code} + csr_mtval_reg <= {32{excp_inst_addr_misalign}} & csr_pc_i + | {32{excp_illegal_inst }} & csr_inst_i + | {32{excp_breakpoint }} & 32'b0 + | {32{excp_env_call_from_m }} & 32'b0; + end + else begin + case({32{csr_we}} & csr_addr_i) + // 0x300-0x3FF Standard read/write + 12'h300: begin // mstatus + csr_mstatus_reg <= csr_wdata_internal; + end + 12'h304: begin // mie + csr_mie_reg <= csr_wdata_internal; + end + 12'h305: begin // mtvec + csr_mtvec_reg <= csr_wdata_internal; + end + 12'h341: begin // mepc + csr_mepc_reg <= csr_wdata_internal; + end + 12'h342: begin // mcause + csr_mcause_reg <= csr_wdata_internal; + end + 12'h343: begin // mtval + csr_mtval_reg <= csr_wdata_internal; + end + 12'h344: begin // mip + csr_mip_reg <= csr_wdata_internal; + end + 12'h340: begin // mscratch + csr_mscratch_reg <= csr_wdata_internal; + end + default: begin + // do nothing + end + endcase + end + end + + assign csr_taken_o = csr_excp; + assign csr_target_o = csr_mtvec_reg; + + assign csr_rdata_o = csr_rdata_internal; +endmodule diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/inst_decoder.v b/rv_cpu.srcs/sources_1/new/sub_unit/inst_decoder.v new file mode 100644 index 0000000..0006f84 --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/inst_decoder.v @@ -0,0 +1,336 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/16 20:10:16 +// Design Name: +// Module Name: inst_decoder +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module inst_decoder( + input [31:0] inst_i, + + output [ 4:0] rs1_o, + output [ 4:0] rs2_o, + output [ 4:0] rd_o, + output [31:0] imm_o, + output [ 4:0] shamt_o, + output [ 3:0] pred_o, // reserved + output [ 3:0] succ_o, // reserved + output [11:0] csr_o, + output [ 4:0] zimm_o, + + output [10:0] alu_op_o, + output [ 3:0] calc_src1_sel_o, + output [ 3:0] calc_src2_sel_o, + + output [ 1:0] jump_op_o, + output [ 5:0] load_op_o, + output [ 2:0] store_op_o, + output [ 5:0] branch_op_o, + + output [ 7:0] m_ext_op_o, + output [ 2:0] csr_op_o, + + output [11:0] amo_op_o, + + output amo_aq_o, // reserved + output amo_rl_o, // reserved + + output excp_illegal_inst_o, + output excp_breakpoint_o, + output excp_env_call_o + ); + + wire [ 7:0] opcode; + wire [ 2:0] funct3; + wire [ 4:0] funct5; + wire [ 6:0] funct7; + + wire [ 1:0] r_type; + wire [ 4:0] i_type; + wire [ 0:0] s_type; + wire [ 0:0] b_type; + wire [ 1:0] u_type; + wire [ 0:0] j_type; + + wire [31:0] i_type_imm; + wire [31:0] s_type_imm; + wire [31:0] b_type_imm; + wire [31:0] u_type_imm; + wire [31:0] j_type_imm; + + wire inst_lui; + wire inst_auipc; + wire inst_jal; + wire inst_jalr; + wire inst_beq; + wire inst_bne; + wire inst_blt; + wire inst_bge; + wire inst_bltu; + wire inst_bgeu; + wire inst_lb; + wire inst_lh; + wire inst_lw; + wire inst_lbu; + wire inst_lhu; + wire inst_sb; + wire inst_sh; + wire inst_sw; + wire inst_addi; + wire inst_slti; + wire inst_sltiu; + wire inst_xori; + wire inst_ori; + wire inst_andi; + wire inst_slli; + wire inst_srli; + wire inst_srai; + wire inst_add; + wire inst_sub; + wire inst_sll; + wire inst_slt; + wire inst_sltu; + wire inst_xor; + wire inst_srl; + wire inst_sra; + wire inst_or; + wire inst_and; + + wire inst_fence; + wire inst_fence_i; + wire inst_ecall; + wire inst_ebreak; + wire inst_mret; // TODO + wire inst_sret; // TODO + wire inst_csrrw; + wire inst_csrrs; + wire inst_csrrc; + wire inst_csrrwi; + wire inst_csrrsi; + wire inst_csrrci; + + wire inst_mul; + wire inst_mulh; + wire inst_mulhsu; + wire inst_mulhu; + wire inst_div; + wire inst_divu; + wire inst_rem; + wire inst_remu; + + wire inst_lr_w; + wire inst_sc_w; + wire inst_amoswap_w; + wire inst_amoadd_w; + wire inst_amoxor_w; + wire inst_amoand_w; + wire inst_amoor_w; + wire inst_amomin_w; + wire inst_amomax_w; + wire inst_amominu_w; + wire inst_amomaxu_w; + + wire calc_src1_is_rs1; + wire calc_src1_is_pc; + wire calc_src1_is_zero; + wire calc_src1_is_zimm; + + wire calc_src2_is_rs2; + wire calc_src2_is_imm; + wire calc_src2_is_4; + + assign opcode = inst_i[6:0]; + assign funct3 = inst_i[14:12]; + assign funct5 = inst_i[31:27]; + assign funct7 = inst_i[31:25]; + + assign r_type = {(opcode == 7'b0101111), (opcode == 7'b0110011)}; + assign i_type = {(opcode == 7'b1110011), (opcode == 7'b0001111), (opcode == 7'b0010011), (opcode == 7'b0000011), (opcode == 7'b1100111)}; + assign s_type = {(opcode == 7'b0100011)}; + assign b_type = {(opcode == 7'b1100011)}; + assign u_type = {(opcode == 7'b0110111), (opcode == 7'b0010111)}; + assign j_type = {(opcode == 7'b1101111)}; + + // basic instructions + assign inst_lui = u_type[1]; + assign inst_auipc = u_type[0]; + assign inst_jal = j_type[0]; + assign inst_jalr = i_type[0]; + assign inst_beq = b_type[0] && (funct3 == 3'b000); + assign inst_bne = b_type[0] && (funct3 == 3'b001); + assign inst_blt = b_type[0] && (funct3 == 3'b100); + assign inst_bge = b_type[0] && (funct3 == 3'b101); + assign inst_bltu = b_type[0] && (funct3 == 3'b110); + assign inst_bgeu = b_type[0] && (funct3 == 3'b111); + assign inst_lb = i_type[1] && (funct3 == 3'b000); + assign inst_lh = i_type[1] && (funct3 == 3'b001); + assign inst_lw = i_type[1] && (funct3 == 3'b010); + assign inst_lbu = i_type[1] && (funct3 == 3'b100); + assign inst_lhu = i_type[1] && (funct3 == 3'b101); + assign inst_sb = s_type[0] && (funct3 == 3'b000); + assign inst_sh = s_type[0] && (funct3 == 3'b001); + assign inst_sw = s_type[0] && (funct3 == 3'b010); + assign inst_addi = i_type[2] && (funct3 == 3'b000); + assign inst_slti = i_type[2] && (funct3 == 3'b010); + assign inst_sltiu = i_type[2] && (funct3 == 3'b011); + assign inst_xori = i_type[2] && (funct3 == 3'b100); + assign inst_ori = i_type[2] && (funct3 == 3'b110); + assign inst_andi = i_type[2] && (funct3 == 3'b111); + assign inst_slli = i_type[2] && (funct3 == 3'b001) && (funct7 == 7'b0000000); + assign inst_srli = i_type[2] && (funct3 == 3'b101) && (funct7 == 7'b0000000); + assign inst_srai = i_type[2] && (funct3 == 3'b101) && (funct7 == 7'b0100000); + assign inst_add = r_type[0] && (funct3 == 3'b000) && (funct7 == 7'b0000000); + assign inst_sub = r_type[0] && (funct3 == 3'b000) && (funct7 == 7'b0100000); + assign inst_sll = r_type[0] && (funct3 == 3'b001) && (funct7 == 7'b0000000); + assign inst_slt = r_type[0] && (funct3 == 3'b010) && (funct7 == 7'b0000000); + assign inst_sltu = r_type[0] && (funct3 == 3'b011) && (funct7 == 7'b0000000); + assign inst_xor = r_type[0] && (funct3 == 3'b100) && (funct7 == 7'b0000000); + assign inst_srl = r_type[0] && (funct3 == 3'b101) && (funct7 == 7'b0000000); + assign inst_sra = r_type[0] && (funct3 == 3'b101) && (funct7 == 7'b0100000); + assign inst_or = r_type[0] && (funct3 == 3'b110) && (funct7 == 7'b0000000); + assign inst_and = r_type[0] && (funct3 == 3'b111) && (funct7 == 7'b0000000); + + // csr instructions + assign inst_fence = i_type[3] && (funct3 == 3'b000); + assign inst_fence_i = i_type[3] && (funct3 == 3'b001); + assign inst_ecall = i_type[4] && (funct3 == 3'b000) && (funct7 == 7'b0000000); + assign inst_ebreak = i_type[4] && (funct3 == 3'b000) && (funct7 == 7'b0000001); + assign inst_mret = i_type[4] && (funct3 == 3'b000) && (funct7 == 7'b0011000); + assign inst_sret = i_type[4] && (funct3 == 3'b000) && (funct7 == 7'b0011001); + assign inst_csrrw = i_type[4] && (funct3 == 3'b001); + assign inst_csrrs = i_type[4] && (funct3 == 3'b010); + assign inst_csrrc = i_type[4] && (funct3 == 3'b011); + assign inst_csrrwi = i_type[4] && (funct3 == 3'b101); + assign inst_csrrsi = i_type[4] && (funct3 == 3'b110); + assign inst_csrrci = i_type[4] && (funct3 == 3'b111); + + // m_extension instructions + assign inst_mul = r_type[0] && (funct3 == 3'b000) && (funct7 == 7'b0000001); + assign inst_mulh = r_type[0] && (funct3 == 3'b001) && (funct7 == 7'b0000001); + assign inst_mulhsu = r_type[0] && (funct3 == 3'b010) && (funct7 == 7'b0000001); + assign inst_mulhu = r_type[0] && (funct3 == 3'b011) && (funct7 == 7'b0000001); + assign inst_div = r_type[0] && (funct3 == 3'b100) && (funct7 == 7'b0000001); + assign inst_divu = r_type[0] && (funct3 == 3'b101) && (funct7 == 7'b0000001); + assign inst_rem = r_type[0] && (funct3 == 3'b110) && (funct7 == 7'b0000001); + assign inst_remu = r_type[0] && (funct3 == 3'b111) && (funct7 == 7'b0000001); + + // a_extension instructions + assign inst_lr_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b00010); + assign inst_sc_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b00011); + assign inst_amoswap_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b00001); + assign inst_amoadd_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b00000); + assign inst_amoxor_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b00100); + assign inst_amoand_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b01100); + assign inst_amoor_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b01000); + assign inst_amomin_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b10000); + assign inst_amomax_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b10100); + assign inst_amominu_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b11000); + assign inst_amomaxu_w = r_type[1] && (funct3 == 3'b010) && (funct5 == 5'b11100); + + + assign i_type_imm = {{20{inst_i[31]}}, inst_i[31:20]}; + assign s_type_imm = {{20{inst_i[31]}}, inst_i[31:25], inst_i[11:7]}; + assign b_type_imm = {{20{inst_i[31]}}, inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0}; + assign u_type_imm = {inst_i[31:12], 12'b0}; + assign j_type_imm = {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0}; + + assign calc_src1_is_rs1 = inst_lb | inst_lh | inst_lw | inst_lbu | inst_lhu | inst_sb | inst_sh | inst_sw + | inst_addi | inst_slti | inst_sltiu | inst_xori | inst_ori | inst_andi + | inst_add | inst_sub | inst_sll | inst_slt | inst_sltu | inst_xor | inst_srl | inst_sra | inst_or | inst_and + | inst_slli | inst_srli | inst_srai + | inst_mul | inst_mulh | inst_mulhsu | inst_mulhu | inst_div | inst_divu | inst_rem | inst_remu + | inst_csrrw | inst_csrrs | inst_csrrc + | inst_lr_w | inst_sc_w + | inst_amoswap_w | inst_amoadd_w | inst_amoxor_w | inst_amoand_w | inst_amoor_w | inst_amomin_w | inst_amomax_w | inst_amominu_w | inst_amomaxu_w; + assign calc_src1_is_pc = inst_auipc | inst_jal | inst_jalr; + assign calc_src1_is_zero = inst_lui; + assign calc_src1_is_zimm = inst_csrrwi | inst_csrrsi | inst_csrrci; + + assign calc_src2_is_rs2 = inst_add | inst_sub | inst_sll | inst_slt | inst_sltu | inst_xor | inst_srl | inst_sra | inst_or | inst_and + | inst_mul | inst_mulh | inst_mulhsu | inst_mulhu | inst_div | inst_divu | inst_rem | inst_remu + | inst_sc_w + | inst_amoswap_w | inst_amoadd_w | inst_amoxor_w | inst_amoand_w | inst_amoor_w | inst_amomin_w | inst_amomax_w | inst_amominu_w | inst_amomaxu_w; + assign calc_src2_is_imm = inst_lui | inst_auipc | inst_lb | inst_lh | inst_lw | inst_lbu | inst_lhu + | inst_sb | inst_sh | inst_sw | inst_addi | inst_slti | inst_sltiu | inst_xori | inst_ori | inst_andi; + assign calc_src2_is_4 = inst_jal | inst_jalr; + assign calc_src2_is_shamt = inst_slli | inst_srli | inst_srai; + + + assign rs1_o = inst_i[19:15]; + assign rs2_o = inst_i[24:20]; + assign rd_o = inst_i[11:7]; + assign imm_o = ({32{|i_type}} & i_type_imm) + | ({32{|s_type}} & s_type_imm) + | ({32{|b_type}} & b_type_imm) + | ({32{|u_type}} & u_type_imm) + | ({32{|j_type}} & j_type_imm); + assign shamt_o = inst_i[24:20]; + assign pred_o = inst_i[27:24]; + assign succ_o = inst_i[23:20]; + assign csr_o = inst_i[31:20]; + assign zimm_o = inst_i[19:15]; + + assign alu_op_o = { + // op_lui + inst_lui, + // op_add + inst_auipc | inst_jal | inst_jalr | inst_lb | inst_lh | inst_lw | inst_lbu | inst_lhu | inst_sb | inst_sh | inst_sw | inst_addi | inst_add, + // op_sub + inst_sub, + // op_slt + inst_slti | inst_slt, + // op_sltu + inst_sltiu | inst_sltu, + // op_xor + inst_xori | inst_xor, + // op_or + inst_ori | inst_or, + // op_and + inst_andi | inst_and, + // op_sll + inst_slli | inst_sll, + // op_srl + inst_srli | inst_srl, + // op_sra + inst_srai | inst_sra + }; + + assign calc_src1_sel_o = {calc_src1_is_zimm, calc_src1_is_zero, calc_src1_is_pc, calc_src1_is_rs1}; + assign calc_src2_sel_o = {calc_src2_is_shamt, calc_src2_is_4, calc_src2_is_imm, calc_src2_is_rs2}; + + assign jump_op_o = {inst_jalr, inst_jal}; + assign branch_op_o = {inst_bgeu, inst_bltu, inst_bge, inst_blt, inst_bne, inst_beq}; + assign load_op_o = {inst_lhu, inst_lbu, inst_lw, inst_lh, inst_lb}; + assign store_op_o = {inst_sw, inst_sh, inst_sb}; + + assign m_ext_op_o = {inst_mul, inst_mulh, inst_mulhsu, inst_mulhu, inst_div, inst_divu, inst_rem, inst_remu}; + assign csr_op_o = { + inst_csrrci | inst_csrrc, + inst_csrrsi | inst_csrrs, + inst_csrrwi | inst_csrrw + }; + + assign amo_op_o = {1'b0, inst_lr_w, inst_sc_w, inst_amoswap_w, inst_amoadd_w, inst_amoxor_w, inst_amoand_w, inst_amoor_w, inst_amomin_w, inst_amomax_w, inst_amominu_w, inst_amomaxu_w}; + + assign amo_aq_o = inst_i[26]; + assign amo_rl_o = inst_i[25]; + + assign excp_illegal_inst_o = !(r_type || i_type || s_type || b_type || u_type || j_type); + assign excp_breakpoint_o = inst_ebreak; + assign excp_env_call_o = inst_ecall; +endmodule diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/divider.v b/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/divider.v new file mode 100644 index 0000000..9f425aa --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/divider.v @@ -0,0 +1,274 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 23:19:17 +// Design Name: +// Module Name: divider +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + +`define TEST_PROG_DIV_0_NO_CONSIDER_SIGN + +module divider( + // Inputs + input wire clk_i, + input wire rstn_i, + input wire start_i, // Start signal for division + input wire signed_mode_i, // 0 for unsigned, 1 for signed + input wire [31:0] dividend_i, // 被除数 + input wire [31:0] divisor_i, // 除数 + + // Outputs + output reg [31:0] quotient_o, // 商 + output reg [31:0] remainder_o, // 余数 + output reg done_o, // Calculation done signal + output reg busy_o, // Divider is busy + output reg div_by_zero_o // Division by zero error +); + + localparam DATA_WIDTH = 32; + + // FSM States + localparam S_IDLE = 3'd0; // Increased state reg width slightly for safety if more states added + localparam S_PREPARE = 3'd1; + localparam S_DIV_STEP = 3'd2; + localparam S_ADJUST_SIGN = 3'd3; + localparam S_FINISH = 3'd4; + + reg [2:0] current_state_reg; + reg [2:0] next_state_reg; + + // Internal Registers for algorithm + reg [DATA_WIDTH-1:0] dividend_abs_reg; // Holds dividend, then quotient bits are shifted in + reg [DATA_WIDTH-1:0] divisor_abs_reg; // Absolute value of divisor + reg [DATA_WIDTH:0] partial_remainder_reg; // Partial remainder (N+1 bits for subtract sign) + + reg [5:0] iter_count_reg; // Iteration counter (0 to DATA_WIDTH) + + reg original_dividend_sign; + reg original_divisor_sign; + reg is_signed_mode_reg; + reg div_by_zero_flag; + + // Temporary variables for calculations within clocked always block (module scope Verilog regs) + reg [DATA_WIDTH:0] p_shifted_in_A_msb_temp; + reg [DATA_WIDTH:0] subtract_result_temp; + reg new_quotient_bit_temp; + reg [DATA_WIDTH-1:0] final_quotient_temp; + reg [DATA_WIDTH-1:0] final_remainder_temp; + reg quotient_sign_temp; + reg remainder_sign_temp; + + + //-------------------------------------------------------------------------- + // FSM State Register + //-------------------------------------------------------------------------- + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + current_state_reg <= S_IDLE; + end else begin + current_state_reg <= next_state_reg; + end + end + + //-------------------------------------------------------------------------- + // FSM Next State Logic & Combinational Output (done_o) + //-------------------------------------------------------------------------- + always @(*) begin // Verilog-2001 equivalent of always_comb + next_state_reg = current_state_reg; // Default: stay in current state + done_o = 1'b0; // Default done_o to low + + case (current_state_reg) + S_IDLE: begin + if (start_i) begin + next_state_reg = S_PREPARE; + end + end + + S_PREPARE: begin + if (div_by_zero_flag) begin + next_state_reg = S_FINISH; + end else begin + next_state_reg = S_DIV_STEP; + end + end + + S_DIV_STEP: begin + if (iter_count_reg == DATA_WIDTH) begin // Completed N iterations + next_state_reg = S_ADJUST_SIGN; + end else begin + next_state_reg = S_DIV_STEP; // Stay for next iteration + end + end + + S_ADJUST_SIGN: begin + next_state_reg = S_FINISH; + end + + S_FINISH: begin + done_o = 1'b1; // Assert done for one cycle + next_state_reg = S_IDLE; + end + + default: begin + next_state_reg = S_IDLE; + end + endcase + end + + //-------------------------------------------------------------------------- + // Datapath Logic (Sequential - Register Updates) + //-------------------------------------------------------------------------- + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + busy_o <= 1'b0; + div_by_zero_o <= 1'b0; + quotient_o <= {DATA_WIDTH{1'b0}}; + remainder_o <= {DATA_WIDTH{1'b0}}; + + dividend_abs_reg <= {DATA_WIDTH{1'b0}}; + divisor_abs_reg <= {DATA_WIDTH{1'b0}}; + partial_remainder_reg <= {DATA_WIDTH+1{1'b0}}; + iter_count_reg <= 6'd0; + original_dividend_sign <= 1'b0; + original_divisor_sign <= 1'b0; + is_signed_mode_reg <= 1'b0; + div_by_zero_flag <= 1'b0; + + end else begin + // busy_o is set high when IDLE sees start_i and calculation begins + // busy_o is set low when FSM transitions out of S_FINISH (or after done pulse) + if (current_state_reg == S_FINISH && next_state_reg == S_IDLE) begin + busy_o <= 1'b0; + end + + case (current_state_reg) + S_IDLE: begin + if (start_i) begin + busy_o <= 1'b1; + div_by_zero_o <= 1'b0; + quotient_o <= {DATA_WIDTH{1'b0}}; + remainder_o <= {DATA_WIDTH{1'b0}}; + + is_signed_mode_reg <= signed_mode_i; + if (divisor_i == {DATA_WIDTH{1'b0}}) begin + div_by_zero_flag <= 1'b1; + // For div by zero, abs regs don't matter as much, but init them + dividend_abs_reg <= dividend_i; // Store original dividend for remainder + original_dividend_sign <= signed_mode_i ? dividend_i[DATA_WIDTH-1] : 1'b0; + end else begin + div_by_zero_flag <= 1'b0; + if (signed_mode_i) begin + original_dividend_sign <= dividend_i[DATA_WIDTH-1]; + original_divisor_sign <= divisor_i[DATA_WIDTH-1]; + dividend_abs_reg <= (dividend_i[DATA_WIDTH-1]) ? -dividend_i : dividend_i; + divisor_abs_reg <= (divisor_i[DATA_WIDTH-1]) ? -divisor_i : divisor_i; + end else begin + original_dividend_sign <= 1'b0; // Unused for unsigned + original_divisor_sign <= 1'b0; // Unused for unsigned + dividend_abs_reg <= dividend_i; + divisor_abs_reg <= divisor_i; + end + partial_remainder_reg <= {DATA_WIDTH+1{1'b0}}; // P = 0 + iter_count_reg <= 6'd0; + end + end + end // S_IDLE + + S_PREPARE: begin + // This state is mainly for FSM transition; + // actual data loading happens in S_IDLE based on start_i. + // If div_by_zero_flag was set, next_state_reg (combinatorially) points to S_FINISH. + end + + S_DIV_STEP: begin + if (iter_count_reg < DATA_WIDTH) begin + // Temporary variables are calculated based on current reg values + p_shifted_in_A_msb_temp = {partial_remainder_reg[DATA_WIDTH-1:0], dividend_abs_reg[DATA_WIDTH-1]}; + subtract_result_temp = p_shifted_in_A_msb_temp - {1'b0, divisor_abs_reg}; + + if (subtract_result_temp[DATA_WIDTH] == 1'b0) begin // No borrow / P_trial >= 0 + partial_remainder_reg <= subtract_result_temp; // Update P + new_quotient_bit_temp = 1'b1; + end else begin // Borrow / P_trial < 0 + partial_remainder_reg <= p_shifted_in_A_msb_temp; // Restore P + new_quotient_bit_temp = 1'b0; + end + // Shift A (dividend_abs_reg) and place new quotient bit + dividend_abs_reg <= {dividend_abs_reg[DATA_WIDTH-2:0], new_quotient_bit_temp}; + iter_count_reg <= iter_count_reg + 1; + end + end // S_DIV_STEP + + S_ADJUST_SIGN: begin + // Use temporary regs for calculation before assigning to outputs + final_quotient_temp = dividend_abs_reg; // Now contains absolute quotient + final_remainder_temp = partial_remainder_reg[DATA_WIDTH-1:0]; // Lower N bits of P + + if (is_signed_mode_reg) begin + quotient_sign_temp = original_dividend_sign ^ original_divisor_sign; + remainder_sign_temp = original_dividend_sign; // Remainder sign matches dividend + + if (quotient_sign_temp && final_quotient_temp != {DATA_WIDTH{1'b0}}) begin + final_quotient_temp = -final_quotient_temp; + end + if (remainder_sign_temp && final_remainder_temp != {DATA_WIDTH{1'b0}}) begin + final_remainder_temp = -final_remainder_temp; + end + end + // Assign to outputs here, they will be stable when S_FINISH asserts done_o + quotient_o <= final_quotient_temp; + remainder_o <= final_remainder_temp; + end // S_ADJUST_SIGN + + S_FINISH: begin + // Outputs (quotient_o, remainder_o) were assigned in S_ADJUST_SIGN. + // Handle div_by_zero case outputs specifically for this state if they weren't already. + if (div_by_zero_flag) begin + div_by_zero_o <= 1'b1; + // Define output values for division by zero + + `ifdef TEST_PROG_DIV_0_NO_CONSIDER_SIGN + quotient_o <= {DATA_WIDTH{1'b1}}; + remainder_o <= dividend_abs_reg; + `else + if (is_signed_mode_reg) begin + // Example: if dividend was negative -> INT_MIN, else INT_MAX + quotient_o <= (original_dividend_sign) ? {1'b1, {(DATA_WIDTH-1){1'b0}}} : {1'b0, {(DATA_WIDTH-1){1'b1}}}; + end else begin + quotient_o <= {DATA_WIDTH{1'b1}}; // Max unsigned + end + // Remainder for div by zero is often the original dividend. + // dividend_abs_reg was loaded with original dividend_i if div_by_zero was detected early. + // For signed remainder, apply original_dividend_sign. + if (is_signed_mode_reg && original_dividend_sign && dividend_abs_reg != 0) begin + remainder_o <= -dividend_abs_reg; + end else begin + remainder_o <= dividend_abs_reg; // Which was set to dividend_i in S_IDLE for div_by_zero + end + `endif + + end else begin + div_by_zero_o <= 1'b0; + // quotient_o and remainder_o already set by S_ADJUST_SIGN + end + // busy_o will be de-asserted when FSM actually transitions from S_FINISH to S_IDLE + // (handled at the top of the clocked always block) + end // S_FINISH + endcase + end + end + +endmodule \ No newline at end of file diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/m_ext_unit.v b/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/m_ext_unit.v new file mode 100644 index 0000000..e77a60d --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/m_ext_unit.v @@ -0,0 +1,109 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/18 00:30:20 +// Design Name: +// Module Name: m_ext_unit +// Project Name: +// Target Devices: +// Tool Versions: +// Description: Module to encapsulate multiplier and divider units. +// +// Dependencies: multiplier, divider +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + +module m_ext_unit( + // Global Signals + input clk_i, + input rstn_i, + + input [ 7:0] m_ext_op_i, + input [31:0] m_ext_src1_i, + input [31:0] m_ext_src2_i, + + output [31:0] m_ext_result_o, + output m_ext_valid_o, + + output m_ext_stall_o + ); + + reg [ 7:0] m_ext_op; + reg m_ext_valid; + + wire [ 3:0] div_op; + wire [ 4:0] mult_op; + + // Multiplier Interface + wire [63:0] mult_product; + wire mult_done; + wire mult_busy; + + // Divider Interface + wire [31:0] div_quotient; + wire [31:0] div_remainder; + wire div_done; + wire div_busy; + wire div_by_zero; + + assign div_op = m_ext_op_i[3:0]; + assign mult_op = m_ext_op_i[7:4]; + + // Instantiate Multiplier + multiplier u_multiplier ( + .clk_i (clk_i), + .rstn_i (rstn_i), + .start_i (!m_ext_valid && |mult_op), + .signed_mode_i ({mult_op[1], mult_op[2] || mult_op[3]}), + .operand_a_i (m_ext_src1_i), + .operand_b_i (m_ext_src2_i), + .product_o (mult_product), + .done_o (mult_done), + .busy_o (mult_busy) + ); + + // Instantiate Divider + divider u_divider ( + .clk_i (clk_i), + .rstn_i (rstn_i), + .start_i (!m_ext_valid && |div_op), + .signed_mode_i (div_op[1] || div_op[3]), + .dividend_i (m_ext_src1_i), + .divisor_i (m_ext_src2_i), + .quotient_o (div_quotient), + .remainder_o (div_remainder), + .done_o (div_done), + .busy_o (div_busy), + .div_by_zero_o (div_by_zero) + ); + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + m_ext_valid <= 1'b0; + end + else begin + m_ext_valid <= mult_done || div_done; + end + end + + // If any m_ext_op_i bit is set (meaning an operation is requested for the current cycle), + // or if either the multiplier or divider is busy from a previous start, + // then the m_ext_unit should signal stall. + assign m_ext_stall_o = !m_ext_valid && (|m_ext_op_i || mult_busy || div_busy); + assign m_ext_valid_o = m_ext_valid; + assign m_ext_result_o = ({32{m_ext_op_i[7]}} & mult_product[31:0 ]) // MUL + | ({32{m_ext_op_i[6]}} & mult_product[63:32]) // MULH + | ({32{m_ext_op_i[5]}} & mult_product[63:32]) // MULHSU + | ({32{m_ext_op_i[4]}} & mult_product[63:32]) // MULHU + | ({32{m_ext_op_i[3]}} & div_quotient ) // DIV + | ({32{m_ext_op_i[2]}} & div_quotient ) // DIVU + | ({32{m_ext_op_i[1]}} & div_remainder ) // REM + | ({32{m_ext_op_i[0]}} & div_remainder );// REMU + +endmodule diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/multiplier.v b/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/multiplier.v new file mode 100644 index 0000000..eeb35de --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/m_ext_unit/multiplier.v @@ -0,0 +1,231 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 23:37:37 +// Design Name: +// Module Name: multiplier +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module multiplier( + // Inputs + input wire clk_i, + input wire rstn_i, + input wire start_i, // Start signal for multiplication + input wire [ 1:0] signed_mode_i, // 0 for unsigned, 1 for signed + input wire [31:0] operand_a_i, // 32-bit Operand A (Multiplicand) + input wire [31:0] operand_b_i, // 32-bit Operand B (Multiplier) + + // Outputs + output reg [63:0] product_o, // 64-bit Product + output reg done_o, // Calculation done signal + output reg busy_o // Multiplier is busy + // No div_by_zero for multiplier +); + + localparam DATA_WIDTH = 32; + localparam PRODUCT_WIDTH = 64; + + // FSM States + localparam S_IDLE = 3'd0; + localparam S_PREPARE = 3'd1; + localparam S_MULTIPLY_STEP = 3'd2; + localparam S_ADJUST_SIGN = 3'd3; + localparam S_FINISH = 3'd4; + + reg [2:0] current_state_reg, next_state_reg; + + // Internal Registers for algorithm + reg [DATA_WIDTH-1:0] m_reg; // Stores Multiplicand's absolute value + reg [DATA_WIDTH-1:0] q_reg; // Stores Multiplier's absolute value, shifts right + reg [DATA_WIDTH-1:0] acc_reg; // Accumulator for upper part of product + + reg [5:0] iter_count_reg; // Iteration counter (0 to DATA_WIDTH-1) + + reg operand_a_sign_reg; + reg operand_b_sign_reg; + reg [1:0] is_signed_mode_reg_internal; + + // Temporary registers for calculations within clocked always block + reg [DATA_WIDTH:0] adder_result_temp; // Holds {carry, sum} from ACC + M + reg [DATA_WIDTH-1:0] final_prod_abs_q_part_temp; + reg [DATA_WIDTH-1:0] final_prod_abs_acc_part_temp; + + reg [PRODUCT_WIDTH-1:0] final_product_abs; + reg final_product_sign; + + //-------------------------------------------------------------------------- + // FSM State Register + //-------------------------------------------------------------------------- + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + current_state_reg <= S_IDLE; + end else begin + current_state_reg <= next_state_reg; + end + end + + //-------------------------------------------------------------------------- + // FSM Next State Logic & Combinational Output (done_o) + //-------------------------------------------------------------------------- + always @(*) begin // Verilog-2001: sensitive to all RHS signals + next_state_reg = current_state_reg; // Default + done_o = 1'b0; // Default + + case (current_state_reg) + S_IDLE: begin + if (start_i) begin + next_state_reg = S_PREPARE; + end + end + S_PREPARE: begin + next_state_reg = S_MULTIPLY_STEP; + end + S_MULTIPLY_STEP: begin + if (iter_count_reg == DATA_WIDTH - 1) begin // After N iterations (0 to N-1) + next_state_reg = S_ADJUST_SIGN; + end else begin + next_state_reg = S_MULTIPLY_STEP; // Continue iteration + end + end + S_ADJUST_SIGN: begin + next_state_reg = S_FINISH; + end + S_FINISH: begin + done_o = 1'b1; // Assert done for one cycle + next_state_reg = S_IDLE; + end + default: begin + next_state_reg = S_IDLE; + end + endcase + end + + //-------------------------------------------------------------------------- + // Datapath Logic (Sequential - Register Updates) + //-------------------------------------------------------------------------- + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + busy_o <= 1'b0; + product_o <= {PRODUCT_WIDTH{1'b0}}; + + m_reg <= {DATA_WIDTH{1'b0}}; + q_reg <= {DATA_WIDTH{1'b0}}; + acc_reg <= {DATA_WIDTH{1'b0}}; + iter_count_reg <= 6'd0; + + operand_a_sign_reg <= 1'b0; + operand_b_sign_reg <= 1'b0; + is_signed_mode_reg_internal <= 2'b0; + end else begin + // busy_o is set high when IDLE sees start_i + // busy_o is set low when FSM transitions out of S_FINISH + if (current_state_reg == S_FINISH && next_state_reg == S_IDLE) begin + busy_o <= 1'b0; + end + + case (current_state_reg) + S_IDLE: begin + if (start_i) begin + busy_o <= 1'b1; + product_o <= {PRODUCT_WIDTH{1'b0}}; // Clear previous product + + is_signed_mode_reg_internal <= signed_mode_i; + if (signed_mode_i[0]) begin + operand_a_sign_reg <= operand_a_i[DATA_WIDTH-1]; + operand_b_sign_reg <= operand_b_i[DATA_WIDTH-1]; + m_reg <= operand_a_i[DATA_WIDTH-1] ? -operand_a_i : operand_a_i; // Abs A + q_reg <= operand_b_i[DATA_WIDTH-1] ? -operand_b_i : operand_b_i; // Abs B + end + else if(signed_mode_i[1]) begin + operand_a_sign_reg <= operand_a_i[DATA_WIDTH-1]; + operand_b_sign_reg <= 1'b0; // Unused in unsigned mode + m_reg <= operand_a_i[DATA_WIDTH-1] ? -operand_a_i : operand_a_i; // Abs A + q_reg <= operand_b_i; // B is unsigned + end + else begin + operand_a_sign_reg <= 1'b0; // Unused + operand_b_sign_reg <= 1'b0; // Unused + m_reg <= operand_a_i; + q_reg <= operand_b_i; + end + acc_reg <= {DATA_WIDTH{1'b0}}; // ACC = 0 + iter_count_reg <= 6'd0; + end + end // S_IDLE + + S_PREPARE: begin + // Data loading happened in S_IDLE based on start_i. + // This state ensures one cycle for setup before iterations. + end + + S_MULTIPLY_STEP: begin + if (iter_count_reg < DATA_WIDTH) begin + // Calculate ACC + M if Q[0] is 1 + if (q_reg[0] == 1'b1) begin + // {Carry, Sum} = ACC + M + adder_result_temp = {1'b0, acc_reg} + {1'b0, m_reg}; // Zero-extend for N+1 bit sum + end else begin + adder_result_temp = {1'b0, acc_reg}; // ACC + 0 + end + + // Shift right {Carry_from_adder, ACC_from_adder, Q} + // New ACC MSB is carry_from_adder + // New Q MSB is ACC_from_adder LSB + acc_reg <= {adder_result_temp[DATA_WIDTH], adder_result_temp[DATA_WIDTH-1:1]}; + q_reg <= {adder_result_temp[0], q_reg[DATA_WIDTH-1:1]}; + + iter_count_reg <= iter_count_reg + 1; + end + end // S_MULTIPLY_STEP + + S_ADJUST_SIGN: begin + // Iteration complete. {acc_reg, q_reg} is the absolute product. + final_prod_abs_acc_part_temp = acc_reg; + final_prod_abs_q_part_temp = q_reg; + // product_o will be assigned in S_FINISH after sign adjustment + end // S_ADJUST_SIGN + + S_FINISH: begin + final_product_abs = {final_prod_abs_acc_part_temp, final_prod_abs_q_part_temp}; + + // Check for signed multiplication modes + if (is_signed_mode_reg_internal[0]) begin // Mode: operand_a signed, operand_b signed (e.g., MULH) + final_product_sign = operand_a_sign_reg ^ operand_b_sign_reg; + if (final_product_sign && final_product_abs != {PRODUCT_WIDTH{1'b0}}) begin + product_o <= -final_product_abs; // Two's complement + end else begin + product_o <= final_product_abs; + end + end else if (is_signed_mode_reg_internal[1]) begin // Mode: operand_a signed, operand_b unsigned (e.g., MULHSU) + // For MULHSU, only operand_a's sign affects the final product's sign. + // operand_b is treated as unsigned, so its original sign bit (operand_b_sign_reg) is irrelevant here. + final_product_sign = operand_a_sign_reg; // Sign is determined by operand_a only + if (final_product_sign && final_product_abs != {PRODUCT_WIDTH{1'b0}}) begin + product_o <= -final_product_abs; // Two's complement + end else begin + product_o <= final_product_abs; + end + end else begin // Mode: Both unsigned (e.g., MULHU or standard MUL lower part) + product_o <= final_product_abs; + end + // busy_o will be de-asserted when FSM actually transitions from S_FINISH to S_IDLE + end // S_FINISH + endcase + end + end + +endmodule \ No newline at end of file diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/pre_if_stage.v b/rv_cpu.srcs/sources_1/new/sub_unit/pre_if_stage.v new file mode 100644 index 0000000..2f19510 --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/pre_if_stage.v @@ -0,0 +1,67 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/19 20:28:17 +// Design Name: +// Module Name: pre_if_stage +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module pre_if_stage( + input rstn_i, + + input pre_fs_to_fs_ready_i, // no use in this module, cause pre_if_stage is the first stage + output [31:0] pre_fs_to_fs_pc_o, + output pre_fs_to_fs_valid_o, + + input [31:0] fs_pc_i, + + input [31:0] br_target_i, + input br_taken_i, + + input load_stall_i, + input m_ext_stall_i, + input a_ext_stall_i, + + output inst_sram_en_o, + output [ 3:0] inst_sram_wen_o, + output [31:0] inst_sram_addr_o, + output [31:0] inst_sram_data_o + ); + + wire pre_fs_valid; + wire [31:0] pre_fs_next_pc; + + wire pre_fs_pipeline_stall; + + wire [31:0] seq_pc; + + assign pre_fs_pipeline_stall = load_stall_i || m_ext_stall_i || a_ext_stall_i; + + assign seq_pc = fs_pc_i + 4; + assign pre_fs_next_pc = br_taken_i ? br_target_i : + pre_fs_pipeline_stall ? fs_pc_i : + seq_pc; + + assign pre_fs_valid = rstn_i && !pre_fs_pipeline_stall; + assign pre_fs_to_fs_pc_o = pre_fs_next_pc; + assign pre_fs_to_fs_valid_o = pre_fs_valid; + + assign inst_sram_en_o = pre_fs_valid; + assign inst_sram_wen_o = 4'b0000; // Read only + assign inst_sram_addr_o = pre_fs_next_pc; + assign inst_sram_data_o = 32'h00000000; // No write data needed +endmodule diff --git a/rv_cpu.srcs/sources_1/new/sub_unit/reg_file.v b/rv_cpu.srcs/sources_1/new/sub_unit/reg_file.v new file mode 100644 index 0000000..6c76f29 --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/sub_unit/reg_file.v @@ -0,0 +1,63 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 02:15:22 +// Design Name: +// Module Name: reg_file +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module reg_file( + input clk_i, + input rstn_i, + // READ PORT 1 + input [ 4:0] raddr1_i, + output [31:0] rdata1_o, + // READ PORT 2 + input [ 4:0] raddr2_i, + output [31:0] rdata2_o, + // WRITE PORT + input we_i, + input [ 4:0] waddr_i, + input [31:0] wdata_i +); + + reg [31:0] register[31:0]; + integer i = 0; + + //WRITE + always @(posedge clk_i) begin + if (!rstn_i) begin + for(i = 0; i < 32; i = i + 1) begin + register[i] <= 32'b0; + end + end + else if (we_i && (waddr_i != 5'b0)) begin + register[waddr_i]<= wdata_i; + end + end + + //READ OUT 1 + assign rdata1_o = ( raddr1_i == 5'b0 ) ? 32'b0 : + (we_i & (raddr1_i == waddr_i)) ? wdata_i : + register[raddr1_i]; + + //READ OUT 2 + assign rdata2_o = ( raddr2_i == 5'b0 ) ? 32'b0 : + (we_i & (raddr2_i == waddr_i)) ? wdata_i : + register[raddr2_i]; + +endmodule \ No newline at end of file diff --git a/rv_cpu.srcs/sources_1/new/wb_stage.v b/rv_cpu.srcs/sources_1/new/wb_stage.v new file mode 100644 index 0000000..a83cb38 --- /dev/null +++ b/rv_cpu.srcs/sources_1/new/wb_stage.v @@ -0,0 +1,98 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2025/05/17 12:29:36 +// Design Name: +// Module Name: wb_stage +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module wb_stage #( + parameter MS_TO_WS_BUS_WIDTH = 70, + parameter WS_TO_DS_BUS_WIDTH = 38 +)( + input clk_i, + input rstn_i, + + output ms_to_ws_bus_ready_o, + input [MS_TO_WS_BUS_WIDTH-1:0] ms_to_ws_bus_data_i, + input ms_to_ws_bus_valid_i, + + output [WS_TO_DS_BUS_WIDTH-1:0] ws_to_ds_bus_data_o, + output ws_to_ds_bus_valid_o, + + output [31:0] debug_wb_pc_o, + output [ 3:0] debug_wb_rf_wen_o, + output [ 4:0] debug_wb_rf_waddr_o, + output [31:0] debug_wb_rf_wdata_o + ); + + reg ms_to_ws_bus_valid; + reg [MS_TO_WS_BUS_WIDTH-1:0] ms_to_ws_bus_data; + + wire ws_to_ds_bus_valid; + wire ws_rf_we; + wire [ 4:0] ws_rf_addr; + wire [31:0] ws_rf_wdata; + wire [31:0] ws_pc; + + assign { + ws_rf_we, // 69:69 + ws_rf_addr, // 68:64 + ws_rf_wdata, // 63:32 + ws_pc // 31:0 + } = ms_to_ws_bus_data; + + assign ws_to_ds_bus_valid = 1'b1; + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + ms_to_ws_bus_valid <= 1'b0; + end + else if(ms_to_ws_bus_ready_o) begin + ms_to_ws_bus_valid <= ms_to_ws_bus_valid_i; + end + else begin + ms_to_ws_bus_valid <= ms_to_ws_bus_valid; + end + end + + always @(posedge clk_i or negedge rstn_i) begin + if (!rstn_i) begin + ms_to_ws_bus_data <= {MS_TO_WS_BUS_WIDTH{1'b0}}; + end + else if(ms_to_ws_bus_valid_i && ms_to_ws_bus_ready_o) begin + ms_to_ws_bus_data <= ms_to_ws_bus_data_i; + end + else begin + ms_to_ws_bus_data <= ms_to_ws_bus_data; + end + end + + assign ws_to_ds_bus_data_o = { + ws_rf_we, // 37:37 + ws_rf_addr, // 36:32 + ws_rf_wdata // 31:0 + }; + + assign ms_to_ws_bus_ready_o = !ms_to_ws_bus_valid || ws_to_ds_bus_valid; + assign ws_to_ds_bus_valid_o = ms_to_ws_bus_valid && ws_to_ds_bus_valid; + + assign debug_wb_pc_o = ws_pc; + assign debug_wb_rf_wen_o = {4{ms_to_ws_bus_valid && ws_rf_we}}; + assign debug_wb_rf_waddr_o = ws_rf_addr; + assign debug_wb_rf_wdata_o = ws_rf_wdata; +endmodule diff --git a/rv_cpu.xpr b/rv_cpu.xpr new file mode 100644 index 0000000..9e78c81 --- /dev/null +++ b/rv_cpu.xpr @@ -0,0 +1,302 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default_dashboard + + +