Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: N2_MemErrDetector.h | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | #ifndef _N2_MEMERRDETECTOR_H | |
24 | #define _N2_MEMERRDETECTOR_H | |
25 | /************************************************************************ | |
26 | ** | |
27 | ** Copyright (C) 2005, Sun Microsystems, Inc. | |
28 | ** | |
29 | ** Sun considers its source code as an unpublished, proprietary | |
30 | ** trade secret and it is available only under strict license provisions. | |
31 | ** This copyright notice is placed here only to protect Sun in the event | |
32 | ** the source is deemed a published work. Disassembly, decompilation, | |
33 | ** or other means of reducing the object code to human readable form | |
34 | ** is prohibited by the license agreement under which this code is | |
35 | ** provided to the user or company in possession of this copy. | |
36 | ** | |
37 | *************************************************************************/ | |
38 | #include "MemoryTransaction.h" | |
39 | #include "SS_MemErrDetector.h" | |
40 | #include "BL_Memory.h" | |
41 | #include "SS_CsrAccess.h" | |
42 | ||
43 | #include "N2_Strand.h" | |
44 | #include "BL_CKEcc.h" | |
45 | #include "BL_CKSyndrome.h" | |
46 | #include "BL_HammingEcc.h" | |
47 | #include "BL_Hamming_32_7_Synd.h" | |
48 | ||
49 | #include "N2_L2AddressingFields.h" | |
50 | #include "N2_L2CacheFlushAddrFields.h" | |
51 | #include "N2_L2DiagDataAddressingFields.h" | |
52 | #include "N2_L2ErrorEnMem.h" | |
53 | #include "N2_L2ErrorStatusReg.h" | |
54 | #include "N2_L2ControlReg.h" | |
55 | #include "N2_L2ErrorAddressReg.h" | |
56 | #include "N2_L2DiagDataMem.h" | |
57 | #include "N2_L2DiagTagMem.h" | |
58 | #include "N2_L2DiagVdMem.h" | |
59 | #include "N2_L2DiagUaMem.h" | |
60 | #include "N2_L2NotdataErrorReg.h" | |
61 | ||
62 | #include "N2_DramErrorStatusMem.h" | |
63 | #include "N2_DramErrorInjectMem.h" | |
64 | #include "N2_DramErrorCounterMem.h" | |
65 | #include "N2_DramErrorLocMem.h" | |
66 | #include "N2_DramFbdInjectedErrSrcReg.h" | |
67 | #include "N2_DramFbdCountReg.h" | |
68 | #include "N2_DramFbdErrorSyndromeReg.h" | |
69 | ||
70 | #include "N2_SocErrorInjectReg.h" | |
71 | #include "N2_SocErrorStatusReg.h" | |
72 | #include "N2_SocPendingErrStatusReg.h" | |
73 | #include "N2_SocErrorLogEnableReg.h" | |
74 | #include "N2_SocErrorIntrEnReg.h" | |
75 | #include "N2_SocFatalErrorEnableReg.h" | |
76 | #include "N2_SocErrorSteeringReg.h" | |
77 | ||
78 | class N2_Model; | |
79 | ||
80 | /** | |
81 | * The N2_MemErrDetector class is used to detect injected RAS errors | |
82 | * associated with the memory hierarchy. In particular, it models and | |
83 | * detects errors in the primary and secondary caches and DRAM. | |
84 | */ | |
85 | ||
86 | #define RAS_OSTR debugOutput_ && cerr | |
87 | ||
88 | // Memory Error Detector for RAS | |
89 | // | |
90 | // Detects RAS error related to memory access: primary cache, | |
91 | // secondary cache, DRAM and FBDIMM errors. | |
92 | class N2_Core; | |
93 | ||
94 | class N2_MemErrDetector : public SS_MemErrDetector { | |
95 | ||
96 | public: | |
97 | // Extend class to include update() method which guarantees (or rather, | |
98 | // approximates) writing to the L2 Error Status Register. | |
99 | class N2_CheckedL2ESRAccess : public SS_CsrAccess<N2_L2ErrorStatusReg> { | |
100 | public: | |
101 | ||
102 | N2_CheckedL2ESRAccess(SS_Csr& csr): | |
103 | SS_CsrAccess<N2_L2ErrorStatusReg>(csr) {} | |
104 | ~N2_CheckedL2ESRAccess() {} | |
105 | const N2_CheckedL2ESRAccess & | |
106 | operator=( const N2_CheckedL2ESRAccess &rhs ) { | |
107 | fprintf(stderr, "Unimplemented function." ); | |
108 | exit(-1); | |
109 | return *this; | |
110 | } | |
111 | ||
112 | // add update checking to insure the MEC, MEU, etc. bits are set | |
113 | // correctly. Returns true if the N2_L2ErrorAddressReg associated | |
114 | // with the error should also be updated. | |
115 | bool access(uint64_t ndx, N2_L2ErrorStatusReg &csr, bool isRead); | |
116 | ||
117 | private: | |
118 | N2_CheckedL2ESRAccess(); | |
119 | }; | |
120 | ||
121 | // Extend N2_L2DiagVdMem class to include ECC and syndrome calculators | |
122 | class N2_L2DiagVdMemWithECC : public N2_L2DiagVdMem { | |
123 | public: | |
124 | N2_L2DiagVdMemWithECC() {} | |
125 | N2_L2DiagVdMemWithECC( const N2_L2DiagVdMemWithECC& obj ) : | |
126 | N2_L2DiagVdMem(obj) | |
127 | {} | |
128 | ||
129 | ~N2_L2DiagVdMemWithECC() {} | |
130 | ||
131 | // Shifts used to convert VD diag data into dirty and valid bits with ECC | |
132 | static const N2_L2_DIAG_VD_ACCESS_VALID_SHIFT = 16; | |
133 | static const N2_L2_DIAG_VD_ACCESS_DIRTY_SHIFT = 0; | |
134 | static const N2_L2_DIAG_VD_ACCESS_ECC_SHIFT = 0; | |
135 | ||
136 | uint32_t getVD() const | |
137 | { | |
138 | return (getVALID() << N2_L2_DIAG_VD_ACCESS_VALID_SHIFT) | | |
139 | getDIRTY(); | |
140 | } | |
141 | ||
142 | void setVD(uint32_t vd) | |
143 | { | |
144 | setDIRTY(vd); | |
145 | setVALID(vd >> N2_L2_DIAG_VD_ACCESS_VALID_SHIFT); | |
146 | } | |
147 | ||
148 | uint32_t calcECC(void) const | |
149 | { | |
150 | return (BL_Hamming_32_7_Synd::calc_check_bits(getVD())).get(); | |
151 | } | |
152 | ||
153 | BL_Hamming_32_7_Synd getSyndrome(void) const | |
154 | { | |
155 | ||
156 | return BL_Hamming_32_7_Synd(getVD(), getVDECC()); | |
157 | } | |
158 | }; | |
159 | ||
160 | struct N2_L2VaudSyndrome { | |
161 | N2_L2VaudSyndrome() : | |
162 | vdSyndrome_(0), | |
163 | uaSyndrome_(0){} | |
164 | ||
165 | ~N2_L2VaudSyndrome() {} | |
166 | ||
167 | N2_L2VaudSyndrome(uint32_t vdSyndrome,uint32_t uaSyndrome) : | |
168 | vdSyndrome_(vdSyndrome), | |
169 | uaSyndrome_(uaSyndrome){} | |
170 | BL_Hamming_32_7_Synd vdSyndrome_; | |
171 | BL_Hamming_32_7_Synd uaSyndrome_; | |
172 | }; | |
173 | ||
174 | ||
175 | // Extend N2_L2DiagUaMem class to include ECC and syndrome calculators | |
176 | class N2_L2DiagUaMemWithECC : public N2_L2DiagUaMem { | |
177 | public: | |
178 | N2_L2DiagUaMemWithECC() {} | |
179 | N2_L2DiagUaMemWithECC( const N2_L2DiagUaMemWithECC& obj ) : | |
180 | N2_L2DiagUaMem(obj) | |
181 | {} | |
182 | ||
183 | ~N2_L2DiagUaMemWithECC() {} | |
184 | ||
185 | // Shifts used to convert VD diag data into dirty and valid bits with ECC | |
186 | static const N2_L2_DIAG_UA_ACCESS_USED_SHIFT = 16; | |
187 | static const N2_L2_DIAG_UA_ACCESS_ALLOC_SHIFT = 0; | |
188 | static const N2_L2_DIAG_UA_ACCESS_ECC_SHIFT = 0; | |
189 | ||
190 | uint32_t getUA() const | |
191 | { | |
192 | return (getUSED() << N2_L2_DIAG_UA_ACCESS_USED_SHIFT) | | |
193 | getALLOC(); | |
194 | } | |
195 | ||
196 | void setUA(uint32_t vd) | |
197 | { | |
198 | setALLOC(vd); | |
199 | setUSED(vd >> N2_L2_DIAG_UA_ACCESS_USED_SHIFT); | |
200 | } | |
201 | ||
202 | uint32_t calcECC(void) const | |
203 | { | |
204 | return (BL_Hamming_32_7_Synd::calc_check_bits(getUA())).get(); | |
205 | } | |
206 | ||
207 | BL_Hamming_32_7_Synd getSyndrome(void) const | |
208 | { | |
209 | ||
210 | return BL_Hamming_32_7_Synd(getUA(), getUAECC()); | |
211 | } | |
212 | }; | |
213 | ||
214 | ||
215 | // Extend N2_L2DiagDataMem class to include ECC and syndrome calculators | |
216 | class N2_L2DiagDataMemWithECC : public N2_L2DiagDataMem { | |
217 | public: | |
218 | N2_L2DiagDataMemWithECC() {} | |
219 | N2_L2DiagDataMemWithECC( const N2_L2DiagDataMemWithECC& obj ) : | |
220 | N2_L2DiagDataMem(obj) | |
221 | {} | |
222 | ~N2_L2DiagDataMemWithECC() {} | |
223 | ||
224 | uint32_t calcECC(void) const | |
225 | { | |
226 | return (BL_Hamming_32_7_Synd::calc_check_bits(getDATA())).get(); | |
227 | } | |
228 | ||
229 | BL_Hamming_32_7_Synd getSyndrome(void) const | |
230 | { | |
231 | return BL_Hamming_32_7_Synd(getDATA(), getECC()); | |
232 | } | |
233 | ||
234 | static const uint64_t L2_NOT_DATA = 0x7f; | |
235 | }; | |
236 | ||
237 | ||
238 | // This class captures the error status of an L2 cache data quarter | |
239 | // line. | |
240 | // The ECC syndromes for 4 32-bit words are captured in the | |
241 | // qLineSyndrome_ field and the physical address corresponding to the | |
242 | // ECC error, if any, is in the errorPaddr_ field. | |
243 | class N2_L2CacheLineError { | |
244 | public: | |
245 | typedef enum { | |
246 | NO_ERROR, | |
247 | CORRECTABLE_ERROR, | |
248 | UNCORRECTABLE_ERROR, | |
249 | NOT_DATA | |
250 | } errorType_t; | |
251 | ||
252 | N2_L2CacheLineError(uint64_t errorPaddr) : | |
253 | errorType_(NO_ERROR), | |
254 | qLineSyndrome_(0), | |
255 | errorPaddr_(errorPaddr), | |
256 | wordNdx_(0) | |
257 | {} | |
258 | ||
259 | virtual ~N2_L2CacheLineError() {} | |
260 | ||
261 | /* | |
262 | * Assignment operator | |
263 | * | |
264 | * @param rhs The right hand side of the assignment operator. | |
265 | * @return The lvalue of the assignment. | |
266 | */ | |
267 | const N2_L2CacheLineError & | |
268 | operator=( const N2_L2CacheLineError &rhs ) | |
269 | { | |
270 | errorType_ = rhs.errorType_; | |
271 | qLineSyndrome_ = rhs.qLineSyndrome_; | |
272 | errorPaddr_ = rhs.errorPaddr_; | |
273 | wordNdx_ = rhs.wordNdx_; | |
274 | return *this; | |
275 | } | |
276 | ||
277 | // if qLineSyndrome, not qLineSyndrome_, compiler bug?!? | |
278 | bool isError() const { return qLineSyndrome_ != 0; } | |
279 | ||
280 | uint32_t qLineSyndrome() const { return qLineSyndrome_; } | |
281 | ||
282 | uint64_t errorPaddr() const { return errorPaddr_; } | |
283 | ||
284 | bool isCorrectable() const { return isError() && | |
285 | errorType_ == CORRECTABLE_ERROR; } | |
286 | ||
287 | bool isUncorrectable() const { return isError() && | |
288 | (errorType_ == UNCORRECTABLE_ERROR || | |
289 | errorType_ == NOT_DATA); } | |
290 | ||
291 | bool isNotData() const { return isError() && | |
292 | errorType_ == NOT_DATA; } | |
293 | ||
294 | void addQuarterLine(BL_Hamming_32_7_Synd wordSyndrome) { | |
295 | qLineSyndrome_ |= (wordSyndrome.getSyndrome() << ( 7 * wordNdx_++)); | |
296 | ||
297 | // dispatch on current worst cache line error type. | |
298 | // Incorportate error from current word into quarter line's | |
299 | // error type. | |
300 | switch (errorType_) { | |
301 | case NO_ERROR: // any new error bad | |
302 | if (!wordSyndrome.noError()) { | |
303 | errorType_ = CORRECTABLE_ERROR; | |
304 | } | |
305 | /* consider NotData or uncorrectable possibility by | |
306 | falling through */ | |
307 | /* FALLTHROUGH*/ | |
308 | case CORRECTABLE_ERROR: // is new uncorrectable? | |
309 | if (wordSyndrome.isUncorrectableError()) { | |
310 | errorType_ = UNCORRECTABLE_ERROR; | |
311 | } | |
312 | /* consider NotData possibility by falling through */ | |
313 | /* FALLTHROUGH*/ | |
314 | case UNCORRECTABLE_ERROR: // only NOT_DATA is worse | |
315 | if (wordSyndrome.getSyndrome() == | |
316 | N2_L2DiagDataMemWithECC::L2_NOT_DATA) { | |
317 | errorType_ = NOT_DATA; | |
318 | } | |
319 | break; | |
320 | case NOT_DATA: // can't get any worse than this | |
321 | break; | |
322 | default: | |
323 | fprintf(stderr, "N2_L2CacheLineError::addQuarterLine " | |
324 | "bad errorType_ 0x%x", errorType_); | |
325 | exit(-1); | |
326 | } | |
327 | } | |
328 | ||
329 | private: | |
330 | N2_L2CacheLineError() {} | |
331 | ||
332 | errorType_t errorType_; | |
333 | ||
334 | uint32_t qLineSyndrome_; | |
335 | ||
336 | uint64_t errorPaddr_; | |
337 | ||
338 | uint_t wordNdx_; | |
339 | }; | |
340 | ||
341 | ||
342 | class N2_CererWithBitMux : public N2_Cerer { | |
343 | public: | |
344 | ~N2_CererWithBitMux() {} | |
345 | N2_CererWithBitMux(const N2_CererWithBitMux &obj) : | |
346 | N2_Cerer(obj) {} | |
347 | N2_CererWithBitMux(const N2_Cerer &obj) : | |
348 | N2_Cerer(obj) {} | |
349 | ||
350 | bool checkOneL2Cbit(const MemoryTransaction &memXact) { | |
351 | return | |
352 | (this->l2c_socc() && memXact.tablewalk()) || | |
353 | (icl2c() && | |
354 | memXact.referenceType() == MemoryTransaction::INSTR) || | |
355 | (dcl2c() && | |
356 | memXact.referenceType() == MemoryTransaction::DATA); | |
357 | } | |
358 | ||
359 | bool checkAnyL2Cbit() { | |
360 | return icl2c() || dcl2c(); | |
361 | } | |
362 | ||
363 | private: | |
364 | N2_CererWithBitMux() : | |
365 | N2_Cerer(){} | |
366 | }; | |
367 | ||
368 | N2_MemErrDetector(SS_Model *model) : | |
369 | n2_model(model), | |
370 | L2ControlRegAccess_(((N2_Model*)n2_model)->csr), | |
371 | L2ErrorStatusRegAccess_(((N2_Model*)n2_model)->csr), | |
372 | L2ErrorAddressRegAccess_(((N2_Model*)n2_model)->csr), | |
373 | L2ErrorEnMemAccess_(((N2_Model*)n2_model)->csr), | |
374 | L2DiagDataMemAccess_(((N2_Model*)n2_model)->csr), | |
375 | L2DiagTagMemAccess_(((N2_Model*)n2_model)->csr), | |
376 | L2DiagVdMemAccess_(((N2_Model*)n2_model)->csr), | |
377 | L2DiagUaMemAccess_(((N2_Model*)n2_model)->csr), | |
378 | L2NotdataErrorRegAccess_(((N2_Model*)n2_model)->csr), | |
379 | DramErrorStatusMemAccess_(((N2_Model*)n2_model)->csr), | |
380 | DramErrorInjectMemAccess_(((N2_Model*)n2_model)->csr), | |
381 | DramErrorCounterMemAccess_(((N2_Model*)n2_model)->csr), | |
382 | DramErrorLocMemAccess_(((N2_Model*)n2_model)->csr), | |
383 | DramFbdInjectedErrSrcRegAccess_(((N2_Model*)n2_model)->csr), | |
384 | DramFbdCountRegAccess_(((N2_Model*)n2_model)->csr), | |
385 | DramFbdErrorSyndromeRegAccess_(((N2_Model*)n2_model)->csr), | |
386 | socErrorInjectRegAccess_(((N2_Model*)n2_model)->csr), | |
387 | socErrorStatusRegAccess_(((N2_Model*)n2_model)->csr), | |
388 | socPendingErrStatusRegAccess_(((N2_Model*)n2_model)->csr), | |
389 | socErrorLogEnableRegAccess_(((N2_Model*)n2_model)->csr), | |
390 | socErrorIntrEnRegAccess_(((N2_Model*)n2_model)->csr), | |
391 | socFatalErrorEnableRegAccess_(((N2_Model*)n2_model)->csr), | |
392 | socErrorSteeringRegAccess_(((N2_Model*)n2_model)->csr), | |
393 | debugOutput_(getenv("RAS_DEBUG") != NULL), | |
394 | debugChipKill_(getenv("CHIPKILL_DEBUG") != NULL) | |
395 | { | |
396 | for (int bank = 0; bank < N2_L2_CACHE_NR_BANKS; ++bank) { | |
397 | L2CacheWaysNRUPtr_[bank] = 0; | |
398 | } | |
399 | step_hook = n2_step_hook; | |
400 | //tick_err_detector = n2_tick_cmpr_disrupting_err_detector; | |
401 | ||
402 | } | |
403 | ||
404 | /** | |
405 | * Copy constructor | |
406 | * | |
407 | * @param orig The MemErrDetector object to copy. | |
408 | */ | |
409 | N2_MemErrDetector( const N2_MemErrDetector &orig ) : | |
410 | n2_model(orig.n2_model), | |
411 | L2ControlRegAccess_(orig.L2ControlRegAccess_), | |
412 | L2ErrorStatusRegAccess_(orig.L2ErrorStatusRegAccess_), | |
413 | L2ErrorAddressRegAccess_(orig.L2ErrorAddressRegAccess_), | |
414 | L2ErrorEnMemAccess_(orig.L2ErrorEnMemAccess_), | |
415 | L2DiagDataMemAccess_(orig.L2DiagDataMemAccess_), | |
416 | L2DiagTagMemAccess_(orig.L2DiagTagMemAccess_), | |
417 | L2DiagVdMemAccess_(orig.L2DiagVdMemAccess_), | |
418 | L2DiagUaMemAccess_(orig.L2DiagUaMemAccess_), | |
419 | L2NotdataErrorRegAccess_(orig.L2NotdataErrorRegAccess_), | |
420 | DramErrorStatusMemAccess_(orig.DramErrorStatusMemAccess_), | |
421 | DramErrorInjectMemAccess_(orig.DramErrorInjectMemAccess_), | |
422 | DramErrorCounterMemAccess_(orig.DramErrorCounterMemAccess_), | |
423 | DramErrorLocMemAccess_(orig.DramErrorLocMemAccess_), | |
424 | DramFbdInjectedErrSrcRegAccess_(orig.DramFbdInjectedErrSrcRegAccess_), | |
425 | DramFbdCountRegAccess_(orig.DramFbdCountRegAccess_), | |
426 | DramFbdErrorSyndromeRegAccess_(orig.DramFbdErrorSyndromeRegAccess_), | |
427 | socErrorInjectRegAccess_(orig.socErrorInjectRegAccess_), | |
428 | socErrorStatusRegAccess_(orig.socErrorStatusRegAccess_), | |
429 | socPendingErrStatusRegAccess_(orig.socPendingErrStatusRegAccess_), | |
430 | socErrorLogEnableRegAccess_(orig.socErrorLogEnableRegAccess_), | |
431 | socErrorIntrEnRegAccess_(orig.socErrorIntrEnRegAccess_), | |
432 | socFatalErrorEnableRegAccess_(orig.socFatalErrorEnableRegAccess_), | |
433 | socErrorSteeringRegAccess_(orig.socErrorSteeringRegAccess_), | |
434 | debugOutput_(orig.debugOutput_), | |
435 | debugChipKill_(orig.debugChipKill_) | |
436 | { | |
437 | for (int bank = 0; bank < N2_L2_CACHE_NR_BANKS; ++bank) { | |
438 | L2CacheWaysNRUPtr_[bank] = orig.L2CacheWaysNRUPtr_[bank] ; | |
439 | } | |
440 | } | |
441 | ||
442 | /** | |
443 | * Destructor | |
444 | */ | |
445 | virtual ~N2_MemErrDetector() {} | |
446 | ||
447 | /** | |
448 | * Equality operator | |
449 | * | |
450 | * @param rhs The right hand side of the equality operator | |
451 | * @return Return true if this objec and rhs are equal, | |
452 | * otherwise return false | |
453 | */ | |
454 | bool operator==( const N2_MemErrDetector &rhs ) const; | |
455 | ||
456 | /** | |
457 | * Assignment operator | |
458 | * | |
459 | * @param rhs The right hand side of the assignment operator. | |
460 | * @return The lvalue of the assignment. | |
461 | */ | |
462 | const N2_MemErrDetector & operator=( const N2_MemErrDetector &rhs ); | |
463 | ||
464 | ||
465 | SS_Trap::Type detect_fetch_err( MemoryLevel level, | |
466 | SS_Vaddr pc, | |
467 | SS_Vaddr npc, SS_Strand* s, SS_Paddr pa) ; | |
468 | ||
469 | SS_Trap::Type detect_load_err( MemoryLevel level, | |
470 | SS_Vaddr pc, SS_Vaddr npc, | |
471 | SS_Strand* s, SS_Instr* line, | |
472 | SS_Paddr pa) ; | |
473 | ||
474 | SS_Trap::Type inject_store_err( MemoryLevel level, | |
475 | SS_Vaddr pc, SS_Vaddr npc, | |
476 | SS_Strand* s, SS_Instr* line, | |
477 | SS_Paddr pa, | |
478 | uint64_t data) ; | |
479 | ||
480 | BL_EccBits N2_MemErrDetector::n2_tick_cmpr_err_injector(SS_Strand* s, | |
481 | uint64_t data); | |
482 | ||
483 | SS_Trap::Type N2_MemErrDetector::n2_tick_cmpr_precise_err_detector(SS_Strand* s, | |
484 | N2_TickAccess::TickAccessIndex array_index); | |
485 | ||
486 | static bool n2_tick_cmpr_disrupting_err_detector(SS_Strand* s); | |
487 | ||
488 | // Returns whether an prefetch instruction is a prefetchICE | |
489 | bool is_prefetchICE(SS_Opcode& opc) | |
490 | { | |
491 | return opc.get_fcn() == 0x18; | |
492 | } | |
493 | ||
494 | // Routine to flush L2 cache | |
495 | void prefetchICE(SS_Paddr pa); | |
496 | ||
497 | SS_Trap::Type ras_flush( SS_Vaddr pc, SS_Vaddr npc, | |
498 | SS_Strand* s, | |
499 | SS_Instr* line, | |
500 | SS_Paddr pa, | |
501 | uint64_t size, | |
502 | CacheType type) | |
503 | { return SS_Trap::NO_TRAP; } | |
504 | ||
505 | void ras_flush( SS_Strand*s, SS_Strand* requesting_strand, SS_Paddr pa, uint64_t size, CacheType type); | |
506 | ||
507 | static SS_Trap::Type n2_step_hook(SS_Strand* s); | |
508 | ||
509 | ||
510 | /** | |
511 | * detectErr() throws traps and furballs when an RAS error | |
512 | * has been injected in the memory hierarchy. | |
513 | */ | |
514 | ||
515 | SS_Trap::Type detectErr(const MemoryTransaction &memXact); | |
516 | ||
517 | /** | |
518 | * L2CacheFill takes a memory transaction and fills the | |
519 | * L-cache as needed with data used by the transaction. | |
520 | */ | |
521 | ||
522 | SS_Trap::Type L2CacheFill(const MemoryTransaction &memXact); | |
523 | ||
524 | void L2CacheFlush(N2_L2CacheFlushAddrFields flushAddr); | |
525 | ||
526 | // In cache look-up routines, setting the way to this value | |
527 | // means a miss or "no way" matched | |
528 | const static int NO_WAY = -1; | |
529 | ||
530 | // SWIG routines for controlling debugging output | |
531 | void startDebugOutput() { debugOutput_ = true; } | |
532 | void stopDebugOutput() { debugOutput_ = false; } | |
533 | ||
534 | protected: | |
535 | ||
536 | private: | |
537 | // | |
538 | // N2 PRM Rev 1.1 Sect B.5.1 | |
539 | // Basic L2 cache size parameters | |
540 | // The number of sets per bank is: | |
541 | // 4MB/8s = 512K bytes per bank | |
542 | // 512K/64B = 8K lines per bank | |
543 | // 8K/16 = 512 sets per bank | |
544 | ||
545 | SS_Model *n2_model; | |
546 | ||
547 | static const N2_L2_CACHE_LINE_SIZE = 64; | |
548 | static const N2_L2_CACHE_NR_BANKS = 8; | |
549 | static const N2_L2_CACHE_NR_SETS_PER_BANK = 512; | |
550 | ||
551 | uint32_t L2CacheWaysNRUPtr_[N2_L2_CACHE_NR_BANKS]; | |
552 | std::map<uint64_t,uint64_t> dramECCMap_; | |
553 | ||
554 | void L2FixTags(N2_L2AddressingFields paddr); | |
555 | ||
556 | void L2FixTagsAndTrap(N2_Strand *strand, | |
557 | N2_L2AddressingFields paddr, | |
558 | const MemoryTransaction &memXact); | |
559 | ||
560 | bool L2FixTag(uint32_t diagNdx); | |
561 | N2_L2VaudSyndrome L2FixVUAD(N2_L2AddressingFields paddr, | |
562 | N2_L2DiagVdMemWithECC &diagVD); | |
563 | ||
564 | N2_L2DiagVdMemWithECC L2FixVUADAndTrap(N2_Strand *strand, | |
565 | N2_L2AddressingFields paddr, | |
566 | const MemoryTransaction &memXact); | |
567 | ||
568 | int L2FindWay(N2_L2AddressingFields paddr, | |
569 | N2_L2DiagVdMemWithECC diagVD); | |
570 | ||
571 | SS_Trap::Type L2CacheMiss(N2_Strand *strand, | |
572 | const MemoryTransaction &memXact, | |
573 | N2_L2DiagVdMemWithECC &diagVD); | |
574 | ||
575 | SS_Trap::Type L2CacheHit(N2_Strand *strand, | |
576 | const MemoryTransaction &memXact, | |
577 | N2_L2DiagVdMemWithECC &diagVD, | |
578 | int hit_way); | |
579 | ||
580 | N2_L2CacheLineError L2ProcessCacheLine(N2_L2AddressingFields paddr, | |
581 | uint32_t way, | |
582 | bool isRead); | |
583 | N2_L2CacheLineError L2ProcessQuarterLine(N2_L2AddressingFields paddr, | |
584 | uint32_t way, | |
585 | bool isRead); | |
586 | ||
587 | SS_Trap::Type ThrowL2DataTrap(const MemoryTransaction &memXact, | |
588 | N2_Strand *strand, | |
589 | uint32_t bank, | |
590 | N2_L2CacheLineError lineError); | |
591 | ||
592 | void ThrowL2DataCorrectableTrap(const MemoryTransaction &memXact, | |
593 | N2_Strand *strand, | |
594 | uint32_t bank, | |
595 | N2_L2CacheLineError lineError); | |
596 | ||
597 | ||
598 | SS_Trap::Type ThrowL2DataUncorrectableTrap(const MemoryTransaction &memXact, | |
599 | N2_Strand *strand, | |
600 | uint32_t bank, | |
601 | N2_L2CacheLineError lineError); | |
602 | ||
603 | void ThrowL2DataWriteBackTrap(const MemoryTransaction &memXact, | |
604 | N2_Strand *strand, | |
605 | uint32_t bank, | |
606 | N2_L2CacheLineError lineError); | |
607 | ||
608 | void poisonL2Line(N2_L2AddressingFields paddr, int way); | |
609 | ||
610 | // | |
611 | // Diagnostic access and modification routines. | |
612 | // | |
613 | typedef void (N2_L2ErrorStatusReg::*ErrorStatusRegBitSetFn)(uint64_t); | |
614 | ||
615 | void setL2ErrorStatusReg(uint32_t bank, | |
616 | ErrorStatusRegBitSetFn bitSetFunction, | |
617 | bool isCorrectable, | |
618 | uint32_t vcid, | |
619 | uint32_t syndrome, | |
620 | uint64_t errorAddr); | |
621 | ||
622 | void setL2NotdataErrorReg(uint32_t bank, | |
623 | uint32_t vcid, | |
624 | uint64_t errorAddress); | |
625 | ||
626 | ||
627 | // trapToErrorSteer() posts a trap to the ERRORSTEER core/strand | |
628 | // associated with bank. | |
629 | void trapToErrorSteer(N2_Strand *strand, uint32_t bank, | |
630 | SS_Interrupt::Bit trapNr) { | |
631 | N2_Strand *target_strand = (N2_Strand*)n2_model->cpu[0]->strand[getErrorSteer(bank)]; | |
632 | // Figure out which strand gets the trap from the L2 Control | |
633 | // Register's ERRORSTEER field. | |
634 | if(trapNr == SS_Interrupt::BIT_HW_CORRECTED_ERROR){ | |
635 | if(!strand->seter.dhcce()) | |
636 | return; | |
637 | } | |
638 | else if(trapNr == SS_Interrupt::BIT_SW_RECOVERABLE_ERROR){ | |
639 | if(!strand->seter.de()) | |
640 | return; | |
641 | } | |
642 | strand->irq.raise(target_strand,trapNr); | |
643 | } | |
644 | ||
645 | void setDESR(uint_t strandId,bool sw_recoverable_trap, | |
646 | uint32_t errorType, uint32_t errorAddr) | |
647 | { | |
648 | N2_Strand *strand = (N2_Strand*)n2_model->cpu[0]->strand[strandId]; | |
649 | N2_Desr *desr = &(strand->desr); | |
650 | if (!desr->f() ) | |
651 | { | |
652 | // sets the Strand's desr; not a copy | |
653 | desr->f(1); // full bit | |
654 | // S <- 1 for SW_recoverable_trap | |
655 | // S <- 0 for HW_corrected_error | |
656 | desr->s(sw_recoverable_trap); | |
657 | desr->errtype(errorType); // error code | |
658 | desr->erraddr(errorAddr); // error address | |
659 | } | |
660 | else | |
661 | { // set multiple error bit | |
662 | desr->me(1); | |
663 | } | |
664 | } | |
665 | ||
666 | ||
667 | // Get the CEEN bit from the L2$ error enable register | |
668 | uint32_t getCEEN(uint32_t bank) { | |
669 | N2_L2ErrorEnMem L2ErrorEnableReg; | |
670 | L2ErrorEnMemAccess_.access(bank, L2ErrorEnableReg, true); | |
671 | ||
672 | return L2ErrorEnableReg.getCEEN(); | |
673 | } | |
674 | ||
675 | // Get the NCEEN bit from the L2$ error enable register | |
676 | bool getNCEEN(uint32_t bank) { | |
677 | N2_L2ErrorEnMem L2ErrorEnableReg; | |
678 | L2ErrorEnMemAccess_.access(bank, L2ErrorEnableReg, true); | |
679 | ||
680 | return L2ErrorEnableReg.getNCEEN(); | |
681 | } | |
682 | ||
683 | // Get the ERRORSTEER core/strand id from the L2$ error control reg | |
684 | uint_t getErrorSteer(uint32_t bank) { | |
685 | N2_L2ControlReg L2ControlReg; | |
686 | L2ControlRegAccess_.access(bank, L2ControlReg, true); | |
687 | ||
688 | return L2ControlReg.getERRORSTEER(); | |
689 | } | |
690 | ||
691 | // get a set-bank index into a diagnostic csr array from a | |
692 | // physical address | |
693 | static uint64_t paddrToSetBankNdx(N2_L2AddressingFields paddr) | |
694 | { | |
695 | uint64_t diagNdx = paddr.getSET(); | |
696 | diagNdx <<= N2_L2AddressingFields::bitSizeBANK; | |
697 | return (diagNdx | paddr.getBANK()); | |
698 | } | |
699 | ||
700 | // get a way-set-bank index into a diagnostic csr array from a | |
701 | // physical address | |
702 | static uint64_t paddrToWaySetBankNdx(N2_L2AddressingFields paddr, | |
703 | uint32_t way) | |
704 | { | |
705 | uint64_t diagNdx = way; | |
706 | diagNdx <<= N2_L2AddressingFields::bitSizeSET; | |
707 | diagNdx |= paddr.getSET(); | |
708 | diagNdx <<= N2_L2AddressingFields::bitSizeBANK; | |
709 | return (diagNdx | paddr.getBANK()); | |
710 | } | |
711 | ||
712 | ||
713 | void DramThrowCorrectableTrap(N2_Strand *strand, | |
714 | const MemoryTransaction &memXact, | |
715 | uint32_t bank); | |
716 | ||
717 | SS_Trap::Type DramThrowUncorrectableTrap(N2_Strand *strand, | |
718 | const MemoryTransaction &memXact, | |
719 | uint32_t bank); | |
720 | ||
721 | static const uint64_t N2_DRAM_PADDR_MCU_SHIFT = 6; | |
722 | static const uint64_t N2_DRAM_PADDR_NR_MCU_LOG2 = 2; | |
723 | static const uint64_t N2_DRAM_PADDR_NR_MCU = | |
724 | (1<< N2_DRAM_PADDR_NR_MCU_LOG2); | |
725 | ||
726 | // Diagnostic access and modification routines. | |
727 | SS_Trap::Type dramProcessMemOp(N2_Strand *strand, | |
728 | const MemoryTransaction &memXact, | |
729 | N2_L2AddressingFields paddr,bool &); | |
730 | ||
731 | void dramUpdateECC(N2_L2AddressingFields paddr, bool isNotData); | |
732 | ||
733 | // Soc Error Detection and Correction Routines | |
734 | void processSocFbdError(N2_Strand &strand, | |
735 | N2_L2AddressingFields paddress, | |
736 | N2_SocErrorReg::SocErrRegBitGetFn getFBR); | |
737 | ||
738 | // Accessor Templates for L2$ Control Registers and Diag Access | |
739 | SS_CsrAccess<N2_L2ControlReg> L2ControlRegAccess_; | |
740 | N2_CheckedL2ESRAccess L2ErrorStatusRegAccess_; | |
741 | SS_CsrAccess<N2_L2ErrorAddressReg> L2ErrorAddressRegAccess_; | |
742 | SS_CsrAccess<N2_L2ErrorEnMem> L2ErrorEnMemAccess_; | |
743 | ||
744 | SS_CsrAccess<N2_L2DiagDataMem> L2DiagDataMemAccess_; | |
745 | SS_CsrAccess<N2_L2DiagTagMem> L2DiagTagMemAccess_; | |
746 | SS_CsrAccess<N2_L2DiagVdMemWithECC> L2DiagVdMemAccess_; | |
747 | SS_CsrAccess<N2_L2DiagUaMemWithECC> L2DiagUaMemAccess_; | |
748 | SS_CsrAccess<N2_L2NotdataErrorReg> L2NotdataErrorRegAccess_; | |
749 | // Accessor Templates for Dram Control Registers | |
750 | SS_CsrAccess<N2_DramErrorStatusMem> DramErrorStatusMemAccess_; | |
751 | SS_CsrAccess<N2_DramErrorInjectMem> DramErrorInjectMemAccess_; | |
752 | SS_CsrAccess<N2_DramErrorCounterMem> DramErrorCounterMemAccess_; | |
753 | SS_CsrAccess<N2_DramErrorLocMem> DramErrorLocMemAccess_; | |
754 | SS_CsrAccess<N2_DramFbdInjectedErrSrcReg> | |
755 | DramFbdInjectedErrSrcRegAccess_; | |
756 | SS_CsrAccess<N2_DramFbdCountReg> DramFbdCountRegAccess_; | |
757 | SS_CsrAccess<N2_DramFbdErrorSyndromeReg> | |
758 | DramFbdErrorSyndromeRegAccess_; | |
759 | ||
760 | // Accessor Templates for Soc Error Control Registers | |
761 | SS_CsrAccess<N2_SocErrorInjectReg> socErrorInjectRegAccess_; | |
762 | SS_CsrAccess<N2_SocErrorStatusReg> socErrorStatusRegAccess_; | |
763 | SS_CsrAccess<N2_SocPendingErrStatusReg> socPendingErrStatusRegAccess_; | |
764 | SS_CsrAccess<N2_SocErrorLogEnableReg> socErrorLogEnableRegAccess_; | |
765 | SS_CsrAccess<N2_SocErrorIntrEnReg> socErrorIntrEnRegAccess_; | |
766 | SS_CsrAccess<N2_SocFatalErrorEnableReg> socFatalErrorEnableRegAccess_; | |
767 | SS_CsrAccess<N2_SocErrorSteeringReg> socErrorSteeringRegAccess_; | |
768 | ||
769 | bool debugOutput_; | |
770 | ||
771 | // set to artificially inject Chip-Kill errors. Note that this | |
772 | // can't be used with "real" CK error injection because it | |
773 | // could result in uncorrectable double nibble errors. | |
774 | bool debugChipKill_; | |
775 | ||
776 | ||
777 | }; | |
778 | ||
779 | #endif /* _N2_MEMERRDETECTOR_H */ |