Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / n2 / lib / ras / src / N2_StoreBuffer.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: N2_StoreBuffer.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21#include "N2_StoreBuffer.h"
22#include "BL_BaseEcc.h"
23#include "BL_Hamming_32_7_Synd.h"
24#include "N2_Core.h"
25#include "N2_Strand.h"
26
27//=============================================================================
28//=============================================================================
29
30// fillStoreBuffer() adds an entry to the strand's store buffer. As
31// arguments, it takes whether or not the store is an ASI, the
32// store's address (physical for memory, virtual for ASI), either the
33// "byte marks" for memory or the ASI number, and the data.
34//
35// The store buffer, which contains 8 entries, is filled in a
36// round-robin fashion by incr_stb_pointer() . It calculates ECC for
37// both the upper and lower 32-bits of the data, injecting an error if
38// indicates by the ASI_ERROR_INJECT_REG. It saves the address in the
39// STB's CAM, the byte-marks-or-ASI, the privilege level, etc. in the
40// store buffer's entry, and the parity of the CAM (again, possibly
41// injecting an error).
42//
43// When a store buffer entry is purged, its CAM parity and data ECC
44// are checked for errors. If the correct state information is set,
45// then the appropriate trap is thrown.
46
47static uint64_t max( uint64_t l, uint64_t r ) { return l<r?r:l; }
48
49SS_Trap::Type N2_StoreBuffer::fill_store_buffer(bool is_asi,uint64_t addr, uint8_t asi,uint64_t data)/*{{{*/
50{
51 uint_t stb_ptr_ndx = get_stb_pointer();
52
53 if (!stb_entry_is_asi[stb_ptr_ndx] && stb_entry_valid(stb_ptr_ndx))
54 {
55 SS_Trap::Type tt = purge_store_buffer(stb_ptr_ndx);
56 if(tt != SS_Trap::NO_TRAP)
57 return tt;
58 }
59
60 N2_ErrorInject *error_inject_reg = &(strand.core.error_inject);
61
62 uint_t stb_pointer = incr_stb_pointer();
63
64 N2_StbAccessDaReg stb_access_da_reg;
65 stb_access_da_reg.data(data);
66 set_stb_data(stb_pointer, stb_access_da_reg);
67
68 N2_StbAccessEccReg stb_access_ecc_reg;
69 BL_EccBits even_ecc = BL_Hamming_32_7_Synd::calc_check_bits(data & 0xffffffff);
70 if (error_inject_reg->ene() == 1 && error_inject_reg->stdu())
71 {
72 even_ecc.set(even_ecc.get() ^ error_inject_reg->eccmask());
73 }
74 stb_access_ecc_reg.ecc_even(even_ecc.get());
75 BL_EccBits odd_ecc = BL_Hamming_32_7_Synd::calc_check_bits(data >> 32);
76 if (error_inject_reg->ene() == 1 && error_inject_reg->stdu())
77 {
78 odd_ecc.set(odd_ecc.get() ^ error_inject_reg->eccmask());
79 }
80 stb_access_ecc_reg.ecc_odd(odd_ecc.get());
81 set_stb_ecc(stb_pointer, stb_access_ecc_reg);
82
83 N2_StbAccessCamReg stb_access_cam_reg;
84 stb_access_cam_reg.set(addr); // set address
85 stb_access_cam_reg.bm_asi(asi); // override bm_asi field
86 set_stb_cam(stb_pointer, stb_access_cam_reg);
87
88 uint_t cam_parity = BL_BitUtility::calc_parity(stb_access_cam_reg());
89 if (error_inject_reg->ene() == 1 && error_inject_reg->stau())
90 {
91 cam_parity = ~cam_parity;;
92 }
93 N2_StbAccessCtlReg stb_access_ctl_reg;
94 stb_access_ctl_reg.c_p(cam_parity);
95
96 if (strand.hpstate.hpriv())
97 {
98 stb_access_ctl_reg.control(N2_StbAccessCtlReg::CTL_HPRIV);
99 } else if (strand.pstate.priv())
100 {
101 stb_access_ctl_reg.control(N2_StbAccessCtlReg::CTL_PRIV);
102 } else
103 {
104 stb_access_ctl_reg.control(N2_StbAccessCtlReg::CTL_USER);
105 }
106 set_stb_ctl(stb_pointer, stb_access_ctl_reg);
107
108 stb_entry_is_asi[stb_pointer] = is_asi;
109 return SS_Trap::NO_TRAP;
110}
111/*}}}*/
112
113SS_Trap::Type N2_StoreBuffer::check_store_buffer_RAWtrap(const MemoryTransaction &memXact)/*{{{*/
114{
115 // search the entire Store Buffer
116 for (uint_t ndx = 0;ndx < (1<<N2_StbAccessAddrFields::bit_size_entry);++ndx)
117 {
118 if (!stb_entry_valid(ndx) || stb_entry_is_asi[ndx])
119 {
120 continue;
121 }
122
123 N2_StbAccessCamReg stb_access_cam_reg = get_stb_cam(ndx);
124
125 // NB: Range check is broken because BM_ASI() should be
126 // log2(BM_ASI()) + 1.
127
128 uint64_t cam_pa = stb_access_cam_reg.pa() << N2_StbAccessCamReg::bit_size_rsvd0;
129 uint64_t cam_len = 0;
130 for (int shift_ndx = 0; shift_ndx < N2_StbAccessCamReg::bit_size_bm_asi; ++shift_ndx)
131 {
132 if (stb_access_cam_reg.bm_asi() & (1 << shift_ndx))
133 {
134 cam_len = shift_ndx + 1;
135 }
136 }
137 if (memXact.paddr() <= cam_pa + cam_len &&
138 memXact.paddr() + memXact.size() >= cam_pa)
139 {
140 SS_Trap::Type tt = check_store_buffer_entry(ndx);
141 if(tt != SS_Trap::NO_TRAP)
142 return tt;
143 }
144 }
145 return SS_Trap::NO_TRAP;
146}
147/*}}}*/
148
149//flush_store_buffer is called at every step interval or any other regular
150//interval to periodically purge the stb contents
151
152SS_Trap::Type N2_StoreBuffer::flush_store_buffer()
153{
154 if(++stb_flush_count == STB_FLUSH_RATE)
155 {
156 stb_flush_count = 0;
157 return purge_store_buffer(incr_stb_pointer());
158 }
159 else
160 return SS_Trap::NO_TRAP;
161}
162
163// purge_store_buffer() is passed the index of store buffer entry and
164// purges the associated entry from the buffer. It checks for un- and
165// correctabled data RAS errors (SBDPU and SBDPC) and CAM address
166// parity RAS errors (SBAPP). If any of these errors are detected, it
167// sets the necessary error status registers and throws or posts the
168// correct trap.
169//
170// In any case, the store buffer entry is invalidated to avoid
171// multiple redundant error hits and mimic the hardware's actual
172// behavior.
173
174SS_Trap::Type N2_StoreBuffer::purge_store_buffer(uint_t ndx)/*{{{*/
175{
176 if (!stb_entry_valid(ndx) || stb_entry_is_asi[ndx])
177 {
178 return SS_Trap::NO_TRAP;
179 }
180
181 N2_StbAccessAddrFields addr;
182 addr.entry(ndx);
183 addr.field(N2_StbAccessAddrFields::CAM_FIELD);
184
185 N2_Cerer *cerer = &(strand.core.cerer);
186
187
188 N2_StbAccessDaReg stb_access_da_reg = get_stb_data(ndx);
189 N2_StbAccessEccReg stb_access_ecc_reg = get_stb_ecc(ndx);
190
191 uint32_t even_data = stb_access_da_reg() & 0xffffffff;
192 BL_EccBits even_ecc(stb_access_ecc_reg.ecc_even());
193
194 BL_Hamming_32_7_Synd even_syndrome(even_data,even_ecc);
195
196 uint32_t odd_data = stb_access_da_reg() >> 32;
197 BL_EccBits odd_ecc(stb_access_ecc_reg.ecc_odd());
198 BL_Hamming_32_7_Synd odd_syndrome(odd_data,odd_ecc);
199
200
201 if (even_syndrome.isUncorrectableError() ||
202 odd_syndrome.isUncorrectableError())
203 {
204 if (cerer->sbdpu_sbiou() && strand.seter.de())
205 {
206 set_desr(true, N2_Desr::RE_SBDPU, ndx);
207 strand.irq.raise(&strand,SS_Interrupt::BIT_SW_RECOVERABLE_ERROR);
208 }
209 }
210 else if (even_syndrome.isSingleBitError() ||
211 odd_syndrome.isSingleBitError())
212 {
213 if (cerer->sbdpc() && strand.seter.dhcce())
214 {
215 set_desr(false, N2_Desr::CE_SBDPC, ndx);
216 strand.irq.raise(&strand,SS_Interrupt::BIT_HW_CORRECTED_ERROR);
217 }
218 }
219
220 // Check CAM parity
221 if (cerer->sbapp())
222 {
223 if (BL_BitUtility::calc_parity(get_stb_cam(ndx)()) !=
224 get_stb_ctl(ndx).c_p())
225 {
226 strand.core.dfesr.type(1);
227 strand.core.dfesr.stbindex(ndx);
228 // scan Store Buffer for entry with highest privledge
229 uint_t max_priv = N2_Dfesr::USER_PRIV;
230 for (int priv_ndx = 0;
231 priv_ndx < (1<<N2_StbAccessAddrFields::bit_size_entry);
232 ++priv_ndx)
233 {
234 if (stb_entry_valid(priv_ndx))
235 {
236 N2_StbAccessCtlReg stb_access_ctl_reg = get_stb_ctl(priv_ndx);
237
238 uint_t entry_control = stb_access_ctl_reg.control();
239 switch (entry_control)
240 {
241 case N2_StbAccessCtlReg::CTL_USER:
242 break;
243 case N2_StbAccessCtlReg::CTL_PRIV:
244 max_priv = max(max_priv, N2_Dfesr::PRIV_PRIV);
245 break;
246 case N2_StbAccessCtlReg::CTL_HPRIV:
247 max_priv = max(max_priv, N2_Dfesr::HPRIV_PRIV);
248 break;
249 default: // parity error in entry_control
250 max_priv = N2_Dfesr::UNKNOWN_PRIV;
251 break;
252 }
253 }
254 }
255 invalidate_stb_entry(ndx);
256 strand.core.dfesr.priv(max_priv);
257 return SS_Trap::STORE_ERROR;
258 }
259 }
260 invalidate_stb_entry(ndx);
261 return SS_Trap::NO_TRAP;
262}
263/*}}}*/
264
265// checkStoreBufferEntry() checks to see if a store buffer entry
266// contains a RAS data error (either SBDLC or SBDLU). If so, it sets
267// the correct status registers and throws a internal_processor_error
268// trap.
269
270SS_Trap::Type N2_StoreBuffer::check_store_buffer_entry(uint_t ndx)/*{{{*/
271{
272 N2_StbAccessDaReg stb_access_da_reg = get_stb_data(ndx);
273 N2_StbAccessEccReg stb_access_ecc_reg = get_stb_ecc(ndx);
274
275 uint32_t even_data = stb_access_da_reg() & 0xffffffff;
276 BL_EccBits even_ecc(stb_access_ecc_reg.ecc_even());
277
278 BL_Hamming_32_7_Synd even_syndrome(even_data,even_ecc);
279
280 uint32_t odd_data = stb_access_da_reg() >> 32;
281 BL_EccBits odd_ecc(stb_access_ecc_reg.ecc_odd());
282 BL_Hamming_32_7_Synd odd_syndrome(odd_data,odd_ecc);
283
284
285 if (even_syndrome.isUncorrectableError() ||
286 odd_syndrome.isUncorrectableError())
287 {
288 N2_Cerer *cerer = &(strand.core.cerer);
289
290 if (cerer->sbdlu() && strand.seter.pscce())
291 {
292 // Set error in DSFSR
293 strand.data_sfsr.error_type(N2_DataSfsr::SBDLU);
294 // Set stb index in DSFAR
295 strand.data_sfar.error_addr(ndx);
296 //purge_store_buffer(ndx);
297 return SS_Trap::INTERNAL_PROCESSOR_ERROR;
298 }
299 } else if (even_syndrome.isSingleBitError() ||
300 odd_syndrome.isSingleBitError())
301 {
302 N2_Cerer *cerer = &(strand.core.cerer);
303
304 if(cerer->sbdlc() && strand.seter.pscce())
305 {
306 // Set error in DSFSR
307 strand.data_sfsr.error_type(N2_DataSfsr::SBDLC);
308 // Set stb index in DSFAR
309 strand.data_sfar.error_addr(ndx);
310 //purge_store_buffer(ndx);
311 return SS_Trap::INTERNAL_PROCESSOR_ERROR;
312 }
313 }
314 return SS_Trap::NO_TRAP;
315}
316/*}}}*/
317
318void N2_StoreBuffer::set_desr(bool sw_recoverable_trap, uint32_t error_type,
319 uint32_t error_addr)/*{{{*/
320{
321 N2_Desr *desr = &(strand.desr);
322 if (!desr->f() )
323 {
324 // sets the Strand's desr; not a copy
325 desr->f(1); // full bit
326 // S <- 1 for SW_recoverable_trap
327 // S <- 0 for HW_corrected_error
328 desr->s(sw_recoverable_trap);
329 desr->errtype(error_type); // error code
330 desr->erraddr(error_addr); // error address
331 }
332 else
333 { // set multiple error bit
334 desr->me(1);
335 }
336}
337/*}}}*/
338
339//=============================================================================
340//=============================================================================
341//
342// STORE BUFFER ACCESS ROUTINES
343//
344//=============================================================================
345//=============================================================================
346// Return store buffer content at addr
347uint64_t N2_StoreBuffer::get_stb_value(uint64_t addr)/*{{{*/
348{
349 uint_t ptr = (stb_access[addr])();
350 return ptr;
351}
352/*}}}*/
353// Return store buffer current pointer
354uint_t N2_StoreBuffer::get_stb_pointer()/*{{{*/
355{
356 N2_StbAccessAddrFields addr;
357 addr.field(N2_StbAccessAddrFields::STB_POINTER_FIELD);
358 addr.entry(0);
359 uint_t ptr = (stb_access[addr()])();
360 return ptr & ((1<<N2_StbAccessAddrFields::bit_size_entry) - 1);
361}
362/*}}}*/
363// Increment store buffer current pointer
364uint_t N2_StoreBuffer::incr_stb_pointer()/*{{{*/
365{
366 N2_StbAccessAddrFields addr;
367 addr.field(N2_StbAccessAddrFields::STB_POINTER_FIELD);
368 addr.entry(0);
369 uint_t old_ptr = stb_access[addr()]();
370 uint_t ptr = old_ptr + 1;
371 ptr &= ((1<<N2_StbAccessAddrFields::bit_size_entry) - 1);
372 stb_access[addr()].set(ptr);
373 return old_ptr;
374}
375/*}}}*/
376
377// Gets the data associated with a store buffer entry
378N2_StbAccessDaReg N2_StoreBuffer::get_stb_data(uint_t entry)/*{{{*/
379{
380 N2_StbAccessAddrFields addr;
381 addr.field(N2_StbAccessAddrFields::DATA_FIELD);
382 addr.entry(entry);
383 return stb_access[addr()];
384}
385/*}}}*/
386
387// Sets the data associated with a store buffer entry
388void N2_StoreBuffer::set_stb_data(uint_t entry, N2_StbAccessDaReg &stb_access_da_reg)/*{{{*/
389{
390 N2_StbAccessAddrFields addr;
391 addr.field(N2_StbAccessAddrFields::DATA_FIELD);
392 addr.entry(entry);
393 stb_access[addr()] = stb_access_da_reg;
394}
395/*}}}*/
396
397// Gets the ECC associated with a store buffer entry
398N2_StbAccessEccReg N2_StoreBuffer::get_stb_ecc(uint_t entry)/*{{{*/
399{
400 N2_StbAccessAddrFields addr;
401 addr.field(N2_StbAccessAddrFields::ECC_FIELD);
402 addr.entry(entry);
403 N2_StbAccessEccReg stb_access_ecc_reg;
404 stb_access_ecc_reg.set(stb_access[addr()]());
405 return stb_access_ecc_reg;
406}
407/*}}}*/
408
409// Sets the ECC associated with a store buffer entry
410void
411N2_StoreBuffer::set_stb_ecc(uint_t entry, N2_StbAccessEccReg &stb_access_ecc_reg)/*{{{*/
412{
413 N2_StbAccessAddrFields addr;
414 addr.field(N2_StbAccessAddrFields::ECC_FIELD);
415 addr.entry(entry);
416 N2_StbAccessDaReg stb_access_da_reg;
417 stb_access_da_reg.set(stb_access_ecc_reg());
418 stb_access[addr()] = stb_access_da_reg;
419}
420/*}}}*/
421
422// Gets the Control/Parity associated with a store buffer entry
423N2_StbAccessCtlReg N2_StoreBuffer::get_stb_ctl(uint_t entry) /*{{{*/
424{
425 N2_StbAccessAddrFields addr;
426 addr.field(N2_StbAccessAddrFields::CNTRL_PARITY_FIELD);
427 addr.entry(entry);
428 N2_StbAccessCtlReg stb_access_ctl_reg;
429 stb_access_ctl_reg.set(stb_access[addr()]());
430 return stb_access_ctl_reg;
431}
432/*}}}*/
433
434// Sets the Control/Parity associated with a store buffer entry
435void N2_StoreBuffer::set_stb_ctl(uint_t entry, N2_StbAccessCtlReg &stb_access_ctl_reg) /*{{{*/
436{
437 N2_StbAccessAddrFields addr;
438 addr.field(N2_StbAccessAddrFields::CNTRL_PARITY_FIELD);
439 addr.entry(entry);
440 N2_StbAccessDaReg stb_access_da_reg;
441 stb_access_da_reg.set(stb_access_ctl_reg());
442 stb_access[addr()] = stb_access_da_reg;
443}
444/*}}}*/
445
446// Gets the CAM address associated with a store buffer entry
447N2_StbAccessCamReg N2_StoreBuffer::get_stb_cam(uint_t entry) {
448 N2_StbAccessAddrFields addr;
449 addr.field(N2_StbAccessAddrFields::CAM_FIELD);
450 addr.entry(entry);
451 N2_StbAccessCamReg stb_access_cam_reg;
452 stb_access_cam_reg.set(stb_access[addr()]());
453 return stb_access_cam_reg;
454}
455/*}}}*/
456
457// Sets the CAM address associated with a store buffer entry
458void N2_StoreBuffer::set_stb_cam(uint_t entry, N2_StbAccessCamReg &stb_access_cam_reg)/*{{{*/
459{
460 N2_StbAccessAddrFields addr;
461 addr.field(N2_StbAccessAddrFields::CAM_FIELD);
462 addr.entry(entry);
463 N2_StbAccessDaReg stb_access_da_reg;
464 stb_access_da_reg.set(stb_access_cam_reg());
465 stb_access[addr()] = stb_access_da_reg;
466}
467/*}}}*/
468
469bool N2_StoreBuffer::stb_entry_valid(uint ndx)/*{{{*/
470{
471 N2_StbAccessAddrFields addr;
472 addr.entry(ndx);
473 addr.field(N2_StbAccessAddrFields::CAM_FIELD);
474 std::map<uint64_t,N2_StbAccessDaReg>::iterator stb_access_da_regNdx = stb_access.find(addr());
475 return stb_access_da_regNdx != stb_access.end();
476}
477/*}}}*/
478
479void N2_StoreBuffer::invalidate_stb_entry(uint ndx)/*{{{*/
480{
481 N2_StbAccessAddrFields addr;
482 addr.entry(ndx);
483 addr.field(N2_StbAccessAddrFields::CAM_FIELD);
484 stb_access.erase(addr());
485}
486/*}}}*/