From c57450fa1c0c16ffd28dd886e09933c40e14311d Mon Sep 17 00:00:00 2001 From: "colin.liang" Date: Thu, 5 Jan 2023 21:28:53 +0800 Subject: [PATCH] Add ivlpp to gen single file of RTL. --- uriscv/demo/Makefile | 9 +- uriscv/demo/include.f | 1 + uriscv/demo/ivlpp | Bin 0 -> 187480 bytes uriscv/demo/soc.mk | 3 +- uriscv/demo/top.v | 3812 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 3819 insertions(+), 6 deletions(-) create mode 100644 uriscv/demo/include.f create mode 100755 uriscv/demo/ivlpp create mode 100644 uriscv/demo/top.v diff --git a/uriscv/demo/Makefile b/uriscv/demo/Makefile index 79bd817..e3fa0e3 100644 --- a/uriscv/demo/Makefile +++ b/uriscv/demo/Makefile @@ -32,15 +32,14 @@ clean: rm -rf build obj_dir ##################### Verilog Builds ##################################### +top.v: + ./ivlpp -F include.f -f soc.mk -o top.v -verilator-build: +verilator-build: top.v verilator --cc -CFLAGS ${CFLAGS} \ -Wno-WIDTH \ -Wno-UNOPTFLAT \ - -Wno-LATCH \ - -I../src \ - -F ./soc.mk \ - soc_sim.v \ + top.v \ --top-module soc_sim -exe test_soc_sim.cpp --autoflush $(VERILATOR_DEBUG) cp ${DEMODIR}/test_soc_sim.cpp obj_dir $(MAKE) -j -e -C obj_dir/ -f Vsoc_sim.mk $(VERILATOR_MAKE_FLAGS) diff --git a/uriscv/demo/include.f b/uriscv/demo/include.f new file mode 100644 index 0000000..ab79373 --- /dev/null +++ b/uriscv/demo/include.f @@ -0,0 +1 @@ +I:../src/ diff --git a/uriscv/demo/ivlpp b/uriscv/demo/ivlpp new file mode 100755 index 0000000000000000000000000000000000000000..9fb108df58d73a2496874636c9da2c6a7699b4a7 GIT binary patch literal 187480 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­<-}bY( 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̳NhD8FTm}` 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 literal 0 HcmV?d00001 diff --git a/uriscv/demo/soc.mk b/uriscv/demo/soc.mk index c0eea5a..5434e80 100644 --- a/uriscv/demo/soc.mk +++ b/uriscv/demo/soc.mk @@ -8,4 +8,5 @@ ./soc_top.v ./tcm_mem_ram.v -./tcm_mem.v \ No newline at end of file +./tcm_mem.v +./soc_sim.v \ No newline at end of file diff --git a/uriscv/demo/top.v b/uriscv/demo/top.v new file mode 100644 index 0000000..a2cfe76 --- /dev/null +++ b/uriscv/demo/top.v @@ -0,0 +1,3812 @@ +//----------------------------------------------------------------- +// 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 + + // External interrupt (M_EXT) + ,input intr_i + + // Initial boot address + ,input [ 31:0] reset_vector_i + + // MHARTID value + ,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 + + // Instruction fetch: Unused on this core + ,output mem_i_flush_o + ,output mem_i_invalidate_o + + // Instruction fetch: Unused (tie low) + ,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 + + // 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 + + // Data Access: Unused (tie low) + ,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 + 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 + next_state_r = state_q; + + case (state_q) + // 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 + // 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 + // Memory access complete + 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)) || + (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; + + 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 : ; + 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]) ? + 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] ? + 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 + 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 + invalid_inst_r = SUPPORT_TRAP_INVALID_OPC; + + if ( type_load_w + | type_opimm_w + | type_auipc_w + | type_store_w + | type_alu_op_w + | type_lui_w + | type_branch_w + | type_jalr_w + | type_jal_w + | inst_ecall_w + | inst_ebreak_w + | inst_mret_w + | 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 + // No register writeback + 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); + 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 +//------------------------------------------------------------------- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +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 +( + // ALU operation select + input [3:0] op_i, + + // Operands + input [31:0] a_i, + input [31:0] b_i, + + // Result + 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; + +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 +); + +//----------------------------------------------------------------- +// 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; + 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; + 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; + 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}; + + // 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; + 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; + +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 +); + + +//----------------------------------------------------------------- +// 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; + + // External interrupt + 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; + + // 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; + 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 +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 + 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; + 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 + 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; + +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 +); + +//----------------------------------------------------------------- +// 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]}; + + // Memory address + 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]: + (inst_lw_w | inst_sw_w) ? (|mem_addr_r[1:0]): + 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 + 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 : ; + endcase + 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 + 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: + ; + 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; + +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, + + // 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, + + // Operands + input [31:0] operand_ra_i, + input [31:0] operand_rb_i, + + // Result + 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 + 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) || + (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 + 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 + +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; + +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; + wire [31:0] mem_i_pc_w; + wire [31:0] mem_d_addr_w; + wire [31:0] mem_d_data_wr_w; + wire mem_d_rd_w; + wire [ 3:0] mem_d_wr_w; + wire mem_d_cacheable_w; + wire [10:0] mem_d_req_tag_w; + wire mem_d_invalidate_w; + wire mem_d_writeback_w; + wire mem_d_flush_w; + wire mem_i_accept_w; + wire mem_i_valid_w; + wire mem_i_error_w; + wire [31:0] mem_i_inst_w; + wire [31:0] mem_d_data_rd_w; + wire mem_d_accept_w; + wire mem_d_ack_w; + wire mem_d_error_w; + wire [10:0] mem_d_resp_tag_w; + + riscv_core u_dut + //----------------------------------------------------------------- + // Ports + //----------------------------------------------------------------- + ( + // Inputs + .clk_i(clk), + .rst_i(rst), + .mem_d_data_rd_i(mem_d_data_rd_w), + .mem_d_accept_i(mem_d_accept_w), + .mem_d_ack_i(mem_d_ack_w), + .mem_d_error_i(mem_d_error_w), + .mem_d_resp_tag_i(mem_d_resp_tag_w), + .mem_i_accept_i(mem_i_accept_w), + .mem_i_valid_i(mem_i_valid_w), + .mem_i_error_i(mem_i_error_w), + .mem_i_inst_i(mem_i_inst_w), + .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), + .mem_d_rd_o(mem_d_rd_w), + .mem_d_wr_o(mem_d_wr_w), + .mem_d_cacheable_o(mem_d_cacheable_w), + .mem_d_req_tag_o(mem_d_req_tag_w), + .mem_d_invalidate_o(mem_d_invalidate_w), + .mem_d_writeback_o(mem_d_writeback_w), + .mem_d_flush_o(mem_d_flush_w), + .mem_i_rd_o(mem_i_rd_w), + .mem_i_flush_o(mem_i_flush_w), + .mem_i_invalidate_o(mem_i_invalidate_w), + .mem_i_pc_o(mem_i_pc_w) + ); + + tcm_mem u_mem ( + // Inputs + .clk_i(clk), + .rst_i(rst), + .mem_i_rd_i(mem_i_rd_w), + .mem_i_flush_i(mem_i_flush_w), + .mem_i_invalidate_i(mem_i_invalidate_w), + .mem_i_pc_i(mem_i_pc_w), + .mem_d_addr_i(mem_d_addr_w), + .mem_d_data_wr_i(mem_d_data_wr_w), + .mem_d_rd_i(mem_d_rd_w), + .mem_d_wr_i(mem_d_wr_w), + .mem_d_cacheable_i(mem_d_cacheable_w), + .mem_d_req_tag_i(mem_d_req_tag_w), + .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), + .mem_i_error_o(mem_i_error_w), + .mem_i_inst_o(mem_i_inst_w), + .mem_d_data_rd_o(mem_d_data_rd_w), + .mem_d_accept_o(mem_d_accept_w), + .mem_d_ack_o(mem_d_ack_w), + .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 + + // 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 + //----------------------------------------------------------------- + /* 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 +( + // 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 + + // 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 +); + +//------------------------------------------------------------- +// 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 +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*/ + 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 + + +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