From ee55a07e0a8590605ec092bafbe268d342d96d98 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Wed, 3 Sep 2025 17:22:00 +0300 Subject: [PATCH] Add ecall/ebreak --- Makefile | 2 +- firmware/link.ld | 10 ++-- firmware/src/entry.S | 17 ++++++- firmware/src/main.rs | 14 +++++- src/core/rvx0_core.sv | 19 +++++++- src/core/rvx0_csr.sv | 2 +- src/decoder/rvx0_decoder.sv | 91 ++++++++++++++++++++++++++++++----- src/decoder/rvx0_decoder_i.sv | 10 +++- src/rvx0_busmux.sv | 2 +- src/rvx0_defs.svh | 4 ++ src/rvx0_simple_ram.sv | 14 +++--- 11 files changed, 148 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index 357be16..9157739 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SRC_ALL=$(wildcard src/**/*.sv) +SRC_ALL=$(wildcard src/**/*.sv src/*.sv) SRC_MODULE=$(filter-out %_top.sv,$(filter-out %_tb.sv,$(SRC_ALL))) DEF_MODULE=$(wildcard src/*.svh) diff --git a/firmware/link.ld b/firmware/link.ld index 79cecd1..4021e34 100644 --- a/firmware/link.ld +++ b/firmware/link.ld @@ -15,12 +15,6 @@ SECTIONS { . = ALIGN(4); } - . = 0x20000; - - .vectors : { - *(.text.vectors) - } - . = 0x20000000; .data : { @@ -32,4 +26,8 @@ SECTIONS { .bss : { *(.bss*) } + + . = 0x20400000; + + .end : {} } diff --git a/firmware/src/entry.S b/firmware/src/entry.S index cb18f62..7d43e9a 100644 --- a/firmware/src/entry.S +++ b/firmware/src/entry.S @@ -4,19 +4,32 @@ .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 -.pushsection .text.vectors +.pushsection .text.vectors, "ax" +.global __vector __vector: j . .popsection // .text.vectors .pushsection .bss stack_bottom: - .skip 2048 + .skip 65536 stack_top: +exception_stack_bottom: + .skip 65536 +exception_stack_top: .popsection // .bss diff --git a/firmware/src/main.rs b/firmware/src/main.rs index a8b2587..bfb7652 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -35,8 +35,18 @@ unsafe extern "C" fn firmware_main() -> ! { loop { // TODO pause/system/fence instruction not implemented // core::hint::spin_loop(); - core::arch::asm!("nop"); + core::arch::asm!("ebreak"); } } -global_asm!(include_str!("entry.S"), firmware_main = sym firmware_main); +unsafe extern "C" fn firmware_exception() { + use fmt::Write; + let mut d = D; + writeln!(d, "In exception handler").ok(); +} + +global_asm!( + include_str!("entry.S"), + firmware_main = sym firmware_main, + firmware_exception = sym firmware_exception +); diff --git a/src/core/rvx0_core.sv b/src/core/rvx0_core.sv index e176b15..1162bdb 100644 --- a/src/core/rvx0_core.sv +++ b/src/core/rvx0_core.sv @@ -40,6 +40,8 @@ module rvx0_core #( wire fault_instruction_decode; wire fault_unsupported_size; wire fault_address_align; + wire raise_ecall; + wire raise_ebreak; // Control @@ -112,6 +114,8 @@ module rvx0_core #( rvx0_decoder decoder ( .instruction_i (instruction), + .instruction_fault_o (fault_instruction_decode), + .v1src_o (v1src), .v2src_o (v2src), .vdsrc_o (vdsrc), @@ -123,8 +127,10 @@ module rvx0_core #( .write_mem_o (need_memory_write), .write_pc_o (write_pc), .funct3_o (funct3), - .instruction_fault_o (fault_instruction_decode), - .conditional_o (conditional) + .conditional_o (conditional), + + .raise_ecall_o (raise_ecall), + .raise_ebreak_o (raise_ebreak) ); rvx0_regfile regfile ( @@ -204,6 +210,8 @@ module rvx0_core #( fault_instruction || fault_memory_align || fault_memory_access || + raise_ecall || + raise_ebreak || intr_ext_i; assign fault_instruction = fault_instruction_decode || (fault_unsupported_size && (need_memory_read || need_memory_write)); @@ -257,6 +265,8 @@ module rvx0_core #( end else if (fault_instruction) begin mcause_write_value = MCAUSE_ILLEGAL_INSTRUCTION; mtval_write_value = instruction; + end else if (raise_ebreak) begin + mcause_write_value = MCAUSE_BREAKPOINT; end else if (~need_memory_write && fault_memory_align) begin mcause_write_value = MCAUSE_LOAD_ADDRESS_MISALIGNED; mtval_write_value = alu_output; @@ -271,6 +281,8 @@ module rvx0_core #( // been incremented mepc_write_value = pc_value - 4; mtval_write_value = alu_output; + end else if (raise_ecall) begin + mcause_write_value = MCAUSE_ECALL_MMODE; end else if (intr_ext_i) begin mcause_write_value = MCAUSE_INTR_EXT_MMODE | MCAUSE_INTERRUPT; end @@ -284,8 +296,11 @@ module rvx0_core #( 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; +`endif exec_stall = 1; end else begin `ifdef RVX0_DEBUGGING diff --git a/src/core/rvx0_csr.sv b/src/core/rvx0_csr.sv index 4a85208..24629c4 100644 --- a/src/core/rvx0_csr.sv +++ b/src/core/rvx0_csr.sv @@ -33,7 +33,7 @@ module rvx0_csr ( always @(posedge clk_i) begin if (rst_i) begin // TODO set from CPU - mtvec_o = 'h00020000; + mtvec_o = 'h00001004; mepc_o = 0; mstatus_o = 0; mstatush_o = 0; diff --git a/src/decoder/rvx0_decoder.sv b/src/decoder/rvx0_decoder.sv index 5301e41..f7b02ef 100644 --- a/src/decoder/rvx0_decoder.sv +++ b/src/decoder/rvx0_decoder.sv @@ -8,7 +8,13 @@ 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_fault_o, + output logic [6:0] opcode_o, output wire [31:0] imm_o, output wire v1src_o, output wire [1:0] v2src_o, @@ -20,15 +26,13 @@ module rvx0_decoder ( output wire [4:0] rs2_o, output wire [4:0] rd_o ); - wire [6:0] opcode; - wire signed [11:0] imm_i_type; wire signed [11:0] imm_s_type; wire signed [12:0] imm_b_type; wire [19:0] imm_u_type; wire signed [20:0] imm_j_type; - assign opcode = instruction_i[6:0]; + assign opcode_o = instruction_i[6:0]; assign funct3_o = instruction_i[14:12]; assign funct7_o = instruction_i[31:25]; @@ -42,10 +46,24 @@ module rvx0_decoder ( assign rs2_o = instruction_i[24:20]; assign rd_o = instruction_i[11:7]; + // Decode select + + // Base ISA + + wire base_instruction_fault; + wire base_write_pc; + wire base_write_mem; + wire base_v1src; + wire [1:0] base_v2src; + wire [1:0] base_vdsrc; + wire base_conditional; + wire [3:0] base_aluop; + wire [31:0] base_imm; + rvx0_decoder_i decoder_i ( .instruction_i (instruction_i), - .opcode (opcode), + .opcode (opcode_o), .funct3 (funct3_o), .imm_i_type (imm_i_type), @@ -54,15 +72,62 @@ module rvx0_decoder ( .imm_u_type (imm_u_type), .imm_j_type (imm_j_type), - .write_pc_o (write_pc_o), - .write_mem_o (write_mem_o), - .conditional_o (conditional_o), + .write_pc_o (base_write_pc), + .write_mem_o (base_write_mem), + .conditional_o (base_conditional), - .instruction_fault_o (instruction_fault_o), - .imm_o (imm_o), - .v1src_o (v1src_o), - .v2src_o (v2src_o), - .vdsrc_o (vdsrc_o), - .aluop_o (aluop_o) + .instruction_fault_o (base_instruction_fault), + .imm_o (base_imm), + .v1src_o (base_v1src), + .v2src_o (base_v2src), + .vdsrc_o (base_vdsrc), + .aluop_o (base_aluop) ); + + 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; + + write_pc_o = 0; + write_mem_o = 0; + conditional_o = 0; + + instruction_fault_o = 0; + imm_o = 0; + v1src_o = V1SRC_ZERO; + v2src_o = V2SRC_ZERO; + 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; + endcase + end else if (rs1_o == 0 && funct3_o == 0 && opcode_o == 'b0001111) begin + // Nice + end else begin + instruction_fault_o = base_instruction_fault; + + if (~base_instruction_fault) begin + write_pc_o = base_write_pc; + write_mem_o = base_write_mem; + conditional_o = base_conditional; + + imm_o = base_imm; + v1src_o = base_v1src; + v2src_o = base_v2src; + vdsrc_o = base_vdsrc; + aluop_o = base_aluop; + end + end + end endmodule diff --git a/src/decoder/rvx0_decoder_i.sv b/src/decoder/rvx0_decoder_i.sv index 565dc22..c186cc2 100644 --- a/src/decoder/rvx0_decoder_i.sv +++ b/src/decoder/rvx0_decoder_i.sv @@ -1,4 +1,4 @@ -// Base rv32i instruction set decoder +// Base rv32i instruction set decoder minus fence/pause/ecall/ebreak module rvx0_decoder_i ( input wire [31:0] instruction_i, @@ -69,6 +69,10 @@ module rvx0_decoder_i ( v2src_o = V2SRC_ZERO; vdsrc_o = RDSRC_MEM; imm_o = 32'(signed'(imm_i_type)); + + if (funct3[1:0] == 2'b11) begin + instruction_fault_o = 1; + end end 7'b0100011: begin // store v1src_o = V1SRC_RS1; @@ -76,6 +80,10 @@ module rvx0_decoder_i ( vdsrc_o = RDSRC_NONE; write_mem_o = 1; imm_o = 32'(signed'(imm_s_type)); + + if (funct3[1:0] == 2'b11) begin + instruction_fault_o = 1; + end end 7'b0010011: begin // alu imm v1src_o = V1SRC_RS1; diff --git a/src/rvx0_busmux.sv b/src/rvx0_busmux.sv index f230e81..fcb5743 100644 --- a/src/rvx0_busmux.sv +++ b/src/rvx0_busmux.sv @@ -14,7 +14,7 @@ module rvx0_busmux ( // RAM const logic [31:0] APB1_BASE = 'h20000000; - const logic [31:0] APB1_SIZE = 'h00001000; + const logic [31:0] APB1_SIZE = 'h00400000; // Debug const logic [31:0] APB2_BASE = 'h10000000; diff --git a/src/rvx0_defs.svh b/src/rvx0_defs.svh index 0e1f65c..528c66b 100644 --- a/src/rvx0_defs.svh +++ b/src/rvx0_defs.svh @@ -2,6 +2,7 @@ `define __RVX0_DEFS_SVH `define RVX0_DEBUGGING 1 +// `define RVX0_CRASH_ON_EXCEPTION 1 const logic [1:0] RDSRC_ALU = 0; const logic [1:0] RDSRC_MEM = 1; @@ -58,4 +59,7 @@ const logic [31:0] MCAUSE_STORE_PAGE_FAULT = 15; const logic [31:0] MCAUSE_INTR_EXT_MMODE = 11; const logic [31:0] MCAUSE_INTERRUPT = 1 << 31; +const logic IGROUP_RV32I = 0; +const logic IGROUP_SYSTEM = 1; + `endif // __RVX0_DEFS_SVH diff --git a/src/rvx0_simple_ram.sv b/src/rvx0_simple_ram.sv index e6f5b29..9cf1c95 100644 --- a/src/rvx0_simple_ram.sv +++ b/src/rvx0_simple_ram.sv @@ -1,7 +1,7 @@ module rvx0_simple_ram ( rvx0_apb.slave apb_slave ); - reg [31:0] words [0:1023]; + reg [31:0] words [0:1048576]; integer i; @@ -9,11 +9,11 @@ module rvx0_simple_ram ( if (apb_slave.prstn) begin if (apb_slave.penable) begin if (apb_slave.pwrite) begin - words[apb_slave.paddr[11:2]] <= apb_slave.pwdata; + words[apb_slave.paddr[22:2]] <= apb_slave.pwdata; $display("RAM write [%x] <= %x", apb_slave.paddr, apb_slave.pwdata); end else begin - apb_slave.prdata <= words[apb_slave.paddr[11:2]]; - $display("RAM read %x <= [%x]", words[apb_slave.paddr[11:2]], apb_slave.paddr); + apb_slave.prdata <= words[apb_slave.paddr[22:2]]; + $display("RAM read %x <= [%x]", words[apb_slave.paddr[22:2]], apb_slave.paddr); end apb_slave.pready <= 1; @@ -21,10 +21,8 @@ module rvx0_simple_ram ( apb_slave.pready <= 0; end end else begin - // for (i = 0; i < 1024; ++i) - // words[i] <= 0; - - words[0] <= 'h11223344; + for (i = 0; i < 1024; ++i) + words[i] <= 0; end end endmodule