Skip to content

Commit

Permalink
Moved check for misaligned atomics out of MPU and into a separate mod…
Browse files Browse the repository at this point in the history
…ule. This module is also used in IF, where the intention is to block misaligned mret pointers.

SEC clean.

Signed-off-by: Oystein Knauserud <Oystein.Knauserud@silabs.com>
  • Loading branch information
silabs-oysteink committed Mar 17, 2023
1 parent b22444c commit 3438fdb
Show file tree
Hide file tree
Showing 14 changed files with 390 additions and 77 deletions.
1 change: 1 addition & 0 deletions cv32e40x_manifest.flist
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
185 changes: 185 additions & 0 deletions rtl/cv32e40x_align_check.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// 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 mpu interface
input logic mpu_trans_ready_i,
output logic mpu_trans_valid_o,
output logic mpu_trans_pushpop_o,
output CORE_REQ_TYPE mpu_trans_o,

input logic mpu_resp_valid_i,
input BUS_RESP_TYPE mpu_resp_i,

// Interface towards core
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 watchpoint triggers 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 watchpoint triggers 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 mpu_trans_valid_o = core_trans_valid_i && !align_block_bus;
assign mpu_trans_o = core_trans_i;
assign mpu_trans_pushpop_o = core_trans_pushpop_i;


// Forward transaction response towards core
assign core_resp_valid_o = mpu_resp_valid_i || align_trans_valid;
assign core_resp_o.bus_resp = mpu_resp_i;
assign core_resp_o.align_status = align_status;

// Detect alignment error
assign align_err = align_check_en_i && misaligned_access_i;

// Report align matches to the core immediatly
assign core_align_err_o = align_err;

// Signal ready towards core
assign core_trans_ready_o = (mpu_trans_ready_i && !align_block_core) || align_trans_ready;

generate
if (IF_STAGE) begin: mpu_if
assign core_trans_we = 1'b0;
end
else begin: mpu_lsu
assign core_trans_we = core_trans_i.we;
end
endgenerate

endmodule
2 changes: 2 additions & 0 deletions rtl/cv32e40x_controller.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 ),
Expand Down
24 changes: 13 additions & 11 deletions rtl/cv32e40x_controller_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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 and mret pointers) in WB
input logic wpt_match_wb_i, // LSU watchpoint trigger (WB)


// From LSU (WB)
Expand Down Expand Up @@ -342,21 +343,22 @@ 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_shim 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 :
(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 :
(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;
(align_status_wb_i == ALIGN_WR_ERR) ? EXC_CAUSE_STORE_MISALIGNED :
EXC_CAUSE_LOAD_MISALIGNED; // todo: will come from align_shim

assign ctrl_fsm_o.exception_cause_wb = exception_cause_wb;

Expand Down Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions rtl/cv32e40x_core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 ),
Expand All @@ -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 ),
Expand Down Expand Up @@ -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 ),
Expand Down
51 changes: 45 additions & 6 deletions rtl/cv32e40x_if_stage.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 ),
Expand All @@ -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 ),
.misaligned_access_i ( misaligned_access ),

.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 ),

.mpu_trans_valid_o ( bus_trans_valid ),
.mpu_trans_ready_i ( bus_trans_ready ),
.mpu_trans_o ( bus_trans ),
.mpu_resp_valid_i ( bus_resp_valid ),
.mpu_resp_i ( bus_resp )

);

//////////////////////////////////////////////////////////////////////////////
Expand Down
Loading

0 comments on commit 3438fdb

Please sign in to comment.