ecall from U-mode has a different mcause value than ecall from M-mode

This commit is contained in:
Luke Wren 2022-05-28 12:07:25 +01:00
parent 632c61daba
commit 81aec325bb
5 changed files with 22 additions and 16 deletions

View File

@ -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;

View File

@ -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

View File

@ -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])

View File

@ -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");

View File

@ -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.