Skip to content

Commit

Permalink
Merge pull request #794 from silabs-oysteink/silabs-oysteink_misalign…
Browse files Browse the repository at this point in the history
…ed-a-exc

Added exception codes 0x4 and 0x6 misaligned atomics.
  • Loading branch information
Silabs-ArjanB authored Feb 27, 2023
2 parents 745d3e0 + 25f616c commit 60b349e
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 55 deletions.
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

0 comments on commit 60b349e

Please sign in to comment.