From 31c90f22f6d793a883a89224c00530b062a034ee Mon Sep 17 00:00:00 2001 From: "colin.liang" Date: Thu, 5 Jan 2023 21:37:01 +0800 Subject: [PATCH] Refine top.v. --- uriscv/demo/Makefile | 1 + uriscv/demo/top.v | 4681 ++++++++++-------------------------------- 2 files changed, 1132 insertions(+), 3550 deletions(-) diff --git a/uriscv/demo/Makefile b/uriscv/demo/Makefile index e3fa0e3..2ca6fe8 100644 --- a/uriscv/demo/Makefile +++ b/uriscv/demo/Makefile @@ -36,6 +36,7 @@ top.v: ./ivlpp -F include.f -f soc.mk -o top.v verilator-build: top.v +# verilator-build: verilator --cc -CFLAGS ${CFLAGS} \ -Wno-WIDTH \ -Wno-UNOPTFLAT \ diff --git a/uriscv/demo/top.v b/uriscv/demo/top.v index a2cfe76..a61e572 100644 --- a/uriscv/demo/top.v +++ b/uriscv/demo/top.v @@ -1,788 +1,310 @@ -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- - -module riscv_core -//----------------------------------------------------------------- -// Params -//----------------------------------------------------------------- -#( - parameter SUPPORT_MUL = 1 - ,parameter SUPPORT_DIV = 1 - ,parameter SUPPORT_CSR = 1 - ,parameter SUPPORT_TRAP_LSU_ALIGN = 1 - ,parameter SUPPORT_MTVEC = 0 - ,parameter SUPPORT_MTVAL = 0 - ,parameter SUPPORT_MIP_MIE = 0 - ,parameter SUPPORT_MSCRATCH = 0 - ,parameter SUPPORT_MCYCLE = 1 - ,parameter SUPPORT_MTIMECMP = 0 - ,parameter SUPPORT_TRAP_INVALID_OPC = 1 - ,parameter SUPPORT_BRAM_REGFILE = 0 - ,parameter ISR_VECTOR = 32'h00000010 -) -//----------------------------------------------------------------- -// Ports -//----------------------------------------------------------------- -( - // Clock - input clk_i - - // Reset (active high) - ,input rst_i - +module riscv_core #( + parameter SUPPORT_MUL = 1, + parameter SUPPORT_DIV = 1, + parameter SUPPORT_CSR = 1, + parameter SUPPORT_TRAP_LSU_ALIGN = 1, + parameter SUPPORT_MTVEC = 0, + parameter SUPPORT_MTVAL = 0, + parameter SUPPORT_MIP_MIE = 0, + parameter SUPPORT_MSCRATCH = 0, + parameter SUPPORT_MCYCLE = 1, + parameter SUPPORT_MTIMECMP = 0, + parameter SUPPORT_TRAP_INVALID_OPC = 1, + parameter SUPPORT_BRAM_REGFILE = 0, + parameter ISR_VECTOR = 32'h00000010 +) ( + input clk_i + , input rst_i // External interrupt (M_EXT) - ,input intr_i - + , input intr_i // Initial boot address - ,input [ 31:0] reset_vector_i - + , input [31:0] reset_vector_i // MHARTID value - ,input [ 31:0] cpu_id_i - + , input [31:0] cpu_id_i // Instruction Fetch - ,output mem_i_rd_o - ,output [ 31:0] mem_i_pc_o - ,input mem_i_accept_i - ,input mem_i_valid_i - ,input [ 31:0] mem_i_inst_i - + , output mem_i_rd_o, + output [31:0] mem_i_pc_o, + input mem_i_accept_i, + input mem_i_valid_i, + input [31:0] mem_i_inst_i // Instruction fetch: Unused on this core - ,output mem_i_flush_o - ,output mem_i_invalidate_o - + , output mem_i_flush_o, + output mem_i_invalidate_o // Instruction fetch: Unused (tie low) - ,input mem_i_error_i - + , input mem_i_error_i // Data Access - ,output [ 31:0] mem_d_addr_o - ,output [ 31:0] mem_d_data_wr_o - ,output mem_d_rd_o - ,output [ 3:0] mem_d_wr_o - ,input [ 31:0] mem_d_data_rd_i - ,input mem_d_accept_i - ,input mem_d_ack_i - + , output [31:0] mem_d_addr_o, + output [31:0] mem_d_data_wr_o, + output mem_d_rd_o, + output [ 3:0] mem_d_wr_o, + input [31:0] mem_d_data_rd_i, + input mem_d_accept_i, + input mem_d_ack_i // Instruction fetch: Unused on this core - ,output mem_d_cacheable_o - ,output [ 10:0] mem_d_req_tag_o - ,output mem_d_invalidate_o - ,output mem_d_writeback_o - ,output mem_d_flush_o - + , output mem_d_cacheable_o, + output [10:0] mem_d_req_tag_o, + output mem_d_invalidate_o, + output mem_d_writeback_o, + output mem_d_flush_o // Data Access: Unused (tie low) - ,input mem_d_error_i - ,input [ 10:0] mem_d_resp_tag_i + , input mem_d_error_i, + input [10:0] mem_d_resp_tag_i ); - - - -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -//-------------------------------------------------------------------- -// ALU Operations -//-------------------------------------------------------------------- - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Privilege levels -//----------------------------------------------------------------- - - - - -//----------------------------------------------------------------- -// Status Register -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// IRQ Numbers -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// CSR Registers - Machine -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Non-std - - - -//----------------------------------------------------------------- -// CSR Registers - Simulation control -//----------------------------------------------------------------- - - - - - - - -//----------------------------------------------------------------- -// Exception Causes -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Debug defines for exception types -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Params -//----------------------------------------------------------------- - - - -localparam PC_W = 32; -localparam PC_PAD_W = 0; -localparam PC_EXT_W = 0; - -localparam ADDR_W = 32; -localparam ADDR_PAD_W = 0; - -// Current state -localparam STATE_W = 3; -localparam STATE_RESET = 0; -localparam STATE_FETCH_WB = 1; -localparam STATE_EXEC = 2; -localparam STATE_MEM = 3; -localparam STATE_DECODE = 4; // Only if SUPPORT_BRAM_REGFILE = 1 - -//----------------------------------------------------------------- -// Registers -//----------------------------------------------------------------- - -// Current state -reg [STATE_W-1:0] state_q; - -// Executing PC -reg [PC_W-1:0] pc_q; - -// Destination register -reg [4:0] rd_q; - -// Destination writeback enable -reg rd_wr_en_q; - -// ALU inputs -reg [31:0] alu_a_q; -reg [31:0] alu_b_q; - -// ALU operation selection -reg [3:0] alu_func_q; - -// CSR read data -wire [31:0] csr_data_w; - -// Instruction decode fault -reg invalid_inst_r; - -// Register indexes -wire [4:0] rd_w; -wire [4:0] rs1_w; -wire [4:0] rs2_w; - -// Operand values -wire [31:0] rs1_val_w; -wire [31:0] rs2_val_w; - -// Opcode (memory bus) -wire [31:0] opcode_w; - -wire opcode_valid_w; -wire opcode_fetch_w = mem_i_rd_o & mem_i_accept_i; - -// Execute exception (or interrupt) -wire exception_w; -wire [5:0] exception_type_w; -wire [31:0] exception_target_w; - -wire [31:0] csr_mepc_w; - -// Load result (formatted based on load type) -reg [31:0] load_result_r; - -// Writeback enable / value -wire rd_writeen_w; -wire [31:0] rd_val_w; - -// Memory interface -wire mem_misaligned_w; -reg [ADDR_W-1:0] mem_addr_q; -reg [31:0] mem_data_q; -reg [3:0] mem_wr_q; -reg mem_rd_q; - -// Load type / byte / half index -reg [1:0] load_offset_q; -reg load_signed_q; -reg load_byte_q; -reg load_half_q; - -wire enable_w = 1'b1; - -wire [31:0] muldiv_result_w; -wire muldiv_ready_w; -wire muldiv_inst_w; - -//----------------------------------------------------------------- -// ALU -//----------------------------------------------------------------- -uriscv_alu alu -( - // ALU operation select - .op_i(alu_func_q), - - // Operands - .a_i(alu_a_q), - .b_i(alu_b_q), - - // Result - .p_o(rd_val_w) -); - -//----------------------------------------------------------------- -// Register file -//----------------------------------------------------------------- -reg [31:0] reg_file[0:31]; - -always @ (posedge clk_i) -if (rd_writeen_w) - reg_file[rd_q] <= rd_val_w; - -wire [31:0] rs1_val_gpr_w = reg_file[mem_i_inst_i[19:15]]; -wire [31:0] rs2_val_gpr_w = reg_file[mem_i_inst_i[24:20]]; - -reg [31:0] rs1_val_gpr_q; -reg [31:0] rs2_val_gpr_q; - -always @ (posedge clk_i) -begin + localparam PC_W = 32; + localparam PC_PAD_W = 0; + localparam PC_EXT_W = 0; + localparam ADDR_W = 32; + localparam ADDR_PAD_W = 0; + localparam STATE_W = 3; + localparam STATE_RESET = 0; + localparam STATE_FETCH_WB = 1; + localparam STATE_EXEC = 2; + localparam STATE_MEM = 3; + localparam STATE_DECODE = 4; // Only if SUPPORT_BRAM_REGFILE = 1 + reg [STATE_W-1:0] state_q; + reg [ PC_W-1:0] pc_q; + reg [ 4:0] rd_q; + reg rd_wr_en_q; + reg [ 31:0] alu_a_q; + reg [ 31:0] alu_b_q; + reg [ 3:0] alu_func_q; + wire [ 31:0] csr_data_w; + reg invalid_inst_r; + wire [ 4:0] rd_w; + wire [ 4:0] rs1_w; + wire [ 4:0] rs2_w; + wire [ 31:0] rs1_val_w; + wire [ 31:0] rs2_val_w; + wire [ 31:0] opcode_w; + wire opcode_valid_w; + wire opcode_fetch_w = mem_i_rd_o & mem_i_accept_i; + wire exception_w; + wire [ 5:0] exception_type_w; + wire [ 31:0] exception_target_w; + wire [ 31:0] csr_mepc_w; + reg [ 31:0] load_result_r; + wire rd_writeen_w; + wire [ 31:0] rd_val_w; + wire mem_misaligned_w; + reg [ ADDR_W-1:0] mem_addr_q; + reg [ 31:0] mem_data_q; + reg [ 3:0] mem_wr_q; + reg mem_rd_q; + reg [ 1:0] load_offset_q; + reg load_signed_q; + reg load_byte_q; + reg load_half_q; + wire enable_w = 1'b1; + wire [ 31:0] muldiv_result_w; + wire muldiv_ready_w; + wire muldiv_inst_w; + uriscv_alu alu ( + // ALU operation select + .op_i(alu_func_q), + // Operands + .a_i (alu_a_q), + .b_i (alu_b_q), + // Result + .p_o (rd_val_w) + ); + reg [31:0] reg_file[0:31]; + always @(posedge clk_i) if (rd_writeen_w) reg_file[rd_q] <= rd_val_w; + wire [31:0] rs1_val_gpr_w = reg_file[mem_i_inst_i[19:15]]; + wire [31:0] rs2_val_gpr_w = reg_file[mem_i_inst_i[24:20]]; + reg [31:0] rs1_val_gpr_q; + reg [31:0] rs2_val_gpr_q; + always @(posedge clk_i) begin rs1_val_gpr_q <= rs1_val_gpr_w; rs2_val_gpr_q <= rs2_val_gpr_w; -end - -assign rs1_val_w = SUPPORT_BRAM_REGFILE ? rs1_val_gpr_q : rs1_val_gpr_w; -assign rs2_val_w = SUPPORT_BRAM_REGFILE ? rs2_val_gpr_q : rs2_val_gpr_w; - -// Writeback enable -assign rd_writeen_w = rd_wr_en_q & (state_q == STATE_FETCH_WB); - - - - - - - - - -// Simulation friendly names - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Next State Logic -//----------------------------------------------------------------- -reg [STATE_W-1:0] next_state_r; -always @ * -begin + end + assign rs1_val_w = SUPPORT_BRAM_REGFILE ? rs1_val_gpr_q : rs1_val_gpr_w; + assign rs2_val_w = SUPPORT_BRAM_REGFILE ? rs2_val_gpr_q : rs2_val_gpr_w; + assign rd_writeen_w = rd_wr_en_q & (state_q == STATE_FETCH_WB); + reg [STATE_W-1:0] next_state_r; + always @* begin next_state_r = state_q; - case (state_q) - // RESET - First cycle after reset - STATE_RESET: - begin + // RESET - First cycle after reset + STATE_RESET: begin next_state_r = STATE_FETCH_WB; - end - // FETCH_WB - Writeback / Fetch next isn - STATE_FETCH_WB : - begin - if (opcode_fetch_w) - next_state_r = SUPPORT_BRAM_REGFILE ? STATE_DECODE : STATE_EXEC; - end - // DECODE - Used to access register file if SUPPORT_BRAM_REGFILE=1 - STATE_DECODE: - begin - if (mem_i_valid_i) - next_state_r = STATE_EXEC; - end - // EXEC - Execute instruction (when ready) - STATE_EXEC : - begin + end + // FETCH_WB - Writeback / Fetch next isn + STATE_FETCH_WB: begin + if (opcode_fetch_w) next_state_r = SUPPORT_BRAM_REGFILE ? STATE_DECODE : STATE_EXEC; + end + // DECODE - Used to access register file if SUPPORT_BRAM_REGFILE=1 + STATE_DECODE: begin + if (mem_i_valid_i) next_state_r = STATE_EXEC; + end + // EXEC - Execute instruction (when ready) + STATE_EXEC: begin // Instruction ready - if (opcode_valid_w) - begin - if (exception_w) - next_state_r = STATE_FETCH_WB; - else if (type_load_w || type_store_w) - next_state_r = STATE_MEM; - // Multiplication / division - stay in exec state until result ready - else if (muldiv_inst_w) - ; - else - next_state_r = STATE_FETCH_WB; - end - else if (muldiv_ready_w) - next_state_r = STATE_FETCH_WB; - end - // MEM - Perform load or store - STATE_MEM : - begin + if (opcode_valid_w) begin + if (exception_w) next_state_r = STATE_FETCH_WB; + else if (type_load_w || type_store_w) next_state_r = STATE_MEM; + // Multiplication / division - stay in exec state until result ready + else + if (muldiv_inst_w); + else next_state_r = STATE_FETCH_WB; + end else if (muldiv_ready_w) next_state_r = STATE_FETCH_WB; + end + // MEM - Perform load or store + STATE_MEM: begin // Memory access complete - if (mem_d_ack_i) - next_state_r = STATE_FETCH_WB; - end - default: - ; + if (mem_d_ack_i) next_state_r = STATE_FETCH_WB; + end + default: ; endcase - - if (!enable_w) - next_state_r = STATE_RESET; -end - -// Update state -always @ (posedge clk_i ) -if (rst_i) - state_q <= STATE_RESET; -else - state_q <= next_state_r; - -//----------------------------------------------------------------- -// Instruction Decode -//----------------------------------------------------------------- -reg [31:0] opcode_q; - -always @ (posedge clk_i ) -if (rst_i) - opcode_q <= 32'b0; -else if (state_q == STATE_DECODE) - opcode_q <= mem_i_inst_i; - -reg opcode_valid_q; - -always @ (posedge clk_i ) -if (rst_i) - opcode_valid_q <= 1'b0; -else if (state_q == STATE_DECODE) - opcode_valid_q <= mem_i_valid_i; -else - opcode_valid_q <= 1'b0; - -assign opcode_w = SUPPORT_BRAM_REGFILE ? opcode_q : mem_i_inst_i; -assign opcode_valid_w = SUPPORT_BRAM_REGFILE ? opcode_valid_q : mem_i_valid_i; - -assign rs1_w = opcode_w[19:15]; -assign rs2_w = opcode_w[24:20]; -assign rd_w = opcode_w[11:7]; - -wire type_rvc_w = (opcode_w[1:0] != 2'b11); - -wire type_load_w = (opcode_w[6:2] == 5'b00000); -wire type_opimm_w = (opcode_w[6:2] == 5'b00100); -wire type_auipc_w = (opcode_w[6:2] == 5'b00101); -wire type_store_w = (opcode_w[6:2] == 5'b01000); -wire type_op_w = (opcode_w[6:2] == 5'b01100); -wire type_lui_w = (opcode_w[6:2] == 5'b01101); -wire type_branch_w = (opcode_w[6:2] == 5'b11000); -wire type_jalr_w = (opcode_w[6:2] == 5'b11001); -wire type_jal_w = (opcode_w[6:2] == 5'b11011); -wire type_system_w = (opcode_w[6:2] == 5'b11100); -wire type_miscm_w = (opcode_w[6:2] == 5'b00011); - -wire [2:0] func3_w = opcode_w[14:12]; // R, I, S -wire [6:0] func7_w = opcode_w[31:25]; // R - -// ALU operations excluding mul/div -wire type_alu_op_w = (type_op_w && (func7_w == 7'b0000000)) || + if (!enable_w) next_state_r = STATE_RESET; + end + always @(posedge clk_i) + if (rst_i) state_q <= STATE_RESET; + else state_q <= next_state_r; + reg [31:0] opcode_q; + always @(posedge clk_i) + if (rst_i) opcode_q <= 32'b0; + else if (state_q == STATE_DECODE) opcode_q <= mem_i_inst_i; + reg opcode_valid_q; + always @(posedge clk_i) + if (rst_i) opcode_valid_q <= 1'b0; + else if (state_q == STATE_DECODE) opcode_valid_q <= mem_i_valid_i; + else opcode_valid_q <= 1'b0; + assign opcode_w = SUPPORT_BRAM_REGFILE ? opcode_q : mem_i_inst_i; + assign opcode_valid_w = SUPPORT_BRAM_REGFILE ? opcode_valid_q : mem_i_valid_i; + assign rs1_w = opcode_w[19:15]; + assign rs2_w = opcode_w[24:20]; + assign rd_w = opcode_w[11:7]; + wire type_rvc_w = (opcode_w[1:0] != 2'b11); + wire type_load_w = (opcode_w[6:2] == 5'b00000); + wire type_opimm_w = (opcode_w[6:2] == 5'b00100); + wire type_auipc_w = (opcode_w[6:2] == 5'b00101); + wire type_store_w = (opcode_w[6:2] == 5'b01000); + wire type_op_w = (opcode_w[6:2] == 5'b01100); + wire type_lui_w = (opcode_w[6:2] == 5'b01101); + wire type_branch_w = (opcode_w[6:2] == 5'b11000); + wire type_jalr_w = (opcode_w[6:2] == 5'b11001); + wire type_jal_w = (opcode_w[6:2] == 5'b11011); + wire type_system_w = (opcode_w[6:2] == 5'b11100); + wire type_miscm_w = (opcode_w[6:2] == 5'b00011); + wire [2:0] func3_w = opcode_w[14:12]; // R, I, S + wire [6:0] func7_w = opcode_w[31:25]; // R + wire type_alu_op_w = (type_op_w && (func7_w == 7'b0000000)) || (type_op_w && (func7_w == 7'b0100000)); - -// Loose decoding - gate with type_load_w on use -wire inst_lb_w = (func3_w == 3'b000); -wire inst_lh_w = (func3_w == 3'b001); -wire inst_lbu_w = (func3_w == 3'b100); -wire inst_lhu_w = (func3_w == 3'b101); - -wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h000000); -wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h002000); -wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h604000); - -wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100); - -wire mul_inst_w = SUPPORT_MUL && type_op_w && (func7_w == 7'b0000001) && ~func3_w[2]; -wire div_inst_w = SUPPORT_DIV && type_op_w && (func7_w == 7'b0000001) && func3_w[2]; -wire inst_mul_w = mul_inst_w && (func3_w == 3'b000); -wire inst_mulh_w = mul_inst_w && (func3_w == 3'b001); -wire inst_mulhsu_w = mul_inst_w && (func3_w == 3'b010); -wire inst_mulhu_w = mul_inst_w && (func3_w == 3'b011); -wire inst_div_w = div_inst_w && (func3_w == 3'b100); -wire inst_divu_w = div_inst_w && (func3_w == 3'b101); -wire inst_rem_w = div_inst_w && (func3_w == 3'b110); -wire inst_remu_w = div_inst_w && (func3_w == 3'b111); -wire inst_nop_w = (type_miscm_w && (func3_w == 3'b000)) | // fence - (type_miscm_w && (func3_w == 3'b001)); // fence.i - -assign muldiv_inst_w = mul_inst_w | div_inst_w; - -reg [31:0] imm20_r; -reg [31:0] imm12_r; - -always @ * -begin - imm20_r = {opcode_w[31:12], 12'b0}; - imm12_r = {{20{opcode_w[31]}}, opcode_w[31:20]}; -end - -//----------------------------------------------------------------- -// ALU inputs -//----------------------------------------------------------------- -// ALU operation selection -reg [3:0] alu_func_r; - -// ALU operands -reg [31:0] alu_input_a_r; -reg [31:0] alu_input_b_r; -reg write_rd_r; - -always @ * -begin - alu_func_r = 4'b0000; - alu_input_a_r = rs1_val_w; - alu_input_b_r = rs2_val_w; - write_rd_r = 1'b0; - + wire inst_lb_w = (func3_w == 3'b000); + wire inst_lh_w = (func3_w == 3'b001); + wire inst_lbu_w = (func3_w == 3'b100); + wire inst_lhu_w = (func3_w == 3'b101); + wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h000000); + wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h002000); + wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h604000); + wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100); + wire mul_inst_w = SUPPORT_MUL && type_op_w && (func7_w == 7'b0000001) && ~func3_w[2]; + wire div_inst_w = SUPPORT_DIV && type_op_w && (func7_w == 7'b0000001) && func3_w[2]; + wire inst_mul_w = mul_inst_w && (func3_w == 3'b000); + wire inst_mulh_w = mul_inst_w && (func3_w == 3'b001); + wire inst_mulhsu_w = mul_inst_w && (func3_w == 3'b010); + wire inst_mulhu_w = mul_inst_w && (func3_w == 3'b011); + wire inst_div_w = div_inst_w && (func3_w == 3'b100); + wire inst_divu_w = div_inst_w && (func3_w == 3'b101); + wire inst_rem_w = div_inst_w && (func3_w == 3'b110); + wire inst_remu_w = div_inst_w && (func3_w == 3'b111); + wire inst_nop_w = (type_miscm_w && (func3_w == 3'b000)) | // fence + (type_miscm_w && (func3_w == 3'b001)); // fence.i + assign muldiv_inst_w = mul_inst_w | div_inst_w; + reg [31:0] imm20_r; + reg [31:0] imm12_r; + always @* begin + imm20_r = {opcode_w[31:12], 12'b0}; + imm12_r = {{20{opcode_w[31]}}, opcode_w[31:20]}; + end + reg [ 3:0] alu_func_r; + reg [31:0] alu_input_a_r; + reg [31:0] alu_input_b_r; + reg write_rd_r; + always @* begin + alu_func_r = 4'b0000; + alu_input_a_r = rs1_val_w; + alu_input_b_r = rs2_val_w; + write_rd_r = 1'b0; case (1'b1) - type_alu_op_w: - begin - alu_input_a_r = rs1_val_w; - alu_input_b_r = rs2_val_w; - end - type_opimm_w: - begin - alu_input_a_r = rs1_val_w; - alu_input_b_r = imm12_r; - end - type_lui_w: - begin - alu_input_a_r = 32'b0; - alu_input_b_r = imm20_r; - end - type_auipc_w: - begin - alu_input_a_r[PC_W-1:0] = pc_q; - alu_input_b_r = imm20_r; - end - type_jal_w, - type_jalr_w: - begin - alu_input_a_r[PC_W-1:0] = pc_q; - alu_input_b_r = 32'd4; - end - default : ; + type_alu_op_w: begin + alu_input_a_r = rs1_val_w; + alu_input_b_r = rs2_val_w; + end + type_opimm_w: begin + alu_input_a_r = rs1_val_w; + alu_input_b_r = imm12_r; + end + type_lui_w: begin + alu_input_a_r = 32'b0; + alu_input_b_r = imm20_r; + end + type_auipc_w: begin + alu_input_a_r[PC_W-1:0] = pc_q; + alu_input_b_r = imm20_r; + end + type_jal_w, type_jalr_w: begin + alu_input_a_r[PC_W-1:0] = pc_q; + alu_input_b_r = 32'd4; + end + default: ; endcase - - if (muldiv_inst_w) - write_rd_r = 1'b1; - else if (type_opimm_w || type_alu_op_w) - begin - case (func3_w) - 3'b000: alu_func_r = (type_op_w & opcode_w[30]) ? + if (muldiv_inst_w) write_rd_r = 1'b1; + else if (type_opimm_w || type_alu_op_w) begin + case (func3_w) + 3'b000: alu_func_r = (type_op_w & opcode_w[30]) ? 4'b0110: // SUB 4'b0100; // ADD / ADDI - 3'b001: alu_func_r = 4'b0001; // SLL / SLLI - 3'b010: alu_func_r = 4'b1011; // SLT / SLTI - 3'b011: alu_func_r = 4'b1010; // SLTU / SLTIU - 3'b100: alu_func_r = 4'b1001; // XOR / XORI - 3'b101: alu_func_r = opcode_w[30] ? + 3'b001: alu_func_r = 4'b0001; // SLL / SLLI + 3'b010: alu_func_r = 4'b1011; // SLT / SLTI + 3'b011: alu_func_r = 4'b1010; // SLTU / SLTIU + 3'b100: alu_func_r = 4'b1001; // XOR / XORI + 3'b101: alu_func_r = opcode_w[30] ? 4'b0011: // SRA / SRAI 4'b0010; // SRL / SRLI - 3'b110: alu_func_r = 4'b1000; // OR / ORI - 3'b111: alu_func_r = 4'b0111; // AND / ANDI - endcase - - write_rd_r = 1'b1; - end - else if (inst_csr_w) - begin - alu_func_r = 4'b0100; - alu_input_a_r = 32'b0; - alu_input_b_r = csr_data_w; - write_rd_r = 1'b1; - end - else if (type_auipc_w || type_lui_w || type_jalr_w || type_jal_w) - begin - write_rd_r = 1'b1; - alu_func_r = 4'b0100; - end - else if (type_load_w) - write_rd_r = 1'b1; -end - -//------------------------------------------------------------------- -// Load result resolve -//------------------------------------------------------------------- -always @ * -begin + 3'b110: alu_func_r = 4'b1000; // OR / ORI + 3'b111: alu_func_r = 4'b0111; // AND / ANDI + endcase + write_rd_r = 1'b1; + end else if (inst_csr_w) begin + alu_func_r = 4'b0100; + alu_input_a_r = 32'b0; + alu_input_b_r = csr_data_w; + write_rd_r = 1'b1; + end else if (type_auipc_w || type_lui_w || type_jalr_w || type_jal_w) begin + write_rd_r = 1'b1; + alu_func_r = 4'b0100; + end else if (type_load_w) write_rd_r = 1'b1; + end + always @* begin load_result_r = 32'b0; - - if (load_byte_q) - begin - case (load_offset_q[1:0]) - 2'h3: - load_result_r = {24'b0, mem_d_data_rd_i[31:24]}; - 2'h2: - load_result_r = {24'b0, mem_d_data_rd_i[23:16]}; - 2'h1: - load_result_r = {24'b0, mem_d_data_rd_i[15:8]}; - 2'h0: - load_result_r = {24'b0, mem_d_data_rd_i[7:0]}; - endcase - - if (load_signed_q && load_result_r[7]) - load_result_r = {24'hFFFFFF, load_result_r[7:0]}; - end - else if (load_half_q) - begin - if (load_offset_q[1]) - load_result_r = {16'b0, mem_d_data_rd_i[31:16]}; - else - load_result_r = {16'b0, mem_d_data_rd_i[15:0]}; - - if (load_signed_q && load_result_r[15]) - load_result_r = {16'hFFFF, load_result_r[15:0]}; - end - else - load_result_r = mem_d_data_rd_i; -end - -//----------------------------------------------------------------- -// Branches -//----------------------------------------------------------------- -wire branch_w; -wire [31:0] branch_target_w; -wire [31:0] pc_ext_w = {{PC_EXT_W{1'b0}}, pc_q}; - -uriscv_branch -u_branch -( - .pc_i(pc_ext_w) - ,.opcode_i(opcode_w) - ,.rs1_val_i(rs1_val_w) - ,.rs2_val_i(rs2_val_w) - ,.branch_o(branch_w) - ,.branch_target_o(branch_target_w) -); - -//----------------------------------------------------------------- -// Invalid instruction -//----------------------------------------------------------------- -always @ * -begin + if (load_byte_q) begin + case (load_offset_q[1:0]) + 2'h3: load_result_r = {24'b0, mem_d_data_rd_i[31:24]}; + 2'h2: load_result_r = {24'b0, mem_d_data_rd_i[23:16]}; + 2'h1: load_result_r = {24'b0, mem_d_data_rd_i[15:8]}; + 2'h0: load_result_r = {24'b0, mem_d_data_rd_i[7:0]}; + endcase + if (load_signed_q && load_result_r[7]) load_result_r = {24'hFFFFFF, load_result_r[7:0]}; + end else if (load_half_q) begin + if (load_offset_q[1]) load_result_r = {16'b0, mem_d_data_rd_i[31:16]}; + else load_result_r = {16'b0, mem_d_data_rd_i[15:0]}; + if (load_signed_q && load_result_r[15]) load_result_r = {16'hFFFF, load_result_r[15:0]}; + end else load_result_r = mem_d_data_rd_i; + end + wire branch_w; + wire [31:0] branch_target_w; + wire [31:0] pc_ext_w = {{PC_EXT_W{1'b0}}, pc_q}; + uriscv_branch u_branch ( + .pc_i(pc_ext_w), + .opcode_i(opcode_w), + .rs1_val_i(rs1_val_w), + .rs2_val_i(rs2_val_w), + .branch_o(branch_w), + .branch_target_o(branch_target_w) + ); + always @* begin invalid_inst_r = SUPPORT_TRAP_INVALID_OPC; - if ( type_load_w | type_opimm_w | type_auipc_w @@ -798,2716 +320,839 @@ begin | inst_csr_w | inst_nop_w | muldiv_inst_w) - invalid_inst_r = SUPPORT_TRAP_INVALID_OPC && type_rvc_w; -end - -//----------------------------------------------------------------- -// Execute: ALU control -//----------------------------------------------------------------- -always @ (posedge clk_i ) -if (rst_i) -begin - alu_func_q <= 4'b0000; - alu_a_q <= 32'h00000000; - alu_b_q <= 32'h00000000; - rd_q <= 5'b00000; - - // Reset x0 in-case of RAM - rd_wr_en_q <= 1'b1; -end -// Load result ready -else if ((state_q == STATE_MEM) && mem_d_ack_i) -begin - // Update ALU input with load result - alu_func_q <= 4'b0000; - alu_a_q <= load_result_r; - alu_b_q <= 32'b0; -end -// Multiplier / Divider result -else if (muldiv_ready_w) -begin - // Update ALU input with load result - alu_func_q <= 4'b0000; - alu_a_q <= muldiv_result_w; - alu_b_q <= 32'b0; -end -// Execute instruction -else if (opcode_valid_w) -begin - // Update ALU input flops - alu_func_q <= alu_func_r; - alu_a_q <= alu_input_a_r; - alu_b_q <= alu_input_b_r; - - // Take exception - if (exception_w) - begin + invalid_inst_r = SUPPORT_TRAP_INVALID_OPC && type_rvc_w; + end + always @(posedge clk_i) + if (rst_i) begin + alu_func_q <= 4'b0000; + alu_a_q <= 32'h00000000; + alu_b_q <= 32'h00000000; + rd_q <= 5'b00000; + // Reset x0 in-case of RAM + rd_wr_en_q <= 1'b1; + end else if ((state_q == STATE_MEM) && mem_d_ack_i) begin + // Update ALU input with load result + alu_func_q <= 4'b0000; + alu_a_q <= load_result_r; + alu_b_q <= 32'b0; + end else if (muldiv_ready_w) begin + // Update ALU input with load result + alu_func_q <= 4'b0000; + alu_a_q <= muldiv_result_w; + alu_b_q <= 32'b0; + end else if (opcode_valid_w) begin + // Update ALU input flops + alu_func_q <= alu_func_r; + alu_a_q <= alu_input_a_r; + alu_b_q <= alu_input_b_r; + // Take exception + if (exception_w) begin // No register writeback - rd_q <= 5'b0; - rd_wr_en_q <= 1'b0; - end - // Valid instruction - else - begin + rd_q <= 5'b0; + rd_wr_en_q <= 1'b0; + end // Valid instruction + else begin // Instruction with register writeback - rd_q <= rd_w; - rd_wr_en_q <= write_rd_r & (rd_w != 5'b0); + rd_q <= rd_w; + rd_wr_en_q <= write_rd_r & (rd_w != 5'b0); + end + end else if (state_q == STATE_FETCH_WB) rd_wr_en_q <= 1'b0; + wire [31:0] boot_vector_w = reset_vector_i; + always @(posedge clk_i) + if (rst_i) pc_q <= boot_vector_w[PC_W-1:0]; + else if (state_q == STATE_RESET) pc_q <= boot_vector_w[PC_W-1:0]; + else if (opcode_valid_w) begin + // Exception / Break / ecall (branch to ISR) + if (exception_w || inst_ebreak_w || inst_ecall_w) pc_q <= exception_target_w[PC_W-1:0]; + // MRET (branch to EPC) + else if (inst_mret_w) pc_q <= csr_mepc_w; + // Branch + else if (branch_w) pc_q <= branch_target_w[PC_W-1:0]; + else pc_q <= pc_q + 32'd4; end -end -else if (state_q == STATE_FETCH_WB) - rd_wr_en_q <= 1'b0; - -//----------------------------------------------------------------- -// Execute: Branch / exceptions -//----------------------------------------------------------------- -wire [31:0] boot_vector_w = reset_vector_i; - -always @ (posedge clk_i ) -if (rst_i) - pc_q <= boot_vector_w[PC_W-1:0]; -else if (state_q == STATE_RESET) - pc_q <= boot_vector_w[PC_W-1:0]; -else if (opcode_valid_w) -begin - // Exception / Break / ecall (branch to ISR) - if (exception_w || inst_ebreak_w || inst_ecall_w) - pc_q <= exception_target_w[PC_W-1:0]; - // MRET (branch to EPC) - else if (inst_mret_w) - pc_q <= csr_mepc_w; - // Branch - else if (branch_w) - pc_q <= branch_target_w[PC_W-1:0]; - else - pc_q <= pc_q + 32'd4; -end - - -//----------------------------------------------------------------- -// Writeback/Fetch: Instruction Fetch -//----------------------------------------------------------------- -assign mem_i_rd_o = (state_q == STATE_FETCH_WB); -assign mem_i_pc_o = pc_ext_w; - -//----------------------------------------------------------------- -// Execute: Memory operations -//----------------------------------------------------------------- -wire mem_rd_w; -wire [3:0] mem_wr_w; -wire [31:0] mem_addr_w; -wire [31:0] mem_data_w; - -uriscv_lsu -#( .SUPPORT_TRAP_LSU_ALIGN(SUPPORT_TRAP_LSU_ALIGN) ) -u_lsu -( - .opcode_i(opcode_w) - ,.rs1_val_i(rs1_val_w) - ,.rs2_val_i(rs2_val_w) - - ,.mem_rd_o(mem_rd_w) - ,.mem_wr_o(mem_wr_w) - ,.mem_addr_o(mem_addr_w) - ,.mem_data_o(mem_data_w) - ,.mem_misaligned_o(mem_misaligned_w) -); - -always @ (posedge clk_i ) -if (rst_i) -begin - mem_addr_q <= {ADDR_W{1'b0}}; - mem_data_q <= 32'h00000000; - mem_wr_q <= 4'b0000; - mem_rd_q <= 1'b0; -end -// Valid instruction to execute -else if (opcode_valid_w && !exception_w) -begin - mem_addr_q <= {mem_addr_w[ADDR_W-1:2], 2'b0}; - mem_data_q <= mem_data_w; - mem_wr_q <= mem_wr_w; - mem_rd_q <= mem_rd_w; -end -// No instruction, clear memory request -else if (mem_d_accept_i) -begin - mem_wr_q <= 4'b0000; - mem_rd_q <= 1'b0; -end - -always @ (posedge clk_i ) -if (rst_i) -begin - load_signed_q <= 1'b0; - load_byte_q <= 1'b0; - load_half_q <= 1'b0; - load_offset_q <= 2'b0; -end -// Valid instruction to execute -else if (opcode_valid_w) -begin - load_signed_q <= inst_lh_w | inst_lb_w; - load_byte_q <= inst_lb_w | inst_lbu_w; - load_half_q <= inst_lh_w | inst_lhu_w; - load_offset_q <= mem_addr_w[1:0]; -end - -assign mem_d_addr_o = {{ADDR_PAD_W{1'b0}}, mem_addr_q}; -assign mem_d_data_wr_o = mem_data_q; -assign mem_d_wr_o = mem_wr_q; -assign mem_d_rd_o = mem_rd_q; - -//----------------------------------------------------------------- -// Execute: CSR Access -//----------------------------------------------------------------- -uriscv_csr -#( - .SUPPORT_CSR(SUPPORT_CSR) - ,.SUPPORT_MCYCLE(SUPPORT_MCYCLE) - ,.SUPPORT_MTIMECMP(SUPPORT_MTIMECMP) - ,.SUPPORT_MSCRATCH(SUPPORT_MSCRATCH) - ,.SUPPORT_MIP_MIE(SUPPORT_MIP_MIE) - ,.SUPPORT_MTVEC(SUPPORT_MTVEC) - ,.SUPPORT_MTVAL(SUPPORT_MTVAL) - ,.SUPPORT_MULDIV(SUPPORT_MUL || SUPPORT_DIV) -) -u_csr -( - .clk_i(clk_i) - ,.rst_i(rst_i) - - // Reset vector (only used if SUPPORT_MTVEC=0) - ,.isr_vector_i(reset_vector_i + ISR_VECTOR) - - // HartID - ,.cpu_id_i(cpu_id_i) - - // External interrupt - ,.intr_i(intr_i) - - // Executing instruction - ,.valid_i(opcode_valid_w) - ,.opcode_i(opcode_w) - ,.pc_i(pc_q) - ,.rs1_val_i(rs1_val_w) - ,.rs2_val_i(rs2_val_w) - - // CSR read result - ,.csr_rdata_o(csr_data_w) - - // Exception sources - ,.excpn_invalid_inst_i(invalid_inst_r) - ,.excpn_lsu_align_i(mem_misaligned_w) - - // Used on memory alignment errors - ,.mem_addr_i(mem_addr_w) - - // CSR registers - ,.csr_mepc_o(csr_mepc_w) - - // Exception entry - ,.exception_o(exception_w) - ,.exception_type_o(exception_type_w) - ,.exception_pc_o(exception_target_w) -); - -//----------------------------------------------------------------- -// Multiplier / Divider -//----------------------------------------------------------------- -generate -if (SUPPORT_MUL != 0 || SUPPORT_DIV != 0) -begin - uriscv_muldiv - u_muldiv - ( - .clk_i(clk_i), - .rst_i(rst_i), - - // Operation select - .valid_i(opcode_valid_w & ~exception_w), - .inst_mul_i(inst_mul_w), - .inst_mulh_i(inst_mulh_w), - .inst_mulhsu_i(inst_mulhsu_w), - .inst_mulhu_i(inst_mulhu_w), - .inst_div_i(inst_div_w), - .inst_divu_i(inst_divu_w), - .inst_rem_i(inst_rem_w), - .inst_remu_i(inst_remu_w), - - // Operands - .operand_ra_i(rs1_val_w), - .operand_rb_i(rs2_val_w), - - // Result - .stall_o(), - .ready_o(muldiv_ready_w), - .result_o(muldiv_result_w) - ); -end -else -begin - assign muldiv_ready_w = 1'b0; - assign muldiv_result_w = 32'b0; -end -endgenerate - -//----------------------------------------------------------------- -// Unused -//----------------------------------------------------------------- -assign mem_i_flush_o = 1'b0; -assign mem_i_invalidate_o = 1'b0; - -assign mem_d_flush_o = 1'b0; -assign mem_d_cacheable_o = 1'b0; -assign mem_d_req_tag_o = 11'b0; -assign mem_d_invalidate_o = 1'b0; -assign mem_d_writeback_o = 1'b0; - -//------------------------------------------------------------------- -// Hooks for debug -//------------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + assign mem_i_rd_o = (state_q == STATE_FETCH_WB); + assign mem_i_pc_o = pc_ext_w; + wire mem_rd_w; + wire [ 3:0] mem_wr_w; + wire [31:0] mem_addr_w; + wire [31:0] mem_data_w; + uriscv_lsu #( + .SUPPORT_TRAP_LSU_ALIGN(SUPPORT_TRAP_LSU_ALIGN) + ) u_lsu ( + .opcode_i(opcode_w), + .rs1_val_i(rs1_val_w), + .rs2_val_i(rs2_val_w), + .mem_rd_o(mem_rd_w), + .mem_wr_o(mem_wr_w), + .mem_addr_o(mem_addr_w), + .mem_data_o(mem_data_w), + .mem_misaligned_o(mem_misaligned_w) + ); + always @(posedge clk_i) + if (rst_i) begin + mem_addr_q <= {ADDR_W{1'b0}}; + mem_data_q <= 32'h00000000; + mem_wr_q <= 4'b0000; + mem_rd_q <= 1'b0; + end else if (opcode_valid_w && !exception_w) begin + mem_addr_q <= {mem_addr_w[ADDR_W-1:2], 2'b0}; + mem_data_q <= mem_data_w; + mem_wr_q <= mem_wr_w; + mem_rd_q <= mem_rd_w; + end else if (mem_d_accept_i) begin + mem_wr_q <= 4'b0000; + mem_rd_q <= 1'b0; + end + always @(posedge clk_i) + if (rst_i) begin + load_signed_q <= 1'b0; + load_byte_q <= 1'b0; + load_half_q <= 1'b0; + load_offset_q <= 2'b0; + end else if (opcode_valid_w) begin + load_signed_q <= inst_lh_w | inst_lb_w; + load_byte_q <= inst_lb_w | inst_lbu_w; + load_half_q <= inst_lh_w | inst_lhu_w; + load_offset_q <= mem_addr_w[1:0]; + end + assign mem_d_addr_o = {{ADDR_PAD_W{1'b0}}, mem_addr_q}; + assign mem_d_data_wr_o = mem_data_q; + assign mem_d_wr_o = mem_wr_q; + assign mem_d_rd_o = mem_rd_q; + uriscv_csr #( + .SUPPORT_CSR(SUPPORT_CSR), + .SUPPORT_MCYCLE(SUPPORT_MCYCLE), + .SUPPORT_MTIMECMP(SUPPORT_MTIMECMP), + .SUPPORT_MSCRATCH(SUPPORT_MSCRATCH), + .SUPPORT_MIP_MIE(SUPPORT_MIP_MIE), + .SUPPORT_MTVEC(SUPPORT_MTVEC), + .SUPPORT_MTVAL(SUPPORT_MTVAL), + .SUPPORT_MULDIV(SUPPORT_MUL || SUPPORT_DIV) + ) u_csr ( + .clk_i(clk_i), + .rst_i(rst_i) + // Reset vector (only used if SUPPORT_MTVEC=0) + , .isr_vector_i(reset_vector_i + ISR_VECTOR) + // HartID + , .cpu_id_i(cpu_id_i) + // External interrupt + , .intr_i(intr_i) + // Executing instruction + , .valid_i(opcode_valid_w), + .opcode_i(opcode_w), + .pc_i(pc_q), + .rs1_val_i(rs1_val_w), + .rs2_val_i(rs2_val_w) + // CSR read result + , .csr_rdata_o(csr_data_w) + // Exception sources + , .excpn_invalid_inst_i(invalid_inst_r), + .excpn_lsu_align_i(mem_misaligned_w) + // Used on memory alignment errors + , .mem_addr_i(mem_addr_w) + // CSR registers + , .csr_mepc_o(csr_mepc_w) + // Exception entry + , .exception_o(exception_w), + .exception_type_o(exception_type_w), + .exception_pc_o(exception_target_w) + ); + generate + if (SUPPORT_MUL != 0 || SUPPORT_DIV != 0) begin + uriscv_muldiv u_muldiv ( + .clk_i(clk_i), + .rst_i(rst_i), + // Operation select + .valid_i(opcode_valid_w & ~exception_w), + .inst_mul_i(inst_mul_w), + .inst_mulh_i(inst_mulh_w), + .inst_mulhsu_i(inst_mulhsu_w), + .inst_mulhu_i(inst_mulhu_w), + .inst_div_i(inst_div_w), + .inst_divu_i(inst_divu_w), + .inst_rem_i(inst_rem_w), + .inst_remu_i(inst_remu_w), + // Operands + .operand_ra_i(rs1_val_w), + .operand_rb_i(rs2_val_w), + // Result + .stall_o(), + .ready_o(muldiv_ready_w), + .result_o(muldiv_result_w) + ); + end else begin + assign muldiv_ready_w = 1'b0; + assign muldiv_result_w = 32'b0; + end + endgenerate + assign mem_i_flush_o = 1'b0; + assign mem_i_invalidate_o = 1'b0; + assign mem_d_flush_o = 1'b0; + assign mem_d_cacheable_o = 1'b0; + assign mem_d_req_tag_o = 11'b0; + assign mem_d_invalidate_o = 1'b0; + assign mem_d_writeback_o = 1'b0; endmodule -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -module uriscv_alu -( +module uriscv_alu ( // ALU operation select - input [3:0] op_i, - + input [ 3:0] op_i, // Operands - input [31:0] a_i, - input [31:0] b_i, - + input [31:0] a_i, + input [31:0] b_i, // Result - output [31:0] p_o + output [31:0] p_o ); - -//----------------------------------------------------------------- -// Includes -//----------------------------------------------------------------- -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -//-------------------------------------------------------------------- -// ALU Operations -//-------------------------------------------------------------------- - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Privilege levels -//----------------------------------------------------------------- - - - - -//----------------------------------------------------------------- -// Status Register -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// IRQ Numbers -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// CSR Registers - Machine -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Non-std - - - -//----------------------------------------------------------------- -// CSR Registers - Simulation control -//----------------------------------------------------------------- - - - - - - - -//----------------------------------------------------------------- -// Exception Causes -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Debug defines for exception types -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Registers -//----------------------------------------------------------------- -reg [31:0] result_r; - -reg [31:16] shift_right_fill_r; -reg [31:0] shift_right_1_r; -reg [31:0] shift_right_2_r; -reg [31:0] shift_right_4_r; -reg [31:0] shift_right_8_r; - -reg [31:0] shift_left_1_r; -reg [31:0] shift_left_2_r; -reg [31:0] shift_left_4_r; -reg [31:0] shift_left_8_r; - -wire [31:0] sub_res_w = a_i - b_i; - -//----------------------------------------------------------------- -// ALU -//----------------------------------------------------------------- -always @ * -begin - case (op_i) - //---------------------------------------------- - // Shift Left - //---------------------------------------------- - 4'b0001 : - begin - if (b_i[0] == 1'b1) - shift_left_1_r = {a_i[30:0],1'b0}; - else - shift_left_1_r = a_i; - - if (b_i[1] == 1'b1) - shift_left_2_r = {shift_left_1_r[29:0],2'b00}; - else - shift_left_2_r = shift_left_1_r; - - if (b_i[2] == 1'b1) - shift_left_4_r = {shift_left_2_r[27:0],4'b0000}; - else - shift_left_4_r = shift_left_2_r; - - if (b_i[3] == 1'b1) - shift_left_8_r = {shift_left_4_r[23:0],8'b00000000}; - else - shift_left_8_r = shift_left_4_r; - - if (b_i[4] == 1'b1) - result_r = {shift_left_8_r[15:0],16'b0000000000000000}; - else - result_r = shift_left_8_r; - end - //---------------------------------------------- - // Shift Right - //---------------------------------------------- - 4'b0010, 4'b0011: - begin - // Arithmetic shift? Fill with 1's if MSB set - if (a_i[31] == 1'b1 && op_i == 4'b0011) - shift_right_fill_r = 16'b1111111111111111; - else - shift_right_fill_r = 16'b0000000000000000; - - if (b_i[0] == 1'b1) - shift_right_1_r = {shift_right_fill_r[31], a_i[31:1]}; - else - shift_right_1_r = a_i; - - if (b_i[1] == 1'b1) - shift_right_2_r = {shift_right_fill_r[31:30], shift_right_1_r[31:2]}; - else - shift_right_2_r = shift_right_1_r; - - if (b_i[2] == 1'b1) - shift_right_4_r = {shift_right_fill_r[31:28], shift_right_2_r[31:4]}; - else - shift_right_4_r = shift_right_2_r; - - if (b_i[3] == 1'b1) - shift_right_8_r = {shift_right_fill_r[31:24], shift_right_4_r[31:8]}; - else - shift_right_8_r = shift_right_4_r; - - if (b_i[4] == 1'b1) - result_r = {shift_right_fill_r[31:16], shift_right_8_r[31:16]}; - else - result_r = shift_right_8_r; - end - //---------------------------------------------- - // Arithmetic - //---------------------------------------------- - 4'b0100 : - begin - result_r = (a_i + b_i); - end - 4'b0110 : - begin - result_r = sub_res_w; - end - //---------------------------------------------- - // Logical - //---------------------------------------------- - 4'b0111 : - begin - result_r = (a_i & b_i); - end - 4'b1000 : - begin - result_r = (a_i | b_i); - end - 4'b1001 : - begin - result_r = (a_i ^ b_i); - end - //---------------------------------------------- - // Comparision - //---------------------------------------------- - 4'b1010 : - begin - result_r = (a_i < b_i) ? 32'h1 : 32'h0; - end - 4'b1011 : - begin - if (a_i[31] != b_i[31]) - result_r = a_i[31] ? 32'h1 : 32'h0; - else - result_r = sub_res_w[31] ? 32'h1 : 32'h0; - end - default : - begin - result_r = a_i; - end - endcase -end - -assign p_o = result_r; - + reg [ 31:0] result_r; + reg [31:16] shift_right_fill_r; + reg [ 31:0] shift_right_1_r; + reg [ 31:0] shift_right_2_r; + reg [ 31:0] shift_right_4_r; + reg [ 31:0] shift_right_8_r; + reg [ 31:0] shift_left_1_r; + reg [ 31:0] shift_left_2_r; + reg [ 31:0] shift_left_4_r; + reg [ 31:0] shift_left_8_r; + wire [ 31:0] sub_res_w = a_i - b_i; + always @* begin + case (op_i) + //---------------------------------------------- + // Shift Left + //---------------------------------------------- + 4'b0001: begin + if (b_i[0] == 1'b1) shift_left_1_r = {a_i[30:0], 1'b0}; + else shift_left_1_r = a_i; + if (b_i[1] == 1'b1) shift_left_2_r = {shift_left_1_r[29:0], 2'b00}; + else shift_left_2_r = shift_left_1_r; + if (b_i[2] == 1'b1) shift_left_4_r = {shift_left_2_r[27:0], 4'b0000}; + else shift_left_4_r = shift_left_2_r; + if (b_i[3] == 1'b1) shift_left_8_r = {shift_left_4_r[23:0], 8'b00000000}; + else shift_left_8_r = shift_left_4_r; + if (b_i[4] == 1'b1) result_r = {shift_left_8_r[15:0], 16'b0000000000000000}; + else result_r = shift_left_8_r; + end + //---------------------------------------------- + // Shift Right + //---------------------------------------------- + 4'b0010, 4'b0011: begin + // Arithmetic shift? Fill with 1's if MSB set + if (a_i[31] == 1'b1 && op_i == 4'b0011) shift_right_fill_r = 16'b1111111111111111; + else shift_right_fill_r = 16'b0000000000000000; + if (b_i[0] == 1'b1) shift_right_1_r = {shift_right_fill_r[31], a_i[31:1]}; + else shift_right_1_r = a_i; + if (b_i[1] == 1'b1) shift_right_2_r = {shift_right_fill_r[31:30], shift_right_1_r[31:2]}; + else shift_right_2_r = shift_right_1_r; + if (b_i[2] == 1'b1) shift_right_4_r = {shift_right_fill_r[31:28], shift_right_2_r[31:4]}; + else shift_right_4_r = shift_right_2_r; + if (b_i[3] == 1'b1) shift_right_8_r = {shift_right_fill_r[31:24], shift_right_4_r[31:8]}; + else shift_right_8_r = shift_right_4_r; + if (b_i[4] == 1'b1) result_r = {shift_right_fill_r[31:16], shift_right_8_r[31:16]}; + else result_r = shift_right_8_r; + end + //---------------------------------------------- + // Arithmetic + //---------------------------------------------- + 4'b0100: begin + result_r = (a_i + b_i); + end + 4'b0110: begin + result_r = sub_res_w; + end + //---------------------------------------------- + // Logical + //---------------------------------------------- + 4'b0111: begin + result_r = (a_i & b_i); + end + 4'b1000: begin + result_r = (a_i | b_i); + end + 4'b1001: begin + result_r = (a_i ^ b_i); + end + //---------------------------------------------- + // Comparision + //---------------------------------------------- + 4'b1010: begin + result_r = (a_i < b_i) ? 32'h1 : 32'h0; + end + 4'b1011: begin + if (a_i[31] != b_i[31]) result_r = a_i[31] ? 32'h1 : 32'h0; + else result_r = sub_res_w[31] ? 32'h1 : 32'h0; + end + default: begin + result_r = a_i; + end + endcase + end + assign p_o = result_r; endmodule -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -module uriscv_branch -( - input [31:0] pc_i - ,input [31:0] opcode_i - ,input [31:0] rs1_val_i - ,input [31:0] rs2_val_i - ,output branch_o - ,output [31:0] branch_target_o +module uriscv_branch ( + input [31:0] pc_i, + input [31:0] opcode_i, + input [31:0] rs1_val_i, + input [31:0] rs2_val_i, + output branch_o, + output [31:0] branch_target_o ); - -//----------------------------------------------------------------- -// Includes -//----------------------------------------------------------------- -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -//-------------------------------------------------------------------- -// ALU Operations -//-------------------------------------------------------------------- - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Privilege levels -//----------------------------------------------------------------- - - - - -//----------------------------------------------------------------- -// Status Register -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// IRQ Numbers -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// CSR Registers - Machine -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Non-std - - - -//----------------------------------------------------------------- -// CSR Registers - Simulation control -//----------------------------------------------------------------- - - - - - - - -//----------------------------------------------------------------- -// Exception Causes -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Debug defines for exception types -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// less_than_signed: Less than operator (signed) -// Inputs: x = left operand, y = right operand -// Return: (int)x < (int)y -//----------------------------------------------------------------- -function [0:0] less_than_signed; - input [31:0] x; - input [31:0] y; + function [0:0] less_than_signed; + input [31:0] x; + input [31:0] y; reg [31:0] v; -begin - v = (x - y); - if (x[31] != y[31]) - less_than_signed = x[31]; - else - less_than_signed = v[31]; -end -endfunction - -//----------------------------------------------------------------- -// greater_than_signed: Greater than operator (signed) -// Inputs: x = left operand, y = right operand -// Return: (int)x > (int)y -//----------------------------------------------------------------- -function [0:0] greater_than_signed; - input [31:0] x; - input [31:0] y; + begin + v = (x - y); + if (x[31] != y[31]) less_than_signed = x[31]; + else less_than_signed = v[31]; + end + endfunction + function [0:0] greater_than_signed; + input [31:0] x; + input [31:0] y; reg [31:0] v; -begin - v = (y - x); - if (x[31] != y[31]) - greater_than_signed = y[31]; - else - greater_than_signed = v[31]; -end -endfunction - -//----------------------------------------------------------------- -// Branch Decode -//----------------------------------------------------------------- -wire type_branch_w = (opcode_i[6:2] == 5'b11000); -wire type_jalr_w = (opcode_i[6:2] == 5'b11001); -wire type_jal_w = (opcode_i[6:2] == 5'b11011); - -wire [2:0] func3_w = opcode_i[14:12]; // R, I, S -wire [6:0] func7_w = opcode_i[31:25]; // R - -wire branch_beq_w = (func3_w == 3'b000); -wire branch_bne_w = (func3_w == 3'b001); -wire branch_blt_w = (func3_w == 3'b100); -wire branch_bge_w = (func3_w == 3'b101); -wire branch_bltu_w = (func3_w == 3'b110); -wire branch_bgeu_w = (func3_w == 3'b111); - -reg branch_r; -reg [31:0] branch_target_r; -reg [31:0] imm12_r; -reg [31:0] bimm_r; -reg [31:0] jimm20_r; - -always @ * -begin - branch_r = 1'b0; + begin + v = (y - x); + if (x[31] != y[31]) greater_than_signed = y[31]; + else greater_than_signed = v[31]; + end + endfunction + wire type_branch_w = (opcode_i[6:2] == 5'b11000); + wire type_jalr_w = (opcode_i[6:2] == 5'b11001); + wire type_jal_w = (opcode_i[6:2] == 5'b11011); + wire [2:0] func3_w = opcode_i[14:12]; // R, I, S + wire [6:0] func7_w = opcode_i[31:25]; // R + wire branch_beq_w = (func3_w == 3'b000); + wire branch_bne_w = (func3_w == 3'b001); + wire branch_blt_w = (func3_w == 3'b100); + wire branch_bge_w = (func3_w == 3'b101); + wire branch_bltu_w = (func3_w == 3'b110); + wire branch_bgeu_w = (func3_w == 3'b111); + reg branch_r; + reg [31:0] branch_target_r; + reg [31:0] imm12_r; + reg [31:0] bimm_r; + reg [31:0] jimm20_r; + always @* begin + branch_r = 1'b0; branch_target_r = 32'b0; - // Opcode decode - imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]}; - bimm_r = {{19{opcode_i[31]}}, opcode_i[31], opcode_i[7], opcode_i[30:25], opcode_i[11:8], 1'b0}; - jimm20_r = {{12{opcode_i[31]}}, opcode_i[19:12], opcode_i[20], opcode_i[30:25], opcode_i[24:21], 1'b0}; - + imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]}; + bimm_r = {{19{opcode_i[31]}}, opcode_i[31], opcode_i[7], opcode_i[30:25], opcode_i[11:8], 1'b0}; + jimm20_r = { + {12{opcode_i[31]}}, opcode_i[19:12], opcode_i[20], opcode_i[30:25], opcode_i[24:21], 1'b0 + }; // Default branch target is relative to current PC - branch_target_r = (pc_i + bimm_r); - - if (type_jal_w) - begin - branch_r = 1'b1; - branch_target_r = pc_i + jimm20_r; + branch_target_r = (pc_i + bimm_r); + if (type_jal_w) begin + branch_r = 1'b1; + branch_target_r = pc_i + jimm20_r; + end else if (type_jalr_w) begin + branch_r = 1'b1; + branch_target_r = rs1_val_i + imm12_r; + branch_target_r[0] = 1'b0; + end else if (type_branch_w) begin + case (1'b1) + branch_beq_w: // beq + branch_r = (rs1_val_i == rs2_val_i); + branch_bne_w: // bne + branch_r = (rs1_val_i != rs2_val_i); + branch_blt_w: // blt + branch_r = less_than_signed(rs1_val_i, rs2_val_i); + branch_bge_w: // bge + branch_r = greater_than_signed(rs1_val_i, rs2_val_i) | (rs1_val_i == rs2_val_i); + branch_bltu_w: // bltu + branch_r = (rs1_val_i < rs2_val_i); + branch_bgeu_w: // bgeu + branch_r = (rs1_val_i >= rs2_val_i); + default: ; + endcase end - else if (type_jalr_w) - begin - branch_r = 1'b1; - branch_target_r = rs1_val_i + imm12_r; - branch_target_r[0] = 1'b0; - end - else if (type_branch_w) - begin - case (1'b1) - branch_beq_w: // beq - branch_r = (rs1_val_i == rs2_val_i); - - branch_bne_w: // bne - branch_r = (rs1_val_i != rs2_val_i); - - branch_blt_w: // blt - branch_r = less_than_signed(rs1_val_i, rs2_val_i); - - branch_bge_w: // bge - branch_r = greater_than_signed(rs1_val_i, rs2_val_i) | (rs1_val_i == rs2_val_i); - - branch_bltu_w: // bltu - branch_r = (rs1_val_i < rs2_val_i); - - branch_bgeu_w: // bgeu - branch_r = (rs1_val_i >= rs2_val_i); - - default: - ; - endcase - end -end - -assign branch_o = branch_r; -assign branch_target_o = branch_target_r; - + end + assign branch_o = branch_r; + assign branch_target_o = branch_target_r; endmodule -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -module uriscv_csr -//----------------------------------------------------------------- -// Params -//----------------------------------------------------------------- -#( - parameter SUPPORT_CSR = 1 - ,parameter SUPPORT_MCYCLE = 1 - ,parameter SUPPORT_MTIMECMP = 1 - ,parameter SUPPORT_MSCRATCH = 1 - ,parameter SUPPORT_MIP_MIE = 1 - ,parameter SUPPORT_MTVEC = 1 - ,parameter SUPPORT_MTVAL = 1 - ,parameter SUPPORT_MULDIV = 1 -) -//----------------------------------------------------------------- -// Ports -//----------------------------------------------------------------- -( - input clk_i - ,input rst_i - - ,input intr_i - ,input [31:0] isr_vector_i - - ,input [31:0] cpu_id_i - - ,input valid_i - ,input [31:0] pc_i - ,input [31:0] opcode_i - ,input [31:0] rs1_val_i - ,input [31:0] rs2_val_i - ,output [31:0] csr_rdata_o - - ,input excpn_invalid_inst_i - ,input excpn_lsu_align_i - - ,input [31:0] mem_addr_i - - ,output [31:0] csr_mepc_o - - ,output exception_o - ,output [5:0] exception_type_o - ,output [31:0] exception_pc_o +module uriscv_csr #( + parameter SUPPORT_CSR = 1, + parameter SUPPORT_MCYCLE = 1, + parameter SUPPORT_MTIMECMP = 1, + parameter SUPPORT_MSCRATCH = 1, + parameter SUPPORT_MIP_MIE = 1, + parameter SUPPORT_MTVEC = 1, + parameter SUPPORT_MTVAL = 1, + parameter SUPPORT_MULDIV = 1 +) ( + input clk_i, + input rst_i, + input intr_i, + input [31:0] isr_vector_i, + input [31:0] cpu_id_i, + input valid_i, + input [31:0] pc_i, + input [31:0] opcode_i, + input [31:0] rs1_val_i, + input [31:0] rs2_val_i, + output [31:0] csr_rdata_o, + input excpn_invalid_inst_i, + input excpn_lsu_align_i, + input [31:0] mem_addr_i, + output [31:0] csr_mepc_o, + output exception_o, + output [ 5:0] exception_type_o, + output [31:0] exception_pc_o ); - - -//----------------------------------------------------------------- -// Includes -//----------------------------------------------------------------- -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -//-------------------------------------------------------------------- -// ALU Operations -//-------------------------------------------------------------------- - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Privilege levels -//----------------------------------------------------------------- - - - - -//----------------------------------------------------------------- -// Status Register -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// IRQ Numbers -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// CSR Registers - Machine -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Non-std - - - -//----------------------------------------------------------------- -// CSR Registers - Simulation control -//----------------------------------------------------------------- - - - - - - - -//----------------------------------------------------------------- -// Exception Causes -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Debug defines for exception types -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - -wire take_interrupt_w; -wire exception_w; - -//----------------------------------------------------------------- -// Instruction Decode -//----------------------------------------------------------------- -wire [2:0] func3_w = opcode_i[14:12]; // R, I, S -wire [4:0] rs1_w = opcode_i[19:15]; -wire [4:0] rs2_w = opcode_i[24:20]; -wire [4:0] rd_w = opcode_i[11:7]; - -wire type_system_w = (opcode_i[6:2] == 5'b11100); -wire type_store_w = (opcode_i[6:2] == 5'b01000); - -wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100); -wire inst_csrrw_w = inst_csr_w && (func3_w == 3'b001); -wire inst_csrrs_w = inst_csr_w && (func3_w == 3'b010); -wire inst_csrrc_w = inst_csr_w && (func3_w == 3'b011); -wire inst_csrrwi_w = inst_csr_w && (func3_w == 3'b101); -wire inst_csrrsi_w = inst_csr_w && (func3_w == 3'b110); -wire inst_csrrci_w = inst_csr_w && (func3_w == 3'b111); - -wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h000000); -wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h002000); -wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h604000); - -wire [11:0] csr_addr_w = valid_i ? opcode_i[31:20] : 12'b0; -wire [31:0] csr_data_w = (inst_csrrwi_w || inst_csrrsi_w || inst_csrrci_w) ? {27'b0, rs1_w} : rs1_val_i; -wire csr_set_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrs_w || inst_csrrwi_w || inst_csrrsi_w): 1'b0; -wire csr_clr_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrc_w || inst_csrrwi_w || inst_csrrci_w): 1'b0; - -//----------------------------------------------------------------- -// Execute: CSR Access -//----------------------------------------------------------------- -reg [31:0] csr_mepc_q; -reg [31:0] csr_mepc_r; -reg [31:0] csr_mcause_q; -reg [31:0] csr_mcause_r; -reg [31:0] csr_sr_q; -reg [31:0] csr_sr_r; -reg [31:0] csr_mcycle_q; -reg [31:0] csr_mcycle_r; -reg [31:0] csr_mtimecmp_q; -reg [31:0] csr_mtimecmp_r; -reg [31:0] csr_mscratch_q; -reg [31:0] csr_mscratch_r; -reg [31:0] csr_mip_q; -reg [31:0] csr_mip_r; -reg [31:0] csr_mie_q; -reg [31:0] csr_mie_r; -reg [31:0] csr_mtvec_q; -reg [31:0] csr_mtvec_r; -reg [31:0] csr_mtval_q; -reg [31:0] csr_mtval_r; - -always @ * -begin - csr_mepc_r = csr_mepc_q; - csr_mcause_r = csr_mcause_q; - csr_sr_r = csr_sr_q; - - csr_mcycle_r = csr_mcycle_q + 32'd1; - csr_mtimecmp_r = csr_mtimecmp_q; - csr_mscratch_r = csr_mscratch_q; - csr_mip_r = csr_mip_q; - csr_mie_r = csr_mie_q; - csr_mtvec_r = csr_mtvec_q; - csr_mtval_r = csr_mtval_q; - + wire take_interrupt_w; + wire exception_w; + wire [2:0] func3_w = opcode_i[14:12]; // R, I, S + wire [4:0] rs1_w = opcode_i[19:15]; + wire [4:0] rs2_w = opcode_i[24:20]; + wire [4:0] rd_w = opcode_i[11:7]; + wire type_system_w = (opcode_i[6:2] == 5'b11100); + wire type_store_w = (opcode_i[6:2] == 5'b01000); + wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100); + wire inst_csrrw_w = inst_csr_w && (func3_w == 3'b001); + wire inst_csrrs_w = inst_csr_w && (func3_w == 3'b010); + wire inst_csrrc_w = inst_csr_w && (func3_w == 3'b011); + wire inst_csrrwi_w = inst_csr_w && (func3_w == 3'b101); + wire inst_csrrsi_w = inst_csr_w && (func3_w == 3'b110); + wire inst_csrrci_w = inst_csr_w && (func3_w == 3'b111); + wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h000000); + wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h002000); + wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h604000); + wire [11:0] csr_addr_w = valid_i ? opcode_i[31:20] : 12'b0; + wire [31:0] csr_data_w = (inst_csrrwi_w || inst_csrrsi_w || inst_csrrci_w) ? {27'b0, rs1_w} : rs1_val_i; + wire csr_set_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrs_w || inst_csrrwi_w || inst_csrrsi_w): 1'b0; + wire csr_clr_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrc_w || inst_csrrwi_w || inst_csrrci_w): 1'b0; + reg [31:0] csr_mepc_q; + reg [31:0] csr_mepc_r; + reg [31:0] csr_mcause_q; + reg [31:0] csr_mcause_r; + reg [31:0] csr_sr_q; + reg [31:0] csr_sr_r; + reg [31:0] csr_mcycle_q; + reg [31:0] csr_mcycle_r; + reg [31:0] csr_mtimecmp_q; + reg [31:0] csr_mtimecmp_r; + reg [31:0] csr_mscratch_q; + reg [31:0] csr_mscratch_r; + reg [31:0] csr_mip_q; + reg [31:0] csr_mip_r; + reg [31:0] csr_mie_q; + reg [31:0] csr_mie_r; + reg [31:0] csr_mtvec_q; + reg [31:0] csr_mtvec_r; + reg [31:0] csr_mtval_q; + reg [31:0] csr_mtval_r; + always @* begin + csr_mepc_r = csr_mepc_q; + csr_mcause_r = csr_mcause_q; + csr_sr_r = csr_sr_q; + csr_mcycle_r = csr_mcycle_q + 32'd1; + csr_mtimecmp_r = csr_mtimecmp_q; + csr_mscratch_r = csr_mscratch_q; + csr_mip_r = csr_mip_q; + csr_mie_r = csr_mie_q; + csr_mtvec_r = csr_mtvec_q; + csr_mtval_r = csr_mtval_q; // External interrupt - if (intr_i) - csr_mip_r[11] = 1'b1; - + if (intr_i) csr_mip_r[11] = 1'b1; // Timer match - generate IRQ - if (SUPPORT_MTIMECMP && csr_mcycle_r == csr_mtimecmp_r) - csr_mip_r[7] = 1'b1; - + if (SUPPORT_MTIMECMP && csr_mcycle_r == csr_mtimecmp_r) csr_mip_r[7] = 1'b1; // Execute instruction / exception - if (valid_i) - begin - // Exception / break / ecall - if (exception_w || inst_ebreak_w || inst_ecall_w) - begin - // Save interrupt / supervisor state - csr_sr_r[7] = csr_sr_q[3]; - csr_sr_r[12:11] = 3; - - // Disable interrupts and enter supervisor mode - csr_sr_r[3] = 1'b0; - - // Save PC of next instruction (not yet executed) - csr_mepc_r = pc_i; - - // Extra info (badaddr / fault opcode) - csr_mtval_r = 32'b0; - - // Exception source - if (excpn_invalid_inst_i) - begin - csr_mcause_r = ((0 << 31) | 2); - csr_mtval_r = opcode_i; + if (valid_i) begin + // Exception / break / ecall + if (exception_w || inst_ebreak_w || inst_ecall_w) begin + // Save interrupt / supervisor state + csr_sr_r[7] = csr_sr_q[3]; + csr_sr_r[12:11] = 3; + // Disable interrupts and enter supervisor mode + csr_sr_r[3] = 1'b0; + // Save PC of next instruction (not yet executed) + csr_mepc_r = pc_i; + // Extra info (badaddr / fault opcode) + csr_mtval_r = 32'b0; + // Exception source + if (excpn_invalid_inst_i) begin + csr_mcause_r = ((0 << 31) | 2); + csr_mtval_r = opcode_i; + end else if (inst_ebreak_w) csr_mcause_r = ((0 << 31) | 3); + else if (inst_ecall_w) csr_mcause_r = ((0 << 31) | 11); + else if (excpn_lsu_align_i) begin + csr_mcause_r = type_store_w ? ((0 << 31) | 6) : ((0 << 31) | 4); + csr_mtval_r = mem_addr_i; + end else if (take_interrupt_w) csr_mcause_r = (1 << 31); + end // MRET + else if (inst_mret_w) begin + // Interrupt enable pop + csr_sr_r[3] = csr_sr_r[7]; + csr_sr_r[7] = 1'b1; + // This CPU only supports machine mode + csr_sr_r[12:11] = 3; + end else begin + case (csr_addr_w) + 12'h341: begin + if (csr_set_w && csr_clr_w) csr_mepc_r = csr_data_w; + else if (csr_set_w) csr_mepc_r = csr_mepc_r | csr_data_w; + else if (csr_clr_w) csr_mepc_r = csr_mepc_r & ~csr_data_w; + end + 12'h342: begin + if (csr_set_w && csr_clr_w) csr_mcause_r = csr_data_w; + else if (csr_set_w) csr_mcause_r = csr_mcause_r | csr_data_w; + else if (csr_clr_w) csr_mcause_r = csr_mcause_r & ~csr_data_w; + end + 12'h300: begin + if (csr_set_w && csr_clr_w) csr_sr_r = csr_data_w; + else if (csr_set_w) csr_sr_r = csr_sr_r | csr_data_w; + else if (csr_clr_w) csr_sr_r = csr_sr_r & ~csr_data_w; + end + 12'h7c0: begin + if (SUPPORT_MTIMECMP && csr_set_w && csr_data_w != 32'b0) begin + csr_mtimecmp_r = csr_data_w; + // Clear interrupt pending + csr_mip_r[7] = 1'b0; end - else if (inst_ebreak_w) - csr_mcause_r = ((0 << 31) | 3); - else if (inst_ecall_w) - csr_mcause_r = ((0 << 31) | 11); - else if (excpn_lsu_align_i) - begin - csr_mcause_r = type_store_w ? ((0 << 31) | 6) : ((0 << 31) | 4); - csr_mtval_r = mem_addr_i; - end - else if (take_interrupt_w) - csr_mcause_r = (1 << 31); - end - // MRET - else if (inst_mret_w) - begin - // Interrupt enable pop - csr_sr_r[3] = csr_sr_r[7]; - csr_sr_r[7] = 1'b1; - - // This CPU only supports machine mode - csr_sr_r[12:11] = 3; - end - else - begin - case (csr_addr_w) - 12'h341: - begin - if (csr_set_w && csr_clr_w) - csr_mepc_r = csr_data_w; - else if (csr_set_w) - csr_mepc_r = csr_mepc_r | csr_data_w; - else if (csr_clr_w) - csr_mepc_r = csr_mepc_r & ~csr_data_w; - end - 12'h342: - begin - if (csr_set_w && csr_clr_w) - csr_mcause_r = csr_data_w; - else if (csr_set_w) - csr_mcause_r = csr_mcause_r | csr_data_w; - else if (csr_clr_w) - csr_mcause_r = csr_mcause_r & ~csr_data_w; - end - 12'h300: - begin - if (csr_set_w && csr_clr_w) - csr_sr_r = csr_data_w; - else if (csr_set_w) - csr_sr_r = csr_sr_r | csr_data_w; - else if (csr_clr_w) - csr_sr_r = csr_sr_r & ~csr_data_w; - end - 12'h7c0: - begin - if (SUPPORT_MTIMECMP && csr_set_w && csr_data_w != 32'b0) - begin - csr_mtimecmp_r = csr_data_w; - - // Clear interrupt pending - csr_mip_r[7] = 1'b0; - end - end - 12'h340: - begin - if (csr_set_w && csr_clr_w) - csr_mscratch_r = csr_data_w; - else if (csr_set_w) - csr_mscratch_r = csr_mscratch_r | csr_data_w; - else if (csr_clr_w) - csr_mscratch_r = csr_mscratch_r & ~csr_data_w; - end - 12'h344: - begin - if (csr_set_w && csr_clr_w) - csr_mip_r = csr_data_w; - else if (csr_set_w) - csr_mip_r = csr_mip_r | csr_data_w; - else if (csr_clr_w) - csr_mip_r = csr_mip_r & ~csr_data_w; - end - 12'h304: - begin - if (csr_set_w && csr_clr_w) - csr_mie_r = csr_data_w; - else if (csr_set_w) - csr_mie_r = csr_mie_r | csr_data_w; - else if (csr_clr_w) - csr_mie_r = csr_mie_r & ~csr_data_w; - end - 12'h305: - begin - if (csr_set_w && csr_clr_w) - csr_mtvec_r = csr_data_w; - else if (csr_set_w) - csr_mtvec_r = csr_mtvec_r | csr_data_w; - else if (csr_clr_w) - csr_mtvec_r = csr_mtvec_r & ~csr_data_w; - end - 12'h343: - begin - if (csr_set_w && csr_clr_w) - csr_mtval_r = csr_data_w; - else if (csr_set_w) - csr_mtval_r = csr_mtval_r | csr_data_w; - else if (csr_clr_w) - csr_mtval_r = csr_mtval_r & ~csr_data_w; - end - default: - ; - endcase - end + end + 12'h340: begin + if (csr_set_w && csr_clr_w) csr_mscratch_r = csr_data_w; + else if (csr_set_w) csr_mscratch_r = csr_mscratch_r | csr_data_w; + else if (csr_clr_w) csr_mscratch_r = csr_mscratch_r & ~csr_data_w; + end + 12'h344: begin + if (csr_set_w && csr_clr_w) csr_mip_r = csr_data_w; + else if (csr_set_w) csr_mip_r = csr_mip_r | csr_data_w; + else if (csr_clr_w) csr_mip_r = csr_mip_r & ~csr_data_w; + end + 12'h304: begin + if (csr_set_w && csr_clr_w) csr_mie_r = csr_data_w; + else if (csr_set_w) csr_mie_r = csr_mie_r | csr_data_w; + else if (csr_clr_w) csr_mie_r = csr_mie_r & ~csr_data_w; + end + 12'h305: begin + if (csr_set_w && csr_clr_w) csr_mtvec_r = csr_data_w; + else if (csr_set_w) csr_mtvec_r = csr_mtvec_r | csr_data_w; + else if (csr_clr_w) csr_mtvec_r = csr_mtvec_r & ~csr_data_w; + end + 12'h343: begin + if (csr_set_w && csr_clr_w) csr_mtval_r = csr_data_w; + else if (csr_set_w) csr_mtval_r = csr_mtval_r | csr_data_w; + else if (csr_clr_w) csr_mtval_r = csr_mtval_r & ~csr_data_w; + end + default: ; + endcase + end end -end - - - - - - - - -always @ (posedge clk_i ) -if (rst_i) -begin - csr_mepc_q <= 32'b0; - csr_mcause_q <= 32'b0; - csr_sr_q <= 32'b0; - csr_mcycle_q <= 32'b0; - csr_mtimecmp_q <= 32'b0; - csr_mscratch_q <= 32'b0; - csr_mie_q <= 32'b0; - csr_mip_q <= 32'b0; - csr_mtvec_q <= 32'b0; - csr_mtval_q <= 32'b0; -end -else -begin - csr_mepc_q <= csr_mepc_r; - csr_mcause_q <= csr_mcause_r; - csr_sr_q <= csr_sr_r; - csr_mcycle_q <= SUPPORT_MCYCLE ? csr_mcycle_r : 32'b0; - csr_mtimecmp_q <= SUPPORT_MTIMECMP ? csr_mtimecmp_r : 32'b0; - csr_mscratch_q <= SUPPORT_MSCRATCH ? csr_mscratch_r : 32'b0; - csr_mie_q <= SUPPORT_MIP_MIE ? csr_mie_r : 32'b0; - csr_mip_q <= SUPPORT_MIP_MIE ? csr_mip_r : 32'b0; - csr_mtvec_q <= SUPPORT_MTVEC ? csr_mtvec_r : 32'b0; - csr_mtval_q <= SUPPORT_MTVAL ? csr_mtval_r : 32'b0; - - - - - - - - - - - - - - - - - -end - -//----------------------------------------------------------------- -// CSR Read Data MUX -//----------------------------------------------------------------- -reg [31:0] csr_data_r; - -always @ * -begin + end + always @(posedge clk_i) + if (rst_i) begin + csr_mepc_q <= 32'b0; + csr_mcause_q <= 32'b0; + csr_sr_q <= 32'b0; + csr_mcycle_q <= 32'b0; + csr_mtimecmp_q <= 32'b0; + csr_mscratch_q <= 32'b0; + csr_mie_q <= 32'b0; + csr_mip_q <= 32'b0; + csr_mtvec_q <= 32'b0; + csr_mtval_q <= 32'b0; + end else begin + csr_mepc_q <= csr_mepc_r; + csr_mcause_q <= csr_mcause_r; + csr_sr_q <= csr_sr_r; + csr_mcycle_q <= SUPPORT_MCYCLE ? csr_mcycle_r : 32'b0; + csr_mtimecmp_q <= SUPPORT_MTIMECMP ? csr_mtimecmp_r : 32'b0; + csr_mscratch_q <= SUPPORT_MSCRATCH ? csr_mscratch_r : 32'b0; + csr_mie_q <= SUPPORT_MIP_MIE ? csr_mie_r : 32'b0; + csr_mip_q <= SUPPORT_MIP_MIE ? csr_mip_r : 32'b0; + csr_mtvec_q <= SUPPORT_MTVEC ? csr_mtvec_r : 32'b0; + csr_mtval_q <= SUPPORT_MTVAL ? csr_mtval_r : 32'b0; + end + reg [31:0] csr_data_r; + always @* begin csr_data_r = 32'b0; - case (csr_addr_w) - 12'h341: csr_data_r = csr_mepc_q & 32'hFFFFFFFF; - 12'h342: csr_data_r = csr_mcause_q & 32'h8000000F; - 12'h300: csr_data_r = csr_sr_q & 32'hFFFFFFFF; - 12'h305: csr_data_r = csr_mtvec_q & 32'hFFFFFFFF; - 12'h343: csr_data_r = csr_mtval_q & 32'hFFFFFFFF; - 12'hc01, - 12'hc00: csr_data_r = csr_mcycle_q & 32'hFFFFFFFF; - 12'h7c0: csr_data_r = csr_mtimecmp_q & 32'hFFFFFFFF; - 12'h340: csr_data_r = csr_mscratch_q & 32'hFFFFFFFF; - 12'h344: csr_data_r = csr_mip_q & ((1 << 11) | (1 << 7) | (1 << 3)); - 12'h304: csr_data_r = csr_mie_q & ((1 << 11) | (1 << 7) | (1 << 3)); - 12'h301: csr_data_r = (SUPPORT_MULDIV ? 32'h00001000 : 32'b0) | - 32'h40000000 | 32'h00000100; - 12'hF14: csr_data_r = cpu_id_i; - default: csr_data_r = 32'b0; + 12'h341: csr_data_r = csr_mepc_q & 32'hFFFFFFFF; + 12'h342: csr_data_r = csr_mcause_q & 32'h8000000F; + 12'h300: csr_data_r = csr_sr_q & 32'hFFFFFFFF; + 12'h305: csr_data_r = csr_mtvec_q & 32'hFFFFFFFF; + 12'h343: csr_data_r = csr_mtval_q & 32'hFFFFFFFF; + 12'hc01, 12'hc00: csr_data_r = csr_mcycle_q & 32'hFFFFFFFF; + 12'h7c0: csr_data_r = csr_mtimecmp_q & 32'hFFFFFFFF; + 12'h340: csr_data_r = csr_mscratch_q & 32'hFFFFFFFF; + 12'h344: csr_data_r = csr_mip_q & ((1 << 11) | (1 << 7) | (1 << 3)); + 12'h304: csr_data_r = csr_mie_q & ((1 << 11) | (1 << 7) | (1 << 3)); + 12'h301: csr_data_r = (SUPPORT_MULDIV ? 32'h00001000 : 32'b0) | 32'h40000000 | 32'h00000100; + 12'hF14: csr_data_r = cpu_id_i; + default: csr_data_r = 32'b0; endcase -end - -assign csr_rdata_o = csr_data_r; - -// Interrupt request and interrupt enabled -assign take_interrupt_w = SUPPORT_MIP_MIE ? ((|(csr_mip_q & csr_mie_q)) & csr_sr_q[3]) : (intr_i & csr_sr_q[3]); -assign exception_w = valid_i && (take_interrupt_w || excpn_invalid_inst_i || (SUPPORT_CSR && excpn_lsu_align_i)); - -assign exception_o = exception_w; -assign exception_pc_o = SUPPORT_MTVEC ? csr_mtvec_q : - SUPPORT_CSR ? isr_vector_i : - pc_i + 32'd4; -assign csr_mepc_o = csr_mepc_q; - -//----------------------------------------------------------------- -// Debug - exception type (checker use only) -//----------------------------------------------------------------- -reg [5:0] v_etype_r; - -always @ * -begin + end + assign csr_rdata_o = csr_data_r; + assign take_interrupt_w = SUPPORT_MIP_MIE ? ((|(csr_mip_q & csr_mie_q)) & csr_sr_q[3]) : (intr_i & csr_sr_q[3]); + assign exception_w = valid_i && (take_interrupt_w || excpn_invalid_inst_i || (SUPPORT_CSR && excpn_lsu_align_i)); + assign exception_o = exception_w; + assign exception_pc_o = SUPPORT_MTVEC ? csr_mtvec_q : SUPPORT_CSR ? isr_vector_i : pc_i + 32'd4; + assign csr_mepc_o = csr_mepc_q; + reg [5:0] v_etype_r; + always @* begin v_etype_r = 6'b0; - - if (csr_mcause_r[31]) - v_etype_r = 6'h20; - else case (csr_mcause_r) - ((0 << 31) | 0) : v_etype_r = 6'h10; - ((0 << 31) | 1) : v_etype_r = 6'h11; - ((0 << 31) | 2): v_etype_r = 6'h12; - ((0 << 31) | 3) : v_etype_r = 6'h13; - ((0 << 31) | 4) : v_etype_r = 6'h14; - ((0 << 31) | 5) : v_etype_r = 6'h15; - ((0 << 31) | 6) : v_etype_r = 6'h16; - ((0 << 31) | 7) : v_etype_r = 6'h17; - ((0 << 31) | 8) : v_etype_r = 6'h18; - ((0 << 31) | 9) : v_etype_r = 6'h19; - ((0 << 31) | 10) : v_etype_r = 6'h1a; - ((0 << 31) | 11) : v_etype_r = 6'h1b; - ((0 << 31) | 12) : v_etype_r = 6'h1c; - ((0 << 31) | 13) : v_etype_r = 6'h1d; - ((0 << 31) | 15) : v_etype_r = 6'h1f; - endcase -end - -assign exception_type_o = v_etype_r; - + if (csr_mcause_r[31]) v_etype_r = 6'h20; + else + case (csr_mcause_r) + ((0 << 31) | 0): v_etype_r = 6'h10; + ((0 << 31) | 1): v_etype_r = 6'h11; + ((0 << 31) | 2): v_etype_r = 6'h12; + ((0 << 31) | 3): v_etype_r = 6'h13; + ((0 << 31) | 4): v_etype_r = 6'h14; + ((0 << 31) | 5): v_etype_r = 6'h15; + ((0 << 31) | 6): v_etype_r = 6'h16; + ((0 << 31) | 7): v_etype_r = 6'h17; + ((0 << 31) | 8): v_etype_r = 6'h18; + ((0 << 31) | 9): v_etype_r = 6'h19; + ((0 << 31) | 10): v_etype_r = 6'h1a; + ((0 << 31) | 11): v_etype_r = 6'h1b; + ((0 << 31) | 12): v_etype_r = 6'h1c; + ((0 << 31) | 13): v_etype_r = 6'h1d; + ((0 << 31) | 15): v_etype_r = 6'h1f; + endcase + end + assign exception_type_o = v_etype_r; endmodule -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -//-------------------------------------------------------------------- -// ALU Operations -//-------------------------------------------------------------------- - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Privilege levels -//----------------------------------------------------------------- - - - - -//----------------------------------------------------------------- -// Status Register -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// IRQ Numbers -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// CSR Registers - Machine -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Non-std - - - -//----------------------------------------------------------------- -// CSR Registers - Simulation control -//----------------------------------------------------------------- - - - - - - - -//----------------------------------------------------------------- -// Exception Causes -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Debug defines for exception types -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -module uriscv_lsu -//----------------------------------------------------------------- -// Params -//----------------------------------------------------------------- -#( - parameter SUPPORT_TRAP_LSU_ALIGN = 1 -) -//----------------------------------------------------------------- -// Ports -//----------------------------------------------------------------- -( - input [31:0] opcode_i - ,input [31:0] rs1_val_i - ,input [31:0] rs2_val_i - - ,output mem_rd_o - ,output [3:0] mem_wr_o - ,output [31:0] mem_addr_o - ,output [31:0] mem_data_o - ,output mem_misaligned_o +module uriscv_lsu #( + parameter SUPPORT_TRAP_LSU_ALIGN = 1 +) ( + input [31:0] opcode_i, + input [31:0] rs1_val_i, + input [31:0] rs2_val_i, + output mem_rd_o, + output [ 3:0] mem_wr_o, + output [31:0] mem_addr_o, + output [31:0] mem_data_o, + output mem_misaligned_o ); - -//----------------------------------------------------------------- -// Includes -//----------------------------------------------------------------- -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -//-------------------------------------------------------------------- -// ALU Operations -//-------------------------------------------------------------------- - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Privilege levels -//----------------------------------------------------------------- - - - - -//----------------------------------------------------------------- -// Status Register -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// IRQ Numbers -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// CSR Registers - Machine -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Non-std - - - -//----------------------------------------------------------------- -// CSR Registers - Simulation control -//----------------------------------------------------------------- - - - - - - - -//----------------------------------------------------------------- -// Exception Causes -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Debug defines for exception types -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Instruction Decode -//----------------------------------------------------------------- -wire type_load_w = (opcode_i[6:2] == 5'b00000); -wire type_store_w = (opcode_i[6:2] == 5'b01000); - -wire [2:0] func3_w = opcode_i[14:12]; // R, I, S - -wire inst_lb_w = type_load_w && (func3_w == 3'b000); -wire inst_lh_w = type_load_w && (func3_w == 3'b001); -wire inst_lw_w = type_load_w && (func3_w == 3'b010); -wire inst_lbu_w = type_load_w && (func3_w == 3'b100); -wire inst_lhu_w = type_load_w && (func3_w == 3'b101); -wire inst_sb_w = type_store_w && (func3_w == 3'b000); -wire inst_sh_w = type_store_w && (func3_w == 3'b001); -wire inst_sw_w = type_store_w && (func3_w == 3'b010); - -//----------------------------------------------------------------- -// Decode LSU operation -//----------------------------------------------------------------- -reg [31:0] imm12_r; -reg [31:0] storeimm_r; - -reg [31:0] mem_addr_r; -reg [31:0] mem_data_r; -reg [3:0] mem_wr_r; -reg mem_rd_r; -reg mem_misaligned_r; - -always @ * -begin - imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]}; - storeimm_r = {{20{opcode_i[31]}}, opcode_i[31:25], opcode_i[11:7]}; - + wire type_load_w = (opcode_i[6:2] == 5'b00000); + wire type_store_w = (opcode_i[6:2] == 5'b01000); + wire [2:0] func3_w = opcode_i[14:12]; // R, I, S + wire inst_lb_w = type_load_w && (func3_w == 3'b000); + wire inst_lh_w = type_load_w && (func3_w == 3'b001); + wire inst_lw_w = type_load_w && (func3_w == 3'b010); + wire inst_lbu_w = type_load_w && (func3_w == 3'b100); + wire inst_lhu_w = type_load_w && (func3_w == 3'b101); + wire inst_sb_w = type_store_w && (func3_w == 3'b000); + wire inst_sh_w = type_store_w && (func3_w == 3'b001); + wire inst_sw_w = type_store_w && (func3_w == 3'b010); + reg [31:0] imm12_r; + reg [31:0] storeimm_r; + reg [31:0] mem_addr_r; + reg [31:0] mem_data_r; + reg [3:0] mem_wr_r; + reg mem_rd_r; + reg mem_misaligned_r; + always @* begin + imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]}; + storeimm_r = {{20{opcode_i[31]}}, opcode_i[31:25], opcode_i[11:7]}; // Memory address - mem_addr_r = rs1_val_i + (type_store_w ? storeimm_r : imm12_r); - + mem_addr_r = rs1_val_i + (type_store_w ? storeimm_r : imm12_r); if (SUPPORT_TRAP_LSU_ALIGN) - mem_misaligned_r = (inst_lh_w | inst_lhu_w | inst_sh_w) ? mem_addr_r[0]: + mem_misaligned_r = (inst_lh_w | inst_lhu_w | inst_sh_w) ? mem_addr_r[0]: (inst_lw_w | inst_sw_w) ? (|mem_addr_r[1:0]): 1'b0; - else - mem_misaligned_r = 1'b0; - + else mem_misaligned_r = 1'b0; mem_data_r = 32'h00000000; mem_wr_r = 4'b0000; mem_rd_r = 1'b0; - case (1'b1) - - type_load_w: - mem_rd_r = 1'b1; - - inst_sb_w: - begin + type_load_w: mem_rd_r = 1'b1; + inst_sb_w: begin case (mem_addr_r[1:0]) - 2'h3 : - begin - mem_data_r = {rs2_val_i[7:0], 24'h000000}; - mem_wr_r = 4'b1000; - mem_rd_r = 1'b0; - end - 2'h2 : - begin - mem_data_r = {8'h00,rs2_val_i[7:0],16'h0000}; - mem_wr_r = 4'b0100; - mem_rd_r = 1'b0; - end - 2'h1 : - begin - mem_data_r = {16'h0000,rs2_val_i[7:0],8'h00}; - mem_wr_r = 4'b0010; - mem_rd_r = 1'b0; - end - 2'h0 : - begin - mem_data_r = {24'h000000,rs2_val_i[7:0]}; - mem_wr_r = 4'b0001; - mem_rd_r = 1'b0; - end - default : ; + 2'h3: begin + mem_data_r = {rs2_val_i[7:0], 24'h000000}; + mem_wr_r = 4'b1000; + mem_rd_r = 1'b0; + end + 2'h2: begin + mem_data_r = {8'h00, rs2_val_i[7:0], 16'h0000}; + mem_wr_r = 4'b0100; + mem_rd_r = 1'b0; + end + 2'h1: begin + mem_data_r = {16'h0000, rs2_val_i[7:0], 8'h00}; + mem_wr_r = 4'b0010; + mem_rd_r = 1'b0; + end + 2'h0: begin + mem_data_r = {24'h000000, rs2_val_i[7:0]}; + mem_wr_r = 4'b0001; + mem_rd_r = 1'b0; + end + default: ; endcase - end - - inst_sh_w: - begin + end + inst_sh_w: begin case (mem_addr_r[1:0]) - 2'h2 : - begin - mem_data_r = {rs2_val_i[15:0],16'h0000}; - mem_wr_r = 4'b1100; - mem_rd_r = 1'b0; - end - default : - begin - mem_data_r = {16'h0000,rs2_val_i[15:0]}; - mem_wr_r = 4'b0011; - mem_rd_r = 1'b0; - end + 2'h2: begin + mem_data_r = {rs2_val_i[15:0], 16'h0000}; + mem_wr_r = 4'b1100; + mem_rd_r = 1'b0; + end + default: begin + mem_data_r = {16'h0000, rs2_val_i[15:0]}; + mem_wr_r = 4'b0011; + mem_rd_r = 1'b0; + end endcase - end - - inst_sw_w: - begin - mem_data_r = rs2_val_i; - mem_wr_r = 4'b1111; - mem_rd_r = 1'b0; - end - - // Non load / store - default: - ; + end + inst_sw_w: begin + mem_data_r = rs2_val_i; + mem_wr_r = 4'b1111; + mem_rd_r = 1'b0; + end + // Non load / store + default: ; endcase -end - -assign mem_rd_o = mem_rd_r; -assign mem_wr_o = mem_wr_r; -assign mem_addr_o = mem_addr_r; -assign mem_data_o = mem_data_r; -assign mem_misaligned_o = mem_misaligned_r; - + end + assign mem_rd_o = mem_rd_r; + assign mem_wr_o = mem_wr_r; + assign mem_addr_o = mem_addr_r; + assign mem_data_o = mem_data_r; + assign mem_misaligned_o = mem_misaligned_r; endmodule -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -module uriscv_muldiv -( - input clk_i, - input rst_i, - +module uriscv_muldiv ( + input clk_i, + input rst_i, // Operation select - input valid_i, - input inst_mul_i, - input inst_mulh_i, - input inst_mulhsu_i, - input inst_mulhu_i, - input inst_div_i, - input inst_divu_i, - input inst_rem_i, - input inst_remu_i, - + input valid_i, + input inst_mul_i, + input inst_mulh_i, + input inst_mulhsu_i, + input inst_mulhu_i, + input inst_div_i, + input inst_divu_i, + input inst_rem_i, + input inst_remu_i, // Operands - input [31:0] operand_ra_i, - input [31:0] operand_rb_i, - + input [31:0] operand_ra_i, + input [31:0] operand_rb_i, // Result - output stall_o, - output ready_o, - output [31:0] result_o + output stall_o, + output ready_o, + output [31:0] result_o ); - -//----------------------------------------------------------------- -// Includes -//----------------------------------------------------------------- -//----------------------------------------------------------------- -// uRISC-V CPU -// V0.5.0 -// github.com/ultraembedded/core_uriscv -// Copyright 2015-2021 -// -// admin@ultra-embedded.com -// -// License: Apache 2.0 -//----------------------------------------------------------------- -// Copyright 2015-2021 github.com/ultraembedded -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//----------------------------------------------------------------- -//-------------------------------------------------------------------- -// ALU Operations -//-------------------------------------------------------------------- - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Privilege levels -//----------------------------------------------------------------- - - - - -//----------------------------------------------------------------- -// Status Register -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// IRQ Numbers -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// CSR Registers - Machine -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Non-std - - - -//----------------------------------------------------------------- -// CSR Registers - Simulation control -//----------------------------------------------------------------- - - - - - - - -//----------------------------------------------------------------- -// Exception Causes -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - -//----------------------------------------------------------------- -// Debug defines for exception types -//----------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - -//------------------------------------------------------------- -// Multiplier -//------------------------------------------------------------- -reg [32:0] mul_operand_a_q; -reg [32:0] mul_operand_b_q; -reg mulhi_sel_q; - -//------------------------------------------------------------- -// Multiplier -//------------------------------------------------------------- -wire [64:0] mult_result_w; -reg [32:0] operand_b_r; -reg [32:0] operand_a_r; -reg [31:0] mul_result_r; - -wire mult_inst_w = inst_mul_i | - inst_mulh_i | - inst_mulhsu_i | - inst_mulhu_i; - - -always @ * -begin - if (inst_mulhsu_i) - operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]}; - else if (inst_mulh_i) - operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]}; - else // MULHU || MUL - operand_a_r = {1'b0, operand_ra_i[31:0]}; -end - -always @ * -begin - if (inst_mulhsu_i) - operand_b_r = {1'b0, operand_rb_i[31:0]}; - else if (inst_mulh_i) - operand_b_r = {operand_rb_i[31], operand_rb_i[31:0]}; - else // MULHU || MUL - operand_b_r = {1'b0, operand_rb_i[31:0]}; -end - -// Pipeline flops for multiplier -always @(posedge clk_i ) -if (rst_i) -begin - mul_operand_a_q <= 33'b0; - mul_operand_b_q <= 33'b0; - mulhi_sel_q <= 1'b0; -end -else if (valid_i && mult_inst_w) -begin - mul_operand_a_q <= operand_a_r; - mul_operand_b_q <= operand_b_r; - mulhi_sel_q <= ~inst_mul_i; -end -else -begin - mul_operand_a_q <= 33'b0; - mul_operand_b_q <= 33'b0; - mulhi_sel_q <= 1'b0; -end - -assign mult_result_w = {{ 32 {mul_operand_a_q[32]}}, mul_operand_a_q}*{{ 32 {mul_operand_b_q[32]}}, mul_operand_b_q}; - -always @ * -begin + reg [32:0] mul_operand_a_q; + reg [32:0] mul_operand_b_q; + reg mulhi_sel_q; + wire [64:0] mult_result_w; + reg [32:0] operand_b_r; + reg [32:0] operand_a_r; + reg [31:0] mul_result_r; + wire mult_inst_w = inst_mul_i | inst_mulh_i | inst_mulhsu_i | inst_mulhu_i; + always @* begin + if (inst_mulhsu_i) operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]}; + else if (inst_mulh_i) operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]}; + else // MULHU || MUL + operand_a_r = {1'b0, operand_ra_i[31:0]}; + end + always @* begin + if (inst_mulhsu_i) operand_b_r = {1'b0, operand_rb_i[31:0]}; + else if (inst_mulh_i) operand_b_r = {operand_rb_i[31], operand_rb_i[31:0]}; + else // MULHU || MUL + operand_b_r = {1'b0, operand_rb_i[31:0]}; + end + always @(posedge clk_i) + if (rst_i) begin + mul_operand_a_q <= 33'b0; + mul_operand_b_q <= 33'b0; + mulhi_sel_q <= 1'b0; + end else if (valid_i && mult_inst_w) begin + mul_operand_a_q <= operand_a_r; + mul_operand_b_q <= operand_b_r; + mulhi_sel_q <= ~inst_mul_i; + end else begin + mul_operand_a_q <= 33'b0; + mul_operand_b_q <= 33'b0; + mulhi_sel_q <= 1'b0; + end + assign mult_result_w = {{ 32 {mul_operand_a_q[32]}}, mul_operand_a_q}*{{ 32 {mul_operand_b_q[32]}}, mul_operand_b_q}; + always @* begin mul_result_r = mulhi_sel_q ? mult_result_w[63:32] : mult_result_w[31:0]; -end - -reg mul_busy_q; - -always @(posedge clk_i ) -if (rst_i) - mul_busy_q <= 1'b0; -else - mul_busy_q <= valid_i & mult_inst_w; - -//------------------------------------------------------------- -// Divider -//------------------------------------------------------------- -wire div_rem_inst_w = inst_div_i || - inst_divu_i || - inst_rem_i || - inst_remu_i; - -wire signed_operation_w = inst_div_i || inst_rem_i; -wire div_operation_w = inst_div_i || inst_divu_i; - -reg [31:0] dividend_q; -reg [62:0] divisor_q; -reg [31:0] quotient_q; -reg [31:0] q_mask_q; -reg div_inst_q; -reg div_busy_q; -reg invert_res_q; - -wire div_start_w = valid_i & div_rem_inst_w & !stall_o; -wire div_complete_w = !(|q_mask_q) & div_busy_q; - -always @ (posedge clk_i ) -if (rst_i) -begin - div_busy_q <= 1'b0; - dividend_q <= 32'b0; - divisor_q <= 63'b0; - invert_res_q <= 1'b0; - quotient_q <= 32'b0; - q_mask_q <= 32'b0; - div_inst_q <= 1'b0; -end -else if (div_start_w) -begin - div_busy_q <= 1'b1; - div_inst_q <= div_operation_w; - - if (signed_operation_w && operand_ra_i[31]) - dividend_q <= -operand_ra_i; - else - dividend_q <= operand_ra_i; - - if (signed_operation_w && operand_rb_i[31]) - divisor_q <= {-operand_rb_i, 31'b0}; - else - divisor_q <= {operand_rb_i, 31'b0}; - - invert_res_q <= (inst_div_i && (operand_ra_i[31] != operand_rb_i[31]) && |operand_rb_i) || + end + reg mul_busy_q; + always @(posedge clk_i) + if (rst_i) mul_busy_q <= 1'b0; + else mul_busy_q <= valid_i & mult_inst_w; + wire div_rem_inst_w = inst_div_i || inst_divu_i || inst_rem_i || inst_remu_i; + wire signed_operation_w = inst_div_i || inst_rem_i; + wire div_operation_w = inst_div_i || inst_divu_i; + reg [31:0] dividend_q; + reg [62:0] divisor_q; + reg [31:0] quotient_q; + reg [31:0] q_mask_q; + reg div_inst_q; + reg div_busy_q; + reg invert_res_q; + wire div_start_w = valid_i & div_rem_inst_w & !stall_o; + wire div_complete_w = !(|q_mask_q) & div_busy_q; + always @(posedge clk_i) + if (rst_i) begin + div_busy_q <= 1'b0; + dividend_q <= 32'b0; + divisor_q <= 63'b0; + invert_res_q <= 1'b0; + quotient_q <= 32'b0; + q_mask_q <= 32'b0; + div_inst_q <= 1'b0; + end else if (div_start_w) begin + div_busy_q <= 1'b1; + div_inst_q <= div_operation_w; + if (signed_operation_w && operand_ra_i[31]) dividend_q <= -operand_ra_i; + else dividend_q <= operand_ra_i; + if (signed_operation_w && operand_rb_i[31]) divisor_q <= {-operand_rb_i, 31'b0}; + else divisor_q <= {operand_rb_i, 31'b0}; + invert_res_q <= (inst_div_i && (operand_ra_i[31] != operand_rb_i[31]) && |operand_rb_i) || (inst_rem_i && operand_ra_i[31]); - - quotient_q <= 32'b0; - q_mask_q <= 32'h80000000; -end -else if (div_complete_w) -begin - div_busy_q <= 1'b0; -end -else if (div_busy_q) -begin - if (divisor_q <= {31'b0, dividend_q}) - begin + quotient_q <= 32'b0; + q_mask_q <= 32'h80000000; + end else if (div_complete_w) begin + div_busy_q <= 1'b0; + end else if (div_busy_q) begin + if (divisor_q <= {31'b0, dividend_q}) begin dividend_q <= dividend_q - divisor_q[31:0]; quotient_q <= quotient_q | q_mask_q; + end + divisor_q <= {1'b0, divisor_q[62:1]}; + q_mask_q <= {1'b0, q_mask_q[31:1]}; end - - divisor_q <= {1'b0, divisor_q[62:1]}; - q_mask_q <= {1'b0, q_mask_q[31:1]}; -end - -reg [31:0] div_result_r; -always @ * -begin + reg [31:0] div_result_r; + always @* begin div_result_r = 32'b0; - - if (div_inst_q) - div_result_r = invert_res_q ? -quotient_q : quotient_q; - else - div_result_r = invert_res_q ? -dividend_q : dividend_q; -end - -//------------------------------------------------------------- -// Shared logic -//------------------------------------------------------------- - -// Stall if divider logic is busy and new multiplier or divider op -assign stall_o = (div_busy_q & (mult_inst_w | div_rem_inst_w)) || - (mul_busy_q & div_rem_inst_w); - -reg [31:0] result_q; -reg ready_q; - -always @ (posedge clk_i ) -if (rst_i) - ready_q <= 1'b0; -else if (mul_busy_q) - ready_q <= 1'b1; -else if (div_complete_w) - ready_q <= 1'b1; -else - ready_q <= 1'b0; - -always @ (posedge clk_i ) -if (rst_i) - result_q <= 32'b0; -else if (div_complete_w) - result_q <= div_result_r; -else if (mul_busy_q) - result_q <= mul_result_r; - -assign result_o = result_q; -assign ready_o = ready_q; - + if (div_inst_q) div_result_r = invert_res_q ? -quotient_q : quotient_q; + else div_result_r = invert_res_q ? -dividend_q : dividend_q; + end + assign stall_o = (div_busy_q & (mult_inst_w | div_rem_inst_w)) || (mul_busy_q & div_rem_inst_w); + reg [31:0] result_q; + reg ready_q; + always @(posedge clk_i) + if (rst_i) ready_q <= 1'b0; + else if (mul_busy_q) ready_q <= 1'b1; + else if (div_complete_w) ready_q <= 1'b1; + else ready_q <= 1'b0; + always @(posedge clk_i) + if (rst_i) result_q <= 32'b0; + else if (div_complete_w) result_q <= div_result_r; + else if (mul_busy_q) result_q <= mul_result_r; + assign result_o = result_q; + assign ready_o = ready_q; endmodule module soc_top ( input bit clk, input bit rst ); - - reg [7:0] mem[65535:0]; integer i; integer f; - initial begin $display("Starting bench"); - // Load TCM memory for (i = 0; i < 65535; i = i + 1) mem[i] = 0; - // $readmemh("test.hex", mem); $readmemh("program.hex", mem); - for (i = 0; i < 65535; i = i + 1) u_mem.write(i, mem[i]); end - wire mem_i_rd_w; wire mem_i_flush_w; wire mem_i_invalidate_w; @@ -3530,7 +1175,6 @@ module soc_top ( wire mem_d_ack_w; wire mem_d_error_w; wire [10:0] mem_d_resp_tag_w; - riscv_core u_dut //----------------------------------------------------------------- // Ports @@ -3551,7 +1195,6 @@ module soc_top ( .intr_i(1'b0), .reset_vector_i(32'h80000000), .cpu_id_i('b0) - // Outputs , .mem_d_addr_o(mem_d_addr_w), .mem_d_data_wr_o(mem_d_data_wr_w), @@ -3567,7 +1210,6 @@ module soc_top ( .mem_i_invalidate_o(mem_i_invalidate_w), .mem_i_pc_o(mem_i_pc_w) ); - tcm_mem u_mem ( // Inputs .clk_i(clk), @@ -3585,7 +1227,6 @@ module soc_top ( .mem_d_invalidate_i(mem_d_invalidate_w), .mem_d_writeback_i(mem_d_writeback_w), .mem_d_flush_i(mem_d_flush_w) - // Outputs , .mem_i_accept_o(mem_i_accept_w), .mem_i_valid_o(mem_i_valid_w), @@ -3597,33 +1238,27 @@ module soc_top ( .mem_d_error_o(mem_d_error_w), .mem_d_resp_tag_o(mem_d_resp_tag_w) ); - endmodule - module tcm_mem_ram ( // Inputs - input clk0_i, - input rst0_i, - input [13:0] addr0_i, - input [31:0] data0_i, - input [ 3:0] wr0_i, - input clk1_i, - input rst1_i, - input [13:0] addr1_i, - input [31:0] data1_i, - input [ 3:0] wr1_i - + input clk0_i, + input rst0_i, + input [13:0] addr0_i, + input [31:0] data0_i, + input [ 3:0] wr0_i, + input clk1_i, + input rst1_i, + input [13:0] addr1_i, + input [31:0] data1_i, + input [ 3:0] wr1_i // Outputs , output [31:0] data0_o, output [31:0] data1_o ); - integer memlog; initial begin memlog = $fopen("mem.log", "w"); end - - //----------------------------------------------------------------- // Dual Port RAM 64KB // Mode: Read First @@ -3631,182 +1266,128 @@ module tcm_mem_ram ( /* verilator lint_off MULTIDRIVEN */ reg [31:0] ram[16383:0] /*verilator public*/; /* verilator lint_on MULTIDRIVEN */ - reg [31:0] ram_read0_q; reg [31:0] ram_read1_q; - // Synchronous write always @(posedge clk0_i) begin if (wr0_i[0]) ram[addr0_i][7:0] <= data0_i[7:0]; if (wr0_i[1]) ram[addr0_i][15:8] <= data0_i[15:8]; if (wr0_i[2]) ram[addr0_i][23:16] <= data0_i[23:16]; if (wr0_i[3]) ram[addr0_i][31:24] <= data0_i[31:24]; - ram_read0_q <= ram[addr0_i]; - $fwrite(memlog, "addr0: 0x%0h data: 0x%0h \n", addr0_i, ram[addr0_i]); end - always @(posedge clk1_i) begin if (wr1_i[0]) ram[addr1_i][7:0] <= data1_i[7:0]; if (wr1_i[1]) ram[addr1_i][15:8] <= data1_i[15:8]; if (wr1_i[2]) ram[addr1_i][23:16] <= data1_i[23:16]; if (wr1_i[3]) ram[addr1_i][31:24] <= data1_i[31:24]; - ram_read1_q <= ram[addr1_i]; $fwrite(memlog, "addr1: 0x%0h data: 0x%0h \n", addr1_i, ram[addr1_i]); end - assign data0_o = ram_read0_q; assign data1_o = ram_read1_q; - - - endmodule - -module tcm_mem -( +module tcm_mem ( // Inputs - input clk_i - ,input rst_i - ,input mem_i_rd_i - ,input mem_i_flush_i - ,input mem_i_invalidate_i - ,input [ 31:0] mem_i_pc_i - ,input [ 31:0] mem_d_addr_i - ,input [ 31:0] mem_d_data_wr_i - ,input mem_d_rd_i - ,input [ 3:0] mem_d_wr_i - ,input mem_d_cacheable_i - ,input [ 10:0] mem_d_req_tag_i - ,input mem_d_invalidate_i - ,input mem_d_writeback_i - ,input mem_d_flush_i - + input clk_i, + input rst_i, + input mem_i_rd_i, + input mem_i_flush_i, + input mem_i_invalidate_i, + input [31:0] mem_i_pc_i, + input [31:0] mem_d_addr_i, + input [31:0] mem_d_data_wr_i, + input mem_d_rd_i, + input [ 3:0] mem_d_wr_i, + input mem_d_cacheable_i, + input [10:0] mem_d_req_tag_i, + input mem_d_invalidate_i, + input mem_d_writeback_i, + input mem_d_flush_i // Outputs - ,output mem_i_accept_o - ,output mem_i_valid_o - ,output mem_i_error_o - ,output [ 31:0] mem_i_inst_o - ,output [ 31:0] mem_d_data_rd_o - ,output mem_d_accept_o - ,output mem_d_ack_o - ,output mem_d_error_o - ,output [ 10:0] mem_d_resp_tag_o + , output mem_i_accept_o, + output mem_i_valid_o, + output mem_i_error_o, + output [31:0] mem_i_inst_o, + output [31:0] mem_d_data_rd_o, + output mem_d_accept_o, + output mem_d_ack_o, + output mem_d_error_o, + output [10:0] mem_d_resp_tag_o ); - -//------------------------------------------------------------- -// Dual Port RAM -//------------------------------------------------------------- -wire [31:0] data_r_w; - -tcm_mem_ram -u_ram -( - // Instruction fetch - .clk0_i(clk_i) - ,.rst0_i(rst_i) - ,.addr0_i(mem_i_pc_i[15:2]) - ,.data0_i(32'b0) - ,.wr0_i(4'b0) - - // External access / Data access - ,.clk1_i(clk_i) - ,.rst1_i(rst_i) - ,.addr1_i(mem_d_addr_i[15:2]) - ,.data1_i(mem_d_data_wr_i) - ,.wr1_i(mem_d_wr_i) - - // Outputs - ,.data0_o(mem_i_inst_o) - ,.data1_o(data_r_w) -); - -//------------------------------------------------------------- -// Instruction Fetch -//------------------------------------------------------------- -reg mem_i_valid_q; - -always @ (posedge clk_i ) -if (rst_i) - mem_i_valid_q <= 1'b0; -else - mem_i_valid_q <= mem_i_rd_i; - -assign mem_i_accept_o = 1'b1; -assign mem_i_valid_o = mem_i_valid_q; -assign mem_i_error_o = 1'b0; - -//------------------------------------------------------------- -// Data Access / Incoming external access -//------------------------------------------------------------- -reg mem_d_accept_q; -reg mem_d_ack_q; -reg [10:0] mem_d_tag_q; - -always @ (posedge clk_i ) -if (rst_i) -begin - mem_d_ack_q <= 1'b0; - mem_d_tag_q <= 11'b0; -end + wire [31:0] data_r_w; + tcm_mem_ram u_ram ( + // Instruction fetch + .clk0_i (clk_i), + .rst0_i (rst_i), + .addr0_i(mem_i_pc_i[15:2]), + .data0_i(32'b0), + .wr0_i (4'b0) + // External access / Data access + , .clk1_i (clk_i), + .rst1_i (rst_i), + .addr1_i(mem_d_addr_i[15:2]), + .data1_i(mem_d_data_wr_i), + .wr1_i (mem_d_wr_i) + // Outputs + , .data0_o(mem_i_inst_o), + .data1_o(data_r_w) + ); + reg mem_i_valid_q; + always @(posedge clk_i) + if (rst_i) mem_i_valid_q <= 1'b0; + else mem_i_valid_q <= mem_i_rd_i; + assign mem_i_accept_o = 1'b1; + assign mem_i_valid_o = mem_i_valid_q; + assign mem_i_error_o = 1'b0; + reg mem_d_accept_q; + reg mem_d_ack_q; + reg [10:0] mem_d_tag_q; + always @(posedge clk_i) + if (rst_i) begin + mem_d_ack_q <= 1'b0; + mem_d_tag_q <= 11'b0; + end else if ((mem_d_rd_i || mem_d_wr_i != 4'b0 || mem_d_flush_i || mem_d_invalidate_i || mem_d_writeback_i) && mem_d_accept_o) begin - mem_d_ack_q <= 1'b1; - mem_d_tag_q <= mem_d_req_tag_i; -end -else - mem_d_ack_q <= 1'b0; - -assign mem_d_ack_o = mem_d_ack_q; -assign mem_d_resp_tag_o = mem_d_tag_q; -assign mem_d_data_rd_o = data_r_w; -assign mem_d_error_o = 1'b0; - -assign mem_d_accept_o = 1'b1; - -//------------------------------------------------------------- -// write: Write byte into memory -//------------------------------------------------------------- -task write; /*verilator public*/ + mem_d_ack_q <= 1'b1; + mem_d_tag_q <= mem_d_req_tag_i; + end else mem_d_ack_q <= 1'b0; + assign mem_d_ack_o = mem_d_ack_q; + assign mem_d_resp_tag_o = mem_d_tag_q; + assign mem_d_data_rd_o = data_r_w; + assign mem_d_error_o = 1'b0; + assign mem_d_accept_o = 1'b1; + task write; /*verilator public*/ input [31:0] addr; - input [7:0] data; -begin - case (addr[1:0]) - 2'd0: u_ram.ram[addr/4][7:0] = data; - 2'd1: u_ram.ram[addr/4][15:8] = data; - 2'd2: u_ram.ram[addr/4][23:16] = data; - 2'd3: u_ram.ram[addr/4][31:24] = data; - endcase -end -endtask - - + input [7:0] data; + begin + case (addr[1:0]) + 2'd0: u_ram.ram[addr/4][7:0] = data; + 2'd1: u_ram.ram[addr/4][15:8] = data; + 2'd2: u_ram.ram[addr/4][23:16] = data; + 2'd3: u_ram.ram[addr/4][31:24] = data; + endcase + end + endtask endmodule module soc_sim ( input bit core_clk ); logic rst_l; - parameter MAX_CYCLES = 1000; - // parameter MAX_CYCLES = 10_000_000_0; int cycleCnt; - always @(posedge core_clk) begin cycleCnt <= cycleCnt + 1; - if (cycleCnt == MAX_CYCLES) begin $display("Hit max cycle count (%0d) .. stopping", cycleCnt); $finish; end end - assign rst_l = cycleCnt > 5; - soc_top rvsoc ( .clk(core_clk), .rst(rst_l) ); - - endmodule