// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: N2_StoreBuffer.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// ========== Copyright Header End ============================================
#include "N2_StoreBuffer.h"
#include "BL_Hamming_32_7_Synd.h"
//=============================================================================
//=============================================================================
// fillStoreBuffer() adds an entry to the strand's store buffer. As
// arguments, it takes whether or not the store is an ASI, the
// store's address (physical for memory, virtual for ASI), either the
// "byte marks" for memory or the ASI number, and the data.
// The store buffer, which contains 8 entries, is filled in a
// round-robin fashion by incr_stb_pointer() . It calculates ECC for
// both the upper and lower 32-bits of the data, injecting an error if
// indicates by the ASI_ERROR_INJECT_REG. It saves the address in the
// STB's CAM, the byte-marks-or-ASI, the privilege level, etc. in the
// store buffer's entry, and the parity of the CAM (again, possibly
// When a store buffer entry is purged, its CAM parity and data ECC
// are checked for errors. If the correct state information is set,
// then the appropriate trap is thrown.
static uint64_t max( uint64_t l
, uint64_t r
) { return l
<r
?r
:l
; }
SS_Trap::Type
N2_StoreBuffer::fill_store_buffer(bool is_asi
,uint64_t addr
, uint8_t asi
,uint64_t data
)/*{{{*/
uint_t stb_ptr_ndx
= get_stb_pointer();
if (!stb_entry_is_asi
[stb_ptr_ndx
] && stb_entry_valid(stb_ptr_ndx
))
SS_Trap::Type tt
= purge_store_buffer(stb_ptr_ndx
);
if(tt
!= SS_Trap::NO_TRAP
)
N2_ErrorInject
*error_inject_reg
= &(strand
.core
.error_inject
);
uint_t stb_pointer
= incr_stb_pointer();
N2_StbAccessDaReg stb_access_da_reg
;
stb_access_da_reg
.data(data
);
set_stb_data(stb_pointer
, stb_access_da_reg
);
N2_StbAccessEccReg stb_access_ecc_reg
;
BL_EccBits even_ecc
= BL_Hamming_32_7_Synd::calc_check_bits(data
& 0xffffffff);
if (error_inject_reg
->ene() == 1 && error_inject_reg
->stdu())
even_ecc
.set(even_ecc
.get() ^ error_inject_reg
->eccmask());
stb_access_ecc_reg
.ecc_even(even_ecc
.get());
BL_EccBits odd_ecc
= BL_Hamming_32_7_Synd::calc_check_bits(data
>> 32);
if (error_inject_reg
->ene() == 1 && error_inject_reg
->stdu())
odd_ecc
.set(odd_ecc
.get() ^ error_inject_reg
->eccmask());
stb_access_ecc_reg
.ecc_odd(odd_ecc
.get());
set_stb_ecc(stb_pointer
, stb_access_ecc_reg
);
N2_StbAccessCamReg stb_access_cam_reg
;
stb_access_cam_reg
.set(addr
); // set address
stb_access_cam_reg
.bm_asi(asi
); // override bm_asi field
set_stb_cam(stb_pointer
, stb_access_cam_reg
);
uint_t cam_parity
= BL_BitUtility::calc_parity(stb_access_cam_reg());
if (error_inject_reg
->ene() == 1 && error_inject_reg
->stau())
cam_parity
= ~cam_parity
;;
N2_StbAccessCtlReg stb_access_ctl_reg
;
stb_access_ctl_reg
.c_p(cam_parity
);
if (strand
.hpstate
.hpriv())
stb_access_ctl_reg
.control(N2_StbAccessCtlReg::CTL_HPRIV
);
} else if (strand
.pstate
.priv())
stb_access_ctl_reg
.control(N2_StbAccessCtlReg::CTL_PRIV
);
stb_access_ctl_reg
.control(N2_StbAccessCtlReg::CTL_USER
);
set_stb_ctl(stb_pointer
, stb_access_ctl_reg
);
stb_entry_is_asi
[stb_pointer
] = is_asi
;
SS_Trap::Type
N2_StoreBuffer::check_store_buffer_RAWtrap(const MemoryTransaction
&memXact
)/*{{{*/
// search the entire Store Buffer
for (uint_t ndx
= 0;ndx
< (1<<N2_StbAccessAddrFields::bit_size_entry
);++ndx
)
if (!stb_entry_valid(ndx
) || stb_entry_is_asi
[ndx
])
N2_StbAccessCamReg stb_access_cam_reg
= get_stb_cam(ndx
);
// NB: Range check is broken because BM_ASI() should be
uint64_t cam_pa
= stb_access_cam_reg
.pa() << N2_StbAccessCamReg::bit_size_rsvd0
;
for (int shift_ndx
= 0; shift_ndx
< N2_StbAccessCamReg::bit_size_bm_asi
; ++shift_ndx
)
if (stb_access_cam_reg
.bm_asi() & (1 << shift_ndx
))
if (memXact
.paddr() <= cam_pa
+ cam_len
&&
memXact
.paddr() + memXact
.size() >= cam_pa
)
SS_Trap::Type tt
= check_store_buffer_entry(ndx
);
if(tt
!= SS_Trap::NO_TRAP
)
//flush_store_buffer is called at every step interval or any other regular
//interval to periodically purge the stb contents
SS_Trap::Type
N2_StoreBuffer::flush_store_buffer()
if(++stb_flush_count
== STB_FLUSH_RATE
)
return purge_store_buffer(incr_stb_pointer());
// purge_store_buffer() is passed the index of store buffer entry and
// purges the associated entry from the buffer. It checks for un- and
// correctabled data RAS errors (SBDPU and SBDPC) and CAM address
// parity RAS errors (SBAPP). If any of these errors are detected, it
// sets the necessary error status registers and throws or posts the
// In any case, the store buffer entry is invalidated to avoid
// multiple redundant error hits and mimic the hardware's actual
SS_Trap::Type
N2_StoreBuffer::purge_store_buffer(uint_t ndx
)/*{{{*/
if (!stb_entry_valid(ndx
) || stb_entry_is_asi
[ndx
])
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::CAM_FIELD
);
N2_Cerer
*cerer
= &(strand
.core
.cerer
);
N2_StbAccessDaReg stb_access_da_reg
= get_stb_data(ndx
);
N2_StbAccessEccReg stb_access_ecc_reg
= get_stb_ecc(ndx
);
uint32_t even_data
= stb_access_da_reg() & 0xffffffff;
BL_EccBits
even_ecc(stb_access_ecc_reg
.ecc_even());
BL_Hamming_32_7_Synd
even_syndrome(even_data
,even_ecc
);
uint32_t odd_data
= stb_access_da_reg() >> 32;
BL_EccBits
odd_ecc(stb_access_ecc_reg
.ecc_odd());
BL_Hamming_32_7_Synd
odd_syndrome(odd_data
,odd_ecc
);
if (even_syndrome
.isUncorrectableError() ||
odd_syndrome
.isUncorrectableError())
if (cerer
->sbdpu_sbiou() && strand
.seter
.de())
set_desr(true, N2_Desr::RE_SBDPU
, ndx
);
strand
.irq
.raise(&strand
,SS_Interrupt::BIT_SW_RECOVERABLE_ERROR
);
else if (even_syndrome
.isSingleBitError() ||
odd_syndrome
.isSingleBitError())
if (cerer
->sbdpc() && strand
.seter
.dhcce())
set_desr(false, N2_Desr::CE_SBDPC
, ndx
);
strand
.irq
.raise(&strand
,SS_Interrupt::BIT_HW_CORRECTED_ERROR
);
if (BL_BitUtility::calc_parity(get_stb_cam(ndx
)()) !=
strand
.core
.dfesr
.type(1);
strand
.core
.dfesr
.stbindex(ndx
);
// scan Store Buffer for entry with highest privledge
uint_t max_priv
= N2_Dfesr::USER_PRIV
;
priv_ndx
< (1<<N2_StbAccessAddrFields::bit_size_entry
);
if (stb_entry_valid(priv_ndx
))
N2_StbAccessCtlReg stb_access_ctl_reg
= get_stb_ctl(priv_ndx
);
uint_t entry_control
= stb_access_ctl_reg
.control();
case N2_StbAccessCtlReg::CTL_USER
:
case N2_StbAccessCtlReg::CTL_PRIV
:
max_priv
= max(max_priv
, N2_Dfesr::PRIV_PRIV
);
case N2_StbAccessCtlReg::CTL_HPRIV
:
max_priv
= max(max_priv
, N2_Dfesr::HPRIV_PRIV
);
default: // parity error in entry_control
max_priv
= N2_Dfesr::UNKNOWN_PRIV
;
invalidate_stb_entry(ndx
);
strand
.core
.dfesr
.priv(max_priv
);
return SS_Trap::STORE_ERROR
;
invalidate_stb_entry(ndx
);
// checkStoreBufferEntry() checks to see if a store buffer entry
// contains a RAS data error (either SBDLC or SBDLU). If so, it sets
// the correct status registers and throws a internal_processor_error
SS_Trap::Type
N2_StoreBuffer::check_store_buffer_entry(uint_t ndx
)/*{{{*/
N2_StbAccessDaReg stb_access_da_reg
= get_stb_data(ndx
);
N2_StbAccessEccReg stb_access_ecc_reg
= get_stb_ecc(ndx
);
uint32_t even_data
= stb_access_da_reg() & 0xffffffff;
BL_EccBits
even_ecc(stb_access_ecc_reg
.ecc_even());
BL_Hamming_32_7_Synd
even_syndrome(even_data
,even_ecc
);
uint32_t odd_data
= stb_access_da_reg() >> 32;
BL_EccBits
odd_ecc(stb_access_ecc_reg
.ecc_odd());
BL_Hamming_32_7_Synd
odd_syndrome(odd_data
,odd_ecc
);
if (even_syndrome
.isUncorrectableError() ||
odd_syndrome
.isUncorrectableError())
N2_Cerer
*cerer
= &(strand
.core
.cerer
);
if (cerer
->sbdlu() && strand
.seter
.pscce())
strand
.data_sfsr
.error_type(N2_DataSfsr::SBDLU
);
// Set stb index in DSFAR
strand
.data_sfar
.error_addr(ndx
);
//purge_store_buffer(ndx);
return SS_Trap::INTERNAL_PROCESSOR_ERROR
;
} else if (even_syndrome
.isSingleBitError() ||
odd_syndrome
.isSingleBitError())
N2_Cerer
*cerer
= &(strand
.core
.cerer
);
if(cerer
->sbdlc() && strand
.seter
.pscce())
strand
.data_sfsr
.error_type(N2_DataSfsr::SBDLC
);
// Set stb index in DSFAR
strand
.data_sfar
.error_addr(ndx
);
//purge_store_buffer(ndx);
return SS_Trap::INTERNAL_PROCESSOR_ERROR
;
void N2_StoreBuffer::set_desr(bool sw_recoverable_trap
, uint32_t error_type
,
uint32_t error_addr
)/*{{{*/
N2_Desr
*desr
= &(strand
.desr
);
// sets the Strand's desr; not a copy
// S <- 1 for SW_recoverable_trap
// S <- 0 for HW_corrected_error
desr
->s(sw_recoverable_trap
);
desr
->errtype(error_type
); // error code
desr
->erraddr(error_addr
); // error address
{ // set multiple error bit
//=============================================================================
//=============================================================================
// STORE BUFFER ACCESS ROUTINES
//=============================================================================
//=============================================================================
// Return store buffer content at addr
uint64_t N2_StoreBuffer::get_stb_value(uint64_t addr
)/*{{{*/
uint_t ptr
= (stb_access
[addr
])();
// Return store buffer current pointer
uint_t
N2_StoreBuffer::get_stb_pointer()/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::STB_POINTER_FIELD
);
uint_t ptr
= (stb_access
[addr()])();
return ptr
& ((1<<N2_StbAccessAddrFields::bit_size_entry
) - 1);
// Increment store buffer current pointer
uint_t
N2_StoreBuffer::incr_stb_pointer()/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::STB_POINTER_FIELD
);
uint_t old_ptr
= stb_access
[addr()]();
uint_t ptr
= old_ptr
+ 1;
ptr
&= ((1<<N2_StbAccessAddrFields::bit_size_entry
) - 1);
stb_access
[addr()].set(ptr
);
// Gets the data associated with a store buffer entry
N2_StbAccessDaReg
N2_StoreBuffer::get_stb_data(uint_t entry
)/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::DATA_FIELD
);
return stb_access
[addr()];
// Sets the data associated with a store buffer entry
void N2_StoreBuffer::set_stb_data(uint_t entry
, N2_StbAccessDaReg
&stb_access_da_reg
)/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::DATA_FIELD
);
stb_access
[addr()] = stb_access_da_reg
;
// Gets the ECC associated with a store buffer entry
N2_StbAccessEccReg
N2_StoreBuffer::get_stb_ecc(uint_t entry
)/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::ECC_FIELD
);
N2_StbAccessEccReg stb_access_ecc_reg
;
stb_access_ecc_reg
.set(stb_access
[addr()]());
return stb_access_ecc_reg
;
// Sets the ECC associated with a store buffer entry
N2_StoreBuffer::set_stb_ecc(uint_t entry
, N2_StbAccessEccReg
&stb_access_ecc_reg
)/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::ECC_FIELD
);
N2_StbAccessDaReg stb_access_da_reg
;
stb_access_da_reg
.set(stb_access_ecc_reg());
stb_access
[addr()] = stb_access_da_reg
;
// Gets the Control/Parity associated with a store buffer entry
N2_StbAccessCtlReg
N2_StoreBuffer::get_stb_ctl(uint_t entry
) /*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::CNTRL_PARITY_FIELD
);
N2_StbAccessCtlReg stb_access_ctl_reg
;
stb_access_ctl_reg
.set(stb_access
[addr()]());
return stb_access_ctl_reg
;
// Sets the Control/Parity associated with a store buffer entry
void N2_StoreBuffer::set_stb_ctl(uint_t entry
, N2_StbAccessCtlReg
&stb_access_ctl_reg
) /*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::CNTRL_PARITY_FIELD
);
N2_StbAccessDaReg stb_access_da_reg
;
stb_access_da_reg
.set(stb_access_ctl_reg());
stb_access
[addr()] = stb_access_da_reg
;
// Gets the CAM address associated with a store buffer entry
N2_StbAccessCamReg
N2_StoreBuffer::get_stb_cam(uint_t entry
) {
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::CAM_FIELD
);
N2_StbAccessCamReg stb_access_cam_reg
;
stb_access_cam_reg
.set(stb_access
[addr()]());
return stb_access_cam_reg
;
// Sets the CAM address associated with a store buffer entry
void N2_StoreBuffer::set_stb_cam(uint_t entry
, N2_StbAccessCamReg
&stb_access_cam_reg
)/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::CAM_FIELD
);
N2_StbAccessDaReg stb_access_da_reg
;
stb_access_da_reg
.set(stb_access_cam_reg());
stb_access
[addr()] = stb_access_da_reg
;
bool N2_StoreBuffer::stb_entry_valid(uint ndx
)/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::CAM_FIELD
);
std::map
<uint64_t,N2_StbAccessDaReg
>::iterator stb_access_da_regNdx
= stb_access
.find(addr());
return stb_access_da_regNdx
!= stb_access
.end();
void N2_StoreBuffer::invalidate_stb_entry(uint ndx
)/*{{{*/
N2_StbAccessAddrFields addr
;
addr
.field(N2_StbAccessAddrFields::CAM_FIELD
);
stb_access
.erase(addr());