diff --git a/hdl/hazard3_core.v b/hdl/hazard3_core.v index b8d1a7f..2b92b66 100644 --- a/hdl/hazard3_core.v +++ b/hdl/hazard3_core.v @@ -819,7 +819,12 @@ wire [W_EXCEPT-1:0] x_except = x_loadstore_pmp_fail ? EXCEPT_LOAD_FAULT : d_except; // If an instruction causes an exceptional condition we do not consider it to have retired. -wire x_except_counts_as_retire = x_except == EXCEPT_EBREAK || x_except == EXCEPT_MRET || x_except == EXCEPT_ECALL; +wire x_except_counts_as_retire = + x_except == EXCEPT_EBREAK || + x_except == EXCEPT_MRET || + x_except == EXCEPT_ECALL_M || + x_except == EXCEPT_ECALL_U; + wire x_instr_ret = |df_cir_use && (x_except == EXCEPT_NONE || x_except_counts_as_retire); wire m_dphase_in_flight = xm_memop != MEMOP_NONE && xm_memop != MEMOP_AMO; diff --git a/hdl/hazard3_decode.v b/hdl/hazard3_decode.v index d82d8a3..1b2a6e5 100644 --- a/hdl/hazard3_decode.v +++ b/hdl/hazard3_decode.v @@ -292,14 +292,14 @@ always @ (*) begin RV_ZIP: if (EXTENSION_ZBKB) begin d_aluop = ALUOP_ZIP; d_rs2 = X0; end else begin d_invalid_32bit = 1'b1; end RV_FENCE: begin d_rs2 = X0; end // NOP, note rs1/rd are zero in instruction - RV_FENCE_I: if (EXTENSION_ZIFENCEI) begin d_invalid_32bit = DEBUG_SUPPORT && debug_mode; d_branchcond = BCOND_ALWAYS; end else begin d_invalid_32bit = 1'b1; end // note rs1/rs2/rd are zero in instruction + RV_FENCE_I: if (EXTENSION_ZIFENCEI) begin d_invalid_32bit = DEBUG_SUPPORT && debug_mode; d_branchcond = BCOND_ALWAYS; end else begin d_invalid_32bit = 1'b1; end // note rs1/rs2/rd are zero in instruction RV_CSRRW: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = 1'b1 ; d_csr_ren = |d_rd; d_csr_wtype = CSR_WTYPE_W; end else begin d_invalid_32bit = 1'b1; end RV_CSRRS: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_S; end else begin d_invalid_32bit = 1'b1; end RV_CSRRC: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_C; end else begin d_invalid_32bit = 1'b1; end RV_CSRRWI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = 1'b1 ; d_csr_ren = |d_rd; d_csr_wtype = CSR_WTYPE_W; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end RV_CSRRSI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_S; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end RV_CSRRCI: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = |d_rs1; d_csr_ren = 1'b1 ; d_csr_wtype = CSR_WTYPE_C; d_csr_w_imm = 1'b1; end else begin d_invalid_32bit = 1'b1; end - RV_ECALL: if (HAVE_CSR) begin d_except = EXCEPT_ECALL; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end + RV_ECALL: if (HAVE_CSR) begin d_except = m_mode || !U_MODE ? EXCEPT_ECALL_M : EXCEPT_ECALL_U; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end RV_EBREAK: if (HAVE_CSR) begin d_except = EXCEPT_EBREAK; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end RV_MRET: if (HAVE_CSR && m_mode) begin d_except = EXCEPT_MRET; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end RV_WFI: if (HAVE_CSR && permit_wfi) begin d_wfi = 1'b1; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end diff --git a/hdl/hazard3_ops.vh b/hdl/hazard3_ops.vh index 7260887..40d35e0 100644 --- a/hdl/hazard3_ops.vh +++ b/hdl/hazard3_ops.vh @@ -103,8 +103,9 @@ localparam EXCEPT_LOAD_ALIGN = 4'h4; localparam EXCEPT_LOAD_FAULT = 4'h5; localparam EXCEPT_STORE_ALIGN = 4'h6; localparam EXCEPT_STORE_FAULT = 4'h7; +localparam EXCEPT_ECALL_U = 4'h8; localparam EXCEPT_MRET = 4'ha; // Not really an exception, but handled like one -localparam EXCEPT_ECALL = 4'hb; +localparam EXCEPT_ECALL_M = 4'hb; // Operations for M extension (these are just instr[14:12]) diff --git a/test/sim/sw_testcases/pmp_u_x.c b/test/sim/sw_testcases/pmp_u_x.c index 0de1edd..6ac8a2c 100644 --- a/test/sim/sw_testcases/pmp_u_x.c +++ b/test/sim/sw_testcases/pmp_u_x.c @@ -15,19 +15,19 @@ Initial mcause = 1 4-byte region -mcause = 11 +mcause = 8 Large region -mcause = 11 +mcause = 8 X under !X -mcause = 11 +mcause = 8 !X under X mcause = 1 Full match under partial match, positive overhang -mcause = 11 +mcause = 8 Partial match under full match, positive overhang mcause = 1 Full match under partial match, negative overhang -mcause = 11 +mcause = 8 Partial match under full match, negative overhang mcause = 1 Jump to bad jump @@ -89,7 +89,7 @@ void __attribute__((naked)) do_jump() { } #define MCAUSE_INSTR_FAULT 1 -#define MCAUSE_ECALL 11 +#define MCAUSE_ECALL_UMODE 8 int main() { // Initially, there are no permissions active in the PMP, so we should get @@ -107,7 +107,7 @@ int main() { enter_umode(&do_ecall); tb_printf("mcause = %u\n", read_csr(mcause)); - tb_assert(read_csr(mcause) == MCAUSE_ECALL, "Should successfully execute ecall\n"); + tb_assert(read_csr(mcause) == MCAUSE_ECALL_UMODE, "Should successfully execute ecall\n"); tb_assert(read_csr(mepc) == (uint32_t)&do_ecall, "Bad mepc\n"); // Make the region larger (all of memory) -- should still pass. @@ -117,7 +117,7 @@ int main() { enter_umode(&do_ecall); tb_printf("mcause = %u\n", read_csr(mcause)); - tb_assert(read_csr(mcause) == MCAUSE_ECALL, "Should successfully execute ecall\n"); + tb_assert(read_csr(mcause) == MCAUSE_ECALL_UMODE, "Should successfully execute ecall\n"); tb_assert(read_csr(mepc) == (uint32_t)&do_ecall, "Bad mepc\n"); // Put another region on top, with no permissions -- should still pass @@ -130,7 +130,7 @@ int main() { enter_umode(&do_ecall); tb_printf("mcause = %u\n", read_csr(mcause)); - tb_assert(read_csr(mcause) == MCAUSE_ECALL, "Should successfully execute ecall\n"); + tb_assert(read_csr(mcause) == MCAUSE_ECALL_UMODE, "Should successfully execute ecall\n"); tb_assert(read_csr(mepc) == (uint32_t)&do_ecall, "Bad mepc\n"); // Swap the two regions. Should now fail, because lower-numbered region @@ -159,7 +159,7 @@ int main() { enter_umode(&do_nops); tb_printf("mcause = %u\n", read_csr(mcause)); - tb_assert(read_csr(mcause) == MCAUSE_ECALL, "Should successfully execute ecall\n"); + tb_assert(read_csr(mcause) == MCAUSE_ECALL_UMODE, "Should successfully execute ecall\n"); tb_assert(read_csr(mepc) == (uint32_t)&do_nops + 6, "Bad mepc\n"); // Now swap the order of the regions. The partial match of the @@ -186,7 +186,7 @@ int main() { enter_umode(&do_nops); tb_printf("mcause = %u\n", read_csr(mcause)); - tb_assert(read_csr(mcause) == MCAUSE_ECALL, "Should successfully execute ecall\n"); + tb_assert(read_csr(mcause) == MCAUSE_ECALL_UMODE, "Should successfully execute ecall\n"); tb_assert(read_csr(mepc) == (uint32_t)&do_nops + 6, "Bad mepc\n"); tb_puts("Partial match under full match, negative overhang\n"); diff --git a/test/sim/sw_testcases/umode_wfi.c b/test/sim/sw_testcases/umode_wfi.c index 8f7c4d3..23a5708 100644 --- a/test/sim/sw_testcases/umode_wfi.c +++ b/test/sim/sw_testcases/umode_wfi.c @@ -7,7 +7,7 @@ /*EXPECTED-OUTPUT*************************************************************** Do WFI with TW=0: -mcause = 11 // = ecall, meaning normal exit. The test also checks mepc. +mcause = 8 // = ecall, meaning normal exit. The test also checks mepc. Do WFI with TW=1: mstatus = 00200000 // Check TW write is reflected in readback mcause = 2 // = illegal instruction. The test also checks mepc.