Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added exception codes 0x4 and 0x6 misaligned atomics. #794

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions bhv/cv32e40x_rvfi.sv
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,6 @@ module cv32e40x_rvfi
// Detect PMA errors due to misaligned accesses
logic lsu_pma_err_misaligned_ex;

// Detect LSU errors due to misaligned atomics (uses PMA logic but is not a true PMA error)
logic lsu_err_misaligned_atomic_ex;

assign mret_ptr_wb = mret_ptr_wb_i;

// PMA error due to atomic not within an atomic region
Expand All @@ -723,9 +720,6 @@ module cv32e40x_rvfi
// PMA error due to misaligned accesses to I/O memory
assign lsu_pma_err_misaligned_ex = lsu_pma_err_ex_i && lsu_misaligned_ex_i && !lsu_pma_cfg_ex_i.main;

// Detect LSU errors due to misaligned atomic instructions
assign lsu_err_misaligned_atomic_ex = lsu_pma_err_ex_i && lsu_pma_atomic_ex_i && lsu_misaligned_ex_i;

assign insn_opcode = rvfi_insn[6:0];
assign insn_rd = rvfi_insn[11:7];
assign insn_funct3 = rvfi_insn[14:12];
Expand Down Expand Up @@ -857,6 +851,12 @@ module cv32e40x_rvfi
EXC_CAUSE_STORE_FAULT : begin
rvfi_trap_next.cause_type = mem_err[STAGE_WB];
end
EXC_CAUSE_LOAD_MISALIGNED : begin
rvfi_trap_next.cause_type = 2'h0;
end
EXC_CAUSE_STORE_MISALIGNED : begin
rvfi_trap_next.cause_type = 2'h0;
end
default : begin
// rvfi_trap_next.cause_type is only set for exception codes that can have multiple causes
end
Expand Down Expand Up @@ -1109,8 +1109,10 @@ module cv32e40x_rvfi
ex_mem_trans <= lsu_data_trans;
end

mem_err [STAGE_WB] = lsu_err_misaligned_atomic_ex ? MEM_ERR_MISALIGNED_ATOMIC : // Non-naturally aligned atomic
lsu_pma_err_misaligned_ex ? MEM_ERR_IO_ALIGN : // Non-natrually aligned access to !main
// Capture cause of LSU exception for the cases that can have multiple reasons for an exception
// These are currently load and store access faults trigger by misaligned access to i/o regions,
// atomic accesses to regions not enabled for atomics or accesses blocked by PMP.
mem_err [STAGE_WB] = lsu_pma_err_misaligned_ex ? MEM_ERR_IO_ALIGN : // Non-natrually aligned access to !main
lsu_pma_err_atomic_ex ? MEM_ERR_ATOMIC : // Any atomic to non-atomic PMA region
MEM_ERR_PMP; // PMP error

Expand Down
7 changes: 3 additions & 4 deletions bhv/include/cv32e40x_rvfi_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ package cv32e40x_rvfi_pkg;
parameter NMEM = 128; // Maximum number of memory transactions per instruction is currently 13 when ZC_EXT=1

typedef enum logic [1:0] { // Memory error types
MEM_ERR_MISALIGNED_ATOMIC = 2'h0,
MEM_ERR_IO_ALIGN = 2'h1,
MEM_ERR_ATOMIC = 2'h2,
MEM_ERR_PMP = 2'h3
MEM_ERR_IO_ALIGN = 2'h0,
MEM_ERR_ATOMIC = 2'h1,
MEM_ERR_PMP = 2'h2
} mem_err_t;

typedef struct packed { // Autonomously updated CSRs
Expand Down
16 changes: 9 additions & 7 deletions rtl/cv32e40x_controller_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,16 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*;
assign ctrl_fsm_o.exception_in_wb = exception_in_wb;

// Set exception cause
assign exception_cause_wb = (ex_wb_pipe_i.instr.mpu_status != MPU_OK) ? EXC_CAUSE_INSTR_FAULT :
ex_wb_pipe_i.instr.bus_resp.err ? EXC_CAUSE_INSTR_BUS_FAULT :
ex_wb_pipe_i.illegal_insn ? EXC_CAUSE_ILLEGAL_INSN :
(ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_ecall_insn) ? EXC_CAUSE_ECALL_MMODE :
assign exception_cause_wb = (ex_wb_pipe_i.instr.mpu_status != MPU_OK) ? EXC_CAUSE_INSTR_FAULT :
ex_wb_pipe_i.instr.bus_resp.err ? EXC_CAUSE_INSTR_BUS_FAULT :
ex_wb_pipe_i.illegal_insn ? EXC_CAUSE_ILLEGAL_INSN :
(ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_ecall_insn) ? EXC_CAUSE_ECALL_MMODE :
(ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_ebrk_insn && (ex_wb_pipe_i.priv_lvl == PRIV_LVL_M) &&
!dcsr_i.ebreakm && !debug_mode_q) ? EXC_CAUSE_BREAKPOINT :
(mpu_status_wb_i == MPU_WR_FAULT) ? EXC_CAUSE_STORE_FAULT :
EXC_CAUSE_LOAD_FAULT; // (mpu_status_wb_i == MPU_RE_FAULT)
!dcsr_i.ebreakm && !debug_mode_q) ? EXC_CAUSE_BREAKPOINT :
(mpu_status_wb_i == MPU_WR_FAULT) ? EXC_CAUSE_STORE_FAULT :
(mpu_status_wb_i == MPU_RE_FAULT) ? EXC_CAUSE_LOAD_FAULT :
(mpu_status_wb_i == MPU_WR_MISALIGNED) ? EXC_CAUSE_STORE_MISALIGNED :
EXC_CAUSE_LOAD_MISALIGNED;

assign ctrl_fsm_o.exception_cause_wb = exception_cause_wb;

Expand Down
28 changes: 21 additions & 7 deletions rtl/cv32e40x_mpu.sv
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ module cv32e40x_mpu import cv32e40x_pkg::*;
);

logic pma_err;
logic pma_misaligned_atomic;
logic mpu_err;
logic mpu_block_core;
logic mpu_block_bus;
Expand Down Expand Up @@ -118,35 +119,47 @@ module cv32e40x_mpu import cv32e40x_pkg::*;
if (core_mpu_err_wait_i) begin
if(core_trans_we) begin
// MPU error on write
state_n = core_one_txn_pend_n ? MPU_WR_ERR_RESP : MPU_WR_ERR_WAIT;
// PMA errors take precedence over misaligned atomics
state_n = core_one_txn_pend_n ? (pma_err ? MPU_WR_ERR_RESP : MPU_WR_MISALIGN_RESP) :
(pma_err ? MPU_WR_ERR_WAIT : MPU_WR_MISALIGN_WAIT);
end
else begin
// MPU error on read
state_n = core_one_txn_pend_n ? MPU_RE_ERR_RESP : MPU_RE_ERR_WAIT;
// PMA errors take precedence over misaligned atomics
state_n = core_one_txn_pend_n ? (pma_err ? MPU_RE_ERR_RESP : MPU_RE_MISALIGN_RESP) :
(pma_err ? MPU_RE_ERR_WAIT : MPU_RE_MISALIGN_WAIT);
end
end

end
end
MPU_RE_ERR_WAIT, MPU_WR_ERR_WAIT: begin
MPU_RE_ERR_WAIT, MPU_WR_ERR_WAIT,
MPU_RE_MISALIGN_WAIT, MPU_WR_MISALIGN_WAIT: begin

// Block new transfers while waiting for in flight transfers to complete
mpu_block_bus = 1'b1;
mpu_block_core = 1'b1;

if (core_one_txn_pend_n) begin
state_n = (state_q == MPU_RE_ERR_WAIT) ? MPU_RE_ERR_RESP : MPU_WR_ERR_RESP;
state_n = (state_q == MPU_RE_ERR_WAIT) ? MPU_RE_ERR_RESP :
(state_q == MPU_WR_ERR_WAIT) ? MPU_WR_ERR_RESP :
(state_q == MPU_RE_MISALIGN_WAIT) ? MPU_RE_MISALIGN_RESP :
MPU_WR_MISALIGN_RESP;
end
end
MPU_RE_ERR_RESP, MPU_WR_ERR_RESP: begin
MPU_RE_ERR_RESP, MPU_WR_ERR_RESP,
MPU_RE_MISALIGN_RESP, MPU_WR_MISALIGN_RESP: begin

// Keep blocking new transfers
mpu_block_bus = 1'b1;
mpu_block_core = 1'b1;

// Set up MPU error response towards the core
mpu_err_trans_valid = 1'b1;
mpu_status = (state_q == MPU_RE_ERR_RESP) ? MPU_RE_FAULT : MPU_WR_FAULT;
mpu_status = (state_q == MPU_RE_ERR_RESP) ? MPU_RE_FAULT :
(state_q == MPU_WR_ERR_RESP) ? MPU_WR_FAULT :
(state_q == MPU_RE_MISALIGN_RESP) ? MPU_RE_MISALIGNED :
MPU_WR_MISALIGNED;

// Go back to IDLE uncoditionally.
// The core is expected to always be ready for the response
Expand Down Expand Up @@ -203,11 +216,12 @@ module cv32e40x_mpu import cv32e40x_pkg::*;
.misaligned_access_i ( misaligned_access_i ),
.load_access_i ( load_access ),
.pma_err_o ( pma_err ),
.pma_misaligned_atomic_o ( pma_misaligned_atomic ),
.pma_bufferable_o ( bus_trans_bufferable ),
.pma_cacheable_o ( bus_trans_cacheable )
);

assign mpu_err = pma_err;
assign mpu_err = pma_err || pma_misaligned_atomic;

// Writes are only supported on the data interface
// Tie to 1'b0 if this MPU is instantiatied in the IF stage
Expand Down
15 changes: 7 additions & 8 deletions rtl/cv32e40x_pma.sv
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module cv32e40x_pma import cv32e40x_pkg::*;
input logic misaligned_access_i, // Indicate that ongoing access is part of a misaligned access
input logic load_access_i, // Indicate that ongoing access is a load
output logic pma_err_o,
output logic pma_misaligned_atomic_o, // Atomic instruction is misaligned
output logic pma_bufferable_o,
output logic pma_cacheable_o
);
Expand Down Expand Up @@ -102,9 +103,15 @@ module cv32e40x_pma import cv32e40x_pkg::*;
generate
if (A_EXT) begin: pma_atomic
assign pma_cfg_atomic = pma_cfg.atomic;

// Check if atomic access is misaligned.
// If not otherwise blocked by the PMA, this will results in exception codes
// 4 or 6 indicating misaligned load/store atomics.
assign pma_misaligned_atomic_o = atomic_access_i && misaligned_access_i;
end
else begin: pma_no_atomic
assign pma_cfg_atomic = 1'b0;
assign pma_misaligned_atomic_o = 1'b0;
end
endgenerate

Expand All @@ -118,14 +125,6 @@ module cv32e40x_pma import cv32e40x_pkg::*;
pma_err_o = 1'b1;
end

// Check that atomic accesses are not misaligned
// Not strictly a part of the PMA, but reusing the PMA logic for flagging errors
// and consume transactions rather than making separate logic in the LSU. Uses the same exception
// codes as PMA errors.
if (atomic_access_i && misaligned_access_i) begin
pma_err_o = 1'b1;
end

// Instruction fetches only allowed in main memory
if (instr_fetch_access_i && !pma_cfg.main) begin
pma_err_o = 1'b1;
Expand Down
32 changes: 19 additions & 13 deletions rtl/include/cv32e40x_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -901,16 +901,19 @@ typedef enum logic[3:0] {
} pc_mux_e;

// Exception Cause
parameter EXC_CAUSE_INSTR_FAULT = 11'h01;
parameter EXC_CAUSE_ILLEGAL_INSN = 11'h02;
parameter EXC_CAUSE_BREAKPOINT = 11'h03;
parameter EXC_CAUSE_LOAD_FAULT = 11'h05;
parameter EXC_CAUSE_STORE_FAULT = 11'h07;
parameter EXC_CAUSE_ECALL_MMODE = 11'h0B;
parameter EXC_CAUSE_INSTR_BUS_FAULT = 11'h18;
parameter EXC_CAUSE_INSTR_FAULT = 11'h01;
parameter EXC_CAUSE_ILLEGAL_INSN = 11'h02;
parameter EXC_CAUSE_BREAKPOINT = 11'h03;
parameter EXC_CAUSE_LOAD_MISALIGNED = 11'h04;
parameter EXC_CAUSE_LOAD_FAULT = 11'h05;
parameter EXC_CAUSE_STORE_MISALIGNED = 11'h06;
parameter EXC_CAUSE_STORE_FAULT = 11'h07;
parameter EXC_CAUSE_ECALL_MMODE = 11'h0B;
parameter EXC_CAUSE_INSTR_BUS_FAULT = 11'h18;

parameter logic [31:0] ETRIGGER_TDATA2_MASK = (1 << EXC_CAUSE_INSTR_BUS_FAULT) | (1 << EXC_CAUSE_ECALL_MMODE) | (1 << EXC_CAUSE_STORE_FAULT) |
(1 << EXC_CAUSE_LOAD_FAULT) | (1 << EXC_CAUSE_BREAKPOINT) | (1 << EXC_CAUSE_ILLEGAL_INSN) | (1 << EXC_CAUSE_INSTR_FAULT);
(1 << EXC_CAUSE_LOAD_FAULT) | (1 << EXC_CAUSE_BREAKPOINT) | (1 << EXC_CAUSE_ILLEGAL_INSN) | (1 << EXC_CAUSE_INSTR_FAULT) |
(1 << EXC_CAUSE_LOAD_MISALIGNED) | (1<<EXC_CAUSE_STORE_MISALIGNED);

parameter INT_CAUSE_LSU_LOAD_FAULT = 11'h400;
parameter INT_CAUSE_LSU_STORE_FAULT = 11'h401;
Expand Down Expand Up @@ -962,13 +965,16 @@ parameter pma_cfg_t PMA_R_DEFAULT = '{word_addr_low : 0,
atomic : 1'b0};

// MPU status. Used for PMA
typedef enum logic [1:0] {
MPU_OK = 2'h0,
MPU_RE_FAULT = 2'h1,
MPU_WR_FAULT = 2'h2
typedef enum logic [2:0] {
MPU_OK = 3'h0,
MPU_RE_FAULT = 3'h1,
MPU_WR_FAULT = 3'h2,
MPU_RE_MISALIGNED = 3'h3,
MPU_WR_MISALIGNED = 3'h4
} mpu_status_e;

typedef enum logic [2:0] {MPU_IDLE, MPU_RE_ERR_RESP, MPU_RE_ERR_WAIT, MPU_WR_ERR_RESP, MPU_WR_ERR_WAIT} mpu_state_e;
typedef enum logic [3:0] {MPU_IDLE, MPU_RE_ERR_RESP, MPU_RE_ERR_WAIT, MPU_RE_MISALIGN_RESP, MPU_RE_MISALIGN_WAIT,
MPU_WR_ERR_RESP, MPU_WR_ERR_WAIT, MPU_WR_MISALIGN_RESP, MPU_WR_MISALIGN_WAIT} mpu_state_e;

// WPT state machine
typedef enum logic [1:0] {WPT_IDLE, WPT_MATCH_WAIT, WPT_MATCH_RESP} wpt_state_e;
Expand Down
14 changes: 11 additions & 3 deletions sva/cv32e40x_mpu_sva.sv
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ module cv32e40x_mpu_sva import cv32e40x_pkg::*; import uvm_pkg::*;
input logic mpu_block_bus,
input mpu_state_e state_q,
input logic mpu_err,
input logic load_access
input logic load_access,
input logic pma_misaligned_atomic
);

// PMA assertions helper signals
Expand Down Expand Up @@ -225,6 +226,7 @@ module cv32e40x_mpu_sva import cv32e40x_pkg::*; import uvm_pkg::*;
// RTL vs SVA expectations
pma_cfg_t pma_expected_cfg;
logic pma_expected_err;
logic pma_expected_misaligned_err;
always_comb begin
pma_expected_cfg = NO_PMA_R_DEFAULT;
if (PMA_NUM_REGIONS) begin
Expand All @@ -236,8 +238,10 @@ module cv32e40x_mpu_sva import cv32e40x_pkg::*; import uvm_pkg::*;
assign pma_expected_err = (instr_fetch_access && !pma_expected_cfg.main) ||
(misaligned_access_i && !pma_expected_cfg.main) ||
(atomic_access_i && !pma_expected_cfg.atomic) ||
(misaligned_access_i && atomic_access_i) ||
(core_trans_pushpop_i && !pma_expected_cfg.main);

assign pma_expected_misaligned_err = (misaligned_access_i && atomic_access_i);

a_pma_expect_cfg :
assert property (@(posedge clk) disable iff (!rst_n) pma_cfg == pma_expected_cfg)
else `uvm_error("mpu", "RTL cfg don't match SVA expectations")
Expand All @@ -257,10 +261,14 @@ module cv32e40x_mpu_sva import cv32e40x_pkg::*; import uvm_pkg::*;
a_pma_expect_cacheable :
assert property (@(posedge clk) disable iff (!rst_n) bus_trans_cacheable == pma_expected_cfg.cacheable)
else `uvm_error("mpu", "expected different cacheable flag")

a_pma_expect_err :
assert property (@(posedge clk) disable iff (!rst_n) pma_err == pma_expected_err)
else `uvm_error("mpu", "expected different err flag")

a_pma_expect_misaligned_err :
assert property (@(posedge clk) disable iff (!rst_n) pma_misaligned_atomic == pma_expected_misaligned_err)
else `uvm_error("mpu", "expected different err flag for misaligned atomics")
// Bufferable
generate
if (bufferable_in_config() && !IS_INSTR_SIDE) begin
Expand Down Expand Up @@ -436,7 +444,7 @@ if (A_EXT != A_NONE) begin
assert property (@(posedge clk) disable iff (!rst_n)
core_trans_valid_i &&
atomic_access_i &&
!pma_err
!pma_misaligned_atomic
|->
(core_trans_i.addr[1:0] == 2'b00))
else `uvm_error("mpu", "Misaligned atomic instruction not flagged with error")
Expand Down
34 changes: 29 additions & 5 deletions sva/cv32e40x_rvfi_sva.sv
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,14 @@ if (DEBUG) begin
end

if ((A_EXT == A) || (A_EXT == ZALRSC)) begin
// A PMA error due to an aligned LR.W accessing a non-atomic region must get cause_type==MEM_ERR_ATOMIC (1)
// If a LR.W gets blocked due to misalignment, it must get cause_type==MEM_ERR_IO_ALIGN (0)
// Aligned atomics blocked by the PMA shall use the EXC_CAUSE_LOAD_FAULT or EXC_CAUSE_STORE_FAULT exception codes with
// cause_type MEM_ERR_ATOMIC.
//
// Misaligned atomics to a non-main PMA region shall use EXC_CAUSE_LOAD_FAULT or EXC_CAUSE_STORE_FAULT exception codes with
// cause_type MEM_ERR_IO_ALIGN
//
// Misaligned atomics which are otherwise not blocked by the PMA (cfg is main and atomic) shall use either
// EXC_CAUSE_LOAD_MISALIGNED or EXC_CAUSE_STORE_MISALIGNED with cause_type MEM_ERR_IO_ALIGN.
a_aligned_lr_access_fault_trap:
assert property (@(posedge clk_i) disable iff (!rst_ni)
pc_mux_exception && (lsu_atomic_wb_i == AT_LR) && lsu_en_wb_i &&
Expand All @@ -239,8 +245,14 @@ if ((A_EXT == A) || (A_EXT == ZALRSC)) begin
lsu_split_q_wb_i
|=>
rvfi_valid &&
(rvfi_trap.cause_type == MEM_ERR_MISALIGNED_ATOMIC) &&
((rvfi_trap.cause_type == MEM_ERR_IO_ALIGN) &&
(rvfi_trap.exception_cause == EXC_CAUSE_LOAD_MISALIGNED))
or
((rvfi_trap.cause_type == MEM_ERR_ATOMIC) &&
(rvfi_trap.exception_cause == EXC_CAUSE_LOAD_FAULT))
or
((rvfi_trap.cause_type == MEM_ERR_IO_ALIGN) &&
(rvfi_trap.exception_cause == EXC_CAUSE_LOAD_FAULT)))
else `uvm_error("rvfi", "Exception on misaligned LR.W atomic instruction did not set correct cause_type in rvfi_trap")

a_aligned_sc_access_fault_trap:
Expand All @@ -259,8 +271,14 @@ if ((A_EXT == A) || (A_EXT == ZALRSC)) begin
lsu_split_q_wb_i
|=>
rvfi_valid &&
(rvfi_trap.cause_type == MEM_ERR_MISALIGNED_ATOMIC) &&
((rvfi_trap.cause_type == MEM_ERR_IO_ALIGN) &&
(rvfi_trap.exception_cause == EXC_CAUSE_STORE_MISALIGNED))
or
((rvfi_trap.cause_type == MEM_ERR_ATOMIC) &&
(rvfi_trap.exception_cause == EXC_CAUSE_STORE_FAULT))
or
((rvfi_trap.cause_type == MEM_ERR_IO_ALIGN) &&
(rvfi_trap.exception_cause == EXC_CAUSE_STORE_FAULT)))
else `uvm_error("rvfi", "Exception on misaligned SC.W atomic instruction did not set correct cause_type in rvfi_trap")
end

Expand All @@ -281,8 +299,14 @@ if (A_EXT == A) begin
lsu_split_q_wb_i
|=>
rvfi_valid &&
(rvfi_trap.cause_type == MEM_ERR_MISALIGNED_ATOMIC) &&
((rvfi_trap.cause_type == MEM_ERR_IO_ALIGN) &&
(rvfi_trap.exception_cause == EXC_CAUSE_STORE_MISALIGNED))
or
((rvfi_trap.cause_type == MEM_ERR_ATOMIC) &&
(rvfi_trap.exception_cause == EXC_CAUSE_STORE_FAULT))
or
((rvfi_trap.cause_type == MEM_ERR_IO_ALIGN) &&
(rvfi_trap.exception_cause == EXC_CAUSE_STORE_FAULT)))
else `uvm_error("rvfi", "Exception on misaligned AMO* atomic instruction did not set correct cause_type in rvfi_trap")
end

Expand Down