diff --git a/firmware/src/entry.S b/firmware/src/entry.S index 7d43e9a..9dbb54c 100644 --- a/firmware/src/entry.S +++ b/firmware/src/entry.S @@ -1,27 +1,115 @@ .global __entry +.global __vector +.global exception_stack_top .pushsection .text.entry .option push .option norvc __entry: __reset: j fw_entry -__exception: j fw_exception_entry fw_entry: la sp, stack_top jal {firmware_main} -fw_exception_entry: - mv tp, sp - la sp, exception_stack_top - jal {firmware_exception} - j . .option pop .popsection // .text.entry +// ra+gp, 7 tN, 12 sN, 8 aN +.set GP_REGS_SIZE, ((2 + 7 + 12 + 8) * 4) +.set CTL_REGS_SIZE, (6 * 8) +.set SAVED_FRAME_SIZE, (GP_REGS_SIZE + CTL_REGS_SIZE) + .pushsection .text.vectors, "ax" -.global __vector __vector: + // Switch to exception stack + csrrw sp, mscratch, sp + + // Store register state + addi sp, sp, -SAVED_FRAME_SIZE + sw ra, 0 * 4(sp) + sw gp, 1 * 4(sp) + + sw t0, 2 * 4(sp) + sw t1, 3 * 4(sp) + sw t2, 4 * 4(sp) + sw t3, 5 * 4(sp) + sw t4, 6 * 4(sp) + sw t5, 7 * 4(sp) + sw t6, 8 * 4(sp) + + sw s0, 9 * 4(sp) + sw s1, 10 * 4(sp) + sw s2, 11 * 4(sp) + sw s3, 12 * 4(sp) + sw s4, 13 * 4(sp) + sw s5, 14 * 4(sp) + sw s6, 15 * 4(sp) + sw s7, 16 * 4(sp) + sw s8, 17 * 4(sp) + sw s9, 18 * 4(sp) + sw s10, 19 * 4(sp) + sw s11, 20 * 4(sp) + + sw a0, 21 * 4(sp) + sw a1, 22 * 4(sp) + sw a2, 23 * 4(sp) + sw a3, 24 * 4(sp) + sw a4, 25 * 4(sp) + sw a5, 26 * 4(sp) + sw a6, 27 * 4(sp) + sw a7, 28 * 4(sp) + + csrr t0, mtval + csrr t1, mepc + csrr t2, mcause + csrr t3, mscratch + + sw t0, 29 * 4(sp) + sw t1, 30 * 4(sp) + sw t2, 31 * 4(sp) + sw t3, 32 * 4(sp) + + mv a0, sp + jal {firmware_exception} + + // Restore state + lw ra, 0 * 4(sp) + lw gp, 1 * 4(sp) + + lw t0, 2 * 4(sp) + lw t1, 3 * 4(sp) + lw t2, 4 * 4(sp) + lw t3, 5 * 4(sp) + lw t4, 6 * 4(sp) + lw t5, 7 * 4(sp) + lw t6, 8 * 4(sp) + + lw s0, 9 * 4(sp) + lw s1, 10 * 4(sp) + lw s2, 11 * 4(sp) + lw s3, 12 * 4(sp) + lw s4, 13 * 4(sp) + lw s5, 14 * 4(sp) + lw s6, 15 * 4(sp) + lw s7, 16 * 4(sp) + lw s8, 17 * 4(sp) + lw s9, 18 * 4(sp) + lw s10, 19 * 4(sp) + lw s11, 20 * 4(sp) + + lw a0, 21 * 4(sp) + lw a1, 22 * 4(sp) + lw a2, 23 * 4(sp) + lw a3, 24 * 4(sp) + lw a4, 25 * 4(sp) + lw a5, 26 * 4(sp) + lw a6, 27 * 4(sp) + lw a7, 28 * 4(sp) + addi sp, sp, SAVED_FRAME_SIZE + + csrrw sp, mscratch, sp + mret j . .popsection // .text.vectors diff --git a/firmware/src/main.rs b/firmware/src/main.rs index bfb7652..440be03 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -24,25 +24,52 @@ impl fmt::Write for D { } unsafe extern "C" fn firmware_main() -> ! { + unsafe extern "C" { + static __vector: u8; + static exception_stack_top: u8; + } + + let vector_address = (&raw const __vector).addr(); + core::arch::asm!("csrw mtvec, {val}", val = in(reg) vector_address); + let exception_stack_address = (&raw const exception_stack_top).addr(); + core::arch::asm!("csrw mscratch, {val}", val = in(reg) exception_stack_address); + use fmt::Write; let mut d = D; - for i in 0..10 { - write!(d, "Hello {i}").ok(); - write!(d, "\n").ok(); + + writeln!(d, "Set mtvec={vector_address:#x}").ok(); + + for i in 0..20 { + writeln!(d, "Hello {i:#x}").ok(); } loop { // TODO pause/system/fence instruction not implemented // core::hint::spin_loop(); - core::arch::asm!("ebreak"); + core::arch::asm!("ecall"); } } -unsafe extern "C" fn firmware_exception() { +#[repr(C)] +struct ExceptionFrame { + regs: [u32; 29], + mtval: u32, + mepc: u32, + mcause: u32, + mscratch: u32, +} + +unsafe extern "C" fn firmware_exception(frame: &ExceptionFrame) { use fmt::Write; let mut d = D; writeln!(d, "In exception handler").ok(); + writeln!( + d, + "mepc={:x}, mcause={:x}, mscratch={:x}", + frame.mepc, frame.mcause, frame.mscratch + ) + .ok(); } global_asm!( diff --git a/src/core/rvx0_control.sv b/src/core/rvx0_control.sv index 1837155..ee3701b 100644 --- a/src/core/rvx0_control.sv +++ b/src/core/rvx0_control.sv @@ -33,7 +33,6 @@ module rvx0_control ( end end - // TODO handle pslverr always @(negedge clk_i) begin if (~rst_i) begin case (control_state_o) @@ -98,7 +97,6 @@ module rvx0_control ( end CSTATE_EXEC: begin if (exec_stall_i) begin - $display("control: exec_stall_i @ %x", pc_value_i); control_state_o <= CSTATE_FETCH; end else if (exec_ready_i) begin control_state_o <= CSTATE_WRITE; @@ -115,8 +113,6 @@ module rvx0_control ( apb_master.pwrite <= 1; apb_master.penable <= 1; - $display("WRITE %x -> %x", memory_write_i, memory_address_i); - if (apb_master.pslverr) begin apb_master.penable <= 0; fault_memory_access_o <= 1; diff --git a/src/core/rvx0_core.sv b/src/core/rvx0_core.sv index 3d99022..4e16f9f 100644 --- a/src/core/rvx0_core.sv +++ b/src/core/rvx0_core.sv @@ -20,6 +20,12 @@ module rvx0_core #( wire [31:0] csr_mtvec; wire [31:0] csr_mepc; + wire csr_clk; + wire csr_write; + wire [11:0] csr_index; + wire [31:0] csr_read_value; + wire undefined_csr; + wire csr_write_fault; // Exception generation @@ -66,11 +72,14 @@ module rvx0_core #( wire [4:0] rd; wire v1src; wire [1:0] v2src; - wire [1:0] vdsrc; + wire [2:0] vdsrc; wire [31:0] imm; wire [3:0] aluop; wire write_pc; wire [2:0] funct3; + wire instruction_multi_cycle; + wire instruction_zicsr; + wire exception_return; // Into ALU @@ -93,6 +102,22 @@ module rvx0_core #( wire [31:0] memory_write_output; wire memory_access_partial; + // "Slow" datapath test + + logic regfile_clk; + logic advance_pc; + + // Zicsr extension + + logic zicsr_clk_gate; + wire zicsr_clk; + wire zicsr_exec_ready; + wire zicsr_regfile_clk; + wire zicsr_instruction_fault; + wire [31:0] zicsr_read_value; + wire [31:0] zicsr_write_value; + wire zicsr_write; + rvx0_pc #( .RESET_VECTOR (RESET_VECTOR) ) pc ( @@ -129,7 +154,11 @@ module rvx0_core #( .conditional_o (conditional), .raise_ecall_o (raise_ecall), - .raise_ebreak_o (raise_ebreak) + .raise_ebreak_o (raise_ebreak), + .exception_return_o (exception_return), + + .instruction_multi_cycle_o (instruction_multi_cycle), + .instruction_zicsr_o (instruction_zicsr) ); rvx0_regfile regfile ( @@ -195,13 +224,18 @@ module rvx0_core #( .rst_i (rst_i), .mepc_i (mepc_write_value), - .mepc_write_i (fault), + .mepc_write_i (csr_write_fault), .mcause_i (mcause_write_value), - .mcause_write_i (fault), + .mcause_write_i (csr_write_fault), .mtval_i (mtval_write_value), - .mtval_write_i (fault), + .mtval_write_i (csr_write_fault), + .mtvec_o (csr_mtvec), - .mtvec_o (csr_mtvec) + .csr_index_i (csr_index), + .csr_write_value_i (zicsr_write_value), + .csr_read_value_o (csr_read_value), + .csr_write_i (csr_write), + .undefined_csr_o (undefined_csr) ); rvx0_fault_encoder fault_encoder ( @@ -227,7 +261,30 @@ module rvx0_core #( .mepc_write_value_o (mepc_write_value) ); - assign fault_instruction = fault_instruction_decode || (fault_unsupported_size && (need_memory_read || need_memory_write)); + rvx0_zicsr zicsr ( + .clk_i (zicsr_clk), + .rst_i (rst_i), + + .funct3_i (funct3), + .rs1_value_i (rs1_value), + .rd_i (rd), + .imm_i (imm), + + .exec_ready_o (zicsr_exec_ready), + .regfile_clk_o (zicsr_regfile_clk), + + .csr_index_o (csr_index), + .csr_read_output_o (zicsr_read_value), + .csr_write_output_o (zicsr_write_value), + .csr_value_i (csr_read_value), + .csr_write_o (zicsr_write), + .undefined_csr_i (undefined_csr), + .instruction_fault_o (zicsr_instruction_fault) + ); + + assign csr_write = (zicsr_write && zicsr_clk_gate) && state_exec; + + assign fault_instruction = fault_instruction_decode || (fault_unsupported_size && (need_memory_read || need_memory_write)) || (zicsr_instruction_fault && instruction_zicsr); assign fault_memory_align = fault_address_align && (need_memory_write || need_memory_read); assign memory_write_input = rs2_value; @@ -236,12 +293,20 @@ module rvx0_core #( assign alu_value1 = v1src == V1SRC_ZERO ? 0 : rs1_value; assign state_exec = control_state == CSTATE_EXEC; - assign pc_clk = (state_exec || rst_i) && clk_i; + assign pc_clk = ((state_exec && (advance_pc || fault)) || rst_i) && clk_i; + + assign zicsr_clk = ((state_exec && zicsr_clk_gate) || rst_i) && clk_i; assign write_rd = (vdsrc != RDSRC_NONE) && state_exec && ~fault; assign write_pc_and_taken = ((conditional ? branch_taken : 1) && write_pc) || fault; + assign pc_write_value = fault ? csr_mtvec : alu_output; + + assign zicsr_clk_gate = instruction_zicsr && state_exec; + assign exec_stall = fault && state_exec; + assign csr_write_fault = fault && state_exec; + // Value mux always_comb begin case (vdsrc) @@ -249,6 +314,7 @@ module rvx0_core #( RDSRC_ALU: rd_write_value = alu_output; RDSRC_MEM: rd_write_value = memory_read_output; RDSRC_NONE: rd_write_value = 0; + RDSRC_CSR: rd_write_value = zicsr_read_value; endcase case (v2src) @@ -256,34 +322,59 @@ module rvx0_core #( V2SRC_PC: alu_value2 = pc_value; V2SRC_RS2: alu_value2 = rs2_value; endcase - - if (fault) begin - pc_write_value = csr_mtvec; - end else begin - pc_write_value = alu_output; - end end always @(posedge clk_i) begin + advance_pc = 0; + case (control_state) CSTATE_EXEC: begin exec_ready = 0; - exec_stall = 0; + regfile_clk = 0; + +`ifdef RVX0_DEBUGGING + $display("[%x] %x, rs1 (r%d)=%x, rs2 (r%d)=%x, v1src=%d, v2src=%d, vdsrc=%d", pc_value, instruction, rs1, rs1_value, rs2, rs2_value, v1src, v2src, vdsrc); + $display("\talu_value1=%x, alu_value2=%x, imm=%x, rd_write_value=%x", alu_value1, alu_value2, imm, rd_write_value); + $display("\tmri=%x, mro=%x, mwi=%x, mwo=%x", memory_read_input, memory_read_output, memory_write_input, memory_write_output); +`endif if (fault) begin $display("Take exception mcause=%x, mepc=%x, mtval=%x to %x", mcause_write_value, mepc_write_value, mtval_write_value, csr_mtvec); $display("Instruction: %x", instruction); -`ifdef RVX0_CRASH_ON_EXCEPTION - regfile.dump_state; - $finish; + if (fault_instruction) begin + $display("Instruction decode fault:"); + if (fault_instruction_decode) begin + $display("\tfault_instruction_decode"); + end + if (fault_unsupported_size && (need_memory_read || need_memory_write)) begin + $display("\tfault_unsupported_size"); + end + if (zicsr_instruction_fault && instruction_zicsr) begin + $display("\tzicsr_instruction_fault"); + end + end + fault_encoder.dump_fault; +`ifndef RVX0_CRASH_ON_EXCEPTION + if (raise_ebreak) begin `endif - exec_stall = 1; + regfile.dump_state; + csr.dump_state; + $finish; +`ifndef RVX0_CRASH_ON_EXCEPTION + end +`endif + end else if (exception_return) begin + $error("TODO: exception return (mret/sret)"); + end else if (instruction_zicsr) begin + regfile_clk = zicsr_regfile_clk; + advance_pc = zicsr_exec_ready; + exec_ready = zicsr_exec_ready; + end else if (instruction_multi_cycle) begin + // "Slow" instruction datapath, allowing multi-cycle + // instructions like mul/div, etc end else begin -`ifdef RVX0_DEBUGGING - $display("[%x] %x, rs1 (r%d)=%x, rs2 (r%d)=%x, v1src=%d, v2src=%d, vdsrc=%d", pc_value, instruction, rs1, rs1_value, rs2, rs2_value, v1src, v2src, vdsrc); - $display("\talu_value1=%x, alu_value2=%x, imm=%x, rd_write_value=%x", alu_value1, alu_value2, imm, rd_write_value); - $display("\tmri=%x, mro=%x, mwi=%x, mwo=%x", memory_read_input, memory_read_output, memory_write_input, memory_write_output); -`endif + regfile_clk = 1; + advance_pc = 1; exec_ready = 1; end end diff --git a/src/core/rvx0_csr.sv b/src/core/rvx0_csr.sv index 24629c4..563f5c5 100644 --- a/src/core/rvx0_csr.sv +++ b/src/core/rvx0_csr.sv @@ -11,42 +11,89 @@ module rvx0_csr ( input wire mcause_write_i, input wire mtval_write_i, - output wire [31:0] misa_o, // Hardwired - output wire [31:0] mvendorid_o, // Hardwired - output wire [31:0] marchid_o, // Hardwired - output wire [31:0] mimpid_o, // Hardwired - output wire [31:0] mhartid_o, // Hardwired - output reg [31:0] mstatus_o, // TODO - output reg [31:0] mstatush_o, // TODO - output reg [31:0] mtvec_o, - output reg [31:0] mepc_o, - output reg [31:0] mcause_o, - output reg [31:0] mtval_o // TODO + output wire [31:0] mtvec_o, + + // CSR access + input wire csr_write_i, + input wire [11:0] csr_index_i, + input wire [31:0] csr_write_value_i, + output logic [31:0] csr_read_value_o, + output logic undefined_csr_o ); - // Add extensions here :) - assign misa_o = MISA_MXLEN_32; - assign mvendorid_o = 0; - assign marchid_o = 0; - assign mimpid_o = 0; - assign mhartid_o = 0; + const logic [3:0] IDX_MISA = 0; + const logic [3:0] IDX_MVENDORID = 1; + const logic [3:0] IDX_MARCHID = 2; + const logic [3:0] IDX_MIMPID = 3; + const logic [3:0] IDX_MHARTID = 4; + const logic [3:0] IDX_MSTATUS = 5; + const logic [3:0] IDX_MSTATUSH = 6; + const logic [3:0] IDX_MTVEC = 7; + const logic [3:0] IDX_MEPC = 8; + const logic [3:0] IDX_MCAUSE = 9; + const logic [3:0] IDX_MTVAL = 10; + const logic [3:0] IDX_MSCRATCH = 11; + + logic [31:0] csr_values [0:15]; + logic [3:0] selected_csr; + wire non_insn_write; + + assign mtvec_o = csr_values[IDX_MTVEC]; + + assign non_insn_write = mepc_write_i || mtval_write_i || mcause_write_i; + + assign csr_read_value_o = csr_values[selected_csr]; + + function void dump_state; + $display("CSR state:"); + $display( + "\tmtvec=%x, mtval=%x, mepc=%x, mcause=%x", + csr_values[IDX_MTVEC], csr_values[IDX_MTVAL], + csr_values[IDX_MEPC], csr_values[IDX_MCAUSE] + ); + $display("\tmscratch=%x", csr_values[IDX_MSCRATCH]); + endfunction + + always_comb begin + undefined_csr_o = 0; + selected_csr = 0; + + case (csr_index_i) + // Machine trap setup + 'h305: selected_csr = IDX_MTVEC; + // Machine trap handling + 'h340: selected_csr = IDX_MSCRATCH; + 'h341: selected_csr = IDX_MEPC; + 'h342: selected_csr = IDX_MCAUSE; + 'h343: selected_csr = IDX_MTVAL; + default: undefined_csr_o = 1; + endcase + end always @(posedge clk_i) begin if (rst_i) begin - // TODO set from CPU - mtvec_o = 'h00001004; - mepc_o = 0; - mstatus_o = 0; - mstatush_o = 0; - end - - if (mepc_write_i) begin - mepc_o <= mepc_i; - end - if (mcause_write_i) begin - mcause_o <= mcause_i; - end - if (mtval_write_i) begin - mtval_o <= mtval_i; + csr_values[IDX_MTVEC] <= 0; + csr_values[IDX_MEPC] <= 0; + csr_values[IDX_MSTATUS] <= 0; + csr_values[IDX_MSTATUSH] <= 0; + end else begin + if (non_insn_write) begin + // Non-Zicsr writes take precedence (likely from an exception) + if (mepc_write_i) begin + $display("CSR write mepc <= %x", mepc_i); + csr_values[IDX_MEPC] <= mepc_i; + end + if (mcause_write_i) begin + csr_values[IDX_MCAUSE] <= mcause_i; + end + if (mtval_write_i) begin + csr_values[IDX_MTVAL] <= mtval_i; + end + end else if (csr_write_i && ~undefined_csr_o) begin + $display("CSR write: %d (%x) <= %x", selected_csr, csr_index_i, csr_write_value_i); + if (selected_csr >= IDX_MSTATUS) begin + csr_values[selected_csr] <= csr_write_value_i; + end + end end end endmodule diff --git a/src/core/rvx0_fault_encoder.sv b/src/core/rvx0_fault_encoder.sv index 1f49c19..aa664f1 100644 --- a/src/core/rvx0_fault_encoder.sv +++ b/src/core/rvx0_fault_encoder.sv @@ -22,6 +22,32 @@ module rvx0_fault_encoder ( output logic [31:0] mepc_write_value_o, output logic fault_o ); + function void dump_fault; + $display("Fault:"); + if (fault_instruction_align_i) begin + $display("\tfault_instruction_align_i"); + end + if (fault_instruction_fetch_i) begin + $display("\tfault_instruction_fetch_i"); + end + if (fault_instruction_decode_i) begin + $display("\tfault_instruction_decode_i"); + end + if (fault_memory_align_i) begin + $display("\tfault_memory_align_i"); + end + if (fault_memory_access_i) begin + $display("\tfault_memory_access_i"); + end + if (raise_ecall_i) begin + $display("\traise_ecall_i"); + end + if (raise_ebreak_i) begin + $display("\traise_ebreak_i"); + end + + endfunction + assign fault_o = fault_instruction_align_i || fault_instruction_fetch_i || fault_instruction_decode_i || @@ -67,5 +93,4 @@ module rvx0_fault_encoder ( mcause_write_value_o = MCAUSE_INTR_EXT_MMODE | MCAUSE_INTERRUPT; end end - endmodule diff --git a/src/core/rvx0_zicsr.sv b/src/core/rvx0_zicsr.sv new file mode 100644 index 0000000..c060d26 --- /dev/null +++ b/src/core/rvx0_zicsr.sv @@ -0,0 +1,119 @@ +module rvx0_zicsr ( + input wire clk_i, + input wire rst_i, + + input wire [2:0] funct3_i, + input wire [31:0] rs1_value_i, + input wire [4:0] rd_i, + input wire [31:0] imm_i, + input wire [31:0] csr_value_i, + input wire undefined_csr_i, + + + output logic exec_ready_o, + output logic regfile_clk_o, + + // CSR access + output logic instruction_fault_o, + output logic [31:0] csr_read_output_o, + output logic [31:0] csr_write_output_o, + output logic [11:0] csr_index_o, + output logic csr_write_o, + output logic csr_clk_o +); + logic need_csr_read; + logic need_csr_write; + logic single_cycle; + + logic [31:0] value1; + logic [31:0] value2; + logic [31:0] rs1_value_latch; + logic [31:0] csr_value_latch; + logic [1:0] latch_state; + + wire [31:0] csrrs_output; + wire [31:0] csrrc_output; + + assign csr_index_o = imm_i[11:0]; + + assign csrrs_output = value1 | value2; + assign csrrc_output = value1 & ~value2; + + assign exec_ready_o = single_cycle || latch_state == 2; + assign csr_write_o = single_cycle ? need_csr_write : latch_state == 2; + assign regfile_clk_o = single_cycle ? need_csr_read : latch_state == 2; + + assign value1 = single_cycle ? csr_value_i : csr_value_latch; + assign value2 = single_cycle ? rs1_value_i : rs1_value_latch; + assign csr_read_output_o = single_cycle ? csr_value_i : csr_value_latch; + + always_comb begin + instruction_fault_o = undefined_csr_i; + need_csr_read = 0; + single_cycle = 0; + + csr_write_output_o = 0; + + case (funct3_i) + 3'b001: begin // csrrw + need_csr_read = rd_i != 0; + need_csr_write = 1; + csr_write_output_o = value2; + end + 3'b010: begin // csrrs + need_csr_read = 1; + need_csr_write = rs1_value_i != 0; + csr_write_output_o = csrrs_output; + end + 3'b011: begin // csrrc + need_csr_read = 1; + need_csr_write = rs1_value_i != 0; + csr_write_output_o = csrrc_output; + end + // TODO csrrwi, csrrsi, csrrci + default: instruction_fault_o = 1; + endcase + + if ((need_csr_read && ~need_csr_write) || (~need_csr_read && need_csr_write)) begin + single_cycle = 1; + end + end + + always @(posedge clk_i) begin + if (rst_i || instruction_fault_o) begin + latch_state <= 0; + end else begin + if (~need_csr_read && ~need_csr_write) begin + $error("TODO: no-op zicsr instruction?"); + end + + if (single_cycle) begin + latch_state <= 0; + + if (need_csr_read) begin + $display("CSR read: csr=%x, csr_read_output_o=%x", csr_index_o, csr_read_output_o); + end else begin + $display("CSR write: csr=%x, csr_write_output_o=%x", csr_index_o, csr_write_output_o); + end + end else begin + // need_csr_read && need_csr_write + case (latch_state) + 0: begin + // Latch CSR and RS1 values + csr_value_latch <= csr_value_i; + rs1_value_latch <= rs1_value_i; + $display("Latched values: csr_value_latch=%x, rs1_value_latch=%x", csr_value_latch, rs1_value_latch); + latch_state <= 1; + end + 1: begin + // Writeback + latch_state <= 2; + end + 2: begin + latch_state <= 0; + end + endcase + end + end + end +endmodule diff --git a/src/decoder/rvx0_decoder.sv b/src/decoder/rvx0_decoder.sv index f7b02ef..65cb006 100644 --- a/src/decoder/rvx0_decoder.sv +++ b/src/decoder/rvx0_decoder.sv @@ -8,17 +8,19 @@ module rvx0_decoder ( output logic write_mem_o, output logic conditional_o, - output logic is_system_o, - output logic raise_ecall_o, output logic raise_ebreak_o, + output logic instruction_multi_cycle_o, + + output logic instruction_zicsr_o, + output logic exception_return_o, output logic instruction_fault_o, output logic [6:0] opcode_o, output wire [31:0] imm_o, output wire v1src_o, output wire [1:0] v2src_o, - output wire [1:0] vdsrc_o, + output wire [2:0] vdsrc_o, output wire [3:0] aluop_o, output wire [2:0] funct3_o, output wire [6:0] funct7_o, @@ -55,7 +57,7 @@ module rvx0_decoder ( wire base_write_mem; wire base_v1src; wire [1:0] base_v2src; - wire [1:0] base_vdsrc; + wire [2:0] base_vdsrc; wire base_conditional; wire [3:0] base_aluop; wire [31:0] base_imm; @@ -85,16 +87,13 @@ module rvx0_decoder ( ); always_comb begin - is_system_o = 0; - - case (opcode_o) - 'b0001111: is_system_o = 1; - 'b1110011: is_system_o = 1; - endcase - raise_ecall_o = 0; raise_ebreak_o = 0; + instruction_multi_cycle_o = 0; + instruction_zicsr_o = 0; + exception_return_o = 0; + write_pc_o = 0; write_mem_o = 0; conditional_o = 0; @@ -106,14 +105,40 @@ module rvx0_decoder ( vdsrc_o = RDSRC_NONE; aluop_o = ALUOP_ADD; - if (rs1_o == 0 && funct3_o == 0 && rd_o == 0 && opcode_o == 'b1110011) begin - case (instruction_i[31:20]) - 0: raise_ecall_o = 1; - 1: raise_ebreak_o = 1; - default: instruction_fault_o = 1; + if (opcode_o == 'b1110011) begin + case (funct3_o) + 0: begin + if (rd_o == 0 && rs1_o == 0) begin + case (instruction_i[31:20]) + 0: raise_ecall_o = 1; + 1: raise_ebreak_o = 1; + 'h302: if (rs2_o == 2) begin + exception_return_o = 1; + end else begin + instruction_fault_o = 1; + end + default: instruction_fault_o = 1; + endcase + end else begin + instruction_fault_o = 1; + end + end + 4: instruction_fault_o = 1; + default: begin + instruction_zicsr_o = 1; + instruction_multi_cycle_o = 1; + vdsrc_o = RDSRC_CSR; + + imm_o = { 20'b0, instruction_i[31:20] }; + end endcase + + if (instruction_fault_o) begin + $display("instruction_fault_o on SYSTEM"); + $display("\timm=%b, rs2=%d, rs1=%d, funct3=%b, rd=%d", instruction_i[31:20], rs2_o, rs1_o, funct3_o, rd_o); + end end else if (rs1_o == 0 && funct3_o == 0 && opcode_o == 'b0001111) begin - // Nice + // Nothing end else begin instruction_fault_o = base_instruction_fault; diff --git a/src/decoder/rvx0_decoder_i.sv b/src/decoder/rvx0_decoder_i.sv index c186cc2..1223fc1 100644 --- a/src/decoder/rvx0_decoder_i.sv +++ b/src/decoder/rvx0_decoder_i.sv @@ -19,7 +19,7 @@ module rvx0_decoder_i ( output wire [31:0] imm_o, output wire v1src_o, output wire [1:0] v2src_o, - output wire [1:0] vdsrc_o, + output wire [2:0] vdsrc_o, output wire [3:0] aluop_o ); always_comb begin diff --git a/src/rvx0_defs.svh b/src/rvx0_defs.svh index 528c66b..ea016d4 100644 --- a/src/rvx0_defs.svh +++ b/src/rvx0_defs.svh @@ -1,13 +1,18 @@ `ifndef __RVX0_DEFS_SVH `define __RVX0_DEFS_SVH -`define RVX0_DEBUGGING 1 +// `define RVX0_DEBUGGING 1 // `define RVX0_CRASH_ON_EXCEPTION 1 +`define RVX0_ZICSR 1 -const logic [1:0] RDSRC_ALU = 0; -const logic [1:0] RDSRC_MEM = 1; -const logic [1:0] RDSRC_PC = 2; -const logic [1:0] RDSRC_NONE = 3; +const logic [2:0] RDSRC_NONE = 0; +const logic [2:0] RDSRC_ALU = 1; +const logic [2:0] RDSRC_MEM = 2; +const logic [2:0] RDSRC_PC = 3; +const logic [2:0] RDSRC_CSR = 4; +const logic [2:0] RDSRC_MALU = 5; // TODO will be used for M extension +const logic [2:0] RDSRC_RES2 = 6; +const logic [2:0] RDSRC_RES3 = 7; const logic V1SRC_ZERO = 0; const logic V1SRC_RS1 = 1; diff --git a/src/rvx0_simple_ram.sv b/src/rvx0_simple_ram.sv index 9cf1c95..9dda656 100644 --- a/src/rvx0_simple_ram.sv +++ b/src/rvx0_simple_ram.sv @@ -10,10 +10,10 @@ module rvx0_simple_ram ( if (apb_slave.penable) begin if (apb_slave.pwrite) begin words[apb_slave.paddr[22:2]] <= apb_slave.pwdata; - $display("RAM write [%x] <= %x", apb_slave.paddr, apb_slave.pwdata); + // $display("RAM write [%x] <= %x", apb_slave.paddr, apb_slave.pwdata); end else begin apb_slave.prdata <= words[apb_slave.paddr[22:2]]; - $display("RAM read %x <= [%x]", words[apb_slave.paddr[22:2]], apb_slave.paddr); + // $display("RAM read %x <= [%x]", words[apb_slave.paddr[22:2]], apb_slave.paddr); end apb_slave.pready <= 1;