185 lines
10 KiB
Systemverilog
185 lines
10 KiB
Systemverilog
// 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 rst_l, // reset
|
|
|
|
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_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 #(.WIDTH(1)) is_sideeffects_dc2ff (.din(is_sideeffects_dc1), .dout(is_sideeffects_dc2), .clk(lsu_freeze_c2_dc2_clk), .*);
|
|
rvdff #(.WIDTH(1)) is_sideeffects_dc3ff (.din(is_sideeffects_dc2), .dout(is_sideeffects_dc3), .clk(lsu_freeze_c2_dc3_clk), .*);
|
|
|
|
endmodule // lsu_addrcheck
|
|
|