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 0000000..9fb108d Binary files /dev/null and b/uriscv/demo/ivlpp differ 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