module riscv_core #( parameter SUPPORT_MUL = 1, parameter SUPPORT_DIV = 1, parameter SUPPORT_CSR = 1, parameter SUPPORT_TRAP_LSU_ALIGN = 1, parameter SUPPORT_MTVEC = 0, parameter SUPPORT_MTVAL = 0, parameter SUPPORT_MIP_MIE = 0, parameter SUPPORT_MSCRATCH = 0, parameter SUPPORT_MCYCLE = 1, parameter SUPPORT_MTIMECMP = 0, parameter SUPPORT_TRAP_INVALID_OPC = 1, parameter SUPPORT_BRAM_REGFILE = 0, parameter ISR_VECTOR = 32'h00000010 ) ( input clk_i , input rst_i // External interrupt (M_EXT) , input intr_i // 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 ); localparam PC_W = 32; localparam PC_PAD_W = 0; localparam PC_EXT_W = 0; localparam ADDR_W = 32; localparam ADDR_PAD_W = 0; localparam STATE_W = 3; localparam STATE_RESET = 0; localparam STATE_FETCH_WB = 1; localparam STATE_EXEC = 2; localparam STATE_MEM = 3; localparam STATE_DECODE = 4; // Only if SUPPORT_BRAM_REGFILE = 1 reg [STATE_W-1:0] state_q; reg [ PC_W-1:0] pc_q; reg [ 4:0] rd_q; reg rd_wr_en_q; reg [ 31:0] alu_a_q; reg [ 31:0] alu_b_q; reg [ 3:0] alu_func_q; wire [ 31:0] csr_data_w; reg invalid_inst_r; wire [ 4:0] rd_w; wire [ 4:0] rs1_w; wire [ 4:0] rs2_w; wire [ 31:0] rs1_val_w; wire [ 31:0] rs2_val_w; wire [ 31:0] opcode_w; wire opcode_valid_w; wire opcode_fetch_w = mem_i_rd_o & mem_i_accept_i; wire exception_w; wire [ 5:0] exception_type_w; wire [ 31:0] exception_target_w; wire [ 31:0] csr_mepc_w; reg [ 31:0] load_result_r; wire rd_writeen_w; wire [ 31:0] rd_val_w; wire mem_misaligned_w; reg [ ADDR_W-1:0] mem_addr_q; reg [ 31:0] mem_data_q; reg [ 3:0] mem_wr_q; reg mem_rd_q; reg [ 1:0] load_offset_q; reg load_signed_q; reg load_byte_q; reg load_half_q; wire enable_w = 1'b1; wire [ 31:0] muldiv_result_w; wire muldiv_ready_w; wire muldiv_inst_w; uriscv_alu alu ( // ALU operation select .op_i(alu_func_q), // Operands .a_i (alu_a_q), .b_i (alu_b_q), // Result .p_o (rd_val_w) ); reg [31:0] reg_file[0:31]; always @(posedge clk_i) if (rd_writeen_w) reg_file[rd_q] <= rd_val_w; wire [31:0] rs1_val_gpr_w = reg_file[mem_i_inst_i[19:15]]; wire [31:0] rs2_val_gpr_w = reg_file[mem_i_inst_i[24:20]]; reg [31:0] rs1_val_gpr_q; reg [31:0] rs2_val_gpr_q; always @(posedge clk_i) begin rs1_val_gpr_q <= rs1_val_gpr_w; rs2_val_gpr_q <= rs2_val_gpr_w; end assign rs1_val_w = SUPPORT_BRAM_REGFILE ? rs1_val_gpr_q : rs1_val_gpr_w; assign rs2_val_w = SUPPORT_BRAM_REGFILE ? rs2_val_gpr_q : rs2_val_gpr_w; assign rd_writeen_w = rd_wr_en_q & (state_q == STATE_FETCH_WB); reg [STATE_W-1:0] next_state_r; always @* begin next_state_r = state_q; case (state_q) // RESET - First cycle after reset STATE_RESET: begin 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 always @(posedge clk_i) if (rst_i) state_q <= STATE_RESET; else state_q <= next_state_r; reg [31:0] opcode_q; always @(posedge clk_i) if (rst_i) opcode_q <= 32'b0; else if (state_q == STATE_DECODE) opcode_q <= mem_i_inst_i; reg opcode_valid_q; always @(posedge clk_i) if (rst_i) opcode_valid_q <= 1'b0; else if (state_q == STATE_DECODE) opcode_valid_q <= mem_i_valid_i; else opcode_valid_q <= 1'b0; assign opcode_w = SUPPORT_BRAM_REGFILE ? opcode_q : mem_i_inst_i; assign opcode_valid_w = SUPPORT_BRAM_REGFILE ? opcode_valid_q : mem_i_valid_i; assign rs1_w = opcode_w[19:15]; assign rs2_w = opcode_w[24:20]; assign rd_w = opcode_w[11:7]; wire type_rvc_w = (opcode_w[1:0] != 2'b11); wire type_load_w = (opcode_w[6:2] == 5'b00000); wire type_opimm_w = (opcode_w[6:2] == 5'b00100); wire type_auipc_w = (opcode_w[6:2] == 5'b00101); wire type_store_w = (opcode_w[6:2] == 5'b01000); wire type_op_w = (opcode_w[6:2] == 5'b01100); wire type_lui_w = (opcode_w[6:2] == 5'b01101); wire type_branch_w = (opcode_w[6:2] == 5'b11000); wire type_jalr_w = (opcode_w[6:2] == 5'b11001); wire type_jal_w = (opcode_w[6:2] == 5'b11011); wire type_system_w = (opcode_w[6:2] == 5'b11100); wire type_miscm_w = (opcode_w[6:2] == 5'b00011); wire [2:0] func3_w = opcode_w[14:12]; // R, I, S wire [6:0] func7_w = opcode_w[31:25]; // R wire type_alu_op_w = (type_op_w && (func7_w == 7'b0000000)) || (type_op_w && (func7_w == 7'b0100000)); wire inst_lb_w = (func3_w == 3'b000); wire inst_lh_w = (func3_w == 3'b001); wire inst_lbu_w = (func3_w == 3'b100); wire inst_lhu_w = (func3_w == 3'b101); wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h000000); wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h002000); wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_w[31:7] == 25'h604000); wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100); wire mul_inst_w = SUPPORT_MUL && type_op_w && (func7_w == 7'b0000001) && ~func3_w[2]; wire div_inst_w = SUPPORT_DIV && type_op_w && (func7_w == 7'b0000001) && func3_w[2]; wire inst_mul_w = mul_inst_w && (func3_w == 3'b000); wire inst_mulh_w = mul_inst_w && (func3_w == 3'b001); wire inst_mulhsu_w = mul_inst_w && (func3_w == 3'b010); wire inst_mulhu_w = mul_inst_w && (func3_w == 3'b011); wire inst_div_w = div_inst_w && (func3_w == 3'b100); wire inst_divu_w = div_inst_w && (func3_w == 3'b101); wire inst_rem_w = div_inst_w && (func3_w == 3'b110); wire inst_remu_w = div_inst_w && (func3_w == 3'b111); wire inst_nop_w = (type_miscm_w && (func3_w == 3'b000)) | // fence (type_miscm_w && (func3_w == 3'b001)); // fence.i assign muldiv_inst_w = mul_inst_w | div_inst_w; reg [31:0] imm20_r; reg [31:0] imm12_r; always @* begin imm20_r = {opcode_w[31:12], 12'b0}; imm12_r = {{20{opcode_w[31]}}, opcode_w[31:20]}; end reg [ 3:0] alu_func_r; reg [31:0] alu_input_a_r; reg [31:0] alu_input_b_r; reg write_rd_r; always @* begin alu_func_r = 4'b0000; alu_input_a_r = rs1_val_w; alu_input_b_r = rs2_val_w; write_rd_r = 1'b0; case (1'b1) type_alu_op_w: begin alu_input_a_r = rs1_val_w; alu_input_b_r = rs2_val_w; end type_opimm_w: begin alu_input_a_r = rs1_val_w; alu_input_b_r = imm12_r; end type_lui_w: begin alu_input_a_r = 32'b0; alu_input_b_r = imm20_r; end type_auipc_w: begin alu_input_a_r[PC_W-1:0] = pc_q; alu_input_b_r = imm20_r; end type_jal_w, type_jalr_w: begin alu_input_a_r[PC_W-1:0] = pc_q; alu_input_b_r = 32'd4; end default: ; 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 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 wire branch_w; wire [31:0] branch_target_w; wire [31:0] pc_ext_w = {{PC_EXT_W{1'b0}}, pc_q}; uriscv_branch u_branch ( .pc_i(pc_ext_w), .opcode_i(opcode_w), .rs1_val_i(rs1_val_w), .rs2_val_i(rs2_val_w), .branch_o(branch_w), .branch_target_o(branch_target_w) ); always @* begin invalid_inst_r = SUPPORT_TRAP_INVALID_OPC; if ( type_load_w | type_opimm_w | type_auipc_w | 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 always @(posedge clk_i) if (rst_i) begin alu_func_q <= 4'b0000; alu_a_q <= 32'h00000000; alu_b_q <= 32'h00000000; rd_q <= 5'b00000; // Reset x0 in-case of RAM rd_wr_en_q <= 1'b1; end else if ((state_q == STATE_MEM) && mem_d_ack_i) begin // Update ALU input with load result alu_func_q <= 4'b0000; alu_a_q <= load_result_r; alu_b_q <= 32'b0; end else if (muldiv_ready_w) begin // Update ALU input with load result alu_func_q <= 4'b0000; alu_a_q <= muldiv_result_w; alu_b_q <= 32'b0; end else if (opcode_valid_w) begin // Update ALU input flops alu_func_q <= alu_func_r; alu_a_q <= alu_input_a_r; alu_b_q <= alu_input_b_r; // Take exception if (exception_w) begin // No register writeback rd_q <= 5'b0; rd_wr_en_q <= 1'b0; end // Valid instruction else begin // 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; 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 assign mem_i_rd_o = (state_q == STATE_FETCH_WB); assign mem_i_pc_o = pc_ext_w; wire mem_rd_w; wire [ 3:0] mem_wr_w; wire [31:0] mem_addr_w; wire [31:0] mem_data_w; uriscv_lsu #( .SUPPORT_TRAP_LSU_ALIGN(SUPPORT_TRAP_LSU_ALIGN) ) u_lsu ( .opcode_i(opcode_w), .rs1_val_i(rs1_val_w), .rs2_val_i(rs2_val_w), .mem_rd_o(mem_rd_w), .mem_wr_o(mem_wr_w), .mem_addr_o(mem_addr_w), .mem_data_o(mem_data_w), .mem_misaligned_o(mem_misaligned_w) ); always @(posedge clk_i) if (rst_i) begin mem_addr_q <= {ADDR_W{1'b0}}; mem_data_q <= 32'h00000000; mem_wr_q <= 4'b0000; mem_rd_q <= 1'b0; end else if (opcode_valid_w && !exception_w) begin mem_addr_q <= {mem_addr_w[ADDR_W-1:2], 2'b0}; mem_data_q <= mem_data_w; mem_wr_q <= mem_wr_w; mem_rd_q <= mem_rd_w; end else if (mem_d_accept_i) begin mem_wr_q <= 4'b0000; mem_rd_q <= 1'b0; end always @(posedge clk_i) if (rst_i) begin load_signed_q <= 1'b0; load_byte_q <= 1'b0; load_half_q <= 1'b0; load_offset_q <= 2'b0; end else if (opcode_valid_w) begin load_signed_q <= inst_lh_w | inst_lb_w; load_byte_q <= inst_lb_w | inst_lbu_w; load_half_q <= inst_lh_w | inst_lhu_w; load_offset_q <= mem_addr_w[1:0]; end assign mem_d_addr_o = {{ADDR_PAD_W{1'b0}}, mem_addr_q}; assign mem_d_data_wr_o = mem_data_q; assign mem_d_wr_o = mem_wr_q; assign mem_d_rd_o = mem_rd_q; uriscv_csr #( .SUPPORT_CSR(SUPPORT_CSR), .SUPPORT_MCYCLE(SUPPORT_MCYCLE), .SUPPORT_MTIMECMP(SUPPORT_MTIMECMP), .SUPPORT_MSCRATCH(SUPPORT_MSCRATCH), .SUPPORT_MIP_MIE(SUPPORT_MIP_MIE), .SUPPORT_MTVEC(SUPPORT_MTVEC), .SUPPORT_MTVAL(SUPPORT_MTVAL), .SUPPORT_MULDIV(SUPPORT_MUL || SUPPORT_DIV) ) u_csr ( .clk_i(clk_i), .rst_i(rst_i) // Reset vector (only used if SUPPORT_MTVEC=0) , .isr_vector_i(reset_vector_i + ISR_VECTOR) // HartID , .cpu_id_i(cpu_id_i) // External interrupt , .intr_i(intr_i) // Executing instruction , .valid_i(opcode_valid_w), .opcode_i(opcode_w), .pc_i(pc_q), .rs1_val_i(rs1_val_w), .rs2_val_i(rs2_val_w) // CSR read result , .csr_rdata_o(csr_data_w) // Exception sources , .excpn_invalid_inst_i(invalid_inst_r), .excpn_lsu_align_i(mem_misaligned_w) // Used on memory alignment errors , .mem_addr_i(mem_addr_w) // CSR registers , .csr_mepc_o(csr_mepc_w) // Exception entry , .exception_o(exception_w), .exception_type_o(exception_type_w), .exception_pc_o(exception_target_w) ); generate if (SUPPORT_MUL != 0 || SUPPORT_DIV != 0) begin uriscv_muldiv u_muldiv ( .clk_i(clk_i), .rst_i(rst_i), // Operation select .valid_i(opcode_valid_w & ~exception_w), .inst_mul_i(inst_mul_w), .inst_mulh_i(inst_mulh_w), .inst_mulhsu_i(inst_mulhsu_w), .inst_mulhu_i(inst_mulhu_w), .inst_div_i(inst_div_w), .inst_divu_i(inst_divu_w), .inst_rem_i(inst_rem_w), .inst_remu_i(inst_remu_w), // Operands .operand_ra_i(rs1_val_w), .operand_rb_i(rs2_val_w), // Result .stall_o(), .ready_o(muldiv_ready_w), .result_o(muldiv_result_w) ); end else begin assign muldiv_ready_w = 1'b0; assign muldiv_result_w = 32'b0; end endgenerate assign mem_i_flush_o = 1'b0; assign mem_i_invalidate_o = 1'b0; assign mem_d_flush_o = 1'b0; assign mem_d_cacheable_o = 1'b0; assign mem_d_req_tag_o = 11'b0; assign mem_d_invalidate_o = 1'b0; assign mem_d_writeback_o = 1'b0; endmodule 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 ); reg [ 31:0] result_r; reg [31:16] shift_right_fill_r; reg [ 31:0] shift_right_1_r; reg [ 31:0] shift_right_2_r; reg [ 31:0] shift_right_4_r; reg [ 31:0] shift_right_8_r; reg [ 31:0] shift_left_1_r; reg [ 31:0] shift_left_2_r; reg [ 31:0] shift_left_4_r; reg [ 31:0] shift_left_8_r; wire [ 31:0] sub_res_w = a_i - b_i; always @* begin case (op_i) //---------------------------------------------- // Shift Left //---------------------------------------------- 4'b0001: begin if (b_i[0] == 1'b1) shift_left_1_r = {a_i[30:0], 1'b0}; else shift_left_1_r = a_i; if (b_i[1] == 1'b1) shift_left_2_r = {shift_left_1_r[29:0], 2'b00}; else shift_left_2_r = shift_left_1_r; if (b_i[2] == 1'b1) shift_left_4_r = {shift_left_2_r[27:0], 4'b0000}; else shift_left_4_r = shift_left_2_r; if (b_i[3] == 1'b1) shift_left_8_r = {shift_left_4_r[23:0], 8'b00000000}; else shift_left_8_r = shift_left_4_r; if (b_i[4] == 1'b1) result_r = {shift_left_8_r[15:0], 16'b0000000000000000}; else result_r = shift_left_8_r; end //---------------------------------------------- // Shift Right //---------------------------------------------- 4'b0010, 4'b0011: begin // Arithmetic shift? Fill with 1's if MSB set if (a_i[31] == 1'b1 && op_i == 4'b0011) shift_right_fill_r = 16'b1111111111111111; else shift_right_fill_r = 16'b0000000000000000; if (b_i[0] == 1'b1) shift_right_1_r = {shift_right_fill_r[31], a_i[31:1]}; else shift_right_1_r = a_i; if (b_i[1] == 1'b1) shift_right_2_r = {shift_right_fill_r[31:30], shift_right_1_r[31:2]}; else shift_right_2_r = shift_right_1_r; if (b_i[2] == 1'b1) shift_right_4_r = {shift_right_fill_r[31:28], shift_right_2_r[31:4]}; else shift_right_4_r = shift_right_2_r; if (b_i[3] == 1'b1) shift_right_8_r = {shift_right_fill_r[31:24], shift_right_4_r[31:8]}; else shift_right_8_r = shift_right_4_r; if (b_i[4] == 1'b1) result_r = {shift_right_fill_r[31:16], shift_right_8_r[31:16]}; else result_r = shift_right_8_r; end //---------------------------------------------- // Arithmetic //---------------------------------------------- 4'b0100: begin result_r = (a_i + b_i); end 4'b0110: begin result_r = sub_res_w; end //---------------------------------------------- // Logical //---------------------------------------------- 4'b0111: begin result_r = (a_i & b_i); end 4'b1000: begin result_r = (a_i | b_i); end 4'b1001: begin result_r = (a_i ^ b_i); end //---------------------------------------------- // Comparision //---------------------------------------------- 4'b1010: begin result_r = (a_i < b_i) ? 32'h1 : 32'h0; end 4'b1011: begin if (a_i[31] != b_i[31]) result_r = a_i[31] ? 32'h1 : 32'h0; else result_r = sub_res_w[31] ? 32'h1 : 32'h0; end default: begin result_r = a_i; end endcase end assign p_o = result_r; endmodule 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 ); 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 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 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 module uriscv_csr #( parameter SUPPORT_CSR = 1, parameter SUPPORT_MCYCLE = 1, parameter SUPPORT_MTIMECMP = 1, parameter SUPPORT_MSCRATCH = 1, parameter SUPPORT_MIP_MIE = 1, parameter SUPPORT_MTVEC = 1, parameter SUPPORT_MTVAL = 1, parameter SUPPORT_MULDIV = 1 ) ( input clk_i, input rst_i, input intr_i, input [31:0] isr_vector_i, input [31:0] cpu_id_i, input valid_i, input [31:0] pc_i, input [31:0] opcode_i, input [31:0] rs1_val_i, input [31:0] rs2_val_i, output [31:0] csr_rdata_o, input excpn_invalid_inst_i, input excpn_lsu_align_i, input [31:0] mem_addr_i, output [31:0] csr_mepc_o, output exception_o, output [ 5:0] exception_type_o, output [31:0] exception_pc_o ); wire take_interrupt_w; wire exception_w; wire [2:0] func3_w = opcode_i[14:12]; // R, I, S wire [4:0] rs1_w = opcode_i[19:15]; wire [4:0] rs2_w = opcode_i[24:20]; wire [4:0] rd_w = opcode_i[11:7]; wire type_system_w = (opcode_i[6:2] == 5'b11100); wire type_store_w = (opcode_i[6:2] == 5'b01000); wire inst_csr_w = SUPPORT_CSR && type_system_w && (func3_w != 3'b000 && func3_w != 3'b100); wire inst_csrrw_w = inst_csr_w && (func3_w == 3'b001); wire inst_csrrs_w = inst_csr_w && (func3_w == 3'b010); wire inst_csrrc_w = inst_csr_w && (func3_w == 3'b011); wire inst_csrrwi_w = inst_csr_w && (func3_w == 3'b101); wire inst_csrrsi_w = inst_csr_w && (func3_w == 3'b110); wire inst_csrrci_w = inst_csr_w && (func3_w == 3'b111); wire inst_ecall_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h000000); wire inst_ebreak_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h002000); wire inst_mret_w = SUPPORT_CSR && type_system_w && (opcode_i[31:7] == 25'h604000); wire [11:0] csr_addr_w = valid_i ? opcode_i[31:20] : 12'b0; wire [31:0] csr_data_w = (inst_csrrwi_w || inst_csrrsi_w || inst_csrrci_w) ? {27'b0, rs1_w} : rs1_val_i; wire csr_set_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrs_w || inst_csrrwi_w || inst_csrrsi_w): 1'b0; wire csr_clr_w = (valid_i && !exception_w) ? (inst_csrrw_w || inst_csrrc_w || inst_csrrwi_w || inst_csrrci_w): 1'b0; reg [31:0] csr_mepc_q; reg [31:0] csr_mepc_r; reg [31:0] csr_mcause_q; reg [31:0] csr_mcause_r; reg [31:0] csr_sr_q; reg [31:0] csr_sr_r; reg [31:0] csr_mcycle_q; reg [31:0] csr_mcycle_r; reg [31:0] csr_mtimecmp_q; reg [31:0] csr_mtimecmp_r; reg [31:0] csr_mscratch_q; reg [31:0] csr_mscratch_r; reg [31:0] csr_mip_q; reg [31:0] csr_mip_r; reg [31:0] csr_mie_q; reg [31:0] csr_mie_r; reg [31:0] csr_mtvec_q; reg [31:0] csr_mtvec_r; reg [31:0] csr_mtval_q; reg [31:0] csr_mtval_r; always @* begin csr_mepc_r = csr_mepc_q; csr_mcause_r = csr_mcause_q; csr_sr_r = csr_sr_q; csr_mcycle_r = csr_mcycle_q + 32'd1; csr_mtimecmp_r = csr_mtimecmp_q; csr_mscratch_r = csr_mscratch_q; csr_mip_r = csr_mip_q; csr_mie_r = csr_mie_q; csr_mtvec_r = csr_mtvec_q; csr_mtval_r = csr_mtval_q; // External interrupt if (intr_i) csr_mip_r[11] = 1'b1; // 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 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; assign take_interrupt_w = SUPPORT_MIP_MIE ? ((|(csr_mip_q & csr_mie_q)) & csr_sr_q[3]) : (intr_i & csr_sr_q[3]); assign exception_w = valid_i && (take_interrupt_w || excpn_invalid_inst_i || (SUPPORT_CSR && excpn_lsu_align_i)); assign exception_o = exception_w; assign exception_pc_o = SUPPORT_MTVEC ? csr_mtvec_q : SUPPORT_CSR ? isr_vector_i : pc_i + 32'd4; assign csr_mepc_o = csr_mepc_q; reg [5:0] v_etype_r; always @* begin v_etype_r = 6'b0; if (csr_mcause_r[31]) v_etype_r = 6'h20; else case (csr_mcause_r) ((0 << 31) | 0): v_etype_r = 6'h10; ((0 << 31) | 1): v_etype_r = 6'h11; ((0 << 31) | 2): v_etype_r = 6'h12; ((0 << 31) | 3): v_etype_r = 6'h13; ((0 << 31) | 4): v_etype_r = 6'h14; ((0 << 31) | 5): v_etype_r = 6'h15; ((0 << 31) | 6): v_etype_r = 6'h16; ((0 << 31) | 7): v_etype_r = 6'h17; ((0 << 31) | 8): v_etype_r = 6'h18; ((0 << 31) | 9): v_etype_r = 6'h19; ((0 << 31) | 10): v_etype_r = 6'h1a; ((0 << 31) | 11): v_etype_r = 6'h1b; ((0 << 31) | 12): v_etype_r = 6'h1c; ((0 << 31) | 13): v_etype_r = 6'h1d; ((0 << 31) | 15): v_etype_r = 6'h1f; endcase end assign exception_type_o = v_etype_r; endmodule module uriscv_lsu #( parameter SUPPORT_TRAP_LSU_ALIGN = 1 ) ( input [31:0] opcode_i, input [31:0] rs1_val_i, input [31:0] rs2_val_i, output mem_rd_o, output [ 3:0] mem_wr_o, output [31:0] mem_addr_o, output [31:0] mem_data_o, output mem_misaligned_o ); wire type_load_w = (opcode_i[6:2] == 5'b00000); wire type_store_w = (opcode_i[6:2] == 5'b01000); wire [2:0] func3_w = opcode_i[14:12]; // R, I, S wire inst_lb_w = type_load_w && (func3_w == 3'b000); wire inst_lh_w = type_load_w && (func3_w == 3'b001); wire inst_lw_w = type_load_w && (func3_w == 3'b010); wire inst_lbu_w = type_load_w && (func3_w == 3'b100); wire inst_lhu_w = type_load_w && (func3_w == 3'b101); wire inst_sb_w = type_store_w && (func3_w == 3'b000); wire inst_sh_w = type_store_w && (func3_w == 3'b001); wire inst_sw_w = type_store_w && (func3_w == 3'b010); reg [31:0] imm12_r; reg [31:0] storeimm_r; reg [31:0] mem_addr_r; reg [31:0] mem_data_r; reg [3:0] mem_wr_r; reg mem_rd_r; reg mem_misaligned_r; always @* begin imm12_r = {{20{opcode_i[31]}}, opcode_i[31:20]}; storeimm_r = {{20{opcode_i[31]}}, opcode_i[31:25], opcode_i[11:7]}; // Memory address mem_addr_r = rs1_val_i + (type_store_w ? storeimm_r : imm12_r); 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 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 ); reg [32:0] mul_operand_a_q; reg [32:0] mul_operand_b_q; reg mulhi_sel_q; wire [64:0] mult_result_w; reg [32:0] operand_b_r; reg [32:0] operand_a_r; reg [31:0] mul_result_r; wire mult_inst_w = inst_mul_i | inst_mulh_i | inst_mulhsu_i | inst_mulhu_i; always @* begin if (inst_mulhsu_i) operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]}; else if (inst_mulh_i) operand_a_r = {operand_ra_i[31], operand_ra_i[31:0]}; else // MULHU || MUL operand_a_r = {1'b0, operand_ra_i[31:0]}; end always @* begin if (inst_mulhsu_i) operand_b_r = {1'b0, operand_rb_i[31:0]}; else if (inst_mulh_i) operand_b_r = {operand_rb_i[31], operand_rb_i[31:0]}; else // MULHU || MUL operand_b_r = {1'b0, operand_rb_i[31:0]}; end always @(posedge clk_i) if (rst_i) begin mul_operand_a_q <= 33'b0; mul_operand_b_q <= 33'b0; mulhi_sel_q <= 1'b0; end else if (valid_i && mult_inst_w) begin mul_operand_a_q <= operand_a_r; mul_operand_b_q <= operand_b_r; mulhi_sel_q <= ~inst_mul_i; end else begin mul_operand_a_q <= 33'b0; mul_operand_b_q <= 33'b0; mulhi_sel_q <= 1'b0; end assign mult_result_w = {{ 32 {mul_operand_a_q[32]}}, mul_operand_a_q}*{{ 32 {mul_operand_b_q[32]}}, mul_operand_b_q}; always @* begin mul_result_r = mulhi_sel_q ? mult_result_w[63:32] : mult_result_w[31:0]; end reg mul_busy_q; always @(posedge clk_i) if (rst_i) mul_busy_q <= 1'b0; else mul_busy_q <= valid_i & mult_inst_w; 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 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 ); wire [31:0] data_r_w; tcm_mem_ram u_ram ( // Instruction fetch .clk0_i (clk_i), .rst0_i (rst_i), .addr0_i(mem_i_pc_i[15:2]), .data0_i(32'b0), .wr0_i (4'b0) // External access / Data access , .clk1_i (clk_i), .rst1_i (rst_i), .addr1_i(mem_d_addr_i[15:2]), .data1_i(mem_d_data_wr_i), .wr1_i (mem_d_wr_i) // Outputs , .data0_o(mem_i_inst_o), .data1_o(data_r_w) ); reg mem_i_valid_q; always @(posedge clk_i) if (rst_i) mem_i_valid_q <= 1'b0; else mem_i_valid_q <= mem_i_rd_i; assign mem_i_accept_o = 1'b1; assign mem_i_valid_o = mem_i_valid_q; assign mem_i_error_o = 1'b0; reg mem_d_accept_q; reg mem_d_ack_q; reg [10:0] mem_d_tag_q; always @(posedge clk_i) if (rst_i) begin mem_d_ack_q <= 1'b0; mem_d_tag_q <= 11'b0; end else if ((mem_d_rd_i || mem_d_wr_i != 4'b0 || mem_d_flush_i || mem_d_invalidate_i || mem_d_writeback_i) && mem_d_accept_o) begin mem_d_ack_q <= 1'b1; mem_d_tag_q <= mem_d_req_tag_i; end else mem_d_ack_q <= 1'b0; assign mem_d_ack_o = mem_d_ack_q; assign mem_d_resp_tag_o = mem_d_tag_q; assign mem_d_data_rd_o = data_r_w; assign mem_d_error_o = 1'b0; assign mem_d_accept_o = 1'b1; 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; 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