// SPDX-License-Identifier: Apache-2.0 // Copyright 2019 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: Checks the memory map for the address // Comments: // //******************************************************************************** module lsu_addrcheck import swerv_types::*; ( input logic lsu_freeze_c2_dc2_clk, // clock input logic lsu_freeze_c2_dc3_clk, input logic lsu_freeze_c2_dc2_clken, input logic lsu_freeze_c2_dc3_clken, input logic rst_l, // reset input logic clk, input logic [31:0] start_addr_dc1, // start address for lsu input logic [31:0] end_addr_dc1, // end address for lsu input lsu_pkt_t lsu_pkt_dc1, // packet in dc1 input logic [31:0] dec_tlu_mrac_ff, // CSR read output logic is_sideeffects_dc2, // is sideffects space output logic is_sideeffects_dc3, output logic addr_in_dccm_dc1, // address in dccm output logic addr_in_pic_dc1, // address in pic output logic addr_external_dc1, // address in external output logic access_fault_dc1, // access fault output logic misaligned_fault_dc1, // misaligned input logic scan_mode ); `include "global.h" localparam DCCM_REGION = `RV_DCCM_REGION; localparam PIC_REGION = `RV_PIC_REGION; localparam ICCM_REGION = `RV_ICCM_REGION; `ifdef RV_ICCM_ENABLE localparam ICCM_ENABLE = 1'b1; `else localparam ICCM_ENABLE = 1'b0; `endif `ifdef RV_DCCM_ENABLE localparam DCCM_ENABLE = 1'b1; `else localparam DCCM_ENABLE = 1'b0; `endif logic is_sideeffects_dc1, is_aligned_dc1; logic start_addr_in_dccm_dc1, end_addr_in_dccm_dc1; logic start_addr_in_dccm_region_dc1, end_addr_in_dccm_region_dc1; logic start_addr_in_pic_dc1, end_addr_in_pic_dc1; logic start_addr_in_pic_region_dc1, end_addr_in_pic_region_dc1; logic [4:0] csr_idx; logic addr_in_iccm; logic non_dccm_access_ok; if (DCCM_ENABLE == 1) begin: Gen_dccm_enable // Start address check rvrangecheck #(.CCM_SADR(`RV_DCCM_SADR), .CCM_SIZE(`RV_DCCM_SIZE)) start_addr_dccm_rangecheck ( .addr(start_addr_dc1[31:0]), .in_range(start_addr_in_dccm_dc1), .in_region(start_addr_in_dccm_region_dc1) ); // End address check rvrangecheck #(.CCM_SADR(`RV_DCCM_SADR), .CCM_SIZE(`RV_DCCM_SIZE)) end_addr_dccm_rangecheck ( .addr(end_addr_dc1[31:0]), .in_range(end_addr_in_dccm_dc1), .in_region(end_addr_in_dccm_region_dc1) ); end else begin: Gen_dccm_disable // block: Gen_dccm_enable assign start_addr_in_dccm_dc1 = '0; assign start_addr_in_dccm_region_dc1 = '0; assign end_addr_in_dccm_dc1 = '0; assign end_addr_in_dccm_region_dc1 = '0; end if (ICCM_ENABLE == 1) begin : check_iccm assign addr_in_iccm = (start_addr_dc1[31:28] == ICCM_REGION); end else begin assign addr_in_iccm = 1'b0; end // PIC memory check // Start address check rvrangecheck #(.CCM_SADR(`RV_PIC_BASE_ADDR), .CCM_SIZE(`RV_PIC_SIZE)) start_addr_pic_rangecheck ( .addr(start_addr_dc1[31:0]), .in_range(start_addr_in_pic_dc1), .in_region(start_addr_in_pic_region_dc1) ); // End address check rvrangecheck #(.CCM_SADR(`RV_PIC_BASE_ADDR), .CCM_SIZE(`RV_PIC_SIZE)) end_addr_pic_rangecheck ( .addr(end_addr_dc1[31:0]), .in_range(end_addr_in_pic_dc1), .in_region(end_addr_in_pic_region_dc1) ); assign addr_in_dccm_dc1 = (start_addr_in_dccm_dc1 & end_addr_in_dccm_dc1); assign addr_in_pic_dc1 = (start_addr_in_pic_dc1 & end_addr_in_pic_dc1); assign addr_external_dc1 = ~(addr_in_dccm_dc1 | addr_in_pic_dc1); //~addr_in_dccm_region_dc1; assign csr_idx[4:0] = {start_addr_dc1[31:28], 1'b1}; assign is_sideeffects_dc1 = dec_tlu_mrac_ff[csr_idx] & ~(start_addr_in_dccm_region_dc1 | start_addr_in_pic_region_dc1 | addr_in_iccm); //every region has the 2 LSB indicating ( 1: sideeffects/no_side effects, and 0: cacheable ). Ignored in internal regions assign is_aligned_dc1 = (lsu_pkt_dc1.word & (start_addr_dc1[1:0] == 2'b0)) | (lsu_pkt_dc1.half & (start_addr_dc1[0] == 1'b0)) | lsu_pkt_dc1.by; assign non_dccm_access_ok = (~(|{`RV_DATA_ACCESS_ENABLE0,`RV_DATA_ACCESS_ENABLE1,`RV_DATA_ACCESS_ENABLE2,`RV_DATA_ACCESS_ENABLE3,`RV_DATA_ACCESS_ENABLE4,`RV_DATA_ACCESS_ENABLE5,`RV_DATA_ACCESS_ENABLE6,`RV_DATA_ACCESS_ENABLE7})) | (((`RV_DATA_ACCESS_ENABLE0 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK0)) == (`RV_DATA_ACCESS_ADDR0 | `RV_DATA_ACCESS_MASK0)) | (`RV_DATA_ACCESS_ENABLE1 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK1)) == (`RV_DATA_ACCESS_ADDR1 | `RV_DATA_ACCESS_MASK1)) | (`RV_DATA_ACCESS_ENABLE2 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK2)) == (`RV_DATA_ACCESS_ADDR2 | `RV_DATA_ACCESS_MASK2)) | (`RV_DATA_ACCESS_ENABLE3 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK3)) == (`RV_DATA_ACCESS_ADDR3 | `RV_DATA_ACCESS_MASK3)) | (`RV_DATA_ACCESS_ENABLE4 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK4)) == (`RV_DATA_ACCESS_ADDR4 | `RV_DATA_ACCESS_MASK4)) | (`RV_DATA_ACCESS_ENABLE5 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK5)) == (`RV_DATA_ACCESS_ADDR5 | `RV_DATA_ACCESS_MASK5)) | (`RV_DATA_ACCESS_ENABLE6 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK6)) == (`RV_DATA_ACCESS_ADDR6 | `RV_DATA_ACCESS_MASK6)) | (`RV_DATA_ACCESS_ENABLE7 & ((start_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK7)) == (`RV_DATA_ACCESS_ADDR7 | `RV_DATA_ACCESS_MASK7))) & ((`RV_DATA_ACCESS_ENABLE0 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK0)) == (`RV_DATA_ACCESS_ADDR0 | `RV_DATA_ACCESS_MASK0)) | (`RV_DATA_ACCESS_ENABLE1 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK1)) == (`RV_DATA_ACCESS_ADDR1 | `RV_DATA_ACCESS_MASK1)) | (`RV_DATA_ACCESS_ENABLE2 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK2)) == (`RV_DATA_ACCESS_ADDR2 | `RV_DATA_ACCESS_MASK2)) | (`RV_DATA_ACCESS_ENABLE3 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK3)) == (`RV_DATA_ACCESS_ADDR3 | `RV_DATA_ACCESS_MASK3)) | (`RV_DATA_ACCESS_ENABLE4 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK4)) == (`RV_DATA_ACCESS_ADDR4 | `RV_DATA_ACCESS_MASK4)) | (`RV_DATA_ACCESS_ENABLE5 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK5)) == (`RV_DATA_ACCESS_ADDR5 | `RV_DATA_ACCESS_MASK5)) | (`RV_DATA_ACCESS_ENABLE6 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK6)) == (`RV_DATA_ACCESS_ADDR6 | `RV_DATA_ACCESS_MASK6)) | (`RV_DATA_ACCESS_ENABLE7 & ((end_addr_dc1[31:0] | `RV_DATA_ACCESS_MASK7)) == (`RV_DATA_ACCESS_ADDR7 | `RV_DATA_ACCESS_MASK7)))); // Access fault logic // 1. Addr in dccm region but not in dccm offset // 2. Addr in picm region but not in picm offset // 3. DCCM -> PIC offset cross when DCCM/PIC in same region (PIC access are always word aligned so no cross possible from PIC->DCCM) // 4. Ld/St access to picm are not word aligned // 5. Address not in protected space or dccm/pic region if (DCCM_ENABLE & (DCCM_REGION == PIC_REGION)) begin assign access_fault_dc1 = ((start_addr_in_dccm_region_dc1 & ~(start_addr_in_dccm_dc1 | start_addr_in_pic_dc1)) | (end_addr_in_dccm_region_dc1 & ~(end_addr_in_dccm_dc1 | end_addr_in_pic_dc1)) | (start_addr_in_dccm_dc1 & end_addr_in_pic_dc1) | (start_addr_in_pic_dc1 & end_addr_in_dccm_dc1) | ((addr_in_pic_dc1 & ((start_addr_dc1[1:0] != 2'b0) | ~lsu_pkt_dc1.word))) | (~start_addr_in_dccm_region_dc1 & ~non_dccm_access_ok)) & lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma; end else begin assign access_fault_dc1 = ((start_addr_in_dccm_region_dc1 & ~start_addr_in_dccm_dc1) | (end_addr_in_dccm_region_dc1 & ~end_addr_in_dccm_dc1) | (start_addr_in_pic_region_dc1 & ~start_addr_in_pic_dc1) | (end_addr_in_pic_region_dc1 & ~end_addr_in_pic_dc1) | ((addr_in_pic_dc1 & ((start_addr_dc1[1:0] != 2'b0) | ~lsu_pkt_dc1.word))) | (~start_addr_in_pic_region_dc1 & ~start_addr_in_dccm_region_dc1 & ~non_dccm_access_ok)) & lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma; end // Misaligned happens due to 2 reasons // 1. Region cross // 2. sideeffects access which are not aligned assign misaligned_fault_dc1 = ((start_addr_dc1[31:28] != end_addr_dc1[31:28]) | (is_sideeffects_dc1 & ~is_aligned_dc1)) & addr_external_dc1 & lsu_pkt_dc1.valid & ~lsu_pkt_dc1.dma; rvdff_fpga #(.WIDTH(1)) is_sideeffects_dc2ff (.din(is_sideeffects_dc1), .dout(is_sideeffects_dc2), .clk(lsu_freeze_c2_dc2_clk), .clken(lsu_freeze_c2_dc2_clken), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(1)) is_sideeffects_dc3ff (.din(is_sideeffects_dc2), .dout(is_sideeffects_dc3), .clk(lsu_freeze_c2_dc3_clk), .clken(lsu_freeze_c2_dc3_clken), .rawclk(clk), .*); endmodule // lsu_addrcheck