Line data Source code
1 : // SPDX-License-Identifier: Apache-2.0
2 : // Copyright 2020 Western Digital Corporation or its affiliates.
3 : //
4 : // Licensed under the Apache License, Version 2.0 (the "License");
5 : // you may not use this file except in compliance with the License.
6 : // You may obtain a copy of the License at
7 : //
8 : // http://www.apache.org/licenses/LICENSE-2.0
9 : //
10 : // Unless required by applicable law or agreed to in writing, software
11 : // distributed under the License is distributed on an "AS IS" BASIS,
12 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : // See the License for the specific language governing permissions and
14 : // limitations under the License.
15 :
16 : //********************************************************************************
17 : // $Id$
18 : //
19 : //
20 : // Owner:
21 : // Function: Checks the memory map for the address
22 : // Comments:
23 : //
24 : //********************************************************************************
25 : module el2_lsu_addrcheck
26 : import el2_pkg::*;
27 : #(
28 : `include "el2_param.vh"
29 : )(
30 69840565 : input logic lsu_c2_m_clk, // clock
31 338 : input logic rst_l, // reset
32 :
33 593287 : input logic [31:0] start_addr_d, // start address for lsu
34 593313 : input logic [31:0] end_addr_d, // end address for lsu
35 477872 : input el2_lsu_pkt_t lsu_pkt_d, // packet in d
36 0 : input logic [31:0] dec_tlu_mrac_ff, // CSR read
37 1446243 : input logic [3:0] rs1_region_d, // address rs operand [31:28]
38 :
39 475446 : input logic [31:0] rs1_d, // address rs operand
40 :
41 36448 : output logic is_sideeffects_m, // is sideffects space
42 614422 : output logic addr_in_dccm_d, // address in dccm
43 12 : output logic addr_in_pic_d, // address in pic
44 614789 : output logic addr_external_d, // address in external
45 :
46 70 : output logic access_fault_d, // access fault
47 10 : output logic misaligned_fault_d, // misaligned
48 0 : output logic [3:0] exc_mscause_d, // mscause for access/misaligned faults
49 :
50 0 : output logic fir_dccm_access_error_d, // Fast interrupt dccm access error
51 0 : output logic fir_nondccm_access_error_d,// Fast interrupt dccm access error
52 :
53 164871 : input logic lsu_pmp_error_start,
54 164871 : input logic lsu_pmp_error_end,
55 :
56 : // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core.
57 : /*verilator coverage_off*/
58 : input logic scan_mode // Scan mode
59 : /*verilator coverage_on*/
60 : );
61 :
62 :
63 0 : logic non_dccm_access_ok;
64 56839 : logic is_sideeffects_d, is_aligned_d;
65 614422 : logic start_addr_in_dccm_d, end_addr_in_dccm_d;
66 614450 : logic start_addr_in_dccm_region_d, end_addr_in_dccm_region_d;
67 12 : logic start_addr_in_pic_d, end_addr_in_pic_d;
68 614450 : logic start_addr_in_pic_region_d, end_addr_in_pic_region_d;
69 822670 : logic [4:0] csr_idx;
70 5862 : logic addr_in_iccm;
71 614450 : logic start_addr_dccm_or_pic;
72 614442 : logic base_reg_dccm_or_pic;
73 8 : logic unmapped_access_fault_d, mpu_access_fault_d, picm_access_fault_d, regpred_access_fault_d;
74 10 : logic regcross_misaligned_fault_d, sideeffect_misaligned_fault_d;
75 0 : logic [3:0] access_fault_mscause_d;
76 0 : logic [3:0] misaligned_fault_mscause_d;
77 :
78 : if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable
79 : // Start address check
80 : rvrangecheck #(.CCM_SADR(pt.DCCM_SADR),
81 : .CCM_SIZE(pt.DCCM_SIZE)) start_addr_dccm_rangecheck (
82 : .addr(start_addr_d[31:0]),
83 : .in_range(start_addr_in_dccm_d),
84 : .in_region(start_addr_in_dccm_region_d)
85 : );
86 :
87 : // End address check
88 : rvrangecheck #(.CCM_SADR(pt.DCCM_SADR),
89 : .CCM_SIZE(pt.DCCM_SIZE)) end_addr_dccm_rangecheck (
90 : .addr(end_addr_d[31:0]),
91 : .in_range(end_addr_in_dccm_d),
92 : .in_region(end_addr_in_dccm_region_d)
93 : );
94 : end else begin: Gen_dccm_disable // block: Gen_dccm_enable
95 : assign start_addr_in_dccm_d = '0;
96 : assign start_addr_in_dccm_region_d = '0;
97 : assign end_addr_in_dccm_d = '0;
98 : assign end_addr_in_dccm_region_d = '0;
99 : end
100 :
101 : if (pt.ICCM_ENABLE == 1) begin : check_iccm
102 : assign addr_in_iccm = (start_addr_d[31:28] == pt.ICCM_REGION);
103 : end else begin
104 : assign addr_in_iccm = 1'b0;
105 : end
106 :
107 : // PIC memory check
108 : // Start address check
109 : rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR),
110 : .CCM_SIZE(pt.PIC_SIZE)) start_addr_pic_rangecheck (
111 : .addr(start_addr_d[31:0]),
112 : .in_range(start_addr_in_pic_d),
113 : .in_region(start_addr_in_pic_region_d)
114 : );
115 :
116 : // End address check
117 : rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR),
118 : .CCM_SIZE(pt.PIC_SIZE)) end_addr_pic_rangecheck (
119 : .addr(end_addr_d[31:0]),
120 : .in_range(end_addr_in_pic_d),
121 : .in_region(end_addr_in_pic_region_d)
122 : );
123 :
124 : assign start_addr_dccm_or_pic = start_addr_in_dccm_region_d | start_addr_in_pic_region_d;
125 : assign base_reg_dccm_or_pic = (|((rs1_region_d[3:0] == pt.DCCM_REGION) & pt.DCCM_ENABLE)) | (rs1_region_d[3:0] == pt.PIC_REGION);
126 : assign addr_in_dccm_d = (start_addr_in_dccm_d & end_addr_in_dccm_d);
127 : assign addr_in_pic_d = (start_addr_in_pic_d & end_addr_in_pic_d);
128 :
129 : assign addr_external_d = ~(start_addr_in_dccm_region_d | start_addr_in_pic_region_d);
130 : assign csr_idx[4:0] = {start_addr_d[31:28], 1'b1};
131 : assign is_sideeffects_d = dec_tlu_mrac_ff[csr_idx] & ~(start_addr_in_dccm_region_d | start_addr_in_pic_region_d | addr_in_iccm) & lsu_pkt_d.valid & (lsu_pkt_d.store | lsu_pkt_d.load); //every region has the 2 LSB indicating ( 1: sideeffects/no_side effects, and 0: cacheable ). Ignored in internal regions
132 : assign is_aligned_d = (lsu_pkt_d.word & (start_addr_d[1:0] == 2'b0)) |
133 : (lsu_pkt_d.half & (start_addr_d[0] == 1'b0)) |
134 : lsu_pkt_d.by;
135 :
136 0 : logic ACCESS0_STARTOK;
137 0 : logic ACCESS1_STARTOK;
138 0 : logic ACCESS2_STARTOK;
139 0 : logic ACCESS3_STARTOK;
140 0 : logic ACCESS4_STARTOK;
141 0 : logic ACCESS5_STARTOK;
142 0 : logic ACCESS6_STARTOK;
143 0 : logic ACCESS7_STARTOK;
144 0 : logic ACCESS0_ENDOK;
145 0 : logic ACCESS1_ENDOK;
146 0 : logic ACCESS2_ENDOK;
147 0 : logic ACCESS3_ENDOK;
148 0 : logic ACCESS4_ENDOK;
149 0 : logic ACCESS5_ENDOK;
150 0 : logic ACCESS6_ENDOK;
151 0 : logic ACCESS7_ENDOK;
152 :
153 : assign ACCESS0_STARTOK = pt.DATA_ACCESS_ENABLE0 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK0)) == (pt.DATA_ACCESS_ADDR0 | pt.DATA_ACCESS_MASK0);
154 : assign ACCESS1_STARTOK = pt.DATA_ACCESS_ENABLE1 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK1)) == (pt.DATA_ACCESS_ADDR1 | pt.DATA_ACCESS_MASK1);
155 : assign ACCESS2_STARTOK = pt.DATA_ACCESS_ENABLE2 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK2)) == (pt.DATA_ACCESS_ADDR2 | pt.DATA_ACCESS_MASK2);
156 : assign ACCESS3_STARTOK = pt.DATA_ACCESS_ENABLE3 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK3)) == (pt.DATA_ACCESS_ADDR3 | pt.DATA_ACCESS_MASK3);
157 : assign ACCESS4_STARTOK = pt.DATA_ACCESS_ENABLE4 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK4)) == (pt.DATA_ACCESS_ADDR4 | pt.DATA_ACCESS_MASK4);
158 : assign ACCESS5_STARTOK = pt.DATA_ACCESS_ENABLE5 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK5)) == (pt.DATA_ACCESS_ADDR5 | pt.DATA_ACCESS_MASK5);
159 : assign ACCESS6_STARTOK = pt.DATA_ACCESS_ENABLE6 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK6)) == (pt.DATA_ACCESS_ADDR6 | pt.DATA_ACCESS_MASK6);
160 : assign ACCESS7_STARTOK = pt.DATA_ACCESS_ENABLE7 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK7)) == (pt.DATA_ACCESS_ADDR7 | pt.DATA_ACCESS_MASK7);
161 : assign ACCESS0_ENDOK = pt.DATA_ACCESS_ENABLE0 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK0)) == (pt.DATA_ACCESS_ADDR0 | pt.DATA_ACCESS_MASK0);
162 : assign ACCESS1_ENDOK = pt.DATA_ACCESS_ENABLE1 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK1)) == (pt.DATA_ACCESS_ADDR1 | pt.DATA_ACCESS_MASK1);
163 : assign ACCESS2_ENDOK = pt.DATA_ACCESS_ENABLE2 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK2)) == (pt.DATA_ACCESS_ADDR2 | pt.DATA_ACCESS_MASK2);
164 : assign ACCESS3_ENDOK = pt.DATA_ACCESS_ENABLE3 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK3)) == (pt.DATA_ACCESS_ADDR3 | pt.DATA_ACCESS_MASK3);
165 : assign ACCESS4_ENDOK = pt.DATA_ACCESS_ENABLE4 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK4)) == (pt.DATA_ACCESS_ADDR4 | pt.DATA_ACCESS_MASK4);
166 : assign ACCESS5_ENDOK = pt.DATA_ACCESS_ENABLE5 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK5)) == (pt.DATA_ACCESS_ADDR5 | pt.DATA_ACCESS_MASK5);
167 : assign ACCESS6_ENDOK = pt.DATA_ACCESS_ENABLE6 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK6)) == (pt.DATA_ACCESS_ADDR6 | pt.DATA_ACCESS_MASK6);
168 : assign ACCESS7_ENDOK = pt.DATA_ACCESS_ENABLE7 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK7)) == (pt.DATA_ACCESS_ADDR7 | pt.DATA_ACCESS_MASK7);
169 :
170 : if (pt.PMP_ENTRIES == 0) begin
171 : assign non_dccm_access_ok = (~(|{pt.DATA_ACCESS_ENABLE0,pt.DATA_ACCESS_ENABLE1,pt.DATA_ACCESS_ENABLE2,pt.DATA_ACCESS_ENABLE3,pt.DATA_ACCESS_ENABLE4,pt.DATA_ACCESS_ENABLE5,pt.DATA_ACCESS_ENABLE6,pt.DATA_ACCESS_ENABLE7})) |
172 : (( ACCESS0_STARTOK|
173 : ACCESS1_STARTOK|
174 : ACCESS2_STARTOK|
175 : ACCESS3_STARTOK|
176 : ACCESS4_STARTOK|
177 : ACCESS5_STARTOK|
178 : ACCESS6_STARTOK|
179 : ACCESS7_STARTOK) &
180 : ( ACCESS0_ENDOK|
181 : ACCESS1_ENDOK|
182 : ACCESS2_ENDOK|
183 : ACCESS3_ENDOK|
184 : ACCESS4_ENDOK|
185 : ACCESS5_ENDOK|
186 : ACCESS6_ENDOK|
187 : ACCESS7_ENDOK));
188 : end
189 :
190 : // Access fault logic
191 : // 0. Unmapped local memory : Addr in dccm region but not in dccm offset OR Addr in picm region but not in picm offset OR DCCM -> PIC cross when DCCM/PIC in same region
192 : // 1. Uncorrectable (double bit) ECC error
193 : // 3. Address is not in a populated non-dccm region
194 : // 5. Region predication access fault: Base Address in DCCM/PIC and Final address in non-DCCM/non-PIC region or vice versa
195 : // 6. Ld/St access to picm are not word aligned or word size
196 : assign regpred_access_fault_d = (start_addr_dccm_or_pic ^ base_reg_dccm_or_pic); // 5. Region predication access fault: Base Address in DCCM/PIC and Final address in non-DCCM/non-PIC region or vice versa
197 : assign picm_access_fault_d = (addr_in_pic_d & ((start_addr_d[1:0] != 2'b0) | ~lsu_pkt_d.word)); // 6. Ld/St access to picm are not word aligned or word size
198 :
199 : if (pt.DCCM_ENABLE & (pt.DCCM_REGION == pt.PIC_REGION)) begin
200 : assign unmapped_access_fault_d = ((start_addr_in_dccm_region_d & ~(start_addr_in_dccm_d | start_addr_in_pic_d)) | // 0. Addr in dccm/pic region but not in dccm/pic offset
201 : (end_addr_in_dccm_region_d & ~(end_addr_in_dccm_d | end_addr_in_pic_d)) | // 0. Addr in dccm/pic region but not in dccm/pic offset
202 : (start_addr_in_dccm_d & end_addr_in_pic_d) | // 0. DCCM -> PIC cross when DCCM/PIC in same region
203 : (start_addr_in_pic_d & end_addr_in_dccm_d)); // 0. DCCM -> PIC cross when DCCM/PIC in same region
204 : if (pt.PMP_ENTRIES > 0) begin
205 : assign mpu_access_fault_d = (lsu_pmp_error_start | lsu_pmp_error_end); // X. Address is in blocked region
206 : end else begin
207 : assign mpu_access_fault_d = (~start_addr_in_dccm_region_d & ~non_dccm_access_ok); // 3. Address is not in a populated non-dccm region
208 : end
209 : end else begin
210 : assign unmapped_access_fault_d = ((start_addr_in_dccm_region_d & ~start_addr_in_dccm_d) | // 0. Addr in dccm region but not in dccm offset
211 : (end_addr_in_dccm_region_d & ~end_addr_in_dccm_d) | // 0. Addr in dccm region but not in dccm offset
212 : (start_addr_in_pic_region_d & ~start_addr_in_pic_d) | // 0. Addr in picm region but not in picm offset
213 : (end_addr_in_pic_region_d & ~end_addr_in_pic_d)); // 0. Addr in picm region but not in picm offset
214 : if (pt.PMP_ENTRIES > 0) begin
215 : assign mpu_access_fault_d = (lsu_pmp_error_start | lsu_pmp_error_end); // X. Address is in blocked region
216 : end else begin
217 : assign mpu_access_fault_d = (~start_addr_in_pic_region_d & ~start_addr_in_dccm_region_d & ~non_dccm_access_ok); // 3. Address is not in a populated non-dccm region
218 : end
219 : end
220 :
221 : assign access_fault_d = (unmapped_access_fault_d | mpu_access_fault_d | picm_access_fault_d | regpred_access_fault_d) & lsu_pkt_d.valid & ~lsu_pkt_d.dma;
222 : assign access_fault_mscause_d[3:0] = unmapped_access_fault_d ? 4'h2 : mpu_access_fault_d ? 4'h3 : regpred_access_fault_d ? 4'h5 : picm_access_fault_d ? 4'h6 : 4'h0;
223 :
224 : // Misaligned happens due to 2 reasons
225 : // 0. Region cross
226 : // 1. sideeffects access which are not aligned
227 : assign regcross_misaligned_fault_d = (start_addr_d[31:28] != end_addr_d[31:28]);
228 : assign sideeffect_misaligned_fault_d = (is_sideeffects_d & ~is_aligned_d);
229 : assign misaligned_fault_d = (regcross_misaligned_fault_d | (sideeffect_misaligned_fault_d & addr_external_d)) & lsu_pkt_d.valid & ~lsu_pkt_d.dma;
230 : assign misaligned_fault_mscause_d[3:0] = regcross_misaligned_fault_d ? 4'h2 : sideeffect_misaligned_fault_d ? 4'h1 : 4'h0;
231 :
232 : assign exc_mscause_d[3:0] = misaligned_fault_d ? misaligned_fault_mscause_d[3:0] : access_fault_mscause_d[3:0];
233 :
234 : // Fast interrupt error logic
235 : assign fir_dccm_access_error_d = ((start_addr_in_dccm_region_d & ~start_addr_in_dccm_d) |
236 : (end_addr_in_dccm_region_d & ~end_addr_in_dccm_d)) & lsu_pkt_d.valid & lsu_pkt_d.fast_int;
237 : assign fir_nondccm_access_error_d = ~(start_addr_in_dccm_region_d & end_addr_in_dccm_region_d) & lsu_pkt_d.valid & lsu_pkt_d.fast_int;
238 :
239 : rvdff #(.WIDTH(1)) is_sideeffects_mff (.din(is_sideeffects_d), .dout(is_sideeffects_m), .clk(lsu_c2_m_clk), .*);
240 :
241 : endmodule // el2_lsu_addrcheck
|