diff --git a/bhv/cv32e40x_wrapper.sv b/bhv/cv32e40x_wrapper.sv index 3d47c6fa..28365d2a 100644 --- a/bhv/cv32e40x_wrapper.sv +++ b/bhv/cv32e40x_wrapper.sv @@ -174,6 +174,7 @@ module cv32e40x_wrapper core_i.if_stage_i cv32e40x_if_stage_sva #(.CLIC(CLIC)) if_stage_sva ( .m_c_obi_instr_if (core_i.m_c_obi_instr_if), // SVA monitor modport cannot connect to a master modport + .align_err_i (core_i.if_stage_i.align_check_i.align_err), .* ); @@ -266,8 +267,8 @@ module cv32e40x_wrapper .lsu_en_id (core_i.id_stage_i.lsu_en), .ctrl_fsm_cs (core_i.controller_i.controller_fsm_i.ctrl_fsm_cs), .ctrl_fsm_ns (core_i.controller_i.controller_fsm_i.ctrl_fsm_ns), - .mpu_err (core_i.load_store_unit_i.mpu_i.mpu_err), - .mpu_block_bus (core_i.load_store_unit_i.mpu_i.mpu_block_bus), + .mpu_err_i (core_i.load_store_unit_i.mpu_i.mpu_err), + .align_err_i (core_i.load_store_unit_i.align_check_i.align_err), .*); generate diff --git a/cv32e40x_manifest.flist b/cv32e40x_manifest.flist index fe22bc92..71a401b7 100644 --- a/cv32e40x_manifest.flist +++ b/cv32e40x_manifest.flist @@ -33,6 +33,7 @@ ${DESIGN_RTL_DIR}/if_c_obi.sv ${DESIGN_RTL_DIR}/if_xif.sv ${DESIGN_RTL_DIR}/../bhv/include/cv32e40x_rvfi_pkg.sv ${DESIGN_RTL_DIR}/../bhv/cv32e40x_wrapper.sv +${DESIGN_RTL_DIR}/cv32e40x_align_check.sv ${DESIGN_RTL_DIR}/cv32e40x_if_stage.sv ${DESIGN_RTL_DIR}/cv32e40x_csr.sv ${DESIGN_RTL_DIR}/cv32e40x_debug_triggers.sv diff --git a/rtl/cv32e40x_align_check.sv b/rtl/cv32e40x_align_check.sv new file mode 100644 index 00000000..dd861b5a --- /dev/null +++ b/rtl/cv32e40x_align_check.sv @@ -0,0 +1,186 @@ +// Copyright 2022 Silicon Labs, Inc. +// +// This file, and derivatives thereof are licensed under the +// Solderpad License, Version 2.0 (the "License"); +// Use of this file means you agree to the terms and conditions +// of the license and are in full compliance with the License. +// You may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.0/ +// +// Unless required by applicable law or agreed to in writing, software +// and hardware implementations thereof +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESSED OR IMPLIED. +// See the License for the specific language governing permissions and +// limitations under the License. + +//////////////////////////////////////////////////////////////////////////////// +// // +// Authors: Oystein Knauserud - oystein.knauserud@silabs.com // +// // +// Description: Alignment checker for mret pointers and atomics // +// // +//////////////////////////////////////////////////////////////////////////////// + +module cv32e40x_align_check import cv32e40x_pkg::*; + #( parameter bit IF_STAGE = 1, + parameter type CORE_REQ_TYPE = obi_inst_req_t, + parameter type CORE_RESP_TYPE = inst_resp_t, + parameter type BUS_RESP_TYPE = inst_resp_t + + ) + ( + input logic clk, + input logic rst_n, + + // Enable signal, active for atomics and pointers + input logic align_check_en_i, + input logic misaligned_access_i, + + // Interface towards bus interface + input logic bus_trans_ready_i, + output logic bus_trans_valid_o, + output logic bus_trans_pushpop_o, + output CORE_REQ_TYPE bus_trans_o, + + input logic bus_resp_valid_i, + input BUS_RESP_TYPE bus_resp_i, + + // Interface towards core (MPU) + input logic core_trans_valid_i, + output logic core_trans_ready_o, + input logic core_trans_pushpop_i, + input CORE_REQ_TYPE core_trans_i, + + output logic core_resp_valid_o, + output CORE_RESP_TYPE core_resp_o, + + // Indication from the core that there will be one pending transaction in the next cycle + input logic core_one_txn_pend_n, + + // Indication from the core that an alignment error should be reported after all in flight transactions + // are complete (default behavior for main core requests, but not used for XIF requests) + input logic core_align_err_wait_i, + + // Report alignment errors to the core immediatly (used in case core_align_wait_i is not asserted) + output logic core_align_err_o + ); + + logic align_block_core; + logic align_block_bus; + logic align_trans_valid; + logic align_trans_ready; + logic align_err; + logic core_trans_we; + align_status_e align_status; + align_state_e state_q, state_n; + + // FSM that will "consume" transfers which violates alignment requirement for atomics or pointers. + // Upon an error, this FSM will prevent the transfer from going out on the bus + // and wait for all in flight bus transactions to complete while blocking new transfers. + // When all in flight transactions are complete, it will respond with the correct status before + // allowing new transfers to go through. + // The input signal core_one_txn_pend_n indicates that there, from the core's point of view, + // will be one pending transaction in the next cycle. Upon an error, this transaction + // will be completed by this FSM + always_comb begin + + state_n = state_q; + align_block_core = 1'b0; + align_block_bus = 1'b0; + align_trans_valid = 1'b0; + align_trans_ready = 1'b0; + align_status = ALIGN_OK; + + case(state_q) + ALIGN_IDLE: begin + if (align_err && core_trans_valid_i) begin + + // Block transfer from going out on the bus. + align_block_bus = 1'b1; + + // Signal to the core that the transfer was accepted (but will be consumed by the align) + align_trans_ready = 1'b1; + + if (core_align_err_wait_i) begin + if (core_trans_we) begin + state_n = core_one_txn_pend_n ? ALIGN_WR_ERR_RESP : ALIGN_WR_ERR_WAIT; + end else begin + state_n = core_one_txn_pend_n ? ALIGN_RE_ERR_RESP : ALIGN_RE_ERR_WAIT; + end + end + + end + end + ALIGN_WR_ERR_WAIT, + ALIGN_RE_ERR_WAIT: begin + + // Block new transfers while waiting for in flight transfers to complete + align_block_bus = 1'b1; + align_block_core = 1'b1; + + if (core_one_txn_pend_n) begin + state_n = (state_q == ALIGN_WR_ERR_WAIT) ? ALIGN_WR_ERR_RESP : ALIGN_RE_ERR_RESP; + end + end + ALIGN_WR_ERR_RESP, + ALIGN_RE_ERR_RESP: begin + + // Keep blocking new transfers + align_block_bus = 1'b1; + align_block_core = 1'b1; + + // Set up align response towards the core + align_trans_valid = 1'b1; + align_status = (state_q == ALIGN_WR_ERR_RESP) ? ALIGN_WR_ERR : ALIGN_RE_ERR; + + // Go back to IDLE uncoditionally. + // The core is expected to always be ready for the response + state_n = ALIGN_IDLE; + + end + default: ; + endcase + end + + always_ff @(posedge clk, negedge rst_n) begin + if (rst_n == 1'b0) begin + state_q <= ALIGN_IDLE; + end + else begin + state_q <= state_n; + end + end + + // Forward transaction request towards MPU + assign bus_trans_valid_o = core_trans_valid_i && !align_block_bus; + assign bus_trans_o = core_trans_i; + assign bus_trans_pushpop_o = core_trans_pushpop_i; + + + // Forward transaction response towards core + assign core_resp_valid_o = bus_resp_valid_i || align_trans_valid; + assign core_resp_o.bus_resp = bus_resp_i; + assign core_resp_o.align_status = align_status; + assign core_resp_o.mpu_status = MPU_OK; // Assigned in the MPU (upstream), tied off to MPU_OK here. + + // Detect alignment error + assign align_err = align_check_en_i && misaligned_access_i; + + // Report align matches to the core immediately + assign core_align_err_o = align_err; + + // Signal ready towards core + assign core_trans_ready_o = (bus_trans_ready_i && !align_block_core) || align_trans_ready; + + generate + if (IF_STAGE) begin: alcheck_if + assign core_trans_we = 1'b0; + end + else begin: alcheck_lsu + assign core_trans_we = core_trans_i.we; + end + endgenerate + +endmodule diff --git a/rtl/cv32e40x_controller.sv b/rtl/cv32e40x_controller.sv index 9b305ce4..74836143 100644 --- a/rtl/cv32e40x_controller.sv +++ b/rtl/cv32e40x_controller.sv @@ -69,6 +69,7 @@ module cv32e40x_controller import cv32e40x_pkg::*; input ex_wb_pipe_t ex_wb_pipe_i, input mpu_status_e mpu_status_wb_i, // MPU status (WB stage) input logic wpt_match_wb_i, // LSU watchpoint trigger in WB + input align_status_e align_status_wb_i, // Aligned status (atomics and mret pointers) in WB // Last operation bits input logic last_op_ex_i, // EX contains the last operation of an instruction @@ -190,6 +191,7 @@ module cv32e40x_controller import cv32e40x_pkg::*; .ex_wb_pipe_i ( ex_wb_pipe_i ), .lsu_err_wb_i ( lsu_err_wb_i ), .mpu_status_wb_i ( mpu_status_wb_i ), + .align_status_wb_i ( align_status_wb_i ), .data_stall_wb_i ( data_stall_wb_i ), .wb_ready_i ( wb_ready_i ), .wb_valid_i ( wb_valid_i ), diff --git a/rtl/cv32e40x_controller_fsm.sv b/rtl/cv32e40x_controller_fsm.sv index 0631159d..8ac0676c 100644 --- a/rtl/cv32e40x_controller_fsm.sv +++ b/rtl/cv32e40x_controller_fsm.sv @@ -67,12 +67,13 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; input logic last_op_ex_i, // EX stage contains the last operation of an instruction // From WB stage - input ex_wb_pipe_t ex_wb_pipe_i, - input logic [1:0] lsu_err_wb_i, // LSU caused bus_error in WB stage, gated with data_rvalid_i inside load_store_unit - input logic last_op_wb_i, // WB stage contains the last operation of an instruction - input logic abort_op_wb_i, // WB stage contains an (to be) aborted instruction or sequence - input mpu_status_e mpu_status_wb_i, // MPU status (WB timing) - input logic wpt_match_wb_i, // LSU watchpoint trigger (WB) + input ex_wb_pipe_t ex_wb_pipe_i, + input logic [1:0] lsu_err_wb_i, // LSU caused bus_error in WB stage, gated with data_rvalid_i inside load_store_unit + input logic last_op_wb_i, // WB stage contains the last operation of an instruction + input logic abort_op_wb_i, // WB stage contains an (to be) aborted instruction or sequence + input mpu_status_e mpu_status_wb_i, // MPU status (WB timing) + input align_status_e align_status_wb_i, // Aligned status (atomics) in WB + input logic wpt_match_wb_i, // LSU watchpoint trigger (WB) // From LSU (WB) @@ -342,12 +343,13 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; (ex_wb_pipe_i.sys_en && ex_wb_pipe_i.sys_ecall_insn) || (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) || - (mpu_status_wb_i != MPU_OK)) && ex_wb_pipe_i.instr_valid; + (mpu_status_wb_i != MPU_OK) || + (align_status_wb_i != ALIGN_OK)) && ex_wb_pipe_i.instr_valid; 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 : + assign exception_cause_wb = (ex_wb_pipe_i.instr.mpu_status != MPU_OK) ? EXC_CAUSE_INSTR_FAULT : // todo: add code from align_check in IF 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 : @@ -355,7 +357,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; !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 : + (align_status_wb_i == ALIGN_WR_ERR) ? EXC_CAUSE_STORE_MISALIGNED : EXC_CAUSE_LOAD_MISALIGNED; assign ctrl_fsm_o.exception_cause_wb = exception_cause_wb; @@ -1021,7 +1023,7 @@ module cv32e40x_controller_fsm import cv32e40x_pkg::*; end end else if (clic_ptr_in_id || mret_ptr_in_id) begin // todo e40s: Factor in integrity related errors - if (!(if_id_pipe_i.instr.bus_resp.err || (if_id_pipe_i.instr.mpu_status != MPU_OK))) begin + if (!(if_id_pipe_i.instr.bus_resp.err || (if_id_pipe_i.instr.mpu_status != MPU_OK))) begin // todo: add check for alignment check in IF (mret pointer) if (!branch_taken_q) begin ctrl_fsm_o.pc_set = 1'b1; ctrl_fsm_o.pc_mux = PC_POINTER; diff --git a/rtl/cv32e40x_core.sv b/rtl/cv32e40x_core.sv index faceb961..978ba977 100644 --- a/rtl/cv32e40x_core.sv +++ b/rtl/cv32e40x_core.sv @@ -259,6 +259,7 @@ module cv32e40x_core import cv32e40x_pkg::*; lsu_atomic_e lsu_atomic_ex; mpu_status_e lsu_mpu_status_wb; logic lsu_wpt_match_wb; + align_status_e lsu_align_status_wb; logic [31:0] lsu_rdata_wb; logic [1:0] lsu_err_wb; lsu_atomic_e lsu_atomic_wb; @@ -282,6 +283,7 @@ module cv32e40x_core import cv32e40x_pkg::*; logic wpt_match_wb; // Sticky wpt_match from WB stage mpu_status_e mpu_status_wb; // Sticky mpu_status from WB stage + align_status_e align_status_wb; // Sticky align_status from WB stage // Stage ready signals logic id_ready; @@ -701,6 +703,7 @@ module cv32e40x_core import cv32e40x_pkg::*; .lsu_rdata_1_o ( lsu_rdata_wb ), .lsu_mpu_status_1_o ( lsu_mpu_status_wb ), .lsu_wpt_match_1_o ( lsu_wpt_match_wb ), + .lsu_align_status_1_o ( lsu_align_status_wb), .lsu_atomic_1_o ( lsu_atomic_wb ), // Valid/ready @@ -742,6 +745,7 @@ module cv32e40x_core import cv32e40x_pkg::*; .lsu_rdata_i ( lsu_rdata_wb ), .lsu_mpu_status_i ( lsu_mpu_status_wb ), .lsu_wpt_match_i ( lsu_wpt_match_wb ), + .lsu_align_status_i ( lsu_align_status_wb ), // Write back to register file .rf_we_wb_o ( rf_we_wb ), @@ -765,6 +769,7 @@ module cv32e40x_core import cv32e40x_pkg::*; .wpt_match_wb_o ( wpt_match_wb ), .mpu_status_wb_o ( mpu_status_wb ), + .align_status_wb_o ( align_status_wb ), // CSR/CLIC pointer inputs .clic_pa_valid_i ( csr_clic_pa_valid ), @@ -912,6 +917,7 @@ module cv32e40x_core import cv32e40x_pkg::*; .ex_wb_pipe_i ( ex_wb_pipe ), .mpu_status_wb_i ( mpu_status_wb ), .wpt_match_wb_i ( wpt_match_wb ), + .align_status_wb_i ( align_status_wb ), // last_op bits .last_op_id_i ( last_op_id ), diff --git a/rtl/cv32e40x_if_stage.sv b/rtl/cv32e40x_if_stage.sv index 06a3206e..d342e4d4 100644 --- a/rtl/cv32e40x_if_stage.sv +++ b/rtl/cv32e40x_if_stage.sv @@ -128,6 +128,12 @@ module cv32e40x_if_stage import cv32e40x_pkg::*; obi_inst_req_t bus_trans; obi_inst_req_t core_trans; + logic alcheck_resp_valid; + inst_resp_t alcheck_resp; + logic alcheck_trans_valid; + logic alcheck_trans_ready; + obi_inst_req_t alcheck_trans; + // Local instr_valid logic instr_valid; @@ -234,7 +240,7 @@ module cv32e40x_if_stage import cv32e40x_pkg::*; .A_EXT ( A_EXT ), .CORE_REQ_TYPE ( obi_inst_req_t ), .CORE_RESP_TYPE ( inst_resp_t ), - .BUS_RESP_TYPE ( obi_inst_resp_t ), + .BUS_RESP_TYPE ( inst_resp_t ), .PMA_NUM_REGIONS ( PMA_NUM_REGIONS ), .PMA_CFG ( PMA_CFG ), .DEBUG ( DEBUG ), @@ -260,11 +266,44 @@ module cv32e40x_if_stage import cv32e40x_pkg::*; .core_resp_valid_o ( prefetch_resp_valid ), .core_resp_o ( prefetch_inst_resp ), - .bus_trans_valid_o ( bus_trans_valid ), - .bus_trans_ready_i ( bus_trans_ready ), - .bus_trans_o ( bus_trans ), - .bus_resp_valid_i ( bus_resp_valid ), - .bus_resp_i ( bus_resp ) + .bus_trans_valid_o ( alcheck_trans_valid ), + .bus_trans_ready_i ( alcheck_trans_ready ), + .bus_trans_o ( alcheck_trans ), + .bus_resp_valid_i ( alcheck_resp_valid ), + .bus_resp_i ( alcheck_resp ) + ); + + + cv32e40x_align_check + #( + .IF_STAGE ( 1 ), + .CORE_RESP_TYPE ( inst_resp_t ), + .BUS_RESP_TYPE ( obi_inst_resp_t ), + .CORE_REQ_TYPE ( obi_inst_req_t ) + ) + align_check_i + ( + .clk ( clk ), + .rst_n ( rst_n ), + .align_check_en_i ( 1'b0 ), // todo: enable check for pointers + .misaligned_access_i ( 1'b0 ), + + .core_one_txn_pend_n ( prefetch_one_txn_pend_n ), + .core_align_err_wait_i( 1'b1 ), + .core_align_err_o ( ), // Unconnected on purpose + + .core_trans_valid_i ( alcheck_trans_valid ), + .core_trans_ready_o ( alcheck_trans_ready ), + .core_trans_i ( alcheck_trans ), + .core_resp_valid_o ( alcheck_resp_valid ), + .core_resp_o ( alcheck_resp ), + + .bus_trans_valid_o ( bus_trans_valid ), + .bus_trans_ready_i ( bus_trans_ready ), + .bus_trans_o ( bus_trans ), + .bus_resp_valid_i ( bus_resp_valid ), + .bus_resp_i ( bus_resp ) + ); ////////////////////////////////////////////////////////////////////////////// diff --git a/rtl/cv32e40x_load_store_unit.sv b/rtl/cv32e40x_load_store_unit.sv index fc40f745..ca4d7346 100644 --- a/rtl/cv32e40x_load_store_unit.sv +++ b/rtl/cv32e40x_load_store_unit.sv @@ -74,6 +74,7 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; output logic [31:0] lsu_rdata_1_o, // LSU read data output mpu_status_e lsu_mpu_status_1_o, // MPU (PMA) status, response/WB timing. To controller and wb_stage output logic lsu_wpt_match_1_o, // Address match trigger, WB timing. + output align_status_e lsu_align_status_1_o, // Alignment status (for atomics), WB timing output lsu_atomic_e lsu_atomic_1_o, // Is there an atomic in WB, and of which type. // Handshakes @@ -105,6 +106,12 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; logic wpt_trans_pushpop; obi_data_req_t wpt_trans; + // Align_check transaction request (to cv32e40x_align_check) + logic alcheck_trans_valid; + logic alcheck_trans_ready; + logic alcheck_trans_pushpop; + obi_data_req_t alcheck_trans; + // Transaction request to cv32e40x_mpu logic mpu_trans_valid; logic mpu_trans_ready; @@ -122,6 +129,11 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; logic [31:0] wpt_resp_rdata; data_resp_t wpt_resp; + // Transaction response interface (from cv32e40x_align_check) + logic alcheck_resp_valid; + logic [31:0] alcheck_resp_rdata; + data_resp_t alcheck_resp; + // Transaction response interface (from cv32e40x_mpu) logic mpu_resp_valid; data_resp_t mpu_resp; @@ -187,6 +199,11 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; logic xif_res_q; // The next memory result is for the XIF interface logic [X_ID_WIDTH-1:0] xif_id_q; // Instruction ID of an XIF memory transaction + logic align_check_en; // Perform alignment checks for atomics + + logic consumer_resp_wait; // Signal to WPT, MPU and alignment checker if they must wait with + // the response until there is one transaction left; + assign xif_req = X_EXT && xif_mem_if.mem_valid; // Transaction (before aligner) @@ -580,8 +597,9 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; end endgenerate - // Export mpu status to WB stage/controller - assign lsu_mpu_status_1_o = resp.mpu_status; + // Export mpu status and align check status to WB stage/controller + assign lsu_mpu_status_1_o = resp.mpu_status; + assign lsu_align_status_1_o = resp.align_status; // Update signals for EX/WB registers (when EX has valid data itself and is ready for next) assign ctrl_update = done_0 && (valid_0_i || xif_req); @@ -684,6 +702,7 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; ////////////////////////////////////////////////////////////////////////////// // WPT ////////////////////////////////////////////////////////////////////////////// + assign consumer_resp_wait = !xif_req; // Watchpint trigger "gate". If a watchpoint trigger is detected, this module will // consume the transaction, not letting it through to the MPU. The triger match will @@ -698,7 +717,7 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; // Input from debug_triggers module .trigger_match_i ( trigger_match_0_i ), - // Interface towards mpu interface + // Interface towards MPU .mpu_trans_ready_i ( mpu_trans_ready ), .mpu_trans_valid_o ( mpu_trans_valid ), .mpu_trans_pushpop_o ( mpu_trans_pushpop ), @@ -721,7 +740,7 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; // Indication from the core that watchpoint triggers should be reported after all in flight transactions // are complete (default behavior for main core requests, but not used for XIF requests) - .core_wpt_wait_i ( !xif_req ), + .core_wpt_wait_i ( consumer_resp_wait), // Report watchpoint triggers to the core immediatly (used in case core_wpt_wait_i is not asserted) .core_wpt_match_o ( xif_wpt_match ) @@ -754,6 +773,8 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; assign resp = wpt_resp; end endgenerate + + ////////////////////////////////////////////////////////////////////////////// // MPU ////////////////////////////////////////////////////////////////////////////// @@ -764,7 +785,7 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; .IF_STAGE ( 0 ), .A_EXT ( A_EXT ), .CORE_RESP_TYPE ( data_resp_t ), - .BUS_RESP_TYPE ( obi_data_resp_t ), + .BUS_RESP_TYPE ( data_resp_t ), .CORE_REQ_TYPE ( obi_data_req_t ), .PMA_NUM_REGIONS ( PMA_NUM_REGIONS ), .PMA_CFG ( PMA_CFG ), @@ -780,7 +801,7 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; .misaligned_access_i ( misaligned_access ), .core_one_txn_pend_n ( cnt_is_one_next ), - .core_mpu_err_wait_i ( !xif_req ), + .core_mpu_err_wait_i ( consumer_resp_wait ), .core_mpu_err_o ( xif_mpu_err ), .core_trans_valid_i ( mpu_trans_valid ), .core_trans_pushpop_i ( mpu_trans_pushpop ), @@ -789,11 +810,50 @@ module cv32e40x_load_store_unit import cv32e40x_pkg::*; .core_resp_valid_o ( mpu_resp_valid ), .core_resp_o ( mpu_resp ), - .bus_trans_valid_o ( filter_trans_valid ), - .bus_trans_ready_i ( filter_trans_ready ), - .bus_trans_o ( filter_trans ), - .bus_resp_valid_i ( filter_resp_valid ), - .bus_resp_i ( filter_resp ) + .bus_trans_valid_o ( alcheck_trans_valid ), + .bus_trans_ready_i ( alcheck_trans_ready ), + .bus_trans_o ( alcheck_trans ), + .bus_resp_valid_i ( alcheck_resp_valid ), + .bus_resp_i ( alcheck_resp ) + + ); + + ////////////////////////////////////////////////////////////////////////////// + // Alignment checker for atomics + ////////////////////////////////////////////////////////////////////////////// + assign align_check_en = alcheck_trans.atop[5]; + + cv32e40x_align_check + #( + .IF_STAGE ( 0 ), + .CORE_RESP_TYPE ( data_resp_t ), + .BUS_RESP_TYPE ( obi_data_resp_t ), + .CORE_REQ_TYPE ( obi_data_req_t ) + + ) + align_check_i + ( + .clk ( clk ), + .rst_n ( rst_n ), + .align_check_en_i ( align_check_en ), + .misaligned_access_i ( misaligned_access ), + + .core_one_txn_pend_n ( cnt_is_one_next ), + .core_align_err_wait_i( consumer_resp_wait ), + .core_align_err_o ( ), // todo: Unconnected on purpose, is this needed for xif? + + .core_trans_valid_i ( alcheck_trans_valid ), + .core_trans_ready_o ( alcheck_trans_ready ), + .core_trans_i ( alcheck_trans ), + .core_resp_valid_o ( alcheck_resp_valid ), + .core_resp_o ( alcheck_resp ), + + .bus_trans_valid_o ( filter_trans_valid ), + .bus_trans_ready_i ( filter_trans_ready ), + .bus_trans_o ( filter_trans ), + .bus_resp_valid_i ( filter_resp_valid ), + .bus_resp_i ( filter_resp ) + ); diff --git a/rtl/cv32e40x_mpu.sv b/rtl/cv32e40x_mpu.sv index 58fa4a82..22c3cc1a 100644 --- a/rtl/cv32e40x_mpu.sv +++ b/rtl/cv32e40x_mpu.sv @@ -28,7 +28,7 @@ module cv32e40x_mpu import cv32e40x_pkg::*; parameter a_ext_e A_EXT = A_NONE, parameter type CORE_REQ_TYPE = obi_inst_req_t, parameter type CORE_RESP_TYPE = inst_resp_t, - parameter type BUS_RESP_TYPE = obi_inst_resp_t, + parameter type BUS_RESP_TYPE = data_resp_t, parameter int PMA_NUM_REGIONS = 0, parameter pma_cfg_t PMA_CFG[PMA_NUM_REGIONS-1:0] = '{default:PMA_R_DEFAULT}, parameter int DEBUG = 1, @@ -70,7 +70,6 @@ module cv32e40x_mpu import cv32e40x_pkg::*; ); logic pma_err; - logic pma_misaligned_atomic; logic mpu_err; logic mpu_block_core; logic mpu_block_bus; @@ -119,36 +118,27 @@ module cv32e40x_mpu import cv32e40x_pkg::*; if (core_mpu_err_wait_i) begin if(core_trans_we) begin // MPU error on write - // 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); + state_n = core_one_txn_pend_n ? MPU_WR_ERR_RESP : MPU_WR_ERR_WAIT; end else begin // MPU error on read - // 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); + state_n = core_one_txn_pend_n ? MPU_RE_ERR_RESP : MPU_RE_ERR_WAIT; end end end end - MPU_RE_ERR_WAIT, MPU_WR_ERR_WAIT, - MPU_RE_MISALIGN_WAIT, MPU_WR_MISALIGN_WAIT: begin + MPU_RE_ERR_WAIT, MPU_WR_ERR_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 : - (state_q == MPU_WR_ERR_WAIT) ? MPU_WR_ERR_RESP : - (state_q == MPU_RE_MISALIGN_WAIT) ? MPU_RE_MISALIGN_RESP : - MPU_WR_MISALIGN_RESP; + state_n = (state_q == MPU_RE_ERR_WAIT) ? MPU_RE_ERR_RESP : MPU_WR_ERR_RESP; end end - MPU_RE_ERR_RESP, MPU_WR_ERR_RESP, - MPU_RE_MISALIGN_RESP, MPU_WR_MISALIGN_RESP: begin + MPU_RE_ERR_RESP, MPU_WR_ERR_RESP: begin // Keep blocking new transfers mpu_block_bus = 1'b1; @@ -156,11 +146,7 @@ module cv32e40x_mpu import cv32e40x_pkg::*; // 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 : - (state_q == MPU_WR_ERR_RESP) ? MPU_WR_FAULT : - (state_q == MPU_RE_MISALIGN_RESP) ? MPU_RE_MISALIGNED : - MPU_WR_MISALIGNED; - + mpu_status = (state_q == MPU_RE_ERR_RESP) ? MPU_RE_FAULT : MPU_WR_FAULT; // Go back to IDLE uncoditionally. // The core is expected to always be ready for the response state_n = MPU_IDLE; @@ -190,10 +176,11 @@ module cv32e40x_mpu import cv32e40x_pkg::*; // Forward transaction response towards core assign core_resp_valid_o = bus_resp_valid_i || mpu_err_trans_valid; - assign core_resp_o.bus_resp = bus_resp_i; + assign core_resp_o.bus_resp = bus_resp_i.bus_resp; assign core_resp_o.mpu_status = mpu_status; + assign core_resp_o.align_status = bus_resp_i.align_status; - // Report MPU errors to the core immediatly + // Report MPU errors to the core immediately assign core_mpu_err_o = mpu_err; // Signal ready towards core @@ -216,12 +203,11 @@ 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 || pma_misaligned_atomic; + assign mpu_err = pma_err; // Writes are only supported on the data interface // Tie to 1'b0 if this MPU is instantiatied in the IF stage diff --git a/rtl/cv32e40x_pma.sv b/rtl/cv32e40x_pma.sv index 0473a39f..a5a501b4 100644 --- a/rtl/cv32e40x_pma.sv +++ b/rtl/cv32e40x_pma.sv @@ -38,7 +38,6 @@ 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 ); @@ -103,15 +102,9 @@ 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 diff --git a/rtl/cv32e40x_wb_stage.sv b/rtl/cv32e40x_wb_stage.sv index d932a763..ece5f97f 100644 --- a/rtl/cv32e40x_wb_stage.sv +++ b/rtl/cv32e40x_wb_stage.sv @@ -52,6 +52,7 @@ module cv32e40x_wb_stage import cv32e40x_pkg::*; input logic [31:0] lsu_rdata_i, input mpu_status_e lsu_mpu_status_i, input logic lsu_wpt_match_i, + input align_status_e lsu_align_status_i, // Register file interface output logic rf_we_wb_o, // Register file write enable @@ -77,6 +78,7 @@ module cv32e40x_wb_stage import cv32e40x_pkg::*; // Sticky WB outputs output logic wpt_match_wb_o, output mpu_status_e mpu_status_wb_o, + output align_status_e align_status_wb_o, // From cs_registers input logic [31:0] clic_pa_i, @@ -97,16 +99,18 @@ module cv32e40x_wb_stage import cv32e40x_pkg::*; // Flops for making volatile LSU outputs sticky until wb_valid mpu_status_e lsu_mpu_status_q; logic lsu_wpt_match_q; + align_status_e lsu_align_status_q; logic lsu_valid_q; mpu_status_e lsu_mpu_status; logic lsu_wpt_match; + align_status_e lsu_align_status; logic lsu_valid; // WB stage has two halt sources, ctrl_fsm_i.halt_wb and ctrl_fsm_i.halt_limited_wb. The limited halt is only set during // the SLEEP state, and is used to prevent timing paths from interrupt inputs to obi outputs when waking up from SLEEP. assign instr_valid = ex_wb_pipe_i.instr_valid && !ctrl_fsm_i.kill_wb && !ctrl_fsm_i.halt_wb && !ctrl_fsm_i.halt_limited_wb; - assign lsu_exception = (lsu_mpu_status != MPU_OK); + assign lsu_exception = (lsu_mpu_status != MPU_OK) || (lsu_align_status != ALIGN_OK); ////////////////////////////////////////////////////////////////////////////// @@ -185,28 +189,33 @@ module cv32e40x_wb_stage import cv32e40x_pkg::*; lsu_valid_q <= 1'b0; lsu_wpt_match_q <= 1'b0; lsu_mpu_status_q <= MPU_OK; + lsu_align_status_q <= ALIGN_OK; end else begin if (wb_valid || ctrl_fsm_i.kill_wb) begin // Clear sticky LSU bits when WB is done lsu_valid_q <= 1'b0; lsu_wpt_match_q <= 1'b0; lsu_mpu_status_q <= MPU_OK; + lsu_align_status_q <= ALIGN_OK; end else begin if (lsu_valid_i) begin lsu_valid_q <= 1'b1; lsu_wpt_match_q <= lsu_wpt_match; lsu_mpu_status_q <= lsu_mpu_status; + lsu_align_status_q <= lsu_align_status; end end end end - assign lsu_valid = lsu_valid_q ? lsu_valid_q : lsu_valid_i; - assign lsu_wpt_match = lsu_valid_q ? lsu_wpt_match_q : lsu_wpt_match_i; - assign lsu_mpu_status = lsu_valid_q ? lsu_mpu_status_q : lsu_mpu_status_i; + assign lsu_valid = lsu_valid_q ? lsu_valid_q : lsu_valid_i; + assign lsu_wpt_match = lsu_valid_q ? lsu_wpt_match_q : lsu_wpt_match_i; + assign lsu_mpu_status = lsu_valid_q ? lsu_mpu_status_q : lsu_mpu_status_i; + assign lsu_align_status = lsu_valid_q ? lsu_align_status_q : lsu_align_status_i; assign wpt_match_wb_o = lsu_wpt_match; assign mpu_status_wb_o = lsu_mpu_status; + assign align_status_wb_o = lsu_align_status; //--------------------------------------------------------------------------- // eXtension interface //--------------------------------------------------------------------------- diff --git a/rtl/cv32e40x_wpt.sv b/rtl/cv32e40x_wpt.sv index bd7594f9..2b067491 100644 --- a/rtl/cv32e40x_wpt.sv +++ b/rtl/cv32e40x_wpt.sv @@ -150,17 +150,18 @@ module cv32e40x_wpt import cv32e40x_pkg::*; // Forward transaction response towards core - assign core_resp_valid_o = mpu_resp_valid_i || wpt_trans_valid; - assign core_resp_o.bus_resp = mpu_resp_i.bus_resp; - assign core_resp_o.mpu_status = mpu_resp_i.mpu_status; - assign core_resp_o.wpt_match = wpt_match; + assign core_resp_valid_o = mpu_resp_valid_i || wpt_trans_valid; + assign core_resp_o.bus_resp = mpu_resp_i.bus_resp; + assign core_resp_o.mpu_status = mpu_resp_i.mpu_status; + assign core_resp_o.align_status = mpu_resp_i.align_status; + assign core_resp_o.wpt_match = wpt_match; - // Report WPT matches to the core immediatly + // Report WPT matches to the core immediately assign core_wpt_match_o = trigger_match_i; // Signal ready towards core - assign core_trans_ready_o = (mpu_trans_ready_i && !wpt_block_core) || wpt_trans_ready; + assign core_trans_ready_o = (mpu_trans_ready_i && !wpt_block_core) || wpt_trans_ready; diff --git a/rtl/include/cv32e40x_pkg.sv b/rtl/include/cv32e40x_pkg.sv index 8263dedb..9bfca2d1 100644 --- a/rtl/include/cv32e40x_pkg.sv +++ b/rtl/include/cv32e40x_pkg.sv @@ -901,6 +901,7 @@ typedef enum logic[3:0] { } pc_mux_e; // Exception Cause +parameter EXC_CAUSE_INSTR_MISALIGNED = 11'h00; parameter EXC_CAUSE_INSTR_FAULT = 11'h01; parameter EXC_CAUSE_ILLEGAL_INSN = 11'h02; parameter EXC_CAUSE_BREAKPOINT = 11'h03; @@ -965,16 +966,23 @@ parameter pma_cfg_t PMA_R_DEFAULT = '{word_addr_low : 0, atomic : 1'b0}; // MPU status. Used for PMA -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 +typedef enum logic [1:0] { + MPU_OK = 2'h0, + MPU_RE_FAULT = 2'h1, + MPU_WR_FAULT = 2'h2 } mpu_status_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; + +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; + +// ALIGN status. Used when checking alignment for atomics and mret pointers +typedef enum logic [1:0] { + ALIGN_OK = 2'h0, + ALIGN_RE_ERR = 2'h1, + ALIGN_WR_ERR = 2'h2 + } align_status_e; + +typedef enum logic [2:0] {ALIGN_IDLE, ALIGN_WR_ERR_RESP, ALIGN_WR_ERR_WAIT, ALIGN_RE_ERR_RESP, ALIGN_RE_ERR_WAIT} align_state_e; // WPT state machine typedef enum logic [1:0] {WPT_IDLE, WPT_MATCH_WAIT, WPT_MATCH_RESP} wpt_state_e; @@ -1031,14 +1039,17 @@ typedef struct packed { typedef struct packed { obi_inst_resp_t bus_resp; mpu_status_e mpu_status; + align_status_e align_status; // Alignment status (for mret pointers) } inst_resp_t; // Reset value for the inst_resp_t type parameter inst_resp_t INST_RESP_RESET_VAL = '{ // Setting rdata[1:0] to 2'b11 to easily assert that all // instructions in ID are uncompressed - bus_resp : '{rdata: 32'h3, err: 1'b0}, - mpu_status : MPU_OK + bus_resp : '{rdata: 32'h3, err: 1'b0}, + mpu_status : MPU_OK, + align_status : ALIGN_OK + }; // Reset value for the obi_inst_req_t type @@ -1054,6 +1065,7 @@ typedef struct packed { obi_data_resp_t bus_resp; mpu_status_e mpu_status; logic wpt_match; + align_status_e align_status; } data_resp_t; // LSU transaction diff --git a/sva/cv32e40x_controller_fsm_sva.sv b/sva/cv32e40x_controller_fsm_sva.sv index 920d3a87..e9beeae3 100644 --- a/sva/cv32e40x_controller_fsm_sva.sv +++ b/sva/cv32e40x_controller_fsm_sva.sv @@ -632,6 +632,16 @@ if (CLIC) begin $stable(mintstatus_i)) else `uvm_error("controller", "mintstatus changed after taking an NMI") + // The only possible cause for a instruction misaligned exception is an mret pointer. + a_mret_ptr_exception: + assert property (@(posedge clk) disable iff (!rst_n) + (exception_cause_wb == EXC_CAUSE_INSTR_MISALIGNED) && + exception_in_wb + |-> + mret_ptr_in_wb) + + else `uvm_error("controller", "Instruction address misaligned exception without mret pointer.") + end else begin // CLIC // Check that CLIC related signals are inactive when CLIC is not configured. a_clic_inactive: diff --git a/sva/cv32e40x_if_stage_sva.sv b/sva/cv32e40x_if_stage_sva.sv index f6f15db9..1bf285b9 100644 --- a/sva/cv32e40x_if_stage_sva.sv +++ b/sva/cv32e40x_if_stage_sva.sv @@ -40,7 +40,9 @@ module cv32e40x_if_stage_sva input logic instr_compressed, input logic prefetch_is_tbljmp_ptr, input logic prefetch_is_clic_ptr, - input logic prefetch_is_mret_ptr + input logic prefetch_is_mret_ptr, + input logic [31:0] branch_addr_n, + input logic align_err_i ); // Check that bus interface transactions are halfword aligned (will be forced word aligned at core boundary) @@ -95,6 +97,48 @@ module cv32e40x_if_stage_sva |-> prefetch_is_mret_ptr != prefetch_is_clic_ptr) else `uvm_error("if_stage", "prefetch_is_mret_ptr high at the same time as prefetch_is_clic_ptr.") + + a_aligned_clic_ptr: + assert property (@(posedge clk) disable iff (!rst_n) + (ctrl_fsm_i.pc_set_clicv) && + (ctrl_fsm_i.pc_mux == PC_TRAP_CLICV) + |-> + (branch_addr_n[1:0] == 2'b00)) + else `uvm_error("if_stage", "Misaligned CLIC pointer") + + a_aligned_mret_ptr: + assert property (@(posedge clk) disable iff (!rst_n) + (ctrl_fsm_i.pc_set_clicv) && + (ctrl_fsm_i.pc_mux == PC_MRET) && + (branch_addr_n[1:0] == 2'b00) + |-> + align_err_i + ) + else `uvm_error("if_stage", "Misaligned mret pointer not flagged with error") + + // Aligned errors may only happen for mret pointers + a_aligned_err_mret_ptr: + assert property (@(posedge clk) disable iff (!rst_n) + align_err_i + |-> + (ctrl_fsm_i.pc_set_clicv) && + (ctrl_fsm_i.pc_mux == PC_MRET)) + else `uvm_error("if_stage", "Alignment error withouth mret pointer") + end else begin + + // Without CLIC support there shall never be an aligned error in the IF stage. + a_no_align_err: + assert property (@(posedge clk) disable iff (!rst_n) + !align_err_i) + else `uvm_error("if_stage", "Alignment error withouth CLIC support.") end + + a_aligned_tbljmp_ptr: + assert property (@(posedge clk) disable iff (!rst_n) + (ctrl_fsm_i.pc_set) && + (ctrl_fsm_i.pc_mux == PC_TBLJUMP) + |-> + (branch_addr_n[1:0] == 2'b00)) + else `uvm_error("if_stage", "Misaligned tablejump pointer") endmodule // cv32e40x_if_stage diff --git a/sva/cv32e40x_load_store_unit_sva.sv b/sva/cv32e40x_load_store_unit_sva.sv index 1ae87748..ba95aeb2 100644 --- a/sva/cv32e40x_load_store_unit_sva.sv +++ b/sva/cv32e40x_load_store_unit_sva.sv @@ -41,6 +41,7 @@ module cv32e40x_load_store_unit_sva input write_buffer_state_e write_buffer_state_i, input logic split_q, input mpu_status_e lsu_mpu_status_1_o, // WB mpu status + input align_status_e lsu_align_status_1_o, input ex_wb_pipe_t ex_wb_pipe_i, if_c_obi.monitor m_c_obi_data_if, input logic xif_req, @@ -53,10 +54,10 @@ module cv32e40x_load_store_unit_sva input logic ready_0_i, input logic trigger_match_0_i, input logic lsu_wpt_match_1_o, - input lsu_atomic_e lsu_atomic_0_o, - input logic mpu_err, - input logic mpu_block_bus, - input logic mpu_trans_valid + input trans_req_t trans, + input logic bus_trans_valid, + input logic mpu_err_i, + input logic align_err_i ); // Check that outstanding transaction count will not overflow DEPTH @@ -128,10 +129,10 @@ module cv32e40x_load_store_unit_sva // Second half of a split transaction should never get killed while in EX // Exception: Second half of a split transaction may be killed if the first half - // gets blocked by the PMA. + // gets blocked by the PMA or alignment checker. a_lsu_no_kill_second_half_ex: assert property (@(posedge clk) disable iff (!rst_n) - (split_q && (lsu_mpu_status_1_o == MPU_OK)) |-> !ctrl_fsm_i.kill_ex) + (split_q && (lsu_mpu_status_1_o == MPU_OK) && (lsu_align_status_1_o == ALIGN_OK)) |-> !ctrl_fsm_i.kill_ex) else `uvm_error("load_store_unit", "Second half of split transaction was killed") // cnt_q == 2'b00 shall be the same as !(ex_wb_pipe.lsu_en && ex_wb_pipe_i.instr_valid) @@ -243,15 +244,16 @@ if (DEBUG) begin end if (A_EXT != A_NONE) begin - // Check that misaligned atomics never reach the bus but get blocked by the MPU - a_a_never_split: + // Check that misaligned atomics never reach the bus but get blocked by the alignment checker + a_misaligned_atomic_err: assert property (@(posedge clk) disable iff (!rst_n) - (lsu_atomic_0_o != AT_NONE) && // Atomic instruction in first part of LSU (EX) - lsu_split_0_o && // LSU wants to split due to misalignment - mpu_trans_valid // Transaction not blocked by WPT + trans_valid && // Active transfer + (trans.atop[5] && (trans.addr[1:0] != 2'b00)) && // Misaligned atomic + !mpu_err_i // Not blocked by MPU |-> - mpu_err && mpu_block_bus) // MPU must block the bus and flag error - else `uvm_error("load_store_unit", "Misaligned atomic not blocked by MPU.") + lsu_split_0_o && + align_err_i && !bus_trans_valid) + else `uvm_error("load_store_unit", "Misaligned atomic not blocked by alignment checker") end endmodule // cv32e40x_load_store_unit_sva diff --git a/sva/cv32e40x_mpu_sva.sv b/sva/cv32e40x_mpu_sva.sv index c98f4194..fefeee06 100644 --- a/sva/cv32e40x_mpu_sva.sv +++ b/sva/cv32e40x_mpu_sva.sv @@ -82,8 +82,7 @@ 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 pma_misaligned_atomic + input logic load_access ); // PMA assertions helper signals @@ -266,9 +265,6 @@ module cv32e40x_mpu_sva import cv32e40x_pkg::*; import uvm_pkg::*; 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 @@ -438,17 +434,6 @@ if (A_EXT != A_NONE) begin else `uvm_error("mpu", "Wrong attributes for non-atomic access to DM during debug mode") end // DEBUG - // All atomic operations must be naturally aligned - // CV32E40X only support 32-bit accesses, and thus all atomics must be 4-byte aligned. - a_atomic_word_align: - assert property (@(posedge clk) disable iff (!rst_n) - core_trans_valid_i && - atomic_access_i && - !pma_misaligned_atomic - |-> - (core_trans_i.addr[1:0] == 2'b00)) - else `uvm_error("mpu", "Misaligned atomic instruction not flagged with error") - end if (DEBUG) begin